qt-installer-framework-4.0.1/0040777000000000000000000000000013764072130013067 5ustar00qt-installer-framework-4.0.1/.qmake.conf0100777000000000000000000000007313761647206015123 0ustar00VERSION=4.0.1 CONFIG=prepare_docs qt_docs_targets $$CONFIG qt-installer-framework-4.0.1/.qt-license-check.exclude0100777000000000000000000000002013761647206017640 0ustar00^src/libs/7zip/ qt-installer-framework-4.0.1/.qt-license-check.optional0100777000000000000000000000002313761647206020037 0ustar00^src/libs/kdtools/ qt-installer-framework-4.0.1/.tag0100777000000000000000000000005113761647206013650 0ustar00457a4a6c203c030b48ad9d9ef34d5b17d5158526 qt-installer-framework-4.0.1/3RDPARTY0100777000000000000000000000135113761647206014233 0ustar00The Qt Installer Framework sources include third party code: ============================================================ LZMA SDK Parts of the sources from the LZMA SDK , version 9.20 are under src/libs/7zip/unix and src/libs/7z/win. The LZMA SDK is written and placed in the public domain by Igor Pavlov. Some code in LZMA SDK is based on public domain code from another developers: 1) PPMd var.H (2001): Dmitry Shkarin 2) SHA-256: Wei Dai (Crypto++ library) ============================================================ KD Tools Sources for the KD Tools library are under src/libs/kdtools. The library is released under the same licenses as the rest of the installer framework. The copyright is owned by Klaralvdalens Datakonsult AB. qt-installer-framework-4.0.1/Changelog0100777000000000000000000006374413761647206014730 0ustar004.0.1 - Enable HighDPI support in X11 - Fix AppendFile undo (QTIFW-2020) - Repogen: Fix unite metadata when --repository switch used ( QTIFW-2018) - Docs: Fix doc on gui::showFinishedPage() (QTIFW-798) - Fix loading controller script with comment on last line (QTIFW-1062) - Fix segfault on file download error properly - Doc: Update command line interface reference - Obey stylesheet in SettingsDialog (QTIFW-1507) - CLI: Fix wrong warning text in command 'purge' for running processes (QTIFW-1996) 4.0.0 - Fix essential update (QTIFW-1970) - Print package id when running checkupdates (QTIFW-1972) - Update documentation to support clang - Allow setting BackgroundPixmap shown on MacStyle regardless of platform (QTIFW-1175) - Hide detailed verbose with lowest verbose level - Add support for vendor set image decoration (QTIFW-1900) - Add verbose levels (QTIFW-1914) - CLI: Ask user confirmation before performing installer actions (QTIFW-1834) - Add possibility to add custom widget from script to certain position (QTIFW-1847) - Add function to get information if default install is performed (QTIFW-1847) - Add possibility to select/deselect component from script using core (QTIFW-1847) - Add a page list widget to installer wizard (QTIFW-1755) - Add function to enable button click with objectname (QTIFW-1707) - Add support for disabling CLI features from configuration file (QTIFW-1760) - Fix interrupt() call from script - CLI: Add option to read arbitrary user input (QTIFW-1631) - Use default button if auto-answer value not found - Fix addElevatedOperation prevents installing from CLI (QTIFW-1700) - Add possibility to accept licenses from CLI (QTIFW-1742, QTIFW-1745) - Answer queries from command line (QTIFW-1739) - Fix creation of local repository with elevated permissions (QTIFW-1500) - Update minimum required Qt version to Qt5.12.7 - Add new option --auto-answer (QTIFW-1740) - Allow setting IFW_LIB_PATH with qmake - Add possibility to auto accept or reject IFW queries from CLI (QTIFW-1736) - Fix bugs in InstallIconsOperation and add unit tests (QTIFW-1715, QTIFW-1465) - Initialize user arguments earlier (QTIFW-576, QTIFW-1730) - Remove existing installation from command line (QTIFW-1574) - Add function to allow additional processes to be run (QTIFW-1019) - Add possibility to compress metadata per repository - Separate maintenance tool writing for testing purpose - Add short versions of CLI options (QTIFW-1634) - Perform headless commands without GUI dependency (QTIFW-1633) - Show progress in CLI when performing time consuming operations (QTIFW-1625) - Add command line option to start the installer binary as uninstaller (QTIFW-1639) - Change IntroductionPage radio button handling in maintenance tool (QTIFW-349) - Enable optional targetDir argument on command line installation (QTIFW-1608) - Uninstall selected packages from command line - Use of QLoggingCategory - Do not prompt admin query when command line interface is used (QTIFW-1598) - Enable command line default components installation (QTIFW-1583) - Remove obsolete sharedFlag() function - Update IFW version number - Install selected packages from CLI - Update selected components from command line - List available packages from command line - List installed packages from command line - Add regular expression support to replace operation (QTIFW-889) - Change ApplicationsDir variable on macOS to return "/Applications"(QTIFW-1011) - Add Brazilian portuguese translation file - Accept translation file names in ifw_language_COUNTRY.ts format 3.2.3 - Translation fixes (QTIFW-1435, QTBUG-75911) - Provide a means to use fixed translations for Qt and IFW 3.2.2 - Using patched Qt5.12.4 for binary builds (QTIFW-1632) - Add a command line argument to disable size check (QTIFW-1602) - Show information about updated components in repogen (QTIFW-1543) - Fix EnvironmentVariableOp undo behavior with non-persistent variables - Fix building against Qt 5.14 and newer (QTIFW-1526) - Fix devtool documentation - Fix building with msvc2013 3.2.1 - Documentation fixes - Fix QWizardPage title color (QTIFW-1557) 3.2.0 - Fix extracted files list formation in ExtractArchive operation (QTIFW-1239) - Decrease the .dat file file size by writing file names to a separate file instead of .dat (QTIFW-1448) - Use grid layout in component selection page (QTIFW-1334) - Fix addDependency functionality (QTIFW-1458) - Fix --no-proxy option in Windows (QTIFW-1445) - Fix env variable remove on Windows (QTIFW-1148) - Fix essential package update (QTIFW-1215) - Fix CreateLink operation destination string formatting on Windows (QTIFW-1443) - Gain admin rights for writing MaintenanceTool config files if needed (QTIFW-1363) - Update INSTALL file (QTIFW-1185) - Fix initially deactivated buttons when selecting components to update (QTIFW-1320) - Fix installer hang on Windows with empty command prompt window appearing (QTIFW-1250) - Add IFW version information to installerbase binary on Windows (QTIFW-1397) - Fix Mkdir undo operation fail to remove directory in Settings operation (QTIFW-1365) - Fix IFW version information not apparent on macOS (QTIFW-1396) - Update repository categories on server authentication request (QTIFW-1358) - Fix recalculation of components to install in MaintenanceTool (QTIFW-694) - Enable support for Qt 5.12. In Windows supported compilers are msvc2015 and msvc2017 (QTIFW-1312) - Set default file permissions to installer created files on Unix (QTIFW-1412) - MacOS: Fix widget overlapping in componentselection page in MacOS 10.12 (QTIFW-1437) 3.1.1 - Add fetch to the same pane with package categories (QTIFW-1284) - Change text in Select Components view when selection of components is not possible (QTIFW-1241) - Fix long description texts not properly shown by enabling scrolling (QTIFW-1308) - Fix install button string having a font name in French translation (QTIFW-1333) - Fix maintenance tool size (QTIFW-1322) - Update Russian translation - Enable links and text selection in component description fields (QTIFW-1292) 3.1.0 - Fix wizard's maximum size not to exceed screen maximum size (QTIFW-1227) - Allow maintenancetool signing in Windows (QTIFW-667) - Enable usage of categorized repositories (QTIFW-1147) - Add possibility to check/uncheck repositories with one button click (QTIFW-1132) - Update danish (da) translation for Qt installer-framework - Add attribute to mark parts of install tree unstable (QTIFW-930) -> Setting AllowUnstablecomponents to true in config.xml will * allow installing other components when there are errors in scripts * allow installing other components when there are missing dependencies * allow installing other components when there are sha mismatches in metadata * will mark the 'broken' components uninstallable in treeview - Add findFiles method (QTIFW-1094) - Enable expanding items by default - Add support dash (-) symbol in component name (QTIFW-948) - Allow comparing non-numeric versions (QTIFW-948) - Add Component::addAutoDependOn method - Teach 'binarycreator' and 'repogen' to repack packages from repository (QTIFW-925) 3.0.6 - Remove 'Your install seems to be corrupted' messagebox (QTIFW-1003) - Register virtual component for uninstall (QTIFW-1102) - Optimize ExctractArchiveOperation::fileFinished() (QTBUG-51337) - Do not reset core data values in restart (QTIFW-504) - Fix maintenancetool writing in Windows (QTIFW-1096) - Fix environment variables for XDG paths not being recognized (QTIFW-1043) - Update german translation file (QTIFW-1084) - Fix admin query retry (QTIFW-988, QTIFW-1173) - Fix install fail if there is no metadata (QTIFW-1150) - Reset meta information download result (QTIFW-1137) 3.0.5 - Decrease metadata dowload amount (QTIFW-975) - Print component warnings only in verbose mode (QTIFW-975) - Fix nested autodependency uninstall (QTIFW-1114, QTBUG-67106) - Fix crash in updater if component does not exist anymore (QTIFW-1140) 3.0.4 - Fix infinite wait if downloadable package is missing (QTIFW-1064) - Fix the maintenancetool that failing to elevate to admin (QTIFW-1010) - Fix devtool's segmentation fault when using operation - Update Japanese translation - Remove unnecessary warning (QTIFW-1022) - Fix Mkdir operation in uninstall (QTIFW-1099) - Enable building IFW with Squish support 3.0.3 - Set correct proxy type (QTBUG-65143) - Add no-proxy option (QTIFW-1085) - Fix maintenancetool icon visibility in Mac (QTIFW-1074) - Fix EnvironmentVariable operation in Windows (QTIFW-794) - Fix crash when downloadable package is missing (QTIFW-1064) - Documentation fixes 3.0.2 - Add possibility to reopen admin query (QTIFW-988) - Implement package download resume (QTIFW-5) - Use QDir::rmdir and not rmpath as that will remove more than it should - Enable HighDPI support only in Windows - Do not reset core when pressing 'Restart' (QTIFW-1017) - Update italian translation - Update russian translation - Fixed building with dynamically linked Qt (QTIFW-993) 3.0.1 - Fix install type if --online-only passed to binarycreator - Fix install fail if there are missing repositories - Fix Component Name visibility in maintenancetool - Adminauthorization freeze fixed under unix (QTIFW-934) - Enable high-DPI scaling (QTBUG-61122) - Fix maintenance tool update with silentUpdate (QTIFW-976) 3.0.0 - Change required Qt version, minimum version is now 5.6.2. - Clarify the add/remove components string to make it clearer - Fix crash at the very end of install if admin rights needed in Windows (QTIFW-943) - Make installer to check the dependency version (QTIFW-914) - Fix uninstallation on Windows when target path contains non-ascii characters - Fix installer crash when it contains replaced and replacement component (QTIFW-915) - Avoid warning messages when passing '--platform minimal' - New --silentUpdate command line option (QTIFW-906) - Allow installing compressed packages. (QTIFW-886) - Make support for modifying installations configurable. Introduces new setting 'SupportsModify' in the config.xml. - Allow the use of relative URLs to update repositories in Updates.xml. - Fix cancel button functionality in Settings->Repositories->Test. (QTIFW-832) - Introduced gui.setTextItems() method - Store lock files in temporary directory - Vertical layout for LicenseAgreement page. (QTIFW-815) - add NOMINMAX to fix compile with Qt5.7 in Windows (QTIFW-854) - Make usage of authorization fallback optional - Fix building with ICC on Windows. (QTIFW-851) - Add ApplicationsDirX86 and ApplicationsDirX64 predefined Variables. - Fixed (and greatly simplified) creating .dmg files - Add a logging category and debug print for http download - Make communication via installer.execute() Unicode safe - added two new optional arguments to installer.execute() to define the used codec. - Allow specifying the installer size in 'em' or 'ex' units - Fixed deleting files when uninstalling on OS X - Fix arguments in RegisterFileType - Add new '--sign' switch to binarycreator for signing OS X app bundles - Fix setValue saving in restart. (QTIFW-504) - Allow calling installer.setValue() with an empty string as the value. - Fixed writing log on Windows if target dir requires admin rights. - Fixed final 'Finish' message on OS X. - Resize banner image to fit default installer width. - Allow defining non-checkable items - introduces new element 'Checkable' for package. (QTIFW-773) - Added support for setting descriptions of Windows shortcuts. - Let mkdmg.sh script on OS X actually create random temporary file names. (QTIFW-780) - Fix timeout errors while building app bundles files on OS X. - Fix timezone issue in archive, simply keep the UTC time. - Optimized checking validity of target directory value on Windows. (QTIFW-673) - Remove implicit expanding vertical spacer from dynamic pages. (QTIFW-779) - Fixed compiling lib7z_facade.cpp with Visual Studio 2013. - Fixed several sudo problems eg. (QTIFW-771) - Fixed running binarycreator if the temporary directory name contains spaces. (QTIFW-787) - Fix violated assertion in error handling of binarycreator. - Automatically choose to perform uninstall if appropriate. - Implemented installer.readFile(). - Implemented support for creating URL shortcuts on Windows. - Fixed occasional crash on Windows when terminating installer. - Fix broken daylight saving time check. - Fix crash when updating admin installation with user/temp repository. (QTIFW-740) - Read UrlQueryString from settings. (QTIFW-744) - Allow to use the stylesheet to customize UI. - Add Castilian Spanish translation. - Add possibility to run silently without a gui. (QTIFW-166) - Removed {kd} and {kdupdater} prefix. - Make the installation relocatable (with some limitations). (QTIFW-653) - Add factory auto test. - Fix canceling the download done by an external call. - Print Qt version in verbose output. - Fix missing filename conversion on UNIX systems. (QTIFW-643) - Remove superfluous clone() method from operations. - Implement generic factory using c++11 variadic template feature. - Follow description on MSDN to implement time utils. (QTIFW-445) - Fix compile for gcc 4.7.3. - Convert to Qt 5 connect syntax. - Remove signal finished() overload. - Use qmake .depends instead of CONFIG += ordered. - Update archivegen. * Stop on file errors. * Better verbose/ help output. * Add support for compression level. * Do not hide symbols in statically build lib7z to use e.g. CPercentPrinter symbol in dynamic IFW builds. - Update source tree with version 9.38.beta of LZMA SDK. - Store AutoDependOn inside components.xml. - Implemented xml:lang attribute support for DisplayName tag. - Added AllUsers constant. - Enable feature live preview of dependencies. Introduces new InstallActionColumnVisible property to config.xml. - Remove scRemoteVersion, it's the same as scVersion. - Introduce a new struct PackageInfo which replaces UpdateSourceInfo. - Use positional arguments instead of options in devtool. - Add a warning if component with data contains children. - Fix reading and checking arguments of CreateShortcutOperation - Introduc new isMaintainer() method 2.0.5 - Fix hang in Windows when admin rights needed. (QTIFW-902) - Use deterministic sorting order for components. (QTIFW-833) - Resolve relative URLs from Updates.xml. - Do not fail to install or update if repository is missing 2.0.4 - Set also display name for Repository action "remove" - Adjusted wrong repogen parameter name - Fix settings test - Make Execute operation work without arguments in Windows - Add make install functionality with INSTALL_ROOT - Do not force doc build on Linux when calling "make install" - Documentation updates 2.0.3 - Update Japanese translation. - Make IFW compile with FreeBSD. (QTIFW-841) - Fix MSVC2015 build. - Revert "Use QQmlV4Function to correctly get empty parameters from script." - Fix crash when updating admin installation with user/temp repository (QTIFW-740) - Compile with Qt 5.5, 5.6. Minimum version is now 5.5. - Fix compile with namespace'ed Qt. 2.0.2 - Doc: Remove dubious sentence from installer.calculateComponentsToUninstall(). - Update documentation for --runoperation. - Update the git-archive export options. - Add alternative option where to read the installer-framework sha1. - Add sync.profile. - Add .qt-license-check.exclude and .qt-license-check.optional rules. - Update license headers. - Fix target directory check for reserved words on Windows. - Use QQmlV4Function to correctly get empty parameters from script. (QTIFW-724) - Fix errors when running updates in a directory requiring elevation. (QTIFW-746) - Doc: Fix the function name in Controller Scripting page. - Fix usage of system proxy with credentials. (QTBUG-46547) - Unify handling of translations. QTIFW-390 - Init all components with proper install action. (QTIFW-727) - Fix .dat file that gets deleted after multiple component changes on Windows. - Fix maintenance tool upgrade on OS X. - Fix handling of system proxy with credentials. (QTBUG-46547) - Unify selection of language for translations. (QTIFW-390) - Fix return value of component.installAction() when updating. (QTIFW-727) - Fix errors when updating an installation requiring elevation on Windows. (QTIFW-746) - Documentation updates. 2.0.1 - Do not throw exception on empty translation files. - Fix --checkupdates mode. - Prevent disabled component to be selected using the Select All button. (QTIFW-635) - Windows: Fix crashes in elevated installation. (QTIFW-6656, QTIFW-659) - OS X: Fix problems with writing settings in elevated installation (QTIFW-709) - Fix crash on exit for Windows XP, Vista. (QTIFW-652) - Re-add handling of zero compression level files supported by 7z. - Improve Proxy Credentials dialog. - Make component checker warning optional (set QT_LOGGING_RULES=ifw.componentChecker=true to enable). - Make code ready to be compiled with Qt 5.5. - Documentation updates. 2.0.0 - Require Qt 5.4 as a minimal version, Qt 4 code removed. - Only support Qt 5 on documentation side as well. - Source code is now available also under LGPLv3. - Changed the default value of AllowSpaceInPath in config.xml to true. - Made cycles in component dependencies fatal. - Respect AllowSpaceInPath everywhere. - Fixed crash while canceling the meta data unzip task. - Fixed replacing of the maintenance tool binary. - Introduced new classes for client-server communication. - Replaced qscript with js engine. - Added an example how to use dynamic pages. - Added an example how to ask for a license agreement. - Provided an API to get all wizard pages from java script. (QTIFW-477) - Made the installer binary paths available for scripts. (QTIFW-424) - Fixed possible case of uninstalling all of Windows. (QTIFW-511) - Stopped trying to get admin rights on Windows if impossible. - Introduced developer tool. - Improved checking of Installationpath and better reporting to user. (QTIFW-468, QTIFW-512) - Fixed detailwindow not following content. (QTIFW-353) - Log messages are now prefixed with a timestamp. (QTIFW-496) - Renamed settings inside config.xml: - UninstallerName renamed to MaintenanceToolName (default value changed to "maintenancetool") - UninstallerIniFile renamed to MaintenanceToolIniFile - Windows: Re-use parent console for verbose output if possible - Fixed disk space checking for updates. (QTIFW-434) - List disk space requirements prior to installation. (QTIFW-16) - Toggle details with verbose mode. (QTIFW-140) - Implemented progress indicator on taskbar on Windows. (QTIFW-15) - Added --framework-version argument. - Fixed the uninstaller calculator. - Fixed broken command line parsing. - Fixed binary data extraction. (QTIFW-574) - Fixed uninstall after installing into a target with elevated permissions. (QTIFW-447, QTIFW-479) - Allow spaces in RunProgramArguments. (QTIFW-227) - Removed some deprecated things. - Removed SetQtCreatorArrayValue, AddQtCreatorArrayValue operations. - Removed ApplyProductKey, ReplaceInstallNames, QtPatch operations. - Added systemInfo to the scripting API. (QTIFW-592) - Changed default of 'AllowSpaceInPath' from false to true. - Added possibility to specify a control script on installer creation. (QTIFW-166, QTIFW-495) - Introduced a setting for Wizard default height and width. (QTIFW-47) - Added CreateLocalRepository configuration option. - Simplified registration of objects into the script engine. - Made sure widgets from .ui files are properly registered to the engine. - No longer use Version as the repository format version. - Introduced InstallAction property for components. - Marked "os" variable as deprecated. - Show "Forced" component as enabled, but without checkbox. (QTIFW-491) - Fixed running out of sockets in server. - No longer show checkbox for autodependent components. - No longer defer deletion of sockets in RemoteObject. - Fixed loading of translations. - Set objectName for QThread. - Use local sockets for client-server communication. (QTIFW-228) - Fixed handling of incomplete messages in client-server communication. - Improved the examples and their documentation. - Added and improved documentation. (QTIFW-526) - Added translations: Polish, Italian - Updated and improved translations. - Fixed various bugs. (QTIFW-397, QTIFW-469, QTIFW-481, QTIFW-524, QTIFW-538, QTIFW-541, QTIFW-542, QTIFW-562, QTIFW-564, QTIFW-568, QTIFW-569, QTIFW-583, QTIFW-589, QTIFW-593, QTIFW-600, QTIFW-602, QTIFW-605, QTIFW-612, QTIFW-615, QTIFW-616, QTIFW-618, QTIFW-620, QTIFW-621, QTIFW-622, QTIFW-625, QTBUG-633) Thanks go to Christoph VogtlÃĪnder, Sze Howe Koh, Ray Donnelly, Tasuku Suzuki, Takayuki Orito, Sascha Cunz, Zhang Xingtao, Sergey Belyashov and Cuoghi Massimiliano for contributions. 1.6.0 - No longer requires Xcode command line tools on Mac. (QTBUG-38015) - Use local encoding to parse executable output in ConsumeOutput. - Avoid 'Too many open files' on Mac. - Fixed HTTP proxy settings not having any effect. (QTIFW-498) - Made it possible to calculate dependencies from script. (QTIFW-503) - Bugfixes (QTBUG-38343, QTIFW-488) - Code cleanup 1.5.1 - The checkupdates option handles no-network situations better. (QTIFW-431) - Fixed random crash while accessing arguments. - Fixed I18N on Windows. - Qt5 compatibility fixes. - Fixed for path handling on Windows. - Fixed preselection of components from another component. - Added operationExists method on script side. - Unified access to the supported schemes. - Implemented missing setNativeArguments wrapper. (QTIFW-310) - Fixed banner image not working in dynamic pages. (QTIFW-471) - Fixed hang when entering wrong sudo password. (QTIFW-409 and QTIFW-451) - Documentation improvements. - Updated translations. Thanks go to Takumi Asaki and Sergey Belyashov for contributions. 1.5.0 - Fixed generation of random temp directory name. (QTIFW-427) - Now reuses http proxy settings for https. - Allow a page to force showing the settings button. - Read qmake output even if it crashed. - Implemented factory to be able to insert wizard pages dynamically. - Open a console window (Windows) to show the verbose output. (QTIFW-403) - Added new settingsoperation. - Offline installer do not require any temporary space. - Now .dmg files are named after the application bundle on Mac OS X. - Introduced ApplicationsDir variable. (QTIFW-258) - Now never delete the install directory if it's not empty. - Environment variables changes are now propagated to the system. (QTIFW-391) - Build installers with accessibility plugin. (QTBUG-34296) - Improved documentation. - Minor bugfixes. 1.4.1 - Added support to pass a query string when downloading archives. (QTIFW-329) - Fixed progress display for redirected HTTP Downloads. (QTIFW-267) - Add support to repogen to update only newer components. (QTIFW-234) - Don't show RunProgram after uninstall. (QTIFW-366) - Fix broken random name generation for temporary directories. (QTIFW-354) - Removed unnecessary WindowModal in the gui. (QTIFW-364) - Made some previously missed elements scriptable. (QTIFW-372) - Fixed searching for magic marker. - Now create the temp remoterepo directory later to avoid conflicts. - Disable close button during installer run to avoid crashes. - Child repositories added by setTempRepository are no longer default. (QTIFW-373) - Ignore filtered repositories as early as possible to avoid hang. - Connect extract operation to progress calculation. (QTIFW-11, QTIFW-141) - Fixed target dir for root installations and empty AdminTargetDir. - Fixed broken dependency resolver. - Implemented a way to replace the default resource. - Renamed forceRestart to needsHardRestart. - Made installer apps retina-ready. - Restart on the wizard now cleans up component leftovers. - Read file content in case mmap fails (fallback). (QTIFW-400) - Added more autotests. - Improved documentation. - Minor bugfixes. 1.4 - Force updating of Essential components. (QTIFW-38, QTIFW-155) - Display release date in Updater and Packagemanager. (QTIFW-25) - Fixed a crash in the package manager. (QTIFW-313) - Fixed component selection showing wrong package sizes. (QTIFW-302) - Better handling of dependencies while updating. (QTIFW-318) - Now allows to ignore SSL errors. - Implemented dedicated translation settings support. - Added exceptionhandler code for connected signals/JS methods. - Now properly calculates the file size for symlinks. (QTIFW-137) - Fixed downloading when the server redirects. - Changed two fatals to warnings. - Added errorString to execute operation error output. - Implemented configuration interface. (QTIFW-196) - Introduced no_app_bundle.pri for Mac. - Added a change installer ui example. - Added entered/left signals to pages. - Forwarded packagemanager core to ProductKeyCheck class. - Added installerscriptengine. - Replaced the external date and time implementation. - Now only uses the basic LZMA SDK (instead of all of 7zip). - Forwarded make "check" target to autotests. - Added documentation for JS API. - Fixed messageboxhandler. - Added INSTALL file, cleaned up README. - Now sets the subTitle to " " if empty on Linux as well. - Now checks for os-release instead of lsb-release on Linux. - Added getrepositorycontent tool. - Now provides documentation for Vendorprefix parameter. - Fixed output of line number in log. - Fixed broken update behavior (in the size and description label). - Binarycreator now assumes offline installer if there are no repositories. (QTIFW-224) - Rewrote copy configuration function. (QTIFW-221) - Added banner pixmap to the wizard. - Removed previously deprecated Pages config.xml element. - Deprecated Icon, introduce replacements for config.xml. - Added component model behavior auto test and fix broken model. (QTIFW-84, QTIFW-213) - Made CreateShortcut operation a NOOP on non-Windows systems. - Added RunProgramArguments to config.xml. - Qt5 SDK specific fixes. - Minor documentation fixes and additions. - Added more autotests. - Bugfixes - Added Japanese translation. - Updated translations - Cleaned up the Code. 1.3.1 - Fixed missing magic cookie in installer binary on Mac. (QTIFW-322) - Fixed UNDO of MkDirOperation and CopyOperation. - Enabled Qt4 patch syntax in QtPatchOperation. - Added the OS attribute to be compatible with old sdks. - Show the error string not the empty errorString when parsing Settings. - Now continues on unknown operations. - Fixed error handling in 7z lib. - Added a DisplayName setting for repositories. (QTIFW-244) - Chinese Translation added - Documentation fixes and additions. - Bugfixes (QTIFW-271 et al) qt-installer-framework-4.0.1/coin/0040777000000000000000000000000013761647206014030 5ustar00qt-installer-framework-4.0.1/coin/create_ifw_installer.py0100777000000000000000000001160013761647206020565 0ustar00#!/usr/bin/env python3 # -*- coding: utf-8 -*- ############################################################################# ## ## Copyright (C) 2020 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# ############################################################################# # Adapted from bld_ifw_tools.py and bldinstallercommon.py in qtsdk repository ############################################################################# import sys import os import platform import argparse import shutil from typing import Generator from subprocess import check_call from contextlib import contextmanager @contextmanager def cd(path: str) -> Generator: oldwd = os.getcwd() os.chdir(path) try: yield finally: os.chdir(oldwd) def create_installer_package(src_dir: str, bld_dir: str, target_dir: str, target_name: str): print('Creating installer for Qt Installer Framework') # Temporary dir for creating installer containing the Qt Installer Framework itself package_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ifw-pkg') os.makedirs(package_dir, exist_ok=True) # Final directory for the installer containing the Qt Installer Framework itself os.makedirs(target_dir, exist_ok=True) # Copy binaries to temporary package dir shutil.copytree(os.path.join(bld_dir, 'bin'), os.path.join(package_dir, 'bin'), ignore=shutil.ignore_patterns("*.exe.manifest", "*.exp", "*.lib")) # Remove symbol information from binaries if sys.platform == 'linux': with cd(package_dir): check_call(["strip", os.path.join(package_dir, 'bin/archivegen')]) check_call(["strip", os.path.join(package_dir, 'bin/binarycreator')]) check_call(["strip", os.path.join(package_dir, 'bin/devtool')]) check_call(["strip", os.path.join(package_dir, 'bin/installerbase')]) check_call(["strip", os.path.join(package_dir, 'bin/repogen')]) # Copy remaining payload to package dir shutil.copytree(os.path.join(bld_dir, 'doc'), os.path.join(package_dir, 'doc')) shutil.copytree(os.path.join(src_dir, 'examples'), os.path.join(package_dir, 'examples')) shutil.copy(os.path.join(src_dir, 'README'), package_dir) # Create 7z archive_file = os.path.join(src_dir, 'dist', 'packages', 'org.qtproject.ifw.binaries', 'data', 'data.7z') os.makedirs(os.path.dirname(archive_file), exist_ok=True) with cd(package_dir): check_call([os.path.join(package_dir, 'bin', 'archivegen'), archive_file, '*']) # Run binarycreator binary_creator = os.path.join(bld_dir, 'bin', 'binarycreator') config_file = os.path.join(src_dir, 'dist', 'config', 'config.xml') package_dir = os.path.join(src_dir, 'dist', 'packages') target = os.path.join(target_dir, target_name) with cd(package_dir): check_call([binary_creator, '--offline-only', '-c', config_file, '-p', package_dir, target]) print('Installer package is at: {0}'.format(target)) if __name__ == "__main__": parser = argparse.ArgumentParser(prog="Script to create an installer which can be used to install the Qt IFW libraries and tools.") parser.add_argument("--src-dir", dest="src_dir", type=str, required=True, help="Absolute path to the installer framework source directory") parser.add_argument("--bld-dir", dest="bld_dir", type=str, required=True, help="Absolute path to the installer framework build directory") parser.add_argument("--target-dir", dest="target_dir", type=str, required=True, help="Absolute path to the generated installer target directory") parser.add_argument("--target-name", dest="target_name", type=str, required=True, help="Filename for the generated installer") args = parser.parse_args(sys.argv[1:]) create_installer_package(args.src_dir, args.bld_dir, args.target_dir, args.target_name) qt-installer-framework-4.0.1/coin/instructions/0040777000000000000000000000000013761647206016574 5ustar00qt-installer-framework-4.0.1/coin/instructions/common_environment.yaml0100777000000000000000000000311513761647206023374 0ustar00type: Group instructions: - type: Group enable_if: condition: property property: target.compiler in_values: [MSVC2015, MSVC2017, MSVC2019] instructions: - type: EnvironmentVariable variableName: MAKEFLAGS variableValue: "" - type: PrependToEnvironmentVariable variableName: PATH variableValue: "{{.InstallDir}}\\bin;" enable_if: condition: property property: target.os equals_value: Windows - type: PrependToEnvironmentVariable variableName: PATH variableValue: "C:\\Utils\\gnuwin32\\bin;" enable_if: condition: property property: target.os equals_value: Windows - type: PrependToEnvironmentVariable variableName: PATH variableValue: "{{.Env.MINGW730}}\\bin;" enable_if: condition: property property: target.compiler equals_value: Mingw73 - type: PrependToEnvironmentVariable variableName: PATH variableValue: "{{.Env.MINGW530}}\\bin;" enable_if: condition: property property: target.compiler equals_value: Mingw53 - type: EnvironmentVariable variableName: LANG variableValue: en_US.UTF-8 enable_if: condition: property property: host.os in_values: [MacOS, Linux] - type: Group instructions: - type: PrependToEnvironmentVariable variableName: PATH variableValue: "{{.InstallDir}}/bin:" - type: EnvironmentVariable variableName: DISPLAY variableValue: ":0" enable_if: condition: property property: host.os equals_value: Linux qt-installer-framework-4.0.1/coin/instructions/execute_bic_tests.yaml0100777000000000000000000000247413761647206023170 0ustar00type: Group enable_if: condition: and conditions: - condition: property property: host.os equals_value: Linux - condition: property property: target.os equals_property: host.os - condition: property property: configureArgs not_contains_value: "-no-widgets" instructions: - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qt/qtqa ref: master directory: qt/qtqa userMessageOnFailure: "Could not install qt/qtqa source archive. Please investigate why." - type: EnvironmentVariable variableName: QT_MODULE_TO_TEST variableValue: "{{.SourceDir}}" - type: ChangeDirectory directory: "{{.AgentWorkingDir}}/qt/qtqa/tests/postbuild/bic" - type: ExecuteCommand command: ['{{.InstallDir}}/bin/qmake'] maxTimeInSeconds: 1800 maxTimeBetweenOutput: 1800 userMessageOnFailure: "Failed to run qmake, check logs." - type: SetExecutionPhaseName executionPhaseName: "testing {{.AgentWorkingDir}}/qt/qtqa/tests/postbuild/bic" - type: RunQtUnitTest directory: "{{.AgentWorkingDir}}/qt/qtqa/tests/postbuild/bic" runTestCommand: ['make', 'check', '-j1'] maxTimeInSeconds: 1800 maxTimeBetweenOutput: 600 testRepetitionAllowance: 1 userMessageOnFailure: "Failed to execute bic tests." qt-installer-framework-4.0.1/coin/instructions/execute_license_check.yaml0100777000000000000000000000157613761647206023772 0ustar00type: Group instructions: - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qt/qtqa ref: master directory: qt/qtqa userMessageOnFailure: "Could not install qt/qtqa source archive. Please investigate why." - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qt/qtbase ref: 5.12.7 directory: qt/qtbase userMessageOnFailure: "Could not install qt/base source archive. Please investigate why." - type: ChangeDirectory directory: "{{.AgentWorkingDir}}" - type: ExecuteCommand command: ["perl", "{{.AgentWorkingDir}}/qt/qtqa/tests/prebuild/license/tst_licenses.pl"] maxTimeInSeconds: 7200 maxTimeBetweenOutput: 120 userMessageOnFailure: "Running license check failed." enable_if: condition: property property: features contains_value: LicenseCheck qt-installer-framework-4.0.1/coin/instructions/find_msvc_compiler.yaml0100777000000000000000000000426213761647206023326 0ustar00# Finds correct msvc compiler for target and writes path to it into "VC_SCRIPT" environment variable # and write bat script for calling compiler. type: Group instructions: - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%VS90COMNTOOLS%\\vsvars32.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2008 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%VS100COMNTOOLS%\\vsvars32.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2010 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%ProgramFiles(x86)%\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2012 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%ProgramFiles(x86)%\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2013 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%ProgramFiles(x86)%\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2015 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%ProgramFiles(x86)%\\Microsoft Visual Studio\\2017\\Professional\\VC\\Auxiliary\\Build\\vcvarsall.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2017 - type: EnvironmentVariable variableName: VC_SCRIPT variableValue: "%ProgramFiles(x86)%\\Microsoft Visual Studio\\2019\\Professional\\VC\\Auxiliary\\Build\\vcvarsall.bat" enable_if: condition: property property: host.compiler equals_value: MSVC2019 - type: WriteFile fileContents: "call \"{{.Env.VC_SCRIPT}}\" {{.Env.TARGET_ARCHITECTURE}} \r\ncmd /c %*" filename: "c:\\users\\qt\\MSVC.bat" fileMode: 420 enable_if: condition: property property: host.compiler in_values: [MSVC2008, MSVC2010, MSVC2012, MSVC2013, MSVC2015, MSVC2017, MSVC2019] qt-installer-framework-4.0.1/coin/instructions/install_module_test_artifact.yaml0100777000000000000000000000045213761647206025410 0ustar00type: Group instructions: - type: InstallBinaryArchive relativeStoragePath: "{{.Env.MODULE_ARTIFACTS_RELATIVE_STORAGE_PATH}}/artifacts.tar.gz" directory: "{{.SourceDir}}" maxTimeInSeconds: 1200 maxTimeBetweenOutput: 1200 userMessageOnFailure: Failed to install tests archive. qt-installer-framework-4.0.1/coin/instructions/make_check_instructions.yaml0100777000000000000000000001005213761647206024354 0ustar00type: Group disable_if: condition: property property: features contains_value: LicenseCheck instructions: - type: EnvironmentVariable variableName: QTEST_ENVIRONMENT variableValue: "ci" - type: EnvironmentVariable variableName: TESTRUNNER variableValue: "{{.Env.CI_WINRTRUNNER_PATH}}\\winrtrunner.exe" enable_if: condition: property property: target.os equals_value: WinRT - type: Group instructions: - type: ChangeDirectory directory: "{{.SourceDir}}/tests" maxTimeInSeconds: 300 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to change into tests directory." - type: ExecuteCommand command: "{{.InstallDir}}/bin/qmake.exe INSTALL_PREFIX={{.InstallDir}} IFW_LIB_PATH={{.InstallDir}}/lib" maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed running qmake, check logs." - type: ExecuteCommand command: Mingw32-make maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run make, check logs." - type: ChangeDirectory directory: "{{.SourceDir}}/tests/auto" maxTimeInSeconds: 300 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to change directory." - type: RunQtUnitTest directory: "{{.SourceDir}}/tests/auto" testRepetitionAllowance: 3 runTestCommand: ["Mingw32-make", "check", "-j1"] maxTimeInSeconds: 3600 maxTimeBetweenOutput: 600 userMessageOnFailure: "Test execution failed, check logs." enable_if: condition: property property: target.compiler in_values: [Mingw53, Mingw73] - type: Group instructions: - type: ChangeDirectory directory: "{{.SourceDir}}/tests" maxTimeInSeconds: 300 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to change into tests directory." - type: ExecuteCommand command: "{{.InstallDir}}/bin/qmake INSTALL_PREFIX={{.InstallDir}} IFW_LIB_PATH={{.InstallDir}}/lib" maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed running qmake, check logs." - type: ExecuteCommand command: make maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run make, check logs." - type: RunQtUnitTest runTestCommand: ["make", "check", "-j1"] directory: "{{.SourceDir}}/tests/auto" testRepetitionAllowance: 3 maxTimeInSeconds: 36000 maxTimeBetweenOutput: 1200 userMessageOnFailure: "Test execution failed, check logs." enable_if: condition: property property: target.compiler in_values: [GCC, Clang] - type: Group instructions: - type: ChangeDirectory directory: "{{.SourceDir}}/tests" maxTimeInSeconds: 300 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to change into tests directory." - type: ExecuteCommand command: "c:{{.InstallDir}}\\bin\\qmake.exe INSTALL_PREFIX={{.InstallDir}} IFW_LIB_PATH={{.InstallDir}}/lib" maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed running qmake, check logs." - type: ExecuteCommand command: "jom" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run jom/make, check logs." - type: ChangeDirectory directory: "{{.SourceDir}}/tests/auto" maxTimeInSeconds: 300 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to change dir" - type: RunQtUnitTest testRepetitionAllowance: 3 directory: "{{.SourceDir}}/tests/auto" runTestCommand: ["jom", "check"] maxTimeInSeconds: 3600 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed to run make check, check logs." enable_if: condition: property property: target.compiler in_values: [MSVC2013, MSVC2015, MSVC2017, MSVC2019] qt-installer-framework-4.0.1/coin/instructions/make_documentation.yaml0100777000000000000000000000077613761647206023340 0ustar00type: Group enable_if: condition: property property: features contains_value: Documentation instructions: - type: ChangeDirectory directory: "{{.BuildDir}}" - type: ExecuteCommand command: ['make', 'docs'] userMessageOnFailure: 'Could not build documentation.' maxTimeInSeconds: 1200 maxTimeBetweenOutput: 1200 - type: UploadArtifact archiveDirectory: '{{.BuildDir}}/doc' transferType: UploadModuleDocumentation maxTimeInSeconds: 1800 maxTimeBetweenOutput: 1800 qt-installer-framework-4.0.1/coin/instructions/make_instructions.yaml0100777000000000000000000000462513761647206023230 0ustar00type: Group instructions: - type: Group instructions: - type: ExecuteCommand command: Mingw32-make maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run make, check logs." - type: ExecuteCommand command: "Mingw32-make -j1 install INSTALL_ROOT={{.InstallRoot}}" maxTimeInSeconds: 1800 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed to run make install, check logs." enable_if: condition: and conditions: - condition: property property: host.os equals_value: Windows - condition: property property: target.compiler in_values: [Mingw53, Mingw73, Clang] - type: Group instructions: - type: ExecuteCommand command: make maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run make, check logs." - type: ExecuteCommand command: "make install INSTALL_ROOT={{.InstallRoot}}" maxTimeInSeconds: 1800 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed to run install, check logs." enable_if: condition: and conditions: - condition: property property: host.os not_equals_value: Windows - condition: property property: target.compiler in_values: [GCC, Clang, ICC_17, ICC_18] - type: Group instructions: - type: ExecuteCommand command: "jom" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run jom/make, check logs." - type: ExecuteCommand command: "nmake install INSTALL_ROOT={{.InstallRoot}}" maxTimeInSeconds: 1800 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed to run nmake install, check logs." enable_if: condition: property property: target.compiler in_values: [MSVC2013, MSVC2015, MSVC2017, MSVC2019] - type: SignPackage directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}" maxTimeInSeconds: 1200 maxTimeBetweenOutput: 1200 enable_if: condition: property property: host.os equals_value: Windows - type: UploadArtifact archiveDirectory: "{{.InstallRoot}}/{{.AgentWorkingDir}}" transferType: UploadModuleBuildArtifact maxTimeInSeconds: 1800 maxTimeBetweenOutput: 1800 qt-installer-framework-4.0.1/coin/instructions/make_test_plan.yaml0100777000000000000000000000270613761647206022453 0ustar00type: Group disable_if: condition: property property: features contains_value: DisableTests instructions: - type: EnvironmentVariable variableName: QMAKEFEATURES variableValue: "{{.AgentWorkingDir}}/test_plan_hook" - type: WriteFile fileContents: "load(default_post) testcase|qmltestcase { !build_pass:contains(TEMPLATE, \".*(lib|app)\"):!insignificant_test:write_file($$PWD/TestLibTestPlan, OUT_PWD, append) } else:if(ctest_testcase) { !insignificant_test:write_file($$PWD/GeneralTestPlan, OUT_PWD, append) }" filename: "{{.AgentWorkingDir}}/test_plan_hook/default_post.prf" fileMode: 420 - type: ChangeDirectory directory: "{{.SourceDir}}/tests" - type: ExecuteCommand command: "c:{{.BuildDir}}\\bin\\qmake.exe -r {{.SourceDir}}\\tests" maxTimeInSeconds: 6000 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed running qmake, check logs." enable_if: condition: property property: target.compiler in_values: [MSVC2013, MSVC2015, MSVC2017, MSVC2019] - type: ExecuteCommand command: "{{.BuildDir}}/bin/qmake -r {{.SourceDir}}/tests" maxTimeInSeconds: 6000 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed running qmake, check logs." enable_if: condition: property property: target.compiler not_in_values: [MSVC2013, MSVC2015, MSVC2017, MSVC2019] - type: UploadTestPlan qtestlibTestPlanPath: "{{.AgentWorkingDir}}/test_plan_hook/TestLibTestPlan" qt-installer-framework-4.0.1/coin/instructions/qmake_module_build.yaml0100777000000000000000000000172613761647206023310 0ustar00type: Group instructions: - type: MakeDirectory directory: ".git" - type: SetBuildDirectory directory: "{{.SourceDir}}" disable_if: condition: property property: features contains_value: OutOfSourceBuild - type: Group instructions: - type: SetBuildDirectory directory: "{{.AgentWorkingDir}}/build" - type: MakeDirectory directory: "{{.BuildDir}}" enable_if: condition: property property: features contains_value: OutOfSourceBuild - type: ChangeDirectory directory: "{{.BuildDir}}" - type: ExecuteCommand command: ["{{.InstallDir}}/bin/qmake", "INSTALL_PREFIX={{.InstallDir}}", "{{.SourceDir}}"] maxTimeInSeconds: 1800 maxTimeBetweenOutput: 600 userMessageOnFailure: "Failed to run qmake, check logs." - !include "{{installer-framework/installer-framework}}/make_instructions.yaml" - !include "{{installer-framework/installer-framework}}/make_documentation.yaml" qt-installer-framework-4.0.1/coin/module_config.yaml0100777000000000000000000000505013761647206017526 0ustar00version: 2 accept_configuration: condition: or conditions: - condition: property property: features contains_value: LicenseCheck - condition: property property: features contains_value: Documentation - condition: and conditions: - condition: property property: features contains_value: Packaging - condition: property property: configureArgs contains_value: -static common_environment: &common_environment type: Group instructions: - !include "{{installer-framework/installer-framework}}/common_environment.yaml" make_instructions: &make_instructions type: Group instructions: - !include "{{installer-framework/installer-framework}}/qmake_module_build.yaml" make_check_instructions: &make_check_instructions type: Group instructions: - type: MakeDirectory directory: .git userMessageOnFailure: Failed to create .git dir, not related to patch - !include "{{installer-framework/installer-framework}}/make_check_instructions.yaml" run_license_check: &run_license_check type: Group enable_if: condition: property property: features contains_value: LicenseCheck instructions: - type: EnvironmentVariable variableName: QT_MODULE_TO_TEST variableValue: "installer-framework/installer-framework" - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qt/qtqa ref: master directory: qt/qtqa userMessageOnFailure: "Could not install qt/qtqa source archive. Please investigate why." - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qt/qtbase ref: 5.12 directory: qt/qtbase userMessageOnFailure: "Could not install qt/base source archive. Please investigate why." - type: ChangeDirectory directory: "{{.AgentWorkingDir}}" - type: ExecuteCommand command: ["perl", "{{.AgentWorkingDir}}/qt/qtqa/tests/prebuild/license/tst_licenses.pl"] maxTimeInSeconds: 7200 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to execute license checker." instructions: Build: - *common_environment - !include "{{installer-framework/installer-framework}}/find_msvc_compiler.yaml" - *make_instructions Test: - *common_environment - *run_license_check - *make_check_instructions LicenseCheck: - *run_license_check qt-installer-framework-4.0.1/dist/0040777000000000000000000000000013761647206014043 5ustar00qt-installer-framework-4.0.1/dist/config/0040777000000000000000000000000013761647206015310 5ustar00qt-installer-framework-4.0.1/dist/config/config.xml0100777000000000000000000000076313761647206017305 0ustar00 Qt Installer Framework Qt Installer Framework @IFW_VERSION_STR@ @IFW_VERSION_STR@ Qt Project http://qt-project.org watermark.png Uninstaller @HomeDir@/Qt/QtIFW-@IFW_VERSION_STR@ qt-installer-framework-4.0.1/dist/config/watermark.png0100777000000000000000000000654613761647206020026 0ustar00‰PNG  IHDRĪ:Ŋp ôļPLTEĸĸĸŠŠŠŅŅŅkkk&&&éééôôôBBBÝÝÝČå­ļļļXXX}}}œœœÅÅÅĀáĄÐéđØėÄĸĸþÃCïũį„ÅIþĸþÚíĮļݕ˜Ïf…ÆJøûôÂâĪŨėÄĻÖ}îũæ’Ë]‚ÄFØíÅŪŲ‡õúðëöá‡ĮMíöäŊ؈šÏiÔëŋõúïĮäŦ­Ø…þþýÅãĻßðÏÍįīƒÅGÎčķųüöÃã͜ÐlüýúåóØøüõŠČRóųíýþûæóڞŅoËZîũåôúï‚ÄE‹ČRŪŲ†ÜîĘûýøˆĮOŲíÆĶÕzĻÖ~žß›ûýųĘY˜ÎfŨėßŌpēی†ÆLŸŌqŽĘWĪÔx§Õ|ýþüšß™ąÚ‹ŋᠰډéõÞųüõ–ÎcÄã§ũûóüþûŅéŧĘæ°™ÏhÂâĨĢÔw‡ÆLũûōÕëÁŠŨ€âņԋČSÄDÏčļŲíĮ—ÎeĮåŽĨÔyŌęžãōՌÉU•Ía™ÏgīÛÉæŊĢÓv•Íbúüũ”Ė`ÝïĖđޖĨÕzðøéŠČQÚîČÛîÉÓęūģÛŽŽØ„ĩܑިƒäōŨŅéš―āčôÝŠŨúýø°ÚŠėöâÁâĢĶÕ{ÉU—ÎdëõáŋៈĮN„ÅHōųėĀáĒ›Ðk†ÆKÜïËŧߙāðÐôúîíũäčôÜÏč·ŧߚÞïÍĐÖ”Í`“Ė^áņŌÉVÁâĒīܐÉåŪņøęáņÓūāžĄÓsĄÓtķܒōųëÆäŠéôÞŦŨ‚âņӝŅmÖëÁžŅnÃãĨēۍĐŨ€Ðč―Čâ·Íįĩ”ËcÞï΅ÅIįóÛęõßķݓĘXūāŸ–ÍcËæąÛîĘÂā­Óę―äō֑Ë\ ŌrÆäŦóųėļޖÅäĐ  Ī·Ý”‘Ë[ŒÉTĖįģ―āœāðŅöûōæóŲ ŌqÖėÂĒÓt€ÃBƒÄF€ÃCFĢd iIDATx^ėÎG€@°õïpŊQ‹ <ð:f‰üČ˜žä’’’’’’’’’’’’’’’’’’’’’’ÛØÛsÝõ,}YįL/;ũÕÔÆ`xïu… Ēc$#Ā–€"ÔP{/ĶÅôÞL‰{{Ü{ï-.é―ũÞ{ģÁƒ39Ōß įûÖŌdqÎɌūÛũۙg–ŅîÚQ9ģ―zęæb!S{ˆĢ ŋpäO_o1o­& Ģũ ŠŦįŒüj;ųï1ŪøvŨõR^Čū 2ëŅýrüÆpR3{ä"2įĐŲp'öŲq†ČUÄÕÉĐÞĢúüäqōpžpä7_oíž"S‡ˆ;FïŸ|ī~žąÄcün aŨÁD·#ũ·ÎPwCïFd ™ŊĐéų#ÖMČ%d>ĮMȇ2xĪéAzöŒU~%/ė~õ9Q‘šÚýY3‹m…_#Ōū7SķŦÝđA0ä‰Gë7OŠ„ž`qžßîg'ō1ĪÎō@þšėôģMN‰ãMyđŒ‘Ï*Rh”QŽN[d@˜â1cX’"qAŪ—”į)$)æ‚ôũÁĶäÂNģ7Dnʀ’H.Č…ØØ}q"Ø·nĘ<(IâôĮÆÆéŌ”SČÅhȕȸýLļ›LÃ;ōÄŲ›{āZķ€Ð59ÏđõHPâ,4Xg 1<yĻŊ…Đ•†øļé`Ėį€<›ģÉ[(['Âō—5VĩÄųĘÁĻéúhųt"h oßΎåÖ%0@vĢ܀Ģ/-™‰G͙‡ōŽA ­æˆžŠōZĢ@:Äyį\@zžēÕDYMÃ؈ę6YÍ-‚ō<ŠiōH[ŧ –WvP@ęuoK>äÓĻÆČsˆĢ“ÁKÂsû™‚ųGŽ ,ÏI .ĶHÆwœeĻŠåųˆEܐaĘH ˆđܐT­ōÜâëܐĻŠäY â+ĸĪ7ĪŠ‘JWĻVnH\―äY…NģéúŸûE„ĸƒĢŒô|šÏĄjUB6ˆz[ėŅrßėïÝKđ!ŸDuDž}A|›r?ŠË”žä*đ![Q “įS n憞ƒj–<§‚Î đÕhyNĪ­pCnTüį€Ī4~H›Ę'q-ÉĖIŪĄ\‡c:Hũ8"Í(?Žc(HE‘[”n9Ý rDū‹r“ÓŊĄ"Gdv2ĖÚpģhąōD’`ԋņõ Œãö=ŽĶJ@2D†'ÂßK‹.“†ũĶ(ājöÔV $éwvŠĄvšQ*=Ņ'óöcLGČņœ™Sü ™CŽ–ÛM“ ’$!å%ÛT°ípôî@ĀcĀ؃W~ș e1ĀbĢōœdVnZYrzą"ę(æ…ĖhV>č'°Ŧû™’„*ŊõÂ]ƒ WÓ FHōĶ‚ŅdĀŧ·Ō–lūe$ސš§Æß[äËŲ·†O™[î›/ŋO… ÄéĘV&Ōû“‡ÚK‰HH’ē^~ĄnîŽïÞœËũĩĀŋDзĢáŲÜ,(’Ž‚ODĒ"?Č0 ČJļýá܌6VČĄ,€LühNČŧސD…öC>þäĮÏf‹,b†ž-ÉgÁl‘AːDã22rM―‹HƒÄINŧˆŒd‰ÔUļ„Œg‰$ķXWÃ$œÚ+sFÖiY ņŠ:+bŪhÆîíNøb6Ɩ@‰Ōõ)·HÂ#ũ–G4~)Iâ"㞈 ŽÐb$æES€PHĖĐũÏÅ<þHĖ }taˆ…Ä<ᐘ'óÄCtžxȀŋĄŋ #ó„CbžHHÄû·{Ëu܆Á,’Ēnd?š…öĐ{éæŧ›šTÔQėÎL3ƒ q0ąėüâwd;—y8#ũßCþņžý=CԐ†4Ī! iHCԐ†4Ī! iHCԐ†4Ī! iHCԐ†4Ī!Έ{ø Ęlôadņ0Š‚2h1Æ"+@BĒ}KøĶ·ŨÆÂŲZür˜ļw'MþĨ12äĮVƒþ1dšÆ·+ĀkdŋxéCČ éič‹Ã4ØZ1Ę  ĄôÆė―—Ĩ3pK~…Ą.Ĩß\õ)Į:“Œf‡{d^HōÐ|ÖÓÞäĮ5‘|ؘoYeo.nAZWŽĪ X&buUÐQrK‡[dzF6;6ðŅđРęH–Ŧ•ø`Ø5’–øz%ųpˆPá:råĐÃR'Z‘tŽ—ĩé@ 2~ÎCýßd“đTĨ'Ã/™S‡[Ī;­äĐCXŽŪH†øČä/ņizšŦ Đ9ÛĩÃ-’ž‘8=ĩ’ÂâŽŲûô„@­ŽãÅ;+ Ī[:švļAĶHģ†ŽŨ;ŊH‚Y_õtM†’€epép{woĸˆĖ°ŅĢĒŦĀUå+2ÓĢƌAރ2ęčÚáYãđjnwgĪķŋT‚š(ēŧžn]:Ü ĮûØY ]/Üô„ėô”OSQÂЙĨÃûïÝ9^‘ÎO|‘mĨį-óĩcūŒ‡ļūėī0P,Ą3rdâЃkžß| ⎈žiE†ī!vöú”Œ[âŽH— !Vį6€Žļ5ĄkÍ·Ý ›ŧ"]–ĐÐÃĐô—HådĐTVĪ‹yė5ĘV+48%=ÞFöĪÁÜRĩ"ŋ"jĶ:DžûúPˆČ]kđņˆVI™7t *—X<Ívm/Bą/bĸš iHCԐ†Īð1@ĪøÍȀRåEðĩč+ôÍH‚Œ˜Ų—ŊCBōGÕ…ÔlĖ)Þ#ŊúŠt‘…CŲįpĀk86hZjũđļˆAu_‘ĻaÂ%Ņãã >ÍU"ØŅ{…Íw’#ŪúmFß@š-9·3rp˜Z%–e°ŧīé/SWdö2ðyF8(ĀŪ3#Ä#G.ÂN*ƒĀUÞå ĘŒūƒDpŽqtŸÔR Čá$?ÎU1ðxT Π%*úž%ߝ`[–_„$mŽ|ïcBؘŅ7‘QÓ –‰Đ6…DÞĨýzã—PįĻđ:ŋÁÅmþ҈dŌąÎaė™Ņ·ėFÍNĪ*’Ĩ‘†ËéV—@OQąËšc“xCųYĢh"G―ƒl]TZŊǘVĪĻ „STtšæÂÁÃĄŽHZ[ÏčČ äė„ĘjĐz:vŲÕ°á éúķu§ŅtÍYĶ €i%ĨmAÎč=ēdĻŌ°‰'Œĸŋ ŒÃ’ŽAl}|Ą™éĻcTSzŽ@ni<49K)ŊHdņE.ŅāũŨČĢRÖ§ĮÎÞë―ē%Ï=diĮĀ‹!rŸ1Ōåd^ĢIcĐŦ> ė RÆÞsäÕČy­@õœ…õĢE™ÞïĒģ Dũš"QļF)ū‡\/ŽkUvïVîîÛëۑ‘*Ũũ„ËũFVïŪUüraßå{ąOæß­ iHCԐ†4Ī! iHCԐ†4Ī! iHCԐ†4Ī! iHCԐ†4Ī! iHCōPéIõ(’ RIENDŪB`‚qt-installer-framework-4.0.1/dist/packages/0040777000000000000000000000000013761647206015621 5ustar00qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/0040777000000000000000000000000013761647206021206 5ustar00qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw.binaries/0040777000000000000000000000000013761647206023001 5ustar00qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw.binaries/meta/0040777000000000000000000000000013761647206023727 5ustar00qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw.binaries/meta/package.xml0100777000000000000000000000043413761647206026045 0ustar00 Qt Installer Framework Binaries Installs the binaries, examples and help files. 4.0.1 2020-11-10 True qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/meta/0040777000000000000000000000000013761647206022134 5ustar00qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/meta/3RDPARTY0100777000000000000000000000135113761647206023267 0ustar00The Qt Installer Framework sources include third party code: ============================================================ LZMA SDK Parts of the sources from the LZMA SDK , version 9.20 are under src/libs/7zip/unix and src/libs/7z/win. The LZMA SDK is written and placed in the public domain by Igor Pavlov. Some code in LZMA SDK is based on public domain code from another developers: 1) PPMd var.H (2001): Dmitry Shkarin 2) SHA-256: Wei Dai (Crypto++ library) ============================================================ KD Tools Sources for the KD Tools library are under src/libs/kdtools. The library is released under the same licenses as the rest of the installer framework. The copyright is owned by Klaralvdalens Datakonsult AB. qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/meta/installscript.qs0100777000000000000000000000347213761647206025402 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { // Install to @RootDir@ instead of @HomeDir@ on Windows if (installer.value("os") === "win") { var homeDir = installer.value("HomeDir"); var targetDir = installer.value("TargetDir").replace(homeDir, "@RootDir@"); installer.setValue("TargetDir", targetDir); } // do not show component selection page installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); // no startmenu entry so no need to ask where to create it installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); } qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/meta/LICENSE.GPL3-EXCEPT0100777000000000000000000010701313761647206024635 0ustar00This is the GNU General Public License version 3, annotated with The Qt Company GPL Exception 1.0: ------------------------------------------------------------------------- The Qt Company GPL Exception 1.0 Exception 1: As a special exception you may create a larger work which contains the output of this application and distribute that work under terms of your choice, so long as the work is not otherwise derived from or based on this application and so long as the work does not in itself generate output that contains the output from this application in its original or modified form. Exception 2: As a special exception, you have permission to combine this application with Plugins licensed under the terms of your choice, to produce an executable, and to copy and distribute the resulting executable under the terms of your choice. However, the executable must be accompanied by a prominent notice offering all users of the executable the entire source code to this application, excluding the source code of the independent modules, but including any changes you have made to this application, under the terms of this license. ------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qt-installer-framework-4.0.1/dist/packages/org.qtproject.ifw/meta/package.xml0100777000000000000000000000071513761647206024254 0ustar00 Qt Installer Framework Installs the Qt Installer Framework. 4.0.1 2020-11-10 qt-installer-framework-4.0.1/dist/README0100777000000000000000000000011413761647206014717 0ustar00Contains the configuration for the installer of the Qt Installer Framework. qt-installer-framework-4.0.1/doc/0040777000000000000000000000000013761647206013645 5ustar00qt-installer-framework-4.0.1/doc/config/0040777000000000000000000000000013761647206015112 5ustar00qt-installer-framework-4.0.1/doc/config/ifw.qdocconf0100777000000000000000000000517213761647206017422 0ustar00include($QT_INSTALL_DOCS/global/qt-cpp-defines.qdocconf) include($QT_INSTALL_DOCS/global/compat.qdocconf) include($QT_INSTALL_DOCS/global/fileextensions.qdocconf) moduleheader = IFWDoc includepaths += -I ./includes \ -I ../src/libs/installer \ -I ../src/libs/kdtools \ -I ../src/libs/7zip/unix/CPP \ -I ../src/libs/7zip/win/CPP language = Cpp project = "QtInstallerFramework" description = "Qt Installer Framework Manual" url = http://qt-project.org/doc/qtinstallerframework/ sourcedirs += ../../src/libs/installer ../../src/libs/kdtools ../includes headerdirs += ../../src/libs/installer ../../src/libs/kdtools imagedirs = ../images ../templates/images exampledirs = .. \ ../../examples headers.fileextensions = "*.h" sources.fileextensions = "*.qdoc *.qdocinc *.cpp" examples.fileextensions = "*.js *.qs *.txt *.xml *.ui *.ts" examples.imageextensions = "*.png" indexes += $QT_INSTALL_DOCS/qtcore/qtcore.index \ $QT_INSTALL_DOCS/qtwidgets/qtwidgets.index \ $QT_INSTALL_DOCS/qtqml/qtqml.index \ $QT_INSTALL_DOCS/qtxml/qtxml.index \ $QT_INSTALL_DOCS/qtconcurrent/qtconcurrent.index \ $QT_INSTALL_DOCS/qtnetwork/qtnetwork.index \ $QT_INSTALL_DOCS/qtdoc/qtdoc.index qhp.projects = InstallerFramework qhp.InstallerFramework.file = ifw.qhp qhp.InstallerFramework.namespace = org.qt-project.ifw.$QT_VERSION_TAG qhp.InstallerFramework.virtualFolder = doc qhp.InstallerFramework.indexTitle = Qt Installer Framework Manual qhp.InstallerFramework.filterAttributes = ifw qhp.InstallerFramework.customFilters.InstallerFramework.name = Installer Framework qhp.InstallerFramework.customFilters.InstallerFramework.filterAttributes = ifw qhp.InstallerFramework.indexRoot = qhp.InstallerFramework.subprojects = manual qhp.InstallerFramework.subprojects.manual.title = Qt Installer Framework Manual qhp.InstallerFramework.subprojects.manual.indexTitle = Qt Installer Framework Manual qhp.InstallerFramework.subprojects.manual.type = manual # For docs, QT_VERSION resolves to IFW version macro.ifwversion = $QT_VERSION # commands borrowed from qtbase/doc/global/macros.qdocconf macro.gui = "\\b" macro.key = "\\b" # Doxygen compatibility commands macro.see = "\\sa" macro.function = "\\fn" # We 'misuse' QML doc commands to generate JS documentation # (only works with qdoc from Qt 5) outputprefixes = QML outputprefixes.QML = navigation.homepage = "Qt Installer Framework Manual" qt-installer-framework-4.0.1/doc/config/style/0040777000000000000000000000000013761647206016252 5ustar00qt-installer-framework-4.0.1/doc/config/style/qt5-sidebar.html0100777000000000000000000000155313761647206021264 0ustar00

Qt Installer Framework Manual

qt-installer-framework-4.0.1/doc/doc.pro0100777000000000000000000000037713761647206015143 0ustar00TEMPLATE = aux CONFIG += force_qt QT += core-private widgets concurrent network qml xml CONFIG += force_independent QMAKE_DOCS_TARGETDIR = html build_online_docs: \ QMAKE_DOCS = $$PWD/ifw-online.qdocconf else: \ QMAKE_DOCS = $$PWD/ifw.qdocconf qt-installer-framework-4.0.1/doc/examples/0040777000000000000000000000000013761647206015463 5ustar00qt-installer-framework-4.0.1/doc/examples/config.xml0100777000000000000000000000240013761647206017446 0ustar00 Some Application 1.0.0 Some Application Setup Your Company http://www.your-fantastic-company.com installericon installericon logo.png watermark.png @TargetDir@/YourAppToRun Argument 1 Argument 2 My nice application Some Application Entry Dir SDKMaintenanceTool true background.png @HomeDir@/testinstall @RootDir@/testinstall http://www.your-repo-location/packages/ qt-installer-framework-4.0.1/doc/examples/package.xml0100777000000000000000000000231613761647206017602 0ustar00 QtGui Qt gui libraries Qt GUI Bibliotheken 1.2.3 2009-04-23 com.vendor.root.component2 com.vendor.root.component1 false specialpage.ui errorpage.ui sv_se.qm de_de.qm component2.7z, component2a.7z com.vendor.root.component3 123 This changed compared to the last release false false false com.vendor.root.component2old qt-installer-framework-4.0.1/doc/fixnavi.pl0100777000000000000000000001676613761647206015666 0ustar00#!/usr/bin/env perl ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# use warnings; use strict; sub visitDir($) { my ($dir) = @_; my @ret = (); my @subret = (); opendir DIR, $dir or die "$dir: $!\n"; my @ents = readdir DIR; closedir DIR; for my $ent (grep !/^\./, @ents) { my $ret = $dir."/".$ent; if (-d $ret) { push @subret, &visitDir($ret); } elsif ($ret =~ /\.qdoc$/) { push @ret, $ret; } } return @ret, @subret; } my @files = (); my %defines = (); for (@ARGV) { if (/^-D(.*)$/) { $defines{$1} = 1; } elsif (/^-/) { printf STDERR "Unknown option '".$_."'\n"; exit 1; } else { if (-d $_) { push @files, visitDir($_); } else { push @files, $_; } } } int(@files) or die "usage: $0 [-D]... ...\n"; my @toc = (); my %title2page = (); my $doctitle = ""; my %prev_skips = (); my %next_skips = (); my %prev_define_skips = (); my %next_define_skips = (); my %prev_polarity_skips = (); my %next_polarity_skips = (); for my $file (@files) { my ($curpage, $inhdr, $intoc, $inif) = ("", 0, 0, 0); my ($define_skip, $polarity_skip, $skipping) = ("", 0, 0); my ($prev_define_skip, $prev_polarity_skip, $prev_skip, $next_define_skip, $next_polarity_skip, $next_skip) = ("", 0, "", "", 0, ""); open FILE, $file or die "File $file cannot be opened.\n"; while () { if (/^\h*\\if\h+defined\h*\(\h*(\H+)\h*\)/) { die "Nested \\if at $file:$.\n" if ($inif); $inif = 1; $skipping = !defined($defines{$1}); if ($inhdr) { $define_skip = $1; $polarity_skip = $skipping; } } elsif (/^\h*\\else/) { die "Unmatched \\else in $file:$.\n" if (!$inif); $skipping = 1 - $skipping; } elsif (/^\h*\\endif/) { die "Unmatched \\endif in $file:$.\n" if (!$inif); $inif = 0; $skipping = 0; $define_skip = ""; } elsif (keys(%title2page) == 1 && /^\h*\\list/) { $intoc++; } elsif ($intoc) { if (/^\h*\\endlist/) { $intoc--; } elsif (!$skipping && /^\h*\\o\h+\\l\h*{(.*)}$/) { push @toc, $1; } } elsif ($inhdr) { if (/^\h*\\previouspage\h+(\H+)/) { $prev_skip = $1 if ($skipping); ($prev_define_skip, $prev_polarity_skip) = ($define_skip, $polarity_skip); } elsif (/^\h*\\nextpage\h+(\H+)/) { $next_skip = $1 if ($skipping); ($next_define_skip, $next_polarity_skip) = ($define_skip, $polarity_skip); } elsif (/^\h*\\page\h+(\H+)/) { $curpage = $1; } elsif (/^\h*\\title\h+(.+)$/) { if ($curpage eq "") { die "Title '$1' appears in no \\page.\n"; } if (length($prev_define_skip)) { ($prev_define_skips{$1}, $prev_polarity_skips{$1}, $prev_skips{$1}) = ($prev_define_skip, $prev_polarity_skip, $prev_skip); $prev_define_skip = $prev_skip = ""; } if (length($next_define_skip)) { ($next_define_skips{$1}, $next_polarity_skips{$1}, $next_skips{$1}) = ($next_define_skip, $next_polarity_skip, $next_skip); $next_define_skip = $next_skip = ""; } $title2page{$1} = $curpage; $doctitle = $1 if (!$doctitle); $curpage = ""; $inhdr = 0; } } else { if (/^\h*\\contentspage\b/) { $inhdr = 1; } } } die "Missing \\title in $file\n" if ($inhdr); die "Unclosed TOC in $file\n" if ($intoc); close FILE; } my %prev = (); my %next = (); my $last = $doctitle; for my $title (@toc) { $next{$last} = $title2page{$title}; $prev{$title} = $title2page{$last}; $last = $title; } for my $file (@files) { open IN, $file or die "File $file cannot be opened a second time?!\n"; open OUT, '>'.$file.".out" or die "File $file.out cannot be created.\n"; my $cutting = 0; while () { if (!$cutting) { if (/^\h*\\contentspage/) { $cutting = 1; } } else { if (/^\h*\\title\h+(.+)$/) { if (defined($prev_define_skips{$1})) { print OUT " \\if defined(".$prev_define_skips{$1}.")\n"; if ($prev_polarity_skips{$1}) { print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1}); print OUT " \\else\n"; } } print OUT " \\previouspage ".$prev{$1} if ($prev{$1}); if (defined($prev_define_skips{$1})) { if (!$prev_polarity_skips{$1}) { print OUT " \\else\n"; print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1}); } print OUT " \\endif\n"; } print OUT " \\page ".$title2page{$1}; if (defined($next_define_skips{$1})) { print OUT " \\if defined(".$next_define_skips{$1}.")\n"; if ($next_polarity_skips{$1}) { print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1}); print OUT " \\else\n"; } } print OUT " \\nextpage ".$next{$1} if ($next{$1}); if (defined($next_define_skips{$1})) { if (!$next_polarity_skips{$1}) { print OUT " \\else\n"; print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1}); } print OUT " \\endif\n"; } print OUT "\n"; $cutting = 0; } else { next; } } print OUT $_; } close OUT; close IN; rename($file.".out", $file) or die "Cannot replace $file with new version.\n"; } qt-installer-framework-4.0.1/doc/ifw-online.qdocconf0100777000000000000000000000201413761647206017427 0ustar00# Run qdoc from the directory that contains this file. include(config/ifw.qdocconf) HTML.footer = \ "
\n" \ "

\n" \ " © 2018 The Qt Company Ltd.\n" \ " Documentation contributions included herein are the copyrights of\n" \ " their respective owners. " \ " The documentation provided herein is licensed under the terms of the" \ " GNU Free Documentation" \ " License version 1.3 as published by the Free Software Foundation. " \ " The Qt Company, Qt and their respective logos are trademarks of The Qt Company Ltd " \ " in Finland and/or other countries worldwide. All other trademarks are property\n" \ " of their respective owners.

\n" include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf) # Add an .html file with sidebar content, used in the online style HTML.stylesheets += config/style/qt5-sidebar.html qt-installer-framework-4.0.1/doc/ifw.qdocconf0100777000000000000000000000023013761647206016143 0ustar00# Run qdoc from the directory that contains this file. include(config/ifw.qdocconf) include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf) qt-installer-framework-4.0.1/doc/images/0040777000000000000000000000000013761647206015112 5ustar00qt-installer-framework-4.0.1/doc/images/arrow.png0100777000000000000000000000205713761647206016756 0ustar00‰PNG  IHDR,oštEXtSoftwareAdobe ImageReadyqÉe<$iTXtXML:com.adobe.xmp ÂüH–ĄIDATxÚbüĸĸ?ÃPL C Œ:xÔÁĢĶ3`(‹ÛÛÛU€ÔtņĘĘĘAÂ@Ž1”’„?Ïb­Ąâāũ@l ÄˁØb(8˜JëņJ ŽbđĄRJ€ÚÄ>ƒķ”äVŨ) .âģƒŲÁlPz#ņ―Áž†9€x'ëØvp;gņ[’ręh~ÔÁĢuððr0@€oó!nŠIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-add-components-introduction.png0100777000000000000000000024160413761647206024044 0ustar00‰PNG  IHDRÎbðZŊrCKIDATxėVŲoTį·*å5Ę_žķQĢ<”Ļ…mœBX毯ÆûŠmlĖRlķīÆ6c°ÂĶ/ÄöxžÎxÖ;w™{įÎÝlÏӇŠJ’JmĨž™/>šđŸ|;Ŋ RŸÏ=įw–ûŧįHrŧ݋‹‹ĸ>ūüōKÚc:‘~D&Ŋūú C)øxĶÎīÕūÂSŌ‡fþ_Ÿ'Ý=öĘۜô&ŊRZŦ•šŌüN{<-}Ð~fõŸVøøÉóÏ?ĸâ‹/>ũÜs_/ãņãĮä$@ŋ%ôÍ7ߐ= €ĖÅ‚ö ,Õčâ8 ÂLĶņčŅ#ëĻ”aķąøSŅĢ?„>€Ģ>–ē6–ūŦŨ‡vŌē Į^tÚčƒßAŋ‚™ĸúØG‚}MýøÃéxÆõŸÖ—^zé…^HÓuýÁƒðÓŧīī'ãņøĀRð—xH O3‰ --z 6ÅtK5ÂÁfáiSG5―ˆ ŽúXĒ6úÐőđRČ2Ī―>ēe Bx–õĸjôąŸ*u}Ė)–aÉJqZÚXýþ žLaõú ‘Š&ÏŽ>ˆUęCšŪ§-,,ĖÍÍÍąxÜÐu‘ãŊ‡g5ÅbĀ„œx‰Į0 Q:§Ķi$jvtå6ĀøBĢĻ ŒDĒp"Ísk⁎čĮŲ,|K s_‚e$Ļ­æĒLzH$`ôYX\zļô`‘Īš_|ÏA}–ëĖĀĸ?ęƒYŒĸW}Åþ%‡KņØ­VKþ+ŧHN b,›š>ôš!bÐ!ģ0qðca"ļ–&ĸÏ1!BH+|qČ2,Ú˃v|īŒĨš?õA'ųĐëƒÎÔõA'ÔZZô™{}Rŋ_pŪF8Ÿ@āÐú`q‹>ˆ4= Č$ų„ōxÚŽĸõÆÃŊþüčëŋj*+$4Įõôôīķķ655ĩīī|ôŅGn·›”œÃëŸ=Ņ|8kĸ›oWŋ–Q·ņāĐJĮÄp"27Ŋ/ņ>" =MÓčt>Ēa)Ž XēEÂ2˜}ČBĀĘėHÖÝÜŨNŸYq9î;§<Š>—tœ{rØ1-ƒeŌ i?2îŠĻ:=6DaIh}Ā/ąÞI—_KVĢ5_ޜ…˜.ßëíėčžzŦŸ•Ø|‚ãÁ_dU‰ð#ƒƒũî}60<&EÁoýâP ēĖú`S‹>–ą“}õāŒÓ ÃâÓûƒ|, †"ņΑĄþþ{}ƒ žš HxL―}íōĩÁÍ vƒZTrU“·@ũOŽŧ|žNū#ÅīßúF€ũ™Đčƒ2æÚčCŊÚī>Đß/œ“æÐúāi!✨•ô#E}0—š<>iŠĒD“PUUI"ār}Õõ›uRÓЇÓĢZgÛÝ­›Žo|}ĒŋēdY&|Ļg0lkkëîîęrwûöíæææééi(Ej-a+ŠË3ģŧ>§Ēië` “yĮøÞWē2ũū9ėŌT 'šĀiöĻËĀGtœipĒaq"°Úh ŸŽD`ŅĮ\Į\ŲRßœvú(\ÃïŨmČŠv̰ j`QÆo3ęf•yCSðÉĄŒŠÏ‡'>ÉzũČ#ÁŨ„âЀ„āāŸđũųĪŽ€W?€47b ã]M9u­ŒĪāQPÍÐDÏņ}Eéé;ęÏ4îJOÏ*?80™ÓdGßļOœ3429ŒtÜ)ßē!·ŽzOUYõŅSnV1t ûEáíĒōīcðþļG7ôeņß߇$ÆFĢIýuc^mŊÎŦþðþ)Ū'A’NŠéŧÃ5 ŽÜĖܔžWūgOeiÝévŸ úō‘á ! aëņ˜ÜPđskŊŽ@ ã‘Iŋ+˜x!Ęų&û‡'Dň/Čgũ–üáōPŦÂĄ$°žKÉïĩŌþŊOŊIïTĀÕĩŋ_–{Ar +Óũ wa™ū2XŸū_ĨîŨFðĪE"I’ä$ĀŨ''.žüģŋŠýwĮ…^―üŊ΋_ŸŽŋĩæÕķŌRį#I!nÝšÕÞÞÎ0 þę‹ĒĸÉíęęË&[DÏ]nÜ^ŋæŪôũE_ðoýė}# m…-Ÿ­>ē yčA?9ĄZd`;bc LE$Āēæⷈ€-ú` Ö5†” @“Íú`/l‡ŽcĢ,2§wŪųéËéíwĶī……ĢgóÚWÞÜvĀ#ëaÖïtŒŽ:Æýސxĩ073!ƒgƒ!6äŸsNøBžfĻCįOo);106Åpb˜ Œ9 +Ā °.áPĀ Ir4Ė…–ųfɂd<V7”Ą?ŸYĸË-7&…ÅÅE-pŋ`íúŠú>äŠÛ‘YÓþYŌ‰ÚŠę­Ė/ ęą9CՐ'āóē;3éœtyÑĻĖ{ÎÖūSXsÜéaā{H|Ā9:<>=+@ŦˆÄ2– ÍLONûB\0ÝÎąąÉNn„ øƒÁ k|ŌāyŋĮĮ†Z‰œkÂ9::ęe€%Ŧ҈gj|Ä1Î,Edy0ĸ@wîî#Ìū0gĀ]füž'‚ÏĮžŽ †|nÐŌ9åæEy~>rzoq}Û YUü^? ŪhTųƒ!>ô:ԉ ÖTąįŌ‰‚ƒãþ°a<ģA–‹DYf&ĮGF>F„ _ Äóė„sl ū‘ąßú:9Đïú ŸŽšÛ°Þ/KYz‡ŅCß/:7…ûøŅč‡Ó`DøCÎ$Đ#ë]ŨkŊ<ÚđõÛĘĒėŦüķšäqnFtÃkíëŨú].Q’ŸĪtvvöõõy<†a8Ž …B^ŊwddäŌĨK~ŋŸ”!‘ũ~_ÓŧåJhŊÔp[9{CnėdßŦÚYÔļÅëó+C NEyžGNK31d~„7Į1č"Â2cÎ2§˜›N…ß+‚DéjæÁ°,9iÃFõ)|kíš Å ’&_oy[úÛģũÍĘŅŧ JƊr2ŠëšƒĒý$ŊüØ4q^ŋPZ\\ĩŧ8cûæâÚæ€ß}nÎ/Öm-Ŧ:ðГék? Y…‰ŽsLDqt7—;†ģ§ĩīĪ„d՞óó •ĪˆŽIÞæc9'ŊɊ EQŊޚ_{ģŧuÓúoïČmlŋŇ"Āú{ŠōŠn8ƒĄ@€ ņë>[™YX―·0?sË͌ ―SÂLïķŨŨl|csU}ŧÏ3ÕrĪ&ŋĻ`WÎŪó=C҈ÐqŠŠ xw~aé™OGŪÔïݕS‘“óÖ[;öļ&éáķ#ĩđY™9;ĘšnŽ}ü~å{W†YļvîøöĖÂōĒü–ÞAXýÏŪ5æäįV>ï‰IDĒQÏ―îÜēC7'‚L H|ĮŅüšÆŦQUáž#5ųŨ‡Į>Ž?PZZôÎķĖc—û5]:YWräâ %â=TđįâõŅĻĄÝýSmų‰ËĒînn(-,ĘÎĖØÝÐåõOĘÞžnÓķ‚ŠFW˜k9XvĒýN8Ė}üĮšßeï*ĖÍ+ĐûÜũAP!3|Ī”c–+-ĮrtMĶeÆÃ^‚hĪ„”2kLÉdzøšŌSŅÄAáäáĢÆĶ0'ČghĘëÞ{ÞgÏŲĩŨYw•Ë5ÉŋþŧũũýûÛĸųũ>W\Þđ>ŽŌg’$)ÄTÕävEY-Y6rĮÎŽˆáŋ~ē  UUĨ†aõz―îgƒ8 ž,Ë?§ôā‘^0ĻŋބtF™Õ+ðGgBAĄF #J‚(I@‘ú ­*Œ1x2 ^E’–ˆ!ÁƒĪÖh:E)ÔĻT‚§íf‰Qm0EņÔ(…HĨ‰fí.|ęĢÍ@ÚČp‡úĀ6‡Ÿ6ÅõÏ3ím_ŸĸîĘģgZ°,ĘũŒ›š_°2#éąÎ/ëūïäÄ)―–0Žy―Cũl֚ėũ· WԀļccĮN^”•>j 1âÁ)/­Z™‘8ąó|ýå.AeR‘ŽĘĀĸ\öj`]lžÔåQA hS°ŠŒŋ Ņó}:Ņcpū—3G?46:b|Ō’yOÞŊĘ"ŅĖč LWûgŧ‹‹Þý úĖh›ŪÎ.Éõęå­|RÚŌiŠ;Yq[dŨMė?dQãđÎ6bÁĘÂ5iÛ}sÝ-ÉūxÝŌņq=].NfXÆõEÓW†!–åŊšú@Œpû_ĮŽœŒyü™ÜôxwkmKëc L”TN―zîāŪâĒũķŸi퉛8Ūí|m{·rõËŠ!fhtøÃOÏ}iuÁs#ú_øķ—†eYhNXRvc$Š*V8†AÄÃ'LÏ+(ȜýÄ­ķooãþMŸ|ĸ˜I‹—Í 3â^Ų[Č­§6õ&.Zū~ÃKCPہēÓĀ—~üÎþāšõkÆ ā— ’ĒŌþ€ķߝû‡xmįÓķ!þϗĪ1š<ÓütiÚĨڏÚâsjĻNXQ  i‰§īĘi@$Ņ…þãúøTöÝŨ`w_V "Ã͈!  „b† aÃŅ―ą(:þ‹·xŸ€ę$åĢtŸúøÆš^$xES­<ˆIrŸ~ĒëŌ'ęŦPÓĘŋ^I– ;24.ŌÖ]VęčÅĄũFõc ų$Ūõ\UŅĶ·ö|~Zô302@Uļ€ yäŅ·Áyöģčž—IoÂ"d–ļ įNn~Ó˒ŒFTŒ Œũ(óĀzÄ˒“E§Š<Ī"Žtvó*hô Æ=7@~&ŌÆ2įæÉFDAxN24Ņž“—›5iĖ OŊ[g ņČCþXbÍ―N™ŒÕ€°ÂyÜYōp%{·Ÿ<Ý9˜Ux‰ĩčb‘].ÎĢ0‘ąąþHíŠnt{xĖDnadž0bAĒ›·Îœ73ärUᆭ'Î}ßÝu‹sđūq–nß[К#šŸ:! #”Ļ=ŨÔčĒ$›ÏųúoęĢ]‹Ūĸy}čĩĀŌwY ~,q\ čĮ…FCcҰ‘pÕʑ1—,6ÃĻ8―ÉDhô]_iĄcL&“EcžN§ĢŊ’9*8VüQõ“ý‚ýú››Bތ™ï"lũęIH•@@đ$ žč8}óøh#\ŠĐ 6'ÅÃ,ņ49Ņ@ëCŸ“‹V–|Ô*§–åÓú MNdÐ$„rįúíôP„­Đņž_ä˜`―ˆYî―\Ví|äų”īg&ę‘Ę0ŠĒē:Ø*ƒtŠāöxDIF0`Tîæ-·„…ÎöãŽúGÓԟāaĀŌŦBË%ˆ$€đ>mЄޑQũ]h9õÕĨ[HĮš:ÚęÏGņŨ)ĒĀõÜļ-bLęCķˆXVÆÞŦŪ]QVtˆņjáŊ,†"•nARü –P[D|ڋ…ŊĶÆĸ^/q Eðš“dÚėĮkŨ{8Ïå {Ýýî ĩ@Ėŧ8^„ÂxEC]Ä^5hØōõk'…KGĘ[ –␰QÍ\ąjõŦŊdŒŽēI"ųž%z…éYI‘DĖĢbÃØ #KöžåÂ~7ā›úēšģ|rÎ OŒŒNe°ŠĶ õë―~ĢģûZ{˅Ŧ{Ū}}žžuÂŽŽ”§G"'1*ÉÅyß2PxĖē˜AFK`0ūÞqŧKōÜ:ĸÝ5[LĪË Uįvqœ ˆa(ļĶĀß}ĸP˜–rįóEķ=ÅÓóEĖ'mZ*•hð9ÚŊ‡t]J!ĶĨøl‚ĐQ…wŪųĩúĀėĸŧ>0‡ĢĶĶĶķÏęęęĀ;kjJ7o:đ2ĸâŪ7ý~ßĮÎWÖ^·ĶķĒĒÖé<Ā(ÅétÂĸ9ŦŽŽ„ëččhkkƒYøí-Œ"!ĻvT}ðéĶĒýđG›6ŸšļũøŲmÅ%Ëķ|ļšēŠōü„ĐŪvôeŅ$4 St‚‡€îBģĢŧ2Č@=°ÄÐEÉļÏÚ=ú(ņIîĢßgGd-R[­-ا>^ ÚúT•f.(üøÄGÉû;wv4Wþ­895ŋēĄú•%s“æÍ]’žôĖė܂·+Žî°/|ųXuCɟ7ĶæĸĐĒŪŲqdĮ„…Ÿ”ÕÔߗüü,{îĘýeĮŨ/™;gþžÜœEI3ŸÏ[ŧußŧoĪl:álvðƒä„„”īt{röûûŨô=OŊ°ŧėģžJ秃°äī5ûVՕ—ĪÎx|EņþS§škJÞOIˆŸoÏĘÎLž˜üúG‡7.ÏZũöæoäÏ~nVjf֒ é…ï9ŦJó-ˆOīgf,ž•ŸĩqOŲĄísf§æü―ŪvC^æšwö467ė~3gނųéöyiKW–:ę+>ÉHYąûÓ--uë_Č(Üöhú79įōGÕDqĸ§Qذe‡ØðŠ"$1ŠōOfē!'ķ{ú1ýîžĀ†ü=üÆG]]uœŽ ĪTFåęzœŠ{šnēð(P;―?6ž?ņæLïzb”6]ß/HTâĻ"4pō0‘SUÓũkšĸ?čkøÁs4ēÝnÉÆH’„‰ÚŠ*‹ÍŸĸþ҇ëOïf?ýØå9ÕĪĨięUĩmËãfģáŋSXŊŨ t]:™ˆJl4mýëģ_,ï~ýĸū[|ē:ýĄĻģrW 3*‘íĶĄ=BG%3Œ åtŽðI@Œ€íĶ@~öØh‡<ķ`ĢSčF§‹øœZyÔËĩ?Ö?Å0tM]deó|?ķUžîšŪívyŅu-°eۏm›§ėfŸ&ÛēŽûĄ‚Õë‡=ĨŧšH•g[ö}č;6Ļî†ūĐóŽĻËj:•U=Ž]–’SõÃXïróÊāĄóæŲúgþŋuëö;·ï?nũϛ*+rĶ?$–}ßÕuU_I‘ï†ąošŠ(3õuMnؐQnh+‡ýXtI›Šņ9uUÂO]eĸ{ïÝũŋúūāUÝ8ķôĻęnlË4%=kÚķiĘ4+ÛšÉĀŠÚąŊéCW_^^ŧŠĖýę3;ŠŠ*Ŧę0fö}M #1S–ãŲ—|W5M74gę:†-pðŧáqhr8ôßôûķ.a§jÚū­!ŠČrĖĄÝ ]%įĘōŠĘœfîŠmšŨuŨ7…^đ.2đ?š\ûƒíl‹JœFŽïūōĢĒūa4jAŽ†•dō~)™7"§ŧLÞŊpΙü*âG2ŸųoĀÏgŧļļõÁH’Ūïųîß:Cû=؊žŸŸcĪLŲėŋe;|[…äq$™ĶÄPšŊÚĪÛtč%ŋøëÅ0 â!ŠV‰ īðuwČķs4XØÎsF…Œ!;Ų:,‘gRŧܞI~·=†Ŧ` ÂăžäG-B~ˆåčc#ļ4ô[æv†<2Õš-į—Ž õT ]ė õS}…gč’įE?þņįPx(!„‡4 •8ŠG8rŌė““•laÂFĻE3€JŒŽB (ôĻ|„ĶÓTžÁ™ čDī@ŦPåLō#@ •Düšïģ_ϏĀņ›Ïc~š†ô$?úč sø!ÁüPõ:üČðĢ1~ČĮCž?ž2°~0øq2N `p:äG~ŲâG :ļÆfÄä+ųŅãäþ(íÆ{??Øņŧ ö™ä‡„ y<Ēõū? ]ϏC~tØŨåG†.Â|~0ÂKt3~pšäeü ūýGî_ ÆņņąŒP"Ïdč›+‚-ŋĢŌ“Q~äläÔĻs͚LļwïžĢ3äÍóƒį­â'‚ē?âĮž7ȏėÐyðß·s.?ØsøąÓPo!?BļžŸŋŲŧï ĻŪþāŸsÎ―ŧw ÕöÔhÔ$ͨҘK4–'ŅhĒĢÆĮωXÁBĒbėØˆBĀˆDJbÁFS:ėē°l―å· Ļ!óĖ3ŋäųæIž™ûšqĮŲ;įœÏįÜđïŲ=üąÖIþĒýąúïî4‰D"‘čOu2‘H$ýįQ+‰D"1jE"‘HŒZ‘H$ĢV$‰DbԊD"‘ĩ"‘H$ ú›C[ „þ†ĨáÖŌþŨvBð_W6””a$4ųÏũŸō?ąý" Ēŋ/DśŒ5U5*‰ãĸÍC…Zü·ēŠPņl}uUeEec“SÖčjSĘŋ)ō9ø7þΆƒN]øða…ŠIôG'ų­ßsSimiö‘ÐoĢ. ‚ŅZaÄŨU•?zTĪnbĸø>‰ÄĻÄ$˜ņ֋CFŽ9|HŊaï&Þo”Jü g6éu:/ŸQ„ŧ{9ráÔąƒ^ýĘ+cž8råæÓÅ ,EPs)Ž^Ŋ7q|ÛA˜ÓÞ[:Âë…~}šwíÚĨŦÕĖ-įĖ…ā_c- ĸį Q4yœ7aäČwCâꠧ ËBĖÆO―úũïÝĢ{—æNúŽōI-6Čhōĸ5žÐ†ŠĖāí›öĮ? ôï,@āÍ―Î`äÉdÂđM+GŽđ)ąˆĄü"1jEˆŦē—Î_{ĩFžóÁžŲþÞÝ;3,g„Ĩ2…R!' ˆ’ Įũn^ĩ.ð‘Ņ–02™”F`%R†aĪ`ÂČЄĶ%Lëp„āw"ę^äþ)SžË(ė;gÉây―ė ‡ķ-ö[―§Ė„Ĩ)HÞŋlؚôĒzFÎĀŊņ抒’Š&xaøĻŅĢ^ķdÄĀž-‘ÉŠĶđ))M@BļÄ―ŦWSq2ƚG-]Ëm,2 ̧ïČĪŠĒ%6JĨ„`DhcJ*·Ne‰@īDj]‚ĒåJ !özøO™:~ A‚ĩ#J"W4Oސ=û”IhĐŌÆŠ‘PÐB QՔ–•1ýĮŒ5ŌÂ{°Ģ-CKĨ­ûl…$RkmČR$#k™ĘzGZŊJ8Nā˜Ē-ĩŅķŠ)F&o9XĀÄú›æû$Ĩ›kĀ”ą&wmĀēïâRyFÉóĪŋũËS§øs·ãxūĨ…ēe‡ĪļeĨæÕ--B7_’[·N$F­č„°^õ$Į`nßkhČÆĀ­ÁĒÂw ínà ˜kŠ=đå#__ßũ}ž_Ū—I„é ;‚BNFœ Í(Ž5kŦcnÛq⒖ÃÄ\q8tïþð2áŠóŋÝšûÔŲ I‘ûüýüæ/[ũPc"ĸŪ/ŋĻáŅĶßTpķo|üÁĀ5ĸü:6bûŌģ{ŋ ÍQ] übKddØÎ][ΜÏÚ>Ų4ĮŲũąũDtlLtôđĻĩ ŲIgwl Íš“·oÃ'“'ûŸ|3tޅ3k·;yôó›žõ@ē^ ԔīíĀŽ”•óý\ČĄėœû{ âီņÄÝψ XėoŲÏEKÖįU뭉MpAōÉïXޛō]L‹éß”! Ā?`OLĖŅįΝ ę!ÜûfįŪ}߅W0EˆĨܘĢÁGâ~ŅŠŸÚŧ}úī)ū“ßþúø…zßrÚðô€<ÉNØīmwbN f$uEYßnZuíĶqI~jHāZK~sđp“ÃÅVG =t:ōôĐĢûöG”ë8Ûn=‡ũęá åŒ ÓX4gšeȇ‡ËŒīD"hŦ‡FĶæ%8cę”éëēŸhÅī}NŒZ‘ Œ“›Ŧ‹ž4ýüīKĒRnꁹQ2lÝí+f­Ü}.Ŋš*1ęĻĸĖ5Tęėœ,#Ģþräé‡e\ciôîŊ6†^Ö°˜æ5‡í ÜģģD‹Ø†G[‚ŋZō9‹ūØõó•Ī“ĄA—í/kjsŒ0ĨP(EAüëĻm,{PP_kįÞcŅžĐīąIĢŅ*ûūōŲÔū‚đþQÁÍĘē۷딟’›VŋyŠtę‚Ü_ēģoæßĻ5ðRÂ^ŋĩqÓŠÉ|‚ÃĒããZ―:ārą^•ŸĪ7>Iˆ ŧō@,oæ[̊îT\?ąuáÂđĩeŠų~ûöeLõ›ûųĩËË ęĒËÛ6ޚ4iJ`D|ōÅøŊVÎúōD2Æ|Lôą _­š:ų―Sq??Q7Ô=Ėܰ:(6IŗūY0wþÁĻ\ Ļ2SĢ j 4ë'7úžïqÞíŒþcÁwq9˜‘"ø-UŅík'đĨĩ2Š>―gÍšM đ• %SSxcÛÚĀGõú'ũ2v‡†Đ ĶŠėÔāsŨŸšÂ!‚=Ûíęŧ ›ŋ žrĢ”RHUnmÞþ]Ęmš.Fœ>|:šįØüŸNþáŒc7*)íãØÔ\ĻČˈ:“` ųýĄ€åQyĩ ?Ÿøú­·? O(ÐTÞ>ŧkÍŦsūH{ŌD›ëÎßĩjņ”7ü>ŽKžw.čŸkk‰C ‘ĩ"e\Üąj`gŧžØïĶŧlkX™–{˜õÓūČtÏÉŦģÏĮm^ęW›v.ŦqÆėéŽhß%4þŌĖWzœ‰PÏķÜ]ÄņĮ›k"3k”Ųŧđ/æzė‘qŪēŠØýEjŒÐģ 5Ö…8vøĐ#GÂï?iDOӖĻŦ*kR öĢûšILf€7›Č€!/#€šútįŸŽ_8 ÝšČSë&"'Ās„‘Šo_öúð!^CĮMûĪĪQ ðÛũÕwĒãįūčQWUyŋīaüʝóžÁŪßkQIi§õɉˆMŧãöR@â―Äuþžrn]Ë}LK()Į%öo.؜|%ōí Fš‘›ũĖ)7"ö8PÚã‡+šXx^0|}úŊ~<~áÍHZ@„B•ũn—”éÚŧŽ ÚsöjZš_o'Ą>?hũÉŌ!ä@lVônđŪä|ōĨĘF„qÛ?NœX;{—ũ0ŊĄ!ņīó +ĶbĩEЗŊЍ\ÆÏ?ޗŋ6Þ{@ũ!ã’Ŋ ;šĸK7sSáĩÐæøY@H ‡@ŽŊ4ÏŒh꧛._ŧ~üô‘ģĮŌŠō'å*ė2lĮÆEðڜ€„ä#=•ˆâ8ÄóRDáúümÁGÕžKPTėÕīŽ ĮÔ\9z2!ƒEk°ņ›ŋ'åĮo<Đ’ å EˆÄĻĩāü’ĸŠsŅQ[VĖĶđÆï·/_øbĨZe(M9:Ųgō氋(ŧHE(Ö$0†ÖĩÞ[Œ1ÁČšąFčæí=ņ ŊžCFžėëBĩFŊGðÂŽęþÁŊ·ïīÚĩ+xý͐Ôû՘hÆó`cg+“ƒÞ˜Ŋj‚[áúÚ2K:H°€ @„9 -Îdēé:bßÉļŸÎE†ŊqUû4w>øėËá=:šH%4B žGĻų âyŒ Š­ ŽāÐīąūI)=ŊŠÖ sfÖyÄÔUógôïæéâ X–eœįĖ{l_ïaĢû:{ï~­žC`Aæ­Úāݧ›“Že{Ž‘íõúÛc<ß9ãĸæøiģūČ-֚īŠj]ÅĶOßóŋĄānyCÖ„jóĨĀįÓ―įããbŋŸ3ĘÝ`ā―}– Ąā§’ēnæ'ė‰?Û`mQƆÅģ&ūõ֜åAåü;€’ŠFk™OœĩaƒŸ‡kg à „ˆþˆþķxžãqįÁĢú ęâ&ŸūâƒÂĢ€C|6,Ÿ&GŽ%šlÚw3ą%œ ÂRÐüÓˈbä2UqEĢF‡ą4šį%€ÁÐPU @Ņ@=[‘•ŧŽLJä jÉ#–™Rə˭Ã9ÞÆÅÃQÉ<*ŧŸœëýŽŃ + ?sCIGŨáv Įņ,€@Ie #Ņ™ĖB›Oę<ãÜþõIzXËLz=Ąg0ģR^ZŠīB`ЙĶÏ#`\ûø|ýõ†ã‰DÚūĢ›QO@A!ÄZ<ÂÖĄ €°fC“ @Ņ^)E­‹› ,Ŧ Ãóvö}&ž:čƒK1A;·'Åh4ŧĮėũâĖ–9Ï]8ÆS& ,Q8vēXN€ķúŒýÖļūÖÚÍFNoÓiāôY/­<―mCŅ mŧ-oŒnĮ–ïÛ<óX|§UÁ[Įy–,žû™Ó…á9Ä#“ĩ6ÄKAĻ-+ŅP”DSx%ðŦ)Ŋ†Å†rɁ+ö]ähš`$ðœu ĶMÐóÜ'„âx0ĖM,Ќ„5jôÔz)d6ĩü€6ī!ĢV„ˆĄ:įxtŽg·îIö­RP*eîÝx:Â―ŽŽĖ;ƒ†ũîPrįÍ:té-sD”V]wîØI—YÛKī9Đ'öïƌ?~ŦTãÜ­34ĢhüäÁøóĘ’ïŨ‰;;ķųF‹%ķNmÎ%„įŲ$u{qŅdßôo#lXėÆlëÛ_Þ‘ņÐÅÛÆÂ—‰ÁČÐpåB”‡ïþžáéôp„čŦ O í Xž§œúMÝšqžÐ’ėÏjá)ÐÜ=y&’™íÓgØ{ Šš–ykðˆžNE9LŽ}ŧΈĀZÝģú°eęKG īp+âdn-ôž7ļ“BŌ|™įŸÂ[Kī"4Ur=>ģHßsțøĶæÞþąšē‰8tÖŊã݄âkŨŌûš Gõ•%\ÛŽŒĩŪ#€u]€œÄðƒõM&°bðĻWuwðöņiw*-%1ÃsĀÛãđu%ęJ(lÛؚÓS~)o„ú›)+&ĩíó€ĀÛĩũ0&_ æŪŸŲē§ €B`Ö5 @uRRæŠĪäbMŸŸ–\;ŪŧLfc ›z%6ú…ņã^ä[įā$–šû8D\đÎŋėt,"ÎNût&ŽXîŊÏXQčoIĨnxœyŒ€…ĖÉQ€zM\p%įAcƒ*5fϘŽJPØY_ėKŌé4BVŧÓþą+RÓXūyķõHĮÎúĻgWgÏÞ Ę2Ų*)›Nō Y§~ŧ~ĘRŨŨĸÎŌÔęšâƒÛWpĩĐž\ˆ ŠNoÐĻëÕęüäãĢûķ€ÞKïŠīõŠ–~,ƒŪOķcāŨ/-­,\î ā–VĪo*ĸr\O‰SŨîĩuįŋYÐC €č~66ÖFÝ:ž·ØØ*ƒÏä4TĨO Ā}ŌŌĖ"UC―J­ižvøS‚={ôswwĀ–é_ŸwõvĐYS2ËĮ  ÃĐô"ZĨŅjrØŨ`ÄōPĩΔžg‰=@;''ZŌeÐøƒgsՍÚōŧ—ĶŋF™Œðœļ$§ī^ĢníDgTœ;Iŋæļ>üĢŲP_’î3Ô€,ؒĪmŌhT51ŧ:P”ė…q3õå–&…ļ9+―–„5ęīU…ïé V/Ė_øn{Ŋ~~\Uųpõ;ØšųÎ~ŋ““;ũŠĘŠ0Ômžþ* äÂo~<hYXšNŦ-ÍûņĢ CKmÚɰÜéģŅĨŠ&õĢī·ØÓĢW—Ļĩę{ Ý:*]_™]þĸØ;Ÿ§(Ž{<"ĒâIðæ!^AžŦ'=ėāAÁĸÁ‹„u؃zRžøƒm:īÍögŌĪMĨM›4ÓĖ›™fYe―8­T&ë^DÅK>§žé{™ïũ <æÔė/V^2ēĸ@Ȑ@L‚fĩŽí~ßäÔôrJįL>ę˜:Bš†+æ$ˆ(0 3§VFŧCŸqÏüJQŨ‹õ)™ũší–íD°ðJ/ä}õęõÛŚƒPĄŌt™āŋŊŒņ}Aûvãģü–öûŨ›wnœ?{úܙS.]ūĸd'Īāđ. jĢKĻōö8ī,SÁęŽb‡=Ól$ þ mŲŽ?›3Ïėš4ėxĄŒÁ†nKGZ>ŦĶDsˆIß2íÞ0Š—Û,GíģÍ'/>~‰\ŦаÞÁĢó~Ŋ#·IžROįáÄ1͎7ĄQčÛÍJ^ÓōļØéû|!d  GĩēŪå6ŠÝĄÔ Š} z­”g`–{YūīģLJ‚ú^  / Ŧ^@ļ="ōtlŧÕņĶ a,īu”Ŋ4ú„„Ët―‰\ ýnYĮša†„4Œ".ÕÆ3Ę›CĢ„ ؐ'ûCÆpÁJó|ŌßÓą–Ëï™åi=’‡ou―xeÛą[vÛ]u:#ĩęL“ðō@ýaÍz`‘pļčÏå=éĘĩ[=þ-Lō‡ÚøŠ„Ó&zûčÁ͍ŧo>đ\pXK;Ώ üTКšv”ŽÕWŦéLėįžÞ“ũ‡;åÃÃTĨRĒl“jÔ/)nąŠZt4ŌĄâBĩĮE˜šĻŠSCՇZĒ:9Ō- ý‡ddĢ6X4nmom―ûļú7á"9øō5I.øóĖ3s[ÛŊ į;;į·rۖ]õÞZïcŪ―ÏŽ'PæFr/ä ÔQ|2ßÂ?ˆŨJ]$†€•ˆ‚æBŦRNrū5Gĸãš―ģŦēŦ@*ĐSÔÆ=ëfŽÁX}Î5?hīŊ>Öĸļ ÝÍÍo‰[joąýŅëŨ þō›Ÿþðĸį7Rĸ·ûigß~ûW?ųîuöææ–Ú››››[jonnnnL>Kn>įnó››ßÁ†ŠzũUŋ@JĮ/JdĶ óvŸ.Á þúļ ―xŠþōž Sđ~6š·3œų_šâTčŌÕc3čøä†>þtÁ§ßeøå'0•?đú'•ûMO~§íþ|{CWŽã0Ó[oon>7q―ũw ĩïßŋĸĸüŸýĮ?ú#3ĩudÉWĩŊ’Šš ^RŠ2ŨZ‘Fą}+ĩDTđũ6ĩĐSĐšŧOŲįyĻžß{îĖĖ\."æÐÉŦęŒg p][Ŧ2܃äTž đ* HŠTfTŌÝEÄĖxDe`_1+—­đndŪeá?WeÕĘ4ģlĻŽŠÖRĻ2#G{[øûÕęĘ%UŠúÍ_~óþá?úĮĸäŸū――ýLg_[Lú§ĸYUåæææs""þāþþŨ_ĸ―ýŨ•ZUý“?þãóŊþå‡ßų@jdfÄĨ2Š‘˜ADšé>ϒz<ÞÍ9ëĖ8އTe%@īNe•^Ð="ÜĖH=ŸoĪÚZ"—VÕ\EŠZ•îÁņxļ{†SŠū7 Š­ŒūIQū*H>ŪKËö]YĮãðíŒWËåžũ­Tö-‰ÔZGķ–ˆ’Ō˜Ufö|>ąÖÜh-^Įrw)ąĩd„G /3PVĶŧŦÚ|ЌTS€{šJÍ|ïo~úÓï}ï{]üMņ?þ―ßûŧŋĸû/"åæææóĀLĸėÏþۏ~ôãßýÝŊmWÛØąÞõâÃÞ[Uųx@–"u-|ŠV"éŪ_}Ĩ„Šđ;ģĩ}K‚›TĨ‚âTSūŊž^Į{[6âēÖĒŌ·ŦZÛU=Ïįēõ’Kôs­U™ŧuó8wŨ.-`DĻ™Đķ 5}ÝgDīĩ”ĘŒūPÆõz…$•Ųbš^„{ęļUÝ{ģoĒŠ"xž{žËLx<ޑpßĶŌÔ"Į1Îú<Ïã8Ļ ‘pï`ÍģZķōRíŊ>|0yŽ%ŋóÕûŋÎøðáŦŊŋþ:"äæææóĀĖ>|ø™ßŲÏÍĻŠ™ffŧ9Ë,―tøøĸļxž'(ŦD„ī`x8Š2K—fĢÔŽÜo›äqŊ Ģ,/­ŽKÍMAėgë Ļ­Yŧęū+'7ļžaH*˜%RYRf+#Ĩ „ķÜgĪŽø†—ČZK:­Œc™ĩ3ĪÆGfĢÔmmŦ€ë˂ļT;32Æŧo ‡dd\óB[6&ýX+Ŧ2ģŊxDÄ,îGũ$‘UFÎžŲŠoßķŸ€üõđđđų<Ļæŧü―ÚĘriąĻ_šĻ<ũŪJŠĒu–ŠfŦJFžl­Ép+ë8ŽĖ+JexHĨ*ĢÃ\Į:Z§ē‹˜ŧ—TIĐ,‘+…ęž4^“#Ģz™ĮĄĘŅĩ1žĀ&ĐR>A„Uæ5 [:w'ŠV­Ķ_ ^•ū·R_xÄT3쌰öØó@*kbV\ðš%ßᚠz.GV–ï]uEŪÕd;ӗÎÖ8hģvýP* œ°âæææ üipģi”TĮĐRbķ #CänũȐ^py^Ā{ķēī(ó|žUĄĶ^“T3”ÔDęîĨ/ČŨŸŒéUÕ)ęš]2Ōz3j‹Ô52kaĖļ·gU —ŲļK ĻúÚwŠJöW‹H)Qrä~-ŧŠĨ/3ˆL…lcÛ2ę1ӌ (ŧ—UĄWw')ĀÓwuĶÓEí]ÝOĶKJ:ĀÕFdž- rssóeþ^­-›Lķ#PmąÐVNnũJ7;ˆÓjwÏįSDŽõroŊ,š°Ýņ‚Úæ7@Že=ÎŲ{žgeūĪgvųčtUüÜ%ĩ&“Ĩ–€sŸ$…ˆïMē3+Ûaw'CģfĢ?ÂÖå|>I*™U‚ž1ę,Ũ•ˆ@ÂígĢ·ķĻ*Ív'°: !%Ķ+še2ķ›^dÄÞįlše&yM āįĄÔðë)·Ŧ―đų]m‰ĻjxˆĖîýl—/tÛĀģwš,3ÂÝ^N$1ÝŊ%jVRiÔĨË}ûÞ`owß)"™/Sœë8JdZSuH >vžfDÔˆí."c$'Ē]f§Â:íÍ,%JŌ{1ˆ@ @į/ÂTŧxWæXŨ–l]‡ĄJ TŽ3•J%â€(•@ļC@jßp*ųčķ‡óų,5æĮc@ŧí6™)įđ+RA‘ŠLĨĘÍÍ͘ÕJJķFFUœæÐŅßđvĻŠF’ŠMĒNŦlKæīūzdAîð>\wÍ&mm=ė‰Ĩî]ĩŒÏ <"TōgGøŌ#b­‘YĐĶĶÚ·”f Õ.ĮzÜđŠŲŽĻŠæÝ%E•Ŋݓé>šGÂFW(ȋso_Į*Đpũt"ß―{ŋŊž-âŧ+SÕÔ<ÜLŨą<âēÛĘ%777_`VKąuėíT,3ÝũėhUx•ĖŋÛ!RŌFēûü1vïMČ%ū’~†RŨZŧ+€XĮÚÛŦę8ĘÕÉ`kQ5|GÆŌö°ģ_Dvō{*ijRåįî>H–ŠVũųâ‚<\ ĶK•î^5EĶ@iÓ ‘RËĖ[ĩDéįÎUJUëöÄđ’Ķ:š?Vúg›fÝ˕Aå;[ûŠP$Ė֜ģ DŸ”S(·Ÿ™Õ;pëž\|Îņ†‡ÜÜÜ|yYí1G§2(xŅZ&Į1›æU™ĪķįÜ ;ðĘ"A• ™s:–j-OR@ÉŧĮû–Ņ4Séļm˜kīŌÖOßŲą@ú5OՂxzužP“ĻB”ˆˆĖ w—Đ LÖŽäGGÞ~vŸã‚>°›‘ĮC qîaßũNW^9—ōz}tũxÍą‘Ĩ"2ÛŊuLK†éõ’9XŽ„T™šû|ĩé þ2]íÍ͝՚ïéI*‘įyf…ŠÕ(#DÍ’%kč#R"°efŦõĻT)–'ŅĨ;ŪjUĄfŨČCĮ]–ĖųÎ―cNô 2ó°ek=û°Ã(uEp\ŪjlGĖČčŸĀÝIīÕŒHË}ͅ&&ŽéóULŸÖt)ž=Ÿ‘AĨˆ„ŧŅ@î;Z{įä.ŽØžįÆôŸ‰dĩŒŠŠēŽķįSG'ž1‡wĐîþ<ß@Įvũ˜ŽyMģpVAnnnūžŽ6*ŨązÓĸ âXGëlPĄŠ1~ķUÎÏģ l•9ũéáģMÝïĩĖÂC•yŲ@‘˰e%•™"XĮ#ģÎýTāxžóÓ3$”ÞÝWTmQ˘ļģõËL§Ē2§ßŦÝąĻšˆx·-ŋRÕ ÔŠō…Šâ;^"Dloûi2‘t•ęļspTž€fÚAsŲ:Ī*ÂĨ3ïoú‚WŠō6Mi%2ÅY%9Ķ:hEpēÚĘRr}™?âussgĩJJÉ4!Đjī9Ž*UËĘ Ž…8ģĖÁŲíąķ>ķũŋ;Þŧo’EYķÞÎ'„jڕ]JŠ’ĪęRÛ~ŽÎÚēð(‘ŽT脾ĮûޚcÁ\v>ÏČ0U’Ģ€FføÆDÆ)Ûtš‚'~GÅÛ_― ÄÔ^D†(_ˆHe‚Ô9L\Bœ6^ĻDv8pŦĪïs‹īh“-ßĻ,]Ü{ĢĪ―33"˜Ģ=Xed2Į!777_œŦUNį“_Pč<XĮƌĘļÆë҆ŅlĐE:Āu"ˆ v@)RRÖY§Ššą;ɞí æčA7ááĐfs0ŨĮš’{Ï!ŨGļû>ÛĨęÞÎ ]vL/Ä4WļŌ”ĶŌ••č2K$"@t{Žîs·)þŋķįmÓ  2süĐLũ[ÕÐõ"sĐuŋDūuĸĻėģûWUþ<įįĮššdæHĸäË(Ќ_ŦŲŦŋø_Bšý"`O6PĸF·Uĩ þßDu å7H@~u>―/ü*õ ČߐŋՇĪ5$ä;ā iøóÛBÁ_ïJĪøĸAjũ ߓ―zg$Š―œŠ››ý$ŸÏ'ÁŅ‘pō„*tN—U)ĩJ&ũDÕ8e͜šYÎîĸZĪV–õ֞KUĩĩ:ÉLĸėÄĐz―ö>œ?fJQĄjހ0ӈĻH3ĨęđÏČ$•`ÉEį;ģø“ÏŠ―P;ý„ óĮ5Ÿ{gFAH>ۖęG]Î `bâšß‘˜V)ĮólįXģŠäo āÏįþũSČó›ýø'ßÖ5۟üā‡ožŸŽ•ø/ßĸwĸþĸ§šþ†ĪĮTy5SŠHųÛøŨĸöĸü[Ó_Aw Įþßĸëũŋĸý?ųOĸKhý)˜Ų'Ōäĸåî;ĢŠšūíOŧũ"H“"D]ąÆŠ…hŒŅØboĻØ@ĀJQ„ĻØcbI4Å*lX°‹(6Ĩ ^:ÜvúŸ―— ïũ2^ĮûðōχŒqĘ>ûœ;ũ\s­57Ŧ++Sæį”Tˆ2·Ÿžõųū#šŠŠZ:ÓīŸÕÖĻ‹a\đï+4ĩŠČ/Ū]š™]AĸÉÁvyðŠŦËĘuœôžĪ^SųčÁýŸ—Vþlð0ÝĸĖ?›ÕVUVÖBađĶĒŽFĮâiŠË+ëĢŽēŠåÏûÎhIsóĘy5čŌĸúšZˆ”Aā”%Ĩ )Š<ÏAé(H“`ā4Âøô1q#îąESŲÐu-ĸ=hĘQë”T8˜ÃrPÚmĩ K˜(Ö_gÛpM”ļ!Ü/ÐüJãû86—(‚„ÛÕ[2r K-ÏąĘéĄDâööư $°xøIÁ9jpRŒ›p)°DĢ/=lýŦĀÝ"ĻÕ(ã‡ó`0‡ĻŪaŋ1ž&ÓĮėü3+hšĐxýlíʀg•ēJÁ&G†,ۓĀ*%Ÿšzį3ĩþS@ĄH>õÄÖݑŲāóðŋūĸ§Ŧ)VWHō_V[QĒŪÐĒĨ™­ŠÝžþØŦ†ųkîIÉڔˆĀĐS'ûŽ ˜ųíīŋ&—ō$%óÅ%ï5ž,|ĢŠyųĮĘÅßųl Þļ1dož­†ĸąâpč,@ÉϖÞdÝĐÝ!ŅóU*æoŊR8vãXÁbp2ā$úAC/ī bdT^GīN: [% G(Ņ]02‚Ë-īÔá‰Ï‘”įøzor x"Ō0\Ībû\â WÂR€?Xð*ōœÓ`ÔݐCÛ04f—BÝ`0ó•qēČāē?dÁÄ ZéÐģÖېĢ9„ÄčQÍî6Æ€Ņc@Čþđ–nÖ6” ~ųð‰ZŌUÜđvæũwŠDĒėŲĩK―ĩĐ EļZßT&3+…Bqw Ē„ĸǰŧz­ôG ‚8VÄ6@2Ę$‚] Sp‹‡„Ūų‰ÁqŅų vŸ­âŅ\âd&šū$Ģ‹\ôå >‰Ïi4Ũ„ĐĢĘZĄ”8N |1lĐ.þįÅIZ™síā‚ ƒƒž".ĨĪß7ųDȌ}į3H}~°·WüÝ·ÄG … %/Ÿę'.\îā;ßÄFiJÜų"ČX„6;h™WÂý·2EÁŽ'@=ļH‚z<”‘ˆXëh˜ô%ĘAã§ ïb[w*NÕō8t#ęį‡D4įŸ<Ĩ+Ęäė{/_åĀmÖŧÄbŠŠg―ÂUĖ4Ņ'7ŽØPuÄŠT* О"ļ,„‡ĒČSx˜uJÖ KÅØ Y,0‘A`Į 0 î_ļš‚Š/ &°`‚”Įžß.˜|pŒĪ(ĻFĀ'JPˆ†P‚‚0,ėJ0]NýŸKŊ$I2næØĨ‹ÅóWęâ7đYïÉ‚ĖžęÚ'iŊûvëÚŌTšztÓ(‘c\L/†"_'5sŊÆÎž0ÆmäˆïüRĢ 3SŸû͏CįúmËЕTJmĪïęĀ Ŋo‡t›ėú\īũ,wŨÎÓO>)S*ČôËQ3‡>úë=I™2EéjߝK‰đ|hũÔyĐoõėëī53&ŧ{Œ3wUjf E“@9ĩų$ĸŋqÅRï ũÆDÖŋūrØÓsØā!3’2ЌŒˆ—‰?Ϙ4lØ  G3åčF)ýÅČļã7ĖrStgũųŦÜ:EŋréĖogâŨ/œūáāuZ‰ïĀŽētttrqqqnےĐÎ Ųēeûķ >Åëaayú­ ŋEgm:rKIÖ$â>rÂ<ß;y5F*âüķŋåKfö›r*1=zýę ŦWN<ĻËĻ…ÉéJ%qõŊoČúIã'œŋ—‘‘šŪŪbHöĖŽĩ#Ý=<ƌ―žŦUŅŌ݋‡Ķuė9ýÐÕŨä§ī‹ĪM­Z9·kįâŌąĩđf·ĸž”ĖšG6*}uŲ7twvAöÖĨģ=Fë7Í'-_O#x!DJAÔ<]ģdĮë*QĄþØ―xßĩ<•Ē&&Ėß}äˆ>ĢgDÝ-–Ŧóđ”py_ø’YËēĘ*Ó/žyĨf”x/ņČôqƒGš}érāTï,óÞ0ýŦŪ|ï―34Ä •…(ð…EjŧķƒwwV0töĢ K==Fļylüí&Ë._9ž|~ü°ĪÆå‹nų7"}ÂnDžõÝxgpx%aLcVĘW<ôšžšę<5îĖé° ąFĨ鋖G8L8w6ĶQnüōÍ ôįÁÅį―7Ÿčĩĸ;ŧ܈ļ|Փe~?šo‹>8öPČķ—å ĒSÛþÝ\ûįÖĮ^·iöĒÕļSįNÏvx·tv`>K1u‡‰|#ŧv_uv5ßĮoýRëF„ķ27õڛ%A;ÝmģļŠ)äíýcŧÅQ‘ácŽŊZÍ((XÕĩyBĮ~ŪĶ"'ˆžDõîÓÚT_ęāÜĨgËģ}×Oė%ņ Ō… gļ―wkЊåÁgŌ HZΞp4:þ•ĸÁŸÛTÞ8•ō ýŪ=ZķŸģæ‡U“ú>ˆ _ó뛟NņäžmÜĢ'銜ôĪëO'î öÞäÅõKÔŌúčĢ m ÖyoŨ’ŠēĖÔĻĪįãýÃÝ:Û>ŧ™ŸÏJ5/vDœ™ô{t—æš·,]ũë„cšÝrwāö܁úĻ!0“OúŪÛ~°Hkb"WĮžŧÂI╄ļÂÚ&M­mFÎ JNŒ[–së5p:ôo}Ų―Œt­„eqö‹įeZR"ÚđÍIšœļĘū<îĖ%ŅžđG'—/ĮO  tīïß―[ÎRėÛÄųŦũYqčlėáš{‘ū;Ŋ’*2ûvŌÅ{ĩ+wödŊEÝzÁŧČ ­ûÏíÆ{ïđ&ô·œRAaxŧÆgs“iã~ōNÚŧíRV­kφ \đwß“û”Ôh)’Ž.Č~\PJĪĶøitBēđGĀĄf\ßŧ2öŅ{ƒIŲđ9Ų>zþâޓüÞį p(ÉĖx|ĩÖķ{Įīð>ãöÓō2ū™ëĸmZč™õð†ÁØĖHA4íäq(.qŸĸļóŋFģ%ÔĪ]ž@™ļíČŨé'ũíJ2Ų~üôšy=đŠr@Ŋ;ԒDhxŌ@KyþƒV€ji11„Ī“ˆuŠĪ%žÚĒïŧÅņ<ė_ˆÁZ"i Ð M€N\ Â‚Ό€Æ‚Iė†_TðÂT‘Äžģr‚ČUË Đõ8Ž€ÃpŒ”,€eT=&Jš"­C–āŌÐz@“hEÁ‹Hš ÉŊ24tý„`á‘%ĐîëNĮ> "Ëq˜ÎĒĸ†š9Ļ7ø Œ4Œ‹3xüå|vv†—ûö*ŧsĸė•ŧfCW-ėkyėÄáUĨ=šķŊ~“Uýv‡ŨĖ]ąŨJÁĢ G [Wō*§ãĒÕóímlÚ99”>ūŪąpįŲÏŠĐÓŠĐn%Ũn•4kd}”öäqÚÅWSĶL°Ķ5O’ķO^šébĐÖTÁ|\J11fPú–VŅ4Î>“ÕŊN~?gÁá§ų*#%E*›ķmlmßĖĐU %’Dý4å,éā6ĮĢ›ĩcŊ•ú―đtKG0Ē…õŠā°A]ŧ:·kŽĻĸ␊u‡ýŋĝ8šëŲŊ›ĶM ÏĖĘ(}“{ųpčlŸC%o­V0oaS7g­[·27S‘” ÄĶĻ•?oûMņ ÐßõŦÉÝ­›>Î)§0ŊdÕĀ1ŪŊâ/<ÉëčūxjWæĮ#ûy‡Öœš2Øó“&–v.ķúuĄûjĮîØï3Ņ˜âō^mš;mįé4‰dxQ%ëŪŪ ĖtnfünB—nœ…ÍRÉ3ÔĘ8Pū0BQ•> ú(üJ2īŸ"ÉUel‡Ha_DÜօÄAÔO…ĸ€2)Ļ0A+ĀY`(œÂĐ!’Õ3ŒˆÎBĨØUŨüK4i5ÔKáJX€Ktk,SˆčrjĻėW Ų<%f‚*• n)6ė!‚El*:„d'†jŅŅÁiJDÃáŅxžåú)Ć-sĀ—<%q0.ųŠŋÍ b XÆ>SC$+įVúŧągŊũčŌq@ŸÛŅą9jëîmLHNīģvö ?—{d“…Žð\)MÍéēŠ—ŊKŠdŅĪĐ=Ą..ĐB•ųo933#BFš&o ž“d/ĄÅÆĩþYZ· MÚĖ]ŧõŨcG>ÜÝ­ĐJŽĮ8QæÔ%ZlŋĶ4ÖÕEŽ•$EV—žä ÆÆJ\›A™eŲRĩž šĄ$hc­ØINASŒŌjōŠQ1g’tk"ó"ÉIËÁÃmnGËĻQÔĒË?x>ŦI‡.æJŠŠ ’žü/_ēD1xŒ›4ytWG Yâ ĘTnÏéq@Šģ…wugifĐlæÜ;8|üû7"W˜ē€ˆF’ãž§,•Ũh ‚(ÍÎeŒ:Ų4ǐ„JʄŊÁŠÆÓ6ļpŲ’āy―N„]Ûô:0c }ČZ9}9ÎģidØÎc1ŅöĮi!@F‹ēĩĢSa|LčŽ#y”ãŌ1CÛšfóķ°UÁąÃܗtķĨhâČĪe§+?lÞ*I/3žA‹ļ*AœĻÓqVÎCwsˆÝs<ōØŅ\ Ua"Oļ/ÚÚÎ,sÞ7ówîÞ―|Þžôũm"VN7ĩmŅŲQ™pdgdĖŠĄë‰ QUÅÕPŋUkýü6üüN'ģz‘Ãw zãUfug1ņGvDĮey,õękú(lŨãGï:y™Ûô"/) šĀĩ>aaÁÉîÓgŲЂAŊÓģ0k'9Q–4Y{|6Ä&ÝŠĒ,ÛY›ØđNínvpsÄoą‘?ˆ+á$ęcîHČžéëŋÎÏÏgÓŪ šÆŽ3·šsíÚ đ3,eĐąĨ}ųÛ{QQąÉ…ėéÓŋgW $Ŋ7paŲķƒ-đ#ÐowÐÝŌB”MĖíĨšÜøČcņ9šKI ņŊ*švÎ:~8ė§Ø Ž$ :žãėûLÔ­tÕ ĸ°ĀÛSô_-ĸÚHdōOžAŨPČ(•ÏũŊ^đ2|ûö ―IÎŪÛ9õøfjŨ‹ũFF;°72ģ°ÚĒu[íýÔ°[ģ5Ķ=ÛÛýū›ßōUž―$ LéQƒÖmõņZTęÔRGNáËTØ}1žąPķicË4oŨ―‘dŅūÝ€ÆØōOoišŋy|ŨŪ ·Û7VÞēq}øïeŽą…1wõ\ĖŲ?ŌrËģ.ß|ÂĪĪ7`fb4āËQO/ð^―fđÏūôœjĨ‘qÕģ„oįøežgúĸ:ĩĨýüüþûĸ­””ääėŽŽFF$I* öŽEe(ļ‘LJ„tPEãF7‰áĒ+ĻÃu`˜áŨÞG'Cžm8 ŕû—žģ5E9?ðĨDicüJģ^dļ‚ Ę~ŌŲÜ‘“e2ŲßupĶĻĐf˜$F^,5Ø ëDlßļsëŠŦWYķāšū§Kyä%]ĩŲÁ?::Ę,Ëü/Ečðððßģ€OōÍŨ_y#Ūę]á•QîđdVÖ.VŠ_ēũm!]W~ëēũ>ĸOŅ݊eYēĪØ–åȎ= Ė L2aúÔæĐ8N\ętō0yfJ ̓q›6i  y+} -y()īSZōŌH‡aâŌÆ9qmëjŲ’üųûŸ―ũZŦGkO(i…íLԖ~į‡ŸĪĸõØ,ÖųíßÅëÁÅTĢûķ·Î]&v]—ō\ŽØ[΃n·ødÔ^[ bðLÛė·aI`&ë]8{ö•ļIŒ=ž;k1Į'Fð°D4ž€ž}ã4jĘŲšvíĖ ÍšˆëžŅ4ķNeóc.h―…B ‰ÁtūÁ‘Ã.Ðī Ķ93Ũ‡9F5™? ›(Z0ŋ­Ú,sC55ŨrÄšîtŊ'ßßĮqýäSOýƒŊãÝw]ÖîäÆ+Ŋžšąą:yōÄ,'įžĘ,ãšŌ0mĩ‰š_ —Ė0Át+įÂÐĮĶHДēœq]ŌP’ĸIÆęŨdXYŧÚôJ­]9úš —’ýđVĮQ f ­†fĩŽ T†Bqß<ÖxL‰‡’MĨķžōāĮRdŽý–u\ßúDJ)'Ō\_ĸé_üā{ßûϟø[öųß9é”OGđõõÁ៰åÂ―uņwAŨaųU!Ó6VĄ”KlÄ&ëąÍāܟ<õ•?øGĸęĐĮîšų-RY‘Öę+aĘĩ5ÁaUð–oúKŨg=*ĖðoF0CÆu‹ËÞÆQĖâcûL6BhĩAXjŋōŒB cS†ˆQŨĨÕĶčW^ĮzãókE8•œbŧŽ­`Y RGŋ+ōWūõƒÅ1roĩ‹ÞüÏgÍxãÛļ6*%{ÐĻš§ïĸÝ/kßįþãģO1€ļō—ķŦ„}=v@^ đųĪĄpŦ9įD0Ckm”J"4CéÍû\Ú8ÃLãFY‡Âþ?áĸđrō—^zŲĖŽ?Vkû ŒÚŊ}õïý‡ĸïvíÚEī―ÏbxUQĪį”˜S“hā÷‹_”Ht-úĖuۀųĄYrÔVM âFޘݛ0ÏYŊ€ÜĶ_c‘äÄLcģf"P51ÍNƒÎų‡sģ‘ũƒÅ #†HĘEĪÏ ­œû8šĨ ä™_RJņÜGAĩĀŽvā(Ę5圃`$æˆëU€9‰FÅRÔAÆ`Æ8ŧà FH*ę•đķdt)ųÚĩëO~á‹_ĸÆ?ų ĢvH†ūUÍîÔ{ĀúĩW^ßsė䁛Á‚ÛnyŊŸ―Ž{8vw@EÞmGíŊÏÕÆä›-ŠÁO’ģāáYðãė8VŠų•Ā°yžwœ-­ëÕjŌURžzmŌ%nØã8ˆ]1^Įķ+sր’s˜rfJæ>Wŋ7§Z[ë=ÆšĐŧȘz„3$V“6{+ØTīwéÂ9Iïā ĒÐĻŧšËB#1GôŠĄģķ"R{c§{gĄ"؜{Ę\ĸ–sÐL$Ā<ęĖÅÂā~°˜bļ'/†0&NsãŊ|8;øģÐoĻŲ|X<}úā2gßOŲ}ðū>ņŅ_sÎ.É^Ý·)ŨÚÁyØVĨÝ*ĩÞsÎ%—ææŨjáûrM0į)i‚—‰Đï°ä n ꭋ—ĮTÍÐn€ú֖Ļ0ĩs’î [`‰Ó8ŽÆ>é"ū ä\ýį”2ĻuiMZ@­·ķÐißRJũ“Ŧ”ýnī !pæ.b&n=ā CRdãΒŽė*ąęƒ˜ 0âi(ūķoĘn$ëÁ\ŧFĒ™ösŧ^rŨŸĐ‡ēØĖß%%ƒĸŨ°ĀĪwx?,ÐĨ…ôŊ2jĀåŪ Č ó*jŌÉÛ―]&øYŨļw;ĄF-(30öŠóHŸĨ”ÆqM@yĩqøž{ĒN&|jJˆķ]§æux—Ąaũ耠|NáĖÏ$iS/žÓŲ,ā[@Xo­Ŋ\ūĻ]lN:WëœÐ0EØĖßÉ'{o­Ĩ\ÐDæ-ū+ø;&ώ1p5XĪ:ČlK€ÕjĨĶ@âŧ2ų†Ý8ÂâA#Ð,X°óFmōY֛æĖ‘/Ô`ĮА(Œ )ģžëĘNYV?(ós0éq\1MÂÐ{ ·ęÞ―{?ĸ…§ü·&RXUnŨūƒ·ûĢÃüïðæŋÞæa)Ĩ—_~ųŸĸģzîÍŨSɑoāT@t…5@ĖÃā\­"bá')ĨøÜūŅgÄíÄTVE];ƒäÕd­É°*`6nEáBŨ1hō~8=‹ķąā=Čml°`Á‚8j=į;ēŊD fĘUmB”Î﯀L™Z­4·|ũØ4ÅŒ‘JĖ<FųŲ―vˆ3xøãgĶ#ļŸüäų'žxĒÖz§ųûÉĻþÝýi―õÎDŲ°æxYfW˜Kŋ8ZŅ‚Eat-WW•œ˜R’Y}œS™Ý˜ģu–S4?zŒoĘ­7bU į1EĸFA"Á‚ vÞĻ5Š*°yNųДēÃT{•(Štō{fŊĸōnõī*öZÝZGõH-ö‘+Ė ÝÝûąûxėąĮž}öŲcĮŽ:uŠũ~§§í§?óû?ûïĸíG?ü!ÝúК†zĄķ™č!V ϛ:+C<ļ ЈK™ŋ`bN<ŪŨqjčɐ ˆ’įx…,ļļĀÖOÔ4ŧhaŪöݎ:K‰a‡ž),X°)oā‹ÉÍĶ!―ōÄBäDę0ÜSŦÎð&ŽžAįJ•ý|ÉïĮįôÂ}ûũđũȃ§Nåœŋýíoó›ß7âXo^4™―†Ý #[õfI&$ęâe9‘“%ŧ'ļV@`JD(ŌÁ v ,X„îūU@P5uæ e@ĘĒÄ)4øčZڐĘOHĩ60ˆā‹(–œž”F€˜ĘÅ @A:D~ˆ9ŅąSŌöÏ~ú‚KēĀ} @H‰ļËo”ˆžģ8Úr2ž-⠀0Š}"Ë&ú(Õ`cĩÕÞ%įũj‘f jmމ؏ãa*ĖĩU@@óWë "ŅÆ`įaÁ‚eÔÆŒËļÐg°é`âÛ"`ü’V€)ų]s'oˆS7xŽ8ĮĄĸž}{ïđįHÎyĮįŸþÕ˜U°7ŌHÚme‡iÏÄķ™Ōķël|Xųï·›ž­5p$æqkKzÏđˆ4Ð9ĐŦõy1]üsv #+# ™ŋCJ‘°cņ†ĖmŽäÁ\âĄ2ž2c.›ŽöIpÛóӍæ–ōę:MÏHÄ>ēQŪv‡bÁĒ@čĩ—œ9'l­brŊÝ@=ú:ĻĒQ§,é<Ð8G™ ĶčļŨ9'BûčÝũ<öøã­ĩ_üâ“…!žŋāðđøâÆ;WVWÞæõGN—SŪø‹·[ó{ÔŪģn_'ūĘxéoģūMÖķ_!€„ĢŽ7+|Ū\đœ8wdĒ:V"Î%‚jĮū­“;ÞxHuÍüpÏÂúeDAGkōė.ó/‹ėĩėUâKoŽāø%ė{Ŧ:rNˆÞ.áņŧ)gÝÔŠũZ°`ĩĒūÁqƒÞ[LQïĪąœį&0ŒŲ:wƒš†KDjm)1Ĩė$F‡ã݇ßĸýQ{öėŲ›ė9"āÅÝ~ūûœĐ~xŨßŲãíĩ kßaŲė`‡C &hčuãÖ!ŋéŽð Ũa' 6õ&wŋëŌđ7―0"$= Č8—ā2…õK'€& ýo 8֚yvŒŠúęšr˜2\,Ė"qhĄ3·xhW0_”ÞZWöQíųāRÂĶÜ 3,X°`ŽÚč1īPÕútˆâXfoĮĸ[ö,ŨØ {ëÉĨÕÓ9ēī- Äšyä‘HEļxņĒŦR Y3ŅģyóÕ]’Aޛïûäž Ļ‡! €Ė{7ØÜ}ũXOV#H#ðĩDï&ļŠé’ô·qu=IÞZŨMŽ€Œ Öĩ§ÄĨ$DčÞ8‰8ũƒ3Ũąr„ę uïþbbđPY€ŠJÄt%ö Ë%Įũé%Bę& ˜ˆ{o"šsÎŌšĒ1“Ýä|}‰6X°`ÁNĩY‚‘ãyƒyŪ°e6_`ãHÍZoėč―‚Đe0ˆŽ[4ģš^O&ąG}lZiŨëõ4jCņų,ĄZ}uũ›Ėb öÞļ{/Ŋ; žĖĢDšM}ėÛßáļŧÁHęÅ+güöFŋ:ĀÛ0žŊðV–+ØÞ’ū)`@@ÞÖ<Rëā`"°œsīãø°gߎÃbKL>x…|~y0P°(é‰å™\<‹z#5ÜÅÔ,X°#ŧÅĖĖnÆYų:ë›]ëĐ$1SÍ%ĩÖTÍŦõ9z "ôkŽãÜ"―2°ĸĀÁ#GŽ˜Ų4g/]šeD6‡·p Ӎ õčÉU@øĩā“ÁĄķßĘÁėnېÝ@ÐÄúŧŠ/Ę{/ŒõG p]Ũ`ý`žœ HĐ`Éĩ\ҌGyĩVrF„‚û?1ķ:ûÓZuš)–âč_ĩHcÆ)(,X°`'‹‰„ŠylÄ!ŽëŠ„˜‰{„(æ4[x ]s*Æ)ΑŽÉÊóžeX:õÐÆŪ Uō777WŦ•™ÍЃockQ~ži`4ƒß ÐÐÔ @ƒ}æ= ũ1âÍ?oĀØks$ĄŸēwŲ:æąčFSCg!ˆéfĪotũĒŊįž–ˆ­E{ÅCň&Įœr.æÃ&ĀĸŋX°`ÁmĀDCDÅũÖĖLâĪĐOˆâXdrqBb›ÞŅtg✊—Ŧ‰&Nđä‡Ïœ™Ž“ð`’”R˜™1pŧ€UŽð>š~ô_sã‡…ÍO Ý.VpQp‹‘jjĩÖ(`ž™ æˆ*"”’Eü@Ėŧxk­Ķ6 +"ōïŠÔUB_<Į0šýbþžŽĄ3̐5,X°`ŽZJIAĩ‹ŧQ9ôģeČóœcNĶÚjó?SņŊ,ÝV‚mÍŋÅwm|䡇N‹ÜðãNBJ á˜0û ũŅŪ~Å5ī·ÆwŨ2šIÕqS6›uøð@S­ĩŠ˜Ûq)ŽéĘj„ WsÎŅ”kë=”Â@ĄūNŽ^™ĀŦ‚M”™[mL‰™‘ Ö9čËL<ęW‡ÕĘĀ]u ,؁ĢÖw.ÍĨpJĩ5uÅĸžÖA—îŌ}0D›œzŽãļ]ÁM*Š‘ŸíÖĐĢĮŽÝ{ï―o°^Ŋ§Å6ÜbԚãƒÄķĒņ7Î^đüúžOîúÜwĸ/ýōïýŌ_;ôŨĶý[šūý’{[æŨ|ýd&ōä‡8ë3OŌI\ĮŅO‘|ķÆgÂ^+x0€EÚ3+ĻhO9Sâ֜dH‰Âë<1øi[JÜZSQ „ ėĀd/_c˜};“”“7ļtSá4€‚Ļ!q vq*b†î°2‘đL,&5á'{|ęõšrĶn›Þ{ÎųíÁ@b8waýóŋũ{ýígũéO?ŽĀkï―ōƒ·ūĸÜÅ{Ą^ʘ!`&€M43T“‚ū^þ æĻ/Ššæ4˰ :ÁČW]ÂÚ*##‚·=ŽHĖH!MvōAš0gk]Ð\„ Ņ>#äŨC|’zÕ# ÐÎ{-X°lĩ•]·ķ4åėŊMÕJY™AëÜŸ j dbĖÔZģ()ąiWSböZQÓ>|OœĸžôŌKĄ=øešŌÞįģ2^:?þåšúĩÏþÃï>ųLĖŲ[q|ŨOßũĮĸÔ?>2ÜÓŽÅ+€?þŊ—ĮÎü‹ĮĸÍŋ|ü;gv?Zĩþ mKÄ1gU |Iwq›03Ļ3ŧa·’_3ë­Ą!ŧËÖf­‰nWēúƒýŠFē-…ýŨ,žÎĶ&)ebęĩ",X°`į…(†Ý+…"01!Ζ$šŨ:_ːC―”rv TcŊƒõ°pãÄ.ó:ôÐéӓCl―^OebĖ|kn7āû\Ų8ÚóĸåâßøÔ}åÓOۘ`W·Ök­‡?ēėýԟ~ėŦßzéŲ-w˜qģ+/―óôßüėņ]ĮāŪrHM…UP0é=•Č|™si‡UĐãˆD‰ ĖšŦ_gįą*ä’[UÉ)aũjŠc‹XÛä1ˆƒ!Ķä,„ø6―Ón1"_æÃΧæaíĸŨą`ÁēՊ4#DSčmö†™ZũÓöXNC>ED­·Þ{J‰LĀ(ZMÍāðáÃ>ø ˆD-nWcŦ ýOöÞ<Šjkß{Ÿ2“―„^BïMPD zEÅWQTė Ä DAŠ( Ļ6ĪØąÐ{ï- !^&sÎŲåŋŨÞaū\‚åûŪųžßĸ7ë‰yvvÎ9œŸžģÎŧÞõ.-+ļ8u@ŽlÏ­ÁęL―îÁ(à íï/ÜqßÎ^õîõO.ž ŪÞėPĐgĸĪ jq^ëĒŨk~WŪ āg•Æ€RVę ÓŌ<°Ý0?`Ú~ŸįQílŦ’w„ÕŅ͚đ ŧ! ÏLwÕqŒxin ģŨĀ­‘€âKŧŲVÜl1ŽšüÎYķüčī™Ûߙūýó%‡ũíË\”“=@ۃ`üg.m„)æ+†ZlûmBôļĶEYXUx ÚŪĖĻ”mĖڒĄk\cz ī C)s…āÍ[ī0 CNo”­b ”:č|`Ĩäîđ;y8Øđ]Ÿš•ЇöóžœéĐ3ųãŽI+'ÏZó)ĪĢ*úWXß$Ûwô\ĩJÕŠWŪĐũÁ6VÐ #€Qå[K•ˆÂVÙBOĖ9sÕ§ā]Ýđ+R3րyП4HuÄĐ2ÓMJĶ›gÚF—ZØ(7ĶeÜDÅ$ģEEîŠoŪ\—.âĒ:]Ņīkĸf‘ÕâݒątőėŽä𥷀9Ų§Ž?~*ý\#Čå; ÓČ=žįŦU{Ýp›ÛŋáC­ēdœ2 m––0=ĶP)öĐPo ’mŲšý_ËĪ ĄĖóÎëO‰ã*ŧĪī”/­ôŌýļĪL`äâ~ˆr;ïŽk‘ĻÆ Û•Ýß]°u[Áö(#*:1šjJÂó+?Č(ÎC*ŠúŠu4û=TrE•ūĸėþz1•õ~œgFƒF@°ĸĘg•0MEZʐLƒ ’•8:ŸÕ#Ų‰’+…ęI NęÂđÎgĮ.e”jAģ―ķmÂĖ`üšjd$3XƒƒxäģžĮV­I;ëâÎWĪ4nU'"6Æ]ŊiÍŪWīĖ'öŋĪƒ”ý›ôÝŊ>~Ũ/Ž{čî›~ų―ãÔ$ø·ĄÖ:·nŲ+[ĖÙíĸ8†Z(Ýhï™Å(ó\WąĕĄf ZĶÅáĶqR#HœR˜%$”@åG…ÜŊ’”$•^’Ĩ•Ãqsrräï.ĀYý÷‹ÄÜ3N #ęķÆËîŊËZiDrЙá„DĘ9•™—zšÔ?ļ‘ž}õãþņD”iëý;jŧåœ7Rf5ˆnēXĒôéÞķĩŨÓ= Z'Ŧ;,”Ŧ™NŪčWízŪ{Ã0ÖVg€˜85ŊA5,pϰ ŪëaÔĢ€öôRJ2lpŪšu+ víĘ8”hŌą17ŽÜbVäAž`."Û7ĖaÖķí§…(}ŋxŅđėï–ž{úþ>ŧæ=ŋtÝ NpPšU8L{ķÁ‚ĀČBrã 3I4$XČ. L*hãäņŽK•…°AĖåŽŦäqšk‚ÉĮĢ ČÅĀ Ũq<† “xŪãzðÆĒÐeÏ߆€C‰`^Ðq*ÝōļŦóĪ0Ô ]OĸoÕ;^PîĻ2CéE° ŪG G8þ6ĻÕ-LeĻ·ĀVŅŊj ÆŊ”ęF2íÄ*Tâ&/īzTWáĨWlrrđÞļqãæÍ›5"ŦÐk[ˆĸ/nČād{1vtƒ2ė@"ÃI7ÔK°Š Ü+Î*Î _ÕðEE*@ E‚T?Ši‹ØķņV‚ŪaíöĀđ6ęfL*j˕Š$ĸÔ1ÁšÝ@A$0'šeY{~sÕ­`™–žÚ ŲmĶBĻþfFÕZëš 'Ķ6dxԓ?V„_-gbρĖļzÕýčĶWtïŲ}ņę4ÛĒ '>­nãúw—ī}ūÃ+ß―ĖÄQÇöėÖîá)Ÿš–?sįWũ đēߞ·Ž|ųt‰0 ]ũÕĖ]zšĸþۆÜþŌ‚>Ú°üÝ;úöësíāĐßí5}þýË&>ųėÃîūþÅŦÏNĖĸķ@DjĸVŠ-YmM) !ÔÐF/ÔPë([SĐšī˜ ’PÏĨŠĨJgLIUŦmÝšUĘi%ėĘAđR]+rßoŦ° @&V>­%É\,Ŋ˜ĩ›—ÝwxÐÐÃĶs"â'ØB‡ģÓC4HLjP;þýßŽ;s4īy6“^˜U ũ"þ,æSÆĩļ†HCĨŲĘD‘€Ĩ·Ā ƒ ÚÅÜĀHË3īĖ€˜Dp­É6žõOíÝĨ. dŪ€ęcZķÅŋ:(ã§ÏæGVN,vXĀŸšxōļĶ7sÚÔ"‡\nFĮœÉ*ÔT b[îŲSË>š9î‘1ŌvjSŊM,ûqåØÁEL\RhĒŊ_j⩜—?XüųÂųkF)įâāó^˜0õÄí7_cĒF=oĸô›oŸ―%åŦųģ úთgîððåŌzWßļzuznŅũó^™ŧ7ęģeŸv-úaܔo°mãŌĸÅlßĶe 7æ>óÖīîþÕO>ĩô‘Ķ éņážbīï3xŲ?>70wÎÄĨyӜÔÏfΊÜgčŽ7ÜþÉäã<2ĄÞÓūZąðÍž óŨ+Ē'ŋųÜ—MxoþØûŅ™mßoÍpŌūxĖÜĶ~ōî} g›t,ĀĖCŸ~õCÜ5Ģïļšģð<ôũE8ÂsMÕú|ĨÎڄŌí–åđT.9WS[Ā Zþ…ŌKĐDØP0$ũԘĮ•P’y63/?_› „zÃ4Ĩë8ŽöTËĩŠxŋl1AÜáÜa­k5þW(q<~Þc‘#bŠę`Nfč€f I­;Æ<þáÃwôŲmā(―đāÔĖõ9kcíøŲ=ŽAAė8Ԁ,·Ô #ād™ ʈnYæZW‹Lpĸru]ąĻ(Qu`$ō‹g\Ë.D4XrøðĪþožL;q$ģØŽŠĢĖĖ-.Ū]Á$ŊĪðĀņã-šũ›þĀU]DŧpÍÓ/OƧÉvDÉڟīšaōm’=J-ÓĖŽņX<åū ~ču—ĨÄđ%đđÛV―ë™{}.JŊ^čbĪm>8éö>&u”Ÿr8Âņw™(ŠÂ‘@ČR#xĐŨŒÉ•:É4īÞ@52Ļ’‘* a pyĐ Ā `°M0d‚ųđy•*W†Įp!E- ĨĨøš{~Ą<c#·ŒŦZvŸ O•ķt˜f Ó‚Ð~#Ōoų‘`e€ŽHäœĨ'ōø [ЏP&īÖĢqĪôNjrš€ i ЗãŌä—Ĩ"Uė8Âįũ‹‚Cī æ1čôUéVӂáļ<Á1Á e.–[T„Ė+>Ö,Ę/ˆŦRÉÓãō+ÓîŒũėÓ/*ūR‰'ĒøhE<Ôuk5šcÄØ^ĩ-ðÉ ï>õÖĒ7?úþäÓË-G$Uņwh[íƒY‰‹iĀkÚį†ëĖeSGüĢįgþí‹sÅļ/?"k§Nĸ<Ã_ŦNĩŸ·l<“ÓlÏ7?ïMóōŋ^<ÏHđé†+cžúŅgžštH4n^―f›Ūŧ:qæ ãß{oÆ[“>Nw‘ð‚ ‹ÂŽŋÝAĻīH{t1&lÛt]‡ĻB†&m åDËu€@ r­ŠíūŸe؊äjn#‘ä@Qa‘įyšÛ―@H Bā Īūī*@Ļïj8CQ–ŋėČqÍĸKú‹(uĸ•į5Пą°Qƒ|ŨŅō}Ęš.âÂgÛ rŠŲ H0Ū&;ÏĢð˜Š+æ\óHÝ/§]%}Ó#Ë,j(ët“C eC}0Ĩž\˜0i˜Ąŋ8ÍŧīopbÅVVPŧj­ŠĄ˜† äw‡ĒDgÉĒiûšõinųLÎāƒ3:đËã/ÔŽž€< –―ÄfŨ͚ŧãh~ģ!ƒHEąĻfį!ó?hēnë^—DķIŽŦŅā֗šã˜øäĮÞYÞiõúäö—Ly/iëþŒæí‡ ÎØO#qý67|4'åČÉ<’―åíw~ä†Ņļ뭟}Ðėŧõ;%>6hVpĶAû‡ū0ÃĻïRsĀ=c{™5\—u0Ž^o_RƒĪY3ßݙZÐ|Čāëũ3ĒEƒ”GÞnîgŪįŦÔâÅioÕōGßųę;5~ŲčŊÞä†7<™Į#k>?aō;ÛUĢ–<~Ūi― ß]ýýĘcđÁ†Æ0·ÅÍÏ―äÆû0Co„#ĖÕáx^õeš`ĻGýˆíbL ųās­ÔĨĶÔ!)ŒāđÎŌ~W€&fQQaIIĀķ}J|Ą1·lz+ÖŋP_3ä—vƒï(ā:!œÕI.vßčO„–…‚—NHÃB]Ýu]ÍPŦŽ (s1İŪb‹2OOoœƒ”ĩ,SûÏĘĩšÍΉzkŧq%c\w:(é.….4RJ ģ  !ęÖ­ÞŧC―_6­ēžVĩԉ‰ûŅîéĢi§ķîėØ ĄAÃZ‚—lÅ$ĩlWyŪn]ãČŨĒëu­š#dĪīâĖó‚NÆ5ëõOÏa(ķ}u–į•û^óÏuIĮËZt&`3ÔĒ9!lïęÅ/Žûļy6ŋ.úūņÕ7­bļŽWĐaÛ!MÚÁ;É<ŨcHņ7iŨ]P—rQ·QëdŦŠuÕÛI–Ō}@ëžę6ZīäÔcœt­*_Ĩ–ÝšRĮÁInū­‰ō”@M[LOŽņXAR3ïȖí§[LîՄzũUę}ãāÞTmāpŸÜķ2æŪGQ8ÂņwB-ÆÚ#Fõė :•2Ÿ ādQƒÐ[Ĩī•k8Ũ˜ĐĶ| |ū]Ę0`.·ãåÚïAm™dB&#V(ÞÁs„a(ïFŠü-ÉýFüb5ŋŠČ…Z&XYčŅ€.€+(TwĒōV)܌ˆņ+›FĀũĀâęÍZ*HÐõŧĄSƒĮó…`•§i§ēŌ—Ę€FĀY@mŧĘņV(TYZé(ÕĢ!Š€ZŒIŧvÍƛvmË=r ".š2 ŠYQAŊVõÛīnŠk˜ĨĮøąēðÜ §—ŌA=—ę5…ÃՉÁ ޘëĒŌ€IņõZ]þėóÕROåô™{ŧV lęÂ[čđĖŧČÍzŪĢWĄį`\ÔĒÜmp‡—Þą§;AcŦ…Ā˜$ÞĸėsŧũózõÝĩcõh“q.rĘ$Āþ2áøO˜˜ŦŌRK™Õ"Åc*ÂØQ@3eĻ  ÓŠRŨuáĒŠ’VģVmƒ˜ųųđRó.=jEEąąqeĩ\š{UëRŒ™kåë9†â\_|4ë ˜ūČ u36BĐ)ֆ \$Zĸ…Š‚zĖC‚hLe Šy*S†/uũĨ6įō3 y˖És0UĶs=W.°ÂeUûBz8nĐwŒĒV=ĮE0ÅĮ§Û đ2@n–äŠjž9֙ē"sAwŽ<Ïl 8„)ãZTĄ1:wiÕļq3gēēģs‘@qukÔHJޜ gL Š ø4ōĮĩîÚŦ­Ģ qCĸ;ïnÕú-j5nĨ ØgÃŽĸä‰đJ3ë(°°@ËĨō\ÅfŠ:y`_p$+Û@Ī‚Óö; žéæėėlĐ.:uę”Üt=O:‚sD…ĩ‹KK1†äUQģˆĄ`€1đ§Ü/Ą€;Î΁&LPČ$–…MTšÖjÂՌŒŅwŽ.r Kœ€\ÝËQ ˆ1c\OxŪ†€mÅï2*’b+]3h ã–xōŋ€üP( Č*M0({ˆsēģ ä͚æšŽĢĸ5 H ę‰[ii-HÄ87Tp-Zp·Ô̰e)WāĢå­ÃĮ’jP.m—Ļ8ČcLHË*I•1&ŠtŊâA{ž‹þŅ*gÔa…#ĸéPŦúĀ6ÅïCĻ4AS"Ãs)ô°úl· ĪųŽĢ€ƒhûØÜŧgw§Î]š6mš’’"ϒóq333eW.ĨTb™\ș7đyđL€ F„ŦŒˆ€dķĻ„™ƒŪüĶÆ˜e§’ðĮM%Ģē°ý&6ËĻāBubuË)Í*:()Drƒn°8 ųa’’Ŋ$ȅÁ•9”E˜âė<ÎüQ‘qqqpybP•ˆAߗ 5L&æųy‡Úģk‡Ŧō\ S ãÁKBF~^`uęîŦüJ,SņČVģĻ”õđ›Ē ƒ (áÄô'DÄJĪ+,.*)ĶfĨäĢ -,,ČČ9—įŘîđĒÂėĒŋ!ρAšÅ5L “ðaųKęĩë”0äŌ ŨUŦ&]yUŋ H`UȄqúÔĐškÁq˜Óč3ä°ī\>[‘đcd‚ Ū{úĀāZ fĀ· b$ÎJ§}ûöUŠT!„čMđģGE›6mäĶŪōŲųýīųkï=ĶQ‚|iėŌž’äįâǐdYNÚã úýe=jĮģēā3ŽiŲĸÝlAÞkķi†Âņŋ•ÕDŨp ũQ ŽĘgKį*Ïl0Ĩ•?*;WƒŠq°XđR‡rA9’%ŸUË iĩ>Áóž(Č+$FĮܑŌįąÞ·œČ;óÕū/ķdîXwbcV @Ø8‚äyÕĮööŠÝ‚˜†„~ŋåoߟz!ė2‘[ÄxDBlDlq S—W0ëh^Qą›Tģr y‡ŅFdĪåŋĪF·:‰Õüf„Ø–ÄklØÄŠDâ›ó–2áÔö9Ę G đątíÎ+”RW…ė'֝c7Ž?|pŋÏgŦ~hŨÕęÃ$úÅĐöĒRtïÞ]ĸ/íWŪ\đS§NëŨŊOOOŊUŦ–ÚD…gRWþļåš§ôŸāŊkŨũ~71bāI+žu<%Vģ}ÐbåwžšHÃýRarZāôâũfÕčũÐå)Õ%·n˜ķĨÞŨ rņ/ũgÛ>ÆždûüÚö…ƒ‰Hm"eSwē[þˆ8h ˜üVjõ+‡r Āý>ŧTŸāļBŽÕ8ÎÐ1Ƃا>m˜ãxeäܔÞAnņâ7&Ũ>šomÛqĻO_Ãƒ G8*†ŦUÂ|x†88^ŧD/įŠÁ‰ PĶLž äRÛPvĐÝe†?+ëÜîÝŧëÔЧó)\&ôėH”” iÐsjWŊq_ŧh 5ïė{ūøxÏŌ?ã4˜vlwf›ūü %.úF6í^ĐĮšü5ĻÄ8ģ7ûŸ]%EÄKp?›—}:7}UÆN͙ũLčß ‹ôģÁqĸßu‹ŠŦKÍþrDPÏėqGfßÚÖK/kÝPFÞ tYOfˆŧví °ˆÛķÉÕtUï2UjË1}ØĸrF đ5(øRŌR.Čã*ĀŲ‹óÔÔTIHœ-_v‹ŒŒ”C1Ž=*YY éøŊDTî™>Ÿ/sĮũKvd ģ[–ü”ÚũާÜËOó–LđoúŠŽ”ÆÍóy”Í OMsôŠ-Y uZū4þÅāÎŊžyņĩˆ~ōð„1CŧíúzÎģ“Į%·ya똯•|Z€ ÓËOŸ7õ™/Öe‰Ę-Į―úbŧøœ·&LüvýÁĘ5Ŋ{î•Û›&ŋ,ýč€SuįwóOG|öņÔYãŋ8^rý#Ïßy“UKįĶģØU˧f‘Į_™Ø·e-'/õ™'Æn;˜^Ĩր ïŠÉúęĢsfÕýK>ܔŸ?ąwģj<˜ûÁč'n9XŦϰ‰ôį|oæŨQÕģū\ē%ŠĮð·ŧņÜúOÆž1­æOÛŽ|âķÞUž{qüŪÔė&7ŒžtoWæVԀ p„đZÐuŲ–ÏĨž`ÔT“ŧđPOÁ–!à šÄĀzö3°,KĄ7T§iÐuäGĘÍ͑OŊĄ4–_„~$ˆH7čŨĄ”ՏI~ēûcōzŨ͊­áßtxĮšãûúúښ–éũĮ™ņƒkÞ} ðÄš­Į/Ŋ{Åc—Ý,.>—Ÿ—_°1cãþœc=jvØŽgaNaūÃj2D ī™Ž†NH…^‡ðF§ÛeŅ6īÐe%9-íĀÞ=ÔĨ„@–„1Rū‚Ø$$H›\É3īY-ãLŋĨōK‰mĄ™Ą" VŌēē&éĐz]ųßĘâØŽ;ôĖtą ĶUœđûõqïīšoė·ÕũԐ)klzïÅųÁqo.úéĢώœ3ɒ@­îCÞĸîØ‘sVŽ~īcÖ‰•ë\wũõ=S27}1üųĨOOŸŧxŌč įž:4qȂEÎô‰Ožĩ!zʘ1ŽSåNōÎÏēū6~ėSžųÐîEM;ąvŅčŲÏūôDĩ]ÜvuŋûŸuyėŠgLđåŌŲĐk―ð…ïņ§ïnxčģûGOø|ęóŦĮßĩĮėõüøáßū=æéWJĶ―ōðņ5þ,ĸágę°ãƒw?XÔéĩGW}ðō‡'"ĮŋöÜĖŅOÎŽŨôÉūÎįŊŋ$n1ôķïŋ6qåuWôŦÛĪKrĩwÞsY§?|ōâæ‚JŊū1 3›V ˆ#Ü-F0R]üœq-ŠmđęI-uQý+(`ÕTGýëyb>ÓįyĘ{Å0OĶĨÉÔIBíEöĒy.Ĩ4 šjRNĀ DڝkvˆsE<"éË6ŽhUĨ1ŒØčÛįkÛn\ƒĐ[Ē_UŊ5 x'sNäžĖMû9s ņð°öC‡Cē{ Ą ĸjœĒ$ÔqÚʝÐBï—Û –Ÿ ›7Ž/ČÏĮŅÝeʓÛ~K!ąÐBđÔ0ÕÔĶ-”zŒ"ÐķĄ *jåÛ(*åw!DyzAĩ–8 …K_Aļ æÃ/XЭvÍðyÞčÏ[·āËÕkwI=ÐûŸCŊūĪ‹Ų.öý^pƒNd:5ŠķþšrW!ó‹‚`Bí–-Z·ŽŅŪkÛÆ‰ßŋąî`NÞĶ•_įî9ķ&/ąĀĄQ~Hi‹NîÝō펧_^1 O#J™{vÃŌïrŧNÓģCÝ#îÞíW 6ĮB€KD>Ë@FvÖđ}ŧw·nÝZ–鑊ō[–^‰“䃭ķsuĻÛĨv§I-VĨmŪŧųāĶIŋTuųmqŅ1>Û'ņĒibĶ•ëäįįŸÉ=—“›wō܉ÅĐŸĶæėY·cïäÞÅųĨĩļē@Đwthâ8„ĪúB;:ôZ“eųāÁƒ‡Tî’D`Īoˆ 5™QŲĨ[&Wo1‰úðk īŠŦÅĘĄ&ČĄ―õŊV!h0•o‹Žā•'o Ý­_Y\båˆøÂœ|psN ãã"lŽP­ŸÐ V”GÉ% ęÉNaŪtüQxãĒ)Ė?ôÔĢ7Ö=ļ>€Áã8čeđ"ĻïĄJbĩ”&-ãÛĩŋģzÃĘķúčAąq‰‡-ŋÖ!Q€Ré\{|͔ĩ“c|1}]æ66Q|ƒˆuŋ{þ›Ų{O•>·žë]G2žųE…gr27œZ?ïč‚=đG}Ėš,đŧ_ø=ę^åå1Ÿ‹î”Ý,ûi!•ķ[7oĘÍÍÆ‘_ŠMH―-œĐrĒĘkՌŽĖjWΰû,ËÔ}n&ŽÄ_.§•.ėŌŽŒr!QXŌ R"zCbrŦNÕNž=~ė7?þ0}ō·CJ­8ӊīv}øáėŲ‹?™ųęšâ˜\ŅĨ]ģ͛=uÎ{<õÚĶÝ9Ķiór2ƒœ:E§3NïØđ!‹FÕ­ģæŧOݘŅöęk›úũl;žë3ØĄÔ MxrÆĒЧ\:ðē—Į?7}ÁÂyó?Mũꚥʊ·Ÿ_ōõ—§―g·îÚšFt°Ø xðūyŽl6š›6P"°Ïį–/zåãŊ–ŋþÎûfģķ];uŋąÜ“_ýęë/ޘþ~JÏn-át7ðTƒ/°QÄ}ÉÍ·ĪŲ™^ˆ“~6'‡#áŪ î”Ã―ųĒü^ŅgïĖŲ›~nĸ–6Ÿ(Ū]?Ų –NÂÃ*ÃQAPŦû­Ęgu“˜Đ; ė8Is †ÂNh:Ž6C@ TPĶ-V ĻøĀþýŪŦč|üá://OB•ߎ8W|.Ŋ8ŊgÃŅv,u™a‘Š #æ­zāó1Óū›{:û u]YOË/,ܙūcÖĄ9‡ōO`ŠęÆTŧĐõ ‚aåÅsę?ü~Ņ Ã8tčÐū―ŧõ sÏ#PcS–l•š%0ŠdčʒQb€Ž^Ä) JIE˜(ƚ˜TԂ @Ąm™_Á=ČáļÕŦWWãāLNhüðØųMÄą™ïLÝhøÎčŧ+›ˆQžØŪ։ ËŋøåäČŨ^ëTŧJũA#ŸžĒöšoÖ$·ōŌļaąØlw݃ZãeßlždðÃ-}ûōŽ›ï|ļzaÚēeûc›^:yℾÝßŋ?ïãUĮ2™~ówEômũyÝ_–~ņã–C#öÎįgđ$öĢđ;ĩzū5~LžÉSz žēsUÆxÃ6=ŊïŨ‘1–”ÜöšëŊô‹æKĻW%n㊏;u§ŒQ·RôįÞíVģāÃđŸÐ:—ūōčqoÕãĶŽMãåYUë·ŧōēN&c=Ūx öŦ—|°`Ҋ“gƒþؚŨXŲĮđÓ­ĸ-Lf$ÜôċqΆ­N3æŽürÁŠÍđĢ_ŸC―0][AÖÕę2—GAȞ 5ĻQ „­ë9)ĶĐō!Ž„Ū qF9R™ŒósbŠ‹‹ķoÝrIŊ^IIIœóēDÁÅÓ[ĩ€q‘žÓ-đ[›ę­)ĢMŠ6nžÐ`MÞ&lZ%”'VŽĘ-Ė|mÉ;fbõGš]›]›‘u†ĄH'ēČÉ”ÝÝyHøzé™éåŲ€ â‚zPQ>Õ‹K+SÂÍ7æåäÂ( Jđ0ïRåØņx”Jˆdąî @Âuo &2čN3m‰þËEĩõęՓŸXÛ·ooÞžđÔ!„h™ïßŋ_þØ Aý’ĩ?lBÃޓį\Š_>§.—›ŒŨíûúŒGbU:t]‘4æÕiH…ÖiņøæŊM›TÜ1čvę:"yāė…åŲÁ [·ãuó> ïHĶ—į―q)ōU1aʈRߚ ĩ‡zgx鏎ËÄĨ7ÞÕGxA‡ĩđt@‡>B^ŠF›+ïé€YÉđ@ņŲķ―_5Ž$­žŪFQÉĢ^š%—[—ÝtfŪãyĩÛ_u{'$ĸiYýzîę‡ô―€ƒÅ°Ņπ %ÞüĀu,oÓë–/ÄĐĮqۅ—ÜĒ( t)úũ"áĀRŦT~W>W>ņØ#Kŋú2ÂaЉBĨđÚN›ÉPSĩ!…ƒmÝŋ @dJLm†€Kg@îwïˆ:wîBŪ?"m!dw“„Ī d Ļ'Ʉ_üBë vô額D6løpޜB)m L 7\ Î<’c}Žõ˜ ‚‰’g0āūąĄ'âčįŲ|ó Á^›(­&‘ ŸÏwôhŠ―VŊ^]yĘŋCŨJņŊlU[ĐĨÕÝbŌ†BķDKųA‹-$þ^X1 áąúDÉ9~pĮYŅ­mc›TD •"jĸÛ§°ã{·Ģ›4oČÂónĸw#ĶiĘŲQBˆ:ujđŪũïfĩډJëÖ]ü  7AīäЁÏððŦ›wõŒn!”ó·Ąq6ƜQD ËķĨŊŨŽíÛÛĩkŊ›\ËeĩĻƒēĪĢĐ ĮsÚ&·oQ­ÅÞĖÃ1J(‰#Øö‰―ŧķlnąŨ(ý\fn~~œHhfÅķiŨ8ҟPR\JŲô"týÐfųôķėúĒßĩð`ÛķÍgu7‚Äl-Ã4lxŧ4—bšF)Ί—Ę<Ąt &"—ŽÍ―PmŠ"šÅäØŪ];ŲČ ér)‘›p[ķlYĢF -e+Nh‹1_§ņeuQÅMßĸ“SŒz-ŧaÁĸÏãl8‚ʭþþąįo}5H)Fķ‚ý<˜ӛœ™ÔÁīp“˜PFõLYΠëá襃ōO]þ‘3ÆtöZ>Ÿ―`ßqĶ&Ôęæ‚_ÔU­ûn]ēŨðEp,ŠKHŠ8y2uüēũoJéíƒŌŽËõ<9ũÚŪŨ Ž.Ā͋.ĘŊõĒŽŌ žö@zėß―Įu]Ó}†nų ā•+lU2â9؞™—W&ëZÏk˜Ķ2ƒWĶsÛ ĩ›Đ]ŧv:uBŊ=Ƒð?ĨT7õ?Â.‹)(3ˆĐp–—NÁRŪTķe UD†.~=―QgspÖc0ÉčK•đRÚā€ĘČ8}ðāJĄ8Vž7­/ؗh*éČč\ŋ} ņ1F8šAAƒ"ūJDjÆöëo8ą=-ïÔЂÓ5j&%ÄÆéŽüĒúĘåuå+ĸ+ybQqņúuksēģ l‚–Kđ"ō8Á‘§”Bkfaޚ­ĖÅÁ Âēīfƒ"E8čÎõŽ€+ÔāDÁĪQƒīē”U2Iđ.Ļ2þ“=_īfƒĻîĸßF8ÂP+ c%ZŠĨ™`·6úŌ |ƒŌe€­†Ūb1ʔÚIUؑ0L5ą\pH ÕDœ]Û·Ëj’ΗĸĪAB­$.ĩŊãđíë·mYŦ™t唂ųŋįq_%;hfn)ØôCæOóÖ$ŨŊÎŅåņīžĖāÏ+!GÚŋg·šČ 4[ęƒCË2Us…AGĨ<'aa˜ĘļVĨŪĘhœËPšcí‰ôĒ"5ōŌūrÛķmŧví:ĪBķJË%{[îó•XķO…mcŒ\éŅð§Eų.ãčĸŨŽðĀpHą ‹”ŧŪc@†‘ē’‘K[=Ôk7Eđy^RŠý˜Ö;ĐRĖ8‡lNu:9rčŌ߄RúgÚÆ47* ;PÜWßŋ]ŋm‡ũ0W€ā ­B˜ÐÖbœũIé= óYv//žÕqqJĄ\\@)„îJēīÖŊ?{6†‰1Ī €ÂīmxEp$öûmŨó L„+ĐTÐ$ĶfB€PÁą-į.ÖVM,‡ž_[Ž32•t‡”"HAV;5.ÓÛ―{ũJĨW“&MJ_ !%ŲĮ—/^tīˆXÄŨþōk/iSŸ°ĸýįtlÛü›9“wû{>~måiĢ'ĩŋãõ~]=Ąĸāø7ˆöp„‡“—Š dd UM ”*LŒS4ÎBgÐjRŦH5IYĶܓûQÔöm›eĸŌEEõŋ•ęę§]―. ũk{Y\d<ä­T А^0Á)·°1âšû\Į―^Ë?,—―þŸidĨīR#ĩkĮvýāQW9Bø˜G•…98iA&2ŦøÃ"\›‚Ŧ2Ģb™úģĻ'§Tsæ_þŨŠĩÉgÛķm+ ÚgUČB™4šéÐĄƒŽ•eee•r)ÄðÎ^ōųGé.Þŋxæa#I-ē-BLŸ_…NsM™öÚ–Þą â;ŋŌýþóŠ@Ӗŋ@*dēėũÉõųl•‰ē'Júæ;Ÿ“‡…—žŸ[f=e5üĨa+ŠÁôëðYę(lųüķíÓ{Ä0Ïß<kÃŊBwxÁ?íS;pŒeų.~Œz™ðšô; w0ÞŲOæ-Č·āŽ°Qú+ŸIÐG8ÂP+iČPŠTÈæŌ ”Ę}9,TÛ1A ΉđÎ0ƒ—ėŲð랝ŦįLŸ4kþ·…”@y9Ë??ņ‰s?Þč" ģĀž ŦŽÞ>oæ”ŲĘcĻĒyŅW ߛ8qԚ#YĶed§îX·ũÄÚå‹'―õöšƒY–ámZ2{ėkŊN|{Ųþīb'ïØ‡ï―ýÆÄ·ŨÉųSv―áw‹aŒ•ĘHF&ļ6T5ÕÃŊžBˆÕ€A„ 0ŊZRð U3΄Jš° „50Î:{NŠūļšlL/HrÉųÐkmf(Ŋ\ú[lŒžv+*AÓ*ðEeGÆdGGgGEœņžjD|tœPégųžõ· üĒtíEmĐ Øĩs8˜zTŋXĮq„zą‚=n.ģ|ŋ2āęAßnLÝō݌Ŧúö™ýãÆŦ>úŌëÜ\1ųG&L'Ņþ•sGóZÎđ―O>þøŽsØĒŲÓF=úáÁŽeO―ôX”uîém>ÐJ +˜}bۑŒĻHüå˧ßĸnBÖoÔĘLQpâgOXžJ’_T,JßïօßĨGÚŲï―û―Ï™ūāâ17\óčĪmi'<;°ï­ßydÉÔgū YÎĒįoðĖ;;2ē—ž9|Üŧ‹D–žyßø+Ė(ë›YOŽ}wQPļ‹^ļáša/oJ=öŅļ‡,=fYlņO―ĸía›eŒā‘Y䈏\ÝʧkŽîXōðOdļ8_l2^œŽšįæŋpÛgŋÄÅH9 ôþT„íf„ 5K—qáœĘ]„QŪē3"8ĒÔ3ˆĄa‹!́ÉlĻÉ ŒauĘøöí[/ïÛW*ęËōĪå[ĘĨ44ōĀõœŪÍŧuŽŌý‘̐n iK\§kŧŽ―:õÐ―XŋåČUÞP&īŊŨåŲ[ĩbiŨʔVÛõĘsķônĄ ĀW'ëšßAÞ")ŽŅ2mzärĘ8\YŅ@cˆmÉ ŪEŲ&›.ęėĨ%džj‘0ü~vbĮSƒ/OKËŋcęįZÆþ8įëïŌ‹_Ū^ãl’đdíÏŲî?ÝÖīËÝÓßūoõÜ'v}”ņĘÔwēš1ö­5ų9ûßwKį—=vKĘŅ&ū{ŸX˜}ÏėëĢ&ÏXēĢiũ]?žĸļ_ŌÃSŪ~Åã5ŠEŽÎۖšÓđfMô”UĢéu—ļ…YGjŨ8uōĖoKĮŅŅMßÍý"ïĩ•‹Ī$ļÏØ6ĸ“cņ”ą­ŦÐ$gøĖ_ūžņŠaųV•[xá…þĩßÉÝ·ŋÚ}ïŒéģämïŧSi”ŨËóU6ō•gŊhī#ÅϜM{Ŋh4wîŪ[į~ý`ÚW%“ŧ&ýīũĘNEūěî}~ė gäíÝ{ėpQ.}ę·U†ŠU5xüįų?í8u V­{éŦ“ߎ”ûË]7ŋ˜Œč1`@ŧw lhˈĖï‹ģ Š j§ÜÐĨY•° íOE˜Ŧ-mpRaBu=ɝÉ5Wã°[oõÄĘ˜ŅŪZĪ€„Rærā~\NOÝđsgˆ?Åŋú·e]ĩ4EFDöëŅĮß/7‡á]Ý;u‘ķŠ”Ņ‹Šŧ~kQū&VöŽ2ÉŊ!}iũėÜé:.VÝÆÔÓs‰z7Ô―L”ŨPsÝãŠÅFÚ VϐlĄfŪM€đĘ?QK˜ĸęĀ*ĪÍđsąÐS$Ęūī$hŨmĸæœĩ­ķeÓæ€‡äïŋþ°ėXqĨ›‡ ŽEAiVKiaŠ/šV­.Õ|&ĨðqŠđāvD|B(.ĄŠßv Dåk^vzɌũf―ŨúЇZÅ{ÅeÚðåŨkÚ]7īS―JŒk%Į7~ýÄ#ĢįūüDnąÏē~ŧ<(<'("+%VŠF ʰ‚šv|ÍÄXxlŠŪ\™ ‡2ßžvMƒ3ïŦÕĪX!ҁĘC\Tl“ZU „ü‘q–š)>t$īu$Vu―✂`lL•ÖM’M… “ØBPÓuÏî^·ėŨ]]G ëQ/&(œĪ֗&Į›LŋvęaÔEÜ@Y•‡ûļ{ÍSĢïžþåß2ðúĢG8ŦÕÏõPSę%•”š ĐÔUĄĒ c˜CŌ=yĒíģõģ?úČÔÜ-yM9ŒfũŪ]]ŧvÕķŠå’Ų‹§·šCßÛvðû"”U.Œ%U­:ôæÛ$‚”kŧx”OĻŋmL&†ŦWĸ*'NĘĩķāžCg‡įđ\aŦiŨĨúæåV”­ęŋ€O­7ð ‡erĨßāū-CîĻÏ0ü—w.ȔV2ãRōŨ/'ķÕÎ^rtø?•”ōÚä1ƒnūelózwÕiÝ’Ūšâ–goč—•[(e.ÓbÎÏ-ŠÆFn1õ{ī§[>û8­íāï/>•œR7>ąïõĩÞï7zvũ•Gš"ŋÓ7ķĘv_'Þæ œq"‰~T2 šï—ïTï9yÔmģŸv"3’|U]U ÆBŠcÎI͖;Ԟ1ã―U†tËę0§Āƒ›"āRmϘŸ›ŋũðņúMĢö,>nzģ˜k^ĸ|ݘĮD"8āũ"aEƀ‘Ć)ą@p=˜X>ĨTË Čųn.đ;Ðˀü>?†Ð%~ÍBpbčĮmH“,dü[7oûÏˆŽ‘ÜĐQhÎEbõ†M&sÎĢãŦĨ4mhųcysF ūjČMC>ßëūúÖëĩ,UŧåĨ·ÜsÝ3wķNŠpDÜģ fwˆúäö\wëЇö ՋėqŦÓõƒ›ýüÏŸlŲ·hûĒŽŦ^ŧ~Ģ‰ØŒŊßĪ}ĨčŌîaF―čäÎŊL™TļnÁ=C‡Ï^ąšÔé5ýÝg·M9čöGN7|pԈ~åĩ·LŒ$œÕę·ĐYÓÏđHĻ^ŋ^ÍŠ‚q;ÞÜņãža· û9ŦōĻĮoŦðčĪétũ‚[oēâ˜ųús#jE š [&F`ŽHÍFíëŨL fĨG&Ό>öÍÍŪūíūQŦŌō“jwHiPœˆí˜Ö­ZD"2)ǻ-'?öÄÏ{Oíûiü­nxw―ô„ĄQāŨóްÝLôĢ?°bŲ稘XĘOĄ}žļ’‰bbč2gÔē|\î"Ž87 “—*D…\S—Ę]•Ū’€‹‚kXÖ°ŋmȍĄŋo† M\hząR|ĨÉsfūõÞ Îh|\ÜŨó?ŦZđŠÜŨ,oĢŨč,SÖ\FïhĮ–ysį,]ō…mTûöķB6Šgáhį„QМVq/ĶmzÁ ŠČKu|ŒĐ}%Ãóyý[n~}üËS&ŋýË/ŋœÉĖĪ”Ų Y'ļ\”-vYĶ•Ė}kÍĪü’žþ―úöîÔ­a―úg/*‰-ŋų;æ2:.8&U vï–Ïøj*#Ā%ej*°Å@ŠoķekĖ‚ûlŸēÝĄjTž”YĶ-ŨžjįŒËđ"„ŽÁ+ČGąqãÆ=zôļVEŊ^―š5k&‡“ĢĸŨBüįĩφ#Ž@! ûs€˜„ĩę‘ÅÄķ`Ļ< ģīݐĮpW Ō‘ī.pXW~]`*ąTĄÓXJĐ$ ĪŽĪ5ĨK‹Ž&­]―:3#úû1†ķ.ĄŌRŽpé™ÁõŦ;”;Ę&ÜS/JýDÏdS/1ÄķëÎ],€ÚÃ`8ÂņĸdVŦōY.TÓ+FšqĀ ĶÜiFĶayŒjVĄÔ/QõāžÏžVčĖä1Ķ\‚&FĘÔø.áaD=ā$™Xę·€ĩēģΝÍĖÜĩcÛį‹ĩ•T;IoŠúõëkīUŠ.8ÅqYÞ)?ĒŸōԃÐH1)Ŧ’HŦBŪ]Ũ-Čϓ;YįÎÉŊÂâBęļŁ⒒SČÎø5æH“ŅĶeëOŽ €óÔ 0  ŽÃČ/5HpŸÏ6Ö6ôƒP8P€šŦYf‚ÂŽpü?čW[:4GÏÓZ.đ#Cą~ķ_€beJāéÄČ\Ï!€ –vö }4—Š•UĻÓ,eÝÄ<Ę„ô|Cy”å3ĩma›ÔĢé§Ï,Oĸõ§•›5ëØąģ$ęÖ­+UdžaHŌ ZĩjpC: ĨÂu]đ–p\$ãĒ"™ŦfggeËĸÎÁũ@qq°$ ~U››ã91ČĸĮÞīFÕAŠš{ÞįÍŋ đˆ^ýðŪþj‘õ B@Ԁ7‰„Đėn’7=oœžŲčČŦe—ŲÝ7ŨĒĶŧĶš=ė^zĢoŠ ƒņėĒ„Ü+ÐiJîK.yHc/ĸ:ĢV`)EĪ—GûK”ÈQĮLķ’ĒĖģĮ‚‚ûÉĩ+VŽĩÚq1Ïq7ĸÕTkcÎB,z–B ÝÝt"Ņ~AïYšúÔë™äpû{ņĄ„ŧέ]‚sÛ ýX*šĩNo>~xĸåččðÍëĮOžūxųŠBv,Kœåíķƒĸ6°đļļü}~~rōģ…Z5•Úøt·ŧÞnۚzmŸ9gUL rē>sÔ1ūŽ›Õ$%Å>}o\CŽ‚KĢeúw8.IKņļ#"\ž0"M…€Ïdˆw"{‘lŠý&ƒŠPdsr**šnŊũjˆ“ēšAî@īGēVGÛ)ĄmÁ* ō~wD‰Ï9gMĸå{UÅ((ÞcVD„RēÂnļĮē‹ Ĩ)įÛRК™ČþōŦYû―GWŠĸöõĮņņŧ·‡žýĸžÎÎÛëėôôW#ÚëÝÍf{Õhw” <Ïmôŋ—’’đŧPTīĄŅåR–izÔėیü­xūļŠŒ‹@ĢļŌž`{`é–` ä’qgfÎģ́ņöž›NUBrÎá(ŋD…šôØČ ˜ęœCņš1†9zØ6îVŽXCKØðÉŅŦĒÚiqt},ųRj/īï·}ð™Ý]?eCŽÜU DÏl-”PŽ>"4šj^ēXāČRdßGJfŅFŠčvŽŠDEÝl/>}îĢĒD„˜Øûû$Į‘ŸgHĶÜïýïšŋ’’$v'éŠgïPBÏD8*T–šĸ€i&>l­+sCšUFwĮZësUmw7s öãfæ_ë@_–ÕÝåNoUŦ |CæCfQˆðėĶ(õZëޏ‰4L'Ģ$Θý@‹p·ŊPC-ąÝ―æÝÜ)ėÜĖ‹/þ\ˆbžVíŅx ļ<íýú|ŪÜERÍĘ6žšF6ëՕUáËČ<œĻŒ.õ7YÜŽ2ņýZm•ĐÃtœ­jsĢ!|­ë2(HáÖ] >Ÿĸ>Ÿîðųo{ëÐHŽŦIį!Ũó 4 ĢU%Īk]{įÄrĸzt†ŪėšĻ]&ČŠÎĒ4i <<§·ĶÕ7Ýyļ:œ@ExDW—úô šj&hōD uŸŨēžęŋWėá­ųĘk­ė+&æcĪqü Õíöx§€Ė­Ïj%đY·EĐöôū˜ŦUjšüėœėWAũýCp]‘đwîs7Ŋ˜ŽôëÓÝĪkīûyZĸý0wJjéļģŠę<žYkþĻ:Ÿį!lŌs@ŠÏš8ŦzŦ[†ĖÝj#!ā+č6kk†ũđũ!nöpÅEēšwÞ]Ŧ†p]ëð>ÜÍmýüü {4pžvĸeĄeVWÄ_Ëoc.Zꖚî;s^ŪÕîAÚýÜFZ8ĪîæŲBîį˜ËŨ~ķ…ļ­ęāFLN˜›…Îó6zļßû†ägām}+sJ-Á',ŧ…ˆ0·ýÜĮ°xFTĐĮ·Ö]ZøóÜ ‡6)ČĖōŲ8ŊŅŠCë~ß'(ĮœnûyævËŊ[ˆ# ĶŅüōg'@3NsÔaŅ4F\*Uo@˃WƒâwŽķ1ÖU–ūb†ņwQûGņâ­q,ÉĖ>ŸOUĐÛ8u5îžĩ!™[Đš:ˇg%˜ņ\ŧ ÍaFJČo8–ï#)5ũĩūzĐët—e>ęŠōIĐiÖĨRŅ€óÅü·ĘJIŨúļđÔnŨĨßF3›/ėÝSŲ[0ÆZ’fjfũiŽ0böá—ŧ“SØÓ§+ 3Ã°ë?DøyŒ;3Í\DVrsH­6ũXŨģŸėąŠkœfnþä b2‡ÄņâŋŋFĩ‡\ĘhGFJ7X'‹ÖýˌâųŊÎj5Ýæ‚Ģ4:9+Ÿës­ošļ9% k›Û4ârôޚðó‘6đb;7iĢE­Ü$ÃĢŧ!ŽuņlŦÛÜZ•gôö`ÕVwxýųęNÜ*cąUU‚^ÃļfæąöÞcÄøVēowÆRɌhUŽÜu(~ų’īũãæ#7ĩƒÛŊzŒ~| ?c–“ÆJg–gâ]q qŋŧÚ?‡ïAgï)á;ցÕ ĖŋĩÛīŦŧ 6Ü:"ûÕų_ëĒņÞ7EŦ*AÓĩ•ŧ$ØojøoÛãŨ°ŧÖĘo·Û7LĀbšŧŒv.æól3‹uC”*Ū•U]įņÜŋi/îNŧóÁXvJáî1Ėn>Y\ޘū•rũĄxs_ŨUy~ŅÝ<ŽÞŨõ!ЧÂW„OŒäaví|úX–ÍØÕna ÃÔ1æ+Ū‘gāŋģðFUŧ6ĀųFÉČn=ũĶäæÏ~ö~͇dõŪJā›ē8Đg?él k2ėļģŦËíÜYéf‚ōôn™YuuËþŋq34s›AōðĩM=ļÏĐZ7 +.ĩ†.cuÅÕRÖķÓ―ØYRÏŌķ@š§,éîĨÞύÃŋĪŽæ‘GËU- Ûû4.ļį~ĖÝÝ&ņÜe=ĮũņûArþ âKКJJ€šįÏî‹/þā!ŧ\Ũ•­h& ûW6lÅõ9ߚũsŧG\ŦՓ7 a? áðžĐKj;ÔS9~VënĢP:GX§Ėl6ŠÕĒûŠxžŧOˆĘ4ÚaC휜Ý1TmôVKÂW^V0_îęžÁs­Ŧēšå$Gĩ‚fŠž”o›™EÄUY Iû|Ūýėášŧ?ŊšŧfJ]Qߍ„ŧŲtúš; Ę&ĖÎ;ïįi lėsûž‡áŋowĩŽë‰mTYáAŸ 4Æ;é[úĪjŠĻŧ€Žĩ”―ŧŒ\ŨĘÎŪŅHą-ī|Ápz#:<ū…'ėðĩŸ9ŧÆž Ly;Ë<Ėėž[é°y· ĀqŒ ŋÁcG#aąBÂpčšČ w>{ŒÅ4ÚģÏz-Đŧ$ĀÃÆ›0'oũޙu­Kā7Ō@P ĀX3üÂÝįņ1˜đšŦōúũA#ŧœæî{gu­čë(Ë Ŋ…Ąŧ1ãĒŅg‹Úmîj}ãU=ģcxHj4)ŪVr‚Ĩ&đ>WW*åī8›ĘĐïNueĐËÜiÖU ŪuåwŌ4’]Ųjũåv ŊînČL•Œþđ>Cd0ŌīŸ;#Į™†ĮB3ģܰÂw&a$x*lŧåánQU„ųĩ&°ĶšŽ.Ē$X0bí*#ÖZt[h†“Ė[]ņÕüÎĢFfĩú—þėjđ/ŲÕ]ëZ™UgeLģî& ^žxņũZ˜ÝĸÜP―+í°ZWÍ(zJŸŠZëŠĐā–ÂCÝŠvsęnÐWð„%NIŸđ?{ūþŧÐÃāk-=ÝbĀää͖U7ÅŧĮä ";1Œūd|jÏ;ļņŲ§é`]Ē*Ĩ2_û™Áļw‚ÖÝëŠ'ģŦĶþā~~[W@˜[„Gå$ĖÍÎÜ―Ū ęÉÄą°Ų>SZWėc‹Xßō…Ö”ãBpįī6ÜÏÆ1;T·ŧgąP4võ;ÕūxņŧÅÉihĐŋģa·t~á8tŦŋ§ížũ“]īßĻ@ŒFÁ˜ĩƒÞ;IšyŽkį6Āà æ“sŽðŦru—°ŧĖĖÝ:kęžOý@r·ŠĒ@Ō—w—JëúČ*ũõđþ™Yž=ãsI €ïcÅ}?]u,^–Uį1֑jíß0‡Ŋ•–nÕ2;jXeu)VĪՉE'aákÂ'!yļĖę+ŪXY™•ĀéÐîūžšY ŒîánŠ}ņâjyþ?™HÖĄ ąúVž˜GÄ3EáRŸd[-ŧ&•æģŪęœĻ- ß;Éφ`\ą€COø6û›Ųv6i ŒžŸ›œ˜ËcŌ]v,Õf€Z]āhāÉlđƒĨ-ï–ŠÎüßqœLđÄZ!ĩ™ŅÄ~ánäģӀˆïq–ŅéyYvFÄÄøyļŽ4c­]$Ht%iR}Ö§šįîœfŋ­ ÝoŠ}ņâjö<;+.uÏŅV8Aýōl•4 žL[kA™4ŦÛ=üxÚö\œ•] œ›7$Ĩ–z˜ŽĄVIÎ7}îý˜9ĪėDį9Ĩ&lz'L "ėý /?Ï ĻÜ|ĖctÏ7_FŌo‰š{TÎFĒiVĸaęŲMã€@Ŋļ$ä™Ų[õė[h5<žŦČÉüEuuŨ$v)Ią|ĘilrĩÕ}ņ§ģ <<ï–a“:˜U6ŧũ―ww9ÝČŠ4c?ÛPÞuÍ#ĩĸŋUíá<ŊÏÜmõ›Ũuöæaįð•Ó[ãūŦZ˜fģ!MA4>9 5č[t0õ9þ<;'Ũ―šūŋHŦƒéŧü“ŧÚ/Þrō0†;Ÿ/Ø7Sf… ķï'ĖiV_[ę|=føhŒfnSŽ{&åĶ;öß+Ï+;…7ũÏiÆß[Ÿ*Ĩ6·å! 8ũ0ž„­6,Đöģ°õĘÎnyŽq—eĨûrûöõš‡ŅįÞ+âtßn_ÆoŽ9Ý*KsŽãnÚWĐÞiqß7A7úXllП4#ģģģčŒXUÝ舸zØJŨuĩzwZĸSgū- /^üŅļ™āæŨgÕw_ŠpïJģ03šw0v7j]+šŌ38s"$*ÓÝü;üŠÄōĻ]Õ% âĘ'Ýüš.:[-čŽ/tDŽ=ô”UnFgU/6î]'ĮÚ;IđQÝģĩ3]twũ}?đ'ũÉ4ōŠĩwĒ!Į[AÁĖ%䓄œ”ŠēÃ"|ĩþÎå{ß "Ėv> AŠ/_ë,ũũΙ•”ĶĒ‚ĒŠ VReĸÕõÁ‹ïąāī3ÏæaIŸŨÃĄQUĢ―ÏÎ<ÉÜq­c ĀYkö›?Ïcfž{WĨ( ĪúŒŪþ-Ũ"[ÕÕŠ óŪúy~Ė-<š:ŦŒôˆÎę.’3ë:áåNÛŲ‰ƒÉ"æĩ71f2ėŪ)KŨ!V=âūfômS]°ótDAq]ĪĩP]æVݓ*é'_Ķ&û U™į1ÃHM(Ēiï{šŌ§… "éæžqÛIZkEž…7/^üÁĐvjąhY;3#"ܟ{ķ"Ķ·ŦÍÞ%[j&4‹û9Õ tˆ™eæËĀIŦîîZ'‘ ũÎÓŧEÄuMŠö'>æþœ&ņė§ščŅŌól’mPũqÐŌÜK=1Œî~ĸüĀܟĢÞí4ZŽĩŸí Ŋå˧{m­Õ]•ifá^ŧšEĀÜrïe~đÆķĨÏįrģ†ŒF㟠Q|ņâÍ@ø ĸĢĸiŋÍÝĖ[Š,Iįė+ 8Ö*>2įWxā6ï$‰ÂúÄŪDŌøĐHs7‚YmĪ_ŦŧēzBuI·|vnÔWXŨBiwŌmĘÆEJžŪĸķ―ôši7ÏŊ•ŦđĄuïž"üšNqÏĶ9ČûþmE8mWŌ@xwkfÔ)Œtģ–,Üh uĶâAė’TgāÍ >â2ĒÐų<æ9i4sģŽŠþ“;„/^‚ę:åļŸĐrqwÏý˜q] hĖĀl NZKė7ōŠuúJāásZÅÃÃÕ•IûĪ+š;aßVp*3Í€›I°ÃM”ō<ÛLÁ= ŧŨ:i/m2;vƒŽ}.·Ü‡Äĩ+Í įóėR…GŲE#@Ügýęfv˜ķIdåœ\-wĩ* ßOA?ųÓ­$˜YVC\ß›6bœlðpxVÍzãŋŅ-ķëpŲɘôU‚uøÔ<Īî ?d'ô đwxŒ‰áyž+üT@þvŒK0\îþÜÏ4{ĪßÝG†AĻŠN€Ë΂ŲđuÂ8e6=•3–™SHģĢ +ũÐ1&c;wîÚĪ…Į!čé)°îæw ISý0õ9ŋ­ qNæüōHLĄŊŧ ŽV·‡đ{>·š;Īã XšG鞀]grũITũ]īkUWg“ßÁį‚ģr͜Gz·ĖxöģšĘ5SŦj>™XU,BíŠŌuJÝ+ŠčjÃ#ë{―xņk5:ĢyxļwõaÆčî1ïŸÔðΝ>=ŒYĒNé!ũÞæ~]—9!‘8 FŸĩ@ŦŨšbŪm4wŸž‚áŊ:ŽF0üü"Īŧu5XAģÜ ÁhÏÏ­CÖï*ýJĩúĢęޕ­Z+vn5Ķq}Īŧą|8ÍcÝMPĻ1ķˆAâyžžvô~n‚Ó·6’?’ŒĄïÓiöH‰Y. Ũi)ŸȚÆ:œ{˜}ÂÔ_žxņĮäņ°ŠFīv%ÝÃl^€îņ ÐøüÜ0ÉTe‘tš~UcËŨ!jH·ã”ÅlNģ:ÜaP7hj™™€ŠžũŲ9AāŠÎÞ-Ūp ”ėÛ} šÅëė‘m]ŨÐëų<øLkÃ2'lJSč[SSōwIÂęn\ŨGnđđŒųėEÞÏmnq­}? NcTĶTá—Ï~ƅnY Č܁ßŧ„w)O*‚9ŸCĘŠņâŋŋEĩƒY9ķ Á‰a u_ŸÏaF ECUĨ:<ŒxžÍÆõïĘ*4xūČ?ũ@[ĄÖ,s[åUÉóæŠ–:ÜÂWž*3_ÃģZ)[šNÆ%ĖBâÐýxĀĖÍėđošá Ŧ Ö-šÆ:1SįÞiÆËýįþ™PZAi§˜·v ĀĐųĐŽŲHČ―i[•ÕPLŊåY _Ũ5õšę‚(Ũt\Š<~Ülčs}W#°íîęsGgýöxÄkĖ}ņâ/Š―ŪC{Ąk]ꞾŊuˆĢŧÍ=xU5Áë0ã7ûũ$Mhxîŧ%w7 ĨC1ŪŌ}ߜВV݀Á,kķ{?hARSasčOÁÃwoĨ| oðKÄWŒŧ ÜpNÛ&.Öhãžh…Ėt;qã žŪØũ†ŅÝaŌŪŲ“Ž.ËŪûđš‘FĐŧĘˉ'ŧ§ģ@€Č*I“i_žxójIšqŽcTÃŊÃY%730ïĖęåîf]ßĀ„ĖzžM#gą+]ë2āĻāĪRvũpkĩĶuÖŋŒtŪXÝínæÞ­―7ÍNhKuŦē-Ē$Ģ…y˜ĩäĮÍ&p|ßëęŪŪ&ļŪuîAöߕ'ņh>”™uiül4dnĀ,lÅĘn`ūÚĢ[4LBWŧq}VWöāė ~ĪŽ°ˆĻLmķ•vöË­:ęæÖhsÆuÍļMČý5æūxņ'uĩc*U{›Ųu]đ‹Ī]fĀŪĶņŠÐ‰šž­œbšYMøũr@ÏÞ ŊuAĘŽ5ä\žÂČŽ­n3“°ũvģŊ؀˜ÄØųæÞÕĸþ]3䖍z’+Ėu7F<ËIëúæNgî2āú\G˜Pî~}ĒŦŠŨ2ZW åGBpšŲŨ„Ė~ŨŽRUqöï OŦnc]Œ?ũc4~?'ĢĮŠC óŸį5ŪZUeanþ*―þ$^žS­pŠŌšÕģĒ%ŸŊĀÖõĄČĩ.óoTvŽÕ0―ÞÕ"VwũLÁÔēąĨnđ…YĻ;Ü v+G—j^YûI ÃYęŌŽdčn§MNnŽÉgHIįų1š`wîg0Ü=MĀV™] ‰ēįįķVcïvģuÞM­.GęįyâdØĒu§ð́ŅBĻvR§šŽjü k}E`ę^áũ؜ŽuáLúCâ%u7^žxņkŧ§6\FŦB›s­ļ‚áÖ­į~*ÓhÝ5þ+žÔðįūsˆ#Våu]ērŽbÕu֝Œ˜œėŽ+<Ž:ŧÐä'Œyl؜8gu—‡­Ë+ ŧGø}?4šSÕŌwML#šiæY1Õ|ö°vî ņls3ú„+šÎžiž”ē―“"Ā―ģZN^ŨŪ,w'íóđ&Ąf” YŲ]ĀåėŲJCŠ*33ÚáØWTûâşmaø›øŨyæÜ‚ XãS˜8+㕚›ĘŠŨįRi˜‘DfuM#™ü–īFwÎčjGHænfûyšÓŒ&~áúŽĐ ‡æâ"9ƇÜiáîĄ5ķīÕÝ;S‡ĩŧkķ þwß0ŪÏE€ˆËWv“ï…qÁŲŦ†™ˆp[+žįYUvÖŽ-]Ÿ%a‚~gU]Ũá]%ČĖĮ8ĮóĀęóg‚kS‹Câŋ‘jÉs€^ŧÔá1õ-ŧw0c[ŠĘC=ÞÕhŊņ°N$öäȘÉÝF;.I-āëŽ5PĨĐóX ëŨ0–5+‹enõ› â~žŪrzîœīšˆï˜ŌïúĒ% •đ››Ŧ{HąŪ&ĖÍ8tĸü|évfUđđ/ĸöĒà }ϟÕ=ņ1ĮyœÃŲ–}þģëÖy㉗LJŨõųßÏOf™ŧęŊjw7ZfYŨlgif.•úu‹―xņ'uĩęĘ,UAösßđE·Yŋ ídVNX@Äęt._īx~6É8aݚfōęúmüæsFQ Ü;óŲÃĄ““―"4‰­õų ĨÆĩœ~v˜=@;yäOnņÖ~ĪžÞ‡ŧēŨZFë]ü†“YfŅÆƒ›’„1Ÿšļ@ŲEŅ’8éųu[ļW5wûږÜ}ĘĖN9cøųqļšé4·!b3‚čjĻVĩ[ŊŽöŋ?žŦ]s°h]ŅYuZÜHĄ…$:)#­ŦĖÍhJRËAW5ĨpŦ.ĩ͉ķ* ]ŸKBNļyu ēßâņĘvs7’“übnīĸ •™CĸÁ–›ûÉ“‘"šmácfÛÏcüúŲro ÏĪđá$íSMgöŪ $ŧĮëkUšŨĩĶëFjskMzLÅr'ŧ+čU9―„UĨ~ŠÚ5ĸJá§QĒĒĮ!ë/^ü―†0ĸßu}eįLsB֖™­ļNWXMö}ß> ÜÔū·Î‘ŅÞ% -zVÃāæĪÝ?ŽÃ@֞ÅođŽûdfKMgxÜÏCr…ëˆU‰aØo0âôƒđÓ"l$―Ð'ĀŪĶ(SíÝÂoœŅÅÉūyÜâyŒiužę–ŧûqMYúðæéŧ] &Ŋk>i* :ë‹{ƒŒkĐ{š{§L§ĸÜY$EØ™_̈ÛiŸ$^žxņÅÎFĩŲ õū·ÛŲÉķū-īŽ„ÛoŽA™ÃÃG K깖úw5Ä}rqXēŧh‡Á…ŸŸĮáW\$aZÓö˜ÉƒģpļiXSĩ+MĒę<0F2@F‹8<›―"TęjĻ'|D“PĢnĖí7qŅhzî‡ éĐ<Ÿ‚tÄđ#ÁÃÏŽ]4~âÂaßŅՎēF’úU ƒœë?ŸŦ57T„įÎęķ8 •…/^ü―]mÍ:ÕhîYIŌZ~v9ņTÏ}WwÄYŋîr#ðˆkå‘ô‡{˜ßũ}X2~‹aŧģz˜ÝũoŋÉį~ĶĶSŲéËAĢŧĨžQšŋŪõü<“(6/ãbĻŠį~ŠŌ͟―ģrqÖŽČÝ]ßHÃ.@v&eI]šÃ―Ė’äæÓž;1į]§ŊW s— ƒĻŪIÕÉ„Ïą·DbÄ 80Žk_žxój7ïîŠėVĖm?ÛhŨŋkĘlĖ`WŅčæFÛõeÉ(Đē=Ü=Î`NwĮwRĶ1ZzÅ7†Qlþ‡xžM0"ÜĶĩĄG›ÏCģ‰7“4-Ïóāܚā™m Ą?YxóâÅŧ@ *Ŧŧ'LäaMũâHBW,ð›6_Øgķ­ž]ægi :}ET–ûó „V›Ųĩ.ĐösŊŨš2SøžõŸƒĻģm8!„kR@Ė9’ŠÏĖļš{ė[€ōŲÂÉrDÏNŲÝïĢXXąĖžNëi*K]S –Įäö-=û8ãjZÐaq_^]YI˜ĸî”ö[xã=•šScžU0˜s†Ųãŧ aþzR"…/^üÉcąFU—Į"9.Sâ=͉Į˜ûðĀhðĸŪÏЍ™ŸĘœîágę4šŅ~3b$œ„-›Ús€‡Íãyî NĪyf›YļWæģ7 ÉHĩ>Ũó˜™ĮøėGßjÅΔGŽ3ûŒĻPUé0ųĄO~[؍rl6ÎîffÕåĪÝÏOũ4<ķ$ŋåf§6íšVĢ'rl–*SrSU§üNŊÔĶ™ųÏýT.ŽČgwŊþāŋŋYx#ýĘķv ũŠāæną+1Ü@î*ssęž~þß'Ÿ§fԉÁŽðe^įÐLÓ]X™įĩ™ŨÎÃA4[óC7ŠĩŸĮœëút dx„yeJ 8i°œ °kđšT2Ão‰ŊÜb"ÉÕr 7/Uw"Îę6ûžVAēð‰V ™Ŧûy6eĸ>Ũۜd2ž þ֛w%`+†ÚyčÔ%õ˜Ä~ëÔÖĩšúŲũô·wë,Ŋˆå.áŋîX,ÜĖL-NŧēeþėÛČáŊS[+Ļa8ˆīó-^ &ôk6ĒŲõÜ?S<ž•ÝúÆxKŲŲ‡iž{Ó=ÖaÃNw?­đω–Ŋxr Ķ*üĐ*ŌšĨLÕY_ˆšØ­3ŒwuÆRwfíÜ;â~“_͇ąE7Yóc|7'†õ›Ņefs§™ų(Š;Ĩ†đį―Ūë" †X1ël: fĨđ·4ÛáiĖÍΐ_žxņįÄ^ģýfĻ3óŠeāūo î6Ū-wŧ"ÔÕՒ–ÏüĻ–Ö‚Æff―BĖAY7NLAĩŠåg\Í]„(xö#i/ĀlvĪŊAr? ƒãkLÃõųôĪÏJ#[t˜-uÃpX?ũŪė°čÆãŋ˜ĘūėCފÏuömáËĢŋݑpe"ÚģũÎ'ŪEcî-jliÏŽŒŊ4Ņ6uŠvĶvũ| @wîŊüāŋ?š@ HÂÃũģŅ=äÛúÆ`·P•áæîÏ.ĻA€~RÃĩ"‚þüïöÓ](aߏˆļbxœīÃāŠ.7#í>Üęá$~~n7[§ĐAxöģÕĒ܃āóÜŪøtŦŧšĩŪĻęĘķ03ŦĸÐÆIxIÍüþų!qüĩNJĀWåjķþ}Vu„CP&ŒhŅīÎgVŦ•á&ˆ]{ÚnÖđ|CôUm ‡WÍó[Ÿ'ÃĖÜ3 jw‹5jâŽĖ^ē}ņâ/R-œáąï}Ēŧ°Qã›ŧ™ŧŦ}M5wëéđ7É+ėP'Hڔ{Ãčd—`:AY—Ô’úÉöVëóïSUĨ&ÍWHĖÜãZûy<Mķž|h zwWĶđ_'ķÔf<ņ€ÓXÎŲTŽĩNŒáîtŦœðoÚ7ĨLfvdž·yPVÝÝEø ŊŠî27ˆģ~Å $ÛŧÜ(ŅÍšÎZƒõäïķwgæšÖ”øŪp3Õ î^'ōË@§Đßž™?‰oáŲ™ŋŒæFXũũHïûĐ뉭ĘãûšÖi)wzļk W|;fí @8dmRgåðlv‡ûšÖh°fáÐÕYûŨÍÕĀdøÏ~`FgŨŲ"ĻęýĪJæ–UįmbÃÔú\—‘đũ8ß:ã óčjuã0mUúZŅÐXlãø)š hŠ­RÕu­ĩb?šûōûŲRŸĶ uÖ0iUÅrÓŊ"Ÿė†ŧw– 7?#vŠ‹xņâŊá­q$Æ f=mƒFfhĩŧ‡{·D á pÃ2ܜBVžĒÏÚӟį™!ÎĻÜ)čätî>!°Ũ~žyŠã­šŊų.Ą;† 6iŨ(óėjŊhĐv‚tĸ.v#ŦĪ™° Iš™ÛWÛ}g aš;ŠĘlâÄ]ÝhЭŠ[ãÐå„$Ė aeĐÛÃ=þeVĮĢsÂŋ§Ø&s{ļIĢ=ðĸ`]Ւŧ /^žøƒšÚï—h›˜+ˆ#Š2cDĖL4Ķh7?„Xø §ĐáØ ÔiÜ{WĶō˜I :ėšV>[-7_ŨW‰UÝ ŧęüÜÆÖÝaÖŠęŨÚy.ˆøĘķ(s'yŪéˆ"wrrrŸ=ë‹óx›OÍ䔛[WeAÅ·a`Ŧ‰1ŸėęXņÍ*ŸĐ\u8ú”ŒíúFš'3ŨėðŊ/y`á|wĩ/^üMŠõSHþÔCōšÂĖ4ĪuvŊc*u(uÉ{?EsuïgWi­―aŸOíꖅnOĘLJ}‹Ęݧ;ĮÃDŒyĖÍf(ž )íl~…ÏuŅ ð(Æ>Ģ9#ĀtĪį—ĩ ģrÍÜIŅ`­†qš~Oz™ÜiÎŽĸāŋĖĐ Ļ•:ÂŧΚä71r$ëœŨí4\Ũzž;ŸrZŽØũCƒŧ›Ųl$ÜŨÞûþyÜėZk?[§Â2,fïņâŋ?§ŦõåųlUĄÓÅ ęóđ4éXčiūÉ.;l˜U’"͘Pf ģĘŪ'ÃčĮÁ%6ÏõĐ9…ĸĶš”ÁîܒŒĸĄvö.ˆnžđđGKŊðg5&ļ–ŦLĐABØŋi[Šge|˜ýŠg?ŠŽðk­į~ZõųwuéŽ_eĪpÉųđ.H4cīž.^sA•Ų•ĸþ­ņëzd{ ?$;ģ0§ÐfæaBÓ>yę ĨQßû1PxņâÅÔÕfMī j cå5§7·ÛŊEōūo@ą.7ë.fYj‘{ŨN5N Á>‡iŦŦ[z2=ŒdïVcR†>Å·ËcöķŨ·9Ķ`Œĩ€ģ“Å—ŋršÝéäō‹DUÏZāŦ78ŋÏÏÓjwšū|]ŨÞGۘļņÚeÎ0ßĮ;a ŸLĻ-œag;u]‡É@„ÓŒDØōˆÝÛėĀĐdžsbn>Ũ•đŧ{VÏ1’‰xņâÅ_{U빖…ß?·‡­ļŠ%õ!”Ói˜mîlė<Vt>?N A){—Āx IļŽĖ JëZßpØg}2ģösęÁŪûyLpssÞÏã$&üЁ0ƒššžũÏ6ÂĮ› ékĢŧÐĢzšqÍÎt,j&БÐ ­ęST“Öæ#‡˜/ýQ]Dđ;ũ“0]ëڕP XŸUđ NÝÎÏĸ~Ėé4Uß{Ožƒ(š-§ŧwOđŧ}ŋ LČ$žxņŨðÞDøø@ļGf‰R)â·K2·ûū)ļGS}g“—‡ĪÞíĸ}Ūįyh8åļŨ›lü-I%YúöåîĮŠÖ‚yø}&JĻEÜOCúũųītōeÜ˟įn‰ÓtÐ[„ÁFK0õ3UU]+ÂΈzÞáyĸü⹖›U—‰fÞýÍŲr_SŌNKđđ­åíûėåWfŦeáÜ?”…–ŧĶrƌ)BYīsÁyįIh<= đbýO'fÄ‹/þ–Ø ęÎū>…y]ŨzN6íŽēÜĖhn–{ÓđĖ Áœ<ƒ\f1AYF§šs?8Įn­VÉĖč–OŠ{žaWĢc- {ïaęĢd 3NŨΈ•ûĄ™A0t6i6ģð„ęæÞ4ĒYW’v] Āýl7ó‰Ŋ†Î_JŌÜÔP—9 vaį6§[L'…7>ũ#€ā„Õ–ęZ!Mr/[wíÚmĶŊ#PCĩÂcŨŒÕ>Åė| o^žø› „S)[ëģT=å0Ŧn1‚'gxüõY9ÍPęėĖ-kwë›ļødw›y+ 4wƒ šUÖ!č0ũîúZ‹3už’…V 2ũ.ĩTĪMIÍÜÜ$tŨÔęø3Š1ÂĖîŸͰ čRV-ŧPmÄõųäiʅxEŒb­6šyâ/^ü=ŠĨa­ÕÕ:Œøų\•{{˜„ŠūÂû†,|ÆÆÝ`8ŦÎÐý+)Ĩ R%ÉësAĖL•ÖĐ Ŋj4ž…ƒ_ŨĮĖšŠ[vũIâ3•å ‚™ÉÜ$U%ĮÍŒ Į$ĶŌdÎîŸý―ØxNÛūK†Ė<Óqd6ÍÆÁqÔl<ŒÝÏó„ĸ‡ođŅi}~•e6Tl;ŦŠOūA?{Ó}]'”6Į›ËgïÉP°ģÜ-ÜßíÁ‹6Dq‘jõ$ŠäއvCp•Mē A0 7lU6ë 7ŦL“ß:Qaæg°…Ķw+ŸÉr wo5Y§2+óš.ƃlēoÆ50Ŋ$ŧz,j1Ūģá_óŠl!Ö:.ƒē0A“ģÕÕ§E‚“?kæ­6CW‘ø.Ihŋķ.3Zw ]ĨĐu4ŪųŧL[wÍúķ-xXw“ŒËf„ðPkzƒ@æ‘ëâŋPė5CŲčüûĀÍ|ĪNš5ŊAíL3Æōę”zŠ_ŠóŨŦýMĻņYŒJ0Øþ―ÁŠ_SQUuØ0;Ÿ}K ™ĶvwŽĀq@xuƒĒqlÆcΜ%ōtĄũĄČņ,ėÓø›™æ‡­Z€ûôHĘÍĨ>ãŠĶ(5"|ÆŌÎ>+Ũ2§Gô‘ëΚÁ$īÃĒŦI›q{ô>ŌãnĢ_Ũ‚Ô-‚xņâÅ_\ +"ŽæīéæËI3·u…ũģ[}’›Ūš"@VuįĪ šë9Đę4·ÏéSĻúė"ŅT7ŠjÚÆūĢīņīČĻŧâôƒweu˜é Ņ*ŧîÝUՇ+ÃOąiöČ{§đuWí=[;Ė~ŪĘt§Ý#Ŧ=–Ũ°ģ{ÎÔܘMÁ+–đ?ÏÓUĪŧ{VÆåŸĢ‘Č]]"mŨSU*ØŋžfT· 4íĖ*‘Œx[^žø“T[YFÍ&“EęĸWV„ˆëė.Ė\PŸĘÅk­ĘĘgCÖ­CĘpũ§ģŧ#ĖÂrge­Výšģ[rûŪ_Mæą-€ĒŧŸ°Z­å’έĸkυPÝl|ûÏŦqÞîĸnzr]hîvf·ŪXE˜@óčJ;R‡ģŦM#Ŋk ūl5pޙœ‰ØĮ…|–đaņdæ“îËģ ™…ŸüI#h$Ķ\rųęîŪ–ú-ū!Š/^üÍ]íŠĐų‚qŠmZm4YIĮTÕBËÃOûwĩĮ—Ũhá2ŒðĀ$ŧK-Â*ŦUū‚UĢeæføß}wj-ŊcĻ2Î24+ÛČá/ÂNũíDsÉČĖáį&ÏóīÄSvðÝáBnĐëģt5ĸþß§Q­ķ°Ã˜u.ž@pÉ@cĐ+Ó wëR7šiaŧ ÝÃÃAXxĐũģ;ۂô F+Ė3Äi$K5HjŋÜÂ―Šv&ņâŋŋ§ŦÍŽRŧĀÎ63ZĖð(æUýۛ0­yxÖšĘ(ģ ųsß0Ԍę|ÐZWÖV+<Ėyßœ$ŠŌÍÜ|WÍ3ĶšŧĖā}?f6eˆų€ëšJ‰FKŸSon·|vž]‡ƒßÚð+>К­…{œ5ą@™;yØÐ=žý e+ î”ŅhÜORˆÏ„€0ę=OÎÓEã„=VæčŒgķÏ­JĩŠ{,s0ĒlĘÞU‹/þâŪöpŒZ/ááUãļühĪēû ˜ß(Ïo&ÜbėŋĪĐYŌčæ$ĶąũZ ĀÏS<ē­ÜICxúZđÂ+ŦģčĨîo–îšö\3š}ël-žĨšS†ÓûPÝínöU\ĖŨÆĩą<šuüAŽ6-Ō8ë6ķīgÃčZEÂūG‚đÂs—ÔnîfÓofNžxņâ/îjwũð―“ß,Ä~îŧfĻŽÎLĀÆžëfq-š ˜ör YiŋõYģēĩwR<í ·žĄŌõ•_%ЁĢCØŲ;"p" ŽĩTȝÖYóúÐ}›ŲZá•ŲęC‘]5aŊŠąœ™ýĶ›H˝đ‹VI2ĸ6ĪÕáÜ1VŒąx #Æ"qrņųũĄH@ Í;v‚ąï=ƍŪÎ| oþ$^žÆ\&ënšKøM°ķŪ& ŠŊoDæžrƝ{ï=™2'Ŧ%#üšŪÜģĻDĢó\āËO‚ÍÎ3ņĐÕį@vnqØ|ķ‡ąĪģų­4[ūô.þŠîįg5ÜÕíqxķēĄ*í/EZŦēĘÝÍSŅ\ąÎÔ<‹ˆ˜BßąrMŲY†teĩp}Ū>Ï)ˆøš{§ü>q6§rĒš[Â){Rĩ>ßäšF“&Ļûõ/žxņWwĩĮŋÐkÅŪ4f­Y-ģĘܛŽnðėnk­|žŪ›uŨNŌh–•jDĻ’čîįE|õtšķ ëšū,F˜Ûģ· œVĮ| ŅOéŽđ‘s•ëŠģ:% Ėé?Ü&Ūŧįė΍ųl7?†·A7·ŪŌۈĮÎK3‡”Õ |Œ.i]Ë=ęÉĶHsgŦ„ūŪkĪĮß uŦvZXœ=ĖŽJ†ĩ ôpDuÄËĩ/^üÍ]­đÍ1‘ ÆßiŪtˆãęĘŪr‹‘jÏ~ģŦ['ąĀATæ Qð}?•eá$Nˆ•<\ÐŪ$'ŊK­ˆk=Ïí'-ÐóÜđÓÍrŨh}cļÕüxbšA‚šŸ‡„™sd…IjĨ;c…ZĀUfžUaá§­WßÜŧR€‘]CþČŠŧUGsæ4āl„kŦø‰Yxž=#vþĘĐwŋnīMģn › Šģ‡°åo‹ã_ŋŨ˜ŅÝĖÎĘ"`aĶ“ŅÏ(:_ĸÝ­vuNiĢÝũî†ÓĶQ†Ģ@n5—4{ŅqũJ߈™―óŧÉ­Þû9ŽUgĻĖüđŸę6О8ģáĻēĀžŠ‡Ęt;ŋ˜­ŌōËĖŧŨZĨ&8Åbģ.ų]Oú—Ïšxđ[[Ý}­Ô:—û)Ï|–‡ŧĨšôð%SŨïAšK}ĒÓ;K /__?ŪđŠUjȌ]ÝÝxņâÅÜÕŠ :V•Ļ$tՔā+m˜ĨJjAūNP)õiŌ} 9›VíāœPnyøˆVŨZ>+ ˜5‰2·@‡•ÔĄŽ1l Ė'UĒ4ƒ$V,ˆ#m%••B[˜Ed% ŦZUŧvđ9Īîvó+ģqd°ĩĀ;éĀįóOÔ―·â0Ū}'z‘ ™ˆÚ5ëėŽ*HŸ8<+År€™'%íˆÖį"―ģ žxņâ/.5aŒ‘ÄԜfyoši'1–43ŦęC‚ôģũœeîČđ–GÄđsKmąŠZ%=lgjĒ]Ėj—áô#)KŋâDÜæ&œœVÄĖ=ķZglîúÖ=0ÜTv,·ónŽ^+ū―‘ļâä)fĐcųÞYđ!:ŋÂ/3ƒ,ģH°GÕŪe>AæĮŋ0*7 pšó·į§ģe0sVeuÓÐđĖLdUņԛĢZę†Ö áŋj[æ•ÛHs7Z>[$Ōö0‹{Vĩ:Üc}^öaĨŅ dĒt”đGÞūüRölWÄÏóĢH€ÝoŪXvuĄ§[ĄÔffĘdnģ+hČhRW·§ėxÎŲW<§á‘f-íýĻqŠ!g Ģ Č9Å:j–t– ĻJĻÜÜu5ä~ åëöĻ6ũ>lé@KŠÍTz*AššbŸŒ™ŅÝ*ģ%ķ<,ßdŊ/þĶÁčę†[wƒČ―1b‚‘ĻŨuMNöŠÓ+þ<ĖĖhûēiTũVŸ~Ú[+|Ķc˜§ ‡ėHIOÞúF.˜[—ĪáVIī0wïŪÎ1˜MGŊ€S­xŸė˜°*“ä:ĒÚę9kâ;<ÎX―ý9ÅéÝ#°]UĒŧĮ1ķIíá +‹”9ûT“ŲyîΟmnŋaŅ0ę+.sŦY>^-đq cZáþ― IÓŠŨRw7ĖÍÏN Ã_ ũĐØ0Đ4]mnžOvOkÃŧŨŨģp c,ÐÕfâ~žÃ›”PÝónšû\ė՝•ŨšxęÍ!ęgïĸýL6n—ēŌ-iœˆņ­Ö+özņâŊîjĨ&}…šÕu sÆUPĢŧWP­iÉÕY ŊļĖėėgĩŽ‘á°!—51û^Ô$ߚ}‰ˆcĸ†DóĻCĀ4ō—%iöÜG 5īLXáŨéÛrw‚đS­0‡0ŽPũýÁÝ'ÆÛ"ÖĩF/qœgá°ižÖzž§ŠæâįŲÕu2gQUCĐ$r—ÁŪë'îĪ…M·Í|Üũm`ŽØųdĶ õg}‡w7áŋ2ÆÜՂųŨ‹Ĩn› ðŽQqIš)ÕÜÕ*ĩ vîĄM§#t­Ŧēϕ6~\Đá<ī{y\Ũgz=Ė#ĶķÖÜIåÞãâ=ßĮoN@ø!5ã\œ™nnæ™Ų•ņ-ķŲ°ģųíŠ.Ũšj'9ĩÜÏŒäđ{›™ĩÆbð<Ï·ĮŽ}"Aât=€ÜYæü|Ū}–đ'ÉėšÜk-ĢAĻ.M^Z~u~čæ‚2‹xņâÅÜ՚)FššKāšbō dXą*ŋĨaFî_ŸX·2ŸðM8‡Q'_æÏmČ&ûjfØQ•. Ï*Ōšę8ļ‚tJÚ5V.’6ķ4Ø?7Œˎ$‹’ExXeAˆļō°öČ` SxpïãĐýt+w ZŸyï›âįúwŌ ÛxŽī; ;ïĒÞMp}.'ë‹ dwUšûŠļïį;ãïįC•Ų]ĸŪ df}bļũ&4žæĘņâŋŋ8Õæïaĩž―sŨŠ ÐÝRŧEeu7Zã8č.wĮÛ RuõýŽģÐMМhUIU’Dį“gîė<Ýâ!â9ōr8ĖxB` ļĶŊĖÃÍö~t~čîʞ‚ę’Äģ2ķVWúéݝôœu… Š={îŪL6Ėm?š ļïMŌÃÜ=ï Bŋßú!5Ð-íĸTbĀó<ģ_ĶqŽ ŸÏ§)ņÔŨQææ*™ŅHžxņâ/Nĩ€ŧ9=ŧÍéūFcn ēKÝߔÅįv„Å"”ĩĮ]ÔÜCЉalōį~.‹Xad•î‡ėƌG Ę}}–Áî}îļ|:Æų"+!ļMŨ!u‚fcĨ ĸD››ydÖHŧ–[ï:ėHŽ9Kfá<”Ÿ]ŸëģŧÄi”ˆ3ŠŽyėŋg6Ҍ2t—‘Y}ZŧNiØ ‰Ãû­zÎĄˆn哿t·įy؀ĄÎ"dnnûâŋŋEĩӘ[Ý9ņ+ūōĖ€f€›ŠÐú.Fw‚NcC“&ájŽã—įXQãoîp§“fųäũŦAðļ`ýÞaqēęķ#ÉōÓÉčîĄo*˜O™3mgŠĩԕ9udQݝ 0ŪĻ―!†=2ũū@•@]ëÚU}Ŧ‚ģH[A–9Ãvå!ņY ėÜ%ŦÕ>Ņ‹ ‡}y_ǃËX=Žínđw˜‹ĪS]8ŲRžÕö‹Ŋ1·[;SÝqrFÂegŨŲîáčĶD†ÎõĻĪ‚óĻ*ŽiÏĨG,I'ËU~x·šôÍĒM5ÔĒ/#Íe%ŋé…5Þ°XvžMacwCZW8Ō8ŧ U>fuf7ĉ”ĨĖH·;ģŅ+” |]p ›čây‘9 3Ÿ Ÿļ<օų-wĢ)aæ#üęCŌ{ŨÎ4Ą9ÓöËՀؐ™ĢĢŋxņâ/Š―š xD—ĶEņ|ų―UMš3“SKt6IwĒ5ūŊ8SįsĖŊ$ũģÃŠĄŧŠö˜zƖâ„ķxX=IŌŒÄ‘@īȝÕŲ§hV…đKП{gÖđx< ĢņēÚuŌ^bn:)6gąŦoĩmmīhžũóä3Á:p#L đ·‰k­éģ‘ús}`įÖ@˜WUvŅā4Ūt3š{ZÔš…sksËs1ĖxĖÄđ7Ē;3Iđ9^žxņĐvv5)zP‚Ņ|-wÏgũĄ–`T‰°u­*ßBïį~†õƔÅĢ 0;d ^ŸgĨJđĄ2ũÞM]ŧĶūŽ„ėåŨR”3"Ö>™în‡—ĮõY‘—}žXëūŸR›Åk5IûÍŧ1ØŋÏ?ĢCpšuŦŠA:í~vuOZg™ųɜ}: Ī*u—ŅhķOoåšūŪîZ+&—ķ!w;ņ:}B"cïÝ­X1ßVâŋTWÛÕ#É:œ+U-§­ë{œĨrs_Ū꩒āágóHMŠĘYø2ėÄdïПÔ]U~˜šöu—eīpwCƒ:‰Ö( Øu*ž―óZŨŠÕ“-ËïiûÔ>šųø\uĒvĒ9ï(ÂĖMÕ4~ŦŧIŪáŲĘu2Æsį˜_ëîîļĒu ÐĀ“&ŽŊu-üûb­ļ– ‡ũ|:z-ŽO~„é^Ęc‰Ÿû§šÜÍĖ æįO€ðŲBŒCŨĖæ/üęŌ†ŋÅš™ĩ3'"ŋÛÞßī4 F{™öŊâÅ[NÞݧ\öÞO§ϟûĪđ‡ũ.Ģ]ëÓSûâīðįy$­I{OŪ• zöcīWUĐaán–;Ey„ŊmÖŠLŋ"ŧp`nĩsȋ˜5ą‘TʂųréÛ)'‚k‚Įh<ģmŪuMVÃhiŦššĮQÖ­)Äúy3žéļ+'ĒŨūxLŽ0jãęėY,ĘLHÐfFð9%k] 7ė7-!<ŪjœJŧûËķ/^Šõ°Ïŋ•™>ŨT—fWŦŠ.đđ9ŅßÁöč·ķŅd ÛósŸ)Ø(vŨ 'tAh šÐ,soįŲ#ŒdUëԆgAĢRþ–Ë^ký<a"c uO`‚zlæõ] ĩ{­*éf;kZ$hč NΚpzw}W Z* ߔۊŽp?~637gåŒÄXŸÏðlĩÜŽ*&Č|ž‘dL.šŅbFéÆäüēÉņŋwāYę,#Ï ûÝ’DüNš]OæĪžTVC$–GU°s]vBļÖÕBeÓx^ë7É0šÚŒķHēŦ Ä=?§īqĶ―ËcÖĪbŦÅĖšŪeDķ@žĮcŦÝmđ čūæäŠNĢeWW­ĩ"l?™Y*‘|öīÂÍВÁþ]]Ē[\ąũsrđÖũCå@K“i@@“Mū\R}3v}ï',ÂMÄáYN’YdU7š ÍĘ:áÎO‚ŠēVwGxĐ i\^•Ļ6‚Ɲįđ’ ™ĮGœ§#óŲ€`$ąïÛĖcEĐ8,"0Kw|―v2Úy6YØdKÎÄÝZ}žMfþ ^žxËÉiîüđԾₘÏCõųZ­Ę2€nÓĨ(‰>gbø|.‹P‹ŅR§ [þuũzĖiû›,žU]eîGģĨĶ>ĸVguAÝ$JęŠpĒŋ―žŨuĐZúvÕė“ËåÆXn šiVĘ3T†‡é0ĐĶ }ūËJ ŊFė|Ķ莥Žė.sΈMģˆĩ3iF’…įIļ{˜ŠØBËhĩũ“éæ rÂqÆÂĶĶ@ãĖŨ}vĘÝ:Ŧ §û~’øsxņâ=Óaĸý3wį ~53f–ô%ãįÞiŒģ"ËZĮ]6Ų1;ģ;ėB°'Ē{ žŽēõԔéģbô}ŠtrWUųĐĸÎ]AîL vˆĖÎOû°›@Ð~ƒd\Óý­ĶyW·pļëÉ=û ™öģOķė§ĨĘŋHĄYՒâßĩž‰ÃI oÃH íÎkų}?3ō;qD]FšxÂeĖinÄŅÏb]>óōH#v 4+HŲ†?ˆ/ÞĐķŠ'šķŧvΗôo•VŸ%)E4ų ČĖ'ØÕ$,|ô[ ,LYjL'6ė6ëŠŠF·Ņh˜*AØ<ĸLûIw_ß*§/2Ŧ[8øųß'§ÕĮiæîöĸ—fk]r‘ąu7Éé4kĩŸŦĮ·6ŊŸį1ũsuĄ[Ũ;YUÄßËŊa4ĮŅŋŠjŠđi|ž{įCŌÃĮ‘ānV‹ó…―ûDsō š{–Ļ#ž…9ņ˞k}‹‡zĶðÆÝĮiFÐÝÔUYĀ7GfâoÖQbApŸĻŠJ#!Ø3ÏxÜíájĖS…GŨ!ÜX$Ŧ ›IšęŊyþŪz†w3Ģa\jũyŒž ]%‚āޙģ.čþ „ŧUý$ÝÏmWðTóîóÖėlĢáâŋũXĖ܍tg Ēƚô,;åēÜOšguIÝŨ=JRwëRu…ŧ[Lfë:4Ú:4ŅĨîT7"ēęW}§xÜÝ’;wf‡{˜?;2w:#sŦ@ė­þ|ŪįŲęí˰ šŧĖĘÊPŦÕ݇OūŒ6ÏÜÝí“nž“qhýüüÏ#ÖZuāyâÆÝݝ‡0yï=+‚ąu8dOŦ<œduO8™Û ޝÔÛ?‰/^ CĮēŠŪLĢ­ˆŊtĸ7嚠›WÕÏsWïX1ėEÁÂîįTØšŸinŸaīköŪóŽ~-tS‡ÓÕĸ?Rƒóû…=SjļA>ĸÃܝ(7wΜsïü°fÝ}öZ;_9/aÏÏ5æ^cSĀŧ ØÃnÖ”Tī…}ŠôKó$Ķzjķā$C-›bRŦāLŌ\ĮjŪ}Õė*z€éËÎĄÂĨ]S+ōmä‘åTH&1FæN•ĨI’W&î|9ÅöRŋZ+ް VŌŽ*ĩ5vV`Úš(·%ø9BBCųeģÞX2^ðŨ)  ÄÏoNōčņBՉ“§ījÓ SŧnÜ4ûjÜe *ŋxÉý7Rei6N1‡^†°K°YûHJæ•ø? Øsā ėĢݍ}t[6ÍĂ[ØĻŌm–dÁ‚Â<™M™&#M;2QĄ\ø,+ŧHCØĩXÂGļóÃ-аM,x8VĖå:™MĄ6]Ļû`*V3EęūčaĻ1 m/`WĨbXFyŊVx_X mÔĻŧæÔĒ‚ÆHÅĄÍcÜîœÚŅu‡ Ņ A °qúĖĐ9_}åß+<›ęW1ŽŅ.0Ēč-ŠTĐōČQĢY0ßŪ*jPkDęšĖž‘ūŅß? ß€Ū?͕j,ĶRŦ;ĸb&) B\üyIŅ6ŋHŊČaQ=˜-ĶÔ=1M›jpL…hZZÆ?vAņ–P·é ' cæ Õ "CЖ?Ø3š2;ÕmĮøŨĻãĒÛNQ°ŋ‹Â€ÆØžIš‚Pu†Öƒ‰đ—ęÜīĩÖKh›TŌØB?+ް‹―”ÔRÖĢjm~Âg ÜđyĩĢëýšdY=Ŋ]― ÂÖĻQ3(8„‚ūT­ZíšurrsíūRšOiWų ÏÕŪ[7''ĶÉ/ģåeįÁ7kárđē3ģ?–hqĩŧbĄ–îē:§kDEU}áE\xČÚÖŠS·vtžü\õ'ČŊ^3ŠALãĀ ŌÅyšĶ°+YÞ<6ŽĀTžĘZīNnŒō>ŌŽ,)•°šQĶ}ėšūgqeą„1į€Ī†QģAČÁĩÉpĖÄą1ÖŪ.ĩÍ'i2ŋĶ„\V‘”ēųÝē ĩ·°Öà ‹ÕJšĀôXÔ§yČZŪ;Ÿ}­wN^oUŪ\yé’ÅÓã§aĸô8õq…į+ÆÏ˜ņrýW@“óįÏ~>uę•ˉݚũütĘg€fō͛™@ līsŨnq#G• KOķjÅōeK—hyŽv!4ÂË?7eÚįŅuëXĮŽŸ:ųđįžĸtęīˆČŠ é…óįūŸóÝŧ}ú4iŌ š™šúdĘĪIĮŽý%9OÕÚƒ]ÔZŠiüŦ!RŨkTpRÖ ‚ø Ąîú‰ŪŠ 7hčQŊ 0$īŦŪ Ą\šJ€ā 0ÕâXĶ}Ɍ-š]):?FũáÐn†iQ°\1~4mwI āČĻđ+ްÂû ÄŅjęސˆ›"° âT­Zr·gÏŪgiÏāώO§NmÓķÝęU+(Ņï?`PZÚÓ9ß|=qōԐАE ūXíĨ°ŽbĨJ fVVæðĄï7þã‰į/œ?ųŨ1—Ÿö°!”ØŽĸxÂmÛLš8ÁßÏųÅô™ÉIIĪš5oągũîÓ§\ېā^o―“xņ–͛#ŦFþûïqxҜ›[ÐRþ4%F,ĀžšŠõ ƒ k t Aģégdĩ6yՖïÉc€ÓáύģégũvZŪŒēgæÐĒ-Ū—$ kņKĨ€Nū…ņe`Øl”åļ% ápĒB„Õ"―Hj!ˆ})XVŧ+ްÂ+…đ†ڍiÐԂ‚~þAœČÎÎ;+Ų<·ógÓĶÍnÞžų՗3f|ņųųóįIã–)[ķRŊŧþøãŦéņsį|—žžHEDF–/_Øĩk·°reŠT‰ô(=.S……•‹ŽŪ Î7iÜļAƒ†ÐØ^xņþýû\UÕ^:—-ûíéÓīŽĖĖðððȈˆeŋýöėéSXŠöŠ)Ō 7'kt @$ÕüYcuĻþģâ ãQÁqg eið‘ ŠĀU,ü—Ļ&&d0ýu4Í Ö0Náęü }€ėR”ÆĮŠ <&;9P˜vČ%Đ Xūę%Ķ76ï +ްX-ÉJŠû}IÏJgE GŸOĻ–– þ<_Đ…YúīŽŧõ~Nõ咊.2ģ@•ŽėlŠė-lWĪ―`t`PЕËĸžJ8}ũÎmV1%ą6‚uՙP}kËŕ+–Ÿ:}j͊ÏŌ‡ >fėļ6íÛŋ? ï·{ Ũĩ{6íÚ{ÐáCđN“ŸeÓIŧã(~o, žUĨī~ĀĨ6·ûų:)0r^§i~ĢÍH=PFfÚ;jI™ÛĶ=Øđr!ŋLhŠqqó‰|W…N]:_óģ"VP;Ó$n›gSųÚ_>$F*­ķOEýLŽ°Â /4Q”­!N†‰AČĀP yôļÏ;oŋÝģ{€+ðý=ŧwþøÃņ+V,ÔŋßšÕŦ˟7rÄðÕŦVŽ1üĢqc6Ū_ËyĘĶßŧWĮ.Z8ėčQgؘ"Y$Ē#—ŌUéy#Ę5ĘQũB0W‹™ÎiUNpR‚K5œ”āŊōQnß 0z0é-fō-2›†‚ĩ6ãËM3 – `ą1$#ŒÂcõpôÚ°ÂĘÕ  Ø €€ŧnŲļRþ…@€Ö^'ŽýûÄ q{qįû’õũOšA\ģĐMŒĒO! Ā6o\˜˜–íƒ[uæT…sįČNŦ- ŒL~ýúUrÔ?·’o&ÝļîĢa:mZ·Ößå/ĻW$ôÏÝŧũíŲ­đN;%šgNŸ>sæ4øUHhï/ãš+DŌøÝĻo7ˆĐÚ QÄųĘą;Ojž”u2PU]ÓeŌ#bÍBhóusÆ\ÓĘ 0œ:üŨp4eūÚWXģÖ§lƒų·&EĀvãŒn‚ˆ%ŲĀËDŅ;à +Å3Âņ”ņ3…Ÿše$ūšifÜ^ {`Ŧ04F@N9ŌšUmI 5ĸœqh0›]ĸ†9Ī2D+īĪŲŠī‹ …TüS=čúŋÁĀūTųrI”ÄП ĩą d6]͗“*~aą>›k―ÃÉn•ÚÎ2;ŲÕ|Ŋ‘ŌB―õŌĖv–GW>k(§’xq{Ð,Š–Ä S.bšyāĀô­―|!þ‡īT0—kĖÛYō·ÆĮ 6l< Œ øJð7Þ7vH1!bþ·)īBž5ąKÎŽ-­b+ÜU·ÚĪ{ŪiēGÅ}Ņ—ŲœŪ"é,Nš˜[S/ã&Ū@,ƒ5!Îę ņʰ +ā0e^ā(ĢUMĶåLMš2åį_~ûÁøŅcĮ͝ũstíčÜÜ|NŦ=ļ|<ĘøØĶwįšsēģ€'Ü ģē3!·dWģssÁCR·ÕŦÕØģĸ`Ýz/ó'ƒÅõ€ƒŦŠûŒ)Gõ(`ųЉ įMģ2~5ꓧ\ ˜Í/š“ë!Úųš_†3ę–+ðē3—%"]›6\.íŧ#ļhëqM4;T9ĶuÚ’Ærht·`+ŒæÂNˆ 4Aqý anÔeÚ a wÖÏ,šAáj%a­ūæ\™7–{Ya…ĩ`xĶyEN―ô=33Ģkžƒ‡{pĸþˆļa#ã†/\07™Žbû ]·ÞČqãPÐÛŦUë6ŸLž6|äȗŠŨČuįđ\AíÚuøðã‰SãŋxýõÖ%J•ŒˆˆødęīÚŅŅqĢFýāçééaåÂû?ýŦØN]‚‚CI,€Ølđ‚ƒß1ēclįNą§~öÅ[o―Qõýaq“§~Öū}GPD,SĶėŧïõ™?}Øð(ŲērēðĶ™4eZ•*―Þyũ­wûļ\Q5kĸņ”iņøÔÓPlM@Ë•G›ô@c)NÞ j…Īó ˆCčŦ]u9ŊW]˜4‚M’ðYé [ÂåôŨ<ŒŠÁāķŠÚā;ļl<Øo”—‹ßÕáĮ +Žð>aŪXķú؍3ŽĻz<ę=øÚŦŊÁpį|;{ųâ%ĄÅB x°ČŅ|ˆ‚%XppðgÓĶÖŦWÜã<ØęõŨûô02nØåK‰3ŋ™­nķŽþýĖþfVŌĪč:u˜52ējNvN…į*þ4!6ŒĮŽóãž={wÐ2ų,QĒäŧ―ß-UŠÔƒ‡Ņ, <øÎ;Ų99åÃà ~ŋk§7/_đ4ũįŊūöÚåK—úôéũvïÞÝŧÄVŽP­D‹–ŊÖĻQã·%KžķnûåWģnßū•™™Å ãĮ]·fđZ°•Œ…1ņ’ķiZxĨûrųfũÏto}ĨÐ@q–!ŒP†,U d ÔŒ4•ķšo‘ĒE֚ `”ēéŌĘÁĶ*™ØÏ–m+ˆ·[Å^VXᝎÖ#PËĢī$ųã;iPØhđðōčÁnßūZ,”$ĶËÏnð þūc{ģÆ Ï$œz§ũŧ”Å~2éc<q\lÝšíĢûúũ}7nČāI>rŧsc6>ī…ą°ŋéņŸ <ļA *߯ÖŊŸėÜĨ+ŪcŒąkŲeR‹Ķ=ųSMĒŊUēIŌAzŦcY@æZs0_í ä„ęjH9ÏN#ĄŊ ąkރt/!Ų†qʈĮlʎuĪAgÚÓVXaÕՂ­ė)9Īj@ eP?(æĀÏãŸiucZ‹ƒ'Ûķlđ’˜øJLCF–.]zӖí˃§i‡V­[ĸhBå*U°—ˊ/bean·ĨĨĶ>MK faĻq§NąL ”š`“âÅe—HKK=røP°;î\ÂÉĀŌÉSĶ–ŊðžĮSĸœLJū””z• +{ãú5N:tðïG)([š,W5sÖŨ\0ŨûėŲ3ō"đŲ9tV7 ÕĩŅ9ļ)―lĨX“âî1y[ą°‘‚īädĨKZ@hï5ÓĮĖŨ4kå–Ļœe03sČXm`‘'ĩė7ŠĀåCČČĘT@·Â +ž°áZXa ppŽĶxceĶg^ŧ~­y˖­Ûī>tðOĖ―J•.Ã&ūôQ“íô%Ē2|p‡ÉÎĘt<|øāó/ūhÜĪɘŅ#o%'ŊY·A$ŋÆC[{Œģ"î_üûöm˖,æÕ kWŊŠžŠI…#)‘NH>Tåg†§ĨĨņïóÏWâ~\.FįææĘīšÝwd,'7ļütâ„ÄÄDč-AxŦՌzx?%#=ÝGĶ֙%ĪA#xjlwŒ+8 ~Š ‰VņņâVŁVŧ=š† ĀģÓîäŧÁWeiLɊœ7ļ u*ķjIF‘Ņԑū 7áĩÍÉ­°ÂēŨ=ŧذj·.?ÖüûøoÝēc­þEՎæŅžNŽxBũ#k%zþė™V­Þˆ121ņ" Ų_ųÅíäjØĻQĮŽąô[ÄA:ˆƒßÚĻq“];ĸĀ”ķK—Ū˜‚ĄåʕëÛûmÓ"Á2Ī·ļ’ûЧŽĖÚΖõÎüóČ>zÜU"#›4m†‘ÍÞ={ČäÏh†ēßå{ðĶ͚zčŅŋþŠˆŒ8wöÖ6K–.ßūu )‹"qË= ‰…ŅsläsRĶ›c\‰Ûē=vÁJč|[>oSĸFžqÝE ŊEÚ‡3 ·GÃWÍŌT@l”ūÔZa…æjí"aø?Yú°HãENþ}âxܰĄėĮd‹šŦWŪäæä^ūtqïžÝä@AQ2đŸO™ēaýZœžŧtënÓš…U+WœJH`ŧ ņį~äðA jÝꕇĻ^ģfĩęÕAįO&N ŸÂmÚÆ4ltĸ~Š(_ĩņ.Ū`ûĸÜĮŠ *Kėß·ũüđģ<‰gfeØĸ'ođzíę˜Q#ɰ †e8ĮΝM}ō„KšråðĖúēßãÜđkŨŠ+ÝŋÞû,“’â#•m”ņŠMŒĒž`. žsãĸïICQĨóc>Ð,,Öīdg˜n‹1'DXŧį‹qŌŲĶŋƒņg0v’€ÖŪ FĄ:7+ްÂÛX-û9*dA øėĸo’XGJ8y",ž ĸÝ―īøŨ… ~þ)88Čå@2áÚĩŦqƔ/_ZzûV’Ã)ø{*áŸÐÐÐGfef1ĻĮ°·{õĻPáųĮmÝīiïî]aááY` =`ŨPÂÔÔGcFŽ€ļpëŅ­3l388äŋŧwŧwéĖŪŦÞŋïtÂß%K•&œ™žÁÝĐS Ýb;!ŧIÁëY3g,^ī72ô2ŧÆv øÁĪJÉ  †PĨ°Ü#čI ōV_ý4D[!ÅķFyėģĀĨšĻōXŧjrk\$Ÿ`ÓšŪBeƜä&ųk„ΊÚÛfyiŪÖ +Ž‚čý‘Į=Ķ ÁĮAÁÁ@į―ŧw9 †\ÔÍЃxĄl ų‹dö~Ę=þ pAã@/ōķđ99@  ąmol·hÄāQI.iV8⭛I Xɚä@› ˜‚qš:Î‡&ØĨmļŸōMhęīeefgf&ģ[EOžÂÂ<€ŽDÉ…‚†vÓږÁiĐOžĨ=Ĩ΀įŽNO ÓýÜnŒaÂ$rÖÜËÚ ›ģ|õš5Ē ą°|ÖR"yGy\Hū$ÏM­°Â‚Z݉’‡t)TēK~)ģŌū6’^)ŌžĶ^đ|éäɓhü]ïõíŨ­{ũogÓ3ũ+lĮ<‘œ@é2eZ·mûûï;þéðfĮþĄw0Ų‰ÕĢĶÏøj‰ĒŽT―zõ_zĐXąb-_}õęŋWžeĪë•­Õm&LúäũíÛ>?.īXąø/gž?ŽBÝķí:„…‡5oŅ{„sgÏL˜ôi­ÚĩĨÛîōĨý |ģS,ßhÏÆŒû€ŲvíÜI5.ĒĩJ•+UŠˆĻ_ĸ•Ó ĸ\ū|ĐfTķ 111Ī8f<Ķ |WŊþËýÖŽEßÉ-7―ðâKÝŧũ€A?―båĘãÆŒÞ·wïĻŅczūõ6Ü622ēoßũþŧËýū;dč°˗q%/žðâ§SĶĄaƒĖK·GŲR”__>Ûm5fģL­°Â[·ÅH>Ŋ&ĸ.R―Ī­_ėÆúKÔP~ĶT Xh(ū\ nÚŽië7ZȟŊX‘‡e&:wîlügSþ2ČÃĢ֝—+Sååņ”]ždÉÛ·OŸ>õ“Ipį&͚oŲī‰ýĨ7;vęõvo\WŪX‘öä €ŋf~ŠV―ÉStđĖĸïå˧OÂ§ąjddŧöí;ö %Ĩn―z ^llė+Ŋ4āę’™w…mÛzvížrųŌߖ,&9РaĢũúô#ŧnݚ ëÖq|ŊQģĶbÜxóW_ŦU+ęØŅĢäRyÔüøņīɓü4ïîÝ;ÐUō'ŸA§ØØjÕ^âCxŪ\8iiŽ9ÜĐc{ViÚž‹ÖĐS§cĮŽ\mdÕHŧC<%€YėlؚĢBÎCUŅg h­°Â+…đ ĐĪ, ØĮKl}Ž0ÂSÉÛ/^"ŠV-ø° VrX$cŧzåJčēTí^#­IPrčĢķ˜GfSÛĢvÅĩKĘû\wîÞÆŊķALÃķíÚ=xðāė™Ó>š@ ,Õ(ĩŠÔLëÏ―{ÖŊ]‡ŲšÕ++VŽØĨ[ōåŸ[ąl Š\ðŽ‹į*=zždŅbš–;ī•ÃĢĮ˜*8$čøŅŋ·kŨūE˖ČՒo&Ģ@ËĖĖDC\ēti›:™GėóįÝLJš=gÎæ;6oÛŅŪݛîœxĨĶë·neŋˆÖ kV­TŪ k‚#þüÓO-ZīÜĩoĸĻ1c:žmóFĮ”u‚kîۛ‘‘á œRšjųē―{ũ’ŌÝķ㏍Û+əž;{öÔĐē“Į_šxņijęÜïūÅ#qŲĘÕlO­ÛļĨF͚ÂĨ‚ƒ~ģēģöîÞ ũũėÞü åþÁ?ĸdÛ·nÝLNš˜˜CONū ,:ýäĮĄ†; !|ðaļyãÆũsūŐwÅŠ5›·ýūjÍ:ŠLš‚›™Û―n͚„„„'LÜļuëĶ-Ûz―õNå*&NGõB‘ŠÆD$G€šüZa…7†eĒ(Ø$Oû(댃Ņjïnĸ le@L-ã—Æą)ũïaŽã™Ó.ąoūúÚë°ž„ŋOüóũIšd .%^˜7ũûę5Ēî߇ Xh‰â­š7ËĖHũsųψĸlÏŪ?Ļ‘JNJ:rðĀäfŌ<ũ―{ũxÉŨÏ4€ð ĒHM}7dP˖ŊEūøâÛ·Ž9B7ĀóÃącg•ž~/%Åt”Ų·gOÛŨ_Ĩģ…Y'Ž=wî ÛŠeSū ęųĘĢé".\€Ÿ•Ö3vŋkŨ;z$-5 ÍÂęåËöíÞŦŽ]þŪĄCI1Ŋöę֙ĒīāАUK—%üý7ubÜ8،ä›I sËfï āöŧRRîõ{ï&M›GDF^ŧúïÉãĮRŸĪŽ †sR`Ŧ Ę­°Â ïëÂp@īĪšÞGB*aĩ} pĸA IRpVūŒ:Kæ8p$\ŋn PVÂōîG8X?z””:ԜŽėK—ĨEŪ{{þ>y@Ôž§ yŋƒÛķiS­Zõoŋųš\­ [[íaŪĶRą[ķll„ķžuųûcöā~ ũ”ūĘŌųyŨŊ_OšqƒÃJzŨQ˜x!‘ÉM?…'MnÞĒĖwíꕈ8 o}–ņėáŲ‡\ĮOŸĶ‘Ø%u€Dâæ$ÞÅåķŨŊ]》á<ÝŌŪ\šDjÅx~ģtâŋŽÂ qärYÛ·nfY ÔtœsIkˆŅ ËhÍ2—‡€XŋHˆ[a…ũ…U`šmsē˜cuŦōQi–M――ĩs‹ÝŨßßĨ[@R)Ëy—áĀ|2þãĮ]ūr™óŠ1Āf3ŋ#Ī5ÏÝZ_VģF $°“?™H0ãŲČ$Ōã€Ĩ{ą k/Ĩš„Čcí,ÁlāĮā/`Į1#ļ ŧZÝØī@˜WéęøôéÓŅ#†Ŋ^ąÂnœe]ÖóĖ1!šüĩ…Ĩ” ðFŒūŒ ĸÍĩŪ,-š:EbpUC/đf™ÁÏeüeļHŽĨd;Õ [“WÕbc›VXáÍÉ5TÆðĮjÃ*ļP šUq}‘/ÂÆĀ& ø3] åØG~ –ãF˜3ûķՌҁŲ­-čėtk­,ðÐ%fúgŸõîÕsþžÝ*ĮRŽðA8́Q` ~MʘģĀģÚwœå ÕĶKrĖéTĀĐ ’ē1bøûïė·ņĸcï vegrädfÝyۏmøá܃îþO)I†ûJįŽ x;‹N}Ŧ‚ 1ĄÍWDHIýŊĸđö^Ŋmļ§ą^Ŋņœ:ū•ęqD 0ĻĖÛĪüÍïĨáöH ęđЈÅĖ·RAœsÆģũŅũq…žÝe"BI|øðáĮdÏäJRW]2ģÎ[ÔÞŦĶĮAęœKÚ―Cx­]U$ýíĸm< qLŌž§7YFH6ŧŦŧŊŨúŨŒpû™uŠØĮ)1nÅŦžŠf†ĄĖ<įH‚™Ũõķąũ‹R]ŨŠļ^câ_ójÏiEFÄsaF\ïk<ĪökW7EšĪŠ+B†{íꊊŒPDW“&@ā}7žŊĩmũԓŪļf`<NŲ&ô ũǘúĻö'ōáÓÕÚ+—ۏ8(M7Đ―v„ĘSÝAIėnЀ]S{­Ũ<ņn|§ö˜TOŸsˆÛ_3ķ13UÄÚŊSŋWÉÕđWŪžę‚!)ÎÅŪĩfĀ' 1ðôžá6Š  g?―-Œ™đ=ŌïĘü |[2ko]-*˜yŌ’ˆļ/7Æ4A‚JāGdW“ī‘§ 4ݞĩ„ũ„`͟ø8Båáų 3 \Ũ#â3áGōáģ1·šV.‚cȈéŪëØ~­]Ýu:$ðŪ"­•§ŪîyTØÝUwēo"ƒ’ ƒ™ŦĮ=!ëĀČĩžë°r“ôÍwLdÆĘ <seWÏ8ïÖôAŧũ–hC QÝ-ę7žuI†vwÞkÝv†@į\ķŨÚ{ŋfĶŦ$y|ꈔt§Õ83Š‹ĐŒŧÅķïEÐ@0ėđŪë™ó;3°Žĩ{ĶŠŨZ0N•áČīýéj$>YmŽęŪ)3ģŧoŧ-I§kjöÞQu<“ó'߄Qu`„ĻP͐€!ifūÕÓUu$ ėSĀH Đû€åtŋŋÞ3ȕÝ5-…ōÔĐ˜Ï[Y r%‰ëzÃ|íŨđnNeĻŠĨ†dÐc]uŠūôM+ä'Иjáņœšf&˜Ū.’‘ B!‚Rtĩ)žN|Å"0öĐ9œöz­H{l(BÁũû‹Ō#ßvxí_uĘãØÕ~øðÉjŲhÄļ΅!čXAģ{"eāëýÁķĮbŪžÞD‰ë\o›’bEOƒ č6Ɍtî|6’ÞŨąky0€Ļ˘%%ģŦ0ØđsEÄZAčq.ƒ§īSqÝÁîÎeļgð$b]ŧ{@bÅzŸ7ŒŠĻ*IĄŒs.ōÉ){Ŋsō.&NíĖ,ŨŒZņ= ķ”U§gh"Üv„0Øį€X‘=ʼnŸĮ‡ÕÓ#ų•ŊŋŪ/đÂōÔ|ÚÕgƕVÔĐF3ŪŊËô<āœS§ŋŸüCðļ="”ņūŪÛđ™įëĩ§ŦÆsåtũäĘėéķ35ãŠ/Û1 ûØÜŊŨôLRKyúŒąVΌåJ†B]M13OÞĐÅýƂ37 ŧŨJPUgęø–uOO9―Ŋ3ÓĸökWã~Úvį3NEÕJ†Ūũ;ŸX!T]ī”āœÔĘ|ßi ĄˆÄOäÇÏn1@Zïs …$†)RļÎĄīÖvŲÓÓßé$„ļcÍŪ―_qĮš·ļÕ= †ēŧlÊęĒxŸÐEefOU·ˆëÔĐn‰$Cjĸúe ŧ<Žˆ:•'ŨŸ=4ŊsQLĨĀSįŲY03Č―f$C"Þu ðäģ(~s[Û$)Á†+GwöZÓuØ{Ÿsz,I}Û\qSÝ Ķgڄ:ÝķïL&ƒŸČ‡ŸŽv-?fŲ+Ýãa(@·-*r°đâԙņ^KĐÓĐĩ·‚į}ŒŒš‚‰AdÖ9Þ.Sc`ˆŠŒigdóüȕïëkÚAQžęˆ uŠdū–i‰ÆėÜ]5c˜Rī[ŽßHį6qfÞŌ›æÎđO͈ÛėÔԚqO7āũVīé•ŲÕ5•Đ8Ũá―;™āĖĩîĸÐ"a_Ũ{ĶũJ’5ũ6åõK`ŨÜįĮTΕzŠ&>|øðŧÚvWÓ>SķEuW―/ØĄ8__] 3"lũÔī{ĶOÃĖļmxG!M5z@C|^öšk‡a)Æ3ŒH-##3rEUëŽ\+“ķ‚ }ú@ŠL“€Į&YSӝ™Ņ=Jf&! 62–iũP‘‘Ý53ĄĖŒs>đ~Fė™îjÃÆt·‰î!1hšw5 ÆŊĩ{šŠ=ąÎĖĄ$XU„ųƒ!ĘcžŽļАZkŸS6D‘€ĻÛģÓÓ3x‚‘)Ï ^Ũ{< ķ{ČPȞ>m ôą”a>|øiB(2Ũ9‡ĪķŦK+ũļŦïë‚ýĪĻí@ =íADTWÕe{Ŋ=3>-ĄSWUEd(Þį]§3“üöM†ÎđŠzŊÜŊmdĶlüĮT°SÕS†%Í4ā WŪŠĻ„ëýžž šï"ÖÞ5%ƒöÜœäđĘå•9nÏØÆĐz$ļ2ïČļ"ōqší§Ža k­35°VŌ8]Ķi €Ý=™’äI)s―ωÃg† ~>|ÆÍô؃6ŪjŒcEՁ-IÐ9E03!Ø0 {Ú%…Ra\k_uyŽĩRŠ*Ąp͞yí=ðéNiïŨ=m@„18ūė―lwŸˆ%ōœC‘ˆĩózÑaû}ŪŧÚ/clŊõÍ=p(u§―Ą`áúzÃXđ@œ:ÏŊįz& ßC ŧ`D(UGā=„ įz‡ĪØ3sÎE0b]ï·ŠĐŽ>3–ĪÐŨû―23—Á:gÆŋ^ŊëÄ›Ī{„>üČŪ–ŌĖDætŸë€ØŊÝ=$"s­U]5{ėŒ€Ý1L·§oÉėę)‰Āõį•R=]U{ïą§'DR=Íû‡2ÚOó(IӃ?2€ˆXU%x­Ïņ™―Ũ―xOB§NÏ(BĀu.‰ãånÏäJãī'#íīs­―Ÿ|VЈuUu21ÓSĄˆČé6L+s}oņˆLEuÍxå @ŪTJÂđ.Ãûõę™HeĪ€žfČ6~">|æÕb+‘‘;vũø7°}Î;ÞŨ5Ýš’PėnI§P<ŧÎDF€Šųú·_ķį.,ĘpŨyúÁîē-…įiUîUU$!FDwÏLū–oegŪýzėÏŽĩĶ{ėˆ€QžĮāëžē83k/ÕûžŨÕu‰PÎ<·Ę zJbîeĢĮdͰcåx(Ī’äĖČĀíïÕŧæ^;wÕ!3}/MA?s‡ŸÉ^A|lLōqkdˆŽSOîЈg›FLUÍØ+OŒIūöŦšIØōœ ãÜŧК•+âÖÓ}2ÉxšRJIūßïČin‡ōn<Ïuõī˜@Ōöđ.)r­ĮÝ"Ēį{ėËãVJ‘1vWIz­ÝÝ#7ŧ‹wŪ䒐™Iōôa@Œƒčî˜.‘‚Yu)#!۞!%ĒŦ \Ŋė)ī Ԍ"hМüðøðáà xcû?GĩŊëúũŋĸÕÝkå_U°Ĩ˜ÎžęîÛTŅÝ]MIĄ?ûYģŦN5fúëë @D8ĸžÉŌÓïs<ÝåĐ+"Cųū;SQk­ŊũÄŲ·XûŠýÚ_ó5ÝaāOĐIp8É8dÏtÕ^ûë=Ý peüãĸxōČx‚…ˆð—ŧũĸÁ_įŸwA*ršŦ[R\zúî˜Ûéã‰{Ņî )RŨûýĖå™ŋĶgBzr’ŠąÖę™:‡ŠĩÖ?ĸų™y€ŦÆ;—ÁŋýóýücáĸÁößĸþ}JēŧņáÇĸDäŋ|ōëŨŊĸ՞ŠĸößĸĮ9Ũëõ§")ęœ €ĪPÔ EĀĻ:AðxÆ^đzچˆˆ5·FŸÞ°§ ’˜ņwžŲ=„mįÚ݇ŋĀŪĢJūOV< œnJ?•hÃö#ūįë Šę―_ÕƓێ=Ó $õ9ŠiėņLÏZŦŦūo\1Ó2ŌpUgåÂDÝ)°ž`ätå':čï k cŠ˜Ä]ŲóÚŧóčĻŠ<āũūĨ*•JRY+{"‹’HZhČp ĢĢ"ˆ Œ­" "ˆ Ļ!aSV‘°FPE§uh JÓ Ø­f„0š–U0ĘbR’T–ŠJÕÛîýMĨrĶgĶ’Óp’éJÏïsįŧååúž{î}uoŦÛ=p`žŪŨįlLLôđsU NJBŒąÜÜ7:ąĨN§3ØŪX,–ĀĶ9Ðö’öÖ$ ðcÐrr}ƒNþß1čü·ÜØČŒžœÞHGrã#ïHĐŪéŠâŧ~bëÏzIHHAQJ ƒéš~ãQz„pĘ"„nxʼnBĻ›aÔ"„F-BaÔ"„úëG-B!‰ü5 „í™ĮŲAātÕsBĻûp€ö HÏ"Dn?R‹vgÔRJCų­ÏÐT„ÁĀéåĩnÖė㜓žÅ,“Ä)1R°šĻ_·D-cĖápÔÕÕ)Šú9–˜˜˜’’"A…RΞĐņT]muĐ·‘HąÉyķ[âLīíęĻĨ”ÖÔÔīīī 4(..Ž„žúúúïŋĸ222pn Ē„xuōc―rūš9*Ԛ}Kt˜Éԓn{hr{/ýė9%&ÂBþ" x[‰& ĪKÅĮĮ{―^2Bš>[Â-1VŲfI§4ģšÖIˆ9&..:&B 7„+Ÿn•Ō…JcĢŽ4*:0čžm1čôX\Jæ·7žüÖÎaTąÝõĘįŊO3]ߚR0ÔF—/ĘeÝįiQ 6&RÏ Ÿu?ļūøîī@ó.äiCB(0S dJ‡ÓQýHų'ë_}óM’nK^ņÛē{2‚ũļ۟ŌÚâÓĨh›•ÕŊ>―莒wïím€ŪzlÎofÁCš‰ģ;|hAŌŠ+^{ĸäŠēŊLwþqÃhŋJ(JõšcŅÛĶ­{Ģ wÜÕ?n/~§vÓoÖ%<|üdoß(ÆÍŋ€RÂoë(FāāŊ"Ā9 %„“ö?š3@B BX DIr~ũÅ3ÏčĸĖæōĨ‰ÞÚo+ŋMĩ'ȁgŒ·įC 3‘AEéø†•›ĒïÞY8†@ôýS'ĨĮŠŒņĸΕķVmÝEʇĀ%ßâéÏqÚQīmÝÖ―Q œóŽî Ē kz Ŧ#—-ąĸØDĒj†ŨqrÃúđ_ŌóĮū:ũŊö|RöéĮ‡/ÖÍYPtawŲŋāžöF銿óG]yCJįnæYÖÃ{Ęë3zgÝKŲņbuÅo—•ŽýÁõ‹üAą™‹ŠÆÛQZēíwnĘfo*?(1ÞŲJMBáĀ ÃiTĒÚūōßyó§Ž]:-1’Ö^Ģ~Շ3ãŌĐ}›ŨžömšyûČEŊ,ČM„]+ÖVɒóĖÞŨr—n\;.ĢeËÞŲ]ģúąÏ‹ŨĖ;wh?ÏūKŪúd]y}Rģcũ—ŲūļvÁīČÆ?-|­rÆŠ™―ŽęîÅ ų‹Ÿ‘ôŧßÞļngu|Öüå+ÆLbœZƒqčÖY-ĨôÏiK‚âŠ9-Æße-™6ķbbáœg§äĶó’Y3f?·Ŧ,ũéœY6lð}đđYņĶ/ZúÐđß]îý‡#öUŦå&™ķþŽ>eō·ĐĮö|tyØcŦWŊÝ1{ΎĢÖÞé™ûÄĒð‰Ĩe32ŨOžņu}þœÁĨKķÂâ_ïÚbŽmŋž ĮE-B8t0{ĪŒwëĀÁyąáTQ5D3dģōãėY‹­Ģg—mZ:Úīųöƒï?å8}čƒÓę+ïž™ūuÞ{Ÿî·ōÁŧûũđ6xÔė9$‡{ŋÞ·Ï6yyfKõĮ֏˜īpýšYE/­ýæąĮGRĮ#G&éÏqÎ.žþÓå>šRõoÏ.ųhŇ;m‡—.Ø4lũę81ØģQœ·Ŋ}tï‚Ķi?N…ȧÞûčöŠ/7Ŋxaō7>ØūĒŌÓX{ðýįÃŦ~r6ķĻ‘zEÛS33lķČäŽþVە^}3Mī‘ą0]ũŠ$ĨŨÜe+ïėcđÕėdĖuåėđÄ[ߟ;:%†Lœũðé\:D?0ņŽ ĨÅÓŦ&,~arlxgŦĒ(„Pč။·U5xÔ Ė04Ū(šĒjSPŲ,VŸ>ü“’ķņ‘Qv{܋OŽÝĸâá‹î‰-ŒMX°ęÉŧ†•ŒŊ ŠÆM‰―­qrjïôŠVĄ†ŪК3iø”%…vōŸyÛ[[=ZD gmq&AŒãû?mŠql[üžāQ]?Ņk5Ę_AfĩŠ cÝþÅ\@:ĀTŸĒ…9á­4éž1óŽ^qGlā?Lzé‘Áaē965]ĐŋĪę…ëeŠĶІC儈Œóķ‘įŒ%šÏ_c€Ä‘dŌė8sîįÞ}•ƒû* ýĨÎĪæ­öČŲ’é/ýԌ’Mo―ĩi݂ÂeURΘŧŽonxõMŦ_~û9SÍ §þČÔ5F(5TŊWÕđA“ûõ9óëwķ}ēŨÍðĩr „ ^·˜ˆr­-aĀŨ+ÕęÞžfåō9+*k é}FLČÏS?ÜúņĄCå{vhæT ]I"7ˆ`€ņ˜Þŋ‘įūÖč‰ÉūĸĒņY"/ß2boʼnkǐa2,qŊ”lųōčEn0kŊ‚ kŨSÅ >î…ÕJRŒ"DŪZ’ ë øKŒôX…G>ûî?8~Ė–œk-Þ{Õf‰ÎÍésēŪĐ hųØ{†s”RœÕ"Ôãt&„éRlÖĘ7wúâ'š5äžaýS“‡-}―ïgŸŨÔ{Ķžžîū‚ÛUŸþðÜe4­ŋáóÝöŦâB!iÞŽŅEĨ›ïĶ“ė3W•$Ø…Ļˆ‰ŊÓ0Ęļh~UIb’އũy}ýÆōĢ?d>þÐŌĻ&Åh―ķnŲúŞŊnÕRߎ „=,xM7D-é°ðĪ“ĶßÖþb–ĄŦšÁs†OĖ+B]õiO|ïĖ!”1UÕ oÔĪAĢđŪĐôÖQÔPTF‡Žm(>RöðûĻĄęĖ―cÆó2åšÞýâxËĖ’‘ĒfþĔŋ „û‡`B=F­H tPGļ.E$ÜûÄô‘œS* W| § žœ”sUS™AsšĶ)ywf€Ąę ‹{ôņéœųh ĢîcŠEö“F|ŠNhäÐŅþÅā$sÐĻYCFsf‰ĄŠL7ÅÞōðŒY”J™ÏŦ―čZhÚ@E7ޘ[QQá?!::Ú0 č<‹āĀõ?Āõ5Vwųûį.y4éķ!ÃĪEŒĸŊƒw”$ĐąąņÔĐSøvm(@ˆRRÝĖ]p5ņýâeJĄg=ŋG%•?zÎÖ4 °N3‡›(‡Ū~ŲËn·Ÿ={6''Įfģ‘ĸ+ĐYƒ2ģ‡PĖ0YĸÂW€›ššÎŸ?Ÿ””DBBH”YȈ‘ëšN^t6ļĒL&‰é1(iņ(—k“ĢL‰‘Ē$Bšüļ™ĖĖĖK—.;vLUՎڄ΅ėfģ؟ģééé8Ĩ !á&ŌŨæjšPÛęhn „’EĪ<)RĘˌöG­(PčŽ?ƘŪë=â8_AdYÆWkC B:ƒûđEkō2ÆIÏ&Óä(9Ų&G˜Đ_·ŽÕöļm}œÏ†&„8ƒÆ{ÞgT DĐH ĨÝģ-†BxĢÜÄŲ^N„BÝ Ģ!„0jBĢ!„F-BaÔ"„Ðĸ‚Ãၠ„ę‚ˆŲĘĘJ—Ë…iÛB˜ģþ€õĮ,)**Úķm›ĸøŦ††gA!äUīúÖģĸ9ŦYÔAÜIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-add-components-selection.png0100777000000000000000000033472413761647206023316 0ustar00‰PNG  IHDRÎbðZŊrđ›IDATxėVŲSŨõĶ\åW—ĸû5ypÅå‡Č•H–”û'YÖ"ˆ} Z,•„äڜ @ēÄXČ Y[ąČĀ0Ž3ĖÚÓËtOOoĀ€PR)ûį’e§*IUÎĖ5'íūĄ3å’\•ïárúÜï,ýõ9#Ĩ šÝîÅÅÅĸĸ>ūüōKĘc:~D&Ŋūú Ŋ’ðņLžiÓŠ}†§ĐÅüŸ>Ošzė•·9éI^Ĩ>īV+Ĩø? >öx ú ýlë?­ðÛßßĸÜ /žðŌK/=ĸüó_/ãņãĮä$@ŋåę›oū!'z,@>9‹WôаdĢ“c'3™ÆĢGĻV­†ŲÆäOAžýaôüõąĪĩyīÔ]―>ī“–…œöú ß^üúĖü'ÓĮ&9ės"čĮNĀ3ŪüīūüōË/ūøbŠŪë<€ŸÞĨĨ%8ðļ°°ð°ü%čÓ d"Áœ™Ô"€H E1ܒpð Ģðīɀ­š^ÄV},·6úÐɑđŌ•ĨI{},dK„ð,ëþÕčcßUōú˜C,'•dī,īąúųA<™>(ÂęõA#MžY}Ŧԇt]O™ŸŸŸû>b †Ū‹Įx=<ÃĻŅh,&\Á €G°!x ÃE spjšFnÍĀ*pUy 0ūĮ(Š-‘[8‘fđ4ņ@Eôcoū%„†đŪ nÉԁÖcŅF&Ý$ð$ô™_\zļô`‘„šą°øžáõYÎ[ĸĐO &fqá?ęOþðOq<\ZˆÍÓú`ķÄŋē‹ä"æÁīÉëC"b&Î~, ŨŌÃ8āĸ &ÜŌ _Ē ‹†6ý ―°Zƒœšƒú €üäõAgōú  ËXRúĖ>>ÉïœŦŅÎ'Ð8ĸV­"EO"I<Ą‡<žķC‡jĩņČk?;öÆ/KЧĮqÝÝÝ---ÍÍÍ}ô‘Ûí&Đ0ûðúgꚎdxëĘŨÓj6:UîŠßĖÎéËĀ@<Ác~$@@Ó4:hX’Ģ–(Þ"aiĖþĘBĀĖŽHÆÝ\ŨNŸ8Yq9î;'=Š>›pœ{bČ1%ƒeŌi?<æŠĻ:Ý6ܐÐú€_b―.ŋ–ČFkū<9ó1]šŨÓŅÞqõV+ąđDóņņÄBqŠáĮ‡úûîÝûŽhTŠ‚ßúÅ!D™õÁĒ},m'ęęÁi§+†Á§įų˜ EâÃƒ}ýý}ũz@=5N1( 1õöĩËŨĶ5ƒš jPÉŠ&ķ@ũOŒđ|žNū#ÅīŸz#ĀÆýGf2ú €Œą6úÐã‡6­Oōû…}ŌZ<-ė‹Ēą’>`$ĐÆ@•'Ð'EQ”hŠŠ* \Ū23:―Nj<õpjDëh―ŧuӉoŒũõA”,˄Ųá ƒ­­­]]]`@^ŽãnßūÝÔÔ455ĐHN ÅmEuyĶũÔf•5ntð1ï(ßsðJFúū·†œƒšŠa'`@8ÍuøˆNBC" N4,NæA ôÓĀ–,ú˜ó˜3[rǁMâ[€ÓN…Ŧĸíš •Ž`æb^ (HûŋīšeÎÐT|rHĢęsáņO2vd$øš +ø#ø§ï}>!+āUĀ ōØüXgcVM #ĐøAÔG34ŅsbAjęŽÚ3 ŧSS3JõÏDf5ŲŅŨ;æg t­wJ·lČ.ĐÜ[QRyė”›U ý_õĒðvQyĘ1pĖĢúēx€ïÏC‚mĢ· ýucNmŦĖĐüðþ,IŪĮ—$œ8TÓw‡5 ßLߔšSšwoyqÍé6Ÿ úō‘æ  në 1đū|Ũ–Y3€@Ú#~—0ðÂ-į›čca^>ŧŊčw—ï€â˜%ŽåYJ|Ŋ•æ‡|}z~,||MzÆ ŽŪý~Yö‚ÄfĶũ gaé^ĖOïÞRûõĢŅ<)‘HD’$9°ÁõI]ý…W~úįÃÕĸhŋð·Ŧ—ĸÞqņë“ĩ·ÖžÖZ\,ð|$A#dĀ­[·ÚÚÚ†Á_}Qá?𝝝‚ `ÚD‰čđË ÛkŨܕ>āūč þĨýĒwxū5ŋyã‘ģ‚ĀG–!/=č''d‹Ž,Gl Ūˆ˜Ö\ü0ĄE Aƒūēī!% Ðdģ>X Ë!óØč#‹Ėé]k~ōJj۝Im~>äčÞžöÕ·ķôČz˜õ;##Ž1?+Ä_-ĖMÏDˆāŲ`ˆ ų§GãūŊęāųÓ[JęúG'N ģąQD8Æ% x‚!IކđÃō!ßī#‘īŌę†2øĮ3ëąåƄ°ļļĻîį­]_VÛ·\5;ŌŦÚ> @8Q[Uƒ=åđƒA=6kϚō|^–c§'œ.o8•yÏŲęwóŦN8= |‰8G†ÆĶf(‘X&ĀrĄéЉ)_ˆ Á Û9::1ÍIĀ°0tMø<ïũøØp\+‘s;GFFž °d5ņLŽ ;ÆA‚Ąˆ,7æïïĘÞstˆŅįg ØeÆï p",|>6āe1äsƒ–ÎI7/Ęss‘Óû k[oČŠâũúYpEĢBČ qð‘ļ Ũ§ŽŲ°ĶŠÝ—ęō5ôųÃR„ņĖY.UdI˜žqú2" ū@ˆįŲqįč$|#)b??ô:9ÉÏú Ÿū5—3oî—%-=ÃčĄũ‹ŽMbŋ?}Âáp īȇ$ĩgėt―þęĢ][ŋ-/øëþōo+‹g§E7žÞķ~­ßå%‰ðIHGGGooŊĮãa†ãļP(äõz‡‡‡/]šäũûIJAâ!aqßđU=[Ū„ôHõ·•ģ7ä†ö―ÚÁ] [ž>03 ÁÞā‘įyô`·4ŊĖðæØDXrĖQæsQâÁŪð{cB@[:›đ1LKNÚ°ŅG`}gōß^ŧnCa}ŧĪÉŨ›ßߖúæöĖý3rôîÅúžĒ’‚ŽīÂšĶ Ļ…F>É)=>ÅEœŨ/Vė)LÛūđ°š)āwŸ;õóu[K*~ędzÛNBT~<ęQ]MĨĮσáėn).*"QÕįü|\%)"k’·éx^ÖÉkēĒ‚GQԁ+GķæVßėjŲī~ã;;ēÚnņáļ0†ūîŠœ‚Î`(`BžĀšÏ–§įWîËÏMßē)íBÏĪ0Ýģí5ßÜ\QÛæóL6­Ę-Č۝ĩû|ũ`4"īŸŠČ+ܓ›_|æÓá+ĩûvgf•ee―ýöŽýuŨ$=Üzī:;#=kGIįÍŅß/ïĘ " ŨΝ؞ž_ZÛÜ3ĢĸŲĩĶüœžžÜėē#įÝ!1"‰€H4ęđŨ•]røæx ‰o?–[Õp5Š*œwļŠ,ũúÐč‡ĩ‹‹ Þݖ~ürŸĶK'kŠŽ^žĄDž‡Ëũ^ž>5īŧĻ.­ŧ,ĘáŪĶúâü‚Ėôī=õ^ĸÄáĖÍë6mË+kp…đæC%umwÂaîãßŨü&sw~vNQųąû3Ž8óųÞ=e{Ŧ*33ŌÞŲ™sõóïÖÍ<4p~,#ą’!H†1F―_čΧ77ˆfâ•ý~Ņ'šũ‹Þ §Ļ y}žû'+Ö[Åq…gvũūöÚũâ'~píšGĖÓN\ž  ĨäGR’&Ĩ D­Jy„„%)oĩ4(ŠPĄķQŦ"ĩ•ÂŋR5JDEHA!y„’0ŽãŨÞ}ĖĖÎô\rīšJ Šú ŽfgÎũÍ·Ggg.„Ãāœ‡R&óNCÚķ…ˆ{nĖó⁗ Y­!)ĨD !$›ÍZ–e~—––BB|.YäS‹UŨUXIjƅa…ðĮLŌēŠlÜ&ŒŒs ðah.šRJAÔŦcðĻ5Q\įtfσKHA U Ņ—Õ@o°„ųĪhŦøĻ=GßĒĻ>QLˆÎ€ÂĸĻĖĻTíŽĮ:ĸ>Óyí“ Wo.xöÛY[ &FO_īiËÖÕËæö?öiŸGĻqÅėŲÝLz͎—ū—ŋüϛēīuâÔæĐóW­Y9edžþ‘…›·m]―tN߅ã7úƒ —U*ĪÖŽg^ÚŽ+'Ŋũŧœ€·PIĸZĨåû ˜›Žm yĐÆiSëg-ûņóߜ,Ӟ‰#ýýÓ{~ũ‡ũÏ܄ķéïëįĐqë7m_Ôlœoo'U­ [sĩ-ܰrQŨG‡Þëð—­XĸøŒšc‡ßŧĮHčÜQ%cV­{yéô:'ðâ5ŋŋuįŽs:Oþíbwž‹@UNxņįëgĩŽtûOƒ8ú86fö†MÛ=ÜÜûÏßß>ÜôØSëV.Éw|ÐÞqS(ÅŒKӔ]įöĸņ=ŋß{Ķc°uÎôk>čŧÎé šÆ5ÖÎxōđÍÛ·<3ąâŌåN_„Ä0 ĨBØRäeRŠÐ# Ķ&Ė~bã–-/<ŧ ũÚå{Šbîó'·Í{qÃs5q5$ …žÝqbĸĐĄĨŦ^ŲõÚæ1ôÚ_ž>ŋ{5VûȎ];ÚŠ9üg%ö °ýîÛ?ĢmĢã~_<ԄˆÉĻ[c—FĢHŅWƒ>aĮhĘĒm\Eį8ЖpĢŊ\ŸĒÚ~ðú@ڃŨĮ‚“ôtēū>(Í5uīi ?ŽmĶĩ9QViՍR†otfÛ6ĨbIII&“C6NÃ9 3x ąa€ßō’‘1+ģ3#íęQéúšôČr;“$ņēT•a˜`,ęvq0  ĢéhÝQ"ĪE>œĸÂÓ Õp€>uų^TŸâqĪu~ĐÚӏZžĻŸpßĒéŅVþōúpÁATŽkÍe8:ĪŠÆ6Œ Ð|Üë8wdÏëŧß|į4KĈ€Tiļ+*[fLŽÍðP&l3ô}r+Đ(sïŌđÃŋúeÅã1"ĐTŒnDákf%ÂĪmJ惔6@TØ7āKðX0Žï|Fģ‰dŒZqŠ”ðōū~°ĀũĖĘqKļvãš5óÚęÜĄž™Ū™8sZ‰âF*f™l’tŒŠÐsóŪāŪŨóÖū―‡Oũ4æFĄÏ ŧĩĨĨŌŽãđ!É57—PYŅÐTVEoļū"“&ØDø~ Ļó~zņó‹+oŲųÚŊĸqîӁþ^Ïq.~x`ïū2•ËÆM6ŒPJîÉÜŨ—-_ŧqí SÓVEËä”ĸz9uškŌž9ąÞÎcïüųõÝŋ=zĨ;•NLЈdBj)č„PPJ Ĩ<ČĸëýýŋŲģû̓'h:e„…Ü„)˜ïûLIĄã8~*W7\s|ãρŸ9þ ĘŒī­%ŪĻČ$ϊöŽœÄþŅ­øeý=‰šÁŽÖŨ9˜ŊŧŦĻKĩ>63ûŋˆ‚"E>a€3HÄLnŠÕŠŋŊŊZŸĒ―ðãúŋŨï.―üĩ[ū^:ÂŦEĮ5Óņ“āĻđĶëv&6ĨÕJ&5 ï øI “L&í\Ũ…hš&^;Z𡾙ݕ ‘(OT”§ŠË“•i’ō{‚úĖX“˜ZčDÁĻpož"oš‹ų€·r1VuDqއĻ(baeõcÔ9ĒŽĒÖĮ„Ļļķ"šrŋúHŪ*›VŸ9uōB"ŨVn1eÄÔЍƒï8óŧËW<5?kQIˆ Ĩa`KBÍ0Čŧ.ã‚ÂT€HïNožŦ ŊóÝĢĮ]šbåÓóK +@)°Ô’Á ãŒƒŽ { 9MįšÔ~âãë―Ô4œžkĮNž-ύ)1Cxƒ·ï1Ĩt}ô+RÊpôūĮDhRRðâ[„ĀŌeá@ĀÃDĖŪĘÔ/YņōÎWwþhÉ·,î—Ā…l mvũVũ įÞļte(?bt• Ęw<ŸAa ĶĄ.lH–eŨÏæÕō·ĩĮėōle͔đ‹šmûŦŋXÝԐáLĸÎbc–ÁCÎ|€+UlęėI'ßÚwÖŦųFkõÅ㏝õ°ö' &5'‰’ŠR`JĻßPũíū[í—šÞúäÝCģŋģfų“Qæq"ĄHŽWļe ðĘ0Ąq;[Ūš{îõs·ũÂÕ[™Ķ\ TšyĮó‚€)Š ā‘þøāýƒ,Rîû}!°í1ŋ/"ĸ’om=q]W˜VĐęCÔDNë:`lãaļ6v‘Mq\_Jūabp}ƒņ Đ!f8sŪûÜąûŌ<åĨVĸDŋáS—NķNÃ`ÕMĨތ–ŨY—o­ýĩÆl*æg'Īd<”ūRBŅJīËHCäĸ0?ôäōÃčŧæF›mێãļûâyīrœÍ™éÆĨąï–þYÝøGéđšze}âS·^w•B>ŌĪD)…ŋsf~!öæÍ|ŸQüß[$0M2aXķųðÅô­ōČF<~ũlįõ―đĩóģĸ`˜5ā0Įē,{_ĪJ@Аta> 9DėVĒQÅB #MéŨZÐ#Nm \cCó đÍN’MÖøAæũø1k“ƒ§'ŸïūēŨ,.­Û‰ņŨđBï˜XWϞė,ttôôõ ÃJëŽįBšƒU–ŠGßï,öc°Bß§å ÓŦ­õųŲÅđr&ÎڃžŽöŪâÐð`ïĮ 7ŸŽO]šļý(H“…ÏƎýæhïāÐŲÓý“_*ssėãÓíĮ‹ƒŸ=Þ>4õtûåóâ‰c―gÆ·<ũÆčāÄݧQ<úüĖĐÓ]ýÅS}į.mځ__čđøčÅnšzŨ~;0yï fĩųû#†ėū9ųûģ?LËŊŌï—­DĒLÐЀ#!Fsē*ĸ~å3ðÁt.?’ÓfíKĢŅ@6 Ã00QĻ”S*mOņÍä•ęÔMëņ_"ÛF5ŌLӔV…aˆGü*lccĢZ­!Š" #Â1‚Ð_Ûyþ°|óÎģK_–þXŲ\r|Ës=bj%īĨЄ e:2ÃH!’C|$@ķ4•č§!~AŽ6„dlÂj§ā+ÔN§ņpÔŌÃ^RŦņ“Ņ“$Qā;–žÚKCe›n…‘k;QÖ ã4 m;36†įųqŦ'{(u}D”m5°ïIaƒü(‰ßķßSI “§ü4,9*NRßĩ…Ž<čž―S}‚ ŞâõųåpïU ,ĮƔä‰^GūŊü}ql7Iã PˆbĶØũ‘ëČðhó’―T9čb ã5s|å_Yį~7ŧčāĐ(MCôP~”†ži"Ý Â0<ÓōB?°€ĨÂ4öŅd$‘ŋŧŧëļĘģåÕ[ŽPJyJ5Į€ģ%{ąŒ„™,ž=wUDIāāLQ„a8ðŧá4 l0‰A~ï…ūvTÆĄĒˆ™„.°A—‡sYv Š<Í"č: Óöý(ūr^4Hîþprî mh‹°DԐ#w_%$Œfï…DĩȧĀR$ũ~1oDœė’{ŋēsķȏ@iüPōÃōӆģÕëõŽn†Å1ūû€oA§{{ČfīVŦÁ3icÏð[ķæ·UœĶHFˆSÂ`4ūjc6Ė$N˜üíßŋM’„üB…f hâCØ]BbKËķ“9ĩB†"Kēčl =đZĘœËDZde Đ&<Ðđü°E–ˆÆsxÃFā>ĒĄžeÜÎ,Õž-ĩú. Ž ęQEtēC?Ų—xšØķ§Ŋĸ–8OVŨŦFÃÄĮlY~ ģî[ÂÏÕPsĒý*..…\htæúÕÏ>5,n#ģ6rv OA1ė ‡(]ŅĶķT Š ^Sņ‚M QøRč1äŪâxųGŽĮ2Ų5ĩzÍ~2ûĢ-ėCĒY˜ÝĐbTߟƒîĩ€ÓŸŧÏēo(į;…!Ë/ÂG _ÐÄŊÝŊė)īĖ—TĩČOšmmmázss?œâ'S8a°€6œô@Cād!l-=ЂH Û–ø6A˜#‹Ãr–HkfŌÖZģĢ6jV4pĒI‰ā3Šņ#'j…â›ČåGr é~Ðú@~„^>ŠG?{ËüĀ mé(€ųüÐOØ]ӏ"ÛĻÕË™Ėðƒâmžč@~xöÍę–mŧūm°5ųar.?Ųņ4~$Mģ-ü1 —ķ <”ö"äU ?ųûsx~˜Žņ#ŲýÉåÆ[óCÉå'züðh%"PđüZ.?o―?@h…H[ĨR)•J/J/ðŽVVaŽ,Ŋ†”ņOĐĐá)­”ĘårĨ\‡xP‚l Āā‡ãŊ °3üĀ€€I†“8Oå‡~Úä‡ <8Į&ĶÆäüð1ŪtÎþðžđüĀÐø}wÚþ@rųAB––H2œŪũÛņīø!r†ö°üÐāEhŲKôvüĀ)ü@þ?Ðmsĸ–ûûc~~žFV4OnčÞūā‘›~‰Rį>jųš“°š“Ģķ2UnÂÝŧwóĢšž+~āųIņĢA‰_įG<ĸ=~hgMĸ}qķĘėVø§@ýų!Âó‹Čĸ˜ŸąSĮ4€@Ä.ø·ú#;"Čo­ˆvXÖ, @ĩŠ@ĩŠP-ŋN<öÎ<(Škûã§·Ų˜qXe1â†ĢcLōbÔ$2€,*A &MŒŠŅ$ŠKÄļDD\"‹ŠˆâŪĻ[\ƒ ę  ģē Ėôôŧ=hâ{ŋōUŠ^ý^%•þPýGŸûýž{ŠĐ:ÕšęþÉÁ0aØņø|€O`ĸ/›Ûvįāāø/hųóÂĄŅéôÍŠ†{UčœĀŠĶfæ9*UuÎ֔?l—ŨĐuHôŅh4Z­æ9K:NÓĒŪŦđ‡NīŦū_§jRĢÄ546žŋÎÁÁ 8tõÕ―ÉãüzJœœ]œĨ}ÞÚĩŪÕĻûũvĒ5•eĢý<í{zĪllnų?u-͏l‹xĢ·ÔÞĄ§[/'ą―Ðm…7ôFCË_ussƒRŅ jzÎ:7@āˆÎFųœ™‰ę!0âÃØčWúõXh+ƒ–pūÐN"‘ˆíDށ m1ÓfŽûŽˆXXHØÓ„/ī%B_HY*Jö%Ė™sIaņĐg7æóð›%YaQŸė/Qžø~üįsc"ßöčŒ4ƒr‘Ø–ĮŽ"ðn Ű㠂īģCKb>E Yw<R’Á#IĘ&SÝqÛO ’°Zd$ÁNRBĄ€" ž€­Y$äað‚âŲŲÔ(Ųģb’x"ō)$&ĒÆōcI_ÎÛ'WKšíl Čʂ6€ƒãÖ m‡æqĨÉėúԈÍËW}·>Ģ o݈~šÁé6uΚø   éģÝTīãķv‹Ų@F'h“rorĒ,(hjėŠŌZ’$0œ„N݉Žul02 @+^‹SÖ7ķĻŅ WÝÂÁÁÍjƒfðWC*X“MŅÆ}ÉóŋÝQĪŌjLKvO ^U€Éëī8† œåý: ƒûeį§Ę&ŽÝ_  ~ØüĻQÓŌ û$b°—Ôl!Ī<Į(^·…ĶáY0œ mk8ö{”Ąŧ”ĩā~!úū6ÆÓÃŪ­―TĄąX‰nĄÓã‡öņōękû_NŸ<ØÛÛÕÕ˜ŪîVÚ*vũ™úqˆ—ũ€q1,†6mģķŲ„ ?‘`|õô4w˜UęVģšy.oÏN―9ĀÕÃŲQ―mzúą0æûÏ"§.ÜŽ4ZLæōf#ƒmáõŒY27hė1û@īĨíđ0Ā04!t+›&…‡kÆūûž,5įį.†Āđ 7Ŧå° ŽũóÅŠÔŽä8sõýúNÛŊĖíåI˒7gįüåę•ïBuYŽĀ‚Ą‹Ī,f<}’ūߘđŧøņDŒfŠz ņ…ė§Ø^ŠŌÛô|ŸÂ~ۓÁ<ž|}yĖíüž"9ÆŠ„ĄHÄ'1šķ0Ž…čēbčĖFsgÐv<›Į·Ðfôƒ$ féė>ԙgūÉŀA:’Āt Ų­Bw ÔwPæ6s§•ąP8Î0ČHâ3JÔíFa`ådÔüo6Ĩdž-đ\˜ĩޕgͭŠ `žŠŧaØþzE(ā1˜`üž”ŸÎ^óšâæÅ_Ž8'W°ųĸÖpp­–#LÍ·ķĪfæįŸB‡ēĘo=D1ąXčõÂP'ļ[VvíNM'mšwįú Åooĩ4ęēCߌčPũāQiđÂbnŋ§ėŨĮũ>―āčÆ-›3ē._.Ę+žÔJ“RRˆ<Įrs/–Wwþôݓvð ëg‹•'Ð4mßkāĻW^ĶóŌđFoÕ7UU^—š0VŒ,ĸfĩš;Mp13ë„ünG›áüޜZĢxüīøIC1ŦđĢĩƒŪÕr_ X[ë–,ž7-2,8drōÎS/―ũŅō' 1)wįcių’YŅÁÁ!ŅąŸœ―Õ@8Ãāá."iįAÁŧ3ŨøÛk—΍…D͜sôŠēāäė­Ŧ†ũŽNZ;yrøŒõųtwޏÝËþxÆŌ…ßĨãĀÂXMŒč―ĻČ5sû‰š6-‰ ›ēhe†ĒžöulՉĖ0ŲĪ9+ŽŠ\˜ēnšnåc8†1@Û_­ Hø"… "ų`zHĖ6ĐĀ-zíö‹§DÎ9§r™ątÍ;Ã=ûÎJ_1Lq&>L65>ŅexhFچ@O~—…œūíe–Í ÆXx.S>[õuĖ„ۗ…O‹Y˜tČHÛ ï~áežˆqĢŧĖÆFrXģ3ne–ēÍ\’›ÉÚĒTHc,zËßÃjĄƒƒûáïFÝĪž!/―PrÉyáJi­ĒIŊÓi4Z―^WĸOöÍ^ĮM â]Ī”)Ē4‘RĪą”.ČĨ9é€l#ŒÍė#` ˜ŊåCéŽbe%}īŋjX†™ĸ6Ð,>Õ ‘eÍÜŲiV€•ūį:nPÔ ā]ßDGWŨ‰hĶåÄi Þ Ï†û-!ŠĒč;?Ž8gĄŧUUuk{7ŋ‚%Ļ_ž*?~{øú(ëŲ;õÃKjēĒj++>ģŪå urðž7É+°*:PęóŠ:ð) *ô]šþžxûæÃ§/ŠgčęŌĪcÃ8XāXD’‰ĶOYŨ·`(Ԑ:û É9Į9(ĨQšąŅÝÖyē1–’"éëëĮÕó)+8fæĄāĮũ―NTÃ> ó$ĄoŽī§'imÚÐ\Wâ‚| đ0`~cäšü[ĸÅ00]›ÛpŊ|Ú>É&ÉģLô4žï’åâýëWï>>žī?ŧ›Ý°;ģŨ+ģ.Ė6ũóÄĖ{ņŠüoŸŒ2þÅÞŽFSqžgššgv'n ‡/—Ü?ČĻ/Ēød"Þs ((>E âŲÓ"Idw§ŧĮßtŧnð FXĄþŧÕ=UĸŠéKÉ··77·ß<þú_aÎd2ԚLë—ßŅËÚ8k2ԚL&“ÉPk2™LĸK‰3ĪĶir&“éTõOĸ\ūüÝũyßũ"2ՅÔgKÝŠ+ Ņ_ØÔā0ք}ēšïïã}atĐĄîŋęĻÕZį'Ō@Očpā}|”ðúYÐŦPįƒîGÎuĄ›{~cJÛÍæð‹cņ§Į[“É ëRĘã8ūj‹ÅŨ_}ųãݝˆ—KÎmÛæœž^§ÉąôޗŠđĶĀ•RB)įRēīŌī͘Fßzpá}Ëd˜Đx!}NNImŅn·ÃiŠû$+wtGÛåœŲĄ#KŲÔXsHĶ#ÃHSÉxģĐÎę@[œI`éóNDX0ndâĀ@ÜĀŦ­ËT‚í›į”œö'€3oäS[а›ļ]QÏtÔ({ü\ÚĻ:ģš0y~yþø“O?ûü‹Ífó'gųuĨ‡‡Ÿį™M&Ó))į|}ýaĩúhÓŋE­ũþ§ûûūĸn8@ ˆķ3eŠ #XÓbˆøq·]ŨÃ,@CvŒ#˜ Č4•YpŌ$"8ïķ^!#M ĩÚ4‘І1vð$īĨÄ YɘFĘģƒ+ÝÜÚÁ\ÚĮ.Ķ1qOAÄÜ―ĪJjBe‰ž)„TóŌ øū96Šïð˜"R9ū6·l’*Uá"Ž2ßd[įiĒjÕnJðu―ŠŌÏŅÎģ1§™YFXgėų@*k0ŦÞ"Ï9~ö=OGV–ŸSõFŪÕĘNĶ{ß5 ÚŽS?” V%ĩ>LVK Ā>›$ ņsČŠÍĘNØÝdh­ôGØZ ėû&ĐdūP%čãÎŲ{+)„;:ÏFķĻ*­ãN`5 !%Ķ+ZË d7}+#Î؟ĄY&ųū-€ïBĐáïHxRíoÔĢ'ÕVģÚh€ÐĐnÆåK ]ļ{Ōe™îffŊėÍŠĪēÖ2d†â§\%Y(RkԜ`p°ĐŪëē"—ZķÁĨTŨķjjēgŋ!oˆĖĻAJ?MZ‘1ŊfÖ7s­WƒÝ37Ģ2*ŲyüĻ ĐĐķ'›—€ĪûIdáCTüZkN.)Ķk°Ā›B#22T™•=N\Š*5Ÿ§Œã͔5Ŧr‚-ÏxjŋQŦEÛÍļ›™}ĘšÕAęŦýKJĻ\kĨ‡Ÿ†SÆ[$1íŨ5+Ќ4ęŌå~üœïz–ŧŸ‘Ėûū3c]W‰L5õZ—”ā§ņšQ[ÝØu™ 9ˆv™üT šöf–%éý`XĄ€’ŅŲÖTŧ |*sĒk[ķŪËP%P*'™J%‰q@”J Ü! ĩ_p*ųęÚÃūïQcþŽiĩÏ›){ŸŠTPĪ*SĐōčŅ/ÔÃj%%Û #ĢŠÆ€'NN9tü·DöÞY5–TuŠēm™S}õȂ<ám|čý…ČJÚÞzŲ59NÝSĩŒÏ <"T1m1ūôˆXkEdVŠĐĐöKJ3…jŨz<\ÕėDTÕOxwIQ%&kũÍô·"|š#aĀÚVû_Ũ*Đpũt"ŋūþpÏ6ņÓ'SÕÔ<ÜLŨĩ<âė%ɒG~ĄVKąuãT,3ÝÏLī*žJæßm)é Ų=L†=įbk•ĪïPęZëô ÖĩÎņŠšŪ‹‚{o[‹Šá'2–v†yŲäwk7XĨĘũé_|‘,T­îųâ-ðp˜.Uöä j:ŽLŌĶ ‘RËĖÛÂŊĩDéûd‰*ĨŠ}{0qĪĪЎïO”þšUwđ2#ĻüēuÞ' ģ5{„‚čM9…ōøÎŽžĀ­ýNņųYo‡˜þ™HFXËĻĻ*kī=ŋu5áYÞĨšû―ŋA^ŊŨqũÖžĶ,œUG~ŸV•ëZ=ôŋA\ëjŸ *T5&ÏķËųÞaŧĖ>ÛÃgLÝũZfá!‰Ę|Į@‘˰e%•™"XŨ+ģöđļ^_ū=3@BéÝūĒj›ZÆāÎö/3.DeNßŦÓąĻšˆxƒÛķ_ĐęĻUefŠ* ~"""Žwü4$]Ĩ:é\ —' €™6h.[—TEļ4Cð~§S"ūïï)Ĩ•Č4‹ģJ ģĶ:ī"8Žķē”\ϗxýN=zX­’R‘2ģ̇UĨjY9Áڈ3Ë ė―Ŧá#~ęý_ŨũCē(ËÖũū!TÓ>ŲĨĪ*!,IŠ.ĩã{|֖…G‰dĨBōū^ējւđlß;šB@rPĀČ ?dœâqL§M2sŽø2J*ãŊË^ Ú[АĸBTōŨû˜G üý!s•ĸî,RGó„ýŧĸ›ņyƒsšü·šŠŅïēÚÓëýÃ^―Y‰ę,§j“æf̟ä}ßĮG"<ÂČũEĻBgŧŽJĐU2ÜPU“”5ósaöiŽĩH­,ëÖū—Šjk5ɈOvpŠūÎŲΟ4Ĩšu˜·@˜iDTĪ™RuŸ™Ī3m>p2‹$1|VÚŋlû† ó'5ïs2Ģ $ïŽĨúã˙ &Ūų‰Đ:HášŪȘÏv֚EðwôKå?Øû)Šåï{9qųāČ9gœA@Qr$YE@ 3&Q”$YÉ9ĮËyw'tũ·]―œ§ūŋïųéãQž0ĖÎÎÎîÝÕTWýBúÕûũï?zęœIųoŊĻąïÛMŪđDKüŪA@u ý:ņy‰wO=)[7mđæB þo͐Bšã?ļe)ðþ0æ^7ĘŽ\Ïŋ–eÔßMΘ™ĮŋßtâBaî=ßl:ŸiýÎw‡ÓŽīĪkŨŪ^―v--+‹ú€üŸs%ÏÝ―eÓđtóŋkĘo.†ÅĐ™Ęĸ•’eÔmĐ'{Ũ†Í—rĻ{uËæíYÖo,˜ 3ßoŲ}4YUČĸŪãü9ãLwˆŽŠe™:*[“RĀE–iD„؆ý*Č` BųŽ3Ių—Đc,ZœˆĐš 5Ž)Ą]’V+ÛÄ EßĶ+h”ŲōåËÁW’_x ksF.  .ĀķųÅŊeˆ#āsŅ|ði{sä“hĀēŠG"ļå“ĩU,ЁīP`Ķ‘ˆĢHč.šÕ Xs0ų "HĪ3* y‰Yö}t á:}høøþŊšwï6dø ‡Ÿēãl–ĶŠĀvÎĮÓĮŊ:™uũ_TL++ųzZ6GļĀ“YÚõ+ĐđBÉĖÎ=ŋ`Â䓙\ýoŽ; qÜļ™”kˆ.Нt?ĖžŒkÉiŋK>ÆĸxƘåëöqEE<3õfFŪüÛĄr7ž=síwÉ:MgęĪm7Íß~w0fž”%/ôøÂ”iÆö}īũĪYŦŊĨÛĸ·Ēg,ŸüÂWr•ŧ?‘ģôÔΌ<#ĸRąŠĄôĢ#ŸŸũãųž?Ė}œY)7ŊįyØoîdbi˜quÅīÉŧR˜•|äĩg&ÛŋŸ’Ą†ģŋœ=bÚō―ŠĶâĸT Ŝ"%ļT@\ųŧa­-Ō“ĻāļĖ_rÐ/ûĄRÐKL@ÁE•c_3Ôöõ:.é°RėՖí]ž dFĐr+)šÃáđēIj™Ö-mr"ëDŅ€t)S*ČįZē@ģ KD:TóӟBÜdûÃŲ)ԝ?C“ēa@‡ãĒS TūxČTU5ŲēČũ†"^’JïdČ!}û@ĒĒ˜ `ÃRč Ék™ýϚoĻ>Ē;ȏ/3tč°æMę6l;gõaĪ;xÖÕE#û7iŅšÅÃ]ßŲxNq8O|1ïÅ)Ó&ūðėĩkó­:ėë'æŒíÔēMógĮ,đæBy—~xiō 3^ĸ@ƒÚ?ŋ$ÕÅ~Þ―þƒ5ë&<ÛkęŠï“n}ŪÃC­Ûīšēôv@ƒ„˜Yįßyú{.îÚuօ<|ųčÖOīmÕĶe·§Gî―œ•Ÿm5üîŦ―‡Ŋ8tūþå)ã'ū0úІĩšô\đó’C'{ŋœßáÁæ­|ėģÉîëŧ§/ú|þäONx/=åÂóOvkÕĶy뇆ūâR5‚Ī1’AŋālTĒx™ŌŠt0qÞČ'–ŋsÁÍ/þüõŽm[5o=áÝí&qX'>ŅĢY›6―ŸvÃt(4{õžqĩiÓĻũˆ]—rÅM~O0ÝģnqÏĶ­wėýÖÎóšŪŸĸyÓĀލ›ķhŲäĐWūûþ›YKūxmBĸ~ß7|c^…å$­ý~Ũ ‹gúnÆä Ó§iРæSĢVĶšFÓ>œ3Žu‹6t,•ßũņĘ/7Í{ôá…k~ļyâŧÞ·kÕĪQ§ ËSME%–·â˂ mĪš9ī_ë6ÍûO[–lbÐŸÍïXŊņ#Ïôũu*ō#ĸcÄ\ŒUŠ”ņ–LYYozwBÆ*]spMUåŠÞ†ŒEŒ/;K„€JĐßĘØ/•&9] šR)č%ÍÄd)1Đ€@@H–ä†qĻ}-iŒ(ÉlN§(œôšdđÄ4+Î/6!ĸBÁ !(^ԖŊũ JČ/y_ī/ ‡J<ŽĖđÔķåĨJóoę‡6·)WķĘoepŲáÅŠ_É@Μō§•Š) iĸÐėĮUM;?ąüģ­6ŅNũÎȗwŽ{ë‹į œ7õåtŨÐS|wäâFīvzމ“ÞōÐėéOõߛU歏>y{éÓ*ToÞŪuŧķÝgNy(ˆÛÐa‰ĩZ6ŪXúÉįĶ&ąėėëWÝ›þúžb'>þähvځũFŋy`ėGk_Ž—5qԊE%råÉŌ^|ēĸž o­þtՊįŠh7Ϝt6ŪĮš/?ŽnČsC_O3Q^Ō™/7ėlŊxúŲá‹R<>Qoœ9úóđë)Ŧiį^óųķÏū9žBÎĮë·1#}ނĨÅøųįoķ.äŒ,Ũ­fĐv―^˜5ī̆īįÆūüõúUÕņÚOŨbšþ/~mËÅ:GÕĻŠíė cGÎė:þģåÃ7ŋ1gˉĪËŧŨ/=éœôÖįKgN Óø‰Í‹'Ŋū°ð‹uƒK]?õKӉHīÏđŊOzŊĮ›ŦõŠž;eÁÍīsãFŽý)Ļû{ķjl·ęe*=R­äCO˜>ø!'â\–­vōá―‡ģsĒék>XĩĮŽūüõá'>ĸpũÉ ŨĩïæÏßú؄åŦÏ,„ãĘ>ÐūZŅ~Ŋ.ęŅē",2eŅûŸ/ŸâÜžę‡Ŧ.]U~Õ%ĀŪw&ú*ŧÖšĩŦÔ/ޘ―îž}uóĀIŸv}}Õ#ŸHˆ!ÜæĸSĐCQ`ę“Ŋķ,_Ŋėg,E„ `|§ +0aQū[ĶeIĸBHÖ ûDÁ…ÔĄ/u0Ā 92’eŽ “^a üâāH”Š4gy~GBUË —äËzĶiČéaƒR8§LVÍē―ÎäĐ%õ@ÁâŽoVéҐé•KB—,?o€Å̌™ĶĐŠ*č0PÃ4ĄœÛr&ņūÆHþuBsŪIĄô'C$Äb-š}īaã˜!Ŋîī`ížŦ™7Og]˜3āņŨ>چˆnÚ6ô‘ųĄm_ä\ŋ0―ï؟§ŅžŽž”}Ü|ė…įŦ&Æ-YŠPHĄØ˜ˆč˜ØÄÂąâpÄAŅÁEŠ•ˆ‹*Ä,S+Vaôä)u*•/YBWqÂėkį§=Ũ{îÖĩÜ,ÛWĀóœ›? ŧũ ÏW)]ĒLizýØá“éO>Ö%&"ķ{Ũ.!§ÍtŧlŦÝsš7Ž^§Ã€Ņ–ŠėN3mškYíŸßąnÕ―z&–=čøđŸoš:ïSĄpdõ6= ŋtüZ&sەšš7°mÅēU‚‚=یôýŪŽÔCŸ=ÝŦĸs)”Ëå‰jÐyþ‹jUŠEē]y…ІĮÆFÅŽŽß·WÝË_=Ų{Ā·'RuM~ø\Ņüã GGF*Q2>ũÂĄ‹Ū˜~=;EGÄ |Ē“ßąŸÎgˆdŲv§!/>ŅļfŲ QÁþķĄ†=ÕëŅ=ïūúÄā‰g2-- :ĄtÉÐȸĘPĸeý‡ {?6qÏÅ<“ert{Ã$Joß =XęcŽÍ䋇ož?ŋí­—ú[róĒ–á.\ŊeįŦúöœąþĻŠŲ‡ŋû"óęÉĄ―[ö­ĮūžåRuåčŪ/3Ŋ]_4ęéņ+N{ŪóÓ'~žrÜō€'Ę$ƖĐX:"ēp\Đ⡑q‰ąaŋF h‚äōÄ5ë>Â5ËW‹ŒäYđY~ņ{v)īhü“Ģg|Ky@dLLIĸļ"%ĢÂBÖõ7g ~rú›g°ęOnC4ЌŸū;qéðg}z üîjzęĪcÛÖ8JĩęÖĪBŅĘm{Õ)„ĸ­TË!qØšQPŲ ”>†V”h ÉÅ/ã’~*ZۜrC$ ‹H0Ėö9·]øĀĪ$”аad‰%p FCØp{D.VU*.įúõHNdd!^ŠZ™—ß~íģTý2EbŋÄķOŽ~sÕŠý—wĻĨ†—xý‹ĩoëšqÚØg-^>,ūÁˋ–}šîƒuïõũ3=TÜ5QTB -ĻôāisV}øîÞ]ģŠMÐÃr~šx™#ÂM1Š5mïĨf)ýęõ—-Ž ‡Æ-d[ĨĒū jäÓģÖ­}wbÎöYK>ڏœJNV^Ū !óōށýpéį^›0ļL(7=ƒ_ -$2°Z‹ĮÞXþΎã?-|ĶŪ#(Āļt--Ũ63ϟžœ‡”ĸ1°—Āļ2[’ũ…ē `ž`h.Tg  ōŽĒŠĸŚ8ZRN…‹Ē"’5—˜€_ q5ęYĄ/)3(ĨēĨĘ!Éđ‚æ‚ėübӀēZUxíHy0$™D:ß`ā&(š…Ī؆Ž*`žnõ‘1&ēꄖ+#·\p0’Q(Ô%Ņ’ö\NŪDYŽŋ$ÚQB2ĀŅ_uõ'ˆķPž‹YšJÄĩŲpŦ\Â\Ö třĸ4žŧRV/˜0tÜī93'}ąĸb›æĩë5yīc„gþ+óß}ũíŋX›Ë4jļ܆YķÕ5Š^Ÿ7eþ‡,{ՆôĀ"#zpûīAÃ&Lð‚ģY,>!~ëįo/Xųu.†°@ũ9  ]:gÖgß@šÂÜn@þ0Ó#NXū͓U‹\ņžðƒũ—ŊzoKķœa1›úÖū͖ÉęĮž~]/ņPũFïū1qÖŦ3‡OŊTŸÞĨBœÔðPéíl|g9·\Øf…莕‹įŸ>{øĻŲQõ;W*žø`ëGÎ~ąx܌W‡œQēGӒ†éĘs{8<͕gåéÏuícoýpÁ’·Þzsþ–Ģãn—åļĮM=6U‚â*ÓÖ­˜ũҚŸwžũæËŊŊØ{*ĐhBáP?•qy&\(:þäþoĶÏz?#Ī|įŽ…Wž6ņĨWg {mgų~―K‡jŒ#ĖãTŒ8ĩmHÆôļ,ę`™+ߜŋā/.dōÂņņNÍQĄjĨCëߜģxŧâÐŌNė}ïí7NžļūïÛ-gŪfQ͘âírÃíĒ\ą’Ôéáݗ ‡Ķäãa=)§WΝ8á…ŅÏõzâ;ģÔžĐO'ŪōHŊęW,zëÝũ–,Xu2%ûÚÁÍģĶŋöí'üÂbœUzēdČąŨæ,ûā―7ßĸx‡Đ(Üíē ĢHÝ:—LûáGo/^ī:/Ēr·žõ^{qø˜I/Ž~éýKđZ•jŽ]6ûÝŋÕsGÄíá6ÔÏ<ņaŠ,ėv‹*)óâũsĶOýôÛïÝZĄÄ˜p= 4ÂÁ–N|aĮéĖ°ÐˆŸvŊë“oļ˜ōÎWÛR=Üōļl?Ū<›DõßĮĩwŲ‚åï――lŲ{ÛN%ÖéZŪОį;ić/š†îÅPƌƒn ]Ũ7mÜxöôi?§cTęS1é+–Ē@$ģĐĶÃŽ#éV t/‘[tåC‰Á|üÉ9ϟ#I%C° G (Ū[@*Sn5|–֐”A&{pģĪ!yi°ģTM•Đ_Údm‰†ÆēĀ”zcÔpŲ€wåAËØf1€æƒa‰VŽČ§JpæpčÐÐ@$xd)-—Ũ úđp%\W•RžĒIŨĖ8>ŪĘ ģ ―ŽdĨ/ŪY~ĪUĻXĐqÓf–iæþ2225M ýCÏ8Ēę~~NÛíázx›Gûwi\ÃÓčáÆØƒÔ€Ē%ʔ,V4ąt•JĨŠFDíÐĒa1LâWŽd…’‰1åš5ŦW+Ö2•č"e*”-^Žl…’ŅAš3ŽTéÂR“q­RÝڅ$8"ūD‰bå+W/U<ÁĄĐ…KWŦTš˜ũ„[6'ô/VŠBéâQ*‚LLq™æÍëֈą-5&ąt… ĨŦÕx D„ÃåF՚wßŧĨÆXxlą ʄų‡Ä­SģRœ·O_ŧvē Gvl`áÅëVHŒ.ŨdÄĀnĄ Š,Sđi•čÜOtŲĶCGũw2ĸ˜UŠTփbŠÖ­[&1šxÝúÍZ•4]f@ht…ōâ⠗-_ąx\„Ķû•ĐZĢzĨbAÕŦŨŠðð-^ądĻËíņ/Zi`ĸĮĘGųŲTj&̰øŠG+\/YĄBģFM‹F8ÜÜīkŋŅÝč2-Wē\åŠCýžUŠV tŖŠRđJ|T8·Ü†Į.U―uŋnm‚U_ēJ‘°PŪÆīéÔūxdĻVäąáЇĮ‹ŧzųR !AEĘT+]žH€HŅēu˖.â§ųpÖXs+]16"","šBý–Ģ' ŊįgZJ―ÍŠ ÉöXQq%*T,ātįåĒĀĻG hV͐Rīc‹zĖ“ôĀežũĐØ’åŦ–)•čÝĶEģX§íâzBbŲŌeJ4iÔĪiąЅK•+WšHŲōÕBC°UūBŒ€@Zūb…ēÅ …E—ŊPąXlļæ(W―fÕōÅ‚Ėp™,Ļaįū›WQ°ģ\ÝAftąj­Úķ `1eéÕ2,0ĪDŅbe+Ö(UīppPXųę5‹$Äė­ŨĻF—+Ïû*UĄ\Éš>P?ŲÅę<<āņîMkVŠ õûĮōÔ !ééé!Ŋ9ųĸIҧĨĨĄÛ" `ėĻŋŲ žQ۔˂Eąhŧ‚=ļčHï[ęVB+€ë‚Ū4Vī-Ms°[ې™mZ2#ÐīÕ@âVRė d &ŠÚWHb ÛÐĩðɍ Ī-ˆ%b°&à}mTAv°™ÍDâÃN@ 9ä}YuŠk†1k@K"ī0Qå!*ĨķLvr€&LTŸf.$s,­ÉāMÔãK}Aló”0Ð/–C–ëÐîՒÄÃðtéÖíÅĐ3rss‘ŅÜ8wî‚7-šø/˜“cMŨ,OĖĨ*đhqËâˆ3Ã0U݉ĻaQNTí֘‚‹ËÞ4Fū'bÅ!nÔ4,Ž|!ŸÂĻИԝšmxĮšÃ,Ãb·݊_Ÿ™!âtčē-.ČÜB„H'\ –@†Ķ‰æP1"æGs& n6õéķ.fš6…Ä+*p6[člp"z7˰lLT‡NLqWÊîāTj™6Į: o'§FáYðĐÎ,КüĀéP~@ƒ^čļ{āÓphō3ä‚Öý °Đü "ęq=‚] gķMCŧˆŠëŠ0o2‘&6l™&V4,z1Hs8˜åĄœ8âãÍg @ēu(Č–iPÆ}Ÿ­C'·v2Ž84Á›1LQë(ī”] A―'að\,:^*†C ÉąxEųOáþGäĢķáąų/Ÿ*…Y XüÁS4jš6‰šĐ0+?öXWÍ6EüØ1UŨ™čc(šCĩ<—?ąÄũí4l*ŋ/ˆ‰Ï 1˰č?؜üĖ™ģœó"ELÓúĪÚqĢG~õå:BnÕģXrUEßV|ϊjQ q„!Ģ0€ßfe”Ér.@ý8 ÍTÓ2Eį#đį€1Ģy_ž Č[íWYHÂ,MáLVÖ ï‹Ðā61b>ýCŸŽĒpþ`2J"ĨА—•e)MÃīĻ7h~Q1(Ģâę1’h‰vÛ0ļcŠĶɞ€‚‰ĒHđ^&{ÄuRŪJ;Hų ˆĖO$n<€ũÕąfZĶlF빖Óå‘ŪSgĖšKŠý_ĒžēôŨÜZHLD0ūŊÁs?î…T{ũ^­Ėˆû(Šē?IDŅ€%gž^äXIæ/ÄąōÞrķä1 ‰fgœŠRTó†j›ĩĐ\°Ëq‚1ģĐ(Lôŋ k `ņŪĀäFÔ§ Q9ð\amNLS€ãeZį Xd ąĨ8ƒ*^N.ƁÚK™h‡REAĀõ‹Ö đļÄHø$z)å*ÜLÛR ÝëŠÝ™KĄÎ9žKŸÐŒH RgFĀ“ĀΰĀßCûŒ!ļh7øĐŽƒî‡Ôü ML(ôËģãĸ3„'ūŧā|ýĮâ~Ü7'—Þ·Šf‚›€ī.Į°Ą\eLĪ!ŲūĪ”_'*āĒZ $˜ãCŸ’ėJ0S †% €XbCž5 ?0-Ãmx€–ÅÜn·Į0„.ĩÝŪ<ĮMS’įrQfŒ ð Ë ”•ĮcĶ„^y·e›Āķ,—ĮmˆU$óļÝ ėÃxyƒĸÛÅ\ĖņlðŨŊX J_tUjãJüƒP{PäpcĘđ4°A>…øDģDÔé’Hf3‹Š%‘8ĀÖa‰Å’^МAð**!bĸ=R<áE n?ÚSĸ§<‹,wnzF.Eø_æQ~—ˆžtjį–g•œÚķyûéԂOC[+ïÆæ[3LüŸ™“ߏû"Š !€ŧZĒ7‹|Ĩ(§6ũCp—‘ýYĀW.ØĄæ]“2b\ŦsĐ>KÄČČCҜ~Ņ11ŌNFō‡DvËNQ’#p ļ‘ Ōē-y ûšĀū&ĐÅĀð3B:'"āÝzܞôÔdfS.•ÎÅĖg Îd!,-#DMÁXLJŧ˜SęŦâm†āUЎ‘Ý1$UĻ–fXBĄÆét2qR ĩ2 ÛRĪ‚!bÄĪ Ï=WžĶÝž†ýÂÃuv‡ú”SÏõé~…bƒ…üïŋģĶSNėúô―ïÍáEbƒōŧeeOvZĶIĒ#B~ó’XŅ.ė^4}}ûķÍËí^0u}û9-ËGQæĢ;f§Ý0qPĄ°OÆĐų“§ÍØÐ"Æ(8ĸf܏ûĐV…\f[LÓĐ/#ĻPpˆ|Gˆ$2Ļr9šŪ ī,M9˜ÓaFm*åļd6‘tą `§āāāΏtóŽ’―MaÆčÜwðþ ÁaÎô‡ĐŠzöėŲŨæĖūqýŠŠkRßZŌ+ĖBXĖ^ W+ōūŪčr(Šô[^7Ēđ ÜĒÝ)b?8 ΆEN‘6 ·4\‰n ļ͜žI·1Ųũ @cûČņ‰É†Å8‚‰ˆÂĻ AO‘)šÞ–Įīp@€Ÿā\K§ÎdŽ;ļs߇)†iˆ(ZCîģ-ҌÖį’ęï1-EØ$8DÜŅD߆ˆ~5ÍI[4hļ9dΌ†ąâ6ʙhlÁ‡™/sāÎ<5qĜÞóV5Ž`=ĖĐaXX\ī|ŅßýŪûķ0&\Ė”$œÅVlØ-–a›ņ_=„Ģ>JAŪ9đéÕY_ų/[11pŌ–mƒö§@đ*Ž0-Æ!ä—Ļw(ųļWĒá /ŒþķŲ°·šUÅD q:{ W †Ï>. °[vũĒÄ°ęÐUË2(ÃÞĮømĨúýļŸjÞ@j_‰55Gū–+,žĨé ` §LhĶI|.ßķŽ4Ą‹)S*,Ĩa?Ų=ģAŽ ”a˖+ïÁ>|ĻS§Nâĸb”†ŸŸ_›ví?úā]j 9 °?uŦO^VÞHč—"]ŅdóŽ‚ #`đDuŊĐ O”č 1p•Bf"ÏJĐ3q„t~_Uh6r’dé&ûĒŅōïHÕēĖŦoϝķdÓ?5fø+ Z–HžøÂÔýįŌ5Rã…yƒÚTIüúWūđäw姍ŌĖ>ƒ§}ēlÝŲ”fƒ§ŋúôƒ7~XũúëkHÎÍ-Ūn5`åÔ§ŽŦoŋ>å―oN2Uytä+Ū{}ï npF]]ŋõF™#ޜø˜’}~ÅŽií=é(ĸāÜ)#*…æž?cܙ€RķŽKΉ›úÆōōYkÞüzŦãDŸ ĢuŠüöī‰ï8Wlڂ•UÂđŰĶ_ΛúŲĶ-{z š=kbË ø­y“>Øxškj‘Ŋ<ÛŪ&†Š_SØî/ÞûōpČôĐÝrŽŧäƒŊ; Ÿëâ‹EîŅÕã_mKiöÜKӞn‘uųįmûÍâU+&ïþâÕß;Ôc^@gģþ/O{ŠYîų-ÃFÏš’j”ė4õ­gĒf-XýõWĘĖpðƒ™Kū>hŧCžžüęģˋÜĘ|ˆ}Š|A4GÆŅuK6n<šåܘģO>ŨĢǚ›þÁË}~ØvUzâÝ9CâõėĖ\ņÅÞŒĻŠ/ϚŅēLĀ7sGmũD^<ļõÐQĮčéOn[ý΁ÃGúN^=Ī{-fĸŠūũS-֓*۔·ä‹ļH"8 €€kfŽĀþ ú— ÔŠ€§ MĪČÎ*˜ˆĒļXņ•+Wžkß[RgŠ*þÓ"ŠÕ^·|öž5W^ĸðà aëÖÜÁýODvøüË[į2tL…o?Í9ûÃęU9 Vūâųiá !ƒĶ-y{JĘæđŸžÚŊs'ïÝēđÃëËފĖþÔÔOšÔ.|eųK_›ëŨŽËþá­§ĶūPūôšŌfúöõëÎ^öFÝóSæŋs|Ā#ÉĖ\vHĸvÝ'‹vŸōZųÏ_izrßgïļ:/ŸóÚŪ—ž[šð›æĩxļę›C^~š}…äÝïŋöņąY[ūljÛþ>u ÛVëuëÛ`ãÍî3GĩŽōÕÂaģŋå_­ų2mįēg͌/Süã僠Ä“Ūžúų\”ølóēNž:CąÓ•üõg_ķ›ųÚĒÚĮĮ|žædŨfJÚõcgs(ņ“īáģ/ÛÏzmaícc?þütįÖŋs=Ļú;+'éđyķPŸFÎzâæÏTÖ;%9åâųsðžqÍ § *ūÕ―ĪHBĪ͌.XžĒ}Ž@ˆĩ!Lĸ0&Tŋ tWĪeŽïŪÃĪĪĪ\ŋÃŲ|T•2ΠĮčŸQDvgę<û\Ŧę%9å4}ßîVų%ýâÃ#zīÏ'ßNúélŠĐ;›<5üŅ6uŋ―öu­ƒ‡=ŌæÄĶ‹‰ä2B(Ïí.RŦé“=ŒFŲu{į‡#{/üļŋa—y• ĄāNÞÚðóņKąĄf‘šMĮ>ÓÁïČúÄby2íސv2ōÉĮú%_tqdÖSX™~Ģf›Úû‘î―GĖč[86Ą\ŋïE‹Į—ÏîžôĘR–~ƒá$|–·‡ŸúŠ)_ĪHLxÚyÓŋlĨqßŦD.–(Ū)ØþųŧĩYWR―šî4‹úįšf$ļÓÐ)ÝëUßsŠBuÚėĐŪõ/î~HýâgÉđTļ„üÉļũĮb0tʗ4žĨð‚MČM ,€mHI 7č›|HkB°W Ŧ†aPŠ`ĘÂķ|3‘q" EzŧīĄÄÄÄ 6Lœ81<<œĸ5PJ诊(_ū|```HhHūũŒęÃĖ" Η!b؂9ĘN'ÐGME•\ččĻČʗˆûÛž%Bæ“Ó}ė2éÜ#ō,b`Ÿƒ…‹Ôũú·ô9=Ôp騅,…ŦĖœÁĶš‘†PBú•Ë)ŲŽˆ0ĸ,ĖŨËĀfÖĻč­[Æ-„SŪÛãēēÓŪ_ēŠ=X:ėFäÁã'j`e'_ĖČN ö‡‡[)‚åtÅ/,šL\ųz ߨ`ž—­bė'ڛ–7ÖēssórÓÅ‹ĻĄ‰Ã—ūĸčÏ_=ÖsÂä"e—=RÚãąEak™đ› š ˜čČĢâEëŲ7/ef ô# 0F›))Y)g'vï=uNņSEV039"ķE˜FÃ} ]Ģü‡8ĨQeš}úEí=ŸÏ0apýŧ 2=v Fčڏïŋ°h͛~‘ējØī īÅŲïƒq8ó˜îäd·ls,Ô2,jRĘŪF._úåÅÓâœ:&Š?3FbŪ ú søīáGe§^ËâAqūŸóûq?ÕBúdRhFĘqAē°D8ðŽ Ó”R0FbŠ"ëYHŊ:4mЁ ]æ#‰ų$Il\|bŅĒ–e*TČétÞžyóƍčŊ JĐjðx<ۜėĪŨ$aŨûšāī`šŽ˜™č`āë ΒO•FV/‘FAŪWÆŪĨ@@ņËō}Ėôē9â†iŠãĀ'Bô ˆĀHČtޗęŸQāíÚôøôņņŸO-Ī7xĪŨ3CÎ\4bÆõfG6­)ņPÏj1~'<ØM-Đéër[UķÛà ôó;đwĮðá/VķOïļĩ°YíĀ"ŽžīrÔītŨÉí'Ģ›LĐSĖÞéĶ 8Ā™íņļ(ņkÞįɆū1w_áQīQïŪåLwą($Pę2˜ĒƄ,š4ŪuŲéĨŒÓo.Ý’@Ԑ„ŌQÁ·ĶC\wF8ēæL™õBĸ–õX3íí1ÓSģ}w&ŪŲ”š‰Čē!ŊЉe*đÞ\8bðāĪMëÓ •# 1ÛĪ ›ŨcˆjŅķ˜ā2!^ā!·Į ˆÝđúíïnæ^L,Ž"ŋōuÉ#gNĸĒS%h\^óîÏķÓĐ'Ū}ĸóÍ`ÕéöP‘" —aģ·iĩH™’›_šú^õYM îv3. W.ÃĒ•Ûũ+ũņ˜y/ŋQđ˜ŨËÞŅ6\n“B‹ŸŧAĻžQÛåæ Akfũ{?―qNWÛĮŽŧũŦZJ5UƒÕ1„"ōŽHĐDđĨŸ-Šķī(ÍW2Ä0)’kp)L/S’T{‘ų—€L”·K›•)BJĒŋ&d){ĩaaa^g‰ŦéüiĪĒ€åræÐtūĨņ8QˆāķQA.Ė]Ą&šđ\“čé, ķ˜‹šĶëŲM‚}aYXŠĐsŠą#ésú "­ĸyEÓNhŌåoĒķė=ÏH WŦĖSŊG•ÝtðdrįÓ[4o–}&Uc1ĶiŨlóøË5jš…Ŧ?4iVƒpd_ðeʖl]ŧīf–~ýųæ5âüqlŊU ĘlßwT-ųėð͊ōŒjí'ÎjJMœXwø„ļø`Y§Į§ŦĘnØuÐÆ~%KVÔāĮ'," ĄĶEÚöŸQÝ*„Lĩũô•…wîu"[ún^3ŽW=ÕĪJ”iR‰SCJN_úÆî—CU›?đŠPđûŽĐŒjÞ,1[ė,›WlÜó ‡Ŋļk=?ˆeeÆ8mĨN§%h eââ &Œ(WĖ߯u: /ÉLģx―.ÃK3ņP‰GT(‚bUŦ^Ķ6zhŰVqšÉ+tXēČïįK~ņ5š/]sð\nÅÅ]Û9ĶØÅ› SÁÏ4íƒ^ŦZ8Ū"ĻMč;{i–øŠ4iþÜ"~ãŅOM\RXÓÂęļjųW›wįX(ūhIÅd-ŋ^;ī„išå[˜ý@ĻešŅZ/œÝX3ÍF―ÆÃÅ)œú~üŊÄ݉đĢF ÛļákÝé”ā|ĻÔļN Âr Ē‚‚kÚ>­YįĘnŊtę:°‚Ý€˜čÏ·Į›ōĶÏz9*:ú… Ÿ|ōÉĐS§öč/KĩRWĖÛ:ˆ‰Ž:~äe™ēelč>jŒßô1nÃub"™ ĨAšĻm}jØqŌ―\ljmļ+ ø&Ŧ˜čĒ4˜Ķę§ ė2[þœÜœÎ]šNŸųŌŋCĖUu§Īĸ N9ÚĶō q^úÐBÄ@=c$á"É=īyÕėU|°ĻB́·<v0y°ð/M —E! âDŠ8&Ótē ^KMÉÄũÉčš}0Ė_UsŠæP ‰~óĒč69I–ą-C(/@KŪGðîóũ`ũŊBDœ8_îā–€ĩ,JT]Á’Ŧ/l{Îô†IÝ!ŪŧĀ5`Ā―10 ŌtÍ2$‘ßÁle>™TذōŸîÝB T5hrŠüÏsüïĮ=ρ0jøÐoūþĘéôS5UÔģTԀŠ‚AqÅVĀXTļ΀‰7·a§*vÂÉéKŋākë3C8_ xÉRģįÎK,’ļoßū_|ҧøõŨ\’Āt%NČÎHOš~MÕ4Ë6Ąë†t‡æņŌņHQEØnRŒzÃápږ Š ĘUŅSQ4 t h(ˆj õU]wØÐí%SđlyŦâ?Ō…,ę–ĀŽĢ7ÏåęŌĩÛÝRí_cWvrRš™Pްvöų—ÅýļŸjÕŧīj9‚ŠŋÄĻÉ9bgBŅ+Hɂ3䐙DNu`‚ qMĘR&Ä9å°Ũʔ)ęņxNŸ>íýӛÜĸš’6ßNœZ–;/c!}‹%?X# ‰ eĐPo„âĀō45ĒbXĀĨY:Žp V‰B ĪĐš4ã”+•B耱7m„Î ―%P‹ĄiËaÄBeCpÎýƒĢK„âŋ‡ųt?îĮ} įb†cIï"ē’I FđŪj Ô"ð͚€š 9I$ģω€›€K9i‹ä„ƒĘ"WSĶl9/U,)éĶ—Áåt: !iĢVĻz+ŠÔ–Ĩî1 5RÛ[2ņ…=#g:čFĘ*[ļ+‰ĩ6M[CšH#.ŧâĀXŨ}ė2ÄphāÔ]ð7îŋðDôÆEc>/H#%ĸßĀNFũã~܏ŋ‡Â ‚üŠ/E•.Ē+Š "ŒInRTK•ˆQĶXƒƒ(‹eš€*―NAB…†ŊÓéį…Ó2FsrrŪ_ŋ.ížÐ_b%ÁÁAyđyBÄËéā‹~)‡<ëT`§ŠË™˜ MƑmĀ–%Ίāü`'Øû‘ǁ ;—ä/Ä*Dˆ(R”iâUD;XN°ÕEB)Œšýų_Œûq?ÕB†RĀ.AŽ”Ąs jĒDĩĻ%2ĒJ >–XZ€Ę6Aý ސÔÖR,š Ķ4a·mÓÄâÅžô0·Û•••šš*éaU ”–šŠ p„( [Aß@ LĪ―‡H—øēYĶE……,š:'€ –Å;C\vsP{,8‚-Ã@Bß@ƒ ĄļE‰ĖN9ĩ-`/ô q•ˆķ…e›ŌËݏûņ?ũS-€cEJŒ" ƒ€†7“žUaæB3DS„uđ4 “âĄB;Ë\&å*q<ÁĪ|ų !!!”Ō#GŽH‡ðßWqD ~ð“„ģīš"€RĸōŽ”Žõósž:~ YHC FíD*%č<4 „8ZZûHīžôĢdų9TāšĻĶIq/KŠŲ"Æ-ÃôI,rãQˆŪˆK”ūÎf‹û–Tīđ_Öþ/ÆýļŸjeŽÝI‘ }f\RR , pQ čuaųE-“!ą(†UģMF@YqEýƒB‚cbb5M3 ãÐĄC‡ƒō›üĻ b"~M5ģđ“ûE“  ŒmÄóT5]á9 ·$+ø“ ;e^Ëēō…Ę á?gkB`Ũō9ÖbÕ―ðS€jšĻŧ‘‚͈”ČáTU*ėpų‚Šb&a. øP™á›EŠtŸdAôÓ}šhi †B $%!ecúoôj1š_ĸŊ‡zã~ÜSЖ s$ŅXT4Uô ,ąÎUš-ÐŨÏô1PąB˒ˆY„đĒI3)§‚ Ã#ú•˜GFÅTŪRÅēŽK—.y) ’ûûK ÜĘÓ~™éÎô ÅPF/UŅĐRĻ.ŠQÅEŽ…å%‡(Y ÎVH͊2–Aļuë4ŋ˜õcƒųðĩôôTUŅlfK--…C*"”õ„û!ųŠļаÛâ0Üã’úÅaēžxÐîâˆÃ›Å Ø:(ŪĪPôĘŋĻu+ƒÐ4cp—ų]ÁėČcgE97,žk0ĄBp?îéÐUč  +ũŌ­õ~ŠĨ *8QÛ"QšāIÃ5ͧÀsŽen…üâ Lą„aŒi úŋŠA“Á'åéĨ-/^ÜívŸ?>ŋ{Ā!Ī>ĀéĀĪ‹78cŅeýË6Ō‰ØÉŽ–Ÿå@ČļiĒ4Ķc+ÚyBӋ n=4sT Ôg8ŒŪ&RĪtĮdŊÉUĻŽĨę9Q$^J :4G $l4é‘ÅŧĒ$û@―R5‚‡†ĸïę‰ĶÍofӔ,wĨ(^ŦtáûĐöŋ:žh PŠėRA?Lz5É `ïɛÉYž›Ų~ ĄÜĄÞær ŋJ ģîvü.ŠÍ·Šb.J)T äøA[ŒÝv éä ÔËÏ*čz ‹BþGšŅâ\E|q{‹q.ÖŋųrVPÎBegŲŠŪ‚J”øh5]ˆË0ƁÃŪHŸ)úe˜&ē4”ķ+<4,<66–sîÍģ)))Ԡ˧ąĀyvcՃ9á˜ÅušbRõ§2!bōŲâoĘõp Ø܏ęČæHôļËØię:b˜?X|ú<ĶpBÞ8MUĐ Ķ–K:ãĘQžišpR"Dú}ü4Ë;%SÎ'ŪHˆ„ˆÁí JrĻ’ĸ\Ģ6ÏdŲ\61 ݏĸæČHWýœNęÄééĐ))6ĨĄĄĄqqąŠÐā·ÏÝĖ=wå™ėwō(QÄ<öȕ›yŽ˜"•KÕļÚ §vÁä‡ÍJKÏqyDmâ*Ē’|ĖK={ü\rv–ŦP>ØĄLÄŠĶg'Ÿ;zúF\ņŠÅbƒ-ÛΚ''#3;ŨĒØ?842"˜YwÓÁŠbĸļ}3­RĢdâüNØ'wVš›ûE†iû·mæqUŠ—ŠQ fðFîAĮ\Ö/ā.ÄŧĪLÃc ÉUæĢī W}^‚ĒO9’R"u°Č=RM\w8K•*íįïĮóę%æååišFä=š2°1@4âÛĶĸLp„E?—sëbˁ‘?"X‹UÍõĀÎþ*P5lÓBĀBÆ0 „›°*KrļaøŒÓ=xؐ_$}å9†·mYR LˆĩHvŊļĘl8ģĶé˜( Œ@þMĮ}Đé{ lĘ,ï—Í’SŌΞ;Ÿšž‘“{éō•‹—Ŋ†IÅŠōNɉ(VÚ[ ĶöčúÔäzķï:uÉŲTU|ãjŪ›BÉ ÏZ0}čSÏ ņüĀ o|–ę<yĘ|ĸå)Ģ'LņÜÏMĸ膛į?‘(Zöų Ÿ{rĖ„ąOũąû\ŠBˆ<ĢæÐŽŽy­ßa“ĮčÛũđWūøÉÆäŽÉ_·`æú=Į1QîtŒæÐZ9具ūS5žnÁŒõ{O!j^ŧvÃeą{Ӝ\!DČ 2 uŦHR• 2‹Č8 ÓJœ`KcÛó"‚1$h[ŌJ:˜3N™H8šVķ|y/•Ā <ð„ŠxĶ9‚Û—7_öG&,ūDü ŋõ4%°‰,îŌÚĮ4MiĀč ųôHv!]Ũ(Ü~ąūsÆ'”į\ƒD‡Wâ‹}2ŒœËö Įž§1‰“Iü?:æāķ;5éfRZĶÛ°Ņ? āD2îēžōŽî%õˆ0ÆēÄ+øÏÛCʰí_5}ÔļÏzN}ũ›Ŋŋųbz·/Ÿ~ÕŨ'đ+åÕþ#ūqŪwN‹ėÜwøäĐӆöjæDūï g&õ{xōœŊ7nZŋrÂáÍŽ\Ė!Š/ kŠëĨiÓÎÅ=ēiÓĶžeOŽ^ðqË?+q];΋7?yrëÄ óFÍšĮˆ4ýīlQE`nx<ãP‡āMũw:,ÃcX6‘Ęp"°ŠķMŧLëÞ}ÛVCˆ{p:húáqýn>z!|6ˆŠ2$tžUoˆ1‘‡(ŠîЃ%ŧĐlPbĉLĘH† Æ%æsïBþ~ĨK—ĄTðq― Đē˜ĸ#Âė_œĐÎĩĖ<Ãðú€ŠÅĐÅm] aÔ?K匙&ŒÔ@dÐķÁ1ŨЋʞ2ŒDŊxáa‚-Û&ÐãQÓm2īI5q+04đXÕEA!Ē߂ 2M[H/`…sĄĮ‡0v8Ķ•Ãþ=ąųÛÖgJÎņm“§ýņf˜‚ėB í­ĢþēR‘yýöŒ˜ÓÐ*ķđ@"x–BpLn3⃠q+ĻĻ`šrÓRsâã9īôd―?ĐĸG7ę~ēâYãŌ§ë·­ÖĨV‰€üģa™t›ĩđĀ J‘FųÖîõ™ÎĸÓ0Œ‚Ó4ïööąĒXÉKūÚ^eā˜į:VÂÔŠÜ}Ððv|ķ}S5ÎV}ó]âĨ.ĐĢĶ îÞszëÛĐЎbk†čÄôxŋõ‘ŋĒqNÛv_ÉI+íâÔ8—™VĨĐG>ØåÕvÎ€ÛuZ8dßŨ3enõ°“PŽ|ųЁ-[-ß|$éä–ũ>ߐ’yÅÐë-šûôÚ9S|ĩŋPņړ§MŠ[ĖéT”―_.ōÞé)҃ĮÏÜ!dōÐĨĩúô}ĻvâÞåCŨâ–ÓúĩŧúóĶ-ļ~ĢĘŅ6ÂþÄØđųËÏ7Žßs!ųø˜đãûÔžé=”jĄæbšŸNĀߐqQŪĘēŽ@)'ðü0âË;ür ]AāßjŌĮsãķmYņ qqqÞūĮãņķų0/øSÄŋbü‚Ąš―v>ÝÂąõ›• u8]Ė}Ãļy"ûįd+ÕIá;fÕß­& üDŠ˜R‰ũÅđĒŠÐ(°aJA`‹dŊ–Je^ΑFlÓðķ8•  UQDąĘ„ž/B(ŋäįâķdЊh˜ˆ‡Mė"Ąĩ"O1úóa<)ˆ–>ý™7NÜð~?šsýFzfŨŽ~ĸéĶ}aEJ?üP%óæ•+Ũ2’Oŧš·lžˆģ—>ŅēŠäg‘qöëÕ[ßëŨę™ę(ӝįēhö•ƒëūږF‹īĪMb ëĀÉ4ė9ŋóįŒķ›^ÛõÉyTĒcûV…üøÉÝßmØŠÁÃ―jÄYũt“D"pþ$ƒ…QÍkTNÄ KÏ4―zúo―wŲŋw—NՋUŸąļKõ˜3_>ÅÁõŠåŽ}ûĨGöņ|Ëje0ĩų­™Xæ™ï?þríĘ9oTô~Í2!ĖðČkģ ·˜†ˆPH\)§cŋ)HųA(:đþÃÖ>šķvōWE +Ēd~õųÚļg^]ÐŦŲË&OYëZĸõÚ }ž8wí†=tŒ.\ʘđä―ÖÏ3xÂÍ_>vâPŅ\7Æ8ëڅĢ8cœqņ§IIđjĩĢVĩš•b+ôœ2·G“ ÔĒüSö"ĀâįÂgA›3ŠĻÄDŧPϊ―Z[°€aŁC%―čĮ•*WņŠs{'­^o[·īØþ/]Ū‚n$y.þėŠ_šĮä:=Ŧ)… ÄeŨđ]i[7$ŊI2S4Žýb #Ī˜Ķ “S+Ęí―$ŸÔ‘v ŠĒ"âƒa!é -!†`™ @ČÁíŅĀDœMB@>F4DĄ§hqË͘ÃȕJĸso`)ō anEAŨ…ĸ›‚žĒwdŸĸ~ŧĢÆ›CÚëVžÉ•Ø"‰G>0mMæ­’Ũ-Ÿ™Œ4vÎxšOPËg’ŋõÍO;>XëâŪ·2‹Ūm{í­~óčõX·ÃߎßãåđMŊœúy―æ­NŪ}sf éßPŸņTŸ€æji76Î]>ū^ĸ‘cëwčöÅÄį/Ï[ŋü……'úŦ^yļëÃûv~‡#*Ģ}SŪoÝžÆŌáÃ―đžžŋmąûĐöũô5<9'DÎsį9ƒýÂcb#K8cã‹ĮD8Ī™bÔ$ĄC'ū>Ā•đyöøÏÏyïó…Õ i‚ŠóŋĻÄZu+4wŜŊÚTéP­0Æāî&(<\đ|ӝAŰĖöRۜžÞhÜK]iií_ŨŽÛüÝKķOū–ü|ŊĮRŽžcÎTŠx–M;ŅŠjyÛũåý_uĐZ€ŠˆD䀆‚Ä―á[ĩ6ÃAQ‰Ą‘ŅŅ ‘…,Óūqĩǚsŧ…ėū&JTÓ°Ášîže7 `Áôg âUŠJĀ$IÁ|HŊ\Uu((DpxxXttŒœĸœ9s&{Pā'ŒĢŧQpĘMÏÁÍYŊt™ŲĸŪNå·ģˆ‰žþ%Š„Ôxåėdo‘ŦaĄüo#üóūԒzƒ·Ÿjó܅į_=’óģNô‚m[iy  ˆWîúAm+Y Fâ]‹ä+VėÂÂÃÁ €ZāyĒ: lذiZr–ˆ„d„Orčŋ@6SĄW˅ˆ"Q [ ĮþdH3Įcadļ2âÂ6Œ3.&ûŋޙPĶɀgûÕqûyŧÛŪ“XūËāŅ|ÏŠÓŨÏy“Ø—ø§CIđ†WĪã°§ïp%.ëŲ7Ží2Ž&–i6ā™~îŠĻýëŧÛ$”JĻÐuÐēĸãe\;y`ˏĮ’ëķũ\på\HÉqäf·}ŠëĀá sŪ/OJvU)YŦrÖŪq5dey8&ķ+ËTŠ=4ꁔĄý^ú gíxd›ÜęˈHŋ|%5Ï ĩPí!O?[üæŧûīō}úÉ›—wíæģߞššŨ˜ōSŲéŨŌrK*ČdčQvü‰āŒ;Ck%yéģ Ci\<Ôi͟ûtýščŠĢ"üQVfnV.Ýû7{ĸ@ĸ€Āú7ōŽ]“™iŌ`Ïś9‘Ņ‘NLI`LÕj…ŦV [8Ų'ŊwĻuöĖ ˜øļÐļØPωëI;sø€Ĩ—ˆðĸå7ŨķXõ–ŒÞÛ_?ņ9 TmPaPáWļBĢWŽ‹ ŅÓˆqŒ2Ó3BéįNŧ­ŌÅ#MÏĄë™vÖÍm;ŪØĩT\ДūG†}ÅÃ,…`ëÞQ”t/Í!æZRPU$Ӊ1(Ð|eƒšC“č%đj6MK;X  5ó*TšL/CĖ›žfbŠĒÔ톔qw+nüÐÎä6Õû<ó@—‚y6Ëíņ03: ATŪ>ļØč—ÎLvÃLąxú™ĖžņO@Eč…gŋ]‰Ü*lvH„ŊÃЛ†=h˜úÕĮûäÃÝëOxû•'ęíÕēĸœiŨęöÅŅ#_‰ÓĀAPÓ#\E7 Ku89ĩÜn…dŧĄýŋ:nō+Aĩ ëŲáug lЙ֗.Ô2~>ŧqMųvCËÆEW.óŅ‚—RÖ9ũž>Rc8Ą‡€‰§ĮÍ,Ë^Šr"oáK~IÚv,eÛôÞ"æRKPþąhōäsÃįÔ6JTSä UVĶ–-Ž*ĖJ ‚ãxŦ@öË4Žččč’%KzëYi‹ ĢĖģū<ūSCUUȉýiqīČƒ”_.ûDÎÏS―zęûëÍã[Né<Â_åjͰ†Fu|ïú*Õ/3Û°\Ĩ‹V@wƒ+ˆ― på*ÁŠ`jP_ݍ0ä\ĪŠ‘)UQ]Ä,aGĶ 2`8ZědCô•Jˆ7ƒ”#ķąðŪęât–ā†Hϟ x-=áÅĐ'ū:ðĄ5…uLCĘwŸ=ꉓ†tn―[ę“_)ėZõW 9-Jr7•pMsûbeŊ=KÎ{‡ĖiT+ķBŅï‡wjý ąÔ~“fĮ;NĻ~HT$p·MĻŅå‰ķ{G=ûlT>ð•y~*qƒV™Š 'I,^=RyŧÏčeïLîŽ"yŋQ0 LĻ=süˆ wۚ361æĖöĨïå…æ?šöðãþpÂ!šøæÎVöûþäôþýžŽJH4~fĨpnģ{2ö'‚ŲV`ņ&‹V~üõ†­éyđÁ‘Jú‰Ũ^ÞĐũ þsßаk_AŋŒūœqņņŪëŪ‡û―ØšuĢbš‹Ô{õÅâe iČQĨZĩ“į“PîËGķ._ÔÏvžŧrŪá"ĶaÖxvėŠâßl?—<íåÍę”įĖ–gīMģęc/NäQ„Sé ^Đ͋Ã&_ãÐēm­(ņíö Ķ”+UĖķHĮqŊÔóä\<ĩÜð9­[Ôa>éõj;ŌðļÁĢžÏPĒ-ÓŽÖkęDmšĻŨ‹óPTI“„M˜óÎÖ}§ÃBœŒó{-&Fð„( É‚Ĩ›wÉīˆÁ@L!>öˆĻė$YKũF„. ,Yų Eņš7z)Ĩ[2n%\þŧ­ĸ―rÆÓ―NóİØüý™Vú^MbGĨŲÜuŊĮEŌļ§ĪÂ<óČÖô ,óøđ”˜°„ØBņBīĩļO ŦĀųČ2j‰þēŠųīÆrĶjŠžBÃc**ņ™s͊,"ï4‚ĩ![+œ ,­d=ČėĖĄtEĒ#!&l#™æ(žŒ"‚pôjŅ;/ĻXįęõtĶ:Ã#bBC‚GN_qųzš^8>‚›‘OŊåāyQõێŦÁˆ‡>Ø{f[gęϒJ>úÄôķÅ GxbLˆBĮĖð>+ãÖģ =5ūŽƒŧ"ī{ĄSmįs#gĩŧzÃÂzlDĻú䓌hy&yfÐSŠęPĩˆą‹?Iui \ņëøøLŠøgåyJ4}îýÚ}ôgéasëõHu†3]jhDýŨŦ8M\šÝŽâH1që§ŸâŠæïį˜6kÁĩ›)Š_pLðÝōėý`ķáMčÞ§/įÜōô}účŪwVïÔŅ…K<úX°Ŋdâͧ-~Ē˜“ĘýzhB“F‰–iRÐĻuŨƈƒL@ĩī€Ú äķpÕ4MĨlŦNåå"EĀ"é{D”ŽĻiSŲ[u†Ū °z.TĄƒãJũė]N^ĨĮīKÖŠW–ÆMÄŋÁŪ“ûG—íÔģˆ‡ DõĒĨ|',^Ģ>ĒbéQšvÏru™PUaũžá gāØ(ôģĄŊĘ Ï(Š(L-EB]ӑτœƒ­Il$(ĸTdâа°Š+y1^éUK ° B~·Š%e&› (]ē:*Gēü”}0\ U#xtE{Ō–U]k>˜†ŠvÄÔR[/>úvŦȖĨĘ *„ Bī5Ðf6ƒÂÎWÏ0 „ĖđATÕpDÞϜsÉ “>2EJŪäÔI"ƒÔ9Cb(Då;óÉøŠúŊ‚ čK@.Ķ $kh ĸɀ̈́ÂA„!ˆÐĻĒaQÅāÁí,4ĶlX ’ĸð tøÁ'Žk~ð·N5Šd&ņ%K”)eQĘQ -{§g!5Īd™PßĢČÏũŲęN•ČÐņBÖœþâ‡ĢDpøŊåÜā@ؓoSU6,Ęũ*ũz€āįŸFm…J“č%Šī˜^―ĨķeÖí ÓøõjTnšŋ~U<ųĸ° ã‰Þ4}Bģ€p ĩ-ïWjĀĪŋ―rËC­ß=Ąmŋ<Ëš‰đ0š‘Ú]ŨĄąČ@xP•Ø~UÆ/ ZI%”îßâ`čibsÆXdT”éåņx._ūœžž.S>'ÚĮ͕KGüû1óͧ†åÂJā…U&Böa8å*bĖãv+ŠęМPÐSx·Rþ[Tũ‚G'@ 8?į‚Č"þļ 20ΰ@2`.O‚}ÍÎčŋã N)ˆ/_1ý{ĨåýøÛ‹4ĸӉ4Ž gN\ž™A” ÂE GG†ŠøïÏ[āĀô.‡0cĮĶ5[ö]ŠÞøÁV ŠęÜæĸSŽđ /Ģr蠈ī Û î…ĪŠ !>Ra˜ÆAah8@ Č;âģ}ÄQŅ1Þ<ë…ÓĘû6‡ rC• é\―]N`”ía™yvtąōĻ@Ėcq #ė[D; ÖЙī뭑/JDD•(šâІšÅj֏) ’]é6e!zpþü ŋXÓu˜O1,ЊŪI%‹‰šUӄp-Ģ2ÏĖŪ åįw?;îLķ!’ūluaž~åtXŅv+æÍîÛ­m ē-ÏŊŪ˜™Ėp›Œß›Đ T§röë` Ęl ųüĩĀ^‘é*…ƒ]ŒĶjų―>EĒ`ž–•‘iŲv^^žTŠ5 LÓī!|ÜÜ|ßóÛČØbČb•BĒ•jđÅ8ýĨŊ`Ī kŪlt+œŠŋSs"Ný $ē\žžl_šė9éĶyŋáïbYÂ2Ŋ˜xĪ7›īfÕŠîũUÕTpĨĪÂo\U č†Ua6kEĘAHƒæĻ p)Ip ŅJ°ĄOõ7EfĶû›­įĩϐĶ]*·čVđĨøÍŧVöOÛžërjjúĢČM;ĸýî]{~:’ņĸđCx?ĪÂŨŧŠöŸęEÕęDˆ/ÝĻyģÝÜūvņc7kŨšņ쓿_ĘC:I^4`Ā„GöîØžvŊ‰žĪwŨfĩj<õåél‡Î6Î2bōäޏĩŊW­åŌõ?(N-eïWšvmŨūõÃόÛ}"OŨØ·ó†L˜õĘ―;ÖĐŲęÝM—õúž5Ï<ÞėÁVí§,ýÖRĐ?}2ð…™ģ'ŽnÞĻöĢãægi‹Þüxã7Ÿô|ĪßöSé'ūÐģËCĩņņ^„ \ŧÆŌÎūšbÝņ― ŸzôéÃWģöŽ[ÔC\śӖ\qc ݜĸėģcõëÜbʉŦE!ũ`ŠÁZ‘:áV&ÔHtU—0M ĩ8Ŧc&}Ž,Ûš,`4‹ļčr*š€—JiËķ―åŽã–ކ ųˆZđßiFg mŲ0ĸĀ__ ÔLČGŊģĪŲÆŊV'HCŋfF(HҰî ‚IAŽĀ?ŸéABÜË2ALGĄTÖė–‚-§â nX†@\ĢĖ0-L„Æ’ŽÁ˜‹Ž-Ú)î˜Á)8Ī2ŒgqF!ƒŦú›"--/9ÛSž|WtŠųbD/Z6:õĪäŧ/lé‰}ëzu|tčø‡õíýÄ ņ'ŌÜ"ųf$ĨdļÐýøŦ#$–|žfÕb”O…ĩåŪó_ ónãŅoųŲ*óð‡cænE:ūðÓķ.iS–.Ž|ėý1KôōÛųŋö'Līgv}žïjŸÉoūú|Õå/Ž=rõĖ”gGXĨŸýęŦÏ:‡ž<āåLæH>·cÅįûšŽœ7š―cÅë_žKãNÔÛ/þâíáۖNÝuÕ"Fږ·–œ`åW.ŸšąyéŽkÎ^ÍŦ/\ÎëŊ4(ķų­1?e4ýôëõCŽÆ9ƒúČ&ĄEŸzīiąēŽ==*yýÓc>j=áÝĩŸž•ųÃÛãįïĀtö‡ïNŌčŲ<_*N—É=ö’ŒOÐčĒ”ëšjšQ}5=úĐ*2åY“–ÖáįК“ |‰ĮãÉÍÉĩ,ë7XZüë DŠŊ#ų%ąð'Pó( МÄÂqüŦōŲķųë>Ŋ‚8ĸ—ĪÂT!dŪxd-ÓDŒ;ހËo0x+ ýËēÅ bųģ.ûŪ—Ĩ],ŠuiYĶiŒsNW™(amΑzæøŅcaå_ß>,XëðÄcs.Kō0Ī…w;Ģ{ÃĘÛ•âĮ3ó2ŊühfŽÛû=+ÅĨ˜C,#Šá“ŊÍĐ\Šf8ķT逐ބâ…ýļÞ#c‹í›Ņ­ÓÏO~Ą{Óōܰæˆ-P8 tą˜ŸÖŽŨKĩíÝī\!ƒŠ5æ‹=Ū ePĄØ§ÆNŊ^Úi6įũ`ŠåD‚ę1‚)žä&`‚`‰ „1QüÎĩĒĻÞp{ ÄļP6@‚Š B_ĒjģD6QsssÜn—Ū;ō‰ÞōS+XÞr„åð…AâB60‡Ö‚Ë4ōóŽoÅĸ{Ũý/bQ ‚š˜Ï! Ði [įƒÎ,€‰ŦšJÅrZˆ5›ZŌ―‘3Ņ–Ō4ŅNúģš&―Ųᒓ…m‘ŠÄ'#pĘð1ŒĖ&ĒÓĨBŅĸŨPQ/1ïāÁƒ·æ–âĨxā;.D[9ĮāNŸâŒ| Xéē†Eņ]•-ÚĩnOHÍ]škĐ2ý͉mF~ēí@ÝåßmÚąáĖðZL˜3#Öݏŋ0Ï:ŠŽ˜ņÞĮ}ŠW7>QOFFZHą2ôĘáŲvDļzîüE^RCâ&ÏLŲ–ÉļGĀ[-ŒĪJ·Âm;9 w’‡“BĄZ晃g3ëEFĨ^>J­`'$rãC ŪÅAĩfýfyĻ$æØęHŋhaŒ…!–™Į8TiĖc_ē gVĻÂcïoęšqAÏŅÏMĻ~ðģ2N_}A™Ámađ]ēīņ晛y<$Č:wņ" ŊŽ A†,ģ5~oŽÅ0†å?xž"Å0‡ÛĖđ5U(đ€7gČļL–Ĩāō -p‘2ŒÅ Ã#ðĸ„Ü^ŌE‘B."Ãr[|Y·<Ė2õ€~*įŲŪ\ÄQūŨ°‚@ŋ%Yųĸ:Õ/Ö·:˜ËΑ ébäv„(’åEˆč–HĮuUSu§ÎĄpāÐC7y+Ē`<ŽĀ€Zķ$Ô,— ’ŪĶɝ€ ėĮRÆz6eļī†TÐ.ŠTĐRĶLÎ}ūp5kÖ,Zīč+zæķŽŦ™ö'z<ĸČCÏwíāûęŲåBJ^ķAņ]Íx\n#ĄHTt ’Sý2–ë”Ý―zÉöĮM˜:<îĮ_œZ4øÉ‘Ģ:xĪkŋi3gL3läč…j•î-kg~Ôī ƒæm·;?ßÉI ęvK›2îqÁO#ĄØãQļŨŋ2cÚtŊÄø”ĒuŊ[ģaßfĩ—O2sÖĪņŊméøð ęrŧ< ŽÅ(wđ %ŠÆĻö-6ΝļpŲ› Î=šjŦXsįI`g7ĩíȒĩŠ:ÎĖ›<ũ§ãiŧ>˜0ųÕ%ßM/VąbļŠŲ/ïđŏĐÛ―QåĪįœöÂā…{ÕG†ttXï5Svo;æBYŠĐŠiYú˜ÐpÝQ‘Í@*P*r‘eJS5QޚĪÅ'Vˆš••áņļóōō\đđÁÁ!—Ļ2K\*'ĒbfĒw Y‹<‹!2EœŸs|.õ&Ģz&=f,\ Č{ Šl„æ—_ųrn[ÔBœČ6ƒpįUTĻ”Å\―ėÔr§ÓŊ|ĨJ.··Ï‘-åhMËĪķtŸĐfŽĪ9ŪO;ZŦ–a",ĻP’ž ĻĒķĩ "–AmŋËJšđķ%j Ē(šh, !Û(xÏĸÉTët:4hpíÚ5ïĮî­pëÔĐsWbóØVWg/~3ŧ@ĩ=Šžmãŧ670ĩĖĒÜteTÜ?Ēړ‹§aná°ēŊ-XųõĶí9&YÜŧqŌqĶ™3jŅŌð"þåũēc.`f Hũ™h2čf[Ž+ąØ/ÚķTū†Ē;‰ ˜HÄvZĩéÚ---íĘåKWŊ^ebÐdyqÚ ‚@HŦ] 對ą(^Ą5‹(’ũ]‘ą@Í?ßžėņxļīPäH%š†ó)ēá€âýƒ|,ĮđFŽÛp‰„*āČåqĐAĶÅ-“c…‹ÝÐßĨ6 kĸč#†éķžĸŧž7…\—Ûex<ގgšŨQ ;ÛŧSĪKË4 Cūš!6+Vc\ôjuĄ€NS @ĖaQ݊ęXėŌ ˜C\8ßHÐWþã. åʕû駟jÔĻ|Ũï2uĻvdvVĐEpÁýČÃPšhųÜíÚJ–Žœvzų—?'õŠýöĢĨ—BĒ*ÆéĮÝŪäk9č~ü fyÔÐļVö(ŒV‡ÄuíҰR6Ðmœåę=ĀLƒrĩÜ E“žōļŌæ6åϊ ­XįáNå8<Œj·~īüþŽ(Į…+Õ'LČ„)_ŋ(7LĄ†YųGŠ5•ˆixļ⅐w?G~ååk1\īVŦ’ĩÅäáV―*€6ØæëŅ:"Š? ÏĒ–ßí1ß5C‘wë<üÞe‹p5%N‡\ëS)sË}ĐÎŦ;tƘč!4ß0 qɀ;=RŧNÝēeËVŽX‘"Qī^h­mÛÞ\æÝðzÞddf0Xšs„)á&˜w`§åšĐĘ@Ý#6fi—OĩŽa;UŽ@)ˆ ސ,ģíÔÜd—;YČô˜ž<—·ĸĀUâv[nã sLǘ™ ã ð Qęf‹9ŪåƒĢ˜·BĖÎĘŨïŅW?ŠÛlt?þĸą` âô_‘‡ēéÂ$ĮąÅË`Nc―Lˆ"=Ēõ<ÄĸPÉPŒŒÅĩ0@ÍûžĻŠĘ-Ô#Cĸ{ĄÞq,F™ŽgAĐ@č]I3KQ”94 †‹'+­q0pT™O3[žYŲYĮŽĐRĩŠ—Œ+eYžyJ–M „Ū‹dUēDÉ å…ūĒiÉđ™ŧ“OwæāđÃÛӍ45B‰BuS„ü”ŽLŨÎ GÚ:kŧ5iø­• Ļø}ÆūEĄđ܌ĻÎpŋ`Ã4sōrÝyž ЗģģōĮÎÉÉū‘ž’iäĐfJnNZŪÛĐp[ÁŠôS°Hh~šÓˆ@X^ŠĖé2áz·ĢĢĢÚī}Ð ! Xo…þÆÂ…Āęˆ1Áb} /hŠC‡fŪ1RuMþð äÁ‰‚øý!óėÝ#""īM“Š[·Øļí;”oB „ČˆĶĩ*DGĸaŋUĐÛž]]ØęÝŦÏį}–mjAAĄ-Û=‚îĮĸŊĀđģÓÝL DœÝ=%į\=ļįTvóVM4bÉrōöj3#- û‡€ŸĢDÓ3?oKw&ÖŽPÝ3ĢŠjÎ͓‡O%é!‘•*–Óąāę`+ũÃŲn;ĶH‰â…c bũS­/ĒÉČAΊCęYĄø']”A†Îcb4oÚ’gĖ6lÆí‹gÏĶĨĨzÝČoŌ20Đĩ,ëq)E‰ ęSąųð&Ý/eÞ\{üó“~Þsé‡TW6Ũý°Éī\;Ïk\ļQ]ӝšģJh]|uBØĪ<#—2Ŋnŋ_pžË•ž™™u*õ\fnž_(NÕÔ@Åß_s6ŠŦ_$"ÆĐú9ˆŪ)Іha$ī<Ŧä§;ž§ÕTšĶ)Š"“ĐÔIĘÛķM‚b(ĨØûý™S'øāäČEkE(mˆāĒüĐUģm‹1*Û*ąä- #MɅŋO‘šbÅŌå˕ļݜC;ýĸĪõ[æÉa/ ûņĸŋĒey_Î}ę―ŒoĖė_$SÆïÜ2"I§ŋ›ōĘþm[:„ ÉÔķėėÕóĶãÚC?RŌ#šXSØîŊWtķŪUĨšƒ‚ Q•ėóĮŒ~8ÃadÞč7}Å3ÖVÜĐo―:bîšóE‚mŋŠ,˜:4Æw…ũS-`>ŦwMØÁrË2 $_ƀā$íĻ(Ð1ŽĮrm]IŲī-Á.SœĐĐ)GŽ)RĪĻ„yáņ›Ę=Þ,é-H=–Q86îđęOđlŨ…ĖKkŽ~þÁŅuŲNĘlÏåóG’ŠķäŠÐp莒þek°'kr+7Ĩ=UïŅ(ŋPorOÎLŧ–q}Į―ĖV—<=ëÁuu$ŊœöéĖ(• āՅ„‹Á=RõÆ0 oõŊƒ#åĮōm} Āļëyį~‡ōx\ÐcšŪ2pĮy—*ýAÄVōŋ Fƒ’ZĶíá<îïÕĸ07t?þ{-É―r`ÁÂõû‹{ë˜X71‹‰.öļþÅ·>ëÔēnÖĶUolĘ\ōÉŨ “Ó—3ƒT›q|ŋŠýE@” Ķmqj‹Ö Q‡U°ĶxÃô˜DÁŌŌÕ4 ēS€ię1ĻöܙÓ^5ÕČČHÎy~†―}#ĸŸoŨcx Ó°mZ<ϨφcŽŋšgipœsߙŸũ\<ÞŌQMÕT§3D íßũdÎĨ=.ķHl5žŲãžžž”ŽīĖŽėnüp"ý|ƒøš”k˜“ž“`XŲ ”)6|ėĀ[ n+Š"Ëí‚Ų6CŌ1žni'ĩMôđ…9ŅI> A(p<ŌŊJ•Đũ˄z–üäîûq?ˆJ~øäCģę3ííïž―Ĩs'øÚžþ““ žÞ―ë8ĐŧtéŽFÅŊïútôŒĐģ+—*”‹p-ģ ‡ŽO8ĸãÉAŊ.­ĄŸ|fÄĖô\ÓáŽũĘē‘ĩâýöė\ŊT{Ē|ɀ=ŦfŒ[ö5RËâë:ĩÉïÛÚYgĶ Tč҉c;VßąlØ'—JL}qPPdīŋuøüņ“g“2 ŨĻŪ_}ŋ―bãĶ$íĖëZZUƒjýiqå{OŲ‹yĄ ―ŦHÛ6+LD6n:C˜`ôƒÉ#Ļ/j–eƒ†zåōåsįÎÉLúŧ‘/ ~ëŸâäŌs.FQøš\WC5Ēæ}đũŦĪô4/ Ëåh‚ōÁÕ§•Xørۅï<óZr$§§fgå\Éļü]Ō.bá~5z! ›ķU ƒ0‘/„odļÓmāö=2{ëßý{ŋÏÎĘŠ˜@ža,ž‚$(XN“LbN…3*%ĀęÜ=+& ēŽ―ũŦÄuöÝÕûێ7ģWûók>8šæQ―ðÓöíGé˜EïtÅ{Þß{Y1ŪL0YiÆ ÛŽ[ļvÍĻ ;.,žĸÔūđÛ ―ÐâąĀ ‡îPUĩlD‘ē…ŠdeeÝĖHIÏČž’ré㠟\ČžŌ0ąV“bMōē|ģļ‚kĸü=ōuĨ›Ī< Ÿ[Qðđ-›ë_ŊOÚéÓ§0$NŽ‘Dž!‚Ā™Qü§h*ƒŽĻDUUËōnËD ―Z 5fZBŊý7ÄĨKY;w_NJqĸęz9Š,äŽU#Ū\ŲBč~üĸ UWOŪ_ēóÆđ&;ÖŪÍ:–ÆwĖûúøGO2ƒ#†LžQŊ|Čą’Њ2Îō‹›ß§qDīũĄ~>ņˆ”>xdÐĞ Ęeœ\ŋũtā°Öíž”ÜGíąâ…ŊO]ÏQ %éÚéÜ uš4-^ˆ$tėÓâ{Ãõ a…’šŽđzÝóCF?―hG·ÆąĖČúėíĨ1MĮ­Ÿ]áĢåŊ šūtíŒ>ÜÂåęķý`îSÚĐoę·™ēđ]ݞu ËÁÚýŠ f‚iGJpåbcbšBĮ žĮ)R L#S’ iYŠŪ)Xą,“svėØáëŨŊkšz§^ííųŨãņØķíïôß}qŨüÝŊ9‚Z–jæā:VQh ŋ=§ūīáÍc—ÎđÝËī<ĶáíðfåæÜLOÚ{õû·Ï―{4㜃j͊=āäNË6“ĘoÏĄøVüΈ߭p―HÛûũyųæBYFˆ„ˆ  Ģ0NäŌûK ™@|zc˜ÜōÔQ%ÏMUÉ…rF†P\tƆ6ïZĨUũ*­Å—ØhŅ­J`BÄæ]—RS]ށrvŨŽŧ~<”nĄŧ„™—yíĘĩ˗/]đr=ÛMQ02’ėÚđcįî+)ŲũEUžöö;?Vé0ŽcÄr-ž|ū}ųƒŦ>L3ÁŸ™btBđ†a–wõčĩlDģvïÚĮ‘šû~œ"Nđke ÖÉÕģį™™ė”6]åđ)Ŋd!+ũōŽĐŠVlzzįWÉy5jĸéà —\”°žÃ‡Ž”ĻŲĄEÛÎ3‡ũĘØąårŽ+OpžŠ3$Ø/H+ˆŧŸj%ß A=+IbŠd@AÍnē· Ōķ™ý‹;bDė@mŅ\đy'Oœ0MČD·â·333u]wę~)y)^Ą†%ęÁķID—ô?—đcāg}ûÖĩī›ķiæđ\Y99‡ŪĸžôôĘÓY—°ƒbšVéäMÁû’ãję?üówĸĐ(ĘéÓ§;"/˜Y36lTÄ.ŸZĩay@D…’ŒŌˆA0z$T$‹ ĸ†HKËMÎņ-Ÿ@‰f!ߗíýÂZbŲxæÔ““ïžûčņÖôzļĮȧčũø“ƒ^Š‹9éIÉéŋÍ҇ķžŲ­ûĢ#GŽ4zâĶã™č—`§·―7røÄéã‡>ŌsÔũ—ĸ§9iŠŠĶ;°ûzÐãÏéÜđÃÃuî?|―ēþŧÃ7tęĢģچÛ0 YąSōãG6øÅŲïîvyT ļ…î įAqUŸ~ĒŌŧӟŸ1kŌ‹+Ö<Ü―]ņPÍ4ąaÚ1eWö 1yyđüØĻqãĻĻ(ÆXÁFÁĘ[QԘĶaõ‹ÕŊ[ÅĶv™čŌåÃKėĘ܇UÍmģˆB9I/ą@ˆZĸĄīėŒĐÞŪō7üs,nÓūuz -z=éúí݀ßÄoæuâö26ĸ`™g322öĸðCfz†ŠĻdpË’ÚLĄrÎ,›*DÍbÎČԘ&ô Ā‘A2ÍĪ $ú;”ŌõëŨĸFqŅŦMsgÅEÛmÚyÆLÜT~ŦļČðÝģ/ėũč3Á=ŋ7Ĩ3ūqtPĢ–ÏĨĮóqĸoGûĪÁāUVw8ɰŊf˜Á›6lj‡ŌØÂđÅļh“Į>nų|Ī#cxN_íž\ïą ĸÃ$1K‰(;wŲËe˄™†É9 +Óö“wcýc*Î[X<Č4qŧ‘o4 K4iČÐy‹*mܞiĮ>7l`z&UMûÁ‘o4 +*(šÄŋËð7cŦnū˜”ûÜĪ…ÍÔU˜ëŅÁÓPp4 ZúÞōíŧ(ÁåNI7M.™`Äĸ‘3ĘÖŊãį /}ņþg\ĖRÚ<37ļ䯓—’ wï?ŠUóxĄjmß_žiĸ1Tūï ķ-ãąeßOĩ28W5Íī,?Ī„H#6PģFPŽ āó JĮr S ˆQĐP^[ßžqý…óÞT›ŋ–G·âNM[iŪišÃv Þ,ãÏ5ėģýØâŌÚ9”)š†Ļuðāä2õ“ģŌ’R“Í;ÞĒZpLŅ2!Îß\EPXL€eΧ^ŨtZ$<ýgĖŊPlí˜xí‡=ÄYĨ~#fY(6Š[&e(ĄB=Ð.°ĩ€˜Ýã`Ïą ÕÄûâbžýķîÜK—r“"ĩXŲ ˆŲވ(\ū[ŊŠ—„ļÄ@–ŒŠŨ"Þ`!]ĶMŽÐȧØŲ°Mį†RðÚFRˆĒØę ŸĻÞзĮūÏ+þĪF—~‹ÅÏ9^ŠfLt!™$ïBžEœƒō·OtF”8˜ø((DŅt=ϕûóÁƒÕŦŨ$Ũ‚Uí]õĮétĘքaՊÕĻSáXŌ(n›„Ž;øąÃ?îŊpLåčzJRFVV/§W­^:ÂîÎsL‘2iޞpeÜ)óÞþ§Ē(^8ÚO?íÏÉɒl$Rđ0 –íšøļd/EUiį#ņ Ôâ -Ģ‚}M°ĸĩāÁŋÉŊ―6ÆÞfˆ4cŊUŦ–WGü.Š‹.Ëšœa=ß·'ĘÉųĨēu8^ß°/ÛĪw—sV‘"‘‘ŋ(.–2Þ=mÅP@qQ)_ȑšvdï-U;>üĖãÝBT”ܕþåįïŊ^ðĘWŦ[%Ēĸí⌊Ęœ›R7Ā4Ŧ]ĀĻ6o“5€Ĩ€ „mYūÃl‹ÚŋĸÚōĩĪ0‚į—ó˜·­‡Lt{ÜOĩRę~ĸąļ1ŪëG€…Ü*ä8WEgAąDcŠš˜ƒILjJ| ‘‹Ą‚õpîô)/ęŦRĨJ”Š2ðwëŲßėÎ]āP+ÉAŽ€ķUZøâ˜âðc˜įqåwåʅ™_ŪčZą‰áņļÜ.ÓēŠŨ1ô›žųŧ·o#ˆ‚HƒÛągϞ=qäĻiš* ž$åƒpõ 'DD Ã-ĘĻĻg°Ė@d]âyAðSŦ•―oô·(.z…Ã―sKïýÃ[áÖŪ]ûŪô0ęĄvRį,] j#b(~y6Ew%\bÛō°ããF^ķÂãcĒý‹û…ĮŽ)^ðØŠ-ŸýĒÉį·Ū~ķϘŒč3ۗøå1g`•zÍĒĢÃæŋļøÍãûķ č~܏ĸÂąÆDŊUČģĖį‚ŠTšĶrQŪRÁâÂ’ÕyÖĒ”fŠ* ņ0B7n\óŪđm†c·―~–@Ā'QŠÓJ[°:Åk5……Ģéá퇇Fú]ļqpņũï―tðræÕŦŲŨââĢƒCä}õwōĖ·ã n?ėö‡!đyyßïŲíõũU°*°\‚T&€™E 18ĖŽð[ÓÁï#áž+16įQ,P“ïLķpáÂ^6EQžŠ‹ĀĒūc0ΊBâ*ŨŒŊZ'ĸ+ŪJ­ĻP%ÐÁŋ[U[šT•īÓĮŨĸœ$ģö†—\ ‹ĐŦįš]ÉWsn§@iš_™6mcŠ Ŧ§3ĒIW/]ÏpC -QĄnˍŦĮėýéĻݏûņ_™jĄŠ%DBĩ€Č$ÆRčKV€âŒ…–Č­ŠœbQčZb&ėˆ+ŠĻō(gĒ$GœÃz§Iē^þ— PØ:ĐkcXfâÕ*%”3=†pƒ°ĐĮC-‹9ÂtšôcöūMI[ČÜUŽx,ĢLÖŠČDþëBČŲ3§O˜DEĖÜH°B8åB[VÍIąĄĻ \ Ĩ+3oîXęE"y jþÎĻ[·ŪŨŽÁŧæøCÅE?Í ņC:ũŨQĀ/_<Ô ÅErWÅÅFūö\õɃû―øĘŦÓĮôï7ëØsӖ–óC åËmyyŌk6š Čņíĸráô—_ũ܀C1Íût*‡hę+CšNøā(BhߚŨ_˜úōėiÃ|tų‘Û ûq?þ{•―Ä$h‚E*:8ŠĻÃ0)ïĶ.ÕŽ14jū)•zT❀Ė*ĶeǚĶÃŲģ§Ož<éU­–"â·Wē·ïáœŧÝn1܇ }°zëŸÎĨ&€_Ė‘…1Ą’€k^ąIĮ:―@ąÛÁģ2îÔR(·CōŊĘŧĘÞûýũÉÉIÂLŒŠŽ F\ÕuņŽÄ‘ØéÔMËR0§\QþÛ`ožĻ  °-cĶ C3…Ų†įĒŋ/žú–-ZīPå Ž–Š‹å‹+ŋV\žxō‚ÃuģPd…?P\đ8௯SW’rIf°Óþzösôzĸ§{ÎY]d+ Q ”īQEK'Ī\Q{?ÓēUąĔg'ūfE”AŊŅĻĒį˜›ÆNyg`Ó:%ÐýļĸÅ. X‚ ĻČ>ûJE˜}QfßJAg…_ŽÂ@úšÁ›īe+}]ĪŠ:øÓ~ïāÅë úš;LÖË^F ‘ëĘk]­Ų‚/WĪįd&öĨ„%­Ē hĸœi˜ōđŊŋņĸ†ô%ū;ĐLķkOœ8qøįƒōQ˜haUuPK`đ|td$Ņsá:!”\4Â(a4-oÎ@Œ†(Šåsp@…ŋa,ö'#CÛ6­šeۏ›ķ}WðÖ ›ÕŪþ‡ŊS§iÛ:°õXŊ>kVžc;C[īéü›:ąRŦ'*Üá(]­>‚ˆ)YŧgÉÚč~܏{@ŲKõéx1Ž`+Ž+1āgAļL@7ļysŽ`IĖ4˜ŲØĻĀĄ‚„%`§.wÞņĢG―æ !!Ąó‚Đö7„ŪßķÐÓT!ŧ™ÅcŠ—Š*š7-…+ ‡^†TŲĶ–]§|õ Þö‚iČgÝlp{{ũlKqđ\~ܟ)z ŠeŲ Œ‰æ,ƒ gãLSUéŠ9p―G>ÎųāŽKĨJþ_"ŠJ*T(]Ū\‰Û/cüU\ ‰)ýÄócŅĸp܏ûU­H1P2ĒøTŪ…+,~åNˁ$ī(*XŌ> ‰NZ)ržÎRE[ÓV0NMNņĒūJ”,Y0·Ęí;•·RĖPÓ4ĐäB°2äĄ~ŧũoÎpÝRt[%œ DL—1dĀÐĀïØJ>ë7uëh Rĩëv,íí*Ÿ^ÅáC?XÓ?M1 CĶ„ĪŅT #,o0ŠĶ“ƒs!Á4Î cKŠŽkšĀÏQSĀqĸKūã*šĸŽïˆ";9RhX ذ’šÝĢáž6Ą`”XH" ŋ21’‘tÁš%ƒ"NŒI1Ž*>RkB$ÅD„čQr™=-[üĮÅ;Į6Œ†ĪĘâÁƒē23åĪë7ÐZųÏÛEŋ|IÂīŒzåëŨŠ|Ā/Ywæ8T—Šzˆ•mÔŦ\Ŧqí’‹%OøŊ# ūôíšššīŧ―%-čczūƒ–ŊÆ`Ļ*Ēӂ 4U·)•‘ÞýˆK-`ĸ2<&ĢĒ-ƒþĮ"#3ûÜÅŦĸ~9?ÏŪžģ§O9{îōĨ˗/xUKÏ\š–|nũķ/öœĘ'™`‚Ý™ÉIéŲüŋyŽü/äYėĘHJÎČSšoËŨ?žKcyWŋ^ģ9)ÓÂäŸj…û`š \ŋī@rÃÂŌâØ‚õŊH=” 1΀"E%쐂ëÅ` Íŋtņ‚—žt‡Jöũįcų­RY„úûų·nÐÜš_ĒNī€võ@íšÁA6ĩ7·Þiãöęĩāģ $bÅŦK{ôÐ!aD lcے>Œ> ļ6ČĩĶiBžU)ePÛ"_ÅápꔊUõČāb‚}æĸ øįÆĖėŌoĪĮ0ŅŋũCŅīä įįLŸöŌŦģF>Ûkäčiģ_yyņÛëö}ļlîš]ö­4ĢéúĄU3Į/ßH‘ōÉï7þÂĀ(ý敛î?]ÄŠŪX9uâŠІū\ôō·.ážcŊūôΙ‚"ôÏQ‹aæ č% ŒdH6‚Jē†hÖZ”b&B!ĒÜĢķ­;tđö'PÉðÝRÅkFsäðaŊŸkūŽâ ļ@ČĨTŒuŠÕt:üĨ˜NiTtô“Ý3 ã.ýŲÛˆOÛRilįÎí^ĮÉ[U6•)Ė9ÚRáækšķžx,Œ0īķÅð€ĨĨÔŧ%?ĄĄ °ÜÃîÁl{ábæÎ=WRR\Ļ@L~8ēųãOŨ=?ĻŊŪkč߈ûA-+Šx‰Ņ/NQXö’ĢyÕĮw-‰ĩĀco}ių#ӓkØþþķi•nÓûiI@ŲvđÜÂŅŲá(ðų žíÎs™ ‡ŸŸCSĐeäđôōŠõâŦsQÝ<=i`Į–­Ú=ØųĐuG2ėœS“‡<ÖĶCĮVMž}ÓĒé‡ŋšßüËO=Ų·y쯓ßüāåįz7kRïņŲxTį‘Ŋæ?;nVŋ'ú4iPwāÜÏrŠô·į ļýCmZ5}ņ­ ĒyŪ˜ðØS“'=ņ`Ŧ†ž#ÅTą‘šbú°.;6|ØwįrøæëO?;aڈ>šÕíÜš]^^ÞíkĸĸėöŒ,KT·ÛíÜžqC%ŌxœIč–ļŧbyýÄŧ_į˜ā+ˆš—aų‰Ī+ŽeōŒšĶE #0Č2\ØūŨ"5-7%Ũ“X.^q8æ0đncGķËZīdđSCÔnîЂŅŋW~X2ýĩøŋŊyfÓāgzM˜õęÄQýßÞr>ĸ‰5KïúÂélûw%Éޝ1yïĨĖ‚oîĩÁý7‡-åÚå4—ýũf[ÂWņ€@Ąâ‡ÞđÏŋöĀ7Æ5þféû—-œ{õČϗSt…m^ļx{LŦũŨ|9葖 5å Påî/–ŽĸürÅųŦŋøtå+͋Ąw_ķ-§Øį_­Ÿ;ŠÄ‚ŅCf2–vníŠuÍýú ÏũÜÖŪũ‹+įÝõîÔ ‡ÓÏ~·xŌŧŨ_úpýGoLøfÉÔOv\ÓTÏO[ūI‹îžäõYa‡>úášyjãģŋÍXķîË%.―8ëcÛĄ\üi۞3Ž KÞíhïxÏųĻō ;UIė0rưg:*ÔQB …ļ?]ģÅĖ=ŧęÍķ~ņųMÃ―ýÓũCËWð\úéįŦĐáĸ&ķ`ï™TK‘T&ķ·lQ‚Á[‘Ú]šę`Š6$aO–Čŋ‚Ũ ‰S",ĩŊ9ŌTiŧˈ(ęðū―ß§ĪĪHßïüöķą˜ˆ‚ĐVnČôįMĩņ11ŒąwŠū]Õûw§[wãMÜē1}ņâÅ―{viŠ‚äubĒą,Á F>*f\ÝÁA|RČ|i‡)C”+šÆ AŦ`‚‹nŒAĸc”/ĒxO…eZn“f{ØÄÉ3§Ï˜›–íqŲčãÏ6|ŋ}ûƒjŲš}nN.úĢpŧrsrr=Uü"qÐbØ)ÕX9gâoNssóŽŠ yđ9nÃĪöoŒYS›[ýŲŋÚšek·ú…„ëڞŅã^ØīûüėI ÓáÔUWnvž)ģjXũ#ę ĶfŌôa6O1LŠþIaæŲĩz ŸÕ§qĐōō Q5anÚĪÅĀgęžúīGũgÖđĐ)DĘxzrnî[ĸSŸžý(_īdL˜{ÏÎë mŸ*Z·]ŊĘĄyŧĶ0Öč>ö™N$Ä&TŠÛo䓝ʕ(VäíMfÖč0âņN5j5jÛĢvėõËĐûķlĐÜķ_ýĒ%Ŧ7ïU)âðÁ39”‡UŠ9fpŊ*eJ$Õ6Žlĸ2ëōŅįíþæ[KsŅð˜į'O­SŪlą’æČ/"š˜_X\BldˆÎH­f݂Î~ģîÃ%…ïý@%ŨÚŊ>Û|ūú쭊› ÄĸuŌāBEÎUL~ ›E%*$ŅÂÅ,å2ĐÃ9’‰Ņ•[E@-8m[FDqGaˆ%Öā–e]8ník~>tČ+–ŠišŪëŋÛ7ČßFRéÕeŧvŸÛU$!ĄBĐē%‹ïÖū“€ē"tũôz·ėđýYBÄ+/oŨÎí9ŲŲaÆ8ī\‰EE/€@šj;ˆ;Ž„–KʑJU“ųÔįdŲ*QußLčōĀ,é yÏ ĮđM­\“9qbõŠåkŋ\āÐÉũWۈMHxŽïsy”ãŧjÓ0wö–Ĩ“5nŌšu‡)ŊïÄ~:†Žyã§ÏŸîŲŠM‹ú<7ášÁģŊé?büŒq̚?PãÁgĮ_ņ d&ŋũĘģĩĩė?čņĮ;õøödÆ/Ųĸō›Ūä=ŌĒâķ­ÛŽ&ó"Q’Ó›óę‹/îóüÐåųϜĖúváčĮÚ4-ßĻũÚ―éål}gåą4ŨūũæŽYŋiü€!+>?‚þþā(? аŐey8Wąls‚FWtíïŲ6õÁ„ąæL1U‚ÖČ’P!ęįӇÅšĻ!…žr !œ{óâ…$ę…9ā-Š …!dZ–áð<Ũ !ONŌO§Ŋ„Į/ž|øgņĻ;ýäõdĸð`EšęÚâYĒ'ËõčĒ›žņÎę[?û|U?Ýc؈cj"Îð6\nWōõ<„Ô[ÔD[ŠNđā=†|Óþ‘AW(4óĐ'ÔVmK9ЭūüSþÍĸųU-ķyiVĄLÔŦRn„kĄ\EÄĶBëĀáÐ`í,š šĒ*S ö˜ÂĒÄ#DąĘ.ę Ėōrģ?ųčƒWfNŸĸúkÛķmŧ™”dÛ4?áÞųÃ.MÕŌ=óvÍÍrg>Øļe“Úõ―ŲÖ0Íß­jïīóöūÁÚžĀƒ#GžE4Xs!ÝKÁX#0ĮšĶ˜Ë9sčÝtĢ-2)ž—-rŦ"úāRŊ6_á^ŽjAqŅīRMí‰A#ãŠkŅüÅŊÍIš~ĩۓÏf9"3\æÝo\ņüļU_z{ýúՃûVĶ“Ã~Gxɑ 6lþ|aÞūũwžÏÃVæîVĖ-ööûóČþö^Ė9øÞĖŨ>?ūlõÚŸjséôÎd—ņK—öú•ėlsŅâ•KÏîßýĐĨ›/!„~\:{UF­ÉãÆ:Hũwˆ$ox\.aęråy,.’Į“d‡OũãQe2& {É@ĘÉc‡“3Ųīb™į'―ÐŧCiŽþæ°(·ËWGt&ƒ„ãöē<ģ ÃĒ~·lþä™Ŋm}ÁŽ^ãЍ‹"ŲaąlTĩYïoß)đĸäeäY,ÚYēęļĨŅö―âĻ2ūqÓæaŠQđýļđƒMÓ,\­Ãâ9ĶfšjBioĖ+ĒÓëĖ]ŽŅ€ÖĩĢn–Š2Ēi‹"Œ—iąjYÜöïRĨúģMš”ŒTóüjO{cn‚jǐbCĶ-#!M>zwåæ]?æŲ$Ąhi Zž<īˆŋiã‡Į.ó„6MÖjÐÂUw:EN‘jžÜŅķßž­āĒa iÐuãwM‹WõiÖ||fŽ2Müøô8Š8 FŊ―R81ÁAĸ'sAa‘MōudĻ­]—3n[2Š ˆd@ ÃÔē}%Â&ôĒPQӉ<ėÝOmÛ§ü$8ŽÂ]Ņ~@sōē=röôéï6o.]Ķė TŊQ#Ō+!.;ė7YRWõŌ‘er]đ†ÛÝĻ~ĮS°―‹(mÁĖûÍ Ý-Ø=ØģgρûMÛŌ5 yY[z+"PĒ{‹tŧQr‹xF āšdĄ­(!X(.s$j, ,Ēęšm[”h€ÂÐ― ļĻŲŅAˆYŽ|­ÚÏķũŽ.Oö ÔüJqÐŧ+.†…„į]8x!‹— Á šYHhČđf>=ôŌÃ3–>3äáޚâT°pX=ęf.cL8ú;r!9ÕsfãšËŨËÐv-Zą3iš8d VsyqÅŧđ.BÓūûäģð66t Į^Zø°Ŋï‹ýƒÃJáŒĨĶd ē~ŨŽžÔŠGęäÖ/°•ë6õïïŽĩĒĨ*"&~aÄŧ+VđX­S-$ĄN}!pkO|ĩš‰5ęIÁo›ēüX*Z―a‰Ēvī-Ëð°â••ŠŠA#\ŽčÃâJF ÏæížÖŽÄ"§ûGTŽÍož$iÚšâÜöÖ*TĪ|ũbĨjļiQ= P…š1ķir- tåZĖ6―ÛΘ’š—FH<Ï4YéZu˜e2†ĘŨÆLœĮÝūCw ŨĘ}į<4ŪD­ÂČ[§q@ėYxņ*‘ð+ŨäT]ĢZ(h<ýģ‰đ‚ũß3 ļE \ ((lÄ}]]EÚ `ĄœĀE+"U‰DlYTrØ =\ÓīōsŸĪHčšč<\žpÎ+õýãþ―%K—ĐUŦN―úõ―>WRkFŅRÁdfzzzË-%ŦâNU­Lē·§āüũß9 jØķüÓ4MX9ŠØ―sgŌëŠú–uŦgĖL“b8īĻô­ 0 ŠŒ­ƒrU“`[ÁāðnÂG‰XŠ/‚æ: čž P\TÍĪĀßŪ[§î―:Ĩæ!->;§úŠ‹Õ>ÚeŲæÁ}ûŨ/WŪM G aØĐEŠG}―ųÓeyaWhöúOÞĐŲL·<.Ę}ó2GéÔŋĸĶ‘c†=?BGŋS+°ĶQckéØjōóÓÚ–ŲžéäÃčĄĩë7”2ûD―ĶĩUŒBÃýSzäfŪX4%uGĖŽuÛī(ķÛ ”Ï€bÅB^Ÿ6ĄðøQŠCgˆ‡d@vcų Jã·öPËĪw:ƒ,‰eČ û+3ÛĪųūHnY͉ŠÚqōÄÖ~Ēa‰íw―8,·lËĖŋNÃþģzë^Ð9âķ+AœýÍ[Î?điēūf € ĻĨIâ€BT·,,RŠfQ[v|z‰LTv·™HķÂDÁ 9—r„åės˜@‰a$øT;NŸÞ%tZjJrRŌáŸúėãÕÕž*ŠĩjWŦV­xņâ2EČA<Å0Œļļļ‚·ëÔ@ČįýōcĖËēõfę ïķišŲY™Þ=Đ))ÞŊœžÛ0ó\yޔK!ģÃ$‰œŦ ،V5]Þi$&ÁĒĻģEĢHÓ59…ŝÁķlą­ >ˆ-äB͔]f‚î―ˆˆ‰ gŽyU1"EđōӐNøĨ“œyɑ‘Ņ#0ąÚK_ąyëþlS)QķDŲøaK*;ԟ™ŧīÄöœąezvïyęjNhÅ2+晑N!ņ8rņÛ^ãÂĀ ĶŊžņé‰ģWBĩäag9JÁųV§Ŋ%Ūĸō`ēkČKËÛV/ý+-~sj‰@íwßʐĨïg0ũÅó7ŦŋöXëzĨ2G.]T2!íųŨ—WÞųshýŊ†ļáD.‰9ģĸ™ ĒĮþcVāg0Ęĸzĩ>ÓlÐHīĪ’J)`tHūŠ…(%ĐeĒ™kDd Š`„!ûČ^*n‡§i"g /‡•Ķ8!CšC•r ŠŪږ}ãúĩ›ëŊoßšÅŦ%å-r―ŊíUXX˜Ē(ĮëÎâMļbR-Á‚0MÓŧm†B—››•••––šæý?EüéĘËóļ]ðPvFFšeXDŽķMaÐįĄŠĒؖ­ĻŦ"§Ę ÔáÐm›YÔō5ŌüI ėˆą!ÂHįpį’žlâS‰eÚŌíß{đlâU\<°yĮ6ŒpÁ~idDhóš EýâĒXļM‡ÂŋØ …‰?ý‹īïTA$–Ý0ĄŦR]5—ķ ķĒHđbGlIĐ=ĪqЈߠ Š·ïZýw^,ļjĩ;á|õŌ5…fcÚŋė).^KD`d‰‡:—ļïofĢĸ\`ž™|9ÃÃ5ÎĸõėŽÄnOũXQģÎïÚ~DiÓū–öėÕJbū\žc°Aõ­‚1b9"I Ēž UiNSBЉŒ 柎įe.–âŠē†:—Ee"#ZĒų IZFË^§eģaxîßwâčŅ­›7–-_ĄYó^ģ€PÆÄˆÉ›vÝnwžˆÜĖĖėŒôô›7Ŋ§ĶĶzŦTčļ―KoõęýÓē,UUe&Ƅ80ÏŦy7t]Å>tė ŲũJĶi‚{ÂļOÞAÓ5!+%Ō1aķ@€U4nmÓ„ˆâ]ZŽkÎ84ķ„W“>9s žÆ{-@qąâå/]ĻņõĶĖ9uîfëÎ―ëÔ(ŦĢûņßXQĖĩ3‡^l>cFĮR‹þJ~HĻŋ'7CrÓod›Ž˜Č„øoRpÖéÕ3fjÚŪĸyŌāķmŦšF@€Ęŧ-åŽ,ÓēđĀϊĻm1á o€-ĐÄ Üu‡Sīj„>€&†f6ČŽHqEËæR‡…qQ3*XŨ–ePĘŐHQ|äWĄ&VîDrϜ>uáėŲßm-VĒDÍZuž@…ītïi))IÞDëvyrórži—ßjÃĶT(ļÁŠ7LÓd”9~X Ę,ާķ*SĪāŨĘFŊ(í‰P㌉Ōė)ąE-™!DÖ6ÅĮIYjŅ""$!!)‰Å[•íčP[<‘pŒ5U5-QņjðņRčĢCđƒ2dXüŸ‰BĀčũRА7ūÕ7įĸņõ/RŪfąrbÓēđÁŅEü;ýz"Fžœ7Ņý‚œ2…`˓—빐âðũsčŠbšō\ĶIÍß_ @‰Ē‰KĄ>ŠˆjyĶŃ·<;…nŸ(›LÃVjþˆŲðäwø8uEÔģŦ„åäļt§ŋŋCÍUJbæåzŸāD”Ųb6ōÜÄ{9þŠ‘—ëōØšŋũAU€ī<Ėŧ#†sŧ-‡ŸÖĪÏÐėč“R8ĘÍĖ!ÁÁN%'3“ŦþþB_…ŲVžËˆäįT•ý/Oy5ļŲGÏ·ós:5 {rēÜķ(ÆójˆŒ™mŪĐi ƒ˜ŋ?Õۀ æ"@,AZdp•XLąåÐ @ Ï‰RƛČ'2ÛVU  ŠâģFRP‘1ĒŠĐšM-EIPǚEq Õ1ƒ2#Ę98‘ Žyn^öҟgD`MŒ8—­ pŸÔ4‡Na™OĀ"ÁīL…ˆM ƒũO€ Ž0.Öų8ߒ€‰—FŲ6Å`Ïn3&ŠP.(†eŠÄIôd”?” Ve€aX@oXŽ:.@ũgšŋĀ_ðuĶП‹'ųę`ÎÔ//ĻĘKR5ˆíÉĶFŪ0ū_ČY6šŨÍQĢ”óOĩ5UÏŲýŊNŸŧáÜuÝũđéOu,s|įģ^™z&ş'6_6oltúÖQƒgœöð„Ō•^[žāОĄgŦų`éï?þæ…Z+F·ÝĸÉKówå™Wy}Fj>>kb Ú{Îîųó^Šé8īzÎKë#WūĸļfšˆčŲg·N›1ýĀy—ZĻÜK æWÓ.ŽŸģ såŧï6iQU&Ïy顊Áóf–yôðNņĖč9Ģ+õņčq;Ū%Ý<äę1{AÓПFNzãĒ;ÛQĪî„ŅÓÄ_œÜã…ðĮĮLęÝhó Ŧ~,ķā­^‡6tĨN|õøėWŸ~!%>ðԞ―įĢZŽëýņŧïŸđRaÖÚųË~đō•)ïnÅđŽųÓ/My,öíí›v_Ų?ôäŽ1óįųdôëŊ_đîßĪũĻ ƒ: $Ķũ)ĮÖÎXšÔīi•âü·ŊûáõjsFuV9û›S­ ŪÚ@ø„(E5˜i[bQJ 80PåfČzŒB3Aä5Ųūõ,8â ˉAļ‚·­2°2Ė—V@·žc)d@H—Ä‚\FDžbōlŠbcXĖōĩ%Îėp8 ÆŌŠÖát.ˆIe‘"ą‚"@™ °ĘĢPnëšÃē,ų›.“/!HW5/ Ē9ŠļýY”Č2î !å†!ÏŠŠ ŋðn0H\\ūUĀ3TqIÐĢthNË2cšĀ&#{āōĸyđŒMyŽ›i*ĸ‡’ÆþMc9Wũ,5ēŪ—zpVõĸ0U ĸĐ'þ­ ßīþŽ4 &:qÏ?|crÓOū\~eÝĪރÆÖŽ0cæøÉŨĘ?óņ›ŌĖėPû ýŸw?0ėģáÝą;/Lģo\lóրŒKG^ņ{éÕ>™5lĄn]>ČžtdßyåĨUoÔ-œ6°Áýáų&T{w\ŋĄƒgmó"œûWë?õđÐÜĮ?yũ§A‹„pûę™O•2ą‚/ÜyÁŲkŽĸŅķó‹yÞ~íÏz>ķxýĄ.ŊÚæË>“.}Ōų‰éŦ>·ļc•Ō™ :LÕ=’œ~rÐīB/|4ŋęŎݧ7ïō`i‚(EqÅĘ]=0óģúVjļtŲîĘÃŧ:Døwƒ―TU‘Ó*VÞĀõâNB˜%EŠ!@6Ą"U‰ęÉŲ‘hɂ1ŒŊƃ5&°6įÐU Ī hiDSu·á&BV,[ ÃCˆĒéPðŠDŽ ‡ZPÕ D4(ĩ9—$úđ‚–&vJûÆ9ÐŌ,‘R ҁ9 ›‰SĀ›‚EÆpÍķ,0 Tļ*°Ā .IBž`B.J^ŒÅrKšÞ)P íl]ÕĐĪ7p ŒļMÕTĄ°c‹ŽũĮíƒd ýėt83ÝIÞýũÚ?‘mĶļ]~đ:ģĢÏyúėÖėóÛ UčDíĩTRþcyčM ˜yX%扔Éäæ{:įL8Åäþéøó•=&ČLۓÔm|ÏÄB!EéũVŊŧw^?8~^Ïâą,&*ëÔŨûύ]ܧht€m‡b`L‚ārU%€Ępģz‡aOtЁÜņ=k­šš?ü‰–ý>\p ūÄÞ+ĩ>zĻ’y !F0ýnÖ˜Ų†q.Õ,ÍDģyLãĐŊô/_*`ÐãÍ6ŋ‘e –ÍP§!“šW,ÍĢŸþåÓGŪšōę4ėÅķ5JŧÎŊ?ZaŘƒIŧ>=æ>ŋōFŠÖå…gė7`ė UŧšŨŒģ념@ ôÔðØįÆMŠRęfxĄøĮi\Ĩ؁ręɔlÄQZŌĄ‘]įųY§LĒļ‘#Šx@˜U4>Ę<ĸÏFvĄ%#{iF–íg‰a æÔÔ"+?Ũ%qöÂĩ­Í +A5&4Ј8ûû‰đ0üĸc‚-ë‹ô*Š<) b™āÜ— + ”mĀ”`MŅĪĨ9Xj Z€RrŒ@ĖJmï—ô&0,–ĸ*B"WzAĄ\Z@‚ҰTýũëšĶ`Eä\‘1ȊųĘm!RN?MÎF’#‘’ÞŪØ–­dU1 Cž)Ē`…Hœ Ē]ŅeJ…ķĩÅĻĻ[…w/ô7Ī-ž;Ķb 0FšĶs†á(š+ЇeœÉá—/}ß RĢōŋũ†bĖc$’ŽĄ}J.šÝxÉÜFKį6ōþđ|~“§ KđīQó‹‰*Ûß=ÕräôÓ*Æëáú}œqŋ0įāa՝˜ÞĩĶ—.ĪȐrO|‘Ā‘‚#·ïšņýīšĨük—ô+B“Ũƒ+ņŦ[ÚŋVQgĻãïRėãˆ8"ØĩŸŽ\š9ŨgĨāøb%ü eí°›ē["—M„ŒėĪO]óŅ+·ė]ėÂæ[Úô™EU&­4uc՘Qküę/[žĻa‘HŦŠČÔI7’ģBûœ0ýTî\7S…ôDĘĐc.ŧL‰(qO2=†Ð—u:3Oí;ŽNūpˆ[Ą”yzëæÍ—ŠUŠôÅŨëÏfZū;Ų-" 3ÜČēMÆÝ‚kĄ@DT?ϕÏŋøúÓ/-œÐõ!?ėpčČķ›Wē)FDó‹bz‡įæ|ķnÃũ{ŋh˜ Z@ð˜Ī}ŊAúé}ÆŊĻÓåÁ’QNÆøß.7ƒ(P§°›ZųîŠb›sã"ŋĐDyÖ4Īč ` Ũ,Fd,  ŌkĖ@U‰g&ŠĒi>ž”Þeķā°R:ÖķiCš'ŒrĘ)&H.Ė!qs†Ä8‹C+@! (ŠÂ‰ĸ0öāb–―Eãō>ïŅįŧĒÂUt@đļg0iĸŘlĘ"‹ŠPU.CČD ĀFâú‘HÖ"‡ƒũšŠéĶeÚĖ–}"Ę ķ…Đ i›0UÓ$2MŅ܋`/jx ‘ĻŠYXÏģ4ÕÓēÍŨ―I\ŋv3‡Ä9ŧk“·nųþsq―*éĶuũÁ  õk^+žJČÝfĖ”ōķÍĒ^$$Č ÔŠQąíŠ…Dkœō;6ˆĶ ïģøŅČŨã‘ðbnqÔšAä;OĮMíĩĒ_L“ĒŠûï˜LЧÐÓÝzœþôõ‘/NvÔ%k>ŅēNƒŪ―›Ū˜9zؘąC§ŋ}C/;z\ë5ģ‡=?S_9‘dĮÆ%Ū]þ B!ššdîŒŅ“§ ĸn•―KŦķĮūŅTĐÞŋuý•/š6텉‹ö<ŌmhīûĖ„Q#üÛÏÚŋįģ&™_=?ma6՘å1)—38ÎĄūõļĨÛU ‚#(NÏ\ûÖŦ}uĀsųČįJĻUóÄ; g,~?7ēî˜ÍŋzeôėŨ^uî+GÓϊuÁ8ĩœ‰õŸĻ•p“9š·ĻŊS‹ĸíH.bø­ŽHĻ˜ˆp {âæĄ;dÍ/M:ĶŌT‘M‡îPˆjZ&FŌÓPˆÔŦ–eÉBX%Ōw pŒáåĮ ’ (ĀR,&[ŠeĐĶé#·ZUaâh@9TJ-Ș*ĪQč8c€^‡xĒ·‡XƒWä€rÕLÓPÄ߄qĀÃÂ^ą%õšŧm 7FTĶxU§œŠ^r‹2RĒ| UŒã°iz8Ðę$YÁPŅCÅŦk[•åŋŨĘZjŦ„eŧ龗g9œÎgžčũŲg_ïÝąĢkŊGëVhŎ<5 ānÄ^Gŧō~šŸŌī|ÐR’9q(Bš Ū87MAėĨ94áTLĘÜģļXËëÖœŧMĶjÄĄbŅ’2%įŧ=i'ĖĨŠŒä æy63(ô’ qBFđIE‚ņŨąm3gx@ũĘŽ•—ŋsŪQĩHúđĸ‰m‚Þ]wuų3퐖“Ëœþ›Ä*Yí§G}XŦîū7ĩ:s4ŠĻ gGžTŋÞŪĢŨ3œQĨÃJõ{õír;.ÜLŨCããCüKž·lÛOx‰ÃÆd™aķÍLî*Úp@ŧzą7ËTŅĪy‘ `wi-kTĢL$cŸþ„Iڍœ^ĸû,öøĢ=Î_JōGéf|ĢG;<LŒŨÚ=Q·j)„ÜYĶÕŧëƒĩ*Ŋ]ïõfj Óî3m/”ČÅ(&°ũėŨ+îÚzęĶŧúË}šÖ)Ëģ.uąžr­šL%óßüčЅtná‡Į,s‡Å›]ē"ވÃd1ãVŪŌãMwýV3­ļžpųG?žH.úÔãÝÝČvh%ęŽúčóY4sį#Ŋ-(ýýÖĢrü‚à ûÛ!Õû―9 9Å8Éá(ĄÕā=š•ē ÏßöIDwpŽ|eŨ(ކ1‘lđJrŒĪŋŒB ·pþB `Ã2„ēŦ*ĻĻāðąŠ‹ē- ‚yWĶ*æļėý`Ÿ˜ĐSęÝĀÁ؄.ŠŠĘĄ朊š&'W`/ĐøÔ^`ÄfØ&’Ô ēĄ*Î-óŽ 0WĐÅ%:ԈSāÛJ 0ĩ-QwCßŌĻB ÝsQƒ;ÜÏĪŠ(č™[å=–;"·‚!kŦPï"™Đ‰*4z@ðW—ð to†ĪæšüüéÓGü12ķHŲ •Þ[đ"ŪpáĮú>ûóþëwQôXžz9ĸ2üûSF―’þ% ĐįŊ̇ZFõŊ ā`-ȁ~ÜvsäVWX|ЌG#ËhĖHTÏõðMĒžŦŽ‘ ýÔwɋŽYCšĮ”āZÞą=eúwyĩŦ„ķó :e”Š6ïá0ÝĒXSĩ\wūōžÁĩŅÆ6ÐÝOŋ™ŒKGŽė0ëík;M;ŲĀ11~1–#'Ų8—LëU Rē­›Ļr1gZš‘–Í„õĘßÜēpbÕfÅŦc § iŠ·ĐU“å ĶÖhØŠ&€R…uŽmßđ;›‘sMW‹iÜēĢOĀ#wĘŲ_%w~ĨS˜J #ŋQÃī čæíM^ĒlóÚæHÅŊLå– +‰ßËōÕ^*uíf]ŧÔåŒZ ˆPļR ÄløQį6öŊÞŽSMŅf Ķåᱍķ-ė ˆ)Ó([ĶPŪ–UaĻtÍZB;KŨۃ@Ņ ķDíx.RH‘Š‹UđĻōuWĢæ9ïŨc9*ÔëPĐūžÜ/ĄV2)fĐ?}x4ļÏøŪjĸb.§ÔĒ–ŽtÎe (ãâ Ė•Nq&―cUQÁ0 xjƒžƒÄH™–)Rą‚Bā +þeŲ ™M†!ŅÕŌ·Pį*ŠJĄ$"°”›!ŠĻe!É1'XŋhæÂ°J4j5ĒË2Vũō‰TWu \Āh‹ˆ)įL6m„īhīlq€ĮĮÚnēĄ+úXą-KŪRUšđ0æN·@ RQÍIčiŪŲĒb XęŦ]9‡–­Ā<Áõ‹KEũ\)ĒhЏņÚī Ŧޘ_ĪTŲ”ŨO˜’ĨGfļ/ÞED‘s҉ŊY2О1e―ĩ|`\—D}ÛuÓĄáøheŲWĐņåÃZTũĮŧĖþ­#jkîV§'T-ôdM'âÜß'Dkß~—ōÁ ãą‡c+ø“>L+T"lr‹Č§]ÄЅ†XjsbûpërڌF‹Q­ƒóģ$ÖļõáŪŽ― îĖãJ_=žúãUFî―éʓãŸDhïŪ’xß(Eӟj](ŦÅ­ņ+“ūđNUýMÁĢW Õ ~uÛ+øÏ|éŒx•ö“&ĩpþ"b€1 Œôւ„Ä8Ëī~C Ë‘ fH)s‹†E ē%° °eáÞĢĶâBCL_ jļ6ãwŊI8þŨŠ\l@€þÁm †aüþKpj2Ґķņs_Y_2°Ų?BŊcöÂH4Om!č IA Ā,™›DķB3ā’ŪeĒo k0ļ—vÝ ŧčQūSÐE|Ves†(˜XhˆTUÐŪQDŅhš,qķóģ!a-`˜w‰áô: l&ðŌHHæ*rÆĄųh\9Üà š Ã{ŧ YėũĨNq0+”›P(bT&Rސ[PüB•ŠĐÔŨ‘į1Ӕĩ9xÏ1č‹3‹ý°Dúœį ũdUkP;Սü‹ EUUNlß\§iģ2 Ú EJADßĐũZ8ÆŅū–_PˆĸĪö!N5nŪc“›ĮŌgoÍ:–j ų(ņaÚáýYëOđ?ܗw3Įį󖕜=iCæöLĩx„rųZî—įOwf\SH™ÝwķČg„·íÉÞx*oõ·E1. ’sæd֌õŲÕ /oåLސ•ĐĒÆu Õō7§ŽžúáϞ*ÕÂ,Ŧ YÆËï^{|ųĩĻĸcU qFĸVnžE’#\‡ÃĄi*.@ĐŌšQ!øŨÍh•XĶhī įä!wDWŪP6<@ŋ]ƒŽR|Õßklč@€:Rˉ-V"."t þ'҇ĸČŌåJ81ĸ§HƒKŠ* ú-1!v‰‘Ru•cąÅ ķé“Î" §3 ’1Rũ@”„ Ï*š§šŪAũ•8–9ķ&FbÎeĐ A^Š™šŲĀĢučNÎļ ų2ĢĒRƒ,·@‡0æŦš*hũbŀ­í$sĻŪk@Í"Hô0ã>äTĘņŠ!$jTš%’›ú8Še ĀÔāDg8’ŒðĨ‚c9§LŠ,Rp•iˆ‹ÞŪŠ)ÍĢ`"Þ ;`’æc”Ýs*$ÔĐŲQÁČOeåjÖznذætéõĖ€Ā@­P t0Îï\Õ\ķlHIjl:éūtÕ―ûHŽ îZ„˜Q†ýuŽ ÛÅÅhE‚•zÅa~XŽŲžËAœzläP i8.Ō/’ð5@oÂīE―XŽV$TŊ_Ėņ+ėįÁáŽnĩŊĶX<< Cq6xđâ~Ėōlü9wîÚĪt―FŽ~ņœļs–íæn†(âĸ­‰–7/_ūž’Ī°ē;cÏÎï6løæÐÉËHĶEÁáÉ:ļņ›;eXĪ`ĘgÞžrúė™ģgϞ9w9ŨâÛŨÏŲðõŨßėø1)*øWgÜžzåFēˆ6q§%]žxÕ@ÄÎMŋ””Î0ÎIŧyþĖé3gϧdyĸų Úæĸ(bŪHP.bąJKlë‚9e"—!h2újG`( ßÐïÝŽČU3˜C§" ‹ÆGðӁÄĢĒJMÅ PŠĒkš<`ŒW: x9X–Ī~ųäĩVD‚ģˆĶ*˜pË4(X! Œ ë ÉĐ-4ƀÖ1ÔRĒÛ U…``Ģ!)s#}ØápØŌÅGKĖčč\+Xhâ "—ĸ €ŽTÆĩE›ÚĮuÆŲ-đt)Į#†&–h3ˆiĄ æJō‚ôLéø^‹ÞÔóCHôī҃]îÖëáÔ<āŽpÏ]r“SŨžjāčhꋟ§įäö/U,Ąé[SŠ X-a.ë‡ÓyÍGÎũŒˆöv2,L”ąSĮb‘aïïɝÖķÐė.Zhą ôËyû/[õ*b?NūîÚÕęÚ2&Ū"KŒuŠ9Ūük1‘ÚĸÁčš~în‹SÛ<7ĪGôäë{Žäõé<―Mq8ĢóĖ#W­―7ēö6óÚ%ĶNšŌ(˜vŌ•ĘņßÔ? JŸóԌuëöĩ|jƘ-†Rö3yęÛšÂnä(g-|ü2Š•ōÆė‰ŸŊ=•Ëō*īðęī>Á˜rŸ ývþČÛs‹ö7ĖāAŊūÞŠXÎG^ŽØųL#ûR‘š―ū22Låŋ€ ĢĒq‚MjÉ3(Cû˜ d+æ28LØl.ž%rĢeŲ0°‚!2#•ö†éAPĄJH{Ŧ"Ãs”^Å#ÚULčuÉÎĩX)ĖAF –/uj>óÆeËqQRHŨÃĖ';0ņ~°l,P Ģģ{ŪŠåÄ/čfĘųä“GKW*!ë*·5ä§ð3GÏ_:{™øUļî‚Q6įýkÉiĶĄ+~ҟ‡]ۓéŒqkÞ'7v”pÆvô†ŋȰDĻ„ïܗúíã|}kݍŸhW9št õélWƒĒ‡•ûøŨ‰"xäŠ+û'hü™%yĮoØŠö·} Âk·ļqéZznžāoZfPĐ&Ŧ>č0·s“ũ?ŲŲŦqų;ßYø^ΊßTČÚØáĄq>Ô|pý8ƒ29?ČJ:WâáĐÓ:ÏÍģĒ Đ& ~tÄĖŋĄãËjt˜üÝsÏv+hÉˌ°'íðŪĩîïšŊÖĢĒ™ttõgüxšĐmZ!å[î0qÝ8Еk1ŧ_ݗúô|}uÓ6Uz`$Ŧ öäeįÔ)4›2ŅT˕m`gŋãWí]ĒЂ5…đhG*‡F=yY.CÕÁAЍĪ–ŧ 4TX Zn7ÅõŸjĄYĢ`" [čiB›VņÐŲÔ*ßī–%*Ĩ‰rŦČ‚â–STTL€MĖē5BŋÕĒ3ęĀ -#ņBĒëĘWBÖ°Ōaō”G @Tsą[Ņ*e ėžlJEåŦŽÔÁTV—bī…E_U^1ī/ŒytUôĄĪ‹ĒtHƒ,5ÐĢ\”HXž"wĒcäCŋų’2čtĐĒŌGXR|R|tŠÂ f6āxŊ‰`Āa̰ €ūū8,f„ũZUËņ ūn}sų}~0‚Š‘°ā;―kÎčþģ6L;å͝ŧ&„„ˆ@-ˆ7RŦé 6 úÓɜC‚s#ūÄofŠq 76―ā:vI}x‡‚oĶŨ9Ōœ›cn=hŠÄđFŧĩH&œ<ïB;TL=Öũ§-E”Éččųžã\qjj!wķņá.SA܂=ý]Á(}ðÁ6™ĮwîĩĐáv†ÅiĶ™qíb )]*AÃčĖũŧ”’åËĮøĮ·ïTmúš-Į7NJEÔcx<™þáņ%J‡ØĶĮfJLbīĮsú|fLÉ2e ý íŊød}ŧoãÝ+\Û―7톭 ­ģŧ—mä՚”ED *WŪRɘég9C|dįgs^w!‹Ū2fęĖĶĨœïŒŧŨc™7ön?_xĜđO6*Ę(wčlÛōŲ+žýÚ31ŽŒŨ‡VÛ íZM›5~ĞsnĒęf,éŲ ð†·ŸsÖ}þ‰7ŋĸ•M7FŽšąå―nÍ;—ÞhėüŲM…jā?9ÕbøŸYœÜēózŒ}/DQaZ… ':;–8#&6ĢR•F ͘í›đI!$Yž ÖĸBcīd Œ" – Ëj7†i`,ebDēmdB,Éā"ō,Rl!ė…nYšM' 'øeĮ DD[@åĀÄŀfĢ[ĄT+58ôä8‹`ė”ð2›ŲŠŠJå.ΆōŸayOĶ `+ãÁ―‚:4e"dCžYŒĨ~cė^T]Á4Ļpn@ĘIm Aû3ŽSß&ûvï?~îŌO?ïj2xÔO[OQŽĐëėПbäëPÎ~õ؈3­8üތĶA6ŽpIîÉFωë1éë§ëū>깥cWėþdpƕĢ[OŠģV~XoÁ€Õ›ũöiXŒ―ģL•ō?.ZðãåÎMŒ}Ŧ~Ė™ų\اóGíW[}öÕģĮÖÎ~nĖËU>|)åÆđ+Áe„ŽœŽSWnšœXŲ7ūßüų‹ÚU+ įŸ]Õ„I8ĩ(@ƒ<—Ŧ~Ðó’y–Ø*[íK8aē`Ē―NĻUežÁÅ'aƒB€ļx"L4ĨLŒD˜æļ E8”'e(˜ŧ‚ochõA“Ã}ė €ũbÛ ø œMƒđt!ˆDYiđČlðÃÕZą[:*B3šIķą)ÅTUÂÝ`Ę+ TŠ6H;KąláԆVbĒD›5ļ ÎlŅųŽ>RÄ š H‚Ø[–ųo2‚֔$â +Ļx?_ĸV`ū)Ô6EŦÔyvjņČ_œ5ņšo=WŠýØđ™sį>Ûąhú4LŨBüD0 'Ļ›z­‘é9ēíƒŪÏĐØâÛÎåBœ…Š6{čąrĨâÆÍ_īšY―ÞÕĢLYsdQ\ĪUvjˇ+ßīJlví#›#XôJQ NYĄ’ėZ‡g-ŋðÓæũó‡&^ōÉý7PŅ:7 xöąöŸ?ųý5“å2ôčĻɝj–ßę%[ĀCŌDãhÝĄøË_ŽŲ’…ū‰iØīz<úxĸŲîãį%„…Ä=ØąäËcŽ_ICŠĻb!R0*ôļë?ŌïŅķX†EųAŊÐŽq%ÝÔUā€IčœĻ)1†ĩ9*­Ā<‹ƒīĖ‚išä†Iƒ[hw3ôYQÍÎTŠnU”ŌmŒ€yĒi™0/‚V&̉&hߨ·4nLÐÜ- J!o‚Ę$b°―Nī†iŠUSMӒļH”@r•Ā%&Pžs)æ đÂāâÃaõDĄøE’} R<ĸiĀSð˜e4ÆDu/č}Qô+ÐĶušô%Á_‘ƒ`īČņŋĄ,•įaíŠÎ}ē(šĸ͑“•fSĪô'Cĩ8!bø`baŦU(ątLbéÜüW|}ÚCYqķïûb›^/d^ÞühĮšTķ2oü|:ŧhŲÄ`1ŽųŨiXŦTðŽ”,AH-_9ē|Ő"“<“úx­hDąöĘSŠ<ŲēdóŅ3ëũxŊn7LZņHmZŠ\óķí/}ązԚË/õ- ōBHLĒ_NĘųKÉ ‹ŧpúdf`p°ŠEqÄL.xØLÁŋ amþø3íÛ>;n{‚sėŦSĢBõčȐóĮÏĒV‰Y7/]ejp`@.ŧz%å‚eļũ~ŧ;55ÞĐ ādˆ_t'ãĸc1‰Ŋ’(ü[iƒņ R€ĩ2ē"ÛQ‹IQZ‘YęĪišä}!ČI–HpX (e)KvNązēHzsI˜Ô_Ą”KnĀ­BSBŖmŠcaéýY,ŽĩĄ%9 q9Į“‰OĶÕs*Þ5ãĖ$qnčBܓ Ų^·óįÏįååýVÎ<  páÂ^w8t?þÁļĢDÕZÃËÕ0Hâä4ķbõZž€T1ũ‘Ķu+éĖæą5Š•ŋ~#ŧÔĀy͚ÖĄĶ§|ŧŨ”‹wX6.\Đ•Ë7Kv4ĒQÃÂáŠÅ‚jÔŊsęz*ųä“õ—‰–ĐŠ%ŌiĖ›í"bԈâ 6˜"w7—MÔM­jßŊpÝ4ŦöšąĪæÕ,Ã~ĪGĸĘUĘų#ĐSÍL0düëÕwíš–œÛh~ŸŠ–2Móņé‹xDË4k<1k**D8+ ā_*$ēÄüĐĮƒë?Ôy\•ãįŊŨŦÛŽiã: ŦÝö™a•ŪđĩĮđ\4Y•|:Ū™ęGMÆĸR-ÆHփ ŋĒ€™  z]„Ļˆ3Ž@GšL…OPŪ QĨ^"ĪQÁĩ•9„Ĩ“.Ó Ē EYÄ ƒĐÛĶ /§ų\M]BŠRPÁ † …}VLŪ| ā ‹M,[Ū>us›ŲfĨLô@0w€"TĐXW5î( Œ(ļē)Ë9‡–+W0æĒZEŠčEk6ŧtp…ČՌsïķB€ĖŠiB`ú°n6ؖķŧŌĒÂæú!Tü Á=Þ {úôiŊŦņí)5))ɛ‚!Ð]ƒ›Ū)9‘qŅþÃŨŧīnãuÚtˆöÓНݕšNņáAų{roüžų@ԃí[ëč?<;-)=ÏÍlZ‰NˆÔČ_…ö@~՛īļ5įcĶaĄĒÕ;”Ļ $ÉĻDHoŲķ3’Ē ð+­ÅÖŪSØĖTžy›RRú’Úā„čŽŅĒ]-ĀF3ØU ÁŽcËÔĀLHø(Eް5"+$ūF82-_Ąqb%8˜nĸE‡L hÔĒžjčŠá„ŠUŽïŠV*ęH ŠŪ^ÛþõųļčT”æ&ŕj5Ū fšBmrއÔiþF\6ålÛö‹-Šyþĸ7ŒÅDQJ ž)ĐŨeš&Ô­ĒþË_üŠÔc3‘qĀÓ>_ JŽLJŒƒRĪĐĐ:ÁXö19†ķĻg•|s-ÆAĢ $ÉĨ&5uUÓ*ĘDŧ؇ķ%ŨãŠÔ:ÐkŠ”—Þ6@1/ĄĄE‹ÅĪ*eF…|­øÎøĻ^ Ã`EڃųĪmˆā‹–-E")#†(P`4ĮĪŠĪâÐ-j °hī nčŽĐĒï!E Q]‚Ą ãb7&‚WöāCō:âSâũ\ó1'ĮķmŊÉ1š-Š)â5Ųôð‡ĐöÔW3ú―~üŲđ+ûTCwŨđYÓfĖ­Ý*:þnĐöô·‹ĶíĻōé‡óũd\Ü=åĨo›ýĐv˂‘Ŋ|“žX4Ðí2oaóâčŊ þkÅĐðۄlZæŊvð_Ô ĻeŅÛDÐïœ;ŋîôŲd2“ÞúÛ2čFĄŋVc€—FLjÉðý3 dëŲó;”\ î{›ŋ} ŋ‘S ü?TäũÂg‹%8T–œ°ŦĀzÂ)–BŒŠū'fˆYĒF֖ÆëÝķLËē->äPT yÓÅR `OTSTP$`–ekŠQŲßÔuĐĒíPb…"(Ž0Ī,^“ AE•qnš"q3‚ĪœļbŒą1MQÃãADÔĘ||)\BV õ üŊŠÐC]TNmËĄ heōĻ@ĸBŠįŠ€Ŋé―ĶišČÀWoÄĒ  Æh–ĨÐÁŒ-ãÜáÐIq€ã{QD*XąÛÂ'ylÛ؁xcþ{ķŊýčíĩ‰`44]YŲyþKVpĨgdšđâ (Ŋb•‰·ÝđnÜøĐ•™‘‘•íAÅvýDađģ22rät–!ŋfoæådfdf™6ŋ•wlFíœĖ<ņ· ėØđŲY.EqNvŪËCs_z‘9ĮĶ(ûƙb͚9óåYcŠĮ8Ņ_ûSÏŧ#ð í6ÔßS2Ž<þWŪë·vGŠBþĩZE'–)so UȝŠZ)þ ØOáš)ã°@`6Ū1nm1.ēxÄAä o`Ą7ĻZĖ–Ī2ɧ°ðÆĒÉĀÄ*^yʂ<W Ĩ…ÓŽmšŌ BFŪš„qJEf‡Î/ƒî+ˆ—›âLœY= š/Ēęī€åeģ5ŊŪëģÄclËwSŅø%~ÔĪ~Ū”u/%`4* 咉Āl ļ^ƅ,˜4Lt xiUv1 ŋ(F )Î&đvÎøģ{ģ‡ ŦûķųýQdÜš=Ĩژį{ųæã3)b‘ôýû  0ôĐĶĩę?<ïŦĒ–―pāÅ'›·nßuPĸE7’Lg ßÉĩģyŪGŊŽ‹>Ųmd]zqČĢ-ęØüÞKÖîąšōÓŨon?, ö|Þ·S‡zf”múŦŠöځϞîåí(4čō܄Ŧæ=vá3OęŨģS‹‰û_X5ūįĻÉĢ;>ÔžEóÞŦÞ|­SŧæõęÕŲ~2é›ÏM\ö―ļĮä^™8Ēïî+9:ĩÝŪ4=$Ūlųēaþ úkBQ•Ëŧ6ēóCøĸf•Ãģ7ŪýüdŠĄāÛS$:ķyí·?\Uė•GHÉ6þU–eđWŨúÍĩ4ãNđĘŲôå'§“Ōq+7ýâÍôąðäų―‹{3ÕBxŸ`Žë`Ld:đā5 SpxtMâŌm‘%F &ē/CD(b/4Ī!čÉ*rZ%ÁPĀ­pÎ-Q0€e">WpÐĩ!ĒQ E ‘ÔBĜÛpmē fŌaWŨlQØ2 /ˆf)`rcb Tā#E PNUŸđ‚ @Ú·ĪÄdZ† &'W &Øī`y"68ŒÄLŒĨ·‚-ū@ œ!ļp'` ĘHš/ØēYÍŅ=\ŽøŦĪØ5ū}kvýåcÎä,įÄécYČJžēBË­Ý*†ý5 jH‰Wc æÉMw[AĄApsró„ ZPC% ”@‰íq™(08S##=Ó/‡ųųé æĪŠĐ·Ŧš_!‡ŽsĪ4~|hÕČXŅ„evfv.W!ĄNxŒ WŠ7rrÜÂŊT!ųIQWFZV€n9üËhğ3­Äķ'Ïe„Th3vw2ĄOŪA…đz9dįef{T‡P€óö{큊+ä/‰°‡9& HT\&ąĻX–Ŧ rVâéō·Kd7øOjlÛbÄfAģF…-} Īī•ėãÂS|ˆWĖ9šåÚ ąr=~K8I ‚ĒMŨā•™Ēq°iHôPÂ8ØÝj\^ cR`hi"ÝKE vx/Ē;AE ‡Œ …9‚ å ~―€ņr ýY.-Ũ„üī5$eSVmæ]ÔŊĐ;ĀUn]8–CĮŦŠjÓ{ė…åõķ;Ņ]ã§ÍŽäÕҧ}Ś ïŊnüāûä<ņ\d!(ðđb)‡Î^áÛđëæÍlĀdĢÎÜĀ ‹R7/‹ãSΝšĖŠÄsqãdZ=ïʁKéånŲžÓē~…˜öˈëŽY8}|ĨMuˆžbų̧„Å­ZxõShŨ [hÁŠŒ{Ž]ģ·†<ąāRņ~Ý*úLÉTŋĘ k• MOÉĖý+ÉfŠįÄæącŸiÕĻÞØWūAšãüŪÏ{>úH—‡[=ņü›)5įüöņ#>5ļϐņ‹Ý4}Ŕ'Ztxxð€áë’2Ð/SŽ ãëũfwnŌķũ '_^wų‰vāÁoßÛr*Mã)Ë_øP—G:˜s2Å#j[t\Ųŧšsŋ ß_qAi þŽđ7ęö`ŧ‡ûô˜vü|š@PúĐ-ãFę7°ŨÐWÜžôãŠïö]?þÕóÃgœK§N§þí[ãÆŊü†g'-šüÄC;wîöüūóŠŠüOĪZ‘ĄÆA ĢŠ‚ÓdF+ä}P Hā,€° æ`z$]Eņ Š?ĀEÃ#Žâą"ÛŒ3XV1WŠË"QĘüE!ŦA‹žˆåŸ0 <+P\ī-ĐĢHLáóƒ@ Ģ>+ÎĪ5 hBœŒqAũ· NĀŲĸĀ’ãā<öšj-ÆÄ†6Ŧ4‰á$āÆD-GXōŪLߐ \Þ(ļ†˜hđp${ šü)ä\ČėRLý iƒ ·…š‰;·Rŋųbc™.Þ_ŲmZĩėÔwtÃb)ËŨ|åОc–a˜Ķzķo·ņÝyFŒ7gÝå&$’lC(ą‰í3ķ·ëÛYcĶM2xL@ˇ'ęSuŧMPšgóÚSF 6ðÅWVíÉs-ø+sxÃûo,{į*ËþrõŠ )&`ô%—Įãķ)tÏ(ē8…‰<•/ø@óÖi‡ömÛŪl°ĻHö,z}æ+ģ‡ũã)ZŊIđ(ô—…âO}ĸshƒÁK&īØžōÃóŲf@TđEoþÅŠ—6ŽÚ}<›9ßmܚYņ‰i“Z>måŊûdŧl!žO„Ð\į7ŽžõMŸeۜ4ībq &9NšpðL&ÅI‡|īuðKËŋ|}@‰PE|ũü7NlóâīVÝ:6*.;‡šŠö~ķxÅũŅó?Y?sdsâĘ˜ywƖo·äU{jĘļ§”Ėc'~šSīėĨķn8x‘đÏ-zįpņÅũ­Y°ė@ĖŌÏūčZ9wŲ;ëōˆ†ĸ' đnýK&ú›š—·fĘ2 %9˜`Óc€z‡ø B”…ßBiЉ 8‘č^B„@īéÁį†]Už3+vŠBÓb ęHŸũ­4:Į@Ę2E"Óu™^á~āŪ šČúDÚäbUúRHņâĒn5IDĀ'.ôƐt,:Éð›č Ą}#―šfĶčęq§į1Š*:ÁÂæGē0TzĩˆQÜzБ°E·"’2§{,ž@.EQ._ūYP`c|õęU/ę6((čÎyÚŋŨ„…þ%*#JÔëo­đ†#‹8KÔ !ĄJMŸma„š xq{õgŊ{*jxŒĒÄzz vB/ŅpØÛŦýðóEĩvƒ†Mš†hČŊÍØ7ëú#Üöâō[·§›Q#ƏČČīý/ÄCóÞ,ŋû€3ķTŸĮ?s5G'Ģß|Ïŋh„ļŪ€ØÁ/Ŋ ,"ā=†Î́ Ą=ŨáÁ"ĩ—oúÅū―ĄE*`xĢ…ŦT*záZ™2C‡7j˜ĶĄŋ,Ė\ŦvŊį§?Ö0uįO[Ü&wØI“Gžœ“•læYÔcš„Ķ]æ<óH‰cÃķ#îē}ŦŌ‹wĐû6bėVϗœØķF+ŅŽsýŌaJ™n5"ß5đėģp EŨÞģõī―ŋmÓ}Ō CÕ`%mĮĻ!Ŧ#KþāŅĖôXŌ!€šO\ŋ^ŦK›šÅ#ÔâVüė―ž\UÕþŋÖÞûœđ7=!RB H―WéR MQŠĒtÁĒ4QÄŠTAštPzB/ éíΜsö^ĸYϚË/žž€?ýû“„YúūŸa2sæÜøáđkÖ~ÖũYãæĒŅĻĪąô–ãŋûųݖëC/?I$ŊvČŪÏŧáķM‹æãuvÛhĨŧ.ysúË}uß―gO}mÍ ŧ͈.ŧÅYj­lä˜Ð‹yRˁ‘ŨjPFŠėHq­…WRũUĒž#Įi1ūȍšŧ  s“ *–~AJ VfvNî3č,øģ­^ąLÆLȐ{ÛÃŲ—úg―#”Ę(đ”„―ĀėŽëÔD2ĮđũõFÝ īz54é.ÏcY ia]"ÚÜ@„Ô ė(ļ,â+XŪ%Fʀ\U0/–q)˰!W Î\Y€ÆØęXĐ`ÄTËūĮčÕĮŌB5pÔjIËæ―‡Ū°"YåŦŊ·ĨIrŦšĸČjĐQãv5îĸ|ôĀcėByŋM·Ý™PÇŌÂÕ9`øķ; 'ԈQxŨŠ­O`_đbëņRKnÝÛÐĨí’äj+­'jéķØ{ĢĸGöΚÁSÖZžųŊ―ôÄó];ėžË)œ{WQ'ĨĒ^Q_ō―ļsΛ "ÍxüĄߙĩŪcB‰PĸĨ†“_|mF―ƒ&?öâ,Y #QÏ}ŽýÁ^Ÿ{zįvúáęë}gó2 ]ëË{ŽpÉ%ŨœyݖĮíēŨBøeäęÏO~yz"žôØ+Ŋž­ä’z”õ2õÉ †Soļö>øû;œ|øý·ųÜ)#ûuvV2rĨmÏŧøīQýĻ_+fOzíõ΁#ũĐĨ$‹­Ô Qé,ËČĪT*IÉx_„#”87ĶAe4$öŧ'iæ+d_Ŧ‰*HŒ—(ïšĮƒĸMŽp^é„GyAI2Ģé0Á…āėПE .D]‰Ï‘`já ÜâÜrœå蔯ö΂cgŧÂ-īķ3pã ūZõĨ5JÂl˜œHm ˌØ`ĶĖå uM3 ļ,úōŧã'4ĸdGĢ TĢķœļöiĮ?8ïĒ6H1m3á˜ŋþå ‡í·ßԃü˜øâ6ĢO?lŊ5ūzíŅÛ/[Ŋ—‹·ĄL)ą° >Jī˜B0D1ķ7ø2ÖÝú v\^ËUčĒxðW"VžēܒJĄä@nÕíTR"K"ØKcYŲ>•ũŪQŊ[TĒÅ=h?h.WÂāļ0žkėÕ[`ĪLPCf!SĨf"„@ZpŊeš§DÉdTÄbwœ^”eYËkNŨŌ먄Ś9ræEbŦbÏj@šfĄcÐĖš‚.é’g„EŠŧĕÏÔ·e\ψŅ'ÔY44ÏbYÎ9úOVŧĘĒXãģgž™úđēč·ú„ËąÃČÞý9åēÕ}10xÄŨÃËoĘÐ1Ãŋõ†ũNe™†Œpþ5#xúí‘ŦŽÚ·lôŲģJb‹aĀĘ'sųf{žcčč‘ĮÆFĮðĒH;㧟î7žėY~á€}ߞÞuðčÕĮ­6$|ũĻĄ#jƒVųė—žÓ1ÂzÏŠŒĮlņŧK/xzŌ[CFŽíÓ# Ú§mÖŨ7ŅKC|Œ= ÉIčéRYæÎþų:ï”+õŨӝfÖį7/ĸŲ}ÍüNJGY­ĢŨ€cŋsqÏრĪâ.Î]-k9ģšRbI:Y‰žÚCÔ !Lĩ€oôąL―0ZdĻ.ÚÖĐpW%‰ęJgĢð“_I"XÏ2~XŽreāŠÄĩ6ĩœ9*Á^CޑĮ2z§ÅLðŸa˜+-ãW-ÏAuQ_B|…{ķõpŽJ!ó”ûĩâ2$ŪcŸ•Õ+n ï‚Î@pÞ%ĀõēÓûĮÞ°š)8dąŌĖCŽYAĀŽaĮF#Ā ‘`ÁvĪóeý8ļÍa)ŦH4IīáeH?}ĒjڌYÓgĖZaÔČvoûo–ĪÔwÄ*HéYŸĄãÖÖ|^jÕí?3†„ɊcĨŽd‰%ØÂŸĘЇŪēŅøU)%˜âKô›ĻTÅÞKúĖnĢAös””sšÔ cY―ë=6Ųr{û<5Sf―VÓ7Všr°ōšŲ>iIyÅąŪī&‹$;3^rÕ~­ ĻæBĮØT–Q$öēâšK‘îy"„žį 1ÛíŽä„„íJcŨ“X.æģZ[Ėe}$QŅÝNý%ŌYrįīįMŽXá @͚ÎÚZ”wėúÂZ—'’Ē4ˆbNØ43SCe/ÎĀÁB>ä’4ĻŅđ–Ų€ÉˆąöÍ=ÅÔŅŅJxŒ’(Q,*΂s†› ”™gŲ`)j9ïÁ‘úķ–Ø•f[cL§ ™c}ąāGö° ›]ՐˆZcVQf›$7wŒTÝDzįļÞ(ö=@æ4ia SÖ07Ū@î@ŋÄü ÓŲ™ãŋðõ·ĶL{ėķŦ;;jÔŪŊR,Sũz•™˜EÜīpĩ^ņþ?|oĨũÁšóä=þh|)ü_đxĶ|ïļ?”Ø―ĒRë>þũŽĘbņw Xx˜ŧËębíގ-ÛY]sØ@%ÂĶŽ0ēķ,K\ĸĪ*KŧE,>€#“H\‡ÕƒX č_^]OB0ŦF§åŅ<ĶZš•*a&Ÿđ”H`]Č|(Š’ØðŒę?cįpĸd―p–sĢŪ nÚmIĀ>čÐV šĒ―6TC˘LîЕ&fþ-Ę2™3W†6ÂÔVY2đˆR‰X?.ģ–1eĄŠæå’æcÝ ķ•etúŒŠ°ÓâX“&ÏžûÞWߙVïHïėæ;oŋû˜#ŋPË3jWŧ>å>(Æ1%P;sƒĢųä<ŦXÔ &Æō‚Bé*H°ý+FöĒÚ;Ęhļn2Ú&˜„C0ÕšjG;đʃL“=ˆÄAãly jn4qljĨčƒËr}LøÞ€æBÉp2ˆu °Đ%v EÕS›ĻV…J?ö)Ė€Æ0ØXøÕŦĄŽ&ŅŧÐl=YÄ—ĨP ģEŦč}Kę]­–ÛÜÜ U4‚ļrJ0n úYLĶĄąžXNfL_pË_^ęŧĖĀíöYsĮýÖÜ ĸÝåsk Y%üþÖëûņ…}&|ä$WŠųŊŋþ6xQ QüÃï~óvWIZ]ģÞy}ú\ZĻæ―ųØïoļé?ÐA•S_ý•—ī^{íĩŨߘŌHÔŪķÔþϒnĖ*f0Œ>7Š)Ó{ †ģ"&ەō€ ÄJĄz>ŔQZ1EK$ófŋev‰ô ËNN`Ī vr…ēĘvŦ ŋŨ2‹ 'ą[Ð,vÃŨí8fÝŠEØ&rBĩÁVL–ÔÐÕhĻķÖr†_„3ÝNķŋ„Y­…æŨ2œJ?Sð.Ë4 ]˜U(ájÐB-!;XŊJĪvcĪĨEœãyģË0nøÝýđ Wf‹ÅY,įïL›7u^cÄ Ã*—’Í/|WĖޜ:ũėï^Ðŧgm›ÍwōüŅPÁĮŪ>jŦöúņ=oÓGւÉß>ó{/Ïh|•ņĶó9úfZĻfūúāég_V§ĸßkÖO›ļųîŧïsÐA[lĩõ„ÏþJŨG##>HdfûĮö8{q–Zô†YÕëÔËTxKÄēcŒ/+Hn”QR!ķV‹†;čwâ―3KŽmĻ(âāģĩÛÚ ,8耓˜a{°―UÛ Fķ‚QÁ ĒPÖ0Ŧā­&„Ö;ĸ'’I Žob `B G ŧđ0Ŧ%ûЙļĻŽũpW%ØŅÔ†E[―ˆÍm™’VīHsā\JÉ{g{Ã9ĀVĀûÕMN`,æęZI”īÎLâœz<ņÄÓūyúŲ3æÖëýá†[þþðÃÛî°ýúmÞĩ`ÁGB/ŧėÖįžüëÍŋđ)vÏ “HcÞĖYó°y‹’jÞīé3$ŨŅs9Ï^ŋ5ĨT.˜ģĀ ŠU1cúô™ģ[:7jģýOýō†„*š›ú3æˆëŅŅ1ō@įÍnug60VÄ5ĘX•ģgĖLąĒTΙ5s^WD&X  /õJČ*éÞïģ'œåO~ōãïŸĸ™Ņe5tãm‘…7;DĪG؆_LŦ-ĩķÎŊĐyŋÕ2 3+ã˜+•ąY§€3ÃĪ,ØðîŊGŸ ģ­ÏÄ&’"­NoD0Ē=o0 8Ųk§§Oâ`9U‰`„ũͰĩZ-IJÆķ5•L­=1 …ũ,°ÁšÜŦMũ_Â0áþX–‹nD3Ąég€ĀAՍŨ4[Ņ6 7_Ë‹ļ°‡į·bŅÅðŪzīï!ýđ†ôõdbÝ"đģ čĸ?ģ|oåž"―öŌKŋŋōŠß_ũ‡‡ûĮ/.ŧtØ2ËL<āđebJŅ>zû]ÓŨüƑ{7!ŠÏODņŠï~č`ŦívÞëˆCðæ”FĒøĖÎ:ėˆCöúėŪ?úÍ―õY/Ÿ|Ä^ÛîēëV~öĮŨÞS―účýå "šzïoØuý]>sȉ§]ó?!ŠĸöāývüĖv›ėþÅ^ë†(~ÐÄÝ?}ōCONūüø‰ĮœrėŪ;o―õ–û\zņyŧíīÕŽ{į3o+Dņâûˆ(Î}õÄĢøë‹]#VZkĢĩÖZķëÏzþ7îôĸ māýúõ#"ۑYjĐĨ,,•ŋjK-w“"E‡•ŪŪģWa4’pf$ÏjÏ2X€š–ĘŠ―~gŠzĐâ BJĒrë=ˆēIDHļ@+JL TUQš†'[#ŋ(%OÉj5“Ԑgž‘ŧƒ Đíđ:ðČ5?œ8he ĒŊTg‘ûЈUĘ2X ĘČ-8™ƒÂvp+gĖ6Ýŧ†k žQØC vƒ1Û6ógzú4y@"ÅrņvķpÆāņŸ Õ‰=[?nûÄö;€$r1–IO[­Ģ8·Q6sŸ<úĪ•ÆŽ―ôÂóÎ9ýäÓĶîsØŅSýÓįL‘>ŽęŨýîˏŸxÚ 'lŅóĨßÝõÏo.oþ}úÄSŊ?ÛžíNĒâ{Į}_ķŨ-·Ýð•}ÖÉËäĻņöĪ?=ðÂĶ_ųŅĄ{ŽŧüŦ_ļŦwómwüîŌÏüâG<85Éžį^|fŊýĨãî~Åí·ĸhũõ—–Š‹Š>ËŽ{öwÝyÃOãĢŋđįųY Q|ö‘™CÖû؟OYg…ü‰‡î|:ũã_þæÓKû ‡wŌ?SXĨknŲ­ļâŠ+ްÂĘ+ŊÜ\k^ĖíYmĶō• (ËCŠÔé;WFĖrõˆVdόE0ėMaę)ąĩå!Ð*O"ķ-l”ŧbl=@‹pŒŲžBwðxŽ’Į&ƒJˆbėtvZ"ęŠ%Ņr`ĮĀ•ĒĶÄÉoËlš†Ā­}ķŠ,‰:͒īŦmLyâÎŧŪãé{.ļøŠ7‹ŨtÓ―‰hA·œxÐ&+ 2žoĸ^ŽĻëïók[î°aĸŽÚę;m5dé>)QŲHkl7ņˆMVė™w=ýÄÔ^ëėØŋ–YkûąÃãߞĄĸ;úœŠ7^ȇîąýØžÖóņ[eĩ…ïDšĶL>wŊũ;þŧŊ͗$ļ™ÎÞŧpðȁ}I>hôįũļ°aCV[õ3‡ė―ĘōË,ĩܚ”æZo—u—xöϏ>Ë·ïpðā­ļï†Kė?öā ëÐĸE)Q°Đ°ÍLķ>}úīuvq‡(„o—į5[Kĩq§Peŧ­YČSŠØËrÎiRĩš6)‹ē*Jįđ, ðęžN~1AžQG ; JŽ\Q 1îīlVėî]”ÉâjŒóÝMÁ19§&aq8iRyîÞ&H*ņúŸŠ,cÕšíŒ.8ŽĸzįY·Q‘Ī<äDčĮ›•é ’DKŦŠB đ!D9Jīß4†šTlXų@yfĄđæ„sÞĩÜ\Ž­43[3°wfž ,ņüâUIR-ŦũĄÎV7î°ĢŲfâ„}>īWŊ0Ļ7õėˆI"}p=rûŸĸū`ÃŊíŋÓ§ÖÝâðcÍn―Ú Š,Åĸ€(>þÂŦBôÔ_ï~ë­DąG ĒØ1`ˆŊ―õ S_|öU9ė=Ň^šN4ũÖ[îzŊ ôíÓ9æíŽĸņ™'*DŅ· Šéĸ@å…(:7tŸí·žôËûĸÕQíĄÅjÎsž{ÅŪ>·l_ĸ‹TĻ”ĩkņÆÍ0kvl–%$WYT>° ™ `å"ĶÚäëķp9Ŋ2Jä4E@EãÎ[呎)ūԔ";ÉōZŠb―^døŪ•,ÉØ‰ĨMK1pPZB†ÅÜVf!7Ē ļ8ŧƒEŒ― ĪŠ§sƒ`ŲFÕR=&˜ĀāĀÅ▐^Ū/5<ĐŊ;•T’š!˜Õ„ŽyŊ’…›âVXą5YYÂËK/ôã* Ãn;J†ē§ZGMûÞ(Ž[.ą„L ĮŪKĒw,īļ•ũŪGÖčß)Ą§cĒmwßiŨ‰;ÍZ@EĨĘÕé„āčJo]͍ktáÛ­^ë–kÖđāŲ‡#ĮÔÚúŨ•힇tĀ6'|sŧ~݃Ëi 2DÝÅū_<ûë_þĘéŧísMŨËO.ŧïa[/“ŋð@G]!ŠŦ~yïíũĸü.w-·J―zĢ^,Œķé;våOđôŒož°üėÎÆežđ鏎• &-Ņã/ƒ(&WēA“.ýmšÃÎĮrþ'ŋēBéõ&swfŋc·[Ą-4íúĀmąhãTĮ­­„`0kŋĘėė;ļ%ŒaƒķÔ g8˜2ĀÕeI’åXj`ŌųĨsš° Ŧ€ F3Û„Ļ•žcr8Ž' hA1ÕE8c•ŠJõ7ïϙЭļb‡øLb‰^™CŨSKœ™RIúÐ{ŧ}ŠdÞXðÆĒ`Lá]„Ŧ <ŋ8`ŸMïŲžhQųæ:ŪôÞ@Ō ÞüdLė2'g―RbÃlk~ŊVz.œL.ę*Dp‹ãbî€%úé)ï<ũÔē+-į§’æ•”9–Wž{đĢkúŨ ŠÐï g^ŌđÜędÅ}Oŋčũoš#jcÖDqõ}ÏünŲË­ąĮá·/=vŌ[]cÖ[Ôë#;(íÓüĢÞQ\rÕ=/üÉ {âåÐëā6Ýī·§·ýÚOĒØ9þkg,đÖ_›Åĩƍœ5{aˆb―Ođ`Äýv Y~ԗ{áy―ü€c~ú‹#QėąÔ—ŋóó^ÃÕL°·B‡ŅÖ{ąžôÖ1ëĻõsÏßúŽX™PC>ĩËÝŋß|åū-4íú@ąĻ Yn‚kī"CÍ0ëŽÐâU ŽUˆšî†Ų’• „(䙁ē‚AÕëuvlē*õæŲ:ĘŪn6’ĄĖPa@î”Ēsl°ZģÛúIJ–i.7!įõF–gĩ,ÄĪEΊ+ģŧ9ôãØ­ ģÄa&æ 3ļž…:C§Ž‘?æ$^üo–ØwûÍĮÞqį#wÞ{―·ėŋõúcęĸÁÅÎQcÖxÏՖ[u Ã}ĄqĐåW Ŧ|Ė:›Ą… „‚Ú.7ö3ËĄiEõ\bø*vĄŽïƟމPÖz/Dąĸ°Oo?ŽõGËá]+ãQ\ztëņ’,ę―-5Â.IœŊ0fí…ŊģzĸaôAÕŪķÔÚ UBÖķI9ïīc—wä8tŌg˜Øķu=ŽĻĘØRÉ •eÁĻŽ­°kÛЏÄVĄ`>#æŠĄaĻa@/ΊS:ØÍ“5žÁ!!ąŒÄĖĩŽš‰ēķژâĖßh°‘OŠD’Þsī-ĨŽ7TX+Њ‹p‰pbŅU:Ģ1X*Ēŋ8RZFáÄZ:GfX žģԆdnÜŠPg.lp­6JáĢ™―­#,ē-–7ĖnåUFŊžĘōôŋWûī§]mģlēŠØc ÂēėEkÐē€=1Ö"Ēo€ē˜ÎføÖümĨĘ,°z kJč.ƒŦā‹F–…æc`‡ZgýŠeø*/€üxUíĖR‰ĄûĨ}ĢWýM)Ųú–YÍL"}™[ŦĮB†CDęĮaó8Z€X…%·Vč™Áž EÏ Ũ$ĮĪOã.<>‚…„É―x“Đ IuĐRã9ržē°w<_&ķÅļøþÛŪvĩÍ^D‰bÔĩÚĖ”ī*+ ņķäD,æŒrė ЙŨLnpĻîõgEtŽĩũe,xv8ˆFķŇ0Ô<āĖŲļŠT”B^éĄ8‰ÝŊE0~bū4ĩLH§čÞ0ao-*œĨC[iĸū;ÛsŽŠTĐ1’uúãkÁ/QÔSē„GīĻŽ[áfˆMS%CŽĩ˜ß$[pŋ!Ï>VŠŋķë\o1A‹ƒ2˜ĀôÉŠwĶÏ|慗Ō'ݙßŪķŊVÜݔ­ī!…K”.Ũ`ž{-æ.Q ‰IÉôŦÖY‹ĐīĖ)ƊœË †%@•І‹ē.vUb։Ž0#9fIĒ+ ,™jŦüÁĩĀĩ$,Xģ`iœC.ŨcŪĻ ŊÓÁhÂf.cōk‘đz†åū1ÃLÖĒ<ŌԌÜčq€FBfĩÕļ― 4ķ†Ue!’ątį)dzw.%Ëū $’lI qjdIމ‹F#8g€‹ģĖCČžųDAgŒĸÂąŧptĢQPŧÚõI> čė œ{ô‰ ļÚ<6žŽHF(0ÖDŧgĢOeĨÍ@ÍĶOcIA7œÏkĩēhÔģ–gQĪJ•ĮՊFé3Žg‘+céá!(‘â%Ī;ļŠzÝÐ/ˆ80‰EŅ-ÞÜ~ØŪ0Ī3†Ž{VĀvĸR!+<Ï;Ą`ЉEePG―U{šĐ59ņœ…ĢË9/ÄŒÐÂÖFJāðĖz4į2ôÝöW§W†q‚1č0Ÿ ēt’‘t-°yņŦ'ÍļûÞŨޙþ^ˆ"ó}ýųŪ;îųęŅ·!ŠíúĪ/æÚīÅ:@ĀAŪĒÅeĢ!ĀuÛ֖:™BP͊ėš! ˆ="Ð8—ĘdÁˆĪ“€)P;–wƒórĖW@Fģ<°\ĢįõžŽRĩ •uōÔZLĢĶ‚'L”›e.ݘ*Õl§!G–Å[oč.Cp!™C‚YßX‰*2Ũ' ĩsĪŅ’>ĪVv$ķ㊊Hp°B{þ"ä;Ö~œÅÖŌ į5‘d4Ēvë˜qkŒ!Ķ€áÆb Qžõ//ũ_nÐûŽûĖþãvÞŋųĸŨÜíók-đŠŋîķ ņų―ĮD16æ―ý曍ŠŽ^yðž?ýéOũ<øxE­*fO―ý–?ĸų–{^zc6-ŠÕŪ6ŲK˜i‰e™ŠĘÄ0ĀŋĩõŦ”+|QĐŲ‰(ģ.Ðī"jēĒŦN3° t‘HđīĶãĻ͓HLˆØbŨ°ïãø^]ŊãÎÜ ‰XjĩÜ1Р'W*jŠY56&aŌ}\-W ÆÕ ―ģa`bHĩŅąoÔëD8Ú1HMkn )ëĻ9]Ĩ• ý<‹RrĒoĐ; ÁmQŅðŦDbĩ—"0ÅÖŦ1tqË ‡ÐudđWŽ\°ī1Vž9kzmįH?ˆâÜĐóÃG-)ÔS˜Ũp]UöƔ9ß>į‚>―jÛlņOQœûė]§uĖßg5Ķ^}ÖxÜužþëG~þ3{žýFUS>úÝūþ―+zÖ>Gĸøw‹* ķ]mĐ%ļ_ËFĐ‘!Ī+%ÃŊ€e§=Ŋ‘F•‘’:L%á[ĩģ/ÐZ”ƒX6An“SVIÂ"Y’ZG˜Ģ@.ģ Ä2pdƒ$ķ<ÖJųƘ5‡'JÎ1Ž i9ã|ƒ&ŪģQ I―™ĄoítËá§įŽIW‰gaˀÐv;xĩ@ :Á€ÝēóŦ―ĀČØ˜ŋ–lÍy—Õ4ę\sÃPÚãëgƒŲ(‘Â1+-84ė ‹D16Ę8ŧO8á”o~ó,ƒ(^wý-ĸxä‘mwØa― 7ûpˆbŊeŨþŌ7Ž]ū/=~ĮU‡Ÿwϑ?žôĒþøŨŸųĖ]ßĸÖoŸyó‘+ođŦßåW^uÕïo=ýsÛZŦ]m‚˜=Ē€Ū”Ô”Jā`54|!AėTÖBPŦVĨÅĢ%„ĒjX…äSk*YČ"ķ‚SQKæ ŠS%ð1Í2* Ä(Á1V陒…uŨj5ąs0K:PÄf^Bž3VÂāĸõĖ”āQĩ\^ņøÂ^–-° ‘@ēÚOlũfÁî|göYÍ2xuÉyUCôÔÄú.ØuóØß·prïBk ė]ÞŲĄŸX€‡āŲāßlƒÜ ôÚI€ņ%‡ķ:Á+‹7DqÍq—]xþ9ßĒXu͘<éé9]ó_{göĻqŧæÔŠÕ7ŲiÁ‚ý˜ýÎ8eãķîöãŋqįSÓhQ­vĩ}ĩZ‘É%Ë čŸÃ—w·{J@TÖ―j+1R7\ļ•ÞQbáH(KÕS‡ð˜”`ðæį§`ŠW”’īÝÓĮ@xČļ…/Ā7}Óĩā\@šH#oË /ÁÆŊzg0*ā5)`áB™(qÆí5§Öú,šcDôØð·*Z ŧDœ$1Ą„ŦÂæĄÅ*GWnH&į2VFËgcG }ŦkôŨg^óÍPYî$īļBģ%—Ûũ°Ģ{öîõÆãŪŧŲæËŽđ ŠBį†þ=Ĩ˜ĸęęŪyÓßtÔĢgïþûÖõūuč›>xŨ“&Ϗī(VŧÚRëH^ÄB‡Ąđv·bĒ…ŲŦ-•ŠĘĀDE„­ÓFĢ,";/ -jTŪ qũnX­K}ŋ ;ļIĖåƒģ+ģîŠ 'Lķ<æC*mIˆl`‡ÉŊP-ÏŲ·öŽjyM{p1ĻE\ ›_.‰õĘŠģ*z.I"Į €äAˆŨ™+WQËŧЭœb€Z‘„ °dŽÅK:g– ôāHxtšd^ŠˆÞ@_.I–7l Ŋ$°ēQ/žnĘe*ũˆ° ÎRuiq†(ŪđæaĮģí>{5!Š={†Á Qė†yæ}ÖÝ|‹§o?įïS mŋúÓĸrØš;ũ™7o~AKŊšÕđįėÍóžš2ŊĒEąÚÕöÕúĖk>‚ó§üН{Mę;―vmUÂ>k@ū!ō·™ c –"ģĩi×pbĮŦŠHÔ"P5‡ŲŦÚDk™t2Zåē*ŽÛjE(Ŧe ņ ÞeLŒĨ†DΓP™ô>― ·DĮ ás%žØ/ _ïjļ 8UøTZžĪÝ­|†$ZÞļRYƒD_ώŽQķ……Ō@3ę`ð fŊĖđá0p@úŽĨOÚ_—Ųā|Ģ,-ÎÅ ÅmvÛqŨ―vœÕEŠbúPˆ"JR,Šz!žé>§;ų˜vŲnå–ž1éïŲč įŸļÓó7Ÿuâ%ũõļä”<ŧÞøCWęŸÓĒXíjCuuĮG[üBŪ$Ė;mŽ)œ|ž1QĢŅ`͐åÞqeqxQĢā*Ļ=‹Xåûä2MˆĒįXМ‚Lj =ú/;ŠûÜký-wXáŪA+lžuđÝŪÅ`17ød‡þ–A€™ŽĀáoYâv|ĪýŽ ‡eI*1įȀIĨŧΚŲÂqs}ą‡ųĶ$ŽyđųF/VŅ’ZąeéČpßĪ "Ž+āËx§,ÄF‚7A2Ĩ09ræL ģDm$ƒC‹Š+äÂÜĻw‘ĻqÂcäę@āmeįĀ~ĨŠm@Ī”ãÏ'Oķ>›ûŦį.—uÁĮΰZ †ī„1—āũ;žW6BĢööIƒ$š$éÂņâQ\iååWZyTĒøAÕŪö% >Čk9‹aåđh‹gũ­íþčáóQã9s.Q"KæÖ"yq.”Óŋ^öX,Œ%‰ðĩz=藔2ģ7”1‘./čG—Ĩ)5ūŅ 5 ĪŽ#Ä@hÚþĨ*1zlë… Š‹ø&˜ RްŦ–QC‡Ņ@ÐEØâ‡Ë}p’H’€åĨē*1X•^‘”cðrbŌįAŌ‰Ęŧį.kDlpNj>ƒKŒbÝ ‰ÖV{ fįÅ1ðæĢ%ĩ]íj;)ģZ&1UH{%í1š4 AQYóLLÃyĖKĢĪ*a<ęŠXķĖŠ:r­p:äSd°\>/(vÎ0`Ų‘ Ī<ËØšÎāó<3.ŒöœÁ‹$$‡;å:–pđ"Įž\Ý<Æä oIÉdŽôÕjÎJ’û@ÝãWã‹Xøî­Ĩ(†îķÞxWTÃ( žÅęøÂcLaYo“ā<Ū$Btl“cå3THĘ%áH_äķeÁ™…ŽÛ‚ÔŪv}RNϑ(#"J!PÅUūÛM –ņ>‘ú·Žm,U%-f1Ķ ÎÉÔm)ÅŲ―ÄĘViIX{ÞĻb]a•–p<ƒÏóZËޟĉ+Ëh‘šúéĪbí90qĨ-ÎÛĘl™u'„˜(ƜÕoúöb‡Ó6$stĮę?Ã`„ėė zK’RQÁkĩäØĮŌ7y­€|0“bdŌî8&=ōŌE8@i+ɂ°•ÆPĒēŠH&óŸØęvĩŦ QĖŒMˌ/é C -ķt†5ĩŠgô-b‹ÁĀVĘ9[‘z7KĄīŠ•6ęuėŦց~ DQlÖĐe&Ö<Ŋ―aŠ€ķ­ËĪ ŊĀf“_īÛÎ\AĨ>FōXæ0ē*ÓÂÄ ēæ•)pūzËŨąĩÚ֐„=ž•ū€ŠūþđÔō gwæƒÃú/ķ6ēĻŊ€ÃvÆ-đaØį†gŒ$vŸąĻ ‡1v…ŸtņäŌN›6yōäųóįÓ{ŦgϞ#FŒXjĐĨĻ]ŸðjÏj­) ™VByįČĩϑÁ’ØŠ+âUpXxM•MÞ]=` UKÓįf‰I[@ąu”`đęA‘MQĢ–šē“[zriy‘‚Ŧa-"Īð;ėĒŲZcvаŅûa°Ą­`Įˆč΂ĪU þY$J”b§Up_™\Š(ŋ1ËĶŌ‰X$Rú‚$BĒ]+―…”ĪŽ*oØRéGókƒ]G" /soņ9Ž}žۖāÅq~ÐTØįŸū)ĐK.đ$―·ĶL™ōŌK/õîÝŧWŊ^v…)ÏÞóð$îŅũSãÖŌ§ƒþƒ%/<|ĸóoOwyŅŦŽąė°%<Óĸ“jW{€Ā°œP`ĐIĩ'óŒąh–Ŧˆ=Ļ―ĄĨŌæ!ģvvU‚–,WéYį―ÎŧšķĻØ  0Q1SbIIĩÕŌÆŽ•&ĮH‘‘”bðĄY*{˜N˜D;^ĨØ(A8ÔŦ„ Áb9›#Ŧ{—Āč2ƒ­#DÜļˆ•ũŒPœPEīÛėƒR +šKÎÖyÝë5ŌðfÍRļLŪÉiIÕ\•]GąÐ7FąU`ßÚi&ŒEˆŠsŒ2_4RfΜųØcŅ?WsæĖ‰16Ĩ6{_ >ž)ēģggvŌã7lĸ™―/žęšÓÎ8ųī_=Aĸą’ú[î·óøCŽ―揷^qþąûŸö―fŌĸĢjW[jÁ{uæ1' vI þ韆ā€ļÖ―)r„xIˆ\ĖT•##.%(#2U€đ8‡ÕƒXE[Ŧ•ĪTŦNWâ]küęÔR…>‘ˆ]gŅ@bđ|īŪ{‘Ļ~qĒā|ĢŅ0;Ņl‘pãĢ ­eßx"Bēƒä!KUdrBėžŠđƒÕģZ}ŽF`ˆŧĐ!I"•ņ­†l!c˜\(” ^yŊJ]ŽÏŽÃŲf.L6~É|ŦŧA-Åđsį6ųÜüãg͚EU ĨÞWV|PĨŋßsË;}6úÕ/ŪøÃŊŪ:jĮ•ĩ`îŒ)SÞYP‰­“ÕëĨ@-ËFWLxPąėš5c^Bóg͘:uęœų]‚kΞ>uęīŲBïЧožčŒëĸĘy—ýėG^võ ß?jŋĨz>köÔ)SfÍ- Ķ4úX4q9ģį•D2kÆī™ģįŲ‡–Iâė™Ó§ÏœMV­·Oĩ·Û ŅžY3ĶϜ“ĻUåü9ÍŨĖiÓv?ąRkð#pVeí{wkķ+ödQĩ$)d>xĪk„xKŨÃčő,ÏÆb`˜TÁ“Ļ(ģ#‰*ΰĘRWĢ‘*•Ņˆ…*|ĄŨĮąBƒ ýbrČū54—8Æá“Į‡h§)Â;H֍ƒ ƒ"˜ČƝĩD:åuÁA1#^LŽ)‰ˆ# Ríą$€Zņą ی ė ° A&ÓĩŽ ­+(3`Qē‹dũ 3…=&U1â—wiI‹@Ų_{ģą―ōĘ+zčĄFĢAZfíĻÞWĶŋôaÅ};C|íĄGž{ā ĄĢ‡ö%*ûų{n·ûžã·›pčé/ūUĖ™|ËÁ‡|_ÕŪþöŽĸė-“ŧHf\zü„ƒ>xÏ}˜4·~ÏŊÏŲu‹­wÝm·3.ŧķ+ýüŽņ{ïö™mö8ïWąšïkŋwÚûuāĶĢ3ĶÎ~CŨ\etß~ûĐwß}Įæ‡í°Í—î~îuŠ3~öĩ GžøÕÝwÛn›­öúÉÎÝc—m7Úpí[‡ĻžîĒã?úĪņãũØpĢÍÎþÃ#ĨÐÛOݰÛnÍ·ïūÃķGÜûüDÅĩ?>áČŊŸtČŧlļɆ—þåúá­§ūķĸÄÝ'ėžãĄ§NžUæĐ]ŸĀĀ|ĩMÞĐFĨ*f“p„'œC“(^U,D­ĘĄĩӓ%•_‹K`ąđ.š\ø "z[}ŠĪ…w…XÁåęË"†§ētpT͜\ŌÕ^õE'FęĖÅÂŊ]PĒ -…=ËâlsÕCc9æĄq5bÁqVY•Ý2Wˆ:HØ-+KtDb?8NŦJĸ8óDķlīë.ŒÁ‹ŲQČ=;ŊžĮŠüޛÚëï-DþƔ4ŽJëá‹ļyZ4ĘĀ@óæÍŧųæ›õŦ_―óÎ;ÞØÖëõïŦŪŪŪ: äõvüĘŨwYyüv›ïsÄĐÏMM ^đýcļõŨ.―ãö›7=ņŋ›>ÞsŊž,0EŋõÚŦ3‰$>ûČ}o-đýų?ŧĻßĪ›?ũõ_nuōOnŧýöØuÁ‹·|áĪ_|Þ ŋþÁÞŋ>ûÄĶ,wŨüÄ―W_™Šj΋'ōõĩ8ëö;n?qÏpÚĐ?zuž<ĸũû_ėąÞOŪþíķCžûųMÕũ/ĸýۍšîÏå3ž{ęđ—zŸŅ5ŋ8cŸ‹Î9ûÞ§ž:ų°ãŨųÜ·ïļãŽãũāSNýŅÛ]~ö ŧį‘iGĸčįß9xã;Ūŋą‹äũįũÚ2ŧþéæë7iÜ}Ņ5H­ƒĐ]ŸžÅ\KgïĪJ AŽCΠÚUŠĩųO§ÎAK-Ņ)ÉĶD]úۘóÐsČ2cŨØáðßÞpË#O^wÜįÖI ęBíúäI-ŽJbyð8 Šū^DŠFéØwĀ{€-Y Š"Ķ„(ý>Ūúë ­’Ė•E;UŸîØðĀÞĄÉKYȅ$JrÔ /€1Ā5Ŧl”" u4ŽĒū1x[ĸerÖÃ:rž―hwĖ „G6„Âī˜õÕžāŸĐĻ* É}Ģī‘Ŧ7ƒ-iþy&,EQYðxä J 5G|Nzœ,7‘JyndÛ(ð ŦĨŨ%Â`Õ(FŒ›—(Ýþ_lŒ‰SÛ/=„…J)5[ŧíķÛøņ㇠öQEoýŊ{_ĨĪaÞû‘ôÛ.=qŦOïīïūãûáÍ{ō…U?õéoėšæYûnģϞ;œw{Į1û9zOuūđũö۝üƒß§%ŠdĮbE̊BDK­ģәŽ8ãāwÛcŨCūuYZvĮïļÉYïķũÞ{|ÔŨÞĻSwđ펾č [ŧ?―Õø―ũŲcįmŋx…ģ:V:å[{ĸō„ ũÝóÐï^}čQŪ<ĀuuÕą”ÃUrG§RÕÓŨJšíē#ũ?pŸÝŽúņg>īŲã”ņW7ūųö/ĸëÏēĒ­riBĒnģũ*jPg1ZBUA"šŦ‚ë‚WlTâĻ;ų&Đěãž_ïbn“Ķ”'aüúa6o,éŽ-qÝa-M…Ö1J†‘l 1gšL ψhKÃÜ0- ÕÔŲ‰'öíۗþ‰jΞũŊžōĘ Aƒnۙųí·ßnNl›ūZú â°Ņ„/ũ^åÅŲóЁG.ŋîļÕ2Ķ}ÏøîęþíÕYÕЕŨ]sđD~xųo}aęēŦ}ŠO9+ÜA~ЗÏýeĨzPģBïýŽ―hĩ-nðđŌ ~}v8ãžĄÛßĸæŒFßÁC‡,dŌÍú,}ú.ßņÞû_›ū Ŧõ\vÅU–Ø#ėt—Üމmė?t™ Ö\•ĪøĘđŋč1TßķïQįŞęÞfß#7H=)͝ŸeŸÞûĪŨŠuŅn8ŪÃŅÚŧžüÃa[ž2uހaËŪ?vĒļũŅg§ÎÁDīę§:qCęAÔg…-/―rČߞ}™|ϕV_–Ĩd9}âŠ=ŦEWbáäLķ€_â $DlaÁALXûr$$õĖBí°Nå’E…;'Øt`Ņ“+"“*ŨŽîģj >OÉ`čgËhī-vęūbîFĘbVëžO ˜{ûŪIcf0ÔČÐ2c"í$Įļ\$@͂rk‹ ķŅ›ųĖ~čq]+‡BhyfMЙđ,+[WƒmF âÔ,$ũīēÜ%öÛČž Ĩýĩ-b˜-xļ―€§E#ð&GŅ?SX =zô /žÐ\{ŋ Ԝ—ŽXyË+ÓÂúŪūáÖŦÓŧå-·Æ6Ëjˆ=3lđ…Þ’õŧþæ ßŅØ ķKĸ[eýŨÝlûuiáōcÖÞd uįï^yð°eÕðP…<Ķ9ý:{u_mƒ—yÏÛŨŲÔގōƒ‡-MĻý—ėŅŸŽ–5fŧQ­WécFíúÄ-æ’sUŠTg1ūÄD2ĄõšæC–į"v—8gĒūÂjUˆĄŒAD ­8ƒból‘c‡t"†ķök™g,Ármmp!ÁV5K’-ōâ‹9å:…hDIyG"ąp•ÎHØŧT­wÏ"Ī ĒÂÁ?āFāÏڟW†ŠŦ°f€Ũh‹jŲ·HoĪ”(ƒU‹IG :”gĄ; y­–Ę…gv>aĶaéđ:Ÿqâ팱Z o˜đ9dø í[į-åzOøÚb֓þĩjWĒčāŦIē U0Īķ9bGЈšÁÂŦY<,Tɘ2’4w+ÏBëh^ßF‰RŨÕanÐ,öū#ËīL S]Ļsöðü{ä>0[ó ô8€^y"ŌŦÁ‚›D@ŦÁ ĀŠņÁB|IB‘ ŊåĐŠŊð įFŸ\BLčÁ=ē_`•ËĒ&1@“NXKÓD†VĀÂŪÞ?5pAïIíD+„)Ŧy&°É)Ų|Ûīļ$uņ.îҧ?ýkÕŪöû zĖUbe‹lŽqF„Q&ĩ„SRZ‚w:9- ûÎX?UADĢĻßÁ… aŒf`áĮŲ8ļtYe(ÅRHðE*ÆŸl‰Ĩ.,Q† {„Î:Ua;€Štg+Ë#F§vÆ]XĀu†ëNvvį[rÞĘ*U=Ð0hÞîMŧcvÎ畈I?Ū(‘Þ˜)ÐŦĻ bkX^JzÏØ[kMĻ“óļ #―DG„lCB9đlĶ:n3?ĄÕŪķÁygĮDNČąus*DŽ<áËŧ`V­Ā> ‘LˆØĄ2ÏŋŠL̈ú_Æf„‘_HĘXī€Áh,hčŽ-Hšm\á薘ƒi+†Y”…h)5,ÚH2Y‹ŠŊ„‰Ð\úFÐŋ4ĘÁ9Ŋóō4úøWŧÚ!IŠ6Á,PŒąeÕ(mŅĮ+–[‡NAö˜{Ú0Wí\ŒĻîë‹E’?­û  ŊPk%,–Ņí*}Ņhψįņ3• Œ+U­Z˜Ôüokĩ„vä1ąļ―ˆ3{yČžÃÕ8ę|ķ•™(ä!ED΃•ūAIž[dE•9ļ_€‘kĖ0Ø­Šû Ō/zėĸš>XļųóvŲ}O:ņč“N―ýŲ…þT7þėØã~xíŨ_:q‹}~wįīp͟|ÆWķŲbģÍþޝôņŊvĩĨ6I ęņ*UXąļZĨĻƒÄ eį4ę+ ī†ŨÖĻ a%L„Ņ)EAJyĐ[šŽ›K•l œ…P/ę’0r%ëWŽ&sŒIrč$ĨŠB‚˜ÅŅ:vúmQõÚķ+€ģ/]Ĩel,$Å.Ē!m pTvŠĨ’Z&2 *X0ÁĪŨÆlA=$™ÏZ°Gėķ%ĻĨGé"Ž%J+‚w‚ 'Ėd°NæôIxÎT—}Э3þï5Š7ÝtӍ7ÞØÔÜĸ0‘f>ĸŨsūō­õþÖe?þÁŋšl­)žpäÏæUåŸO<îč?<Kf&0;$óÕ2q2øĒ XbÃš”@P‡fĨ$ļ­;f3„ĨĪY[60õÚ=;ĶŲfá[ķáÉ1"‹ŋ…ÚŠÅĘ?ôXĻė_uŽxĩlÁJĻÁęKˆÏaljEĀÄˆŲ eUÂïåĒĘhŠ!8=%3ØjN‘upbI ’@M䈆ŨyN`Đ8܈.›ÖKį]7ė‘A:įz―‹°âÛt$ÎY”øaޓ°ü·đˆO<ņÄĪI“Ö_ýÕW_―ĢĢãŸá"ūŧá#'ΏÞũ§Į‡nxņ—·U†Õ Ņ'^|Ōv_ųŏlüŦ‡îŋïÞ7O|zëŋ{ÆRÔŠŠ1sÆīŪÐ{ôð~īpqXj™ÕH+ôïÛãqï―þcŨÞÜMþÍÕoķĨķ]‹‚Ô".Ą’ˆãŊ˜’(ãJ‘16|Ė™iÉ;† !sÛÛ °ũDÄRuCžáīJĩŌCg`Le;Ŋ7ü " [[[Îca·ĻlS6`Ũ6e‰IOۜ3°€ūØybuģB7YāļēŦ‘fēv§;Š€ˆ7'Ą€~ķŅU76nŠ:äÅК“$Ā2TÁÕŠēē%„îmōžÁŸ…R{‡˜5ĻđÏôĘÔĘ^ģ†˜ˆ€OTIÂošDlˆņR’üwÍ^Æiķ··ÜrËÓO?―ýöÛ<øÃļˆ(zoE}hÕËīôÐ~:ÉjИuFÕ:YF°ņŠCƝvöëuv,īmĩęęãþ~įi{ėÚđÞf§žqʰũéĸ=—õÓ[åÜ7āĸ%ï9RŧÚĩHH­āˆĮggå1„€Ý*Ƙ5’%I,%WDõ†„ÂŨ@˜XޒNĮķJ‹ÓÔLŅ!(·DÃôeôðĒbÍŽÕ6*˜ũ/.H,Ū‚˜ŽueHYÏÜļū˜ Đl·G­$J–FĢaÚjŋ\Pūđˆþ„æ‘HXĘYČ]V…$ÜîÓcÝjēŸĨ*aKŨ9gý/îYÍķšôÐhĻ$kþyQ)ŧGŊ†_KhÞ―“ąđJŧÜrËMðá"šŠ˜[O‘Z•æÏœáâČ%äƒēýúõ2Ąm^w·óÖÚéĩoøÂnĮœ·þÄsw_a!―Ŋ~wŌQgýõoþîōMVéOï+^dâÞÛÕ΃ˆ<ÛV§DÄĻķ.ĨŽXP\­KÅÁ”DIÐ<}’™,9þTÉuģ á•ājk%•jJ SÖbhhąĩļĻęĐ<…€ïã 6Q3dqĀ‹ŦŠēė^]_ˆUh۔ä0ųMsŌÛ(ŦČÏsY˜!AõŸĄāĀV ŠĒhĨā8—šũ,`;`BÖ1ÉĩZ^b˜ ’Y^Yâo–9vóW+šĨj ž„3LôîŋĘEôÞŊļâŠÍED}Q‹>īV^e퓞úõýŊVã7—ýā­%GY2›_ŸĸÖä™ôūbŸ-―öÚ=‡ŅĖ7æ•ŊžðôäКšðĖuįžxãŒģ.ĸŲvk ÆŨyóÅgĸ1iž+xĢ ėĩŦ]‹Ā ƒsR%;à .·íŅÏ3“Ã7}Ð―ũHu,"š”t;ĶÚ ˆTJ8č*—ąŊl–đý‹1ÍīÉ/áķˆØGȐŦ‚ŦJ g+buŽïfˆēÏ\KĸÎĄ­Él° .ŽžÐb åyÍa3BÔqĨ fĢlH"óϖ:ЈYp ÛĒßD  gĩ<ä!–% T!XĖ4Î6F^ŊSfn”Ėxcšđ;ōÜ!udž―ކ†―ëŠ95Kĸ—đˆŧîšë{ėņ‘ŪXÚ4ŧ… óTb9›>ļ–ŲxâÕgMüÎaãwŸļÏø·=ø;oŸvþ%Ģ;hĨķļųĖC9ï’đBÝUÞþģĢĮOÜg§mw{g܁Gí―*UÓÏ;rÂ)ŋzšˆîŋᆗĶÜĸ­/îūå[_üŧ‰čúï~øwŽð›·Î=áó_úö ĸņŒüÎSŊ. vĩëc―˜‹žĻ@)ējōĀB6dôĮ\0øn‰\gN,ēƒûD!ëhÂĻ“)IŽ–ÄfÂÞUE"ķÛZU‰™ėī ąÞrÃcY‚7(%gŠx“óāqIՊ4o!ll%!aa,x›);&œ!5Ø2Đ)ÍzUNĪĄaX9cĖeŌ{ÚļšÜœũķPkÓjįļu/’k§ßZĸ%ŌF>_Œǰ:skj§Āt‚ˆðÃR<9Œ/vsĸK5dȐ–‹X—ũþÕW_8pāĸā"ūõÖ[ĘEDđÎ öøúõËnôâÓæM}þŲįņý/ïúÜgŋräÄãïü˖e>hĄČŋĘĶãũð–ï°Ö†,Ų;§īÄWŋwuÕgíōÕ+VßëzĢâáË­HÄŽûņ–ĐWO‹m?á ëíð…ÜĮŪØwÄ9ĩŦ]k‚ŠšęY•™y ‚wÄT!Ô°EY,ž=Ā$U,AÕbb§Ú*lk4 cbŪ7ŠÜ…‚8ŋS@CdŠ€ÄŠĖk™#Ũ(ņ‰™·Œq cЊŠSÞŲ0JX"°UڀƒĄUÍڕy—ĘČ#IÖŊC™á=ĩ2Đ.bA. ônzÏNØ9F*eŒWŦ˜ðIԜÛR’2&Ä멚č~’XāÐ Üq=!Ä_ĢS N"r”ˆŨ+8- "‹ą™ŋð!\ďZÔ*ã6\eœ>ØcÂÞüýõ3z.ŅŦģįZëmAï)·ÔōëïžüÂOd#FŊFĻCG5ĸKVö˰ĘwŽüĐuĐ]íZds3ėÝ~ÅgvϜ °“â*Ä Xώ‰ŅÄâMŅŽã3o)^.@|ŦRĨgũUQAíœ 25h,“ `!ÖcÃÁ’åšW€B vdV‰·%1ī„ŪÄZ­ū^[&}E럈ŧŋōģ!TKëOIbUąÎ‘|Cb?8–\XHŸĘœįā‰ûÉĩÆŅøßÖÝ{C/&ōäZš/ž8s ũ˜ŨrzÔæ<2ŨXRÄÄ6%‘ ĢíE‚‹Ø24·ÅޟÐÃĻĸ;•ï3lŨĨvĩë“ QLI—GkY yFÄ-ĀvČ t„/ė*ZøŦĢT$âoP_ė\°Ü‚Č2Սš(` ĄBdŊ!{ÉfĩŽv*Œð@bXWáÅäc™ļ* ý(ðzØ·]íjŨ'Qjm†Í#Ŗ_ Ē‘én˜b[!-N~Ô}Ĩ“SÛä=\P=[ĘbļœƒX“f°TUe(Vũ /ĒËhņeQĻJąx݀ }ĀęY(Á,ĀUP]b5ĨĮ–EË^f žôþģF̰Þk`ŠāÝžGŪĢÖáØƌ\tƒˆ{v ―,N-Д{0g ‡‰D"2Ë0―p%œYÞÚÚH)šWD°Ņë€ŨI€DЭ`ß$ɈéŸĖjWŧÚŲb0üįp@Ô(‰ÃaTzĄg‰DóAĒs0Ū+3·Âŧ0ðuÁ%i%ŒyïÔÄfaČ dp­ÉþÁhÜ,ŽWNzmĮė3W™;dķz /ĀļÓ|ūy–[Ũ ũ‘ū8͘ųĀčFĢåý$WFmŌ°‹ŧ0Ē‚EĻyTóąJŊ#a)A·ÝĢ:8ÛôOƚ…€]rĐ4Î$ģÞFŌēÖ>$ Á!ÂZpĐĘä<úv‘ 'GÖK/―4oÞžĸĒh1šĸ|ĩŦ]íŪÖlĪY`ąáĄjVŠāŸ…͈ˆ„Á6yT’Čhâ8mČũNÓ2 %Q,+J- ^{ “Á™X;Jh Á‹Š˜ŊŠáÆjJ§*u’TĶ’ ‰Sku m‹đšŒQ(tÏ[FŊJ?øW˜‡DL˜)Ũą–†ų*9ĸDÂm ašZøÁmQ –ČŦŨûģ`]üuéīĀ9KÕĩđíŧī‡ÄLö]AˆbÓ~Ð<Ûä}ĩôŌK7Ãqĸˆâ;Ŋ>výĩŨþáÖŋūųáÅŲj{晧Ÿ}vŌôũB‹đÓî―ãĶkŊŧþ‰W§ŅûМûÆmšîÖŧžJÔŪv}ėĨļjÉōžQ֍K―ŅûzwƒF”gĩ„ØŽVQˆ† .+ÝĶũæóĒÝhũ’nÐkÄēÂkģ\…3#Ž*V*‚N=XƎąoý&^°îVh.ŲrĮõÏ3/DP2pã–ķŠƘNF­Đ4:AÖēô&ü PYī Ė7 Ë<ģĻFAŲ*mJ,@jeYÚ`AHôÅ"øB“aw°Ņ›Ðƒ{ŽEˆ]ĄÅSÏ3&WęD%Ą7_d ŠM4mx_5õũŸ(ÞöÛs·ÚėsŋšåŽ_}ü.Ûïtû$]›úŌ3Ïŋ6‹Þ[ßüĢæZÅI'Ÿtô)§Ýņ^ˆâúõã/šþî?^ąÏ–ûüö/ï(ÆYÏ·ßîį_~ÃũOûâi—ĸĐNíjŨĮ[j}pĩŽŽÂA-Ŋá‹0ŲũnÓsGhKY›XĨ,: cŲ;īr^‰ŅƒãÅāÓR2Ę­ófkÕpY4đú&| Á&#‡į+ĖguB•ZąĩėH Čīā‘Ļe53Ė•ŧxuŠŅ@šeÁ#v&ä˜ðēT3û”Z4[ĄdÍ;öt=F< ģ:@(LÁk5āt'Ī'c„ΘYĐįbáŊŅ >1―$Aü߄(Þpà ӧOĸOCg<Ũ9GžĩŅĄßūėGßŋüW—ŊûΓ'|ÅūqäuMŸ>saˆâīzmôßļð‚ xÎé[ŊÚoaēŨúŧuÕO.<ïâË>ŧVqÛ}ï(>xûïïLcŋéO.ų΁7üîžü1ÛvĩĨÖ„Ģla· ZÎŧ˜Ē.>A.U ANÉ|@^7Aëpī%JHĒĻėĨ›dZ$šŒ™áÃqZ<ķÐF!­Ü_ŨW WUĖóĖ1U0$āöįrN™ēDæfvrûŊģ­-,čn˜öÁ…™đ@ǐ[ŊbЇfy„ēB4ņWH[Q‡_*(Û3͉ąÉ3‹ā5ÆŪĶžã„uĸÂ1L RÕjзÂĸUˆâ“O>yÕUW=øāƒ†ėúHˆbųū"ĒĒxÓÃ6:öKŸŪ1Õ.üÅ'Ößšþއŧæ‘8ũĪSN9oęÂ^5Ķŋóö<ęąėŌ#ûuBĄü’#ĮŒč—‘ëÕ·wŋĒØxúĮÖÛhįåzų!+oïÆ yaäŨ‚^<ÎéúũÜŧ,>Ö „vĩĨ–ŦRELõKŽÝËļúØs"ą„˜đX&3ĸģwRšþŠP'as_eÉ"qˆƒ$œ5iDĨ”Û2ۈg`abŠðNũn+ÆâÄfÁW :U@tģ ĩŒ_>T`DG>JLʋĐ%‰PjdęÆčˆ-œ―Ú@ƒ(ūņÂ3O―8]8_aĩ_xņĐyD Þ|ፖķĩŦ]cĐĢä&@ +įh°āYCŒuSŦŒĐĶKI•%Ѝŋ –Zžģķ—)ļÜgY*+Iâ3ϐ!åæÎĔI Qŧ€ÛFŊÁb)dÚýE0 ,Ð ÔÚĖBwČŲ"—-uS5M‰čāŒqĐHbG0*D@g44ŨöÐȑ2&Bó+ûčs>b‹Õ 5ÝBNĒ‹đ$Ē;eÉģY†―į<ójoHķ/nÔ9sã:Ģ:ēŦJˎôĩ5EĐݗ*x$ÝčuĸEˆb“i°ÛnŧíūûîÍĸYˆâFŊþöÞį>a·―öÞc‡OrΔoDqã-oųÖaGŸûˆâm?=j='îļíîÓŨ:čĻ}ÆP9ýüĢö<íšgˆč{ĸøōÛũŸqðn[nņé‹~ũÝpÁáGœ{Õ|ō›O8bŲþļãg&|zĸÓÖ;âЭĮ vĩëã<Ŧp{aZjÃDqūEÏ2ũ+%Aß!H–S@lgôN›Į’š\ß@™Éâŋ`ÛâĪrĻŲą­4•sķĨg5:ïm%8ÞŠ5"(%ąó%‹r GæšeCÆtg2"4I’oeę _Į9SIíŽá3ĶĮk-,Ũ°qœa‘$˜ĀXm[·HΏ\ņ_ĩĖĪ?ķÚ=ĮXņĀnqBWn3„nŧąNT’n—åÓC>þw!ŠüSdŊBÓ?;hР ĒØąþîĮÞļÜÆ“Þœ6wĘó/Lšę‚#v~æģ_9jïãĸzŨÖeūÄÂÅ1›ïĩĸ ·|ãÖ_oHŊŒŌ_ŧ⚨gY"Úõk?_cïiu”ŧĄËŽDÄ{žpņÖĐWQ4ę;Wüčū§^H=–Üxãĩ:ĩŦ]kĐ5ĘŠ…Ę8§Ņ„P vč%-yL%É)e1EąĢmÁŠĨÅÂĄĶã0Ūzģ‘šāuōcĢ*ûš!Ä@T@+­ou9tVđę?%’ēQ:įē°[ĪaāštP–HM'bVe”Čjé%ðs‘ų2Ŧĸ7Ã\V2֌q"BĖĒ^ĘD9ę‚OÉˉĨ‹ ĖR)7']5Š:Ll&Ðp{WĒbÂLYÏÍŨUE-;ûJ]m·mo ŋ–c {Ā^ÃĒQ=zts‹áå—_~?Dņ#ÃrŽVŧþJcõÁîãũþÓĩŨÏč1ĻWg5ŨŲ”ÞSnÉQëî4ę=ÅáËŊJĻþK-Ûü/YĩžݟZÕcøŠ[ _‘ÚÕŪE@jQŠŅÁYŸkĮ\† t˜ÏŲ( Ģ–W)™ãĮcä ĮĨ›üĸ5į‚n-đ&2lÞĻÛ2Ýsĩ­;‡q­Á(A/SeäÖčn]Ö} )ІӸ•KBB; R†0ŧŒ”…žŠeÞᆄ`ÆZ—ŠÞÕĀā$―% ļ…hķN-ÆĒįƒDbß,ÓL?Ŋ\Ęk|ŽũxK‘R’<eŰĮ}⠊YïĨvÞïjWŧ>ÁRksh&§ÐVįT,°2ˆ… Ö`ĩHjČ[KVÎāßÉDo ”AĻ'ø,„hÛnv WސWVK }Q‹#C–éŪ3’@YD[˜Đ{ØŦj§$ļ%˜ŊАbēQ€Ø=“Ā&ˆþB?ŽeabÝÃŽ@•Úįėđ݆Ã|6EÁžsdÎÜBëwFũ̓ęŊķĐ æ^Ï.ęˆ#faĨ/ēûũýĸoĶΧ‚ú—ïĄ]ö/… ė˜‘Q‚b‰íŋÛÅRjEu\DŒ:Î|Ģg)ÄË;.ÁöÎCÆĖ &VÃu›“Ô„8‚~íNH2oЎ‰-`Uے”(…ŌB1ž ŨKčBGppô&,ôúĒŽëô īėąTęÜ ÕjyQ”zYvča+‚j31\l{ĩ†,ÐÛõÄēģ{Ö'―ŅÍ+[K ”Ī^ïō!čÕPU•%äČŲJ/Áä†>ŊÃh[ë€@gJ“hđ;–‘Žŋ$Wbr-$ĸ†öđŪzÓŨ4―Ļ-ĒÕ.ŽíÕj5ú€ fB§@íZėVRČÂZ„Š–uŸ”ë ‡íΘ­pYôÁÂBČ1,YZ‰đÍĮ‚ŠæoI˔N„=ž ë?PRQË24Œˆ2 ― Y./ąÃi–øZ‹XHL.sD\Ö+aąķ”,þ hđĐōõÄcÓޙÖ|/9Đ1VåŧKŸ5õ‘ųUVS•ņųįžÍ2V:bðŦŽY™ž|â1Ģ.Žžę˜æÛĸņäãEŅ(ĀcqÎS…Ņ„ų%Ęērč°ôú‰°nābu8dūY ŽjšwēV4á0 rläā4\6*"}’RRŦŊŨólˆˆƒjÛßĪM~Ģ$;ĮĢD>ó†—Š„(Ë3ųũ1ģfÍjf†Ģyw‡iŦŠjĒŠŠZqÅՅÝŪ­ķÎ~rĨVˆûˆžnUC―QfÞw5šÆïđWSgŊļėŌ3O?ÕđŽWϞÓfL>béÓŋõ­qk­íœ{ōÉĮŋyĘ)Ï>óÝũ˜pâɧ9ï^~éĨđsįQR"Ô.ŧí~ø_―vÉ%+ŽībÓÜÞÔēĨGŽl*æüųóûâÁ_<ôðŊ~ýļ'ŸzōÁ{îëČ5Ã&5 íWŋþ­·ÝæøãūQËģ3Îüö˓'û6ÞdÓ[nūųŅGîėččÝŦũž{íýŋ?uÝĩŨŽZ~ÔsÏ=ž'ĖĒD™ēYlYŠ™Āų&IŅ!=ĨĘNąē€‰0 /’Ļ”ÂéiUÍģŦ vÚÝ NÛ ŧËZQĐQėŪ*UuÞŽpTč0FæĒjč"tTŠĻ%é•ó˜*Cņ:O(^úũŠŲÜþueԇßUŧÚÕ^Ėĩ>Éy=kJ)āī'Ŋ5ŋýũŒ1.XÐ%D`č‹7ÚhãfäÔŲg}kÁ‚ųãÖZ§9Æ4xðČĨ—ūæęŦÏ>óô5ƍÛd“M‰iđQ̚øf“ÛÜđēäāË.;ę{îIâŒ^c2dÉO}jŽ$Ųpƒ \_ĢGŊpßýũŅōĢG?ųÄãW^yųāÁCæÏ›ŨŽZnđ+/ŋ|öŽYėŽãĢ”)ƒf<%„įÂ–č‹ þlQĶ”ŒĒPĘ)čĖkÂŽKbėҁÆFĢČóœ―KĘ9KXV ÃP\ĩãSRĨ}n–8IEmvΓ ī Nå2žcIÂėSŽ ņ1ÁuKĸF%‘Nygš­Ē}|ŒĒ hķī"ōwÕŪöŽķ―€Ī%[W VmĘÐņđđMU›9#Ïó#G6YömŲå!”ëŽĐ9™ÍóĖäcþ‚IRÓøŲT•5”õčŲóŲgž{äáG_íUįžYb‰Čbcūœ€ŋļęį<úČŊŪšjîė9‡zؑG―ÍöÛ|ЁûLÜóÐÃßmņÛl·ýĄþŊwÝÉėfC„āH‹“ƒūŦīđw F į>Į‚ųl—.q9x.Ĩ™ŌDĪl4ā§ ėŽ#nđqËHžÕF–(&Í+ŸóYĮÎBz,$‚‹Š ŽÏUš ĪŽ1īÕĪņėD ]üũD­gŊ>#GŽüX‹õíÛwÉ%—ôÞðýīŦm0h˜“Ά~}æĖû„ŲĨ%l?ðƒÛí°ã~ûíĸΔ)ÍÖēŲ―>þøc/M~iô +ŽŧΚM%nž„LzņÅ9sæEąę˜UWģÚ:ëŪŨlpbŠÓĶOk ņœŲģôƒï—Uĩä!o―ųĶĨ„Ę97}úīwĶNmÆþåŽ;yčÁ!K.ŲÔéå–õęŦ/õå#NĸÖY›lšisXņĀýũ~ę)O=õÔŨŽýúF›nVTåZk­{íoýæ›o°gOØ|•Ō·ēŒĨ.’PZÆ<Ī* ķM‡˜Šē >sžĢ˜!Áuũ°ŽH‚:smÃQ:–Bæóē^ gSrFÉyã1Ū#TÅŌŧ`kuėÜc%!oÝfôŊ–ĶÉP"ōąš?âĪą]ĸĸĖj…Úĩøm‹9'Il_Ș­ČŨųË_\9tø°CųâÕŨü†ˆæĖ™ŧÃķ[Ÿzō _ré/ú‰ÉЏ~páĪI/üė§—4ÏkoøãëŊŋÞŧÏÄŠRAī0óŽÎŽĒ,.8ĸÜïžwÁũøÃ·ßz{ĀūûģûũëwČa‡O™2ĨpóÍnęø 7ýyúīéÍk6Ņ'·Ý|óþÔäþãO―ņæë™ËX 4ÃJ$B™Ķ;b‡ĸS<#ķ―,Ļ’Jš_üāRaóÁØ-‹ Ȃ,ĒTŋ-ËŌziĒĒQbi83°zŒą–Ũ„ˆÜt'ËóBÓ)°·-dė†ü_æÎĀڍ ĖLÚĩČč#æHĨÃshŧm1lАđ5Ô ËĨóæÎ=įŽ3ođéOkŽ[ŧQ4îšãöŨ^}õ…įėđĮn›nūEČē›oúÓëŊŋ*Qūs֙Ï>óĖĀAƒnøÃĩĩ<Ŋ#QüœoŸuãõØtģ͛íí}ũÜýėsÏÔr%ÆNgÚ~{O ™ïėčņ—ŋÜ1a]6ÚxÓAƒ=ųøO>þąüýéŒĩüĪ_ļũîŋ6―MÍæwĖjŦ7Ewßų—_|ĄŠŠŧĸzŨc?ŽĐ9B6"ČtŠ*­ßŽ ĒjNx7*ëĮÜ(tĖŠóŲĻe™h ؍ôF?Ę r ú—Ōl‰1iáÖō›―QŨ‚EÍ­=`‰ė3;î#R­Q ŪXÆBþĨ Gāwi‰^ūŊüąŨgū2ãE^„›žvé)Eþyô•ˆfĖ+ôé·D/Ÿ9jŨâ2ŦUAą_ĩQ„SĶ\ŨdŪ<EĢņĀ}ũþ큈Đj”JEŽÕ&OjÖ @ĩ:L{cĢŊýÝŊ‑ÕmˆjÁüĮyøĐ'žÐéP[ÎąūĒŠ^|ņųĒ(ō,oÖ+/ŋ4yŌ‹ÅHûýŊŊĐuÔTõ’Ęßí7ß|Û-7cÖÉÍā€Į}ôąĮ >_œ„q^gŅd-Þ ģ&į°[A„°k4 UH‹ŸŅ klƒņs% yØķ˜=;{Æi!ŌĮa&TgĨŨÛ(JÏNQčØ+ÎôÐŽ–āëē Ķb|‰< ËcN'ĸDQ(ó<ļ·6 ģ?­ˆL‹pĩ‹™Īü°ßŽ=õë|po=Š^līķ-ĩ Ęē/ÂĒL™ÜŒŸ82ōfã7ԖŠ‘cï™'6oރo^z@˜]@)9ĸ 2ÕRjŦSeYāā*$Č1 !H ˆ*­Gą É}ÁģQūĄo᚝ó Į„E)+‹YĖÔcžŽ'_ÖKrXĨE!hŲq–āaĀ;€Ņ…‰―ó6E!ā\tgAÏŧœØDB˜l‹ųí>ÂĀœ·―aĪU*QĄĀúŊę:ĖúÐąûo„ČŧĶԆqKwސ/(’PŧÛbĒđØËũïᱎÞŪÅh€ BÄāȀɏ"†=ôÎwOC"&Í{Iđũ Éc&“†2C7K 4įËqĒ„']DZAËþ ó Qē#ļ ÐDņ  `L•1óN1FŪ!]„‚O^|·Ø™ŲË1‹ĪāU’-5‡=g.%`%·!ƒ &Ÿ"‰Óįm7ģõ3Ï Ų&}ė°§ nō–ÔË*Uđ†cŠe ĸkU nHo7ĻWi7:‹są‘.ÚsÚÅo€ ’ :cœu_Eäū8ž;wNŠâž3ߒ$Šé‘‘J‹sōÐčj8r>ïæ·’ [ÖįęwQ1ĘóLώž#Įķƒ›9+7 åíõĀxVEĨķVJ:ũlV,ƒ Äl.Ŧ< …ĘĨĻåĄŅ(`l`p_9ŌbŠŠh™’ J‚Šę–Iî<Ų|íĩiĩŦŽÅ+\†ĩīķŌSoÞJ PK_ôķ𠓐į,ÜŌ˝įFY%–'[Œ‘OŸ€j—PŧŧëX@y.ÚÆ@"õŠRôŸW]Š%oŋÃNŦj f~ōÉ'îŋïÞF}ĢbF‚Ē€t’3<+'A8cUUĨÓÎÖ[^·€~ĢAŋV'ĐbE5 ÜŊā| 1ķeđÃČŠÚÎijCĻ^F,Ĩ5ŋŽÂW”%%!G[ģ ĒÕ1;ΉÄĒĖjy^Eä›áĀJ=^N›l―°(&\ÕL0tÞA[™ ĶQŌ(īĔĻLe āģŽJ@ rdƒo―NĶŊ‡ë‹#EĮâˆÜ'óßĀvĩŦNĖæ% ôp5Д0ŽB…?ųäĸä§GóÕŊuôũøãO­þĐz―ôėmDĀä_–gzĢkÁ|\Åbþ‚y‘U‡ÔëQU·ZyĨUnđãÎąkŽÓް\ІȎɕðdžĐŌaHĘčYīU‚LU–ČÔ%vļĒ ĶbɅĐŦÞÍ:ËJĖ— 3~Ŧ„ãŠjŪīųā„’đĩØ#w0EcÐŽ<dØŽ+!6 ;­―[ïƒīv.ZīüĒ*ĄâR%lsHōØ:S―u>ģŪŦ―N”SŪkpÍKmą™ÚÕŪv}ŌĪ6ÅÔbb1’’ūĒϛ7w·ņūðÅCĸ?öū.ŠŦ}wfwaX:Ō5E‰ėą ķD―ũÞą‹ØƒÝh,1QlÄŪą7ŧQĢØPQŠTiŧ,3ģũyÏäÞ_îáKōqŋûĸūpā§ģģgÏ93;<óÎóūïóͧĨ3jܘŅ[·lFĒmįÐC†úÕó7yrPãÆĻíÕŠMÛŲsŒ7îӚ>úbƒFcŅū}Įi3fÍ_Üšu[{;Tý›=A?ŋ1ã'Lš2-7/ÏÉđō€ÁCÂ#–‡†tEúą lFV;|ėļÎĄ]BBŧĖ_ļļWŊŊŠUŦ1|ԘđóvčÐĻDŽTÉąoŋþóÃ#F‹LķB]!īiÂæ-ðôŽÖóŦū―úöŨhĖ|kՙ4uÆžáÐĐL rT+UÉžLĪL‹āŠ­ĀDu–ƒKéģŠ Žc?c\čr ĶÉ(mF’ā\1øjŠu&Éũ-ØŪØÉ .-k 0Ūįšð―Â6­híoš˜K’­ ^V†Ĩ€EÏ{Ë-aáŪ‰üzŨŽïŽŽ-Š0N˜2 •Eåԅ æûûŨŸyŌŋĸĀÞ}úôčęáæ\ ðúøøėüîŧÜ6í–._ņæMRAA!F˜:yԁ}{JÂVPēēˆi~đeŋœð+‡ WoúR ÃYtAf!STƒHž@=åL-tæČ§§`đČāFö@Ī*ļŽUĻÄĀĶJJíÄó4įßŊUīŠVaÕ jņ(Í’ēpÖĻseäƒAÕĘÚ $ĶÆTĢPԃ<@ðä‰ãÁ‚îß―ũUŸū‹6‰P\lÓĶ]FZú }ĮŒ6szqą>0ĻŅ•‹į ë/"|áČaÃ6lÔčĮččđaģŪ]iŨŪ―_]@>æGIsé{=rIx8KÍ*2 ïšÕ‘n$ä6lœ]ŋnmįŽíįÏ ƒ„nHhW€Ē,‘ŌąÃŠeĄ]ŧBúdýÚ5Ë"A+ KŨnPc…Γ+^ æâ%u4Q°TZf㓔'‘Ū‚qĄŪDþ@ž‘ŨFÚ/Bƒ€earúó›€nØ%'qĖ:f=etRWЭĒýÝbĀVļ†,Xe\2FL?˜xÅz=āÏã€?Ķ|h”K‹OŽ9ō,.. 0=Ą5učČqŒƒī.ЭÚī™:}fUOOČËĖllށX… įđœėėܜK­Ã4 ۀrsÉn•8žZNN6ōÁīŽÛ/Þ―uX:wÞ|7w!˜ø&!!čåč䈞2ėžråō훱ptpÄŠ–­X‰c―>|/Ē/ŌĄēš\P]ÖÔö1ÉŠæÂâĨĖے„ u Ī5Pėî”Ŧ\G.ÚĻäÍ,r‹”öĒ3FÆ&úēÄrŋ/˜ŋ'!ŋ°@ú›ē­ĒUžaVĶĶjEˆk#'äÄŋŒoÚžy›ķmŪ\ūq/{‡JœDQY< 8`•ūü ÝĻà Ųûũé‹/nÔļņÄ ã’ũø‘R~­^ËÉB3PĸÂŋĮûáŧxŨÂŌ2þÅ3ŠW& ÃpžœJ §NĘŌÏd <''ĸŧŧWÁņh4jôÖëõ4,sũ“ÔĄÂĻÓ.į˚óÁāõŪåû>-5?/OACģ‘ĐI@Tōqą#bŠ`rmV ã Īã…C-aqŋ@TđāāŲ„7Á―AÉŌŌ0$fdē\†Ýh°•…dHrN]ą)́Ŧh­Ēý-ĨÁ™ÏŸ7R˜DT&Ëz’ÔfęĢGCXkАĄūuüðhoie CđjŸœÖ >Š­Z}>fėļļļĮ d·}ûmq1!WPƝ;‡Ē3@H'â°á#6j|úÔOiii]ŧvƒh!0ú{úô&0•ːzkĘ*é*īf5Z9j@―ûwîŲ'LžâY―zã&Áē9wö,˜\ßBˆ/ųŧ”—/]jÜtčð‘ąŨŪUŦ^íჇķųîû]Įe!eĩÜ_ ÛĐa“ŒXXôؖÓį(­–9Į°ķÍ3ČfÕ.9‚č„{Qp―4”K ^YIJēuY•ujr”&ĨPbÖļŋ]Ŧh­jy^Ξb(ƒZ/öÄÄÂ%ssóÛ7oŒ5rÂĉžÕŠÃā}ðó=―NĸôÉãsgπŠ‚É]4ohĸÏę{y{CĘžĻÝîîp—Å\đēaýZŒĻ:°7ĘŨ·VÍZĩ`C›föŽ™ÃGŽüžm;`孛Ũ)ó• \ U°‹ÎkÔj *ĶļxþÂņ$^PXpéâ”`xĸbâøqÓĶO‡ ‚šØ~ôðÆÔKzö뉒XTã;wŊ;…„téÖ |řӧ pOMMUøvSá$8ʘ„ Tb~&Ī+‘ Û)WC*ÄĀģŠš8 #\P1s/åŠ3ēïKEÂâDËb:3[”S–A7c6_ūõ`X Lņ?ĄÂ˜„ß?^^—ûlkDŧRÁÚkū—Ņø 6W@-ü9Lš€ÔŪUTSëĸˆĪȐsåN•ðîís3‹Ûķnųf“VkĄQ›Mâã_Œ5ÂÅÅ fé›Ī• áï―ŧwP?5#ã}aA!FÓZjŅ­wÏ/ÜÜÜ333ĖĩG:wæīSåʅųųĀ@ÔhāH`[ĖÎΘ8n,l@3ŲãGŋčÞÖĶVkųîíÛ]ŧājĮ,1Ïĸ|ũķ―ļā‚ž|øčP ―{hˆ…đOÁ āõŠeKvlߊĒÐ&r·ÐŽ~ĐRŅHJ ÄĄr 9Ģ\ÔGÍÎF F‘aTdá―ØKĀėģĻ ŧčÍōqy–žËąļ.‘YĘØ‰Ęä/ãd$%‚`ÛÂräjąÔ7oóĮeūI.!üĸ1“ÔÞVãýНOM{%SX/cÁøjpÃËÎÎ&^û?Šáz€F0 ‹Āt(ûqŧMcJšþ76üÅđšš"LˆŦhŪā Õ+‚™ŠŽÉQ2 `ÛBŦtĶž}‹mK +Ā F šÚ8t&ššRfÓRSðŌĖLƒ‹ čÞVŊÓbCĐīŒQ–ÝB!#KÉÍ ę3éu ßҚ‚ė˜Ri4„qŒ:’Ū6OeÃM™)„Ï*9Ū° Ļ  Þ*ÔäE€ĖÖÎV$4äåŌķ蜓õ!'qĻpŽŲaÃô”•ÂĐ,ėSF°Ü6RpĄü –(!Kũē7ēF a(+S†Î2óĪ)C‰<‹ãE 'ïJFôiý&j`:ÓrPĘ<8‡ßōhX֛äžgyK ûNĶJfÚb‰ĸÆĖQV―ÃĄææč.ÞHÕ õýËĀ HOŸ>T!Î<öüÏ,OðŅ…á€†2Öïëë NŦīĨb?یŒ Ðb(NņŅĸé*æÐ5…ēNn<æp*Š“ÓŊQÃK™f–ĻQ  G™‚Yvž’p ïĘŲĻJüČUĀÕJ_†§BE [‚*Cč @Pœ%üÓ_.ĮĀƚ Ėf”5š˜x.8PR‰e•―€›ēĨÉVĘ|wČIÓĻĖäbÏïē2,! –AV'A!Ïīoðˆ ō—”҃­^ĪC†ĐšŧÎtü<Ĩģ|0š…l[–)pŊ”äÆ:+Y)]Yq‘nī 6řÁÐ̓qp rNģÁĨŦ ]^ÔÁݟSŒZm5WÓFĀ™fšcĸūfÄ|,ŒMkkĨĩļ}?ÉÏŨÔ!>ÖX€JķnÝšĸĄOÖ(pwũîÝĖĖLÔ )Í*ĮõöîÝŧzõęŲØØpĸĨ G°·€ķļü‰Ŋē"Ø ļL‘„I`›ÝwåP'Z‰Ž`["72ēV€$;ĐDjÂÄ\ BYĨŅc"|ũjrčĸęRēRálŒLģ`jrbņR Ķd䖁‰fÁ1â[Ø% osJ&ã—áā ;y4ŽŌąUÁŋOS ØqóĀ’ˆfeY°č€Đ‰ ĩŅ:i6l#õG„Θ\ĩeD4`$ŧ Ā}ĖX,Ð;Ņ… Ó(Á^fĒ3t0Œ%ڔ‹5`ė4•ïÓÉ5QēŠ åeÕ*^'~°õБWdPÓũ"Gnüc“™QyNĶÔfükAŦĶâĀļ‹hÍRŌuA2UcĒ/Qwø+ý—þ8RNFongĢՔÏÝBÞ§Ĩií],Tú”īˆ$Ũ(Ë:įX?ʂ”qĒ(‚Œ"{öĸu3ŌSßkė\Ž5åó$cČÏ~_(š:W*ČI/4N•Žų2ï:>üsU;+ŽZB öd+KÃČÎ’”D <ũ[NA*„ũÖéŠ`q Œy„Œ—‘É,{dĩ {ÂŊ`&#$ŧxÏj5šŅóŲ“ļĆ˜LƒÖ ÓB$€Vē’9ORϰ<†_UšRÓÓ:ý(Ïr‚“æBH, žž=9Ęeūč]tĮԌÅȀN‚TĶ É|ē”9l‹ˆ+ ~#3đ2v‚$ąķąîņe/üŧuÓ7z]Ž=éļ^Px€)- ĄSR‰Üāīąe-ŌÔ<;âäŒĖ}Ë /ó‰˜ŋžĪö€æx(ðÝēˆ3üü#Ίr;s ĄkFSĮĀV―jTąãþ,ÜâØÓIĐ4‚Äؐ8-eÓ#rŲ‹ēg‹3ĒV„oøéŪZe9zÉĶÞÁÕĸïũ‹ŽŽ—į―d€OËGúĀũû;ģ3û‡5k }ūŲą6ŪüôUCGŨ^ģŋŋÝãĢV…EĻiYöĒņf|Ūģē;PCö +ïfĐĖx‘7ĩkÖĄ[sĸjĘ? ˜ÆŒˆą#š‡ïîVËöŸzóčöĸŧ%é2­\Ý~蔀O诐ýpýĻĨęý'g>\9ąĶՉy_ĻþŲyøÓėAEķ° e ezEÚ1‡ų iģį/]žŧuĮũ=z}œ0 ™˜čZ"0S‘‡þ, Ęc@aO€dĢpës8iRHHŒG €HA)+sÓð Ø#ˉb~S•šÁņ,‹+ÖéY„€ë%ōq“ã…\F žB D‹bBŒLŧK’9ÉØČ4h°!ß{eïr|yÞ dD–$ÉöŽÔ0âÏúõ@ÁģD·Š%L‡ü`°ØĪ P(ð–cąbøÜ((§‚R á]™Eá)LŒĒjéĪ’Þ NnØ_~TšĻĪb‰ûõWäôĸðkTåžŧ{隯Å=ųúÖusįūŅyAiƛYĄ\ĨüŊÁK^co/‹*Nƒ—– M œ*3åÁé#Ņj›ãïÆGgęÏØ6°í8ņ O?Þð–ņþžĩËw― [ķvlûEáû’ßúđIZMČ đMô›; ų‡"’oNî_uč:{S”ß•;žģlQøč…;SuZ‰ŅĀ›ĨŠ "l‰’ôÔ6°XJ“WþųMąī&…ĒœkgdkÝkļ9%^ŽîÚĪÓŌ#OčĄã7‡JkþÍk:ˆßžÄÅFĸΧ2ß|LdûÛ›Đąøjôš3ũ’åADđ1]ĪĮ'ÖÏ_ūýØUë. ĐžÁ,ÝB*@ •ÞĘ&s+ ķ”FV=ƒ ĀuD€3 0äääTĨjUdsÝžqÃŧfÍõë7Ž5ĨhóŸ_P€Ī€:uëÂÐ477ŦĻĩ°īĩĩmÜŽÏ1Ï;ƒqū~Œ&ŲXÛ ŧŽē›;ÖŌĘķ~`P-ŋ:Ėo&đđ{4kŲĘŲđ2šĄ?đŽ8ŅÕÍíģ ÔsŽ„jņ5BGPƒ––VAMûøÖFOH84ŠVĢzŪŨfjÔ‹·ģ·ŊS·^@`Ã*žÕaąšŠM …ÔĻIpóæĩýü€’ļĩ öÖŧĶ:[ZZĒ/4€Óðæ!ĢQps33s,ķ­NŊƒ}ÔÐĢJU9OÁÚÎæģo°sĻ„(7 ļÞ ŊVĢFý@$Ąė.ÖÚ!Âr.@[Mڏås#V œNāŠ$úÕýî·XRh­5ė6yĀÄМôā]HņÁŲ ‘ÓŋÜsôLžĪ,æŒI\7Ģgdøžįé:AĨÎËzķsqĸȅcoŋÎ6—·Í<žįë͋7$åŠúߍOó vNN}–[ŲFŸPJã8Ãŧw:ĸĶ-šô [üe›0óųÕI#ú5|ŌÝä\vƒš&pÉKŠ™9ŠWŊ>ÓoÄįðdz—ÄFoØŦgïƒŊ?{ųí†s§Ïž2~ö“4―‚a1û: /;fáÕĖ9íÔÁØ$…ėĀ萁réJ(ĩýA;ÎȚPzÃĐąrîܭ߀‘~ļxqnOˍs#_Krâ7LÞŦũˆ·yX†žƒ+æöîÕs|ØÂ4$î N|·žgÏ^+ö],f!™ĻqÍ,VņŅÅĻ^={N‹ü!_n9I{VÆž^ģ·Þļ}vōĖ9ã†ô™ąîXĄ°e įŊ0~UÔÅÆū~ðېđĮI€_d"IäĘjÅĪ­ X}CŽU m˜r„ üc8­‡þx`Ïn@Õķ;‡đgŨ.ÎB;Ĩ„átßŋ/lÚÔJNÎ_Ŋ^óč—_>ņúĪJUÏëąŨĶNž(ßũpyÏæ'MķĩģÀûöîY·:2•iŌ…­cįœé5đĸã-Ŧq›Æ4˜=eÔÞx‹y#šŠ%æZ•ŌUĄēó ðũvįEQþUõËģû_älûvÄÔîÝOÞųŲ Yč# ēĸåõ—jÂĸĩČčŠ`/‘=Īkˆ‡äĻ~•*d Ę,nÃ9đŲϞ>đuë֗={ŠÍ5_~ŲŦ{ÓĶNn.[ū"{ÆŽïwî@đÜ6íÚ!gŨąSįļĮŊÆ\•Ų ŸšūK–~ČËÅŧŸ0qŌ[·ŪÅ\;~‚Ũ§Ÿ4oŅâųģ§ōó8VĒŦÕįmg†Íþfã†ŦWc€ČáK—mýv uÛĩïxëÖÍĶ͚Cááƒû3ÃæÔŪSgėčQ>ĩ|fĖ {ðóÏa€Wtâä)wnß:}ę”ŦŦ’ÖŠT­‚˜°úõqamĐėęÚīi3Č&‚FĻåë‹þmĀ)xņâ9Ž·V-ßí[·Æ=zmҁ“ō?>Šž ÞqÝ`9ˆ@X+%ĒĀÉŋkôvŦð™‹úõ:9aíŪNâģŌš5)ČÎĘ;2æÉ˜/L/øýŦGÞĪ ČÎČ-.I{—–ýîĀæSíæÎ‚•Æ,§ŪŦWN@įЎjĢAOÕä€J渘]·Š zó’E]‡§Ņŧo$ ķXô4šH%īMŽĩŋŠUÆ1âZÃþ$šI(æLŒĘõúîÝŦOœÛ}–^ ĘyĸËģäĘÚüũ /S‚š„Ø+Þîßt2ÕĨÕû”ũ™ņϝš3ąE}ŠOŠČ?ģóčýŠÎYié)gß˜ÞÆxóbĘÜÍûĩöáT(ųÐ8ļAŠo›Ïk ųElMJS1kώ“Ŧ`ŪJ'Ûm;ύ b>ųķĊ‘b‘P[în1ōČģb\€%Ŧ§@ŅK’$į!ąHX%Ó”čņŲĘ š\ĀĶ&ÁMLUtÃu§Ø=|ø |áü.]!S‹ØÉóįÏŅPžēmėėĒĒvE„GÜš~ãôų ƒ›þ1bļ:‡x}ępčĻÝŧsēēÔj \jyŨô†Ã.ÆþôéÏũîA§1jŨÎö:Üļ~==5ĩžŋ?žčCCCmlmq HÕE6Đ+;6~ô9aÖoÜÔ ĻaÝšõĀÆ8°ÏÕÕ―cĮNĀw 3DÅĀK4mŅēvmßëąąāRaÎ#”gÁÜ0WWķÚ!Äü "BBC===q\+'ž|‰ $ũčjĶÖŽ^·“"†ÉģjUŽķzęžŠ4%$‰älXoDcĄhŋPN~1äĐå•pĻĄ”>^ˆŠđz…KH—9}bf ―vęĒõ€Ķ:)%y:eåþŸTm˜!š6ĩ5þÚÁ‹ÛÆŋčąĶķđR‡+ĐôŪ ›LëaĨ5ËJ,/ž[Ė TaããP+Q ÁáZߕð’’Ō`C!ėÅĩnŦ›Š?ué6ŋáž6æfæFŅŌ§áÚ^ĩí•/ LL^ŊįMČÍĐąô ‹čéjŠÓ•H*3SÁö’Ô*‹…’Ė%ÔBōŪĮŠÖŠĸāĖaNgå!$8uïģ/ĀY1žœ-)Ð=+”a’ĸĄ„ĩŌ 0†3É.ļp î_zĐu5Ģ Ÿ šljÃī…aÁÕí*9·ýaĢęø‰ƒƒûœ^ģkžFĨtÔŠEƒŠë’e^~~E…:‰LÁ>ZKŪÐā?bJgïF C‚ ōˆ―„ãcT!§Ø§‡ĸ™ŌÉ'œþ8ædBūK5ÝĄã1^ÞūNFŸ{6:ĀHšt"˜MŽ ĐjË91—A*(KĢŊČ å .h,‘ŋÄ@ž­­oíÚČĢeÁZ ĶJĢcŧ7**>>aϊ!ō ”ØT°B[rŠaĖĸūLĄÚEáýfšä·oðü ‚ÃÜĸYÁķ€ûrĶ–ÄÄī.œ;›“ûb ûöF}―zmŨî_ļļļB>ą° x‡Åc•™ßm߁Ēå*VĘ!#3CiÍ57bŊ―~ýš}ûĀVĪŦ%ūNDqAAAŨî=ėöDE9;9·ïØŅÉÉšyy(nÁ`@ĪŽ{5 5 ÆPOŸ=ũX­ŅāÐēē2p[;VFD‹'q=räÝŧd˜Ūļ\PÆ!hFFßō,F€Äzʍ@ĖLĄŧ‹YņQĮ>_‡0 ―ÎÜ1ĻÍČÁ›ÖˉņÚņY§Ö §XVäl) J+.=>-ĢZP§ėWWŠr3ükÖąĖįĖ>ų,X—›Ŧ51š˜›éēßf―~RÉŦĘĮ€ gE"EüŋČÞņČôŽŧyóE_ÓŦŌëäBGŸOęÖōؚĮiƒ›―O+0T㎋ķUę·M uNM;yįeįIŽ{ýī3b·ŋ™ŧ2—w ēŪlõjëŲØÎ͂}=;ļõĨÄ>ũŠÚŌýKP0Žũķ.XzōHŋC%ą˜9ä$ōŊþŧōëôųũï^uĖ2}yýÜÆïīė[?o'o—79ÜČÁ†ŒLxORã―:tlwōāŨIųöū š|üeúyy{Î p,4Á=Z|ŋėGĩûčājšī|ÉÖÝÏ'Ā|ÎÚuŠî†<. ĀËÉÕ>öYėĢĮ>U­xÂ|ņ…3'%ïÎk"§ZKÅĶ&ŲúÝ6ïļTŊōwŽ'ÂPþđ|PËŠ`QœŽ‚‘ķôÐÉęnņxĨX؊ĸgþ Ó{~Õy2ßíØþæMbJJ*`.æōe•œ˜Â,•@„Ýį_Ŋ>ŽHŒ€ JYC\DĘŧ·§N?ĸz~}úõĮN°™)ïÞ9xpÍšõøÔП~éÉփ‘8<ĄĢĸãGŋėÚmĨÕÂŨ“•͐Ð9pÐ`dv>þlCJj °ō`ôþÄĪĪĘ.•ÓRÓ==Ŧ2Ϟ’*'r ĖûÓɐÂpïÛģ'=õö歛-ZķÂg>Üš8Ą]) õ–Û û]~  ˆ]D;ˆDXG'%ūvquwŒôb9~ ģäį%ŸÄÅAX)Čhķķ6…°ŲĐĮč^†aYvŠ2–ƒTËĨEsŅ\ÍSÖÅĮÜÁøNũz5 ­Ŗ‡ôM}óäÕE—AóB•ŦŊ{ÂŦZLóõŪ–~gũý·éĶN Z·iagoÓ~ÂÆŸķ-ŋðÍÞÖįóás<ü>oÐävÜūMžaKœ,MĨßÁ)ŲVĖŠÍæÅņČxLFōþ‡ŠDÉĘÃoÝžþ•\,—/XžzûīkUƒįMéįåŨ:ÛÉLe[uéáĨË6Nå=kÎ^ôYÓÁóŨîÞīœW™õ˜Rŧg둭.-ŲŧóÛO—,Ŋjaä•bZrþįÃúļÛŠĄØŽóKé7r‹Œ> šđX)yĩ]“ĶÁÖ&å“ÍWķk^ĐąŪSŧæņcÛãäjíôõáC5CąrŲ–…ŦfO―ŠR~2eųĖŠ™ÖmÎ0ōõFOëRÓÞĶւ ŌšU ĶņžÚ·ũī Ú š6w5WTk;b…Ī]ōí’cžÂŠqŸ:õšE,_é°`ÕÚeKUUZUóŊÓķÛāë ŋ]đäÜ7›{˜+đ’b„lVÚ­Î„Ļ‡Eä1hÆðĻŧ õāđžëK|đŦ}VTa()Ō2a+b‘EĐ\" ĀÚÐa#ð ˜ÛšuKÄĒ…ČpÝēyc@@ĀŨkÖĀĢUÉŅiӆ ŅûöĀtCēCôŅĢö(°oO”ÖŠb!MpõŌåo6m1bÄéó‘Hs%æØáƒČ ļÎŽN@í…óįōóóÍ-Ėåâ`{výk”nïÞ_f―sįö/ũï?|ðāÞ―;?öė“Į4ëWGFŪ]ĸCÔÞĖŽŽJŽŽpPx9QPŊą°Ļðܙ3ÂëŲ3§ĖÍĩéĐi—/\hÝŠõ›ĪĪŨ‰ ãâBŧvKL| X41ĨÜÁā(ä†ŨŊ^­]đ`ÁĒÝ{ö[@„ ĸĀ4fĨÚÁĻ嘆Ŋu›ķ3fÎ0hĨÖō䉐jœ9+ ũ†C?îGl2)‹óJV[’<å jMyDp˜*9‚ōß[ËÆŦ}4â™―Ķ Ų„GĖ™ÞĐûŽĀ/Y7ĐâWģŋĢ €röô°ÅÍ=ęYmd ‚OĐ.í'lëĀSīPõ·süZNä(…Č&ō,ý+:,W't`t— ēð ó ?Ž>­·|ߖ‚ 9 å”―GĄ€gQĄÁæ“Öë~héz}Q‰ŅēûČð^cŒF^%âĄYtYŋ-JdÓÄčŋÞ3xĻëOšmYÓÁ0SVJ†"ÁXsâĘƒN'KĘ2Vþgz"ģÅ~āŌÃÔō+#/3*{ïé[wMDdöāk’ø6ۏw4’đƒ>08-ŧZÔs, ðã"ƒ4di$œkŪŪŨ~ČąÎÃ`.)qfô%œ“oø:v˜zÔßģkŋųPgž1 DŊÔvŸ8bŧŠ OZõu:Ž åôiEvēï3ëq"#ļų á/4i‘ŋß “qø'Ž17·―EÉW$PĨ(.Ą Y7w]eBČčâę‚XfÝžûðá}€Žg5ÏLīŒL XŧöėęõęŅMvËØXŲTvsÉÉÎÁá8Ø9ĢaÕ➡Qk*9;ÂP}›œŒŋ^ŒŒŋCė‡uėUÓqbHÞ›‘ø:ËC ĖöԔØGHžģw°oÜĪ)˜øÏoÝļž•ÝĨ{XÁØ"SŪ3ą(<Äqž2rmA~>ĮļÝWŊ^C;ĒjÕ*D°üáíģČÕ?<ýÜ\ ėĀęKrôûĮ ŊßpēQņíŨŠUŦ4*.ØØØ&MšČÄô_›ĻŒ#įe9úŌūÐRÆ)Ũ3Á)Yūû͛7[ķlų_Œđøšãã_âŽyxļáō.‡Ä\œ,%]Ŋ &‡`ßĨĨ§‚$•%Ŋ˜8ÓˀEÂčûx"7)=ÝMŅLL ux#6”‚‰ÚTWXôäi•Č%aoãí[7ˆŒũ$q”C†ĩkÛÖÛŧf䩕āj5$kKh™h€ Tė‘#?*lŲ˘‚ēb 6-ķB_ięÃ˗/^―RQē–HôŪJŒ{‡Áåz 3Âæ6mÖ ęāûũFÁá!—7ĸĸáýƒũXķsss@ėŽ637CŠÄëW ø–Æöe|<6°ėGĩīgOž€Z‘5ŋ15â+0 FPǃ ĮēŽ=Œi! ŽĮ(į‚ÖY°Ë!ĩhG`pI*™ø‹――ÝnÄŋpvķīu°3%ąîß|Ų“CŒUĘÏ/Ė|ųĒšŧ5ÎiÎ"DځÖwttD 3Îí–ð ūMܒaŊxyy•ąr|áO‚ ‚››.žĸÅÞģFqüýįíū=E#ÄŌB‹!–Á|‚ ßÄ";‹~‘ (~ÁÆT6,RÅÚBc°ÉKÞøŸ™K§ ‡áŽ›Xė-ŧ3órŲߎģoĸoþ&ŸāÕqxxČoóŊœ]XwŲ]Ô5PíīEŲ•’úûQč†Î—ÏŠI•ûÉPd#š/€xē·ũ‰õ ũ+ņHR"ð•n Õþĸn[ŋú`mĨôŦ—/Þėî2ī#þ„ĮHžýŨ:ÆË™Þˆ~$Ä"]Fēr›ü%ĸÅ·G&Аl>pUGŠ=ÛÞzĸî-ņg‰.Ä@捷›; ĩÖ,RŠ –SĖ̐ækéŸg=ĨÆ+*dš8pOiÄÁšũĖCãŠs‡ŠjÛÍóœÖĩĮä7Þ?>þüõã‡/ėóE éŋQë íģÞYūąđđÎóãŋæ<ĒjFĨNE„ũ vĀ8– JĄ•••ƒƒƒo|ö0§€wÞr&;mÚæ&@jöCs.‡ ^LPF:éƒ}·’ŒĄlےKËįO·E2š†ÐÁųS DôĻš·„2ŒčMĄĒx―ģCo|ŽÏpŊ–3Zf:Sĩ[QiZJÕÁ ԐîZ>u!óŌ cĐ‘ņ ØÞz ų2Bow‰9ęŒE †*˜0 Ąé#â‰tH&ãl€îœ’€6 æSâBg’g2ŧÕRmĨ”(9ýN’Œ"`Š–ĸßedÄĨĨ›mŽĸqüëũÕVOĢkÃōmÎļŧuAę:jŦŦŦĪįąŒ…fÄb5 vØOã(.fĖPd‹Ė› shĨþøÛ˜ėīÅd/B―@\Ÿ%NB@Ų*„šÄõŠjui+—,8ĐIÉ/ïäXŽ~5_MÖi â/T ŘeXT9ëöCÏ~*Ą‡ėˆČ҃‚ģUŲ*ŨDüŲ̐kQDŨZC­ŠĐ˜V–ĶRˆpeï%ā˜N™zĩĩž‰Ŧq%Ī8‘8ų’ĐR†Â„ €Ĩ,„5<Ŧæđ/ÜI393}ĀøË.Ž“! ĢŧĒL“™Å‰Üi°–ũ‚ĀœSžþųį~ũÞõ1ĀõęHäÉ\Šû -I”fÖ.Ķے[šk›ðîū@­šJė™pÍ―æÕĨ wĐņƒ$ĘØ;ƒi’Ü“”"ŦũmlŋĸKؘéʐD†ūÎaŋūSĄ‘<4K`„DJbuÃH…íššÖQ5’f:Ccx·aR=Ýŧ"’TÍØŽĖ3ċŌZŊ]•D2bßoEˆâBU‡âGga;Öō ‰ēîû&‘Þï·Ļ•ó~ßRÄ#J;"Ŧ ēD…ÜM0"m‹qÆãvwFž—’DĻÝ―ïu­ˆčąÖõūßWĶî‰P(LôÞ W.…ųZŨyëĩ’Āņ‘IõLÏüÝĸųüųý·ĮŸn1ÏL /…fflÂKyï陠2ó”~`€ėnBz\{kEŪŦjc°ÖĒÐ5]“k…bũ˜ĘÓU+ÖĐ:ŊĖHu ČĖč7H Žýi Ī]ÛãĖÆî™ĐQĩąāqUE2ŋÄWø>öąkÎĀüýÞđ22Ķŧ{2âÄ"€ˆ13VˆŌ‘ÅČĸKū!ϧ~>Č`UŅĢHĩw(”qÜĄØĩIЌČûū=^Ũ"ég{€øðáÃo7ŲË[Ąé6pôŦ~ĖÐëZ=åq(OšĀԄr<㉕Ą°Ýc… t?’"P}{$ė]Ũʕwݰ3$ÅŪęŪĩÖLƒxĖÐ%…{ÚĻ.€ž|"`ĖĖĢģ!å]7?*ŠuœÓjQĄĀĖqK"âļšÓ "(3C "ŧšĪŒØU )čŅY{@ˆpOHfššg&BåáņyŽJÜũýÏn|øðáũ’ZēšV.‚cȈéŪ{Û~­ŦškwHāģŠīVîšŧįHawW=+ý”lĖ\=ißFŪEpß7€•I?HėîG›båLÕ™+ŧzƙë$ŨÚūŪKĒ )Du·Ļ_ð‘K2°ŧÛðĩNØûķ―ÖõL*˜Ū’äņ9(“ôļÕ8OÜ@*ã)ąíg4 {Ž­ąrÍ lk]=SÕk­sBh82mŠÚ~?ĐĩWŽęŪ)3ģŧu[’vŨÔ\ŨUÛ31~Á€Qĩa„ĻP͐€!ifxΧŦjKØŧ€‘RũĘé~ŋg+ŧk0Z åŪ]50Ï­,đ’Ä}ŋaūŪŨū5œĘPUI É Į4šjWņôM+äãTLĩĮðxvÝ3LwÉČĄA)šÚ€ Þŧ@ūb{W‰ÎŨz­H{l(BÁũû›Ōßvx]_ĩËãOUûáÃïØ˜ÛhÄļũ!čXAģ{"eāûýÁ+m'Ä\yŋoˆ#Öūß6%ŊžAŅm’!i?þl*$―ïm+Öō`Q™15KJfWapåīũkĄĢđ îÞÐNÅýŧW.Ã=ƒãˆu<ŧ{@bÅzï7ŒŠĻ*IĄŒ―oōø›‰ëZûÞäģ˜8=į―\3fh…Nm)ŦvÏÐDļíCĪũą"{Šŋ>|Ī–˜ÉŊ|ýu“Č–§ā)Wό+­Ļ]ŒfÜß·é•ë„ĘÔîsōc€`·G„2ÞũýhnFæÞ›Äz]ÓUc‚đrš{ reötۙšqշ팘†―m^ŊŨôLRKđ{ąVΌåJ†B]M13ÏÝ^>ŪÅûýœy‘°{­Uĩ§ķąîé)į ũ―gú_W5žÓķĮĮ˜Áp*Š6 P2tŋßyl…Óĩa)ãä§ĩ2ߏ[B("ņōáÃįXŒ€īÞû I4 SĪpïMi­ËeOOãļ“Vdāą5ŧŪëuRláVũ€Ęîē #ĻŠ›âó@•™=UÝ"Ū\ŧvuK$9RŨŨ—îō8"jUžPÜĩOĨIóÞ7ÅT ÜĩqZf0 Ũ9y#C"ÞupüY ŋxTÛ$)Á†+#ũZÓĩļŪkïÝcIĘčG͕ũÞÕ bzĶMHĄÝmûņdb0øųðáãÕþô˜æĩBŅ=†tÛĒ"ŨxK‘+ví_k)ĩû&ĩŪKÁýū FFMÁÄ 2ko -Sc`ˆŠŒigdí}>äĘũý=í (Þĩ DÚE2_ËīDcŪžšjÆ0Ĩh·ŋöĢęųˆÞD0ŊœįҌx”―ƒZZ3îéÆ<­h˜^™]]S™‘Š}o>ÝÉNæîz~@‹„}ßï™ūV’Žqf~­/]ó<SM8W č)šø ųðáSÕķŧš ˜öžē-Šŧę}ÃÅþþîj˜q:ĢĶÝ3―fÆĢ†§ģ@šjô€†ļënOdūžLÃ]ûôŨÞũîЕQ.à EÄŪķM DÏĀ– ŧęŽdæšwĖX=ĢÐĩV(ŠvïšŪÕĩï.ŸdõHA.Æ#øÝ2"îÞũ}ƒļō āu]đŦėĄ-žJÏ·ú―7Ĩˆ8w3"âĘŦö(†ÝÓ}LOQĪǧL>Ï`p’Ŧ ~7>|ø\öšë ÃSŒg‘ZGFfäŠ'ėsŊ\+“ķ‚ ―{CŠL“€Į&YSӝg>K’™Iˆ‚ŒeÚ=TddwÍĖ™]ģïÝŧ3WÃįŨĖITķ1ÝmĒ{H šæģ ãk]=]՞ÎX{fŒPōīĀü…AƒeŒ1§"ŪjĪÖšö.Ēȟ+ūÓÓ38ÆČŒó‚ũýOƂí2ēįd§„ƒޖ2# ãwãǏŠĖĩũ&)†íęRÆĘkÜÕČ'qÞĮEmÏRĀči"ĒšŠnÛŨšfÆŧÅ īëŪŠˆ Å{ŋkwf’8z“Ą―ïŠūV^ŊË6ČLŲ8E.Ĩ]ÕS†%Í4ā WŪŠĻ„ûýžž šŸ"ÖuՔ Úó,ž$ũ].ŊĖq{ÆF0vÕÁ•ųXÆ‘GÓmŸu SXkíЁĩ’Æî2MSėîɔ$ÏHJiïû―wDÞ3ņáÇßnÜL=hsáŠÆ8VTmؒí}"ŋ‚ а§]R(†ĀĩŪŧnĩVJU!ŪĀ3Ŋëxwį3īðūoI„1Øū\ŨēÝ―#–Č―7E"֕ũ{Ž Ûï}?Ŧ}gÚĀ1š{āPęq{CĀÂýý†ąrØĩύŨ}ŋ ÐŨëkwÁˆP ŠķĀŨëËÆūß!)Ū™Ųû&ąî'„ęœÂUïKRčûý^™™Ë`í=ãŊŨëÞņŠ‹Ī{„>ü–U-Ĩ™‰ĖéÞũq―Ūî!™k­ęŠĐȈāØcgėˆA`š=ýˆĖU] %ļŪ”‚8cgŊë{zB$ÕÓ|>(Ģ}ŠGIšüTĘ"beT•āĩŪ<ŸđŪõlÞӃÐŪÝ3Špï[âxDđÛ3đŌxړ‘ö@šr­ë:þŽRëŪęebͧB‘Óm˜VæęÓ♊ęšņĘ€\Д„}߆ŊŨŦg"•qÎĚ!ÛøðáÃox,6˜ĢJcdäWũøøÃęTxßũtGh~"†@ąŧ%íÚBqšÎDFĉÅųúĮ—íyeļkŸz°ŧlKaãœVåĩNÐÄs053ųZ~$;s]ŊĀžņÏ€Ýą#FyŽ‚ŊgĘâ˜t€ęÂÓŅÛÓĩ7‰PΜWeP=%1ŊeĢĮdͰcåx(Ī’äĖČĀíģ{tÍģ ŪžŠ6‘˜égk úĖ@øðáũœėĀĢÆ$ķF†ČÚu|OEœ6ĸŒ˜Ššp­Ü―1~b^ÕMÂF{ßįuUUÓĒråQC<ōô…įūïžÃ“Č“š~K‘kí†==3:ÚJ)2Æî*IŊuu7ÅȋÆSÅ;Wō˜$df’Ü―cÆ š;3§ËFĪ`VÝĘHČķgH‰čj‚Ũë'āÝ6P3Š AsfðĸāøũāÇ|°ýũH-Áûūĸįŋš{­üŦ ķÓŲSÝý(UtwWSR觟5ŧjWc†ĄŋūŋDýĮķ-Đįđ#œęrŨ‘Ą|?•ĐĻĩÖũûâŲ3”úŪëu}Ïũtg„ŸĨF$Áá$c“=ÓUŨšūßÓÝWÆŋĒ?ĮXˆŧŧņüüĩĸ|Ī"§ŧš%Å­Swgæ<š>žx6힐"uŋßg.Ïü5=ŌņIŠZÄZŦgjo*ÖZþųO™đŧ7ÆW.ƒĸýįûübáð`û?þųŊÜŠîÆŋ>|ˆČéÉŨŨŨß#ĩŧę?þóŋöū_ŊŸIQ{ßĮ–(âĖ—‰‚€Į3ö:Іˆˆ5ŒžÚ°§ ’˜ņņâDŅĀķs]ݛŋĀŪ­JÎÃįÎ,)§›’ĮGF%‹ãßIgˆPU_ŨŦzÃ8ūíØ3 JRרּÆÏôŽĩš įÅ3 # WÕxV.ü ęquŒ‘Ý”ícqœ/Öþ—―{ŠŠÚãūÖÞį Ę;”hĶN>æŌõ^MģĒrî­ėÞk>3M󕌋 Ļ* ‚`DjBYĶˆ%‚ZˆDāįyœs8ïsöc­u7ĮéŽ3zļĖÕfÖĮö°{ģÃĖũ,6ão9ÖÂR–š…ŌĄãÎ[LͰ°1‚ ޙģx]ŧVŦŅhEQ= Bhô葄°99!DڑMæ˜ÕA'rŧúŽ―LîųupWÓc'HßĨûwvRāī'ÅÝhķûwvÞ,„/Øíķ;ķŽÝYBEQ= „@‘ ũĩÝ…Ē(§þŸ­Wĩŋ3ŠĒ(ŠFíEQ4j)ŠĒhÔREQ4j)ŠĒhÔREŅĻĨ(ŠĒhÔRĨsč5ŠûÍä!Eõl·'.555ét:žį{þÓšđđøûûKĮÎjôz―JĨ2 ݔi‚ŸŸ_PPËē ÛhÔRTO‡1V( ÃLš4ÉÓÓģį?­Z­Ū­­•’HJ[ŒņÝ9k·ÛëëëĮ'Íi‰ZSSC2d!„þĮÜ^‚Ē8ŽŧtéŌīiÓĪMšÁCĒÁa„ Ē(Þ5‹U*•FĢqōäÉāá$ÅfEE…ôÉš=EQČĄ;9Kx“ĒĄîƍ›Ę–N$ĸĢÖf5čtzÝAę*Î^l2€îņöö6™L·_ ÜsUëîîšÁnÔHýÔÕ)Úufg 9‡Ž&3xÐhģŲ!ôBoCŅw]!‚ķ5]HÜõÝeÍí-ðnƇËgŽ„Üŧë3ķF}WÓæ&·ú|~ÝęEÃ|Üšž?:ģķ|nÖÁžÝ‰˜ŪægßŅˆÓšÎÎæîښz“—Éíļk`ėŸ=ėęä’;rÜb° 2/O7(*·ŋõþ”Îæhí~8éŪF-EQÎĸ‚ §ÜųŊY%Ë>ū)Ô\,-ÁýEĮˆgĮtfĀ0`ĮFІ•![ŲųâþS"WŒÞ^žÞ+tÜķ9á€H:+ącŧ}Ķ  ÊŪÁp0 ˆtžt™DĄî|x8+ce2mÍÉÅŊ.ą8ĨpóŽĩ参úB0 ĸm!,ĩ":‚B€dewĮ%{MËYų ^/.˜3h +ÕuÖ;z—Š:/e!rtÁ0,$ĀJÝv‚ާ#ÝëÕŧĒ–Ē(âāxïy #S_>}äŨþYßČ2@ÄðˆŨ°( L”ŨKũ%n;Ũh4æŊĢ7ŒōqEAdKW=6ü‰gf 52 š@sKíšũÖ]iÖļy?“”ýd°{kýųļũbŠÚMŽŧwĸ^ĖʑáJBÔî>ÏŪ\óĘhGΒc|Aä‹ ó­į%n^čïD·ĄÏý=#ąņ—Ē”„í”ÜāąÓߏŽíOŽÆ&ÖĘeÚËĮKZGoNJ|)ذĸø—Ęâ·*ŋ[Ÿ°öZY1~bŠž6wga{P~Rpę‰WV$F.ôÐUmÜþãŌmï u㠒Ök&F- 8[p igNģÏð 1ąģóX–ĨŦZŠę°ƒģ“ģŲóĸĮƒ=EŧGВ‘ŲŨ,ß—|–ø—ÔĻEóŨffŪpgąT[ەä^zäšÂåÏ13Ÿæõ óWÅ &[Þx9ũëŲĄ‹|·-™søžĖĪŲŽÝæNė° nJ^–PŽ™ņQüHÞ.ûøýZ*pÞ$H4˜,aãĮ ėí āEy{ýŠeQn3W}ķ{ž nð+=4_U]vļš‹þ uPúÚŽžâ—â^™6"ĪuüsŦVŋØÏúCQ‘į›1ƒ ͟ïÞ>gãŪ„eëÖ$þôÆ?§CUÉđss„%̆ę*Eˆ`ŊýęíMŲąŸæx–ĮތLž\ïÍ:]Ų2 sŧMĩ― EWĩ<Ïsî…a‘Ā!,ŠžKŒĀʄOv&â§^}Þ§Naˆ›ýb€ŋߊ7_:―ĪžNŧčI/ˆ ’a!ėááóäø™ '‹rOTŪ™ęĸ}ÁÁ‹WۚUĶ)\{ûŊíeÕ}ߋ_6ČÝĆpDfĖZā‘ýÉ*_†ģs8Zg ð;—―œÃ=Ï3HjÛ펆‡”ũa›Ŧ˛ė&―öœŸŸũŠđÅ+ĘLĸ0 4;rÛÜГ K}Î@;]ü‡đy˃† zrĩ@Qā9^ð§yI;Vúš1™w Û#žV:dċÅyJUFÔrÆĖ›`Ŧ™ë/']―ý ŦZŠęeš^P?/_J™_^ģ>"ĖՕQ?cė?yVˆÜjjkÓģašV•E.“CŒ0”þIˆžš>}ųœI-…y‡ ūTԗ· Üđ:gS#€@î"íyejRŦŧF Ņ* ‹}Ã#^ï8—søógĒ͒a:OŌûYՊ ð/=PZ6ũõGøēXī™õļïđÅØĶ1ēĄ>í-*‹‹\°@€Œl;Â"đŒ`„8Ũ­Ļ3Ŋ1&wâđ?#Úė"gŎ­‘`ĩ^ԚąUõŌ%ģïËÄÓ7Hî1|Áš#―<åō~~2Q@@ō Ē–E=äÁūĄÓÓÞ}:+z՚ļ=éĐé§ŊĻĄÜÅ#hˌižĪlOÞĸ~ÚŲĮæĖæ!ÃH ϝú4#jíŧųÆˆ)cûūCq­äÔ1ÅuUUəvöņeïŒÍNX·9qObJF]'Xl^ãįí‰~§2}ņÖĖĢ<”3ðũjˆĮō‰ „ÞZ4éŽäīī䝑+·ÔĘF―0Õ-uũÖ}Éņĸ>p~ÔžŨũƒRd <J)jå,ÂĀАË?ČČ=nB ąY:ûŌÕÄ9–Ļ˜·Z"}ž‡đ™RâbVĮþØĒ"ž>{âîÓôÏËĘ ŋ.(Ņcø€ÃQÛģQÕÜÜ|ėØ1‹ÅŌU‘ŪÃ`МÉ?ēckĖ–-ą)i‡*Ū*tzCĮ­†ėöoßūãp~q‹NŊû­ZŊUŸúöˌýi))Đų'ËÚôƖÆ_§ïMJÍ(+=―ÏáŸoŠõ:U~væî] ĐsnĻÚ~.ÎĸĄZaķšŠKŋ:’“ŦÔčuΧĻÕęžž<ĢŅĻ―‹Á`ĻŠŠŠŽŽ4›ÍZg4ÞĻQÞü*k_llLÜķČŽoZõę›gĶJí|üõmRĮMʼn‚óÕuŌáõģߞüĐZĢëÐÜŠ?rp_úĄlE›šī ïŠR{ëÆųc'*[ĨįŌ4•äį]mjëÐkkĘōũėڕWTVQTPvĨÉ`0ķ7VIIŠO8õmS{WcĪūŽ=JĮÍü§―ŧWUÃ8ū,ĪũTÄ[ô^ž íl­ėEÐÂĘBD˜˜ųČ·8ÏÄb…,9YØģhøĸŠdœ„y›')&Ŋ@Ģ6„~!s^œTUUYš*yō*Ծ˞ÂÃĪ7įÃG-þÓ·ðĄk]Ļ\ŪŲ·Ė ÝAg…RķȌIK§ߒDY–u‰ÚæÃĢųøÐTŽ+‹ëå<ęqņ4.ÆUŠĢÜzWõeqŽwN‰oCČo(ƒ/·tõˆÖŦ2gcđ6ŋ-[Ó>ŠKvšŌBõ-j(ķ‹…1FÉõEOĐÛoÁÎ=ŦžĶ7oÖå&JĒý~ŋZ­”ŠiCžįŧÝn―^Ŧ§Ōĩ į‘…tšõß]Ļ_ĩlĩþY.—―ęė I’Á`p8ĶÓĐūg}ýMi—ËE †ÃĄŽĸ8AåœN§ãņ8âĮoĨ( =HÔÜ+îiĢÝLŸ€&ŠÖZĩÂŌ+Õý~oųÎõjŲXŠ&ŠęÚ5[Ú ^ŊWĨ­ęŌcÝ+z…ęôlPÎN&uSÔ)Q ôĘŊZ|O|yJØ$IīÏŋ}ģŨĢǘŠoEuĐšĮS„ĻúųzûF{VQģ:6{ĸ-D-€ĻĒ@ÔQ }óó|>ĮÆ€o €1ŧŲlĘē$mā;rVŦ˜ý1›Íæóųvŧ5ÆĪ€DĄŠhUĀ*f?‡öBžxRÓIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-installation-finished.png0100777000000000000000000005000713761647206022675 0ustar00‰PNG  IHDRÎGæąmOÎIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšŸĶĄ8úŨéŠ| _ý\Ûu-[`Ķ g‰ ƒCˆ'Ë Žôcë+Æ€„øļøGxĨæjÚü=ܜÜ{ÎïޞœûŌŦë†a4îŠŲl‚Ņ4ŒęŌĒ:=yóņÃÏZõ‡īkåē_ē3 Yn˜&ā”˜ĶYĐTEobívûööŽ‚ŋ·™hšZߖRՖčÞėČßóų“‰7ÅL]•AŸ?M#Cl(ėųð+Bøþō·}|•/ôð' áߓėOÜĖ€―|Ó †þøĖ{üđ<AĢŲOįŽŲ0LŦQŊĶ1” itÉĖ–§–‹ĢƒŅa‚a4‚??7œ“ũóäÔkY3aËķ6_>íŽ"ņąT‹āÉĐR]ÉŌČÃĮý,ïĻ-G™&F<ęįøÄ@$V(ОgįÓdJ<ðŪTÂ–ũÏНî-#ā\ŽŨĪŲäØúÎୋÏ&FQGŠŸŧlšōÞzŠfwj–Ģq#ÃK[eÓķü‚%z,ģwaĀ$gvÏ,ũŽģž]ŪHzKð,FL+ķĨ_Ėēƒ·ĩ_Ę%ņ4ÆĨƉÁNaiãīzĀÔąŅ*ŋH~Õųv­H›L_ɰ CoT Uz…āđšō7ĀŨÕY%(žĢĢ―čJņôúÚųž6ŨŨ3Ä&XŠŽS+į‡šŧ!ûUsÅĖ“ČĘðņX” ŪgŊĶG::ú ‰v-lHŪk…“ÎOĀü°úßüäî <ϰ$|_ũëģÖóEDóŸæō<åfŒŠ?PDĖåCDĒ‚‚c„xČ&þ=ÝÓÝÓģxRüs|=ĩëd]âÍBšÚŠŨŊÞž­%‡IX ų\ûûš8ðOų؉? Þ2c(Ĩ€F"Ĩ„Ē‚}8ōøôÎíģGõ›ŨŲÜLkMHÎSJø8ŸÏgģŲųų9Pŧƒ`œÄ>]ž=øðāĸwŧϏîÏ^đ`|ëIÆ*’súˆ.·p’ LD‘…QŽâO^#ļēŠgT቗ý™čA0fUÆä)č+œ<ÝĐã.óós!ŸøÃį&ĪÉ9ųЎ<Ķ qQ’B[?, ØQé‚Zį2”’ą>t}I4ƒD›{īĪrQėü·―xęīt]J í—Z9:kĩ4>•ī2ІĘÆ.åÎŲ6`ˆ· Bŧ„Z‰ÁJãjŅXČ ĐÏÁIũ],ĨÅîķaJ€ĪÞ(*CEŲT†Îō—o})hÕk}ąüÓ`ÐōÕLûūŦ \Ɉ "*”óąĪˆA>æŪëīŌ!—>Ņ4UMk}ŒĐï-ŲCþh;Ŋe3Ÿvá"^RĀ ĶmžŅ>õ1B―>äÜZe|·ø:Äĩ‘ûŨķwžžtÎĻķ ČŨïŊîÚý!<žɆýá%a0žÛLˆāëŒįÅ͜_“žĀŒgĐLēáũ%„ā"Ëc ÓâžĒ?<šĐ&þPü•?|>^ҟ-<[ƒĨ @>p})xũŊá `…Ž]žŽ„Dšœ3þ— Ŋ}x@M$h!á[xđ­f€ü9ųK]bcZDœ'?Ë&āqÔeĖÉ€!fóIÁ øäë\YëÅË$,ƒoáœpōʼn?Ą,óą&tĮķøÔ|^%ÖâãŨ‰Ŧķ+Ųx$=ŸÎüN|üþu~áp<Ýĸ|â7ęýÝÝėš|\―ʇ âƒzFKð‰ųŸz…ßZå(ŸķY™k.F%’'ž7ÉâQšĘ§‡ĮßH]ÍGESĐųð§•6ŪōÁ·ÞŸ áM|<ķøĖ˜|N+_ˆ->Ø2Ÿļ§Į?įÃ6ōŲ•R†a‡ŅG|ßõãģMãÄßuÝÐÓ4•ĐP·åPĪP(#°%ē(Ž"PT1fÓL1[ļFßũÄņTÚ“-Ķ€FF"xg>ÜĘ]ÞA=īĖ―zVāiôz~#ŽÅ‡Ž&[2ųÐH™7Yá“î„Ė1ø˜Zāƒũqd>‰đĮ-|(>‡Rhž―ýRÆÄ§‘Pķð!>ÔûÐ{ Ÿî>ōąXQ>XžœßŸ(ÆäôæĮa,FëŸCýþÄԚ˜·ĨtŸåS|ßdŌâ31}ðAßȇ@ÎÁ#ĀŪã̧w;ÄļŒ âý ڙŠ|P–ųŨ|8^ĮQ>ąÃ_ðÁï>ūاŧđđÁĸÖÉpl›YĘ><[Ė!ÎeõõąŪÏ"žųu%W]ūUވö°ý~ßZšƒu>X›OĶ—ų(þ>ߛî>õ(ģ5•wäƒ]ðÁŒ·ó‰8ø ./ ĨÅ'vĢüg|ˆW—/óQwøûōÉâ/öÞ0Š$ïĸŪö™ļ‘"°IÎâN‚ÛÂâî. ww· Éâ°øÂĒ‹‚Ē!!@Üuܧí_!9Xî―wŸÛŧ{xļþÜmŌSÝõģšþĶŧč™úÔīĸ­_()"ÖGŽČ û7#"""""J­ˆˆˆˆ(ĩ""""ĒԊˆˆˆˆüuĐĨVDDDD”Zˆü_AČŋÍ%‘J(ōO:€`#úŨAPÍ~›XĪ*ōûEQhAþÍA#/ČŋÎ"FIĨ’€&ĸ‹}ՈČ ĨJ!ËÉ–nƒ p—ÉäJ…ü_íD^^ôî|ðŽ“W2 ä ųß·/Ŋ bCV\ WûyŸ™_ýE߈R^øû/!ÁÁ?Gū-R)ĸfJĨZ­R*U6•*|ýĩ ĨR–}ëôჇN$g•*Ę ā*(oÓēKËåōĶ^pĖJŌRSãßd–ÁĶšü*ĄvŠŠJŠÔ*EĨĄŠ yAæ‡øÄ7đųÅ=ĸåņ.ÎN<ĩoKč•9ErˆxUûŋ‚ā—“ôpfŋŪ­ÛīíŌĩk‡Í5ëēėĘ[ЄĸJPÞXvj劕‡Îęy–V%âĀqŽ(éÁˆ€€ĄûnļŋtaÆsËIp<@P3ß?ļwņÆÝÏsĩ$†þÉČI\{|æ°ÆMÚl;ĮK%Š‘ˆėāĻ~=O.4âÄŨs šÛ{v.Þš?UÎÕŧ=—‡fkŽýŲ yžË`9€bR ÜžbJ@§nOsôø?•&Šbēũũ[5n:ĸĀE=Z[ņ—VÏiÛīÕđŨ%3ŠÔ9;_ĸ6lc`āˆkQŔĸ—ÔÁĪČ9ždõķËO4, ĸ/áë•Z ÃÓ‡Žé;ô|ÄïúmÆMœ4°cŦZÕėĨGÔЕuÅ"CÖ$Ž'(+);J­áúC6ÁÃŽlláQpð<@ÞžÁicą&*”AjfXš††ø YzAցv)D}xÛēõ{ۚ­m0Ø:yAéĻë·QœZYFJŽ`+ ‰€āĪTðm#%IR"ĩ"?WqC?<=špŅŠļŒ  V* q‘ØØB$$^u+ą‚ņBSÖØgg'G󎝆ķSgĶ9qčõ…ĩĩ$ö·ã{ÞUk;ŌӖg8@Ālí Rōq6‹`đfN$R‘5l&I‚„ÎŽ­ĸ °b–šØÚÂd-‰ $-Iœ°ŪØŠ2q ކ°"Â@°ø€ĮœĄ…"s.q čÜĨK_[piϊęÁŽa`|ŽŠ]EÎuāQœ’ĨÜXšxņïąŲR;+•ÔkŌšKŨ@'’ã,ģ•™VNĄĖ–ƒņqXI>MŠĀÆąšwiÆÕ‡o ÕfĖ {û6ã}XDJâ猨kï6nķnžÍšvoïé.åXڑÂ{Š Ą†–P­? Ušī’Jp€ĩx–W8ĘÖZˆČĖb,ũĻ8 "‡wn‰9 0-$ŧÜ`Ðë FCIANVVžÍ+NÛąfÁG[výé…ZĢ–FÜ9―qûЄø;LņĖýWJF^˜uûĖÞݧ~ ŧ2{ā ÁCމLWŦTå9Ï{Kc“>‘ir―Nû!jÝÔqÐøœåG2JEņŊ›§H`(N>óũOÉ,Ėûw2xï•G1 •<áų­Ý7>ŒMšydÓ AƒŨđžW.܄Š呷ũô·HxŦPŠKóÓ~^7Æ3yöēØī…B!ûĩ,wĮĻv -įŸ*ɊþąūĢ}ۑo d čCYōčԁņĢ`ŨÁ[^Í-UĀŧåĒôäcû7îŪ ZGdĐēĒní =œ­’—<ú5tëÎÝûũ _ĒrāĀîā·ō•ē7/ïï\ŋ\uŌŽc·"e Ž"ņŅÅMŧŽžŒ‹Ú=mĘ•§Kĩ†Â·OÖÁįoßūÞ€šƒ—ŋÍWÂũƒøÂĸ.ĒŌŠscÎ8a€øŪý―7%z­Šj6 NLæ'üÖ­Ū·””ø6ōģ–JlœïļôĘĪ-ØđxŠ[ŧšÖĻf/H˜SõZÞÎÖ$ÜŪÕitBūV›Ÿ°hPmÂÚŪZõÛ―^/Öž°HmLĶ*/ņúÐfnķV6uüý$”uïE?åĶŽÝEJPn úމÏ{ös múÓAđAu}g Š:VsŦîę "Žuį‰eLę‡ŋŽquĀ ŦŨĀËÛÍĒ$ã?ŅŠ*§UšØ Ë]­pØÃÎĨz5Ķü%­ëĒ8áâ^ÃÅVˆ_ZŊoØÛReNüâ‘íėŽĨuümĪRïģ Ę>=C•jMzÔđ†N(°ų~øČ^IíŨÕZJ•ũóŌnÎv”ÄŧŽ‹‹”īųaæ–e†Ü˜Ŧ­]PēÍâeeÚïMüŠđŨk[ ËŒ8Ŋ?­mm]œŽk6i™­Ō(?ÎZ–åĨ.ičWãûĶ-<­‰sË “ŠUÆļ[âåäâîTQp+ÏæÃޙ5%Á?ĩÅā°Tũp– Å·uó9ü8ÍĪI­”ÚBEfX;óļ0!O#ϊÝŧĐŽR'G‡ÚMÖŦËvĖííQĢ}ŧķ.ÜĘĩæūG™yÏ7óķžØ;6ķŧīÕė(G\|{§(J·Í^†Úķ“·Ūáö^ŊÓÞÝ;%(G'7{RÚĶįŠžžˆNÍý` k7n0–z_‰ÔŠsĩ"<L(pvqtīĄX†ĩ4r,ĄôāÍaïō[Ų™xëØ +MŌēÐ_‹t,ėÂ1š:&ß ŋÓŦ‘§V)û.`äÝĮ·ŧđ#JyđÞÄ †Ģu’ĀđûĢâŸnôúüĩ8@ČGú° {Ŋž.·õØģŨgôrŋŧëJ&ï5uþjWŌģöˆGÏúÚēfe9\ppžĢ9ÎX―ŅæswŽÎ āŲYRuĶ’kķ•jŽW―·jd Ųd$ÁßāsíAk§ĩĀaÝÁkįŨü€˜€Ā‡æ?\6§ģ“!5ĩ ŧ,éåā /ýFlJÛúSŋ܈ÃũŠ?F`Æģ~·ÁCŧKõ‰—.„Μ5Ž“/ð’Ļ ۏ…l[Üž^wwÔwč#GoGžCú§iP1u‚·ôŒ‰į…mc&lÝfo=qýLĻ—KsžeŠĄœ&ĸr=æîík§î-ę!‹}ž‘#ã1ŒáāȘšvû4&r[ßĶúüWaá Ž‚ufxí=IŒ›3Ī™Ą$óø™g4þ· Dex eâ]ūp7ÞĄÞð§ iiï“o]3`Āė Ï^Æ^―yyûĪhiNfviĩã·. 1eéҧ'įØĢ< ―3fŒ”FžÝ~ü9įŌ~Õx^Ė­Á܍āÐûq‚ŽWKÝįþõĘæŅ6@‘y;^‡VM„ó,NÕóĐï‰sbÓâ3Sé=Gtō(UĻR“bï›đš;;"4H‚į9ĖzØōÓņ‰ÉwOŊŪgo2KÜF,œãŽâƒ‚ķĀEŠŪÞšž}|gū(+§Pƒ"Aa/ÚÞĨëĄŦNOzyjGĖŦtŋÎãßdĨß9ĩÎú_ â\­ËĀ#cYÉX@P ŅåžÕc·€Ýí PũûÖ]j.ęe‘Úˆĸå[æīlāßÔÎÎÉ­fÐĘÕßŨ­ßĶ>Æó(R)rāŧþ›'õðöi:ēĢ7mZĶÁ‘ ÝáXSþ‡ ļy'dÓāQ“ŊEð:Ŧ\K`8Š`"ÅĄN!ÅâcPžðŧÏī•c›6iÕĻPJ“^•›hŪ›7ýN€zš{HÁAB`8Af9õÜÎcėėĨíÖkŌĒ1j―Y_&/5õčØĀÃv^| ‹É6cËsz`;kÚX?k·Ú3ƍĻF00ݒė,ŠõŽŅīŽ·ęPŦó˜žÐLVi~Åjūƒ·dUU^š†N2r°_M/+X3ūŠčLRÄų‰#ũ0ôČï°_e1náx_ÏÚ}Ķ„/4™‰KƒjÖÎ^ŨŊÁĀúöčS>h8ŽēWUžcËåĨÂÆ6Ļn0+7wg Į c./ž6ö‡}·\xiĀ­pTÐ&Ģā§P@,i`R”™ĨÓoæ~žö„‹_āĻ.Īg–ņ―šŒ\4­Oûï[ĩ°·"ķÜÄVĨ X­Q§ŪŸŸmÂđ_Î^šÛūS·Ãû‹ēũoÞĒŌĐûwjČ1ŽĐĨp‰­6ý~Ðė g….ã·]76@‚ðų‘įįOCÝz)Ƅ[chåیōøiÛōa―šų~įPŊŅÄ+p„·=ZÍĢVčZ”ÚŊžįĨö5ęØáŠw‰^ΰΕ„Ē(‰”$PŽãYģĐHĶÁI †pfØBÛW>ëHō<ÍrÐŽ!Ę2,Ͱ<Ļnڑ%pŒŨčHĖʑ@?Á‰oóðUë6„œšņčņÕvÞ6 ĮņpŠRR)”đ/ßF.ĘXôĀĻ5éMˆŲXZRnÚŋL“īŠ’P$!ôĶpĖE† ­Vč .ȰGó> Wm=ú \ke/?3ÁOáXГ&ĄĪöRÏj6,Ë ķĄ °ŠÁ2‘ļQ] â(Î Õ^"‘”äôÆÏ–‹fŲŠ’ B[’x}ō­eRŸÕ;öŽęV 6bQU؝$q]y™P ūBj )`”dfā1ÖÎÆÁæ?€ĸ”—hxŒÆX*Qg?ßīn啯ÉËķ-šÐŽ2rpļ!%h'`:D•sá?–áĀņBĶ$šÔ2KĶ–ŅŪF mY?A>ŽcÜ}Ŧ{ûrĨÏÃĢäþ5›ÔiŌ’2•D†Į(éNMýŦĘA1ÂT–ēdņēŧ lŊ™[ũÍėãd-Qd„oXŧæZ8;m厅c›ZS&žĀQËXĮah Įō Į Ęn0ā$Å5Jð• J­ϐîÍMë!Ĩ‹Ö,Y°ýČđČW‰1·N„đx3Ŋm“Gūð4ōõó—ÂӁũ 6VB ŠĮó–íÏĀpøčÂĨë1ŊŸž‘ pÛú=S&šŪ”°kðĢ5))Yr­ÔÞ”ä}(Ó2uËŽVž―uý~ąĘ$œÝā#РĒq•BĢ`q›ÍÚ{E|HðæuóæŊÝy–E ô‹$9†Đy~7ōu: mVôþÔ‹`5jÕu·)‰oså:;+yI>Ü@ūÐmA!7„ôÍŽ_ûÞĩŦQYéŨ.]šõäÉåß„#-›ųŨĨ‘`\ÂËK§Ž Ÿū*­Øuėovļ? "‚ ēž·jðtkbÕdĶg MÏĖÐŌ}æ*x=ĸfÏá$ȍųõĖųϧwN]~­ Aĸæķ,KWYæcųžĩjÛāāÜĶ}'.ߎ ŧ–ĻQjËe^Ó­šYĪŌq)q/”FEhŒoâ?|šĻį>ÆK›ŲÚ~ðĩGÓÞýz .ŊųøâͰĻSŧĶ~~ÏY†æ·•Û8–ģvéRËÝ âäQģîwŪnuš8HõžžV(Š@PģüÄö%—ŸĪŲ:ķŌŲóÞ­_ŧ'Whdr^RÓÝݎyYŽŅš“c_Ļ…P‘Š7' " |}ÝqĀŋĸíxčÉÓŨmHĀîĨök@„Dϟö†Ūíbx―eÁĪúöëÛwxÐâõiÅ|Ų[·,RÜŊG)›ÏļôŸ~aÕ0g T\ƒ –‹(Žp‘)·iŽá?^kĀ_úŦĄË{ šø,‡›šrãÜŪ>FĨ Ė<īíĀE‡—OÍ ;9jPŊ>―{ŋæuŽĘÖŦɘÝåųOæŽqûU!AR84ŒA V„·<' †{œržļýØÄÎM_<š'NÞe@wkþģkk’­{oígufũâéAGĻTĘq4ËpĻEĖH@5j?ėlČææeįŽØŦOŸ!#ĮÞK.þ{ÏĒō4CWĨĖģ&ŦïũîŲŲśY8a`ŊūÓd·Úþó֍ŦŲ{4îÛĨ%n|ēpÎbŊv=jļZÓīƒ9ĄŦ·ĮąÏT€ãß6CúķĻ~ûĖŌķa5ú8‚=ëöĪ+iEāþ_ÖnÔsPHxaŨĐë& jšbÍūžÜŧßÐËqŲ=Į/ß8Ž™™EHĻ팠Ђ“°€iUú:ú\$ũ^ØãČĻ”žâr9lĘÏx—šž[\V”›ø!KĶ€ÏĨÅEGŋË)”ËåE9ĒĢãÞūËW(åđ™o~ŋųûƒGᑑWNę ˜{2Ēō „ʇåï“âāōÍ/ĢSJēĖĪø˜ļŨY…Ĩ0ĒėÐCBn~iÅgŋâĢÂ*ŠˆŠÎ>đ$ûđŽī áu\Üë„â2øÂ‚\ĢUfĨ&ĀĨĢïޝðAĄ>―e―}W2]XZš”øúU|B‰L^V”—ŲOMÏ-ĸŌšBžĸčÁý§Qo‹rē^ĀĩĻÃ_ĐĘŌGõmąûrDÜũčyfat */<0ģ ðč9<þY؃°§‘™…rØ.——e$žŽyŸ_R―Ž~ōF+D%+I‰}—X…ëũG'§ËŠüĖda9õg1ųEEŅÏ?|™UXŪR+ģá„R؃'Ï^—•Ķ&'DĮ$Âáķdš‘oÉ4&1]UĘKōē^GGŋIρ ”d―ŠM|“‡ėđ•垎‹ŽOzS*öe§%GGŋĘ.€%‘ÃĸdĨFĮūÎ,(‘ËJ>ž‰ķ—\"Säe$?Ŧy?…ĄF=}ôðiTN‘Ž([č•UPÓķž“‹s>< {pĸņ“ŽÜžũ‰ŅŊÞĶ•–‹_7óõ "—+?§ōc“§(•*O…BuŌōî†Tn GðÁĐ9ÝŦŋņo å•` RUä°§åøÏœŠ •ŠŠ„T‚zXÚáķ匒 f #h\þðÄ" oŸzÞvÄŋíŽļŒ2ŗ"V™ƒ%fUU‚Ðę§áUTéë >ÆüųūĘĻ-eúĒUQ™Đ%kÁļåĻ/ĻęĐDc’§ ėRæv<2[§Q[ŽA+Šō‚ÝęĮîŋÅįéu˜ReĀ• ZĒ­ĻÔĢ,4~V—Ę]UaXŽU·ĨĮ™V SÕ6<üK*ßK•™Z:UŲPTŲ€{>:úûĄVöēØĻŠđŠ"AĒ淊(ĩĒjËKrŸÝ9r!,Ŋī\þoþF~J땐ļþéĄÃ!!g/Įį”~[g—\%+šwërHČÏÉ9%ŸiŠŽ4îŅŐS·Þå ‚%"ō_'ĩ"r…Fg4īōĸÄė‡Ú`ŠÄhPÃ+ o‹r™\§RT}q!ŽÖLFݟ>_D”ZQjEDDDDĐÁÁW‰A8Žņ<øŠAĀ0,MÓā‚(ĩ_ĐΊTŠwïŌ0 _ """<ËrõëŨĩąąfæĸķԊ (*“)ė===8Ž_"""†egį( ;;ņŠö[A(ĩ..Î,˂Ŋ‚ĀĄÎZ.€DĐýFā+_"""ĮCÄŊ›ŋŲKDDDD”ZQjEDDDDĐųĮR+"""""J­ˆˆˆˆ(ĩ"""""ĒԊˆˆˆˆR+""""J­ˆˆˆˆˆ(ĩ"‚ Ā øēbãc;ōũŽøĸēô āëâO†dÉîOðyŽĸųŒĸ0Rĸt5þ‰.–dŦķ-?ĸz""ĒÔ~ŧ (I`zĩ<';;'·H­5„N~Un@ÞĪŨ›îg›YUö*ę•ĖČyrð,­ŨhU*•ZĢ53ÁâĪ)ĸÕÚÝ!gíčŅķ͘Á%fĮØ—ũu ė;ffB‘ģHŽ–ū ?ķ}ŨūÝë'Ė8ĨÆˆÜøßg ėØqþķcåfýÛí?šýÛÄN―‡‹Î#)sØÁÍK·^a$Ū,iÞČMoĘiƒ2?̰Ļ0åŅɐS{wŽ0óīĎ$Ņg'vúåĘâs^HD­Ī˜YũûáY―;·ëŋôΜÆH”?ŧĢo§NÆŊˆ+6XƒįhÜąŅ‚5“_‡GÆ>Y&rĘæE>ķ˜67aÝô‘: ڜ\H$ĸäčúÓÏē)’L{z|Ųņ’B#ÎŪßzpŨčnÄeĢ8­a8*Ï|1~@ŸNí†n<ĢĪ Fžš{ޒ3ĶvoŨĶßĒÐ2=ŠšË.î\šïĀÆþ=:të;+đHՋį/Ü×§FŋRÓčgWvôíÞ>0°ÛœÓņtYŌ†Ųý`0ÃĶŊΐkbž\?qá|ИĄÎ̕…/ ģhCÔđ'ŨÏéØĐĮØ9ũ“äĪ„J―~`ũĄk§ĩm°û| @…„9†uôiėcŸ•’™Qšĸ^QĒ7Ī&é·ÞtlfËęĒrßip>ïųÕ―{›:eÖÔ1 w\ļØë;čÖĐ}ûŽûŪž$a(NÜīxÓä1Ã~šŸ]ŊŨœ MˆŸÏ†ę―j6ōũFxC  6ÎÞ-ëÛ>r,Ŧýúc]lH‰NšbÞą “fģŲųûVóĖk^Į99#­éˆA}ZŨé0jTóūfƒĄōø!J­AÖtuūq;üLGI$‰3fƒ™å?cAOŽĪ:eÂH8 u™5ŅVÎ5čÝ1+|˃ĪØ |†b$ p’P~ˆyYŌĩksĮíx+œBÆÂ<­•Ģ=ƛÄUŠr€gŒĮ” 1·ZßϘ―hũŲˏO-t!ĄcPg4Ó,ĮcØ8šðr…ĘĀĒ(äĨŽ„" I^ÐK+;gLZk،đŦ7m ßÕØU8]lxރ“WI™âCĐęc2 ‚A€Ģ•° lޘRA…c-åÆ C#xÜÖІ­kóđ˖ï<|õ—đ6Œ zīĀÄŅÖĐA?GĀ ý CQ~™AƒšĄI…ķYV„Õgæ$rV,p'p 0ĀŌ;°o,9°pBÞeáô õ]Ķb&FIsp7Ģ,6;Û{I ^fģÐĪŨęĪ&ųė2<âėåĶÔæŠ8 L·ĒĶ‹k—Ɛ˘3§ĩ—ŦÁaMÍLĄ™§ĸV “0eÅJšŅõž1 œl$<hÚČóŠT‰ŦÕš+—~ûú“Äæ­6j]ïÁŅÓn^þ5VȄ‡ÖxštóœŲ·ĘÝ=īÔ˖TfEÍßå=pڔĄ=Ŧ àG!PËĀq8ÐËJ3&YĄBĄÄpŒgiĩFĮ@kßĒԊðœ™ĩî9rzOâyŊa3ũ‡=žoëōE;’ĘYÄhyŧóīNŦ7`M~ŌQ6sþʃvđúÂh0jhŦĄ+ÎOkĒ^<á‡ĮĐ%†Užî\ZBėÁvoZ6fî*Žóœé=›5éÝË·øÚš­{Žl_}]!Üģ!Įð:•‰f&FŦĮ›ĸ8Ļđí› ·ŋ‰đþ$ÁĀð•1g—‡7.žđi]ŊsÛúÅŦWo9ēsÍŲī6ÓŧC9€53îul;s3)%áņƒ'*†‰ļ°~_„mdJôÎîsg/HSškŌM,VŊî|ĸ·sįoDÐ(fyð‰į%ÎNԉ#ÁŅ)đEh­–å+T^Ŋ5Ōl“ū―2nÜ|þ&éųÓgŊ–^•0fĢV́ēeum<ŪUÝāõ+?ījóéķm'ŨīFqŌņÎŲÐõël―ø^]!"īAŦ3Ō|ÞÉĖåd~xó4ĢėōĢ—ZŽ,MK]ąfëą―[OÜ+ėÕ+ЎäŒ%™ĄŦ6?ķûÏįš ė[ËÓi5‚óŒY§cXĪų€é„ņŲäyëíß{ęî[ŠBĘJóãb"ӕå‘O/âý=Ė·Î…Þy\ˆbĻNg4K\ĮwéôøøÞ]?Ÿ\ē|›ĢĮ öĩlFFgĻ(Ŧ՚ŦåY†ōhÔŝĶx7(ŊžõšãFĘß·Ģ xč,†ą1įũŪ:}ŊmmɓSwđYfu™ïßÄDƧË2"_Ĩš ‚ëtBIËŅŋ_\šaËü۟%‘eęíþcįĮ1ė’QjE8ÆlíÝæøđ›û‡4VįË TÓĀî>ö6Ģ–oęVϕĶĐqŦ6uös <š>~yāũÕôfžĶ—ģ}ÍfS‚û:XÛ|ũ’Đm&ÕĶq§ {ŨÎwĒ8ĖŪæĪĨÁvĸä›m}š<~ØÏÚŽBÝw‡žųĄž æÞnÓō‘.V<ÍH&ŽÞÜÉŨ–ôlyðčđv^d‰Lkãâˆ}T3ÞLƒķCĶ-hËhĐįރĮzŨ·/•ģA;obķL}@ĄĄj8xtZWŸŌ‚bTę$áŒļ[›―G·úVs>wû–QíMSVƒŒėÉÓlĸyŦŒčhPĻđŠ?9žÓOÛv jäĒÖ(Į: 6­õ’0á Đ­ÓAQO—OŨ%ïĢZÕÓûõ:ö#ÆBjá`"þlJ~'ļ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jG ZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZę4TT?0ĪUg’Z"ĒmÛĶir.i€ÉdŌķŧŲėâRK)eđ\l·oŧÝ{ įēZݖ'ŸZšŪ›ÏŊ6›įˆ4(@UĨūÏ]ŨĨi €Ī@jĪАZęp:­Št|)Îō @DúĖŅ—%Ņ{wUÕpüyÎđģt:m§-FĶ@ K Ð* …#‘€+*HPYJ VŒ4 ‰,n!D bøA‚!(!Ņ ū…7ZQ EÚīÐm˜éÜđË9ÄÄ!h‚Н<ŋœũËÍ=Ÿþy’›œ#x$JDN-c,ģhMŅ$5FÝķ.åhčF~úä―sdЇ)œÚĖÁwķ3Iŋī˜ĩįĢí "@č&d …óŒō~Ą’^Þ {~jc ’ .t:ĩ Rw ĘfûĄŧuÄg[S› ø ģōŅ#‘zzjc LG7v:Ķū·ŽhėĀÏ€ë@!0R詛ÝýĻ$‚“õ­-1É3žõüÔ2ƘŦĀtHH#?ÛʒBĀuÕ‹›–ÖdxųĄ üōsģĩ'R”qŋÅcŒ”Öˆi :ą=o,üāÛÄĀÂ@[KSÉčæ/šWZ”GD7qŠÕš SgŒ1ÐZ+W @‚ŋ@!ĩyæĸ?õ1ŋjÖļ–Ó_/X\}ðhâØ—ÕųīëjR ÐJ !īŌ„B")R‚VJ“”ÖDiƒ.\WiŌ˜ZÆC ÐĪ]íĒ›>ĩāšÁHßaĨÃĘSkE§-ÞvėėóSýg7ūēaßÉsÞ[K—/Ŋ™V9ą}íūFŊÝ\{čČé™ËÞZYYaû~ÃÆŠÃĩfųäg_ŠzžĀGD6ĩJk"ČØÔ2Æé”ôS-čŌŽmY@Úī‡MxhLáŪSŋžĐßķpĸʼnūĐnįŠĨOŪ\ŧãró‰·ßųyÞÚ-ëm­zí“9ģFn_ščȀĘ=ŧĮ͟VđsLŲsS†k­Ō&Ÿī&"ĘČÔ2ÆđŪkYĪEúĐV9–ŌĪ”cۖvīsđ­Ļ—č<ОõDõĢ‘‚‚âĮææ|úĖĐßĒyI]1gõšĘû.üÆį;―Øt<ÖŲ|lûܧwŨ5tŒíēlËRJĨj-‹”R”ĐS-cŒ‘ūÁTKZ‘! ­Zl­iŌýÆ N6ž>w'ĩž5cŌo€r Ũ/“ ;i™D’@l{Ä=ģŠįÜíũx‚ĄüëÞgƒ 5ĨĀ?$ C0Ƙė8īũýõ5ëV­Ļ|ó°―Ļf͐pøĐ)ũýpãŦ›7­\ģePŲė1ÅA;™č2m@Ōņx2/xpz㞏vėÝŋũģm'ę/! ļĐ `ŒąžŊ€4H9/ŲPRŨhŲnĸ’Ų ^œ4ø–,ÓT–ŪyoôĮë.õžņōÔĐwæđɑ3W/“rÍÂē›_‘*]ōÂŧĢūúŪ ~‘‚ "`šïĸą33ĩŒ1FWK'ŌAÏÐQËÆI "ĮēŨ•š<å“đ}2 hÛē]W‡GÜU ŪåļÞCĶ Ëī‡Ž>|<Ēk%ĨÓö\ā•=dZjcːāũ đn4áÄ-ŋWĪC`™†‚dþĖ6Ŋ=ÅŨÞí‚A„ļ qSĒö{PbFĪ–1ƈ ⑐§Á?žo™Ą@–š EãVCs{8ĮÛ'Gˆ8ĩ=cŒ|"!Ģ|@č‡účĸęÛt‰:œkÜÖ?T”#Ĩ@âЖ1–„Ā<ŋ( gýÞÖ.Ũq šß#ÂyFŸ\Ïß?Ž6ÛÚÚā?1ƈĀÕĪ4hęî o~oïŽmˆAŠZĖė]ž=C\Į5^ ‰nƒHq•ũ+ü‚†xŪīŸR xãxĀëŲŊkp˜ÔH-€Ô ĩR ðâšŪˆņd63ũÞj pĒģ{ïĖsÎĩVUuũý#twU­ĩæœoˆŊcDšŽIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-introduction-page.png0100777000000000000000000004376113761647206022051 0ustar00‰PNG  IHDRÎGæąmGļIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšŸĶĄ8úŨéŠ| _ý\Ûu-[`Ķ g‰ ƒCˆ'Ë Žôcë+Æ€„øļøGxĨæjÚü=ܜÜ{ÎïޞœûŌŦë†a4îŠŲl‚Ņ4ŒęŌĒ:=yóņÃÏZõ‡īkåē_ē3 Yn˜&ā”˜ĶYĐTEobívûööŽ‚ŋ·™hšZߖRՖčÞėČßóų“‰7ÅL]•AŸ?M#Cl(ėųð+Bøþō·}|•/ôð' áߓėOÜĖ€―|Ó †þøĖ{üđ<AĢŲOįŽŲ0LŦQŊĶ1” itÉĖ–§–‹ĢƒŅa‚a4‚??7œ“ũóäÔkY3aËķ6_>íŽ"ņąT‹āÉĐR]ÉŌČÃĮý,ïĻ-G™&F<ęįøÄ@$V(ОgįÓdJ<ðŪTÂ–ũÏНî-#ā\ŽŨĪŲäØúÎୋÏ&FQGŠŸŧlšōÞzŠfwj–Ģq#ÃK[eÓķü‚%z,ģwaĀ$gvÏ,ũŽģž]ŪHzKð,FL+ķĨ_Ėēƒ·ĩ_Ę%ņ4ÆĨƉÁNaiãīzĀÔąŅ*ŋH~Õųv­H›L_ɰ CoT Uz…āđšō7ĀŨÕY%(žĢĢ―čJņôúÚųž6ŨŨ3Ä&XŠŽS+į‡šŧ!ûUsÅĖ“ČĘðņX” ŪgŊĶG::ú ‰v-lHŪk…“ÎOĀü°úßüäî <ϰ$|_ũëģÖóEDóŸæō<åfŒŠ?PDĖåCDĒ‚‚c„xČ&þ=ÝÓÝÓģxRüs|=ĩëd]âÍBšÚŠŨŊÞž­%‡IX ų\ûûš8ðOų؉? Þ2c(Ĩ€F"Ĩ„Ē‚}8ōøôÎíģGõ›ŨŲÜLkMHÎSJø8ŸÏgģŲųų9Pŧƒ`œÄ>]ž=øðāĸwŧϏîÏ^đ`|ëIÆ*’súˆ.·p’ LD‘…QŽâO^#ļēŠgT቗ý™čA0fUÆä)č+œ<ÝĐã.óós!ŸøÃį&ĪÉ9ųЎ<Ķ qQ’B[?, ØQé‚Zį2”’ą>t}I4ƒD›{īĪrQėü·―xęīt]J í—Z9:kĩ4>•ī2ІĘÆ.åÎŲ6`ˆ· Bŧ„Z‰ÁJãjŅXČ ĐÏÁIũ],ĨÅîķaJ€ĪÞ(*CEŲT†Îō—o})hÕk}ąüÓ`ÐōÕLûūŦ \Ɉ "*”óąĪˆA>æŪëīŌ!—>Ņ4UMk}ŒĐï-ŲCþh;Ŋe3Ÿvá"^RĀ ĶmžŅ>õ1B―>äÜZe|·ø:Äĩ‘ûŨķwžžtÎĻķ ČŨïŊîÚý!<žɆýá%a0žÛLˆāëŒįÅ͜_“žĀŒgĐLēáũ%„ā"Ëc ÓâžĒ?<šĐ&þPü•?|>^ҟ-<[ƒĨ @>p})xũŊá `…Ž]žŽ„Dšœ3þ— Ŋ}x@M$h!á[xđ­f€ü9ųK]bcZDœ'?Ë&āqÔeĖÉ€!fóIÁ øäë\YëÅË$,ƒoáœpōʼn?X8âëˆe“ĒŠę(Í~ó·96R0ûĶũ'ë2\―}Ÿõ„íßB”ęhõŧ$›ã?Â‡Ū•|.øæ)9ü<Ïx~™"GŒIáPœ8Å*zSŠîÂ\Ï.‡ļš2 Ô3 KŧGįÔ@KAZôĩŽ­ĖÆ\)z|ðXŠŌãe™5ŅÛãcÐōy•X_'WíWēņ–ô|8ō;ņáûŨų™Ãíáîį#ŋQïnnfŨ­äãę“|>ĻGD°„Oæ[>í ŋĩĘ­|úf勚:А<ā―I8ÔGiŠū?dîï~|#u6MĨåÜVÚx’ūũþToâãąĮgÆäs8ņũ…Øãƒ-óÉ==þ9ÏÅ4MÛív·Ýųáˆ6ÃîÉÆÝČŋŲlķÃvĮiœĻĮ[ēŸöĪP(#°%YG(Šļˆi͘ĀĮ-\cbŒx*mÉdD‹) ‘‘ޙ·r—wPŊ-sŊžx―žßëņ1‹ÉĮ–ĘGE>4RæMNð)wBåƒ>Ķøā}•GbnÅq  Âg?M4^_™v…ϰCBYÇ8|ĻũĄ3ö>›WøČĮbEų`ur}RŒÉ'ôÖĮa,Fë Ÿ}ûþdiËĖëiÚ|–Ïäû&“Ÿ ŽÄTôáƒū’A8Ë#ĀÎã̧w=Ä\ƏyBŧōA‘Ę2ã–Įóø Ę'1ü >ø‹ÏöéŲŪŪŪðŋu2ûFÖēO–9ÄĩĖĢū=ķõUÄ3ŋ­äŠË·ĘŠīĮ.//{KkpšÖįSéU>ЁĮũæƒ;‡O;ĘlËGåų`/ø`Æëų$ÄåĨQz|ēå?ãC|r)ņ2u‡ŋ/Ÿ_ė\ŨúũÏī]Ī7ąaŊą$VDԘX[5{-jbbAbï ;ØÐhląW@Á‚Ĉ(R”"Hß6Û§ŋgąÜĸ}ï›ÜûÞûáú?ßÏGœyæœį<į·á—‡Yցü'õÓĸVėĸ äĪԁ@ü›AV‹@ ČjY-@ Õ"ēZ@V‹@ ĸ: Š8†ÛÁ0€øk”BĐRQ„]9'ĮþĩŨÁ‘âŸĘ@hUžŅ–—eŋČĘÉ+Pkī:ÝĸuĪցæßVŦcÃčߎĶÓ놁§U ­Q'\>ūnýõĪF[š™þ4õizQĐæ/ÕĐuā8Pŋz™™ōðņóž"xĶA PWûÁ@` ûæĄąýÛwėÜ­K‡–Ģn>7*(ü=$Q`mŽ ÉāßFŦˆ'įötjĸŅ#ËE‰cJžrtSŨv]Ēģ{ŨXe hėßŽ.\žčtjĐĨŸ4ēÛĢbsÍNPĀ?‰ c9jŠĀåĪË;ƒzíM ˆĪŦEhõĨą]\h…‹Wũ ģæLØmäŲ;/ =ėnMV–įyŽĩ1:­Z˘4đÛV|?~Ęė„Wf‹AÍV‹ÉĻÕ@t&ģŲb6éīðąĀ°Éh0™+Ķëĸb/ŠcĖ%1Ýüh ô·įĶģ=―9 ĩ‹ĸį 2Jė+č™ŨOlą?b*L\ÖŽÓjacÎLVû%†…ALƒڙAŊý›vÞlĩq<„5 ÚŨŦá\ƒ1Ylð‚Õl|‡ų8ÅÆ:âpžÖÂjöŒëG0-"5ŋÚ7wę 1߯Ķ™ûÚĢ™sd‡zčāhŧ2VÂq&ãČi*M‹^<{ėŽ%‘Žĩ0š[w2ø—˜$­Þ>@oxģSsÅNaļQĻŪž1°vy­ ŒWqĻŦEwh­šüd3[ĢEį}ë6oÝqðâ™-šˆ2.[u'7Í ™ōݒô2VĨs’ĢŨŪÛtðؑ}{þ‘§åÍę+Q[ķļiq‚WŸ9| rĸ™"–ËÓönÞyęüÍÛįũ>üÛ+^šx‚ĀÁŸFl*ĸŽKįM$me‡wo\džēk΅"ĸMaüœœ" Ro„Îk[ļnïs GÂä›pzïúČĢ:V‰Ûß:·uãūL@ēå§í?u>9ņĘwSGĮeˆĘÛ Ž•eĸąomØäa!!#æþrýĄĢH\~õäæ–ĩ;o'§_2|øˆõ‡ŪXp'ˆâĮ1[vH}žqtÉw0ūųā]VvÜTÅė1{Ëü;öíŲĄf5B”1’ŊGMûõČÃWî<]b EĐŧŨŪøzøðác'š›!âÎ3§vl\u0rã–}į t6_ßú=;ũōqs–$‰Īð—Ŋ/š3îtÉĶ9:îT4ØūþDtbΓÛs‡ŸôýúÔ"+Žã ę‚@]-BËg\­å­ýIČėËũRËõFØ1ĐóR~äæŽroÚÄYĨōë8%íUnäō1 ÃHĘÛŊ型 Ób‡D›™OŠsáƒŪ­ý=ęķšœÅ=8äéĒRĐÜjVũĨ Đē*―č―ۗZÞúö›ïĄÓ•ĪNíâ€Į ‘_ŧӊÞãv•ÛÛV&ņÂÚÖ~. 7/·€ĶJ‚nøIϓũ Lšœš(qŊާ~ϗL/WÏý’Āé―·s,…I[ÕĄi'/o77Ũí72*[-cÖŅŋvÝúÍ{ķŪéŪRy6ŸģũŪĀ2įöĖ&0ŌÅͧ†Ŋ§ãv†Gĸ• ëČi*Zá^ÝÏŨÍÕîÖ ÛϛyfÏøþJĶGÜãÍY3>nDŨhz<ЀcŠ#–ŒðpĒqRéææâë7":!ûúáųþ~ÍšvíęŽ"œ<í︐)LÝ―ŽBĄôë89îÉËsŧg1wïEĢÍryũÔæÕ)7ĸ:JB ˆ{+―\“äL99ŧųųŨr&í&_ԖÂōŠÜŲ"PW‹•ïĮ‘ëæ5ũQ>8>°wðũ›~-ģI/\ÜvävíKŌoߨ4wHQbędÓŨfķmâãä[?ōڍ1=É"‹áĒČËļĢ=v< ›•eû1ËY 'ßÛÎ&^<øiueþĐIđš·ïŠc8g(€ĸčņJNœļ˜SlÆÞkÍ$ÂĐîØïCkđęÎýz 4ę9ĸĮ!NĒĀ–gÛ‘ZD-Ú{Đäņ­_ĩ}ņ >bûŊRARœÄIĀQ€$Qb%Y†ĮœČq2ÖuČīč›·ú5ņŽžŅ Ë—Ū…ÏfŠ9zuŨÂ~Vm拄?Žļ`@”ïz―]―âûnĒîcŧ_šqIóŽäŅ|ÐþøĪÓ;ūsšˆČčb37û”ĀKžHw{ؚãœK›Čsŋŋ|™w7nE‹úÕZvŸž{æä/+§YuÏ3ōóeK~šUĮ h5.áʖNuŠqĒ Ęnj|ÉÓ]‘ŋ=+sZūĸZéÓ;+û7Ëž{ôTžĪi^īUÏoWßļ|°ņō\b‰U„ę"8ĻŠ D™čōÓđģ§Âū ‘-ÚĻģÂĖhÕ î6xؚ#ŅpXŌ 5ESA`€ķ&Ėa°ŽaŽA€ ;vÜŋK‹NAÝ äbÅЁJ0œW§m^°äįev–/ ›ûãš[ÏJq’ïĀ‹āĢĀ/&}Տ™Úĩķ’“dģAW’—ˆĶÝÚpēsð7_â@RŽŽcÅĀ2H ũ­<7ĸ3\ÚĶq€‡!ËĀŽÓūš?ę7ûũ›·í"Ž―U2ðÛo:7oÔkĖāÚ~N,ũĘÂJÚg┉ýÚ4ėÔ­GKoĀ?Ë,·žįqX%mIĄCö l$āãëåėĪx‘7cŌĻþýŪØ} 'āL™$hŧxļ’ 0ŲžĘĄ'Ž™ŪL čæÝÚÖcqŊžcŋ„’j2M6\$Ÿn#æŽiÕĒUíú’Pjd€@ Ŧ­ÚȒŒŨïÐsņúÝûWO€ÍČĘą9ZÕm>›ŧhŲۈ#ð)NË6įyQ’e Ãī’"pĮģ— (ĨJeÐhĖFë›ūUķÛĐL@9“FN`oïÅ:Õ:]ų”’č;qĮwŪ-ōÂûuÉ$­RyŨ„‡ÍúȞ䊒`B#U*š3ëā &Ņ8$X +”JÞl(),•n‹Á#L–DVÅJŸA}æ CÏÞy>lÞŠE>…Đ1‚ÄqŽr„L)0ĢåX)ûÖdŧZB8+€ĘŧmĸOpœ„_Z#ËáīRE+h^—đjÜė˜lyô‚uĄS‡Vƒc(Ļ"&ËĒ}ičĩ*%ņvuŧJĒ„Ã%aYNp§&­=-Fá8ļ*R”·Æ@åV Š&Á–ĨF]MŊß Ąu"'_ cJ'šVýæĩÜ@fęģÞýýܕYĐðeeđeŒs {wý~+ũQŋž,ęÞĮßυbYËâ~9ÜɧßÓ'RĘAĀčķ~NĸĶnōëå\k4j^ Ü;z|KíZĢūhV\*4öĩöGÕkšÉĐ1Ï d§ä– āq\DÎRþôŌĨÛ―;6­øÉšĻ{æ-$Ý8tāWą‡|8 tëfÝ(jņū\’ D•DŦ3ä'vTūÞÕā_ŸŽŽIÎ02ęļ“ë:y+aΚ›3ü:~GŽÕÂ\Ú8Ŋ& “·œb ę_– §„č6t\=wWĸFŨē …đ:“p^ Uux•ōiīæė}­^ĸŨ‹ÓÛôy+įôƒ ėŒ}Zņ+Mz#“ũ0~ƀO†ŋøþqkJūÚlÐß>ēĻž@šöŅïģáADBŽĨ(đU€—G―îq9:ƒî―äMnč„``Įûó/BÚ(āįÞ+ÉĖŊÖvv5vöQžÉhšŧ‰95ĻßÄŋŽŒ· úúFJ6+0‘cûÃĐS"xKÎũ­ëb'“ōY óðjxP}/8ŌŅu>;u'åį‘=á)ĨĀ?2ļA \nßÝ<ĶðņĒ1=€€ŨŸÞ= îl၃Ւ{zrßķö)$üR{|čŪėR―úyĖâĸÅėGŊL†žĪ>đbpRūʃ@ Ŧ­ēhÕĨŋ'Ä_ŧr>îę[iyÅöeéôFĸâqRŽýĄđąwîÝÏ-(†ÆŽ-/|t/þztėÓŽ<ž)/Ėđ o.ÄÝÏ+.}úä҃‡Š5†žÄC4ZöŸð>āønŌÝ?û)/Ķ<;+ >”>ŊĻôMÆĀ”ægݎŧqõZtü―”Ēr―ý— īZmYaĘý[1Ņņ™/‹_æeÁYų%åZuIĘ̇Ĩ—Ļĸķ­ÞöÍž ëÏ/JŧsóÚõ[ųŊŠÎFĖLXq0ņέkŅqĐÏ ŒŒ^ĮïFÎ*ĸЃq)IwĒco<Íķ ĨÓi 2Ō’áĒ:]yöãGIɏ JĘuZc0äŦĩG+*ÓkŨ*kc5Āëš7ģÞßÕĸȁN ŅÛ1ī§ķOLßqZgēVlĐâģ·wĀuņņ$ž·VŽō6IĨ>:{ēũ>L\\AëÉžVéõ•ŨĒūs %}ŦvŔŠ9owŠ…ËÁo^;8\ƒ@ Ŧý߅―U|ągÏéKŨKī­æŋ čˆéâũėŲsûqÜË;-°>'%fOdÔ―'yČÚČjUÁl–e­fģVĢÖüĒgL°~#Ģĸ[ķĮmFF§VkdĩŽ@ Čjâŋ Š$E‘$!ˁ@T)0 ‚Čóü‡ði1äģ Ãdd<' ˆŠ‚,ŠRóæMŦ ‚€ŽöŋĮ5ŧŧ›ŋ-I’Ļ‘—ũR§Óđš:]-Ã0hĩÞÞ^Ē(Q5 (úlEôX-BŪ ˆŠ$ɐи("@V‹@ ČjŽ@ Õ"ēZ@ ŦE dĩ@V‹@ ČjY-Ē*€aXåŅ{‡g$Á@•áO—óþv0;ĸi‘qžbŅbéŪZ8 ·óĸwŦäŠøfkĸJbĮ‹‰@Vû"ŠĒÅl•ß&"gcY8ŽYŦUdðōÓĪf–áþïq|œø™Ģ0x ‹ė“ÄÄŽržþãžēĀ™L8ģ∞Ųl•ĀYČKMĘ-2ā°Y-PX ü?€ŧŽÜ—dģXxQ‚$x+“ĸōeQ™Ö&Č_m‘·Ym\Å!œÕÂqb…ĀŽÅĘ žÕf“äōĸC†pl–€S5Šö&d8@dĩ’$9ûÕkÕŌåYæmi^nzūü"­ĀhIŧŸŅŪMË:žÔÃóúõ î3pæÝįz{ŧ!ˎïL=kô  āî_OÜo ŊÍéÜ―ÛœU{Ë9œĶ,ŋ†…m _;óŦĀOÆŊū}ïʂņ―:ī›z=“Ą("'ųü„AA}†ūŸ‹DÅũžd,:séÐŲmū ŸcåÏV~;f8cŲãWėk&–ü‡ÛΞųeÁŒY3––ØH'L(L>9ėËî―úNŋũÂĪΉ‚Äã“C‚‚š†œNČ­žŅ!ó’rĖÜđĩ3în:}ëŨ°Ýø€å}[ypÖōýëæv œqųA4†Žļ öÝ"h…!3fÞčå…ýōî‘%["gOųjãE^vļëōîÜ/8Ļːe‡ī<qę“l _9ĻO·žýĶ=)2’ĒîĆ·†Ŋ\)6$ĨÃdX‹5ïyŠÖÂC—.Iū4r`ĻáÄ9'uęīÕs ›ē8SĮ•ĶEŒ8žqučÄYĮXJ|™œX įIœ‹;ąĐS· nFí<ųPīþéåÐ͇·­ęÞđÄåûī"† D›„—(@;ĩĸâŦķMęÂõ3nðy_†ÄĪ— ͜CŦ–î=°eČЍ%ÝÎÛc+húŲ™ÕŽß$iųĘæukWޘÔåãÏĮüzįUÅË$ ĒG@ë·ÜīœėēW™šR‹5ýq‘Oļ˜ÔVÉŦģrsD―rp}ŸþĢ&O†ēZm“„ÃkįuîÞcÂĨäš"Óbö‡nÝ7mėÐ1{âxKéúÉ#ƒƒšO^s8[ Õ~ m­ÂŧcÓĶYÏģ>ÍäüûôjgJ{ōäÁ+}óm‹ÏZxięö_ÆtâW.^ÃāN„Ģ?˜ĮÓúN,rëqðĀsƒ•Ú'ã'‡Ņ―>īCýûëŪ‰žyë|Ôđ‡}æŊjþôČŨ3· ëMýąüÄɘ>yöڏïØ=·ÓÆEŦ3ĩŽ―‘eÜŲŦ]ģ֝z|6}éÂ6ĩl+ŋ{·īÃū#ú(LđŠP 8LiŸzŸ6ĐóŲĻ)ÓfóP›öųÅSw‡Ė\ø‘œū5ÞÂ<ž9aûČíá ;oþé§4#IáĀŽÄ;Õí6įūë―Ģ ÞÎoÉveãž]ņÅÛD…Nð\>mĖS=āJ“~ŋũ ĮpŦņՅôh“„YŠo_ūÍ·õ7Ŧū "1@d‘Į=Ķ…n;ķs)qaÏí\#MŠÉŨöFüÁN]ßÃëņÏv—ēāŅõ―‘ð0ė™ōóúÝåž‚°ũę–Ä[ž_˜8ĐïTŸ.cũØĸÝÔO$›ÔeôēÓĮ#‰ĖÓĮŪ%ļÕkßĨM‹Ï>4V -™nĮ\/ķIOOŽ_°å·yöėXŅóDØĻ)ÜRtj}čé°bÅÔŽßÖß~Á8fß­H1}lÛōģ]š<|-ÉCÆÍ) Žôĸ>|ų—MW/ÚúœõíÖw@`›āĨaCj(ŽwîÞĘUp ÓdĨÜĘ(Ā0ž(%þØÉË]–oœÚ„]:ę§Ģ€Ûõ—€“_ŊŊ”ôŒäԜ6_ŽéTŊ(ýiZtđ{û–-…ōįWï'•ÚwïŧvíŌQ―ę]8w†§dˆM?îôĖБ­l^q•'Hcރí+wÕï4iuČG§w­ļ` ß··_+/Y– Ædĩ$2/S-:ķ+IJūĸÐ9ø‡Ü=}0ƒŅīýĻYaQfšþåþÅsũ_ļgĩÚlœ„aĀpsQZš9Ąs[ÔoŨĶĐúŅM­Sŧ™#zŨmØnņ˜OóŪÆŦÁ*Ķ­Ø:8ø“:žžf„ÎÔģE+J­Év§,·ð·-a‹·Å—>3ŠÍžÝd Õ5ÔĻŅĀŋuËĶ>bi,ë={ÝØÆu}=}šMˆÍ*HƒVK8yÕkîRģAӍëÓ@ā\_ķaäį=[6ŊoaK4EŲŋJ’#~Û~Ö`īčLü›{Í" z ŨĢA―ĄģĮ7ņVbRiüÕgūýŋëÐļ^ÏáS?ņīÄ=.ĄhŠÄïŌöõ€(YÛ šģxþ &ūŪ?ŲʀtĨđčckæn>ō\4Œ‰‚äÕbé?  6rTQViĄÖ|`äĮAA!_*Ė*-flXe%4Ž;aļ&?õyãĶ3gŒnÖ  e‹FîžEįĒ.Y‘§ã8NRVŦî_ÝĢn@Ãfę@Æėũ ŽIWï›ZŽÐĄeŧÏĮęTótL†<ڏÜĩ3ŽGïūž―X–ŽEDžóëðõ‰ģ—ŨŠŋtæĻoũÝ,ČĖĖÉ}q|ûÏk]JÍ|i`‰€Fuüjúĩl  1ŒtŪļŋ’É ’4ė‡ ÃzN\<ÝŧfōÃĘkÖgÖļ6Tđ―–Úu[5Ū ĩq†™pÂŊIÛzĘÂ={ũ _s`ÁĻ/ Āh3~šz)đŒ Žð2ũIČũ göŊE1Éũ}õÍď7<āˆŊü%ēÚ I|·wÕß?r&.ĻOŧ–]ÛÅGÎ*­ÖķĄŦdc―žëOøî§Í{ŽÚĩÔģŠŽg"‘*'`ē—NI@VšûÃXyķLP*( 2 d•ā1€LzË#ŠđxâtÝaSf…Ū\}3ns_Ĩ$ˁ(ņ†•íÖKPlņŦr ŽcVc‘Ā) ˆÃ”YŽŨy˜ Č@‰“n*ČžĀó8ĶĀeŲMéųÅøï—­ ĸíĖÞķ^2'ÉoÚwZåėíįWÝŲؗP*Ė…·€ËV}đZrvUĘܟó–•J’d_ ˆĪŌ‚ø:&óå;ū—šÏ›>ū….P$Ā0%€ã―x‹ÉĪĒ %…È\1š`„Äí.] ðãÏŦ~Ûš1ËÛy"ýĘæof,/ē9ÞDE Ŧý€8^9|忈]ŧ”MũhÐē2ōßFbnZšėUŧŪŊ@­eÕ°Z ĸŧÁšEûeI|㊠#í+#ĸuČâĸaߎqˆ0ŒÎ’tD"Ī&=-E3ląĄtIïy<>e–ÔŪ^kmŋ8ÞŠĘ4ÅõÚ[kņ#3ŋLjĪ@jZĐøķðĶ)ĶXĨŠ(' Āøō“―ŧ‘Š:ãþ<įÜyŲŲŲ™}ŸEYy-Dk›"PēM+5"ĒÖð&„âb-ĨB]^X6š`Ã5MˆˆĩUޔŠEKZĄÚŌ"bJŲeWva—Ũ{ï9ÏÓeýÔt(!ĄÍLr~™'ũdnæÓž\2WUĮZö<·ų[ģV<ŋuņ‹6ydfhýčØąŲŠˆôđS'Î VĐŋŋõÃUŊ­uwáGu Ú8öWKdĶφĀDĖ Ā&j ÃČvÄėļnÚ&ȅr•CɔcێTķfôøeóɏ›Ýū‹§N,**^øðũÖþîóØCÝZÏXšæáq_;pĻø}īí)đ5Pä­č-Gû4šŪc;Ņ1ģ6­]X gFCÉdÂņƒ~ŌŽãš„ęŋŲsåBËóKæa_čw1n‡óHs†ŠÖķYkæ†a0S„ PIŅŊ2úaÓĄC?˜zĸ° I*ŧŽóKžņŪÖ/ŪXƒKÚZÎĮý^°Ë ŅI:ŽíjËb"íšv{WBĢš˜Đ‡ƒVŠTZŲIbfMÚMĪŽwÄĐOĮŸ‹EïãHE•'Ô9ÅęáEa!―Eåjȁˆ{Ā `†‘]Ø!Ï]ũΞ?üŌ‚Ų ÖnnlÜüĖŌÚUŸĘŊLŪ 7mZ―Ĩ~õŠĮFΙQ@7™TŪDm§RŽ"…ŅĄƒþōōϛvūŅ­§“$“1GóՕ›Ljb_quU0ŅļþéUOŪûĪ―•§úîĢG9/5žļwßŊî:ØĨQĀuä@Uk†― #íZ‘uŧkÞÝĒųúĘÆÜ{ÏÐ>ĢWnļï@s{|^ÝæšŅ#ė”;}ŲZŽĒRĐáӗ/ÆJí$Õ,ynÛ°nķĘkŸĐ/)áāCÏ.G?j’å‹6ԗVxÜ@õÖ-ï}ōYÕĖvi‘“_ØÔīýāۇšnÕmýó%fœFÖŧcĒÖ0Œœ‰Z‰ĀŨØrE~ņ„3' d§mÆĒĐÎd`í8ŽV8ôîņ ]ĮUŅacú‚ē]þȔiģ˜Čvœ’‰“īĒā I•ķ]Āāßîđ’V}GN˜ĮDԚQēēíz ŦĶĖĈ”NŲ ņ°öūn^n†ņįŧôáOŧÛŧSc‡”*õ ^oÂUüïWþŪsDˆ;pälėTKŨØ!ewÞâ x‘Ėƒđ†ad†OTE<;:~ébwČįģ˜!W ð•ļ}ŪírīĀ[Q -Ė́`F–a€€”įu'çÛâÎv ä‰ Y·ũ+,+R ›^­aYČXĢú…Ë#yI­5äŋGDÃVEČÓ;ŽÖôj ÃČbÄ 4qNþá@‰7VŽĸŦ―;6Õˆ0hŪfõĒŽ”Ŧgrr ø;0N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšžĶĄ0üëôE>ŒŊ~mmŨĩl™‚ œY$B‚X  : Pl8YeĨ[ŋX1þâ%ņGxĪæhÎ.ļð―8yrúžÏ9}ōžWĮ0LÓlÜUģŲŦešÕĨEmzōú㇟ĩęyŨÎfūdfŠŌ°,Ā4ØbYVĨRQUž‰ÝÞÞÞÜ܀ŊårŌ ÝÐōōâÛbēڒžëå{.w<ņ͐Ūk ÐųÃŅu°‚vØE öƒS þŠïŦāˆ@tÁe ĸÞđp°‰ļė€ģÓˆó.Î^0xæÓ™k5LËnÔŦ)§ÆŌó·åkĨÂč`x˜bY‘ÏÏLũøý|dęĩĒ[PÄvė͗OŧÃXl,#BdbŠXW3 öðq?ĮĮú{ĢkZËU§Đ‘úy!>Šæ‹šï;đT$)ø—šHËû§ūgŽdcŋu2ĩ°yļ-ĄNšð4ÕӉmŨNö–1ðŽ?.Õkōlbl}įüŌ1ĪgĢ8Eâ-Ė]4=eo=Ép;5ÛUø‘áĨ­’åØA Á'f,―wîĀ&fvOmïŽģž]ŠČyf”ˆ AM–UĮ6ÎgđÁ‚ßÚ/fäå“ãÔ`§ļīqR=ā(šlķJïĈ°ę~ŧRåMķŊ+Âr,ËlTLM~…‘Ųšú7ĀŨÕY§hgÂ―øJáäęĘýž6ŨŨ3ÄÅ9šTK/冚ŧY1óUwĨô“ÐÎ ąh8"æ=ßYMttôÅã<îZؐ=ÏnOf{~óÃęócšƒĖ <Ļöt^Ðų‚"č°ĸbÖz^Ģh‚hþÓ\ūÓwĘí‹QņŠˆđ|ˆHTPPbŒŲdĢÓŋ§{š{zOŠŽŊ§ÖbÝYcžYČP[õúÕë·ĩäā ČÏÍŋŊЍ?xnô‡Á[f ĨÐHĪ”P”B°oįžÞšyöāū~õ2ƒÓ€i­ ÉyJ įóųl6;??*`ŨcŒ“˜Â‡‹ŨïîýĸfũéŅíãŲ Œo=ÉXErNŅåž$€Qda”Ģļ†'Ŋ\YÅģŠóÄĐ?kzŒY•ąv ú Wo7õä8Ëü|/äSðü?Ōäœ|hGӆļ(I Ą­ėĻtÁ ­sJÉÎXšū$šAŅÆæ-ĐŽG`b;ĸlïž:-]—‡’BûĐVŽÎZ-O%­LŠá…ēąKđsķ ⭂Ð.ĄVb°ŌļZ4ōBęspRĀ}KiąŧmX@§ 釅wŠĘFQ6•ĄģüåÁ[_ ZõXßG,Åôī|5SÅūïŠWrÄŅA"áCÄĨĄB9KŠäcîšN+réSMSÕīÖĮ˜úޒ=ä6ąóZ6óųGWŅ.â% jŅķÁíS#Ô+āCέUÆw‹ÏCŒQđĸïöÎã“ÎÕvCųæýáÕÝļ?„Į]\ē?ž$ †w› |œņžØ”óïkm/0ãY*“\ōûBp‘åM_x^ŅÍTSäá؁+úģ…ŧ5X Š1GŨ—‚wðÚžÃbސĩ‹—u€ČA—sÆĸēáõą/ω-$| /ũ UĀ ð7€ŋ"'ĐKlLKƒ(óDâgŲĢ<ŽšŽ“9Y0ÄĖ`~r0ZEōqŪlôâ”„eð)–ĜԝúÃ#6úÃķc‚  rĨc—h%­Œ5ĸ؟FŨBŽ+%/îėíόąāĻʋŧŨũž―?ģÆ*ĩT}Ču *dŧ6Ļá_=…a@€Ó>ŠY äĮēĒŽI0)!Ixēoˆf9‚Ū@ JR,ĸŽ’–†r]ac 3Š0šļb#Óh(€RtØúŽ,čģzÄ ŽĘ(§–:GÖT€N jīāÉĩĸnV>Kē9þ#|2a•Ï?āyžÉá§iÂÄãņhƒ1)žqЧ˜@EoJŅ]ëŲåWSf#zĶaiũčœ2ÐR}YVWfcŪ->x,Åiņ‰ēĖĮščŽmņ1ĻųžJŽÅĮĮÉUەl<žæ#ĸ'Þĸø6=s8Ė·ŋøõvŋŸrU>!žĘ‡ âƒzDKødūÅáSŊðĐUōi›•e͋QÉïMÂĄü*M•ï™ŧ‡ŧûŸßMÆGESĐųėũ{+m\åƒo―?%„wņņØâ3aō™W~_ˆ->Ø2§eČßóáoäs1Žã0 ›aã‡#ūïú͓mų}ŨuC?l·ÛqûX·e7îHĄPF`Kē(Ž"PT!pÓL1[ļFßũÄņTڒɈS@##ž3nå.ï ^īĖ―zVāiôz>ÖâCV“-%ųÐH™7YáSÜ­ï >!>X›ïĻðņHĖ­8ŪōÉ(ųėÆ‘Æ››ŊãĶāÓoPVųØ>ÔûĨ3ö>Ý+|äcąĒ|°rrųþĪ“O č-ŋc1Z_ðŲÕïO–Ö|pĀžĮîKg‹ï›LZ|2°$F Ēô7ō!sø`Øi|ôöū…b.ãĮ‚ž?Ą]ōA‘Ę2ãšĮÓø †“1ü >ø‹ÏÏvõlŨŨŨø?: 3KŲ§'ËâēĖĢū>ÖõĨˆg~]ÉU—o•i]^^ķ––Á:ŽÍ§ĪWōQü>ÏÍw Ÿz”ŲšĘų`/ø`Æïâc>ˆËKĢīø\5ĸãÕĨ!ģōþ8ü||īäó›:ķ†Ą j}ï?jšļ‡HïpÅÝjĸÕĖėOčĢÔāeĩ°ZŦĀjŽĀjx*Åi’îNˆ{įÕĩũý]NŠÝDKĒÆ–˜Ükr“Ļ %æ5XĒÆ$bIėhDE‚―!"Jl`C "ˆÅBSQP@é‚ Ō{™FfNyÏĖ8ž&OÖzrßõÜÄä؟?X{o~ŋïþî3sūsVV^f Â4M!MsNQSQR^Ï âŸmĒ%sĩЇ@Ē–`CņÖIį‘#Į‡%V`–2ÄF­U§Ü&[ϊ;wķ°°0&8 G!2Ļ#„)cŦŒe$cf,‹ ~QfnÎŌ͚uîdAIKJãNúÂN ;"\_`ؘĨq…ae2KaĘŌR*ïÄŌXR3·”† Õą+–™[ہ™$n:‚tJSīĨņ BŠåjÓïXŋóÐhiICC%@Ē–ŋwLjØ#F}öņ@2<årŠ›gĸ`/áäéÛ 1EQĨ)W6.‘Vfŋ|_iŒ@MnÂþŸ|ngæÅyϘ1c_@Ī Iķ7Dųï“Ú§/w:Ļo—īušÏ°·_ļ|wFyMĄ_ŧ\fbdtūVŨ•Ķþ|&›ÓАģZų“Ã[gÛÛ;ø‡ÞŠņ;v>\ہMÕ9ûö\OÎŧséŒE›ģj5,æS/žgo?{ĄcäƒDŅa Úî^:Ïåjf-–Ž‚4·BýO\xō,gíŠų3į, ŋWŠ­ÏÛë2cĶÃÆĻ널Ô(ķ”îßd/Đ­9ôĻVK!Ä·U‡úė9“\œ›ļz֌EŦwgUihūéâŊ]‡Îœ>đÏûTx…J#uƒ_C Ļ%@„uʘ@—]Ũ”~9ČĮ}ŽghĢš6ųq>FYz:āf‰Š#QK QKøMDą Ō<ĖXü(îBHTĸšÕÅûËKrÃNmí­)Üįå_Ī6[{8ęYœ·–ēÛ1ÁåjˆäENöęĀý?_=đyhUf–ĻĐvEdîĢFÎō“EnQ)"‚Ý_Å|nŒŊũõ‚V“ĢîĶú8~ûav% (`bšîŅ ÜNcí–9,uŲffĶ?xZgfÎäÞū”˜ÕóýĐũ‹ĒÏîî§ŅŠ!Ā`AhĒŧÏßéŸë7Ķđí8ßÞwLtDÂĩĢkÛ*Ŋ%Ķ—e'>­dŋŠÎK :ę ŠŠŽ_Ʉf9ū]' °{;jf?ĶYŅüú—ˆ˜K6C-ęÔé„ûūngöĩ1ĐÂī™îpUR?L˜óÍdïKŲԔÔWpÏA4Õå*‚Ķœ{'6yėoDP““˜ĶœžīQōóŠÕŽ―hË^ýú2zŊĶ0øį3ĮōĨSÕcÔ^‘đrþ·+<ÏhH/ŠSÖ7T+ä>eåî 5uųuíŠGuígŋÐéƒ!ƒÞĪÝFl]2kä=šw@‹ĄĶšŽURĻĖ?ýíøiGŠAŦķĄĶQÄHÐņ=?ĩwY4ë―wÞíũfwĀÕķp…Y1Df˜†áƒ„—ŠaÍÍÍ8„!Â|+ėˆ\ę#ŽĒĩž‹Eóæ8Н?Ÿ―rú?š‰ÓæÝ†vƒéžT0ÐęxN  ę85!‡ķ~ĸÝ܅ .˜ũÝí9äy€õĸwčĢūö>ļõ=ĶĘcĐýøI“į:îČkėņÓރkfY?>įa7nÜø‰Ó–đz+ĩ=fŒ%HfIIS!ĖŦ‚ݝí'M°›8;ęQŔ%Ŧ—9ļû°Đ]‡ąŦ&Ų}1þëY .'• ÃYhŽļ)ĩhŌ{―9}fólÏ!v§É°7ēŦÕĖ―;{7Tėßúoũõ‡,āõI1Ä: ŽÄËzý+(ðÄĖũŲCŲ}a7áŦ™‡ÂîZôĩņā‰ŊŽðî5óíÆO˜øíŒcŨrDš– ‚ŽŨ Hp:˜S2…!žât#&:öŲ6HöÐaú„qã'LŸëxeY†œČ‹†Ļį9āšSĒķë°ąsū[[ŧpÚĒŲĩˆÆā@^bJŸåĶžHjjiEeAnFJ֓چđBÕĪjxš™ŦĸCŸ7SŌrŦęäęÆfyU҃ŧņŅ‘Ņąņw2rrë•eRóģŌ*…RY]ö,-%åqI•R^W•q'þfdDdü{ĨU j•BŪP65Ŧōs3ânFGÞļy'éaai\ĄëQČëkžf?ČyVĶ0ŽHH‚u•Å’āÃī‚euŌíøČ+‘·cB―{ÐóƒĐiĨ*eMYvJJV~ąäØØÔØÔTU˜›pëfTäø;IųEĨ ŌūęōžøØ˜čĻčۉũŸ–T(” EYĐӋŦę$·ų’JÆ#éŒĘ†šžœŒ”ÔžšzýEhV+žæ<ž›˜š^VS§hĻÉKMIÏÍŊiP(ękrģĶĪ>Đ­—jUĩåÏîÄĮÆÆ%–ÎE Ŋ›!(”*õ/‘2N)-Š”Ķ …~f˜† ÃĒþ§ŌX%õ*ŠįĶąR*1TvüÖī­Ģ@ĮšĨR’TvL;UÍÍ5™cŋ Ākï{ Hž2ÔÅ#LŅÜ,)…~­#aÜZĐøíEĢC•ĘhÁx*ihrÞĄĻčč3ë,ųüŊÅ Ó$f $j EJyõ―‹!ĮŽųúøø=æwîvz­R­”ĩ„ĸIM­mí&ښ•ŠßÕF Ļ%‰Z@ QK  ^JhšĶ(,Š€@ žT@8ŽŨétäæþrV­V?yR€1ðē ōžðöÛÃ,--8Ž#QûŨ!$—+ŧvíŌ·oA@x9Ā—””*•Jé‹čÉSíߥĩ={öāy„—šĶΜ5>‘Ļý› šáå@þ›[’|Ý @ oö"ĩ@ QK $j D-@ HÔ‰Z@ Ļ%ĩ@Ē–@ $j Єq‚‚/ƒ+„Œ–~ÓðŋáBlāŋŠA$;ĸîEûĸ:‚/t ž_^U‰Úŋ!<ŨŌÔĻV7ķīi)šæšäiÉåAøgÆŽØ^œ—VVŊ‚―˜˜’)„‘šēø~N 'Âß!„AŦüÆÅģ!aųõíÔ y*é4ä$į”Šž$ø;ųķ–6^üũÅĩ5―EA“ˆ‚FDE)ÜQ1,Eąý‘ØQZ•Š43vŽÝ‘ÝFëEš‹―š14’$õîŒ'ĄLÛCøÂ].ĻÕ*fn?ļßëȗÃŧōz%ĢgÃîŊ]6š ,B€L§ )%3ØĻ/ôʆ…ÓĐï—ßMë%y(™jĪ0’ïč―[L „;éį|ߑŸÏē&rBĮvFqhšJ[ã^ÃõFqÚpÕ)ĢōóŨˆ1ļŋÜËxaRúJLI”ĄÁĸ'ŪW†ŋŌ1:aŒNŒÛHtSšéîP6]1ƒC=X_Š_A, ƒ―ÝBîæK+āEDA‡šÚûðfˆũéû• ÓāęYŲûÓwú˜ó"Ēõč·0ģãJJķ0úåI ÞLïLLéŒąF:áóad(~þĶEKƂöš^H.’HÔþoķíÝï-ŦQŸ,šŋhjjlӉ‚>qøvEčî5ŸŲÚLYwĪĪ0ˆ ũÝjecûɧģÎÝ*Ķiš$ųĘžącĨßkɈa[žn5ÕÖúóå>ŨÛmJgÜZ•ybßFOĮđKķ*(œrņ ĩí—ß-ÍĻnaY\˜þÕ8[kŦąËüĒue‘.=l§­Õ7_mKέfhĢ–Ũލ 8|aó”)į“ËõųŠxvtŊã˜1c<Ž'˜Åm ĸö6ķÖóVxÕ·ã FaáQÜåāŸã#|Ø|2^ÐĐBzôG+ķSņ h­órœgõŲg3VT·34j=å9ŅÖÖjÁÖĖšvŒ€ŒQĘe_kérŒ™ž/øþ`°%*ĀýãO­W­XŋtMrߔášïˆŨ֕cŨ­lÖÆōœ`kkģČ-ŦūÂļđðÞš…ŸØZO<ðs bØĮᇾ|ïr;ę_ãýŊÞ:ĩgíčĸé~ėš) [oxJoŒÎ;ōÕTîÚïpĘoęčQS–š4s•§ŸÝåūé‡UĄZšy1']{+‡ußRgũų܏ņ Ügó XA›w7tÁÔOm­GoņđÐÐøČm­oi+ 0sÄåLrK!Ó3wËÏõŋŸÃlŧOŽÞJNX>wÚG}øó"†nøļžKĐb*3ÚŨ5(•eéœČ3Ó?ĩ•ÞpaéEeŊûŸ öt]ŋl]˜–‘Œ‘ĻýOB@4Ĩ*ȉŒÝĩå„ÐĸóÁ―ÍĨðĨ äųSŽōDČé·+ÏoôŽiؘõé°ðUãKļ]jÚģvĪ}ļ(äė™I―CkëŽynŪxgzāŅÕÕá{Ãî•Q4ežÄ6ElÐŅ‹ŠĄ?Ž\Ēšėļëîķg ā6oTk9Ôy Į‘ĀÃN ƒ|Ÿ4ō%·Ïýļ*|ŪĮņ ĸ!Zi ˆ˜2ô}›ũÞZāąÃú^€Å™áŲ”­Įĸ'tũ‰ē֖Øc;| ?|üuÕ-ŋKI<ĶĨ.A€ýGŒī5ÂjĒ‹ÃäaąGķy7z?ãjĄēøöí[Wãf?ïVųk‡OžÚë9ýUPąÚyc‹Í —öyFį4 A|dO@^7Ï­óRÏø'äÔ”Ý―ž+Yã|8pßF—N4x–pjĨ_ōÎāsó{ĨŊr Ī 3l"Š:‹Οĸi1°ÝŊšCY!;·ŸˆÚäåį0ķ_llHy+Į7WüžoÏýōáûė›’Ŋ<žúSðđïš?Xí~Aj\į­ŽúŨöĀ .íސXÃĩT$ïÝïS9dÖŠ/ŧnžŧ8ĐæŸ;œ?ž|8°DģÏíZí—āėŲKc7{]ÕōÚÄĀ―{üS—írGYÁĄ7ŌšúpĖ?†O˜ô͏ŽĢ0Į‰"xQĮÓß/óbsƒÆĖ<ýĨÛʑ=Ĩ˜˜ï―ÍÝsÚwgzØî ~)”ķîÆÄ&^DfÜPÕ0,Lõð‹īZīyōkéģĶmņÅē%ã,|―ÂÚ S”{Ŋš"TW˜ôāA„õ‡ÖíĐĸfÓÅ ĸQzõ4rô{Ã&NîüÃGX'#QûŸ„€*,ʍŽ‹mnļķŋ9äđÆŽøpyaΚ•kãģiuAÍļöŠí.ëBâ+ī\™’§ĮΙÂ\ØŧÜÝŊRƒškŸ<ū7;*ČeËņžV^ŊŒwüŋėœ\ÉķĸŦe ·āÁļ;O€Dˆŧ'$@܉oÜÝÝ7J܉  îãÖþï$ėÝÝ{ũÝũöÝÝũïï' ÕÕ§NŠž9ĐîĶ~€ÔjEÞö,™Ũ­…SáįĂŌôËĢũßz•ü=OE"&Hõ‰ËW_~RÅC…4™š:vōo; ,4ž›V­ÖđÐ[89:y™xų6·7æãĖkČĖCK†wjÝÉÄHĄ”T%TæKŌ.™ŧôņįL…ŊųÚÐ dbãėėėæčŲÄՆũ.Ŋjāę)íüÝNŒīwüžX(n˜iaŪĖþšQm>}ÂhgïÓÂĄ€GKūŽâՓWIɒ0?(íÍÓį‰Ï\‚‚EĢîK1ꖃ–ŽÔ―Š’ĪøÕ―BÛþQ­žžšŸÞÂ@HýÎs„'bd™/irƚŭ=Ý[īiN–$|ÏüpýpôšģEßą*ąŨb–]ÂnŒęŅą›5U%SX·čÔKX°%:ō؇RC!•ðøēĪ(oudäđ—˜ė{ąĒö]& DdĻÝīxņÁéjŠLÃāŸâī~SúĩkŌ~Ðä 'g˜f-ĩl;bũĄŲ­Ü,Rž]æŪŠŒžðА§—)Īđ/åUŲŨķGÅ-АI•ĨĨ[ŽZī{BH·ÍÝĮoÛ>ŪGÐHsÔ|)*ýķ.zÞÕÏßSRr1RFÛwÚrpGĸ ^ÝÜ= •Zdbįhmæâîéåá„04`ClC“fžÝæMîŅĄŨ°‘―Û øöā*pę3kp'·f=…ĩKūýL†ŠøĻąþ9,@ļĄ†!PŦĄ 7NėÔ&°u›a æŒëÛ9pÃ(؞6†jq!0€Iĸ‘―ŠũŊŠ<'ÁaCs‡FfnޞnŲĀîĮŸ ށĄK—íÛ°jNsgŠĒ` ˜o`âhëīpɊCgÚ2ē:ņōüõ‚ÆÍ؝‡ōa€t™°āÖíCˆ”ņ+Š`#‘C‡ā1KWĮ^š}xtw 'ęîšC‚čÜŌ<bíŌlúޘ­g.ŋ8·Ø°ę͚Yó ýFÍÚßɘĒQ•ĒZÍR^QRR‚ HÃ'{2%†Q`Ą€…‘€ ī4Â0Ė#p·Vý#Ŋ ŲIíU0 fí˛M^œŋíÛDŦ Œõðį§2.ÕrÐÆĻ > S„')†&5*ŽIßÞ}úņë‡Įï>f€ ĨEđĐŊ>―HŦúžð.þÛÍCGnLŨĻđHhdãÝwdĸũq?ŋų”ðöŃĖR)Ļûø2ĐR*Iš Ü*4ŽqŌ…ŧϒū~žņ,AC#„F›“þíÕŨīøÔžŦoR}[A_ĢVŽ_―ņĖÃdŪ}VËЌ‘-T^p`Óķ,)ÎP˜BĨĶu'•BĢä[…vĮžÄÝņņËûįŸsŠ˜NĮ 'Čē_·>ÎíÛ|āøÂÅëø–!VļV­ÖâšÔĐ•*ĩŸî&GöÄ>~ ú§ûVCÃ]--ŧũu-Í.o6:ÐŋK\ThlŅÜÁ‚PĐØh(å t%­JNëŅó‡TÝZ9}þ‚č g„ä/ŨJ4‰Ũķb”* 0m2Ŧ]ëss§ýīgï– G%fM‚Ãü_Þžņákâ‹Gs+€Ą•JĄKWīZ…“S”ðėčĐÛÅ2ˈo €‘Ö'Ø|ĸųöëĪ„W/_%āpíK$šÄ(yiqÖĮwOŋ)ē“ïßÍę7kŽsɅ™óæM[ēGR.GYCĻdŚfÚšh#Lŧy'>)á勗Ÿ(‡vs:ķ{uėôĮĪä7ÏïfËIgįGː”R­/C*•˜Z+č?k‚'!.þۇŨ·^ĨRËq Ũ™ājAē=Āvvæ?Ÿ?uãņ·ŠoWŧvü8O̓AöBȔjš † ÝšŒð·OYīlÓĄ+6ÝĐ˜bjboc ßĩyÝō)1ũģs4ӅFē'•ZĒfš•*]g|ãÔūUŦĒķÝČSér~Ųđ­{ŸĶæ3@`i ĩĩ3ŧvæØ‡hĀ_dŅĒE€ã/ŠĒ‰”ĮCÍĖˆų—ïÄx†æ.î^nöāÚwýöŪūn,^-ûķqÏËÍVa°―“oËví›ŧXWVĻ;ÐÍŨ‘Įޙ›R™đ…|6 §ģ66ômŅЙ“]TBÁÆūM›Z› jz‡ų†önūnnB˜â™7îØM^š'Q†nm[īiŲĶ…J^áОßĪā8dօ}CÔÆMUVáÞbāŒiCžÝ[™ =|#[–þ„ĒÔÞŧĨĢĩ‹›·Ŧ%Ę7rõöũónėŌŽUŨŪ–EyĨjxú5sī2úÞ€˜[;y{đZ˜lýZurįåæ•˜xö^6ÕÍâ™Úxú6sķĩ™Ųzú4uēwčÚ5Ā R•HZ‡Œ]3ĄŊÐf>MÚØÜķ™O‹~#{9›DäėîÍN›Đ™ƒ'{ęh !Bgw_wWĸŪ}šī24ũÜÅîÍÛäāą“ņ(ŠĐyF!röðņ`[™;zz{ļ:X5íŨËÏ•* ˜šķhÚ+(ČۈĖ..ƒųÖ~ÍžYZ4vņôrķōųön>-[úXōé‚ĖĖ*œ<}΀–ösũ-ËóģŦļĩ―Ŋ˰P<ĮÖþUerĸCCŧ·`aû^ÁÁ=ŧ››Ų ęÓ*íÍËfĮ5mėäėéííŠ[’Y{ėÖĒ,?ŦZA°~ž=Z‡ôōrPäæ‹!ūqÓfÍmmí<|š9[›ĢB+7?o§F*tróņóīģrjŌ―sŧŠĒđ†1qņjîéæėâîïmo(@,mýš5ą23öhÞԘÖˆiӖþ^6þ>~fB„ųÅý„…ŧ§Ģ―BS°‘CŸ€ŽŌĒ&>#jz€;…˜vnæĨ‘*š =5Ēŋ—·-{ ęڛÚ8ûøúؚðEšKååjcĖ™zųøzļØļ7oiŽĐây͟2ž­‹­‰šĻ0ŦĻÜ6hČÂą}ŒøĻWóĶ"REó,ý|á?ĸa- ÃbąXģĐþöņSýŨƒCĐT&&&eddâ8Ūų`ÅДķîP‹ Ãāúc’fę Ų34óšf›ÕBXMKĶaÍo9dÁ8Ĩĩmý­oĶŅjišų-?,ZJŠĀÄüÃđ–ŽũKŋlEŨųŅþCĖ8{LS Z gęĀk‡Eę;eûАÄu•ZĶëŸfOÖŨ8‘ýėhXøœ;Wtjļøī†ŽCÃVĪū [SĶýÅ!‰ģæD]=VSƒõĢŽ―dEĸCMÑÖ#Kŧ3~Ääí;ķE·q_^(Sc8Õ°IC?ĸĄ­™R_]ŨŠf,úöŲ ­ŪžÆõ'tĶ$^ûÓAbõ“ųKp’nø!Äkí™úĘÚhšýIģ3ÚŠŪ† uĨšîĻ:?učNiéÓ[gY7u>AĪĶĶĨĪĪ*ōęĸ ûüÅāŲŲđ"‘ÐÅřĒ(Āņŋ ’‚ø·ŸJŠÔ–Í:4A óˆ hŠ>ü˜™W!ēõėÚĩ•Ąĸqqwœ™™Y Ã899â8Á=ŦýSáĻÓø?EÝÞ}†æ™;õ0tüĪņ!]›ĸó< ëEþm]…ßÐm€~ĮC‘eŧ ą“&…ũïb)‚ĸēyV?'ĸŌFŋą†8 „ĸßáR)CŋąŲb+!—|þðĐRû‡öĀBúfĨqÁŋuP„V‹õy$Į ’bþÉ.=F›üõc‘Xņ#;ŌīFŦĨþEü!Q™‘ô!ĨЏ0p6 ōũžĘSĪ>ŠŋĖ/ę§j84W%ūĸTĶ þÉEG *ĸëËÓG?K*ÄĨZŽĸO €Ŧdb…†PƒJF!Ū’iI‚ yæÆĻI†ũ/s(ī*ĐLĄ…þŦV\̐ƔŋÎS| ņ놅{ojiäŧCø|ËŠywÞ§Á(O_ÁƒĪßĖßĸ]ÁCað{ÐĪD*ÃHšĮã?ōÓüpŨ‡‘pzÝĒwTJ‰B‰ģ[ŋy\†ĸÞ @0Rųlrð„'O'å3€Kĩ+8ŊĢN=FPū…ō†‡ĩ"0ĒW8ĻąG‰ŋsâčl ŠŨ|ûW/z’-ðķ! óBˆmT·ąĐņÉÓûރ­zĩnåē'Ų!ú•^“e#Gā‘ÝqÍVw”Į:Öę„t ŋšŨFX;=0Ôā°^Ą~Ũŋ@ĀÎ*dÝ5ûČC’'dĻ™_gLdãÖ―CšĢóĢŋÎ ëü6Ô"`ƒÕ‹< ĻŒę~›Æ6aĄ=Ý,„€ęĪl8ЏDÃÕŲëĒæ=û^ÅVÂvŒĩ){je*Ø0œÚô éÚtƒN‘žÖüÚõ ėQU ĻF°‚Ō_\~Ýė5üĻühĻ‘z€‘eūÎÚÐ3ŸW' ÁšąĶšéÔyCyð―eKÖ―/Ôkî0€A…l…YkīîÖpŲēĪ4SÖ*øÐ•ë1aŲ jNé:Õģ1°ðë,ęrĐö? ÂãË Ƅũ č2rúŪ 5$@ĐïONũėÐkÉÆG0ų|oĸˆÐŽãö―@ųЇë{ššĄ1€nÝīnҞ‚{šS™l㖝ÛbĮL=!†tß6•Ĩ<_›ØýðóޏŊ ŌK[uïŌ- gŊĮđ*T]zaS4{ÔkôŽŧ •l>Čļs`Įū;ÖÍęÔūëæSïHyņ‘Û—Ūmß8#bĘũJq܁U†LūôЄM2ōŠėėÂRūz°gëŽ];WMëÜŪïä˟JØÄ"Î}ŋ$,8 [ŸÍ?ĒØ„ áĖęŲ­ëˆĄëģJ”õ"nģōsaĶb9ïũîØqxĸÚNÚÏYsAJÔ>á#äûg7Ž;?oôÐõt̃ŦÓwoœŌĐCĀÖ3ï!‘•gæ—ąiŽ:ýMÔ vÔąGŊiáÚÝý Wgŋ7°o@ŨÎÃ7ž—’ÂZßģK·sĒfG.y“)EÉʋŧ—îØąhİ)y8Č|~.īw`ũß|Ŋā „Š’ŊÓF b%,ķĸüMrÚōoÛį/ßĩqzÏ ÎãwÜ|zyCïŪŲ_A"|{xd]ßĀĀ ĐkSŠIJ=?žjßÉSÓÆ†īïũM.K―·óڍ“s'.ÝtJBÔiå°Y•֯ߨŌ―Sĸ!Qé•j6/+ ?M‰ЭûŪ; @™ūsÓéŌÄŧ“Ē6dTęōĉXĨ‡ĄĢwÉ1>­šuvįރB‡ßöŠT‘ûz~HāqI ;V.Õþ'á`(œäÍZšåėĄųøĮ―ũß”å――69bYû‹Ú12ĖŊ<á|čėƒ‚W;ļg^GáëK36<[~ð„NÄ`Í)%@dų‰gN_ö‰^―(Äs}DT>ęÔ%Ļ[P·þ æ2Ã0$IÛ7íÜÁÛ-|ėčIM`’‘æf=ø(›ģt‘ðÅĄó RIâÅéÛL=tfķ{FÔēã:yý*O`íÚÃËĐwÄäĐs&ŦNOÛúpúĄ3ģÜūG-;‰ÁüŌOw6―iØgN`S‡Âũ·ķĮîï>tnXszƈĄLQ“úŧÞ=~ RŦ:ŋiV5äÜåã}ýlęö@ūŋ}þ’‹ ķïßŋ}K3GôĖĒ™ÛÎČķ<1§-=dÎį*BUöqûÆÍ_„AKF;Ÿ]{ —6ïęåÞĄ{ßiKĒ iSßāsW/N0Ė?u>N Õ)Oî|Ig īôÛË―ŧŽ7 i™{üĘcJ[đXÚiü‰“ŊoÛð0Đ<ýŅĐĨû §l<9Ė[RT Ģð'ÁDé‹ļ—eU4DTžŲŧéč7ãĩËGŋ;qôņįRHoF2Ļ·‡—o#·ˆ™KFuũEðĮŸŊĪö^<ēņĐĩ‡ ļ2™ #‹Įw7Ž? ĩ>pōÔčޝázŲš"`‹+wŸÚū@{u_|!VøöȔÏįė<ÕÛų֕+ŸóĪ(Būŧžũp:,2Z”ûlrĖؐŧVôu_ŋlwZaÞÆČ‚öӎm‰|ī|ÁÃLĩČï?ð•lķtÁ„ũ+&Ū{ÆD/œ[ņ設IþŦĢó}ÞxæėPãøĻ5—TûéōƟÎķ5ĒiÉÖ՗…ž­{{9ô0{ė°^!Só‚^Qšy;L_ĩąxšjĮ‰ĘęâĩsužudãŒļ%ŅJˆwąuí:wüðFdÁšY“hßāc'5o/Ųt\øđŊŊlÛõ:b|Ė8?Íô‹ųƒĒ­ ?―~íˌjäïžķEÁß@Ķ–†ũïÉĖ-ʒČԘ4#û‹ŽmЌqÁ`BÐ[ËĶ;Ų\;3ؔ xž-!ŋ$cũŠ…ęôĪTC#5E( F@†Ęß.[~ļ0ģHÐĨVcŅ†Ø‚Œ ‡D۟7°W|æÉrš"ĸ[Áũtĩōø‚WüÂ4­ļĒō[všØ !ÝüEĀŠÝŲ·u"õŊžx“Z­E—° ›bÚ"ßvY_+ ÕH:˜Û{Û8:;{ųđØæĻą&ÃĢÆ Už.3ޗjuéÚ$ĩ č―čPĖĒĘ) ŧ:ÁM0b*ܑ*ÖæA!>ÜšíÓuōāv~ĪL4°Åa’†gl›Ž^ēth“oWâēóē.퍖g“úįĨžš$S(yĻúRPV\TAxÍÛ,Y8Įĩōą“ģoԒ˜~V%ėī˜XüåõUIĄ|õüųōBÖw‘ Āj>dɖYƒÚŌČĨé”isė,DFÆÖV(D1Ãõŧ!RÆŅÆTĪ ePКTŪ‡!ÕŽNŅÕ ah§i†ÏĀ&æv†VĶSĒįŲó ,18]ŧÉÆ \ĒĀŲv§–‘•Õ”čH [b(öž9e(‚f€_Ƈ‘1bíq‚Ätđ íąõl‡Ī#Ŧ'ÄDBŨnĮZÐ8Ͱūy†HUe1`Ķi Đęēr‰.R ŧĶų(ÂŒĨ‰ YWà`0ŠËqTĨߌ^”yl]\ō€Ŋ U7Rbĸ%(ŠGĄH'kÐuĀØá>ž•&^֏’ĐT*­H$0‚ü֝cfhĀcMh) F ÖĶnFhvNĘp€X˜ˆJ'Ą€jà pŌ7dÂĸÎwm™ĩx‡ÓđM-ŽP’Œķtįü EŪ1‘“ŽvĮŪ#Ą…ĩ89ŋĮąÜäo ”;Ę0 ĄˆPᆁØĖÎ#büė–ÎĶB#+k(—ojÞ/|ԐvŽËųNmÔåßuĢf ‚‚íƒDA€á›Ų™Ų{G.˜nŠ™Z i-DÃFÖ-A`āC€Ö`˜TICuģĮ@ĀЀ õ/ÍT†D€ĒC'nãĀvęâÜĻč Æ04ÅÑ€@Hķä•6 €ōD(Û ā˜B<ĮžC'·qYūĘĖÉÚĒhîÂ@ÃPęjIQöŨw/Š3óÞ<þÔļIŋUfôœ%{wí>}éđ_Č sŅ·‘SbîÛđũrRËámM’ŊÜ™žüõöŦ$ M› ĮÜrāDėō͈oßķÎæï\9w㕊Qģf†oe!Ýīõėã·~ý'ŧXå_ŧô<ĩ‰ĸĒÖ-ýTJ ôZZĨÏȁ+UkÃÕ W\?°îöĮlšņ ‡"€õĻ#īObĢ6ėÚģmýõŊę ―‚ÞžÝŧåðĐÅKÖ ,ƒŧđ[aZ•BĐĄõ™OĐÄĩ$cíå’qöėþ eZžĒš2įëŨ—Š{O?-PBSŦĨ QáØQcŧĶ}ûŋūsëKrʛįOģŦĩ-Û~}|}ášM1Ņž|*DýģÚ:Ô‚Ī†bgHЗ>ĶĄj š˜Ų{Øãw/yøš„f06BÝ9šR)qBßĐZKðyÄģģ§.=þŽ"yf‘þƙŅĸA-QŸóáÓį—Y—Ÿžõė?‘/ŋ5~æžčŲkË­\í-’ÔĻ˜>yv îí[}óöÝī”Ī{O?ŠMü&MoóúÞå/Ißß<QĶ@`g/%ĢŨP°ëzQ* Ú šh…ĶÞ}ø!-%þíŧ$BBU3EĄÐé:ĀÖöqë6Į}É Õū9@Šŋ'ėYķéÄņÛN]ë=°ŸŊ_û1“Zžž{åsōũøįņ™å Ē•*’íÉÔĐÕČæ§Ö/9qęĀšÃŧ‡tw3hÕĪFK˜:·éęþ䯭ĪÔÔŨOŸJÕôËWœ§Ā0ˆ+)•Œ•ëĻĐcøJēyŊžýÚ’2™4võkÚĒMxP[CYE•†ąņôoŅŽY€ŪŌŌÜjđÖĀÁ―_ãĖøRÆÐÍÚąm―(fĒ―ÏÆÝÓÖ(1‘3OūþKN3|ĸÖM(Y5jhëããÞØÉÝÛŨÓEĖí\}|žížķŌ–į‹ÕæÖ^þþŽ<ĶVbÆÞ§―Ĩ…BDÍ;öØRSž_"V[Øxųų؛[Ú{ú6q47`ljåęįįîdchhÚČĮÏÏĩą…@dęæÓÄÕݙ–įdgWļv›5ÆV„Ðu9ËÖŧCŨ^•Å…bėŨĒuŨāÞ\ÐŽėB#þŅ+Ķđ™@|kwßfŪķ–|Ą™‹_óĶūŽŽŪ-Ý ī*mįÐ m}MËÅxȈą=Ü  æž.ŪÞM]l--ŽíYý cĄĐŧOG;ûn݂žŒ‰Ž‚ĩôiâįÕĪe[7SŽZėÝ:lÜØ~M|œ-…€Ņ§BÄĀž―Ŧöķ755utfĨė…<>;C­Zz[ņklžA3?_JĄ<—Ö}Ý―ØN-x"sWßæMý›™ģ6sĩkD‰Ësō 0 Ũđs'ķ°7ŠYÐ!œ„ tY^ķ1wslŅ4āø;ŅĪâËŦøŒ‚J•K@ũ.Ö€f§ĀņWƒĄ(ČÆÅÛËŅęæŲ?ūĮĸßsģ@ĸšÝąŠ7þÜŨŊ/üŅĸ|5fÅĮO™8bP`Ģŋ`žåāR-·Á БRÖÝËŦą?øÔ‰Ą1Lû?ĩŸ&1 Nę‚ĐÛJÏPXʧOYUĒ?üM\VųņëwÆü‘ĪF`Z‚ĶÁ°üĩÝ΄ä/ŸŠĪ$j  ýķŽ[`(Bw3þŋųŸ%IÖ #ppЖãŊ‰ŦÄb Ąˆ2ïšØĮ b>þ—Â1°"wϚØ'‰küßFøöÍ^ó€á̘JĶPbš%ŪF|4zþÁũkĸīR&Qi„ÏSĨž]ļþĀ7%ô/EFs}OėÉļ|Ą€ũ/FĮú—T)0 úÕ°ų°dïÂȧY2*e ÏģÄ ýZÖ'i„/&^ž:ïD5Æ@€ƒãĸZŠåÐm{čÐouŨïsŨðy5ŦÅZ…ūŪRŊ0€Ķ>]ŧv§Š‡ĒFA―ûy[R4ĪߏÖ4„ônŲÚfÕï‰5°Ô72 mŽë…WsČŌ0!ĩÛ1ۈ-Ô,ĐíštÖ՗Ģ/Ũ­\þ4‡m `č,P!€x<ŪwHĢ8ĩč`Ķ…``D[Z̆°fÝՋ0 ĩ―7žÃ§!^Ŧ€~Ü,‚f jD X+ŠoRsˆ„ŠÝ+ū,Ð tYž_Fw°!`x0ôTwFëfAxˆ&gCôü§i•ŽĩĄsŦ‘};"lÄš)Šq‚Ô]–šJ녃Kĩ#ti‹ÝÞŋĒkŨŪÝš ŧýĄœVŽ_0ą[@@Čāõ_ $|„yy}ĸĶcW–Ž ëÐëØÓïUvfÝēWO ī!ĐP–QœYÉКâĪ“[V;ōSŨNGNûĐ įĄšĒ#v―Ζóųšļ]›]üJ“Äũnj*@Ŧ‹OnYsėðfÖxÔôŸŠ0D€P_ŊoėÕ­kXØÂ+Ũ?N,…QDŋŪ$âÎnŲt%A @ޜÚģā,!šŧsížüēēoj™šäËÎëWN-œ9weđ5€ĻŌŊŨF ę2û]ŽŠ&%Á0/ũýåí>81bëé'ÄFTýôĘú.;ÎY}NL lïODũ š ―B[—~DSų…ų˜Ķ$Ũw.?yjxhPïsÓ+J??ąĨo@``ÏūïJ•ņ'ķ?{9fÚė}—’PđmÞ„Ā€Ū]§ŪJ,Į!ā ]áiJ6F č6búĘ,ąōÓŦ[GΞ›7fčŠSï yų§Šæēäė†ĻŪŽ&ÃØČ‡Éb61ŋ―Ũ#;bgvęļõÜ{vT€ƒKĩ ]Ę8ōÓâmÏĶ­ÚķwŨâfņ―óĮ?,3Ýâh_ŨŊŅ3į—‘‚ĘÄû?-‹ĩî3.Ē‹ééÝ[Š!ëŽ}īuņ_š<ÜŲPōųY\a1Óâļ3Ûwŋ"—.Ÿ ~wþîëB’§ūQRNĀ0“œũâ]i>DV}vŋ°„€iÉ―3ÛöÄÓ˖Wū9ĸāCqö›ósg_[°kÉïį§Ï§Ë š•,Ĩą/^•“ŠŸũ-9wđļJóöŲÕ§bĪęŲý{éBk—î{ Ÿ4iús!Ī­ÎļyņYČīhėųŪíOʃô{!đĩėéã2+zpϖ|!ŊøíÃKŸáeKĮ~õþÎŪõŌÂgEŧ+Ÿžŧ–„k2cWk―xŨÅ;\Œî]úĩóp6aLp€#Ą&šÏžt~_‡ô›Įž|Hi. ƒ$™ķ×_<ŧŸNđtîŅGwŋFnç-Óģ Vþ.îö%Î,œąóžú§ƒĮĶ7“GŽü&Ĩ”%ï6ŊߐhØcÁpۓkį*)ppЖãï".KĘ?æ}k;sÞðžíýšĩr4?z!k>2ŠĐŧŨĻɓÍyŸē* ”4acôØA―{9óÝ―\mÍ-[īö2åÃŒB0LiĩÏö{ķ,ïÐÝËÝ\Ž”ęWĖ(ÕÜ0ŨūđŠĐĄīĄg‡―[–ũ bĨōŠÔŒïP·ūcīn7 lČČ J­‚ôy‰†øm:t2Æŋ=|õ8UÖÍÝ"þéóÏï2ƒ'… pŌ õYļų›Ø{ų5óõā’0õ˜°zËčþ―šûŧ*5EļÞ CӍŧų5önénoAkÕ&Øžī_· F"ŊÎ*Í.-M<šbá…Ger–Ð/äŦ@ī…ïōÍkGöïŲĖßYĶŠ§ýšÜ]ģhųĩ/ ŒÚzx8X˜ú6kîlc.DyŌô+Qëũū”ĻŋZ{24chi]wqåšMRBŦĨÍXYƒÆÎÎ>þ† PD€ĻŦâŠĐðuSÛû{†Ooeó-ąPFãtÓQ‡ëÜū‹Ą°ZŠĄ =€ƒKĩ`TÄTWJp 0 ĘãÓ$ƞŅHĨrj`ĀcXhhÅÖā$Ič—fA`"šƒ:đU`$ °gH]E"0Lã*qĩ Ö%:c  ø:cŨĢČ+K*ļ,ĸ{ZRĘÖXŌãāÓš‰-žfô‚æ1‹įũqÜ;?^ÞkH I=K•$ÐåtFóĖ ø€ÆŲaˆ:RĐÁ]ZŊ0Āg{'qš‚ŲÞa·uk3nVÔæ―'Z8Ō`4ęĻ)1"5dL$Aøæ3v:īftņ‰sŲÛy@Ŧqð9„ĒöOßy^;yâĪ@wS’ŨļωČŦk—îLĶĮMŅķąĩ ėyŽƒýčBduYĨ Ōų­Ä44ŸWŦÉÐ@ņĒB­e—j9þâ0 ›ô P}zĮĒ5ÛũnßóĄČhėxßø ž=ūvÛ~“ŽÝ[;iTĪRĄK‰kÕ†&Ķ–UEЇÞĐŌÐ8F$hRĨTúÝú˜W“4X6ÂeįŽlYģþČí/(AÂīĄVTģÆl+ˆaÜšCHkYZôôYóÎzœPÄãÁuR°ĨK‡”ŌĘ―ü›·r)ĘÎð5Ā$ÉĻ48۟“Í“ÛÎ?y‹1ĶVĻ1@€ĀpĨĶV/Š™ĒäØMō*†V*•úPĩ SŌHێC$ß―û.3=éÓũ4 ýã݁ÓAą–•B_ÐyVSeßv4KĒ5@†|>€„fž‡öÍ,ĶĪēĪô{Âįį…ĘũîÉĀΠ^LP+)F—#ŦŠËS’ūäJŦÞĮ?(ĨĖ<ðû—Žß{^Á°R…áÂFc‚š>?ąkĮņ3K–­7° íėj†iÕĩš īN“ˆ„‰—Oß&Ņ —ƒKĩi'=ú=}cģHŦĪPS#Óðč#ąsCĘóJ›†Ė8ļiĐ1Lu ‹šîE„c“óÏ1Ē û–}ŨmŒáKĘTžÆĢ§Íoï!âŲ44g‘ŧ1MðmFÅŽ imGōė&.YÔÄÜ­Õ kŨŪŽ lDŽq;w!ßķ9kėfL|;Öļ_s[3ïĀýoN<%jc?Sˆ ˆĐÉĩ8Áëĩ"ÔĮ —NSVLëDD§ņ[V-ęĪĐŪdCįĆø$Ōcü’EÓzčÅĶX€š_wxÚ0;ąXfčÜvÎäņ.†$!tˆ^ŋĒ—#3ĸîGnnlãˆUD<Ôj0ĀÂÞŅ;ŲŒÉ°đąí…‰öœļdBhS97ågWŽØī}xsœ0›―yK°§Qeĩ*pڞĩ :ĘņF[ķïél+UOZđŪ‹› AšN\ÛÚΞ_LėŠˆÖ ­áŠ-‡FīuÓ&‹cwũņĩŦ,•šx‡­" ™ž ֝X9+Í·l7įčÅX”ð ž9ī;B&^ýÖo‰vЎ­C#Gö4„8þócc.·1â 0ÐA‘8AAõŋFJâI3<„Ģ`”ÏGaLŦe X āCšEōy4 "äĢĶĨX ä3$Ž“4* õëCŠÔ’īP§ŒdAąPČ€ŪúúzóʝüÞ}öÆýŽž8åiŐSũƒ5‡p­–†66ÖÁķä ø­ÕÂðtŌ|€Ņ+ð„lĖ{ԁō(Ņ$AÐPmïfãĄkBå Qļ~ŸÎÔό@Ņ8;<P ûI3|ĄĶ -Îč"ŨCāZŠ5hŠ (Pëáói]Ė@(°SJC<~Íē]ŋęfkTģb†ŲyÅīxý ģÔDˆð…<ˆÖb8„ð<˜ ˆ­îr€ĸ{psđTËi ü {Ïh­"åó›/Ųe|#ÛÎÝ\ ëó,—jQð?ũÄ5ïÚŊU ŽWz"đ<ËÁņ'ĨZNđ†Ī(ĀÁÁņw|-ÆÁÁÁÁĨZ.ÕrppppЖƒƒƒƒKĩÜo p@„ øïÁÁÁAQÃ0\Šåøí<‹ãxqq1MÓā߅ƒƒ†aGGGEđTËņÛČåōôôôƍƒŽ‚‚ SSÓß]ØrЖûߨÃÃÃßßüŧpppðxžĄĖ―ã Iü ppp_ĒŋqŠåāāāā~Ų‹ƒƒĄðĸôŋqĨ9ļTËĄ—Ĩ&'§}OÏÎÎÉĖøž’œ’SP–xũæÏ…āQúîáÚĻų[+Sƒ?LQ]\.ųÝ/8C$<ūōðe[——KÕāχÁÏ_JŠÄþÓiOûņÁåOĐUĸ}Géîūøšþ)„īäĖÖ +–.đŸZ ~Eîģ{įŸ'ÓdöHŽĪ(}1›WL‚­Bœ“žÁ~t‹ĘŠÁoA)Ŧïœŧō]Ü RųöîĨ„t xYqĄ §đTûŋGAŌ‹Ý;vîŲ;uø€Å+·íÞąûüíWï.í>õ.üˆē˜9ģŌ([?7ú—™Aš”šĐųË"R#ËLûŪĀ]„NÎÝvYEĸn*~uëĀŅ›lŠĨnî^ĩj["øóaīâ[‡6},'ĀFýėÚþûïÄĸýTûþņÕËũ?ĸóÎ^^Ýšãf‚O3/s^ÝÕWĨĨĶK4$[Ėđ{č`Ü ü$™KĶ…Ž›5sH`čžÃō/ߒ/Ūl 7ký†ĨÝšũZqōþŊ?!”ŽčęÁ- âAŅŌû—<ų*ŠžŸ"g?>ĢDĨ%ÓÐXEĻØãjМf€ėküŠyŦ_äUipĘĄsØōIýE°ÞF+cmX#üGū†xÆæ pïņóæōz4JYEy…XĒÖÛ1ōƊJ‰’Ūígã"ĩŠĘŠ~0đ„u,WijŽIĩBwĻýÔ@Fކ†#W‰ÚZeEyy•Xũ•gH\Đ­OÄīRĨģĄĩ2Ö§§1Zvˆĩ1ā* 'teđīŠœ範&0-ĨoDā^SŠŧĐĨЌ§”Š+Ŧõ'”21{Ĩ°ZŊīZ.)ŊĻĻąw8†‘8&ې”íŠJĘŲxæā—ĻRve BŨŒTįÉZö84bb{ģÚ!W}[1{æÏņĐ Áģæ[™9;ŅS—ė4RvȚ_.! .ÎãEĖ]ģqå˜Ä#ÛßdHô3Ūb?^Rđķ>OJŦ**Ŧåĩ$NЌR!+ĩ ŽēŌžF-ÖŊÛēl Ïé㷋aúëɰEP Ã, MiR\U!VÖ á™Z 08L]ķĶ­Ŋfâ%Õl˜•2 ÉĨÚ? ‰­Đ𱅍[ķ27ášėÕЙsÆķí°éÄWÖŽâÝíĐû 8kåqéDžļ|!)éãķEãÞͧݛ=qPøā~'Dåj(žāÝīđŅËĢcôę3!šDĢ|pįæóWæŒ›zîyū8íî,qßÁĢs5 )ûūqÎØáÃ&.ØPĶf>―ŧvïŲËícGßJސĪŋ8ó ž†@qÚëqÃú2`܏EІ2ã€ÖeWũϞý ™p~GXĸ>ƒ‡†ÍŒ>§äģËÛÆ† ę? |ýÕOlč)W6Ė3wÎüé=:·šĩü*@þëk#ƒ† ÛxüšiEęĒ aCõŸķ"S‚ƒ_ÁB­8îØŠðð~]ÂÞĪģÁhOmŒ4lxŊ€þ{Ŋį`yũ{M‰I“é’Ô·Ŧ[ûŊšŠČųēl΀!CŽ›ĩ9KŽŪ‹?ŧkážOuáŦēf[|ï}Á—ģ;ũ2,ŽoĜ9e8ĀKũ.™ņ<@}~ïŌÏōĶ|>ŸyĸøČôლv:ņ<­*úrsˈáCö[ļý’’ī"kÍŽ)ÃÃt<ýQÛoÅÎ ãfŒ1,xmJžėýąBCF ™ęŌ[>_P”ðóāA!aƄôŸũ.§TUøöØá›ïŊÆÎ^wNÍÔFĸþų{ϞĮΙš?.ƒ/Ļūݙ=đgį6ŅîQČR^ĮĖ :`Bäö|™ķaAP;{WŨÆ^nĶĪĪ|į’ŅĄaaƒ†L›%4öüðŠ!aÁ}Fļ•Čööõį­Ģf.=,bÎé7 ÝXÛØ9;đuhIHÔâēŒ=ËfĮ‘€‘ÛąäܛĄU•ŸÚ5(īoũ°åEÃ@Då­ GŌ%$ĨŪÚŧrrï~!aƒG,ŋø…Kĩ2E렀%ū}— šĩëčŌŽ—ö_â…ó€ íî+đŧãFbĻ…ß-<žĨ—EëOčé*hÔbý‰g/]eÜ}™&E€6ņöÏrŧ ËũŊ;dß{”Ķ éÕËßđóŪSĮĮwwX·Øpâ9k,ø~;>SĐHŋ}ęzaėákŨö­ą1€Zķï30 éō‹W·ąSUf”ЁŠx_lŒĖ7æþã'Noje-ĸ-)I-Ę'ąē—ænk;qÛã§OíŽĮG­ļ<öøÏ—w;ŋnsķęž›Ï>û[~}ũØwįÏäāÔË#GŸˆ:œđýdåäĄ"€ßÜą4Į!ôîÃ;― ũÎŋŋF`™ĒŠ øï=}}„ŸøĘ­ũ ÁãŋzņđŨVųpÅūë*.-LŦŌ- ÉęâLI ęPX*Î˔ÎßsfӔ.OoßˋL^å3vs܅i[cŊ}Ûë?yoœðó6M3Eé Z·'ŽķW>™đöÎÂãânŪnn+ĒhԁU§.™ķīËô­OŸ= ÁVŽ:Ļuė2yÚā€ð5ÛĢÂDPmũí;uoïÞzņŽãóúÓ0™”RÚaÔš+[‡>9qķL#ßī(2ĨŅäGũoðR͌ûÚ lŠæo˜9Ļ[čR° ]= _\Úp,Õåė‡ŧ0Ž_ÍNŽ›―ų^ˁļ“ëzŸZŋĒ„dcVüÃīŲk›ęð…Ý]8eĘðõzÍÓĖ ÎËK­ÆYĸDUAĶīš\)SŊgoÆEõDŨl:*ÕÂĖ@j ē“ešōóšuWŧŊ<|ōøæš>œÂĸ*Áë5avhkŨŒB;_…“ēLJ+;đīĸļPnhĀã:„Æ–‘ą™……P€Vdįėˆ™Z`&ʕS €%7h9hŅÜÁ"ĖÓĖ ŒČŠ‘ĀÐĀÔ܂χ%åŲÛcĶšä(i’И49mčĻŅýÛu‹ØōÓ\‘đ‘ąĀÜԄ‚ŒPXR’‘þŪj˜~–Āþų- a„IÜ] ë,BČ„—ĸųģžž`ÛŽÉĮ.$H5ÕrāčYAūŠ/ކrĻotdčԕÃú ūô§đýē^Ë-üíēļTÜú­ĸ˜HžđûĪic}++‹RchvM}ėøÍ,T]Ą2ē˜86xüĨK)ÎL*ŌqW;ëŲ;ąžG_)ÉÃF™Ô;õé<Č;rûÉ}þƒĮ7:ĒÉŋĀ^í­:ôiũüC–â#ˆ‚ā̈ÁęĄqČ$|Ftk/g^ЧY>ĐQW•Ĩå~Ûóá€6›/BīZB-ŧēcÍĢ2ĻĒ@Ņ_ ŧp„‘éĀą- ē“J ·–Aūf`ÖđoÛg ÔA*ŠÓJŒ‚[ĩáÁhPŸūąũÎ3ff–BÆÔÄPę[ŠLŒLLų TTŧð‰:{‰ß:ˆ rL™EYũ†~9Y\Dĩ24õ0šķ<>Šģuá–-ą·úøŦquŲũWӆ$ÉŦKڏŽ’WdI 6MīūyB54đg;ÐÖūÍ ßĢW'<…#X?QĻC€$ lÜG†ũwē­ÚuÞu\ŽÄHPkˇąÏũ_7õ‹ėčlÆÖXˆļgĩĸp0 ˆBˆf 1 CBtXóÁģԌW›Yýr9LéWʟfDåöŒ>}`wK 67 ˜bhšÐđQŅ4@•Ŋe ņô˜ü> tÆfF(€`īҜ]/Ÿ]XT·ņâÓB˜Ä…úĮ/[;Ųû=MLÔGJģÝþVälá›6âUžĸXŪkHf^SïĻ§žūŠKKŲác† `€éF§eGĮ˜ąwÐĐ7ïOïŧrëû īąGŦæýf\đųāsâ͕Ó:S„"'õ‹\K7ėL’Ž’$ØL˜ĸõôęO\;>ŋ{7BQžûŽnZ~iüÄ;ý†27YâΧɗn=HĘø2opËúˆ!#ũÉÝZo7›―3>īĩ°ÂÏiR]…ĐI†|+JŦTÃڒOņI_#Ô1C$Ä5$AåYšÚŒŠÞ|ïŲ›ŽŽ7ílŪÄF\Mlĸóą]!^ĶâškË04Ķ›Y> )Ę33ä ĄĘ{þę3Ęãĸp,0·6QĻ+u-ē“Sĩĩ 'I†úåĢz"ĻBĨ,Á S7Ŧ*h„“Íg_đó(9ãóŒūūā4Mņ}Ûö éÍ(óÞeVØÅŧĸū ·Þųķe^Ļ`:ŪØwéųÛOoí°AŅ€â_BāXóŪ=gGÍïß؜QÅNCĘÜũïŌyÆ€ X-Ŋ(UēÆÅææÆ†Īᧅaøžšä―. ‰\Šý“á` ‚)˜Đ[ÕbAéŋË0†QļÐnÓēE™ĮĶ9jø°ð§Ųâ†ï8p Ņ+ŨZuōûprýœÅŦ%Ôé=ą‰>MÖþ&Œc Mōl›vuV,;îøųü=›ū?ÁŊ‘Pįo}üōōÔƒį,;ΰôoãi)rðĩá‘#Åka†ŌjĩˆĐÛä ŸíœŨwPXčϘÏEęų†áUSĀpœoðÓčÎG§ö6túžÃŒ{ÐâČ–ÛÆŒ5jĈˆõ…Ž!‰c8Ąk Álð12bøĻSwSpMúüáã_įk΁c$ÅčÓ‚QŒĐ­kc"-rėˆëŸŠ%ŸâŪ=ÍâY5éâ•ČũØŋ†‹–ÄZ~Ý7t;CÎ―J č5wZS!ŅĻįĪĶ–ĀĖ'da°䐐QÃCöĮ›Fjl`ÔČĘ|ÕĪÐA weH-ið‹Ũb4-"HJWĒHˆ$ ,=ÖlŸ~wۜˆQ̆Žšu7­šiû>Õ 'GÍ\ũVÁŋp`ËŨ2­þ?]vķk: ‰ņ°ā~áak^dĘ uØ6_ūjðÉa#Į ÜwsÎüņEIB @Ķ=Z˜î^0yˁ˜Ga8ÉčgÓ2*ūåŌeąüŨ›‡ąC:øŌûĖÍx;#žW‘ļ{øŪ-z„ÅBņ‡GDD Ûqųū}ŦakÛŽ?tÔψYKWWŅ… 0Œŋ„Ō]GŽ~:PS[KSƒ%ãú‡/?˜§hDÓ@EQÖú‰cGīúÂŦđóĮš‹`’’]ĸęŽõ°đýzģ€Á_ŠjŽŋJĨ211)##ĮqÍ?…M[%%% LCHMA^N•’`ôˆ Ōr+älA#.JN-ÄÅéŊïÞšũāq™cęĄ5iĐđr-ÉĩōŌgũï>‰ĸZ’—úōõÛ đô{Fąþ Yô=ĨJĐkU›wûabŠ”P•?­7ŽWRUôîé―[wî}IËaô”g<ˆŧ]Ļ ī’’Ė‚2’Ņ‘ûåÍ­›·â^|ŪV“L-TEQ~vą‚ ĨĒ(O_`Q$ŋrë֝·ŸētÁÓęď~ūqëÉÓo*šQ–fg–QlXŠĘ”Īl5MWeĶ<ū{ũÎý'E ̧*+éÞí›wî<Ę*’Rę‚yc;LRý4‰fĶTŦ)ķXžŸ•_*gå~{uũÞýŽĒüÏO_ĪįWģfėípbN1ÁÔ"-þwûÖ―{rËĨLˆügšûžĸVÅԀ‰ß<ūwóÖÝ/9’Ú†eđîÝ~žœST”S"Ö2 â(+Ė+ĐÖÅŽŠ.É/(Й”ī/ņwØŅ<Ž/’a ĄøüâŅ―į_ rŋˆ/SjŠŋ§ˆëfOQ•ĸðîÍĮÏÓJJŠ JĨĖ/ĀÞ>eg;þsJMgUĨEųĨ2æ—(K3݋{ĸĨRQž•U\ĐŽĒ<9)§Ķ‡ęÂÏq·oދ{_%o0`uFĘį—ÏŸ>}ņ&ŊŠvÂĩ’ öÃsûÎ―”Üb}o’/îßūu;þcÆÆYYø=ïÂĢ+‹ģjŪc=Õ%YũïÝ~•–WX”S&ÅR“•ôųý›ŨwîÜyó-]߈(ÉÏ+“°§Ôų™Đ-­ëš*ĸŅÝ[·î=NĖ—2ĸū|ųRQQĄÕj5ĸ‚ RSÓRRR yõˆý þbp‚ėė\‘HčââLQÔ?Q‹ÅėGĪyóæāĀĄgÛübÄÆÉ–0ø`^Ūŋ>ÅáōųĶ0øÁņõëWVDŅÄÄäŸ+{Ą(š™™ÅÚ899â8Á―ûm88„žģ6{‚?Ķģ–žį™py–ƒKĩđ…5ø?ũZŒC^Éj ĻA*qeyĩ‚6DiAūDMŋ9šęü—îÝ―ũ Ĩ°pppЖãũxą=zÍ­o Ž—gķï=ĸøÏNēŒŧ}zôÝýü(ËNI/úŊ%J5ŧ_"Ŧ įËýCĮŪ=ļvdxИ/JÁoÂÁÁĨZ\]ŠÂPG›ãÆčˆ4ĶĻŪŠŠ’Č ZŸ_dUUÕrĶæE4 pMĩX‚SuŪ4ōŠĘ*đŦąapÛZĐ&ĀŊxyå@RVęÝû—Kī †WWId \‹SīŪœĪ)RS%•ëÜ3ĪīŠŠn'ŧ\%f+jctÆė?˜nĮ=ÉvNI*+ĒÎ3ÁŽBĶŪmKâŽZŦĻËÕ5z§wÄŧõZ,Ó0u īj IÕQ˜ĶF.@&ĐŪ–Ö ŸJxyeۑ˅bĨs‡ŽÞ}øPûoâÁoÂÁÁĨZˆ `ԑþōįÛOhJ3ÞMØ't`ðĻĻũEŌÔë;GŒ í9ø§3ŊqrŸ5wŲĘđ3ƒšķš°öˆœ’īŸgÆîš_vė! €ķ5xĮÂ- rëĄÓĶ ?{>ŌŲĒeÉ æĖð˜ģuęP?ĀÁÁýĮïAPÃ2‚ĀĘĘĖÔ7eĢ†42 ”•I3TŨVŧĮ( ‘3B ĻžƒgÎ ëÄ(’ÜB í†nėņ|ƈÞiģŨĖ‹hQŽUū;74ô~uIYH{Sļ,˃—O’ŋ!vîýŊyóænîúqå9EÕÖ=|ėŒy U3;˜a­0hŲîœî–|ĸþĐī°dþ°`\ŽšøĪ$“Ōj. >*0Âķî?gFw[*ÓÔšįėđ3]Ž46ÆYšWŠ(z;#l€"'›iÖ 'ĻŽĘ‰Ã'Górˆ ES3CCP‡ŨÐŅũ\ž~ĸmÕ×=ÂŨ›…ŠĒÔÝ1ã„ĘJÚ &™ąĄ!bij„°ĸðšį›ŲĢ„€ƒƒKĩŋ DCHC=šbDæüŒ_$%Œ ę šø<‹qKOLîeϐ@AkDërA* ąęšĸNfÖĢĩýG/ęÕįŪy·sfÏėF†N# ŽŠīįw>/\·ą™―ĻПk~ōÂS2‚m, % ™Ååpų‡ëđ‹`„ F>ėäÝÂØÎyûÉÝÍíLq 0ĨVä;yӚ)í„l°(ŸĖ$ÃĢĩŽ{’ĄagKFģ!Ēf–ÆvÞíöÜãmkˆkHĄÎ/€\9I# `Ņjq„nCxnS&w0q˜Yۀ3}ŧ^·pņŠŲttHÛÆĪyŸUĨ†€ËÞCwX›îĮïuÜöyƒ °dĸĶ ’€E“.ŽßÓopø€‘1é‚Ū;§ũ;ŧpðØqc§FÎĸŪ<ØŦIO ã8*€ūœ‹24bÕî{~݃ėLÍÃ'.qÎ:5rä˜Q#‡Ÿ|ō™5Ŋ\—ÛŒ‰ÚŧWÏ>!×Et9ĸÓ1‡!SÆúUEN{ð‘ë0$°Z ĸÐų”sÂFŒ3bÞâģr—­KĢ“N5fėČQ#^á(,Äĩ€ŪŅdĀ!JWb`LĢV1-§iR1Šcäˆë/á ôī^  u§Ķ·Ūž·ę”ü Í€iîYPŨ°ÖB›6Ą‹"6EŽ;ftØüÉbÂͧiöû‹#F­)!4ųųýĐ 88ļU-ĮïyôrpđJ—s S{/+Ï6ī@ÓŪũ.š$æ•óL<ėY.ßäØ7>ĢPebeį"‚ Ļ“ÍlsžĐï†Ó'™@tĸéģė yûV(>v^?ûæC.Ąū-ÜášÄÞ}Ėēvãø –ū‹·:“Z:LYž+0ŋT+Ēŋ>4@ Ä1ðôžķķFšv<—uÛžyóĐRCŲ:4ā7rÍŌ%ĻČĻ™ÂGšŸÞÓÞZČÚš=ĩÞÉZĀ6Š9rNØØ2,úét‡øũ*1tôEđfadÚ6―~i ģ30qéiŋ>Ԗũ ų)ŌĄąsþAšPQãŅ ũ{u}[*ÅDV.ŽÆyþĪøŋ§ĀÁaá·uφ‚âjžÉŒ&ÞÎøÏãÚýĸągĮ6Ã@EO(NĨQP2D&`bĨŽ“*r@ļč=y}ũĮmÜQgņ‡îtđūNüŒņxŽÅĪ`7Ī@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ€.þÛķÕZĢļDRû }ß/Ë2Ïs| XŨĩ”"ĩÃ0LÓÍĀ`›™RÛĀÛ°ZĪķ €ÔH-Āģ―ûŠĘû~ÎđwJÚĪLz BMŒ‘*š‹WÄšę⚎ĘÚŨ‚Áĩ ËbYuwE–"ˆ”@ HŌ{o“i·œsþ7™…müŋ ïðũyt<9ó›9ũ>>Ïũ9sæÞ3āĮvĀ}PÞ`V .BÆØn··ķķ644īīīØl6Wĸĸiô_üYŒ€Ļ―ŠĀdV–åōōōžžžĒĒĒ3gΜ:uęøņãÅÅŒ$]*҈N'b|…’_äYŽĩˆN0Ē øœu8ZČjóŲääänļaúôéSĶLIIIŅr677W›Þö›ķXĪÆÏ?ßŨaW]%DuĒH0þ{[§ĩĩ2ŌÛ‰Ö)ˆ――}Z§ØW@°†`Ē5ÎMVąĻ7Š–SkūĖvPQ'ūųĩÐũnŊQlmß<óf“­ņ›ï‹ þm,ŨKīÞ^Bï+þņrÜ{ÐĸËD-DmII‰^ŊOOO ÁĩnāïïŊÝģëååĨÍmû[īÅDÔĶÞÍíī2Œ4īą4/ûØņVŦŠ…ķڒ}ßįīØļ@­'Ž<’WÃDR“Ÿw4ïŒ"rOûŲâÂėýy+?š{õēÕgÛ%ĒĄķũŸþģ―…V§―ķšĶ ũÐéēA­­åûëēŦ―qÉbJsOŦüLnnéëHŦđ;/'ŧļÎ* Ž―ĄĐļ ũdq[Wãá낯.IÄJņ‰Cđō D-øßYĒíęęęččHHHE‘ĸ+ŒąÖßÓÓÓÜÜÜÁĀ!―ĸšB›ŦĨyŧ>xgÅg ëËO>ģôŲw?üĒš―ëāW[ž[öÆ_VœØŧyÍę5ŦŨmúĶķöð†ÅŊnø`ÍĘå_æT—ÛšuG^q Ejm>―įŦ/tr·’=>ųýË/žöQYSýëŦ6ž·þÍ[óœ ŧFÝ=ˆģųĀКĘSGŸ^úĖúŋŽmmÛ·įË5kŨŊ[ĸj…Óņþ“­ĸðí'ŸyãÄĐĶŊW<ąęƒ}5Í=%;_zsãÛŊ=Sß#\Ū8AÚÚÚ|||<==EAĸÁh4jÓÛšššððð~ũZäȅQ§ę68ŅŋŲ+nl \°õ­›QSÎŊŽyüÝ?O‰E[_|pó™0ÜÜØÔÆģXķxdãøĨGnŧ1sņ‚Āđ“ãÓiŒ—1cðŌbäĢŅŨMZĩxÂWÛĸ–xŨæ―ݟVÚÚĪPdÐ!ŒĪ›åāĄÜΐŧĸúÆÔqōá-ë}Bn4Ŧ֖n‡Ã}ØS+Íþt{[SG ąŧ†ŧÓ}›ßęÆĶy·6v:Ä(oÎ)ãQ ŪčęÕjuww§”jQŦýųŸYŽĨ°6Ŧíwđ–1ŧ*3­AÄîōïV}ZúðäØãõŌāX?ĨáPvn`ļŸ)< āЎoŊ‹0DĨ‡X2ģĶĮÆ• ÖǜÃM QÁ^:ĨęLQY“%ÁŨČ·u7æ*ŒŪxx‰ĖÎ(óðŽ>$5+:ŲMė[Ïā\‘$ÆļĘPp@€ī/ûPŪļŸgTĘøn]ōŒ1ņÃ|Ø_yĻĄHĄzQ—ðӟfýaÓ_wėŸĻ‹NMŋ9qépöwaņņÁœ1tEQ k’$9NUU/8í՞ÕŅqÆÄ€9 FšÜ gÔ;dätóރíĪ]Mļcú]ĨÜðFæĒ5wÝ6sųĘÏ·”ÝõÄà 5ŦūÝĩĮ254Ŧ'wlī§,øųÍC‡HŲ‘ųųĩņ“‡P•ĪÜ4îƒïgŸ4)Ƀčžb‡ ũôƒĨ›?ûĪcŽß˜ ĒwOHc2šŊ.fĶĪw·ū―ų―ĩ―ēpÞŽå+ĸķ§ūÅ?éŽëĶÄ X=|ˆ›Y<đgKŪ%ööq“3%ŸyiÓÖMÕæáC ósƒsBTØŒZ jcĖÛÛŧšššRŠ1ūāŨ_Ú‚VyĄĪUUcÄSŋˆ‘%‰q†―cŧá=Ũ3ēŽÄ=žrūÖRe…G―ĩé­W‘åa+ßD} ·~øĨgg ņfT–UôÐ kz å%Nŋoí Ūõƅa§ÂŌÓCUân~dÂ- Ķ:e•s$―'͟ŦJ꾉XR؂_ŪZ€§ēÂ"ÞÚ8­w,I2žėTĮŽOãœ%%­ŸƒÓ ÔĀeŊþN+PeiäĢOsŠJŠ‚Āp{{;ŒÁ`(/Ŋts3FGGQJ/9ĨĩZ­ûũïŨūþ þ·‰­(ŠÚĸâ“'OĶĨĨOÛ˅Р%ĒŽ`ôã€(ŠĨĨeœóČČpYV~\ģZ˜ÕjKą111ĨĨĨFĢŅŨŨWëq]{@ąŲlÚí ‘‘‘fģųēï ND=A~$Q i§ŠŠvC@@€vĨūZČ644455iÆĮĮ_™Í8úņŪŦ‚ $&&Ž=š1Ķ-ėÞ―ûĉ’$%%% 6ėōü>fĩcŽ­Õ†„„ ÂÏAˆZpY@Špõ/ €Ļ#Q$z―`0ÚĢֆ a€Ļ—!ļ§G>˜]ŋ鏧Öū}|ãŠöïŊmkģ F—€ĸsûpŽ―  SŧČÁ`,hOŧjŪ jFčĖ™ķ/þrķžÅ9<,ãĶa1)5ÝĘWߔī\ôŠ,ŒđŌŲiĄŒĸsī5”t9UŒ~(Ũ&ģý—° Ó‹øïĐŨ‰ĄMĩÎ G)&ÝMgš­ÎöÖN›]đRq D-RYŲđįp]PbxęĪ„ĀƒŧG@˜yĖ„ø!ãâöå6””īi5肈NtTžøÂ—ÅS:―QŊ7yýíSÍAÐû|Ū\ Æ^‘ „õŪķ^‡$KS]đ,\oBÄŋ?ƒÏ· šóõ"ÁŪN}ŅEkŊ-nĨZA_vÓîšN^ýöË=Å=ƒ6fo·ëÝ0r Ī+ĸöõå §ŽÕ7[ύŦĮŸ?r­Æ5„NÐþÎŋ\К{›Ē\ÁØf“ũŽ ÜeW-nq2íąË͚‚|Òí=TÛÞn'ũó‹4Ž‚ēŒī&ÁtŨæWæß}Ũ†JĶwwo+Û·ðÖûį/ú]i‡*,ęuŨĸîЙw,úð@ĩ^gýüõįfÎ|hóŪĒō#™wãŽUŋĨH ‚XŸũ՜ŧýęųėD_—ýųÂ3ûánĪX7―štæĖEŲU–ōƒŸßų“›7í-冷WŋōÐí7.~nSkÝÉgÏūï7/ķ9zŨšKũnšóÆo~qÜÏÃđ{Óģóï$ŧFrÖúÍė9ËÞÝfeBïq.ęƒ ĒĀ#ąTï~øŽ™ ŸûÄfm[ųÄģ-?ۃ*ö~ĩî•'gÞqßŪ3rÓąĨw?öæÆ=vQ_ķûĢ;gÏ{o{!"Ē\„ ’úšN L!ænŧbWÐņ‚Ē}|8ũļMAÝvŲ3ĀWŌJJšôĸŲŋ/‡ąÐÓptõ§Ōģ+ž™äį­o?ûŅķ]é‹™;Jxų…ÏđÞ ĄótNĐÕĸéĩŸí(:öųĮ]ÃßY{ũŊŌf›wû7fĨę0cŒûF$?2'’ŠãE…›^üà ŋ}å—sFïßþŲ–ĢšŨÞy!֑ũÉæßš2ûÔ;ÔI];ũ9þäSÞíÕóÉ-?›:įöųf7ĶR64iôOî―er’lŦō91+)þÓģ?[ö’ύSóvåî;R/ŠõâĒĀÎäT7–Wž~e؂+ÎĘŲņį“݃fh}iwYûŅrØý“Į•î>vōø‡{tþ™iÅöÓïŊúhŌ]?}gwsL`å@Ԃ‹ ·ķu!ww™'ÅeU5˖>ųþ›Ŋ=ũԒÓÅ%N*8)LĶÚÚÖ~Ģ–#ÄP/ŒĩēGtBĐðP";Úŧœņ)ÉÇŠ-Õ2BQY ™”™™œ”!t4”ĒbbũUZ* öōÆ‹‚óëĸZPZАŽŲëÞiã‡û{ũX{ÜCFĮĮ„{aĐâdus+sïOLŠ}ðMĐi#ӆ†xËvÉėo Ī#ˆsdts3… ņÕcŸ”ŒÔņ#G Šóķ”5ķæ69fß:nDĒŊŠēœT§CŠT2ŌF‡Ë=u ­ĒŨˆ‡GXÅļŽ‰’’‡øúHÃĶŪxÐŦøÅvTķtœmj=ÓaXø@ŠÉ(Ļ EýĒ`Ld§Ô&“ZŪą’Sg+;:ڐ ÚŧŧŠJĘkzpMj•‰ÝfÓjû‰Z‚"ZƒųDĐ||Ë= ū:ØiN™6,aՒÛŊý"óî[ÝĐĘúÆS)ÓpŠ OXÞ[ģoŸOG§IˆŦ-:šî;d. k,ų67ŋđ"ŋôd-š™åģäĶ›~öú_ÆĶ›ë7,üųM_7,ļojySAYn'Ō{m}íî{ïûôTWęÄŽŽæw^ząÉAæ‚{€ēó―u_ä`‘PΘĘTdþŲCw•ä–4t؜Ôõ%˜öĻÓÜđ!0dâ͙+~vĮ܅ï˜GΉ3XJN6Û$‚‘JeąŠā“ÎŅ%ø%.šcēģčxi›ĖZ>ŧémv)p·ļ0Î𧗞:­’ĘE I3v\ęŲÓE‘ƒ%ŽJSW’í?_ãŊCāTQ܇n~/ÆËCĮ―bWŽßÐÐ.ųxø˜―tS†›J‰GTdĻŽĻHE‰3nJDæ?‰wóōXņô ĩöÐðHowýĒ'Þī07ĖI6>ôęûu͊ŧ›h4ųxMY•TWGÝýĢ‚|ŨžĩŪĩÃęcJ9ĄIg u—Î ɜwÏŽ ģ·9,Ð-ðŧœĨ*enQËßxŲĄ3ųxˆ 4({xĪ/Mžæĩõcoâs%~öãƒE7öčODƒAŸžôÝQõNâáĸōęå]=ŠoˆŊĮ―ũs^Ā|VĮÔūäWÉfĸ _˜_ŊHŽkFžþnūšÅ·Ä™žĘ8öŦ…ýjĸ“( U• |]|ÝDO“‡(/n­Ŋ8gMŠĘívgíÁ―?Ɉ=zĻŌÏĮäÞScŨÚrޛ;ØõecėßJ]ĸÅ}ļĶŊíŠ~W•!Þ đޑ3­æ\ÓÕÉ1AÖúĢĨΑÃcô‚Ŧ@ƒØđČÄ ū7ü—1{_Ų[üχ„\ĮåqÆþeŽ3BäÜĢĐp qØŊöŒZˆZW0ýéŦ}ÕÔ+þúTƒ^Ô::$Ј3ĪPV’“āhū}Þ―^?݈U…rŪYĩ]åįH„I㓞mU9°ģÓŨy›'TKÝÉ\c{eÖÄ$ƒÁ8@'mœ)ģūc, ÐA'V>pœEܚ5 s‘Ũ›<ąĒöūä|ýųbWÐĸGÏųÆÅýŒZïÓ߇VBĆÂÝ[Íß&)Â[QhęÔđLU(į•ŧßX―*ŊF IĸÔóŋM r§Œ#‚DÆAŒ‰’6!"!>Ft­g~õŦ_Ũķ}Ō_[·,%ÚŦņlöó-;ŅađöÝĩ„!&čԎüåOþÎkæãß4\čŋ‰ZM?e˜(ΚŠSŽ ‘™Đ)Þî„!Ã`Ÿ­ž―æôÞýĮlŠŠũ‰ČČí‡rvínbĒÚVß,yĪfMîë,Ž(­ęŪüīŧnbfJÕĐÂ`Ï0\ôû3=~F{Iyƒ)2yú”ëÜ­åÛ[‘6-+ÐĻÛđݝ‘ïs6ĸÐáU2r=arR”ïEŌ–rmF-€õéïI›Íæ0(ĖĪ82E”Q„ģâŨ>#N~äOk'ū―táĒ_oøöýĮžDĶÕ#ƈ ėŲōá―W&,Ÿ6Zĸ7Ŧb"Øs·ÎüÓÖ;ŽļQmō}?~qØ=đ“bÓĘWą:Į2ëýŽDYęwũ‡\TËÏéįYŠČēh ›žĻŠŠQ,GÓwß}Ï"Ŋ›–·wÛķ]đ‹æķZ;ËPzVĶĐ0;Ŋ°*yF|°ŸđÝ+tüõI>FĐŪĩÍCfþŽžšģĮ•Äë23üö*Ļh3œ[:ŧ%ÞŦģĩÛĀ ųß唌œ6Į­úÐÁïDÝ5Ûó‹ü5ĩĀŽV–eI’Ð…ĘUUrJ QQųøĨ•tÔmģËjė!+~:ÝßðН7þíþeö$L1™L)ó5‡ĨŽŊÝš}óŨ9KnÞöéš§Ûękmåķ֚ÖėӏŋrWBˆ§UöC\â‚åģĨũxÆÜīeÓ#fėtJ õĩ—üÖČ5Iïg#DåJo̘rŽîhinïrŸ6;ÎÛŨ”Q}ĻžÅ™Ēp=:#uXl~U~­Ē2Ēũt3õ>Af_Ī4p„8Ĩ*“=üß0ņzoܔwŽL–e*"„Eí9ÆÁˆ`Z]Z-Y­%Göc§…ŠnÝóÐ1†.ėšýG j/2Ŧåˆzúu6ÔþéûüĨsGB㉜ŋņ†!:ŧĨąąCHjnĻíŅéõ„Q†fJiōΉũ-HŦÞöÉÆŊŋ Ŧ*=Ōēâ…{6=Y0Ōë=ÜEKUm2"Q•í +LqËžeAŨÁŋߔķėÁyzæ ãĸéÂEį†ânōn>|ķ.qP\ˆAÔi·sAŊ#ÎŪgΟ§Õn—ąNG8Cˆ\VĘæˆ3Ķ5d§“r$pþQļ›ĀU•ŠqÔ[FUÕfąQ?GC“UöáØÓËM0˜’RÓC= a7R~9ïp#p•㜠ūaÝc雖=öËįVŊ}míÎÂ:ĪÓ{†Ž˜1ÕžaíŠß­Yūt]NÂÏoņwÍđ,IÛĸð΋úK•uîä1ū:Þ^–ŋõÏ[*Jrũėk&q<2vËę%OŊ\―ęõ·ÏķĘŠÃaqįŦÏ/.xĸËŨ"a€ŅB‘.lÐĻ‘Aöm_o;sôhÎÁ_ĸ­™‡Ä™ŽdĖÉþþŧĒæ€øQþ:D…ŅÞXgŠŠĻ”sėmöīU?\Xb§Z§Â{ϕ)ēʑ†ũÖ3&zļ!ųØūo·ï<ÔÚce* ŠK 6“܃ĮĘĘÏ[9Â?ķ+øÔ&g>ôvÔ°ŲE=vīāĐUЙI2w{ėéWwîŠjē,|zÍԌĢũF{?þėëU5M’Ę_ž}_ÚØ$֍Ėß·ŦÆg>Ÿ[tžž1<ëoxĮm/oč0˜ĢžÜ&?°jīŸwDė/ßû8Ĩ°ÁAđë°ú=Úĸf3ÎĻ–†ã§ß]SÓfącbšîïkž~ŠđšĶË*ĨŽŸŽĻtÄļLænĶ HI3qwĶŠ!‰ãĶyÛŌRw|æ$vs9ɓ‹ˆ1WĀ AYYSęZŧÜýGŒe öôTîS§ÍŽĻŠģIÔäoÄŪ@\ œT•$Mž3bįĻ’ĪP|gÏ[ uaN%YfįŠUdH˘š!„UI’SäÍw.ÂSUM5N–$ĘÉäY·eõF3—$'5™PŲi—#FL49N~Y’ĻĸīŒĶ؄ĪÆ1&#ŠŠHôœÔ{:˜S•2FÃǧZË;8Ėq­ë―b‡j5ŒQî­Õqc`ī7RUĘą1":šQ•1ä6ČþũëŋĢŅÃ7!ÉĖ9rÅŅĨÁđŨ7æ=z4##CŊŨŦЊ.WpaNWÓGÛīĄŋsívŧķ%ëƊŦëã!D’ĪĶĶĶČČH˜Õ^;ВËÛÛûôéÓąąąžžž<‰(Ĩ QQQŒą ÆąŅhėęęęėė4™L‚ \]QŦålkkŦŧŧ;ĖjŊ5j­Vkyyy{{ŧĒ( ŊĩsŦ‡‡‡ķe—6éŧHŒjgäÚt†s~é3Hg'‚v‚ūūūĒ(^kQ  ”j9{Uėî*‚C„KžŅųiïU·† Yí5 ĀôöjýÁÐ`ĀĸŒ#ˆZ€ĻˆZĩQ €ÔŨŨBЀū˜=tčÅbī€+‘ģZĀj1‹–,Yōîŧïæįį·ĩĩĩļLīPÕĒU X-fĸ@Íðš ŦxØIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-overview.png0100777000000000000000000007520313761647206020260 0ustar00‰PNG  IHDRûi‹ŨtEXtSoftwareAdobe ImageReadyqÉe<$iTXtXML:com.adobe.xmp \[!ðvõIDATxÚėÝXWĸöqzDĀÞ **bĮ{7ą—Ļ1Æ5ÆXc‹-šä‰-&jŠ―DĢF%öÞ{AP:žŋpžĸžû,ˆ€ÔÝïįōÂŲŲŲ™3ģgÎđgvvĮ466ÖĀ ™ą ‰€Ä@â ņxH<$ ņxH<$‰€Ä@â$‰ĀXOllėĩkŨvÆđ~ýz æ”#Ž ČÃĻĻĻĄC‡4(222- öäɓtÞJ[·n3fŒ>|øp·nÝĻŽ ˜ÏîÝŧ·oß~îÜđčččø„††öëŨ/{öėĶĶĶ...‹/–‘‡ōōō233ģ°°ĻPĄÂŪ]ŧĪk(_ūžzÉóįÏ{öė9}úô4*sHHH@@@:oĻ3füôÓOjXä!•'“&y{ *TĶL™&qJ—.íęęšbŊäfĶ 82 ïÝŧ7wîÜüņæÍ›iQæãĮwîÜųÝįóōå˘˜˜$N,éMvo5,‘îÕŦWTVIð<<<Š)ŌĻQĢæÍ›K‚ɝ;·täzđgʔ)‹-’CÐÚĩkįɓG^"jŦV­$!ÉkkÖŽéææfii)]ƒŒW/ŲŋĸēeËÆŸF%ĸã?&Ožüîó LÖAxxxļ–yHJ"‹ô\ØįŸ>kÖ, SŦV-ÏŊ_ŋþá‡Jš;vlĘf+ĩ|„ ēoļŧŧgæm=iŌ$)§Pí@YžxqïÞ―e @ 6īģģ“#Į™cƌđpáÂęÕŦĩ)·lŲ"ŋýöÛĄC‡Š1ĸý·äggį+WŪČ UÄŅđD(™ļdɒ™|#Œ1âįŸĶ2NâŲŧwŊŠ;’ˆĮgjj*Ã111_}õ•Œ‘ ÞĒE‹ *č―*44ôéÓ§...ošģ™™™ĖäMÏ>zô(22ē`Á‚æææņŸõũũõęUÞžymllŌz œ>}š š‡8Pšté"ŅĮÚÚZ_ĩjUũîÝŨŽYÓēeKí3ýāā`ų[Ū\9íåęzƒRĨJĐļ_öėŲgϞāSrüøņcÞ!þģąąąōlTTTþüų-,ŌķĢ”e:uŠĘŌïS­üQþÖŽYSŠ;*ŽLš4ÉÓÓSĒÏ?ü  ‘ 6nÜøÉ'ŸäȑÃÕÕ5gΜuëÖýįŸœs`` iubP=ŽWŊžÄĸ%JČqCŅĒEsåĘĩpáBÝWíŲģGöœÜđsËüe)rĄv§·jÚī郚víęîî.Ŋ•ŋ‹-ŌžõóóëŲģgņâÅeŅēÜÆ;vėüųóÕŠU;|øpíÚĩee›7oŪ&–1;w.[ķŽ”ĪL™2j―UDD„ý”.]ZösyáōåËĩ§öíÛ·`Á‚mÛķ•/_ūpá:uNJČī~ýõŨ°°09æüå—_īļ#𯑁yóæ™Ä}āíí- Ŋ 7hÐ@Zø^―z9rذa2FÚXÕÜŋ_oþûũï—ņŌŦ‡ŌËÃÁƒKw/_ūBqäŲ;węūjéŌĨEŠ‘ūCþĘÁķtI ^WĪGziüåČķI“&Ō8+VLŽáĨŌ&ļvíš8éä)é;:tč – ĪņŋzõŠgĩFbýúõŌS”‰ãååĩuëÖĪlÏgϞõéÓ§dɒŌI§#=‚ö”t ōð§Ÿ~’g%äM˜0sēüýýëŨŊ/ųIÍ6r0$ûáŲģgmmm}}}[ĩj%R$“ļkš7lØ s“ •'OÚS™™4ėō·uëÖņOŌHãžråĘS§N…„„<þ\úé‹/ūzõJÚ[IHĩjՒ6PŌ€īąŌÖÉĻžÄÞÞ>) •ĢDi*Ĩ―͟?ŋž\bGŧví|||œœœLþïS6)Oŋ~ýēeËķzõęŊūú*44TÚüÄg+ĘĶM›nÝš%íŋ‡‡‡ XŌҜ|ļÞļqãÐĄCĩHzSÃr@ ŧšZ/EöĐÐÚŦd3J͎€LŊD‰ŌðJˆĸ”DՒßļqCkBՙlmõu-ÝöYÕ)|xîÜ95ÏĐS§Š1rĻ)ąFS‘‡r˜-)DĘa°šāæÍ›ŌõHŧŋR­ĄV]Öm)ƒ–B}ÛFæœāFj%|“þöÛoZ9kÖ,5,ōP Ëf”ļĢû*‰>~øĄö*WWWYAcŪoéôЖv1đ••UügÕÉLíâsĨråĘę|ŒÜjwŅÔÎĪ/tĀ€ęã3IŧēKĻHdũĐC‡ɀ··ũý8Ϟ=Sßf<~üxRæŽĘĢ‘.)G ·jÕęóÏ?ŨRWē+VLJ’ø4þų§$9ícAQ­ZĩÛ·oKTëÕŦĮŲY‚tĀōWeý þïę­qKEýûũW9sæTĐŊwÉAŊŸŸŸ]ŲēeUï`iiY @éž.]šôÖŲ:;;kݖRļpa___“ļ+Š$ލ;6e_­’^FýK"䈷K—.šc5j$‡ÄÚÃ>ø@VĮ˜ë[:}Š%oķHð=S#ô*Š6ėččĻ’þín“ĸ―ÍÖÖV~øðĄúZŧ„―—<þ<)s–DũĄÔ!­`sæĖųúëŊ%?5nÜX}Ž–øIČe˖8p@Š­Îa&âîÝŧr ą{ũnݑēt)đ:Q™7o^šQY‚jöüIíÂJ‰ĐŧPétŋ Ģ{ýj™ÝÜÜô^õÖÃŅø―˜nn3‰ûŪ™$ž’%KvîÜđoßūŋOdVž–,YrôčQ •@6xðā·öÓĶMSßR"##u‹ā5Ú$žÔgffæîî~ýúõ“'OķlŲRïYõ%&ÉÔš#LýÉōĶŊwIaÔĀ7ß|ĢxŦWŊž”9ëî!zd†&L9räÚĩkûõë'đmųōåņwUĄ%rĩmÛvذa’ßsįÎýgœÄ-áæģÏ>ŦQĢ†Þø|ųōŅzČZʔ)sųōåŋĐĪFJã™øÅ+)āG Š:}.Įī_~ųĨÞSšßK''§Ÿ~úIâčĘ!qŦV­$hý‘ŪóįÏŋĸþûq&Ož,HŽ9&MšôÖųKï0sæLu5Rüþ&éyår‹-$ņüöÛo’tŊ/“·_ýaëÖ­Ó§$R$—Hø­_ŋ~åʕÓb666=zôčÖ­›„žĐS§&xɛTýf͚éþhHHHR /‡>ÚW ë’~A·nÝzûömÝsŅŅŅęŧŦ2A‚?,’FÔuEŌÆ~üņĮ Đū;ggg9jíÛ·ŊīĸŦWŊNðũô§L™"§gϞژŨŊ_ŋõ·ÜĪw§wHėäKš-IÞcGGG__ßæÍ›_ŧvMžxņb“&Mž={–/_> éS;;; Ũ&qŋˆĻ8•īcĮŽÔ]ėĻíÛ·ŋ{ũŪz˜-[6ݓ·?vuu՝þ­'xD˖-ÕuÓÔ]Y]§NÜÝÝĨųmÚīéĄC‡TËöÏ?ĸtėØņĖ™3VVV)þeڔĐPĄBĐRĨ$7H‡ĨĨ ÝŊy§V7$]ĄęĪkÐŧ ÂÏÏO7ļHþSŋū˜8éŨĪw ReŠÄS°`AÉōōÖJĩ.SĶLΜ9%ęJõ:}úī‹‹ËÆSýÃÚDĖž=;þüR’B… ÕĐS§J•*đrå’ÄýŽģ•ZŧtéR­îÞļqcúôéÚlK—.­ūtĶÔŊ__&VŨbŋ|ųrÜļqÚ/Ģ'ĒM›6NNN}úôŅ>õņņIâO5@Ķbmm―~ýzéîÜđ#Mąįɓ§páÂ6l°īī\ķlŲŧ–”žŅĖė·ß~“8"ĨõęÕóôô”ÞAû™œŧté’Īí~AGýå—_5jdw-„ôGš‡Üuë֝?ūúŽģú7™ā­‹B|ø0ÕL“Ūw™hÜļņÕŦW%mėÜđSúiĐ[å˗—@ iZũz[–$Ī{åēŠÞ&ĸũųŦđđđzĻÎv&þP)P €ŒÔ>– #S§NÝū}ŧ ØÛÛ/^üM‰G=Ŧ=ŒŋĘęlTÜÝŧwËlÕ·čĨŽöíÛWý€šIÜíßšwïūpáBY‹―{ũĘÁüjÕŠI9ØŋíĮ eÏŨJŦÍß$îcfI‡2+Ų%ä$&&&_ū|€īWém7ČĖäXŌĀÜđs%Üŧw/$$Īdɒ5>ĸüsõŦ"šSæČ‘CũĒuØŽÛ>Ëģ2FËzmmmåĄÞĮUōōĀĀ@íÛÛÛûäɓr°šĸþS§NIĢęååÕĢG /ŊŌjiÉĨ„zHZR?č/þųįÁƒKŧ­ū–/ŦŽ]9*-ĸ€† "3<~üļ>\V_^•;wîņãĮKŊĄ}#XšHmīųŦ••ÃxõĢūŌSDGGËd>ņ_eīLų|<Ūâ$‰€Ä@â ņxH<€Ä@â ņxH<$‰xH<$‰€Ä@â ņ‰€Ä@â ņxH<$@â ņxH<$€Ôc‘ĨKééūeįÆž ó7ė7)ŧMŪîžÓ*äm@}`īŒĪÁ§+I;ĶąąąY·ôƒ·x†=5†ũÉÜĖrHßžō7e§`œŒ§Á§+!ņ$āÃuđäï j‹Ž-ė øMÚ}į·‹Oöz3#iðéJŌŽ…ރĢMn {~“>(3ZþJM{Ž7Ą€13øŸŪ$ípårVx“LÍĪĶ–Ïû^tLĪÔÔģv°Mt%$j*t%$j*€ŪÄČšOŪĐįïd›čJH<^S>5„ x·Ūd°‘Žĩ…ĄŪØÞŧKO>Üm0kõZï‡BÂ6\™ųAŲQė―Œ™á5øéەž0’ŪÄ`ÏÁû+cbc û͋5‰ÝtmVëŌÃ,ĖŽØ-chðéJH] ‰į-\ė ØY:RĄĀāŅā#q\đ H<$‰€Ä@â ņ+ÎÅv ņ`°ÎønûûÖĒ=w–°) ˜›`ĖĒb"V]˜ ŪĖô.ÜÎÞĘ)ýËð:ōågĮïAWķÞøáöóÓō°Ru‹vŅ›æû#ÝiYŠ9WžpnÎą$ôxnϐá’{ ­thðĸļüĩ6ķųڜĄÞ‹Óhõ_„>þ'čZĨwøFšĖ!îô˜I^7gÛü)›‰āįSCB%eÆÐ•Ī_âIÁUrÛõĘßtáÉAG}֟ņÝjmnÛīDĸ ŲLKώ:ęóG ^øŲ֊Ķ&ĶšcĪ&õðšĄ7ō]ŒĻ―fųđąē‰œĪæOk ceķ?Ö$VïŠ)[_•üsNWýwĐlma—‚ĒĘkŨ]žö ð’úÜMrOaGŽåƕÉ]+đģ’H1ŪųĐYĪ]‰Iz^đœē;ŠČ>ÓïßžŲN†%sdÔ |XqšgūFŊ#_ęþKĘ C#ƒu_"3‘YĨbÜŅÝDąą1 þm,þ0€ •Ų|iuÝsÕÐS:WÍĪž0<ęõàŦōrŧdœhđýütМÕSPΝ·~žsī§lŸZߜÖhŋü[ÐæVÍ"íeäß·Ĩ`†R uڌŪÄ$ŋŦÕĪDß\“ŸBnRL^.3‘YĨ]ņ=2‰Tiðĸš17ĩĘóqåŲ…KŦáJš·-óų[_kŧüü˜°ĻWeōÔą·rNúēßLÁ5˗žî[eæļú[ïúHŌü{þÚWĘČ WfĘɝgAĮŌRš%―ïŦ•ē;ŠĻ·!nXŊރôĸxK· ™*îÄ/oČ Þ―Á?ųpģ ī,5äÝ “;[‘ÏkŪķÍ+§]ĄÏž—ūuú˜Øč_Nvčþ+s›nĶ$kYƒïäÏ^"đ%\uab— “ 9–ųûÖĒU&HÔÖčZaēÄĮ.ūZy~Œ&‡’5Ï|ÅĨ0t%ĸ]ŧ ŲŒíLOZĮ#‰įēbčyĮ_BO*žéIĒϘˆųĮ?QqgHÅÚÉĄ$ |io唎—øūžðúQí"|ŊŽ đ+ëđv/•Ŧ†…™U Š!ļþė˜Ī(š’L—x #ôĪĸŲÅgū°6·Mžæzz4Õ ―omnũÃņ>î­ z­ēĶ–<öŪ9lō\zšß3_Ģž\rRŲÕzũûÏÉ>°âü—ßX蝓<íûW7Q§üd)îRĨSđņßęü4ä^Z/KņÝĄ.ˍ—…Ō•$kccc3m―ĸp].ųŧ°ím;KGŠŊRŋė I þ"&6záŋŸ/þ{  3ë˜Ø(yK Ģ]ˆ5QïiÂOÆĐ[ī[Ÿ*ģ“ļ‰l,ēÍnq>›UÚ\ÆÓāĮęī™itķGkŪMÓljkajbšēē|Wb–…öÝāŋāäĀG/o&1øũ­úƒŽŠ —·DÞ]Ãø§S#ãĸûŊũWūõĮ*Ô&rēÍõęދóīžŒŠÁŨm3MŌļđNË!VK0Þ•Ü 8— +•E–Û,ÍŽW]œxäÁ:ųgin-ßúŠČ˜pmØŅ&ũøú™›Zvccó0čę–ëón??5ïØĮVæķ‰ÞÞåß Š—úšŨÁĶ >ÞĨ+ɗ―x&\ŽWš–ė_"gÕ-Ũį\|ēGķŽüKÆ-Só 0ŋ“7ĩrĸĖākjîlE<ó5Vį#ĒCå_âÓÛ[9u­09§]!vr4ø0žŪ$K&_7gŊÏž—ÆÄF…ųGĮDūuzs3Ë!•“cŋ4eíĨi&&ĶIĸ`8ëŌ―„ÞÔÔLjaåüÍßī‰rØäNįû‚ >] ‰'ImÞd―ä=·žą&ąÉýÞĢÁÔÔU&d·vá+čhða„]‰Ņ}š™ēŧÖLMåwwÐāÃ8ŧ öBÐāÃāŧ öBÐāÃāŧ öBÐāÃāŧ3#ßRð[æPSđ­|ĪVWręaÖčJĖØŒ9ô,<ųéŦˆ@ö^4øHqWēčTÖčJøý•þ–yVŊĐ}ŦĖËa“įßßqŽ:€ߕðÛÛĸÝRð[æYÚĸĸ-p‡âT4ø0øŪ„Äó_ę·Ėĸš>ũ“ÝÉý-ó,ŠÛJ Á7’ŸŪ„Äó?ܜ―†z/Iúo™g~ÃķyÉßņõ·:ÛæÓ{ŠÛJ Á ó3ŒŸŪÄÏãāÛnΕŌmq)ø-óLÎŲ.'rd éÜāKWm` >]Ibý{æ/âķóĐj` hðaΉ§|Þũäïɇ[ķ\ŸÍ[ŒFxFÔþ――ĮX“ŋF8ßNFƒĢN<ĒMéaü`|uâ1áW2ĀhÐāÃĻûzĢH<ė@čŒ"ņ°Ą0ŠÄÃ>„Ā(ûzĢH<ė@čŒ"ņ°Ą0ŠÄÃ>„Ā(ûzĢH<ė@čŒ"ņ°Ą0ŠÄÃ>„Ā(ûzĢH<ė@čŒ"ņ°Ą0ŠÄÃ>„Ā(ûz=žĻ@þņ6€a‡|ž•™aïZð7ęTkfEE`ðĄ‡ŸŪÄxî>`ĖŽĖmØWOč]IÂĄÍöK3ë•ÆËðg[+šš˜Ė€ÆÖ•XÃûÔīdĸŦ~‡Î=ÞlluīFáŽĖmŲW‰|ĸÃįým„ >]IâLcccä óŒ3Š:jinãh“‹}€ą1ÂŸŪ„Ä`čW.x‰€Ä@â ņxH<$ ņxH<$‰€Ä@â$‰€Ä@â ņxH<€ÄƒäˆŽŽŽŠŠb;ôHï }ہÄc Ο?ōäIķ@ôŌG°H<$‰€ÄŒƒill,[6Îņ‰€Ä@â1ÜW  îŦEâ1(ÜW  îŦEâ ņxH<$`LļŊ0|œã$‰€ÄcļŊ AÜW‹ÄcPļŊ AÜW‹Ä@â ņxH<˜p_-`ø8ĮH<$‰Į p_-@‚ļŊ‰Į p_-@‚ļŊ‰€Ä@â ņx€1áūZĀðqސxH<$AāūZ€q_-AáūZ€q_-‰€Ä@âøĸŌð.‹-bû°^―zYYYą$WDDĒ%KØŽoßū™°Ti:ũŪ]ŧŌ)$Z+ï~ÔÄF ƒ0œÄc‡·ŋƒ`# =q ņxH<$‰€Ä@â$C`‘%JyâĉlŲēyxxčŋråJxxļ——Ũ›^xýúu™ B… YũÚ·o_PPÞČråĘđđđ%wVmÛķýóÏ?Đô Des<_ýõ€âïÛ·ïÜđsyáå˗Ϟ=›øĖwîܙ™Ũ=8880Ώ?þxņâE5,{)ÍÐAÐA$EV)há…Ož2>,,lÜļq2[sss ‹Ųģg˜ežŒ,]šī”Mæ#q{ƌډÓ+VŽYģÆĘĘJæ/ãĨ‚9ŌÏÏOfÞĶM9.Iâ69zôĻÜČreVüqĮŽÕøŧwïJ^―z%‹Ū_ŋūĖ\ŠA]`Ļė >üðÃuëÖĨz1a™OR:iŋüōËø„Œ,SĶLŌ;ˆQĢF=}ú422RJNņNbӌT8Ų Đ2+É/^žĻWŊžüUcĪ4iŌDj’„5æþýû2RĒĢĢ5jäãã#Ã7n\žxą œ;wNŠï‘#GÔÄ˗/—ZŦ†ëÖ­Ŧ-ČßßŋF?–က€jÕŠ=þ\†‡Z§NĐĘ2ÕŽYģ›7oŠ—\žxQ Ȏ1hÐ 5\žxņI“&ÅÄÄȰ”ĪvíÚjž.Č4RqeXž•YÉ@‹-dĮS%ïÖ­ÛöíÛÜRY íá7ĪäRH–]TVvėØ!ÃRĨØŨŪ]S‹š=uęTm3fÂ7€ą‘ÖCڐԚ›ę Ī=LëâŲģgÞÞÞoí š7ož`1pāĀtë Īz„zĄ^1~üø4ę 2gÅËJßÕęŅ̇TD-K~Ũ}ķH‘"Ųģg—IßRE._ūŽũrБRYÕpÛķmĨr$xStÞžyeØÉÉĐC‡[·nUOIe•]B$­·lŲō… j|đråÔ@ãÆĨ’i9rôčŅ*8*TČÖÖV*ą /X°āŧïū“Ð-ÃōŽĖJöGGGu  %ĸâ‹/$ā'ek,ZīH*ŦR†mllf͚Ĩ>ąÞžyóûïŋïîîŪņÕW_­_ŋžC@†­WŊ^ïŌAHėÐ:iBßÔA|ōÉ'oí dþ v·oß~kņí·ß&ŌAŒ1"‰„d―bÞžyņ; ^FÕAXdĄēvęÔIbûāÁƒexÆ RÕ$kkφ„„Ž^―úęÕŦÃïÜđ3räH―—.\Xķ··—<ēH>þžzxãÆ YĒ.ZīĻ6™,N;s(áÝŨŨ7,,,00PĖ“'ĩĩĩ6―ThIÖē?H –ʧŧDĐÐrðņŲgŸĐ‡ēô‡&ekȚŽ3F{X°`A9ūQã%Ûiãe'ɟ?ŋˆļļļÐ&0T;v|—B"‘6œ-[ķ;ˆK—.―KĄščÄ;NĸBķIΜ9I<™‹T#OOOĐ@+VŽĻ[c‚ƒƒ›5k6hÐ ĐĮĀįĖ™ĸåVVVo]DLLLŋ~ý\]]ĩ1ÎÎÎj@wq Î’† RēdIĐĐZMēīī|ÓˆņGJöïŲģ§6F/―‰,Bonęa‚ãĨZÓ 0`‰w͛78pāŧw}ûö-VŽXÖí d5đƒ°ČZŕ8ōÝwߙšš~ųå—šãũïßß Aƒ.]šĻ‡<ÐM܉Ó}û˖-+ š~ýúI|íš5kd“`.ÃOž**JtÔđM0`ýûũĸæ›oĪA;vŽ^ņÞ{ïĨJáëë+ģJAņôéÓĖÐA”/_>~Ąå6ƒ—Å’žýRáŠ/Ū;ūpáÂgΜ‘7Ï$î,âöíۓ>OĐÐVÔpŊ^―~øáírœG%^GĨĒĻÏkCBB&L˜ [S$ƒ “áČČHĐÜr,âįį·eË5ĖGV0‰áoÚīiRBu3xðāÏ?ĸ\†›5kķkŨŪÓ§OŦÚ ýnÁäɓ{ũî#G‰,2·å˗O:UęąsyđT™F^+sÐ^ŦŪ\3‰ûRâĻQĢĒĢĢĨ*=zóæÍz3Ũ+ŋ$*KKË:ČCŲ‘þóŸĸļđđ­]ŧVʰpáByĘÖÖvøðá ˆŋôĘ Ó,Zīč‹/ūÝC ›ĨnÝš&q'37lØ {ŨôéÓÃÃÃ[·n-U_+m"“%:ЂK"„•••ÖAČĖ%ÃŅAĪ"ÓøĶŲÜęýc‡4<žđR,""bɒ%Iĸidđ"sūđ\Ð ‰xH<$‰€Äðvķ>;wî|ýúĩIÜÍo+UŠ”· ‰ŽŽ^ŋ~}ĮŽÓhþ>>>&ĸ{ãwqöėYwww;;ŧ   }ûöБđsįŪRĨŠvšÃ‡ŨŠU‹*ošgϞ[·nY[[KëZ·n]u?,C;Į3vėØĀĀĀ/^H&hÓĶÍÏ?ĸœÖK”€õįŸŠáÝŧw§úüũÆŅ9wî\???“ļûÃýøãēĘþþþÛķmŦQ̆ŽļšfÜļqÔoxŦýûũKÄđyóͧ§§ŦŦŦDŸ]ŧveÝÕđ~ýzoŋelēÞ9žûũïKŊw_――}Ŋ^―Ôð°aÞžž:wîėāāv呙ŊZĩJ /[ķŽaÆéžAʔ)Ģ­ēŽėðáÃĸþûoj6häļīmÛķ >%ĮŸ}ö™Dœ\đrĐ1͚5ËŌ+ŧsįÎ:uę$xû-OÖK<âM‰G—•••΁G•*U*::zōäÉįϟ—ņĨK—ž6mšđđyHHČüųócbbNœ8%Õý›oūQ•^MæĖSSSGGĮ™3gŠÚģ{ũny‰ „‡‡ŧđđ͛7O†eo™={öˆ#þúë/>ūûîŧœ9s^ŧvmüøņ2į°°°æÍ›2Dlƌyóæ]·nĖžf͚ݹuÓ>īš{ũîúõëeV)Û8OŸ>ĨZ@Ï?ü ­―wt―zõj˘1‰ĪG(ZīčŨ_-݁ŒŸ0aB5.\(݇ģģó·ß~+}ÄõëŨcccĨĐ4hIÜu?ÞŧwŊüˆˆÃïŊūúJ}Ræïï?jÔĻgϞIï öÔĐSÕ= Ĩ+Vüå—_ĖĖĖdŅŌ}ÔŪ][•d͚5+WŪīķķķĩĩýþûïUie†îîîrČ-]‰tISĶLĐ\đōęÕŦĨ?’ŪJ Ö§Oooo)öącĮ,--_ŋ~ÝŊ_ŋ>øĀxëAlš‘Ú ïAŠÏvßū}‹/~ÓģuëÖՆeé•*U •áŅĢG/X°@Ÿ3gŽÔ0xņâ…T ĩkŨŠņ”ĘІŋøâ‹YģfĐaÉ=Ri"##eXŠã˗/ÕxÉz Õ]šĖžjÕŠēŦȰė-’Š$Ч$Mœ8Q oÝšUjđö*ĐâÏuŨhq―ÕėŲ짚óđsį†Š—‡;vŒ_˜Žōæ0ŌzH’žK”6óMOiÝD|ķmÛ͆å€ķuëÖjļM›6kĪa—aIr{āĀ–$ČíÛ·exãÆųōåS1HHėPýŽL#ó‘#GÔøŸþYRˆŪ_ŋūôƒd8 @â‹ŋyóæ>úHõAōÂ-Zh%;vŽ*Ɠ'OΟRãĨSū@{­ÖGHðzþüy:lít~s“.˜ãņõõ•->”ĖĄÎÖtíÚUR…îdÚU5ōöK˜ ccc#eŨŪ]§OŸVÓ 8Pâų—_~)Ãnnn:tPã%MKĨ|ôč‘ÄgĐū'OžTã%›ËS{öėiŌΉTV‰ÞęcēÜđs'R` RēÉa K`—#€š5k~úé§ŠjéBæ9cƌqãÆIH—™Kž›4iRēķĖ;wd•e'‘)Ī;Žį@üúëŊ—.]’iÏ%LȀģģó„ t§‘Bš‰øŊ}ðāīŦÚ'\’3dnŌĖJŊ!?þøciØe aÆŌÔĐSG†ĨoÜļąĪ5MÛķmåøV―|øðáÕŦW—–ĸøņãeʔ‘tĒÆũéÓgŲēeÁÁÁŌ­H “Đó@NNNŋ—ŽLâ”~ĸþûïĸöŨōBÉgrD-Hņƌ̊‘'OGGGyĘÖÖVw-ėėė$åȜe2KKËtø6ŸjĨyŨU8|ø°dõ^ęM&ïk``  lŲēE‚ģDrõQ‘ÔUÝíĢ•H4RÃnÝš%‰DŦ͊DékŨŪI:Yīh‘Tô%J 2ĪXąb‰XĶïŌĨ‹îGl*{I+RΈö*Đܧ:$;ŒäŲyTõM:9ZRŦžtéŌĢGæČ‘ƒfLâ.mlŨŪ øųųĐ$~+Íō›Úp―Ë'*WŪ|õęU•f ,øßNÔÂB;īęö/ŌæKũ$29ŠÖmųōåĨߑ‘ÖÖÖšģ’‡aaa2pûöíiÓĶéĸ I<’īėííu{éôOƒ Ū\đŌĻQĢöíÛËAxüN“Ä“I2P}đžÁōž―Đ_ŨŪ\–7XōuÓĶMĨÄÆÆJ•ŌM<ŸþđˆŽŽÖûŒOaU5uƒ”ÚOŠV­šuëV9\9rĪŦŦŦ:픠ø3QGj]tGJgΜ)‰G"‹nĩÖV\}ß^WDD„Ęû&:W.ËåØeîÜđ4s`ũ3%ZxSŊ!đäÆzGđŠíßĻ6\ĩ·š­}‚sŽßŋĻ’ĻĢŨïȀ^XŅäʕK·ĸ’áüųó'x˟ 9>ïßŋĸÚĩk%ýLŸ>―~ýúF[ ö (ÐĄC‡ïŋĸ^†‹+öÏ?ĸÕĄ{Ĩ°îŦ$ ŧŧŧKĘVÄjã?îááĄ=”ÜóĮœ?þɓ'zûƒnl?vė˜ö044T7Ķč*QĒÄÓ§OŸ?RĪH―geđÔ[ʝ;wōå˧7eŨŪ]/ÅĄ™€$ęÖ­ÛŽYģâũôô}:þĄēQ1īß\ÖýØU‚ÎŨ_-ąC"ÂÔĐSį͛ŨŠU+kkkÉŋ=zôpuu•iš7o.•ŧC‡Rŋ‹/ŪýbĄún—ä‰ ™ČŦĒĢĢe†Ïž=“ī!UîÜđęĪĒķP IR5íííGŒáååĩvíÚ &žxņB2VĮŽ?üðÃø…TĪĢFŌ~ŨGėiß|óM˖-Õ!‚‘ĻOĶMâ>œbkSĘūT·n]ĐÖUŠTɛ7ŊĪ4íĐĶM›ĘJŅð€Þąâš5k$ŲȑĪDé8~üņGŋ3gÎTŨƒ–+WNK?Ú {Ðý@^íÚ9Ð]đråīiÓš5kÖŊ_?5~õęÕ'N\ļpĄô)ÞÞÞÚÕšóîîîŠÍ—Æ_: iųՁnõęÕåĐøÓkĨ’nĀ€{ũî•.ĖŲŲyėØąŌÉęH\›3gŽQŋŨiw>`ŅĒE―zõJüä[ƒä+%Ô~199rDbMš'óŋđ2-9Â\ēdIßū} xĨgđĸūîõ7ÆC:ˆĖųær'ŅLáûïŋŨâ?Hul‚Œ5eʔ#GŽ”/_ūlŲēl H<ĐÏŅŅqåʕ[†ącĮ†……%~Ų kiŅĒEü(‰'ؚšfxÔ077'yӏô q ņxH<$‰€Ä@â$Cķw™Xēd ›ßĒE‹ØHOĶąąąi4눈#؈įϟ—•­ZĩŠQU+++öt‰;yōĪī–žžžt†œx2 Ūã$‰€ÄcĒĢĢĢĒĒØ=Ō;HÁv ņˆóįϟÐđaÃŲ―{ũī(ÆO?ý”7oÞ īoßūE‹’ĀJ—.}ïÞ―Ėžé6oÞÜŪ]ŧI“&7Ū[·nRfŲb^æ+VL:U{øäÉ*9pŽČ`2ķmÛķĸ~mLhhčdāėŲģ~~~đsįVãÕ4ï―ũ^Š—aïÞ―T3ũôô|úôéÁƒ_ū|™ųOóījÕjöėŲj8::zÖŽYē ŨŪ]ģąąÉĻ"uíÚ588X GFFNœ8qá…Ôs€Ä;•`Nœ8aee%ÃwÂÃÃģgÏ.™cĮŽ=zôPSJ ‰Ÿx|||ōįÏŊ#=2ŦÛ·o[ZZ–(QÂÔÔ4ÁiÖ­['ÛĩkũĮĻ1ąąą=277ŨL◌trr*RĪˆîø   ™ŌÞÞ^†ïÜđ&QIō‡ĩĩĩ­­­6YTTTHHˆ 8::j%đwïžžžPĄB...ڔōZ 6q$4ÜšuKæĢ>§K„”á‹/ūXŧvíž={ZīhĄû”„Hݒ艎Ģ6~‚yđž0&&FũÓ4ݍséŌ%Ųþ)˜m‚sð.øT Č`*Tș3§Īíúũŋĸþ[þvėØQþnßū]|ōä‰tüfffõęÕScŽ?.Ŋ•þĩbŊyōäĐ_ŋþýûũõĀïŋĸž/_>RĨJ•,YōM—ØKŨ+ ( ‘DĒûPrŒĖ_–"Ë*Zīhđråtg%eðöö~øða­ZĩŠ/.‹›5k–̆ ę.åįŸ–‘UŦVU%—H‘Š+&ó”-Оysí 2åðáÃ>ėææVķlŲ.]š$q{Ęôĩ‡?þøĢŽ{õęÕe|ßū}_ŋ~­ÆKš”TtęÔĐÚĩkKeĘ—/ŋyófÝYIžëÜđģĪ7)ģü=zīĪRÝÕ)S͌žPŠ'[ _ŋ~jžĪÆÉ“'ËĀwß}ŨēeK™§gœ•+WŠ ž>}úá‡JČSģ1b„žûÚle‰ēšwïŪ6Ž,E’ĻÞ:JLlÔĻû<ą2š 7SĶLQÝÝÝåáĩkŨ$ēļļļČąūŒ\―zĩŒŽ\đ皿úõëvvvЃœ1cFãÆeXŌ†ôčōŽš–E^niiŲķmÛÁƒËS2FæöėŲģøX°`ÞjŌΉ,K–(Ã9räøįŸÔŽŽŽÖÖÖ^^^ČĪkŊS§Ž<ĨÎâHÓæ#yHÆLŸ>]†%jHŲdú>úHæĐžŠTВZŲsįÎÉÃŌĨK˜ĨT’ >ýôÓøÅ^žxņÐĄCõFJ9räˆþöÛoeËĻU–õ’‰ŧuëĶ­”―――5ɑjĖÕŦW%ĖíÛ·O=”H$oÄO?ýΊ,E•āĨž=xð ,HBžz(Ïj Õ-ÕÆ{öėĐ[žWŊ^Éz͟?_Í6$$äã?nÝšĩ6AÝšu%)ĘÛ­‘Ävũî]ݙŒ?^mFIGâ2ÞĒE‹Īƒ—Ģv~ð⁠Ëņ― ŨŽYSË‘áþýûËðĻQĢÔKĪį–‡TcbbÔđ“å˗k‰GLžÔ―G Ŧ&zF=xðāŋO™2åÞ―{’!nÞž™7oއĘ߯Ņ}‰Þ5đ•+WÖ}()$GŽ—.]’’—-[V%ƒüýýÕ1ņŊÎŅ―ĮÖÖö­ŋjS·nÝ &Ļ‹cZĩj5bÄÉvęĐûũïKļŅ.{RŪ_ŋŪ]Ԝ3gN―KģģeË&Đ(((H}fWīhŅø >|X ,(q˘1ēô>}úôîÝ[斔ũÚŨŨWÞîøāŊŋþŌĘ6Ũ}6_ū|@ũïßŊ.Zĸí·ßdqė5‰ȒĪ3“ĻqöėŲC‡IøPýīš$Ybú–VõęÕÕĩ;Z?-ŅDš^ÝųĻëu4ĄĄĄŲģgWÃ*dĻóo"]ūĪŦ:”/_ÞÏÏoóæÍ}ûöU‹8p`•*Ut'Öë˜-,,ô"T·nÝæÏŸŋf͚îÝŧ_ļpÁÅÅĨuëÖšSΚ5Kē…îŦt#N"_žŌČÚĐ\"ĨĻ_|ņ…v°:Å5iŌ$―—ĻmhũÕņø3üũÔwÜ&’ĨĮ?#cīïîîūqãF F ,Í5cÆ í[u‰Í’āl_$).]šT*‰ĪąĢGĘ0ŧ @âÉęĒ―æHAâŲķmÛÓ§O4h zeSSÓÆ/_ū\ž2ŅųHK*›››Û;wĪ›Oü eÉLjøęÕŦ*žĩ0ōéÂwïÞ-ýŦ<,UŠÔíÛ·%šôęÕ+Y+%ÓKâY·núæđ bråĘåääôâŋ’%K6oÞ<ĩķáØąc%0IdTŸUɚ>|X/QézþüđÞũÃeŒls•%;^ŧvMï|Lü1… š6mÚ'Ÿ|Rđråf͚Åĸ NïgŊåå2õοƕ+ņOüčR§ŊĪīëŨŊ—ĮWÖģĻĻ(ĐTzg‘!ļŽ'p_-ĪJâ1‰ŧČÃäĸ>ŌRĪ5‰ŧĶÄ䉧kŨŪōw„ wïÞÕÎXČd*Ģh&MšĪū-UTýÖN‚ cäȑkŨŪõũũW=īĖG]îĢ>ĻRWIĸðÃڕ=2‹[·n%ūRōōråĘÝļqCB›IÜIĸ·Ý13S_ø=zīŊŊŊūiÓ&Ýïi'—ÄÄoŋýöÓO?Uwö•€(…T·ĄHPLLŒú QģråJmãŋĸþûŋþúŦîģŊ^―Zģf:MĨGŌ•$$???―ņ’·$ÂęŽųāƒԅęYå+VīiÓ&‘U“ˆ#lÞžyÕŠU}úôaÉBļŊV&ÂÅÛïîôéÓÚSS_Všßxzöė™úžÃÞÞ^ũ{ã’cŠWŊnũ —‡‡‡ŧŧ{ķlŲLâ~ĐEûŪ–t·Ųģg—ņŊSßŊYģĶ:%ЧB… jŅēíüAŧvíī/‚uęÔI”B–-[V8ŲļqĢîwĩΝ;Îßĸ―zĄ———îø€€™ęËeé2[õ+É/^žÐūŦ%ģM|‹%øítɅsæĖQÃ?ĸüģlœÃ‡Ŧo™IšZļpĄöíôžyóV­ZõōŽlYsóæMí‹]ÞÞÞ#FŒxþüđ<”xŨļqãáÇŦgWŊ^―oßūĀĀ@õIŌ*]šī$-―R=yōDÖB}·\fĻū™Õ AƒŠŲĘS’ąŽûíô·äĨK—äŊUŦ{JÖ"―ƒôl‡Ė€b€ĖĒwïÞÛķm“ŒĒû'—>účöíە*UŌýäÔÖÖvïÞ―óæÍÛ°aÃ$ÖHnhذĄú KԃtœŌC·nÝzÜļq§NrsskŅĒÅäɓž^DĶYĩj՝;wüüüd‰%K–ėÚĩŦvUŠĪ%yV:æe˖I 9Č’ŠUŦĶ&n8$$DýæēžîÝŧoÚīIúöíŦ;ÞÉÉéØącģgϖg%ˆČkŦTĐŌĪI5ų+åOp†š$ č]·$d›Œ3ĶĸþVVV}úô)X°āÔĐSĨØē2―î).kkëĩkŨŽ?^ō‡Ä‘ōåËïŲģ§D‰Úi•;wJbŦWŊ^XX˜lu…ē ŋþúkŲōēâō–É4ōvĻO.tK%o‡Ä/Ųō’VÛīióÝwßÉ4ýõŨþóÉ=Ŋ^―’íÐŦW/õÓЧ§g‚+.ŅMbî!CØS€”1Mέ•‘ 3g΄‡‡Ŧ/ŅČ%[čýJuf&ŅJ‚Ô­[·ī/Ģ!K8zôĻdk9baSd8Ūã€,`éŌĨ-[ķ$î)ƧZŲĐK…tģ‰'pš@ŲģgÏÐĄCFåááÁÉrļā!óā:Æ(6îöŸÚÏ3ffáááæææüâ@âx Ū\$LâîŦĨ~Õ]Ō;HÁv ņîŦHũÕ"ņxH<$0&üæ20|œã$‰€ÄcļŊ AÜW‹ÄcPļŊ AÜW‹Ä@â ņxH<˜p_-`ø8ĮH<$‰Į p_-@‚ļŊ‰Į p_-@‚ļŊ‰€Äz,ØRWllĖӐ{ĸ]{øōúģW>Ï_û†ų…DDF‡…FĮšÄZš[[šYÛZ:ØY::Ųæuą+˜ÓŪP!ĮŌ…r”‘6 €ĖšrLbžļtáɞώÝ~~Z’M"GF‡ËŋŨ‘/Ÿ›øþtUũ){+§’9Ŧ—Î]ģlî:’Ø°H<2EÐđųėÄqŸ§|·…ųkã­-ė f/]ÐŅ=―kŪl…sØäq°vķ6Ïfc™ÍĖÔ<<*4:&24*äe˜ß‹°'/B?ūãxÅũ卐ˆgm—2“Ü؊T-ÔĶjÁÖŪNØÔÞũՐÁáÏũÝ]ūĸÞrĸW>jŒEķ2đë”ËS·dÎę’u$Ų$wž1ąŅ/]ũ?&ĸŪøz­ÆČîÞЭW­Ēl,ėŲōH<ŌÃӐ{[oĖ;ü`mdtx\ÐąŊZ°UĩBmËäŪeaf•ZK‰ˆŧōô‰‡›Îøn ‹zĨU―bķ(õi›<ž H<ŌJ@čĢ Wfšĸ{LėŋŋĻæęTĄaņŦlcma—v ‹ 9æģaϝÅ/ËCKsëũŠõl[fļ―•3ï€ÔúŨõy[oĖ‹ˆ“‡åōÖoå>ītۚéY†ËOũoš6ëšĸQÎf•Ģ―Į˜úÅz˜›r1"€ÔpÅïāog†û…Ü—áâ.U:•ïžŦFFæšĸ‘Õ&Þ{qA† į(Û·ĘErxð ņ·ččh،kÂÐDD‡­š0aϝÅ2œÃ&OŨ “Ŧ~ßÔÄ4cKsøÁÚß/M ó77ĩxŋėˆ–îC8؃Ė)**ĘÔÔÔÜܜMAâ1gΜ ũööfSøūž1ũXïG/oĘp=Ũî]*LēģtĖ<Å ‰X~nėQŸõ2\ÂĨĘïÅ\ҌLččŅĢÖÖ֕*UbSd8î2 'n™ļ§ąÄk—áĩV}\yV͊;&ĸþVĄó€j >ó^šÍ*Į­į§ÆíŠóŲ Þ8$IĩųÚėyĮz‡G―.™ģÚŨzæk”i‹ZĐ@óЍöš:y…ųO?ðþĄûkxûxžELlô’ģ#Ũ]ž&à Ü>[wĢĢMîL^æœv…&ž·ĩvŅÎŅ1‘‹N Þvc>ï#€ÄâΓƒÔuĘ]*|ÕËës3Ë,Qr 3ŦOŠĖmSús^}qŌï—Ķðn ņH@ŽIŽÄĢ>ëMMÍúWýąyɁYŦüĶ&Ķí=ÆôŽ8C†ĸš>ũÏŦĸá=ð?­ßÕ –ž―ûöŊqqgūwáöYwEöÜYžäėH“ļÓTY.·H;œãðïI‰;2зĘÜ,wLâ.?ęQņkX}aâißŋxsxüëŒï6uáKįōjédkÔĻxŸf%ČĀO'Ļ_g`ԞßYpr Ôĸũķäƒ f―:—Ÿč•ŋYDt؜Ģ=C"^ðF ņÆ+*&bîąÞaQ!nΕzÄ]ók8M›Đų€j?ås(þüĩï/§?‹5á‚E€ÄƒwÅv@–ģöŌÔ‚ŪÚ[9 ņþÍÂĖĘĀÖÎÆ"Û§Õ‘õ:ãŧM}åȀãŠĻ(é#Ø$qþüų“'OēĩÜz~jĮÍ2ðqåïmóä:ÎQķ›įŋ—(­đøÕóŨyӑþĪw>‚íp·aĀ(;c"Ôg=5‹tĻ\ ĨŊi·Nüóįuĸc‹ÏŽøĒÖę7MõęÎóÓĸ]{|; ôQhdphT°đĐĨEķlV9rÚĖįPž cébÎ ïd@â`°þūĩ(î.ĄÎÝ*L5ė5551í]éûą;ë^xžûÔÃŋŠüŸxũüĩ›N?üëNĀŲ˜Ø·ô`enSÂĨjåÍŦ~ßÞʙАxd^/ßmšö― tð'ĄĮāŨ7ŸCņ–îƒĸžúŸß/MöĘßDÝ:ãšĸ‘m7æK Ō.jÎm_ī˜“gėî.vēYå°ĩtˆŠ‰‹|ð4äÞãāÛwÎ…ų_ņ;(ĸV\_)ӖîC]*PĢ€ĖhóĩYĄ‘Á…s”­įÚÍHVđEĐÁûî.“āēũîRW'ÏU&Üz~Ę$î PŲ|xõęÕ5j888ĪĘ ƒƒƒ;VŠTĐ"Eаy‘QV_œīíÆ|7įJ“ė0ŠŽđ̆_Č}SÓÚE;w(ũeRNę$îIðįŋžðd Č^jp_ dw§ŽŅAĪļƒ(YēdŅĒEŲžiÄ|ŌĪIl…ý?öî.Šúĸ8{pß§Ü ‡Ļrˆũm}Ņ4Ŋ43M+KÓGą1r ë0ģ—ëx•qgïåĮ’ŋTŦ•æõÁxßejĩH™˜V߉”­™e‰Z G xÓuã0 ߎÐÐļ™xÞüĩ\.CݰĢDxüo_ÍŌčb(Ô$ô”Ôäþ/nö­ü 4oeā4ÎgIˆÓ5Ų)döQŸŌšjĩĶĖõm7ŧІ%$Ũ’ĮfGļõß gŸð·úvāF]+ÍÜ ęĪĒi‡œŅXÔ~“ÏšÅV͞ËLYoK0Ð6AéĻģé‘īēędĩHü}ÂGUâ2þ+æžÜa†úI™šVãļC!ėĨïđšų^ūĸەœĢŠZ*uK`ĸô -^w§WÂ~ŧģųHŌ†Ŧđ§ÂOũ›Ųý­{hbâ‘Õ2}aûČTžžĻģ깇s°4›Šō·Zw°Ũ ô<#™\úóõOOßý†æÝ,üßŲfkäĶnMŦņÅQދFtšK3ĄÎĢÖþųڍgQ3y æëžÚų̧_Åž“Uvëó ŊNėšrĻįŧ; h ÐzpB€–†žĪĪĪĖĖĖVýC5uëĸšČĝæ-p\ÝâÎĢžmz)æ}ÚõGĩ4ÃÞØ3bĀĐþnoŌ[į]ŨÂw__*ŨÂoJx4,ôTˆŠWžvýÁÞėÐïĮtųDĀcÁ‘īŌJŪ6šGĐ4O[ ;ĩÛýVŅü‰”Ŋw&,DčP.@9Ą§•ūÞĒļóų…Wï—'™čZ-čý‹ŦđŊڎƒžÐˆĮã+ūāßwsĨTVįbîwĸhLvĪĘÞÕąę@/yN7ŨģýúōûgÓv ųړü>Įö€ÄĀýÐ#’TŊųsÅs}ŧð~‡ÛĩWįA lábÖEq0ąīvύ•/•ģ™7ŧj)Äi„T.ŲvyÆéŧßPúÖq6ķ/åžFa”z”øõ–\KNïõ)@ëZ,î{HÍã#Ėë,RËõpýVĀZšŲ—øŲõž?°q ņp9ôüšøy|Îq!_gnÏ]ķ,9ívw§WGy/äiņÔaah1hah‘ØXKýÝÞęųŪ\.Û;―Ļ:@Ëá[-凞–―u+ĸÂ‘Ī4óvāOË ĀŦØŋ›YP•Q'ŋĀ#$æŸKk˜ųNÖ=õŸĸĻ]ÚCŨ§‘.f]Ø[Kš.Ï,KžSõŋËģ>éwHMr$(-ôTŠK·ĮÕ3Č}jO—qŽĘ-‰s(>՘跊ÕĐĨ%<á{Á_}|ŠwRáĨÓwŋŅäƒô ņ§ÄĮ7ý쟟Ÿ@ PįÛīRčŲu-žī恭ąû„Ū( Mfiā8Éĸóoâfļĩ:Ôy”Æžƒ‰8E$5đæŅ“ūĐÛmš{ƒ.ðų|‰Dōžãp·8îRæ~Oïïuú( ŨÛuüđ{?ĨĮýšøSŧ}@âÖëŅĢënó$ŅŅŅnnnîîÏ·Įą\KūëZ8Íôu}ÝÝĒŨc­ĪępŌú莃ĖyÝ[hÉï/x°fKĮPįQ#:ÍÓēzŧāiņÞð[qfčųô]a^°â'{ę ŋÕP2EÜņððxÞûÆÝĸí^ÉUjŌcš|ÂŌļģęÜðĢw6+%îī--- -Û+ĘÝ" Ða˜\.;–žÛëã9–ü%M_îðūО Ÿ~äíu™e7Õgyhah‘8PWÃ:ÎĒéŌ―eĩųØĘxØwîFß+đŠ-Ðėņ6KG *ëW,Rkp·čhÝC*Ŧû3c/64$ĮōGÚ·4íåōšąŪ%G N**­yðϋ OðŊ™3Bķ9SáR5^$VëŨþ š"ņ ņ°;îÔJŠrOŌĖ`i,„:Ymã‹Ģ―?žāęíúĢNZHWhāg7„fŪæžÂh ņ°2î+9'hėø gF&­äjĢųx”JËuĩHÓÎ`(^ŽĮ úļ#Ũ’'EŅL€ýKė =ĄĮ—ËeĖÅ}7WJdbWsßËũ‹ÉŽTŲŧ:ž€3õæk[Ÿxî•\­•TŌhc@â`SÜ!9åw*D%šBsöe ģ.Ĩ7˜‹biíÞËUūTÎfޜ)9]+kCįÂŠŽŒŌ›­Cą <ßk†@ĩqGŦáĖ4õī ðØý&$ĖkĐUĩ7ïJÓôŌkؐxXwHnÅ]­†SŽģ}dš;å―§ÅS‡…ĄÅ …ĄEâRí9›Õ ˜ó0›!Āó·ZϧēēRđq‡äWÜĢi;#7ŒÏŦtģĸOLöĄ‚ŠŒ:Đø!1ĸžXZÃĖwēîĐŊmōž -Ðą1t qɁŲ„Ą M‹T}$îŦĐĐņōōrqqQâcæWĶ7$Žœ$ŌŲĖŧ%{ÏĖ=PTÍĖOô[Å―ÔŌ–Ž4-ŪĘÆP ņī.kkkĨ?fĨļ”Ķæúķ^hž™~;š>a(žöãP=æüÞšB 4OW ŊÕð;8 ĀóÂg<ŠĮėķĒ'4äFz;œī>:ë`ą2ö5Yōû ŽŲŌĀ1ÔyԈNóļ1Š Ú]šJdbl5H<,#“Kĸĸ,íÏĨVRđęÜðĖēD•/ å­Ģw6ß|pvIĸßp°>āxâ‘H$§OŸūuë–T*uss:tĻĐĐ)V9Ļ›F–ģýđš―NâŽ- -ŌßÎT ó}–Ŋƒ }žûŖŦOŒ šwïÞWŊ^ Ĩ™‚‚‚}ûöąũéTTTüõŨ_ĻWŪb>„Ļ—ąý‰DgĀ"ĩ*‘ĪZ ŧ|)Ŋ/ėßŋ}Aspó3žŠŠŠŨ_"Ž——sMϞ=YýŒâââēēēzõꅒå$=ŦÚĘʇĩ…ĖŅVXŠN**­y ļ(ā ‡v˜ÞÞÜ/îþ‘ËũSÕR5^$ĻŪ{HS}mcl5č WŪ\ÉĖĖD_ÐôÄC5ýÚkŊ)Ęš1ĐT‘ l°fÍwwwš~ÛķmtGąX,—ËŨ­[wāĀŠÏÚÚÚ[ķlđđđ?þøcqqqjjŠD"177ßļq#ÝŦþeĻšú“O>đwŊþ8rÆÆÆtw{{{š_štiũîÝwėØAótĮ7ß|sÚīiĖ’œ9sfýúõôøôP+WŪôũũgnOáÖ­[ų|~iiéôéÓ'L˜N pþüų!C†ÐFûÍ7ß:tHGG‡þî-Z„Rf5K}‡‚ĘŒžŠTË@'Ųŋ~@4Ę{Ņ+æh5ˆyݟãŊãŒßĘĀėnĄoĄxū0nÜļč ûũï‰D2™ė‹/ūx–ū°aÃKKË&}ÁÄÄdíÚĩĘí ‹/~l_ĻĐĐ0`ú‚Ķ$*š>účąĸëÓO?ĩķķ>vėÍ'''SÝ\ļpA__ĸÁƒī=œ8qBWWũΝ;}ûöĨj;~ü8Ýlɒ%‘‘‘ĢGĶ0ī|ųō“'OŌĸĨëOŸ>ýÎ;ïÐ@ó3fĖ ÛīiÍĮĮĮSÞšxņ"ĮËĘĘĒ­ˆnCKÕË/ŋŦ‰'nÞžđI aRpaaaã*Œ‰‰éÚĩëģ?ōÝŧĸÚÓ"55ÕĢÁõëŨ_éŌ%Ÿæú–ŊŊorrēY#ۛ[O|ūâý„Bŋ~ýŽ;öÃ?°wMåää`;ĪļãeŠUÚð Ž~"a^ģ°H­įnŅe™\jcč‚S°Đs_ ‹L_ļqãúOŦëÜđóĻQĢFŽI‰„đĶĒĒĒžžœfĶN:þ|&ŅSŽŠŠĒPüėœ••ĩgÏf~˖-!!!ú žzõj™LFŨGFF3ûØ?É|°dɒôôtæbbbâĢ…Û˜‹‹KllŽbsbvþ'”īLLLXšš233oÞžÉ|™ ~vƒiš{‚ÕÏĒŧÓČQÞ Õä‹9Z ZZ$ÎIRaýÞ~Žšc{QŦū@/eč ėxoÉÕ'ķ`ÁŠ-Š*hĄPhddītéRSSÓéÓ§ĸüóÏãĮ§ĪïęęzðāAæƒĘŽ;ZYY)îÞøt/úŋĖüØąc‹ŠŠFMo‚ƒƒŨŊ_Ï\ŋlŲēmÛķŅæ$—Ë―――Gĩ P|,ĐÕð]ŽVÃÎ:;vė EŠŽŽÔjØWnŊĖíĩĩĩ·W,UïÞ―9BD[ėōåËiãĄøokkŧsįN–ƝĪĪĪîÝŧ〧Œ`ĮáŧŊ}šRtųAå=[#7ö>‘W;/t‹Î:XP•Q'UÍéŸī:6†ŪĄÎ̜L;sĐH˜ÃųÛÁöŌÂūPVVFŊīûÂîÝŧŅ8GkĒíĸęĪýõûŽm™j ÍĶn—‘‘ĄQ•ÔJkJwĖĖ˰*|~~$―‰ÞņÃq>K0ÐtŦ)ŧđäũšBƒ­Ŋ$ëô8öėŠëʧGÖïaóÓØBv-đĶõöŪ)-ŸeÔũ…qį úŧ―IÓ?3öâĖØðĻčŽúCžøÛ á^Ü@âÄÍä8ĖLŊ]YmþÅôÝ hL,­đÐP=\Æb4xZģģóÖ­[1ˆ;­DČŨyĐÃ{4säÎF|Ė]ĖØS).ą5róģ„Ņ@_$žÖ,>ŋņîf€ļĢtÝß2Õģ)ŪÎ9›†—ÂßĪrÉДí43Äó/Úč €Äˆ;ė§'4ŲĐþhũû?įØIŋá…]HĸųAå=c]‹ÞŪ0H<€ļÃýÝ';™vŪ•TîšķĢÕuMü?­†ŸýS ƀ ņâGxÂĐÝūāņø—ïĸŸsĒáßþĒBTlkė>Ā} F‰w8ÅÃ2ð%Ïé4ģãƜâę ˆÆJ)Š=qwÍžÞuEa O‹œK\ĖšTŠK·DOÅïķ4S­ĪōëËïËåē§þv8Î2úúŠ­^―úîuøða âNëōuf…~g mšV’ðMÜlđ–cĒiū―2ŊĻ*ÛLŊÝdĸ5 ôPÂë*†āÅėŲģgĈ%Ɲøøø&Ũøųų uūMŦjgÔþƒîߎûkBTÖ3}Û ū(-Íq,yKLö!ĸ~Č6c] ú ņ(ÓŌĨK{ôčąmÛ6>Ÿ_XXøîŧïNš4‰ŪŋråƊ+„BĄX,ÖÖÖÞ―{7]üã?ĶL™BĸwÝšuVVVüqrr2ÝĶķķv͚5:uzŌ_‰ŒŒÜąc=Ž\.§ûzxԟ ĪššzΜ9yyyôŪŪŪĖ)|5H$jrÍĢ'}S·Ûī6ÛþSŧ}ąãƜãÉ_ xBœoKCPÖŲ{Ģþ’ã}—uķé…A_ÐØū drUxcŸýŦ—ÉÕ@ßū}™™É“'3†ŠŠæiÚ§OŠošïÕŦWAAs›’’’&ũbĪĶĶ23)))Çor›?ü0==f.]š4zôhæOÐ]BCCe2ÍO:ußū}ĖĢĒnjŒŒŪ^―ŠƒóÂk*##ãĉĨĨĨrhąĢw63+bũõe2đ Âmņ9'&ĸjGŦûÛ+s5įYӋ SäjēöŽąąąGŽĄ @ äææ>éņoÝšõßĸþ—Ïĸ;hR`/..ÎÎÎĶ*o80˜Ėģ Ðƒý—•z>0Ō1ĸ.~~LöĄüĘô{ėī4p°pĖow6íŧđŠfÂf„lįó5ï 43sæĖÖč t/Nö$5ĒĻđÆwïÞMõ·qãFŠË0a\áįŸ>zôhxxļ——ýŊaÆ=éņémÁæÍ›_cdd”žžNqŠņ•mŋŋBúëÛ~Ē…ý—ŅïĪ—^ ĸ―ßہ†aXļĄVRđãƜØėà +úõĐÝÖ#î /4é Í|JÏš*1ÏČŲŲyýúõšĢĒǚ„’]ŧvmÚīĐK—.TÖ555ÍbÁÝݝķģF„B!=ō―{ũß,--3ã†Ŋ·”ȧ]ĸ•ƒÏļ˜ųT‰Ë6E―ĩ9ú­’š\ ÛĨņĸޟâĮįþvā&ÄôJ<ÏØ<==5­/ ņĻ)‘HtîÜ9&\ÝšuËÉɉÉāĖ·đLŽ9{ö,ÍPYōÉ'úúúOzī>úhöėŲyyyĖ푐@3šššÛ·ognÉąĘFčQ"C—ˆ'Þ> îwĸčĒ“=§lKk12lT!*Ų™°pÕđá•ĶzÖ {ĸ2žã Ŧû;w˜ÛP :sæŒĒ/4s~õyóæÍš5ëŅūÄáū øVKŦWŊŋüÐļ()ĮXYYņxžĢGŪ^―šęĒĖ‚ ˜ïVWŪ\IEŽĢĢģhŅĒ+VÐtïÞ―Tî~øĄâ'ˆŠGöņņaŲßßíÚĩóįϧm€.víڕþ(ÍlÜļq͚5#GŽ}úôųöÛoMMM9zīðõ–ē6ZūÎxßeAŽÃū‹ŸŸUvkÏõeĮ“ŋÖqö·É:=Œ+TŨ=<™ēíäÝm5ut1Øqø”€ĩÆš–ķũ…Å‹7î ŋüōËģô…uëÖ=Ú6lØÐļ/|ũÝwë m§’]F&í·Ķéö‘ĐÚXjMđk bV.™\zþÞOoŊ-Ŋ- ‹&šV―]Įũiĸš―ą'GmåUĪžOßu1}OĨļDŦá8“ŧŪô·Šņ°|zdý/›~[ˆ"Ášj­·‹XÐfðIrņy‚îSzđŽ?“öýɔm%5đĮ’ŋĪ–AþvC|lûŧšųðxøæZ-ä>įØÂhæK‡W:ÎĄ„*äë`|xĄžBG ũr‡ũ‡xž}%įøđôŸnį_L-ŽĢû?3Ō1w·ėfgėáhŌÉÎØÝXŨŌHĮBĀĮ^ą­K$ĐŪ‘TÖÔUVeæ>LĄŽ“V’P\ĢeÐ iÁŽÃ‘uxĄž€Ŋâ4‚þ•Ö<ˆÏ9–w*đ0šR\z=ïú‡ņQ9>Oāfāo7$Øé[#7  ô@‹˜ëÛō˜FĸĪrIFéõôŌëũËï<ĻžWRS!*ĐŠ+“ËqTV§'44Ōą0Ó·mgäę`âåjîëiLWbdx@sCOhh(~€Ð<ĄŧE7ú‡Ą@⇁@P[[‹ÄH<ĀeŽŽŽhøå* ņ ņ ņ ņ ņ ņ ņ ņ ņ ņ ņ ņī ž\.oûŋ:iŋ5†žEzšŒ{/ø+ŒīąīvÚA'Œ‹ôqðNÐfv-ģj>ãáŅĀ—2ũ-?û2ÆZ‰ķ@}].fėa]_PÍg< O†æUĪ*.Žó čþ H IduįïíڟøÍ{X.pcč č lė ŠI<ŌÞqeNãkĶŽAqŦ­3ißïLXˆÐč ĀÞū ˆˆˆhûŋęjî[.*L/―ĶļæZÞïĶzÖnþ(#5Dë…Ö­Ģ’šÜ›ųįúĩcč č ėę ŠI<ÄÏn0ŠÅ €ū€ūÐ6Tó­CŪ%ߙ°ðlÚÎÆW>ËĮ˜Ųå·ÃOũĢŧĢā”ÅÞĪÃ:ĖėÛþõæo†Ŋ·}}Ĩ}AeŸņh5übëÅ=Ý LTÐø^ÐBĒâ„Ü“u2Q—v}đ”č€]ÐÐļ™xZRÜÞ Z.Ĩ(ĄXzÐÐÔ:ņžpq?ö^€â =č č ęžxPÜ(nôôH<(n7úú‚F$7Š}}A#ŠÅ €ū€ū ‰ōâ@_@_ЈăâFq / /hDâAqĢļÐÐ4"ņ ļQÜč č ‘xPÜ(nôôH<(n7úú‚F$7Š}}A#ŠÅ €ū€ū ‰ōâ@_@_ЈăâFq / /hDâAqĢļÐÐ4"ņīĪļýí†X8äVÜ­—Ē(•XÜAŽÃhðz}Ôđ/ðär9TŪ%ߙ°ðlÚÎÆWN X3Ðý­§ÞW,­•ČD(JĨōuuzÏrË3ißÓ*ĢËĀeN`č}}Ą-û[O ‹TĄÐ@U}Å‰‡ŝ]~;üt?z/üö&þÓafßöŊĢļÐКÁūýxþ•Ũ^čŧ[õAËY&*hÉ~sĒâ„Ü“OÝML}`Ÿ@_@_PI_`wâá@q+åĮÏēopœ@_@_hÕūĀĩÏxšOôBūŽģ™·ķ@WýŸ‚€/Ôč―Ø?š/ëV>éôô…Ví ÜüŒ§™DŽ€Oz}”ÛļųO3‰X=ĮïdÝCč  ”ūĀį|qO X3Ā} j…ubēa}”Õø(nPOyĐrđ ãč  č H•Ķ @_E_hŅ#pxÏeÞC ņ ņ ņ ņ ņ ņ ņ ņ€zø hÆ>――‘IENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-perform-installation.png0100777000000000000000000005102513761647206022557 0ustar00‰PNG  IHDRÎGæąmQÜIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/b­=6ŽĢŒÏĖîí=í;Ÿ;ņÅŪ“ø•ÆyÔ) īTĨ6Đ D% TRPå6vBđy’”Šˆ ‚ A…*ĄV<„JDBS!ĩ" ((Ä6Iš8Æ&įžíøÎũڝ™Yæ<ĘhēQ þ"­fgūųæ·ŋý}ß­ĨčþQŨđžôŧZŦ•anĪZšs}ĐŦ•ŊūTüŪÄÝëƒØ,(ĨL‚óPĐxO,ĶÄēKŧl9å0Å "Á8u(Æ"’sŪķâņļišÆMˆq,WŨuoĶŽ€P MŌÐXk† p‘ÁÉŒĻЋ[@(b …čŽ<ÏWđ*Ū„™V’‘jĢ{+TĩĪķ((Š2^č+Ąļ‰%Ŋ oKęVr֟ÂŊ!*ƒ ÐĨwĐÅ%Õ~vÃÚ §ŽŒ8-ÝŨæ9ÓïžþMšvÍŪ‡^Üö™+ï=3< Ļ[‡2ņ%–§ó8v'gŒõ_ÞýԆĩ^đāVDĀņæî­;ũîŲŲ› Ģ—Ó9Ξ2ÅuËéýúĄŸūįíGÓeäˆ™ŪÍÎ4ŋ}âõtŅ!āq ”!ƒ^~ũÔ!―ŧũíÛ`ÝĘf3œÜ°yëþÝÛV'ß?nÖŊztÕÂķîGwôŽCĖí"·ÝK>qę=įŲ݇ūąũđfrþ؟†(ónLäRŦ7ÜÕÏ Œ*5"zÎÄ?>žžI}hã {ûŠēC—FĮ§ÆŊ]œ ­ûâö=[â0pĸ§Ö·6·öô?{_KēõþO>ŋkOßÓ§ŊýuĒ@9T‘ƒ{ ƒÎ\ýÅŊOÖ?ļĨŋïóđKAˆ–3mk·žðô'jƒŒ0Fą―čá͛>ûÉũūųŌË?―šåđ+<öæāãÏlßúDŨ…ÓŋMukÚZ;xž·ũKM Ã)ŲB—šŒXąĒOđXvŠÛŸÛypߎ'Þ:>8^6 §ŽŦûGÔŌ\ĸøŒĄ;_ŲF^õ0Ýą 2§Č`ݍęhåRýV/_ÕȜÂąz€"ŽRŦŠđˆųĸ‰>ūZš{}DØÝëƒ0ÆjŋœĨRĪ*n,h„-K`G'\Ō›ÜšÚ@jĄp 8S'‡…+#‘ˆhŊÕÕÕUUUŅh4ˆĨ™ũžšX}Ā ÔDŠ"õĐXj~ī!ĐAŦ&\Wq6ŧ…Ĩ &ÆxēËčFŅ_€ä#ÂԋPóūnuÛl*@æQiu}|c]kuŌGÆĻ[™Üį'ĨÏ܎ĐbÔ+ŋƒ>:%ę2§˜ķ~øeKz8ÎKŽ]ÎïÞîfį―h}Í|#_ķ)ũ‚b•G0‘a‚‰Cë:š—Î 1re•đðÚwŋóōŦGĶm`B&N Ķĩļ―Í$ļąĢÍ–&f05ƒ­í–Kī·"Ŧ81ãˆ<^ öŒLįĘÖÂåõaX,ÃRnôwG_ûöK?˜2ŽJĢ& j!ÎÛ&.ƒČËÛļŪĩĨ:ˆm·ĻūŒ‹ŪCCó[W/_ ģ".7Ÿ—VZ-€\<ŒcKVvßÛ FMŨvęŊÞØ=öÃo~åÉ‚Ã0 ȉƒqyčĖ›ß?|øĮ'Ï#ā2Â<ÁšģŲāļT°ðڙŨðę mHX€BĻaåšeóDĮŽH._(|Sï]ÏXãį~õËãŨþ™ávþ?{åᧇŦ“ !!B5ÃØvĶĒ•üЂBą…/[G4P“ Á‚#ývĸĻIĩĪŨ—jdsŪūtĸH7*óČ―Ķ|ÔëKŸũÛ^[š›Dņ”Áä&üu­Aë”ÔAĸ―>úYŠļþú đ,Š\>’8-ēbÕh,a/h‚흰ģ ķušM‹Æ"ņ@Ũ 3Ō?Ö‰DĄP…B ķm‹l†.–@sē“Lō LkkÃõÉP] Dœ NUĩ!`ȄĘr ™ïÖũ›&û”þ+$Ą‹(Ī‚r^Ļxđ*Ŋúköé# ïR/OõJßoĐ⎍ýÖW™åXŅГˆ-ĸ‘>âÎ.ŲaË4 h @Ģ*ļø·ũōØÍeFō7X2j2—aQþåėåŋæ=Zų q§XķLļ€ ˟<ö–ÝĩĄŋoKs"ĘJ@dŪ§m‚‡†Đ8ōeŪ—0ū*fŽÆĶb„ÐŦč ‘ËQ<ž@Sƒ—ŌYBĘŲéÜÐŲãKŅŊôo[“JTi‘Č„Ï`A^ö9GÂ‘ŽøïšSĨōĖûé‘L2ÉôD쯔 čr ęRą‰5ŊÂŲ„nĐTt( Ōē Ø]ûÔÖŊõ?™<{nøp™C&ÔÎųýĀG6oïŲôHЃ.å‚īNũžŦfŨCŸÛ―ĸĀ‹Ÿ_Zgđ@– eĄzÓãŨĮ2ÓąÔōĮlķģӍ-ÍáDjÝzöüęÁ=OÎģ<ʙ=™-‘ŠM\ %ųĖ•óĮ@T*ņBz4kãĐą@Ëωš„šüV(“čuÝŲ?*Þg9ŸtĸčðĒęK‡^G5#ã}•ĒSmDßöSÔũhšÛ|Îŋ­>’ųŋÓGĸ{ô_ŽYÛOÓnöŸûy"ƒ=Ūíš–-0S3‹DH‹Á!D‡ ƒ 'Ë [éaëaŽĸâ%ņð“šjzÃÍï―øōäýžįyß>éÝũŋįãîö@UUMÓšwÕëõĀĐkZsyIž™šþøágŦųCØ3Š…/…ŲŪ(vuð͕čšÞh4$Iob···777āķ^Ŋŧ4— €ĒĘeaém5Ûðýë]ņ{Đt2ųĶ’ïČ"ðųÃQpđŦrM<åô).ßý /ūŊœŽP9BgO>āþÝÄģ°ÓôĪáé€YNh{ōĖ{ōđ8A…Oį–ÞÕtĢÛiæ#I8å*ÖĀ–k•D$Ã(Š‚ýčósÍ:yŋ€OŋÝ51LcëåS_JgSˆÍLW;R„>ŌL*8–\?”–4ƒÅĸ{dØtȟ,WeÛ6K9<Ëڗ2G +gv_]-Ķ~ûhnqëh‡GüÃ…36: íœīNũW ðŽ?ÁwZÂ\f|c·}iŠüģÉŒĄ0D°ó―ūļŋ‘%éݖaIĮL<ķž]ÓMÃų Á9žßo›P™Ų―3ĢĮYŲĐ5„2™@Ō,`SuÉ4Ôö !ĖöAĩ˜ACp’ÉN`‘anyóīyHcD]ÔÞq8ŧf}ŧ’„-*0‚S4E‘› M^Ahą%ýý@Ūks4Œ,C†ĮāÕĘéՕõy}>0ĨÓ4ApĮ’ŪÔJQŸâ _ëˆÏ?ņGaŠM%Ã8WîÛæZ.>4H§(<ēø‹YŦg‘"ĒũO/12šÐD4PDžD D”ó4ÐāövÕéïŊęŒŽoķĄXfØãĀÄ ššŠŨÕŊÞVGÛŊ/KIëÉ<6?°Åüð°Áþq~dĖâ~ņĀÃÖ[Öũeqŋļ“á ŊGîŨRĸGÆ,ôað‰Ų›R h8RJ0Ę1ڏŧgOŊÜŋ~ōXŋ{[ŒÁnĀīÖÉ~ΟŧÝnģŲl·[T@ÕõÞ:ŒĘņë·ũŊ>=zþáÞˡŸ7o\4Á‡NãÉ~ĸD–SX;n8A&Ö}øŪ5Œ#‡x&Ðã|âZŸci,šč?áĒŧ…>(Ž―\Ÿû‚ŋŌ‡ŨãúHSJŅïëijY Ąm§†ęˆĪč„ÖĨ­glˆĐķÜÏčhcKEJ*‡í ‘8ŧsz~qåītЌ-GĸcŽ\^{-MČ­D­Lž-e)咜õ‡Ŧ@4eÄE+›ƒÆ‚^ĖĩD'ÔwԚĮėú8§(RĮ)8FmĖ{R6·1Yþņ mh Đy[­„áŸ1ĩƒT˜ÅTTkšļV "âxBÓ`Ą\ – *)%­t,­æ(†afãm ĘĩÚ.OŨGJAËa·ûîf4AEVôZãÝtïß\~Yī|―ņywöÃFƒËUųĒÅĮ #(įīÝm]ü°Œ ŊIņē’ÅLvWB‡ÂŽT‘Ŋg?GņÏęnë„øŠĶÆ!ČýbN,1چ°)‘ðņ=åþ><@ƒĢŒŋþL  s ˆđĶïʧ‚É?ŊÞ~]=îĀ@ÂāýA+qÚÁБû“*ĢãïvđCķŠïģڄðÁ°°þ,ÄSęJų^ÍņáCÕH>|€ųAJ Ýķ-š_Ķ8ŧŪģ@›Z;Éą“ŒĄGmH§ģ Į3Ë&Ž&ÍB ýé†ĪÜĢ}JCIBJÔIëÍĖÄŽC|ÐH’m2Ä'žã|ˉßķC|4j>―Ćøøvēęp&ĸ%ÜÞvüN|ļĸŅʁũ~{ũß#ŋQïnnZĮäãč“|0*>x;œ` Ÿô79|ęîģ7ä3,f>Ë)[$ũG7 ‡ōQ*ï‘Ýãîaŧ&t6=ŠžšĸqšiáI>čþûSAÏĮ㟑Ïí‰Ï—þ^>Čq>ŲÓãŊóa‡‘|.šĶ™Ïį‹ųÂGôl:[dđXrDO§Óųlū\.›å>m>žUģ"„‡4 KÅc+ zīD7Ctāå֘ÍfØ ŅdZ’Î8M&BZâpg^lå,wÐ_64ÍđjF )t=ß2ćĻ"KJ>zäC!inr‚OąJ>8ÃĮÐ>hGÉĮ#6[qDŽðY5 …ŨŨߛEÁgķĀ…g ėðÁ ߇NÛsøL{ø`ČĮdōAĘÎåýI2"Ÿ$P[>m1š_ðYÕũ'Ck>(`^7Íô›|ï›L†øĪaI C:|ðäƒ!įðA0óøĻĐÏg–ņeBîOh—|ðČÏq>H/ŽįņÁ)ŸLDÐÏø />>ɧ'™L&čŸ~"‡Å(i’>ØešGu}ŽóK'šþu&Ŧß*#RđššZ§ų Ã|Jz%ŋĮ—æƒ:‡OÝĘhÍGÏ ōAžņAīĮó‰>8gˆOfãųËø`Ÿú?{ũEĩĸüũŧwʖT:ĄKPD)*XPąāS" *"*Uʓ* *]ņQž" ˆ ‚ M΃ĄBI()ĪnÚîÎĖ―ũŋ;I„ þU,õ~N wîĖ|gvēįëœÍŲlņ•ų™įÏĖßĸųcûģŪ ōþĐė?()Éë#Ŋôg€Œ?˜$I’$ŦV’$IV­$I’ŽZI’$IV­$I’ŽZI’ĪßNV­$I’DāŊ@B„ŋ{0Ĩ”øÓaá‘ņđXš#@†ÅátjŠ‚ð?%IŨ4)3++ۓ•‘x&øŅm įÎĨedfgeþÆĖ {žváČĄØ#qņĐiöÔÕ'fåääxēģŋ_ödgýôöéįâccž>—úk›iûéÕŲ™į}0wÎėw?8‘œzâۙ“§,]ŧõ|zöí$IōŪVBT(O<ļáųÛÜŌėÖÖmÚīļĐIƒÆ­‡-?ętĻpÕ3|>ƒq@"ōÎ ļŦUŦžÃŽes•ļ*„Šg·-lÜĻQ·AŊæ‚SQu–vļÃC­ŸļUŠðCčtÂîåsnoÕrÄÚãšBāWœ™~ŸŸ‰ŸžKGĸ…ĐSĮŒ:=“ĐūôÃ/ŋ2tņúoüD' Iĸ3ŪUĨJüæđ]Û=þáķ•ë5ëöTÏö-›V-Ķfy…Ē8]N]Ũ4=øQC8œî°€—RÜoTҜîādĻ[S):ŧuųþý·_ðŧtJīˆ··nÓô† đUwJœRÕæþū'‰ĒŲ1n]Su‡ÓĄ)p9ΧŸ&)Ų$„úsSOÆN<›ûšœNUĄšÃŒpéÂâĪ|•:w·nÝļbc u:JÁã†^ĘGĒ;]…Ī8ąāypς™Fūöfšp9U‚Hŧ†††ļ"2L#ð…Āo™ģ°øĸ .{k—S#Á)T [WÍé sS„IV­„„įy{ô”ÃđŽGzM ü5ĄC‡Lþ`ųgŸ―?ð‰ëóÎÆū;åíåŸmújå” :æQĘŌ·GvčÐá‰þo8ïS"ðSû6M}ePįĮ;<ųĖčuûNMËNÜ7kŌ›ĸýčĢï―ũ醖RįžŧÛÞv}ļNļ7ûë•sį,Ųváäž1/õ|ĒÓð]§=” ĨJÚņõĢúvėðÄðU_n]đ`úûc-p‰@⠔°!Ŧ•DBSmš:sÞ·ą ëūŅąc§W§ŽöĄ­\―u›;nŽJˆïŦåóįÎûāșÓ3=Ũąóģl<ŠŠJĻ"ž™ŦޛxPOõč1cņŽÖÉ]ë'Mš>ĸÃĀ+ïĮžÏöå'<ÆSÝštčØyââ 9~vÝĒ ŠŲã@Ī’zjĮk―Ÿ ŽŸģ6Û Ėčy‰ßÍgÖį;m˜ýÚÓOŒIČãˆðO!ÉŠ•iޅØÏŽfĻ՚ô~Đ}‡QāõähîðR‘!ÞĖãã'îólŨ§L\ûÕ΋™gF=Ý―ĸĻũö|}dÃ{Ŋ=ûL·™ĻōžUC†Ï^ŧųLÖþ5KĶ?ýėoOd$žØûÕĄ °mųÖn:<ã―}MžŸ”O4æųę“·‡õíÔæþîs? üš·† |' đņkÛ=ÞëÍđ+c~8ōåįú 1ïËïL ?%ãÄÆŨFîøpۗÆLĸtåŠ‰Ģ†Ŋݑ ‡Šņ_ŊÔoĀ{’œšĩé―w†îũðýíÞXīlåōEý_ymïyo(dŋ?søsƒĮïÜîČĄíï,ÞmúrŋÝđÕc"äe}ôîâ“ųï†QÝkæœÜąIÛ§>ÝF-ü|ÖļÎÔë%†%LF)€b@ÓûFmÞžŽaÕÐS§WŸÎ,øō―7O$zšwžcĸÉĸŒééō3ʁĀ/…D3ü†ŠÕ›ōß/æūÚØé}'›œĻœqÆU@·˜a°ðFũšycßÖĨžĮŽž=“åófžŒý6Ũņė°Ũ?]ŋkũGƒœzT§ž/Ô­^ĐîĮߎ}ôæ˜ōĩï\óՎÕ/ûāý7Šø<ĮÎĪs?ÎĖY·xęŨ'2ŸúþÖuËÛÔSVŋņÉŲ|ƒÝ4-nDũ›īdÓæYÕÃ(ðO"ÉŠ•˜^ŸUøIŪP’égŨ5kó\ũ.uŠ•cŲ9i‰‹ŧī}pڗĮÁ°RÎĪ̆ĮũŪėÝ­Cŧ‡ÚO]y@EB‰Ēi jJáO.…s Š=:á'ëV­ė D ‰―€ĨŠ5o_ƍe*T. Ū@T‚Bačũ7ĩŌwŋ0ä‰ķ *ÄÄØ+ŠĸÁĒM,%žŌ“/ k~}Ýnj“ïÏ'á1wĩkŠ&}þąöušóé/EU %HP…j]<6ehŊöíÚuï7é<EøQˆĖō? ŸNõhŨįvžČ؛îE ôZ ėßŦM­ę•C( øĮdÕJBgx…ÚaŠ'.vÓö#Ls9t]w85• Á!Y–Á-a `ĨŠĩ8bˌĀk°›V|ēQĘÏžîũę$>ėõi=ïŊ ˆŠ.„]ĩšŪĐ?ęĶÜī,&8·›Ppb°ĖėL@ČJJÉüÁ“FpUąē0MTq84bßąZŒÛŦ Jš°‚āĮĒÐö§ã$wÜŅéՍ_,ïÛåĶļ=[Æ î―áx%Ā„‚šÓI™įÃÉ]gŊ8ÜĻí‹oŒïS-üDQ~Ēm š?ÜyÄŦã/ĸbó†e7Up2. q€iXÁ…IV­$,­\ã—{Ýã4“G 8iÎâûbwo[=îÜŦâT‡\0.„É՚ë–Ō0#>ötr^D„+')9å|'9îb>/[šI8f:yĀúĖÉ‹„P Ö}žrïĄC ƒ’L&ÄĨeÚĪåuYۖŒ?~\ĸ§F$\ŲfBč‘j•‚Ã;wÍ^ąæðÁ]KgĖ?™š_―Z4f‰āY ( ø~ÆÁmįÅÅ+‘įĨėørY2ŊØŦĸā'ïo`åĪy ?QõHAēÓÓūøøó“É™ēÁUšjĩČ3‡âSģrĮđę·=ÞąeÕßĖx°íp_ôCUÁ3sė›Ré=ũ?~s™O§yiė[9âd`r&ģ,  P f1ÆLf‘;_œ8ĒG;ϑ―#gŪŪŨ―SuKˆ’Mk…Vn1îØf―o=ÓņŪ6ũ|ĸËÖŋņ|K°į ļÉŽČ0€*€ĀBHtÎMË,\ə āPU—ƒŽý`â#ũß{ÏC]|qēmŊá­Š†šŽ˜=;FeþüĢóūJžĢË3áūýCŸybęöŒŠu+_Üž`Þæ3šĒ˜Ķ^ÚĄ`a{;”p$īÕãC&―Ð!nÍ܎ī―ïūštw$Õ$ ,ËīĸX’|·˜”å HÝŧsýŦ·j͗ßîÝw.%-=åÜî]ŧ9™^ôķŊŽžœĖ‡ũo ~âᆭŧöž>Ÿ’••yöxė– ë·l?tálâūÍÖoØy.5#++=îĀÎĀ'ïØ›–q1nÏŪ―ą‡“Ó23ÓSOŲŋ+öøÅôā8öĀū=û\HËĖH=ųeāĢrŨnøjûöĸžþžЊßėä OfÉ·påx<'XŋæÓĀ<ŪÛôíéĪLOvV`>9ņÄŪ=ûŽđ•y>!~ŨŪ]'Îgfg%ŽßŧkW\brā|N<°{ïþ3.fef$œ8ļkŨwg/Īee͟:q$ðÁäŸŊYŧiÛŪċYöÛäē2/žß·mKāĢ :›~ņüÎoķŽĸōŦã‰I‡öï <ÂïN&gĨ%}·ßūĮ.fdĶ%'Žx,þlā1.ffڅ―;·­<žM_íÜ}ôÂÅĀęýûö|w"Ņ~Ú?–$ĸ܌”™™]’Ý ™ö_ģ.ß.+ŧˆ';;ËÞ(Ŧx*ŦxTTĖÅģ…m^4ooėG[ņ&žs{G8ÊŨŦĪ€ŦÚíË6ÍÎÉÎ(áRlņŽEÍeW\ŅųØcOŅ8p°âq–}ÎÅĸŨLíMJ<ĒKĞɾôPŠ&[Î}ĸáËOĶødgĨyė—$YĩŌĸLfú…ø/æÏ›3ûíYoÏyį―…Ÿï‹ô”lĶߕ$ŦV’2ģó}þbū‚\OÆïM’dÕJ’$Iēj%I’dÕJ’$I \“$UU… ŨI’Áē˜išðk(pM’=ëņxâââ)%Ũ I’cž^―:!!nËēþÚU+B22ē""Â+UŠČ9‡kƒ$I”Ō„„ÄŽŽŽ°°yWûw€ˆŠŽŽbŒÁĩA’$UU=[x$ŦöoBƒkƒ$Iœ‹€kņÏÍH’$I$I’$Yĩ’$Iēj%I’$Yĩ’$Iēj%I’dÕJ’$Iēj%I’dÕJ’$I H/ˆHAD$é§ !8įBYĩWC2M3#=Ýï+@$ IRI@Ëē\.WddĪĒ(ējĨ_—˜š‰Ąe Âå$IB@ŋ/?ëtlđrå―^o:uęŨŊÏ“U+ýęŠ―˜–ĶE_Ŋ†Wð“þߕW’92įyŲá ĩkŨūpáÂŋ4h ŦöjHŠĒxļK)ð^þ`ÁڋB”\wŲֈ%'ðÚΗíôs9hOcņĪĖųu96ņŨÎAæ7N—Ãá ËÍͅŦ#ŦVĒ”úZ‚üxÕ Á…]mƒ‹W<3‰ŲsŨxްB°Â;.Ëąw€$8&ŅBüïsļüŊƒLPE!„(ŠB)•ŋŧZ’T "žt/Ëz 9ÁDpĶĻėJÜ<î…E" JæpÁágr‚!RNáūșž( dąH‘æ$B ~6'8Q"ĮÞKØß‘ók ‡ĸšHŪ؜ā2Ĩ”ØŪŽŽZ‰ ú9H?9đœƒā0`œđėĐ  īðųmG\™ÃÃŊÎ!X2‡3ŋCŽ]Ö ˜œs,Vēē%Á@Ļ@ČoÍ!€øŧä "ųđĸņ@~"‡ !ė‚Û9Lŋ"É@čÏåÁŲĸ$  Š(…=+ŦöŠIBóĒā(,z)” Ā ‹ļ%s{"ˆ $ˆ‰‚ö€â9‚ q åÁ@pāVa ―(Jä*€;„Ba PļFrAø 9„ þ\į ė;ŠDk;‡"’9_MŽ č`ĪĄĒ€ŽÚßJōpā–@Xü!ė"cÁ1rāÁ•ö<„ï @@\ÍíÅā—ļ–s ûDá" °Ãƒ.å ĀÂ°w$öĄþn9ð rÄUåp!øïšÃA\–#~Ÿ`rPœĘoíYYĩ!XÆ BEB .p{ĀPŧØ~é.0ļ  ėÅ` â“ÈߚÃđ°+ƒ!„°ĄD{_DBÁÛ!~k‚LG.~qAB~.‡#įvNpđdNpŸJ"89Qå7ŋĐRV­|ųąœ BÄā—íû›øþŨýB ―― —mTī/Áā’k:‡s@°sŠūЁËsŅŽšü—Ņ ð/ÃĀÏåøŲāŋGŽá 3PĐ*_ŦýM$‚‡Ŧ€ŠĀ+bQž`Ã{Û·,ZFŨrŽÅ­,ŅÎ)R2§xđ0ä s~Y Ļ(Q!Ā9—U+]DÁYyĩĀ B€$I%QĶPƒrÎ „ējĨŦÁ9ŊPūBΙĢFĘI…R@’$}O4rΝ;Į9ž=—s.ŦVššŠ‰‰‰*É- " ’$C@Ž„sŪ(ŠÛí–U+]%BHhX8"ÂO“$IØā%ŦV>‡$I’x#I’$ŦV’$I’U+I’$ŦV’$IV­$!RJė %þ‰RŠ’$ŦVúQH…ü 5K˜/ïü…TāËÏššÅ@āï EUĸŲ{€ĖŸt!ĐĀ`’$ŦV* ÁĘųlî”ĩGģt…ĀĸO~€(Š?iCĸ^ģŌ-=yÍēgĶ|ėWņŧĩ.Yŧ—þúD‰ŋ@N˜ũėœ1#†ŋúęč‘Ŋž:|äŦŊŽņĘ[ûŽïÝwüŽCyŠJāũ&@ÎáŊ€ ’ŽZéG0cßËvĪøQĄšÃĄi›N ƒK6ĒhĸÎŽYĻ;4J”â5š"‰e%s‹ dzķ“įAýūÆMΚā°iī0•8.Ņ.ƒDwą›ĸŌ–ÔÞNÕGW6•Gņϰņ/ĨęjaœZG oĢë—ö @―ę žEs-ߚđsũįÃ!H Ņ*ÔĻZ­ZMqnãēõÉÕŊŦ^­FL„&RMÓOU…ŠßŸíũWI%ÅJžŠzųEVėÍJ΀ĒëI_~õd§Î{ðåQ HĻB!€…&xŲJU*•.ĨRvâ›/V­]·hbũ.―†m9•MUøģæëŨĩgï‰ģÞYøņ7>ŽXÜ@ÄÜb ąóKãbÓ,s?˜ýZ§Nú[šâE­=[>ýx˞‘C^čö°―Ō—ŽØđGŸĨŧ5UM‹Û―ô?ï/>ļs—gĶ­9€ŠĶŧvnNzõ’éŨ5zņØÎ•ŊYĩ`X—î―ïLDUUĐųųīq›ŋŲĪ*˜žŊ–/ÚķuÍË/<õ™i~šīï“Ą#_Öģį‚OķrĪ ŅË=ŌýŲįzväÞ[*6đĸĐn={õęTŦ”“„:2ÎïÜ­Ë˓^ČŠĶeŸÚ6āđnOö›Z ĐlTÁ”#;–/ųhî !cÆ}ëp˜Û?žŲ9p’ĢgËķ(Ĩõmģgž3#.H~ĘÜ“G1lāč“ŽĻ‘P+íÃYc›=õėŽdS!ųILz)p­^giWT•ïXöáę5kfëÔuČŽĢ)ÉËĶžØõɑ[eĻŠŽúdåĘĐÝ:w8qįųžÂƒ~ýŅô@ZïWgũ0MUÏ|ģbՆŊ>?ūKŨįWn?DQIÁšĸ \Ŧ9Ëv UË;{ðÓUkūZóŸÎ]šÎZšMÜũÍōŅ̆?ýd9ŸÅ*ö‰^F’U+ @ĀĘxĸ•~/ŋĩžBíjŧf_z0ÛwfóÐÉóšīmßšn4ZJC7F6hØĻJ”#%!ųæ{ĸuwĢüÉ/ÏJĖDļœŪ‘C_öųÖXJÕ û6ö{öđ]ŽfųĖýoÎûœóžũgœą/§í=·žųzQßÉ+ģ hßÏbއsFõyũhãÛïmQŋēÓĘY2ņđi+wÞûČyįô6&qÞëÝ­GĐäČØþXÛŧūĘÕ"Žø)ÓĶgSZp!ö́ý7æúĨ­·Ÿôulęîĩowģä†{*Ãâ; ™Ÿ ÞĪC#zũZðUӝ3{ú‚„ūcåŒĐ_'ÜßþŪcKF-ÚxJÓ­/ßéÛíß iÅŠ§ŨN_üÉqWtT•ˆúUŠ…B@0 ð„ßðrf2° “qĶ&ýÚ+o…Ôūnëc>ØkĶđïëFĨ[›ļÓ'ž6/!ŸÝYSâIØ?âĨūÛōņ†f‘_ū6t`ŋõ·ÞûPôųϞ~x|2›' ØĸËĀLÔđÏz><• ―ŪbL­ŊwĻ`ŸQ‰gΓ=&ÏßÕží}Ín*ï‚ĖQCúÎÞk=øČ―[—ŋõôŸ"Ĩ‡>ŋï—RJ5ČýfÁÃũ>ļ>ģžûčÚïŽŪ~ðK=ĩiû?ëóč›Y6Ž<øå-Íï{("aeÏG&$3’z`Eß§{ĖŲĮŠĐûÆ xÏ̈/Fýy~ŧö·Ŋ˜6æã‰Ķį䛟~aþÁú5é;ŊžđãDNĪ[ åîÚõ›Ô(öã/%Hēj%Á-_­ß˜w†õïŨĶžĸBŪĄ(UðÃņĐuęŨrjÎMïĻRĩÁ#];5­SŪîm·W s2ŪäĨíŋgáÓEŧYž–ïķĮ_~cÄČgŸļcvÆđÃ[Ũ}Ũûå]Ÿč>Ļûƒå>‹ƒ]@ī ųČW+6õ:iĀs=ž}šKõėÂĸÆ5aJŽ]Gë‘ŧgGė…lÓ$Mî0uÂŋÛßqSéjÍ_Ÿōzï'ÚUũ\ôsðú ŠÜÔzääIÃ'ŋÖą­ÝöM?þžVËūzt5rxÄþoķėNð2­Û;Lĸfĸ§;DšēŌsēw­^lq=?ÏtXÚޝ‡ýHó]žþÚĪW?ØŠæĐsņa5›ĩhVúö=ïnz‡ðŌ@Ķ(ÓgÜ̇üWƒšÞīÔÓûūYũÝEÕfݧ[â’<…U‹>_Aƒûš™2Đ}›Ļßėk>ēŸÆÅ}Ÿí„Z\ UŽĪƒ OœzzԌšu}ĶŨŋô”ý[ũx_8žsĮÓ=|rņ'§ ,3îé3aüaũ]WŠ\ã'fŒþxŦų‡æƒðZþ‡―5tøāsëĢØļS wžsĖ€ÞÝaäŪØv:WVŠU·SFŋøT'(8‘žžüáþTQý9–•v<öÄyff­VSߜ8üŗ*„ĪĮ§dŨhØĒV­†­Ûwlss‹qdÕJ?$„@·ģBÅRÜ2€ [XŽũ.™?§6?útÎkŽgqÁ,–aĄFŌČ!―–n9Č ŽÓ­ €ƒö—ÁĄ\LiĀ<”nY†N]€ü Ŋ7‡ 2\æÖ„ā&Š!ĄNphn$Ük˜Â­FUŦNÁĘ7]eĢë‡#–e!ESÅårë„:e5ŸO8a@ÕĄX&ģL.J•/3]Uā^/ŨUÍôZ-{ĄWû[DŨí ŊSļi1Ū„Y „ÁŪ8ļ——ĐUŧZ #H(AÆX„ËĄ~GÝæģfūąŒfq6DXdļK0-44Ä%ˆîP4äĖž -šĄðĀ”`y—ýjN@…Ķ8#\Ā °@:]š.·CŸÉ…_`ttó1]FCpT=L!€^ĀȈp@Õ݊Zž€ā@CíKM *„ðC­Ú5JĐ`˜r΀;jNï0hü“wßĀžFå*•c"]–iĻ *Œ1ËĘ0đ)@’U+]IX†ßnnú|ĖâE3‚˜ĐGŽå†wėŌQ+865/$ǜSK<ðÝĄä3§öė?Ðīuóš!$ĸÜŲ IÂoX@ou,ā–iYŽp`úM°Wy}FxÅú77Ŋ6zŌØĐ“Æ·(ĒnP•‚ΎЊõnš·áø™ÓÖïØûíÖŽŌÝ-pï‚wŽÄþāÃ%đek5Ļnþ<ËNóû}ÞÂ#š†!Üšv0öðĘÍßíY―lãžĖVÍoŧíÎF·žģõPÜęe‹ũ…_wýõ1Ä4LŸÁÎüĶIīð›ÛޟžįŊßâþûÚԊ΅éũš&@8q‹Õ9é[?ų:9ß@@ļ g–ßbPÁĖ3üFpŅg>?iÐīnÅlÓ]ᡇÚÕĐ…œWĨ}Î~ŧ―ÕĻ{*GŪøï’oŸXą`ZŪ§öõĩŪkđ|QáĖôüÜz +†;Ģ]ņmØu,Ņäˆöi™ÚļBį žýĀĄm·šåÔАþáēeGŽ7cÎį9M[Tw+Ķá7íŸ3|_p`X†7XîĶÐE+Ũė>t|éÛs―Ĩo―ĄVÕ;+E,]°tį‘ËLÜs7ŽØÝįõ ûp>Ŋßï*ÓŪJ­Üų7ÞŅîî–õ4•sÆ|>ÆPågL )–y(vũųĪ$—Hō/{IDŧŪQ Ĩ v[Ëæe]„cpF‰v0Ó3ï y^vóÃm\aý;ß?kæøðÐá};M>6ūa―.OÜīqŅÚ;ĸ]§e3Á ĘÕhRW.*VŊƒR‰ÛƒÕJ‚swđšMęĻ|~äÔčEóãrÂ{ôyxųy• ā ļIJõzybÆāO>ŒF7|mōŦýßœÏÆMčû|ŋðēUĶL}―ŽÎ*Ũ―Ģ į\”ŦÖðæüÎyD™j͚Zš@”_ōēÉCWXz‹ÞcÛÞPÔ|å\Îcúŋ@BĘž;ýõV1ŪøÄ*7504Á1Ž\ãõ\ mÜmxrÂĻ žÄõXï1ÝŽ\§qóōĄ įĪڍ­HT9#îÝôĖ+nŪðĖ=‘[`‚EÄ4―ĩiÁ…ĩ2MoiZ6œr.ęÞØ47&ÚUđņīĐãGL|ũé5ó°úGūP:,œ‹ČrÕon tā†Ĩ>ųú,ëŊöÂę[8īvXČugšo /šY4ī^8úï}ĐųúQsfL­:ej539ģx™ĄÎSÆ9tˆ;ü–Đ Įū9mŌĀQoö}þÓŌ7Üŧrčģš€ÚnņU-ÃđļîÆ[î,UQp^ūN“6fe„BĻ’ðõ˜A‡™ŧÞ[o G―ûäYÖäWFõ}ÂëOX4īŪž576csgéÚ­î@+ßš3ð !ĪĮ˜™wEWnŌÐp+0ō–;Ԅ+ęÅîOL\ķpfzåIãš3à ]%ĖČȀkŒĪëúĐSgœNGÕŠUcðë æÐÁô u‡fų}LÏpâÐΑũÛwŽŠî ‚sn ĒQ@ÎX͉šNý>M#Âg˜TÕ)0Ãīūā*āÂŋmÍŌíņFJļ`âėęÝ&Mč{ąL(„#Ќ Jˆeø,A5MÁ !ĶáĖŦZ ÍōŒŠšJ…ÏgŠŠ*n~ûņÔŨæĮūĸÅâ(‚3ŋa ŪkB˜a1N”Āķhø ŠŪRÃðóÂË9"núMXäöm~ðÁgX`'…Ē}›Îá24˜Á|~ëû3· #ļĢÁĖ4LF‚gI ‚0ý~& Ðũ§!ė5]Î Af™ĶÅK˘ĶÉ8 ĩ<°$AŠé*pA>Ÿ TŨTÆ8E4-?ã< Ë4,Pnų ‹(`Á+ĸj ŒšÐó.ao"~xPŠ9Tî…TÕUbøƒŨJÕu"8ØÆÔûqčšeú9Šæ  „0 “€Ī(J|üI!Dåʕ ÔUûO­ÚŸ‡ˆ „ļ|Ų^,/ĸBŠŠņ{ķ,_―ÍkŠˆŠšvjWڍœ—(ų‹Ž@)&Ÿ<°ûhV›vũļÁâ%wø™€ŸßÆū p5 OĸWoTrĶäâ7]+TëÛ5kY•Æ·Ö‹AÎÅÓ~Óã)Þ@’U+Ŧö į\€Ē*`~Ŋ\‚ðKŌ$D d!^ËUŦ€$ý6BˆĒZdėũ͕5ûË/\Û${’$Iēj%I’dÕJ’$Iēj%I’dÕJ’$I$I’$Yĩ’$Iēj%I’$Yĩ’$Iēj%I’dÕJ’$Iēj%I’dÕJ’$I$I’$Yĩ’$Iēj%I’$Yĩ’$Iēj%I’dÕJ’$Iēj%I’dÕJ’$I üIˆð"üĐ$IV­Ä0&8ðO€@ˆI’U+<-ÏJÍąō ĸ!T'åÂÕh·Ē)4I’U+ų,žėąâR| †§Ā„Bþž@!ĒÔ,­Ũ-ï,BUŠðĮ‘$Yĩ’ß)ŲV\ēũØOfķŸ3@ŧėo7Ēč?đ<§B@/ĒČķýIējĨŽëDšq$ÁãÏ7onXąl”SQ@ø‹nĸ|W2@0ā|~+ébÁŅļÔÃ*%*)åĶBĀB’dÕJ9^–šgĶĶÔŠVšT„8&‚ŊŽ)BU…"8g–É‚ ļJv"Ą„ ØgœsüĩÁĒāB€ĀŸN…Įá‚–‰rŸp%Ĩ{ËF;ŦGņ(7ðĮ$Yĩ’ɰĀ[`ęNÍëcLED .'PQyʑ] įR]ŅUŦÖŠ§åÅíøö|ã6·ŧuWGˆORvŪ—[UÝĨ˅šuË2áJH(œ !ۘ˛••éˆ,Kģũí9zݝũ•q.øĸ_Ï\ÎÁ°@shÞĖ|“ƒÅüŅ$IV­$€ûMî·@ $€€W”JŽ~8rÞûÛĒ\—ĩoÏ3ūjŠÆ.Yī3æ–ÛU…ðK%XīŦQīTbPlũē!ïoIŠ_§vÆéíyĪfŧĮ·lÜļ€h‡öéÅĪģŽč*án‡Â^e# æÆ­˜ōví'&Ü@ŽŽ[6GŧųH1™@€KįP@ŒsÆÅí‰?‰$ÉŠ•ļÁÁĀ’MŦņž­ŦÖ(wíĸÂiĮŋÓ*†û’5%:Ââfzš‡šÂš€(Ž €%ŨZHH˜ûüé}'’nŊ^Ŋģ €ĐÜLXóîČ{ķˆjwözerE—wį’ŅŸŽÛíž|žCģ ‹g—―sp‹Ú°zü ύ/uéØėĀ’ĐįÝÍîiŨ†0“˜ÂápUrGUVÂ+wîŊŸéÓuÏÉÔŧ*ú>™óâÁ3^WäÍÝFŒ3oذn‹v0=9}Z‡ŧJ2}@\Bž…Ū#ßoíŲšåĢũū\“ĢÁĀ/h^ÚĐÕÓFî9—QšęcÃæU ŽdŸ.pĶ&·'þ’$ŦVB!„ÅĀπ €ā~ŋŧÅK.Î7Ąûš[šýûĄĮW„Ë<ĩ+ŋáļįgõZ:āąc‰ƒĖĪK6žë5imÕÐÔųÏ<žæšĨ…įðþïŠĐļ{ÃĘĸ­ũÝęÞ{tgĩGžâ‚ (€%€1V`zýjųj–Đ’˜pzûöĖ{ûOëšuzïuë·uhÝúĶëo(õØĖŧ[ßä72š=ŧčĄ(uÃ[ÝũėÜYģmUÏŲđačČX€ĐGķlÞzęąwŨ6.Ŧ›”˜?ZĨvÕ2`\ČŠý3Iēj%žåf( ą”ēwÝ5ĪNåo~ķxčEĩÆcõōyÕûšīë(BóBœŅđ>oÂéÓūčjHT–Ģtĩ1;ĨĩŊSïÔķo·›áäú‘'·n`™Ά1•S<>&€äšÂÏ 5ˆĐ)yžģy•úđüÜŽÃKæ ZŸŸ‘R―vH!Ĩü4,FnþūđĢōr―ŲįĒb””|ð2ší…‹ ōMļ˜ÃÕïđųķ-ŦFĩßÝžũ]>î \ĀqĶ%r ējĸ<’ŽZID(üBðEØtWdĨƝFdÅ~žëĀ!ÖÐ ānZÂôįĻ)‘ájþ9Ÿ ĄÄsîDšō@ų2 *ŅŲ=ŋÞÁ[MÝhÍoũŲĒÍÕï™P&\°ŧh‚pĒĮ֎Oũ—ŧŧn­sûyD­Î xŅ­Zęā?eB†^G8_4mģŊnĸ1}―Ó' TĒĒ@‚@ėsD.\enļ°Éų͋ ÚXĨq§6u|†W@īþ’$ŦVbN]„:‰J AD(*Šw˔~‡=>—n]ĖĻzŨā{"ī]‚ĄËAÂ\T·ü**õÚõžõH?Ūxü•n{ŽuÃðrx}uūÃsËM +æÝŲhCÜŨ―'Ra†‹AÕí27ÎX<čæM"áÕۏy·V•r•šōÚ +ÆîŅ­ kÝō†ú7Ö_―p Išx%A]ũΊɧ"7éäôĪFĸÖˆÃĄaĻ”ĄnžýbõĖyf8ånšąNE—ŽĨp!‹ņ|•û‡?$ÉŠ•„ýÍĐBĻ& [J„ļníÖ'æ|ĒÁhtífÕj”ãų-žqcéRĻQWŧ1 ”ēŅĄa! {Ŋþwąjë7/íäBÜ7|Ų­Vé ŠÉڎÞ0­lu—Š\W‚ųˆę-ÝfTi“bøýĻšĒk4.f™fhÖON[xúX"CĨ\Ýę.MoÚyBTýC4īRõ û…VöΊU+g_ˆĻRŋڋĢõH·“īė8ļVXīPÜ·ī}Vófxõ›ŦTŽÎ@AļL“Ū€þ,’$ŦVB öŽË‰š‚`pîr4ŽIóęMšC€āŒYUŠY,ļŠa#ÁL!,,W―ô5@°Â·~AX†€3Æ Š|T™ŠÜ2\ ŦVŊRú`ãÁ]LPĀ ĐÚĪ|õ&—rĘVūåūŠöĒTŦûƒó‚cÍœYHĒ·DEF•Ė!åĒîiWx’öđá•oĖœ˜\˜Ũ{ýM’dÕJNC4îôf§ŧcBW%D "\Ʉ8čWŽē~z/üŌĄ$ l?w,{ß^Jāžä øÜJâBcų>îÏɊs†hDW‰€?Œ$ÉŠ•"ÜJL„’Z62))åī*ĘĮ”QUJQĀß ‚ā8`Aū/é\Š/?ŋv­čŠĸĮÞýė$s…>óA°*iŠÆĶ‹.šï óNML·uĄ‘ę UĐsĘĶqeÚ.ø2Āód.āĖ$įũ†ÍËa>ėĶAk‘ZÖį —þxÔ}ŋœ„Ķųý›ŧ°õbĖōž8\^|ĸËYq1éėwÖ9W@jéĪÉwŲÏI?ÏOŽO&þĩ#ĸ‹^zyÔýéļ[ėgiÖ Ī–ÛuģĩeíĘÕYÖ-véOuowßæ‡ošO’ū“wNéü`0þUŧxĸq‘fģŲd2 ÍB0Æø―KZaÄÁ`PDę$üUękÖĸ‡ä5FĄŲårÉĢÁ%’}J.—Û[ý―6& fŲD<‰Fcąĩ­Ž*útNWađėĶ0ždr+ĢbB0ŌCäN,-NŋŒ}ä!vB-ĨT'„ëÍØv:E9`üA;%ŠBÞŨŊlĮ–ĶgàøŦ…™p|7šeA"Ų€†Žß°Täaï苘ÍaMŪ%üM]WÎ6Z…ũ/ĮØōäýĖ ÔPāk;Ũ^YîFœí˜^Q^ü5:*!>ųŒ0Ķéĩ;ßũÕv^=RfQđÞÄi&ĩ™áN§ü‹æÍ呁!ĨŠŪjytø1Š#ų‰D‚ôW‚;ŊhsÃ=?yđ.TĖó*―ĀđÔZĸÞŨibī6ķvÕ‹@Ûģ3,.Øæt+lÎ{6E5õ°ũĮŲX8ĐoéōͅęáņŲ…ÅØúþÜqū-5Mˆ~{é!ŸiĐ·įvՑ†fwąŦČa2'‹―ĢQÄ&G{ïl%ÖķĨģĖČ9 `ŒjWÐ/ ČĮ8J$]#āœXė WgĮ§ë} v“!›ÞXmóĢA‡ŋMĶ(‡l6ĩÅĢ‚!ķ­ķ—”Õ54BôOƒs‹ÖŨŋĖÄÏt\Hū}ū…01Y ,Ldh15‹ Œ‚―ŽŌÍVž=}âu5Y€sīÛ ý   âœĐŒæËÆŨĩßŪÎ<ūõKoŊ"ˆ8ƒŽ J.6ÖĸhĪķõzItĻrƒœOïäúw­V~ØK"‘CöP[ÓŅĖōÐw7û†GFžO…1Q &kõņڅ‰áūþûũ‡˜ĸx…ŧāŊčüdÏO†ĶüUĄŦ‰Ĩ7_͎ÍEķÞÆ"ŦqÜôEõÖōã›ũ Üo`Nđ5xĶëēyeøįŧũŨ3ÚIUUâ†S•Âų”Zėül-5˜í6#rzžFķ5:8ōf=K˜]œ˜z•ØL&à +@0U™HÆĐČÁŅ‘V+‘Č/2čųgåu§ŋđÖ]ãuloįĘ6žųžÚˆ‘ŋöTũé‡A TyĢģŅi!ųĩ%pøŦ - Þ2߉ÖKWN Ô4užm)r7uu·Ÿj4Ąœ·îô•îŽÛæ*ņ{ -ūú“gķĒōÎëß6U{1€ūÚÝĖŦŦĨĢÍįR öĀųķ–BÃf­§Ð`,ðŠmŠÝßŅŅYéÂĪč`ĮųŪ€C1—ÔŠ›`‘ëHK[ũ…ģ…JÎlloĸ Sjl>ûyÚĨfY@H$œqgiĻĄ4„ÎãHņWÕ*aĖE“Ōí·ĸĻ'˜o1Ę8(ĩĮˆ†óđHGQiāPY šØįB@)ģŧ―5%>NUčÓA –`ÕÎ(GŪ…B!K(ßcöÔ/ËËÂ―•5å•Ā9Įn—7„6&N$4ŧžþ""ýGÁât/$‘Hþ_ÖģápØãņX­VÐØãj !Ųlvuu5 ‰æ{Ôŋēē E$hė͑HDhޏ'—H$‰DbnnnllLؓļßûj…ÉŽÏĖĖėĮ'&&ͧ§ĢŅψß#šŸ={&4ïÓój% 8NÎđXsQJwŠŲ;åcBˆÃáÐ9" cėvŧ…Á---qÎĸ›ÓÁëü(4ïë‚D"áĸ+Gƒ]Ėhj–„ŋĩw‡F1ŊģrQFâÄ2=QŪ25ýcÝA o1Đ@jĪ@jZ€R @Ü{#âyßĖvũîŠ-ĀÝÝî~2ģŠÎ93óũO˜™sNUeæ˜Z*•bQIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-perform-update.png0100777000000000000000000024645213761647206021352 0ustar00‰PNG  IHDRÎbðZŊrLņIDATxėVŲoTį·*å5Ę_žķQĢ<”Ļ…mœBX毯ÆûŠmlĖRlķīÆ6c°ÂĶ/ÄöxžÎxÖ;w™{įÎÝlÏӇŠJ’JmĨž™/>šđŸ|;Ŋ RŸÏ=įw–ûŧįHrŧ݋‹‹ĸ>ūüōKÚc:‘~D&Ŋūú C)øxĶÎīÕūÂSŌ‡fþ_Ÿ'Ý=öĘۜô&ŊRZŦ•šŌüN{<-}Ð~fõŸVøøÉóÏ?ĸâ‹/>ũÜs_/ãņãĮä$@ŋ%ôÍ7ߐ= €ĖÅ‚ö ,Õčâ8 ÂLĶņčŅ#ëĻ”aķąøSŅĢ?„>€Ģ>–ē6–ūŦŨ‡vŌē Į^tÚčƒßAŋ‚™ĸúØG‚}MýøÃéxÆõŸÖ—^zé…^HÓuýÁƒðÓŧīī'ãņøĀRð—xH O3‰ --z 6ÅtK5ÂÁfáiSG5―ˆ ŽúXĒ6úÐőđRČ2Ī―>ēe Bx–õĸjôąŸ*u}Ė)–aÉJqZÚXýþ žLaõú ‘Š&ÏŽ>ˆUęCšŪ§-,,ĖÍÍÍąxÜÐu‘ãŊ‡g5ÅbĀ„œx‰Į0 Q:§Ķi$jvtå6ĀøBĢĻ ŒDĒp"Ísk⁎čĮŲ,|K s_‚e$Ļ­æĒLzH$`ôYX\zļô`‘Īš_|ÏA}–ëĖĀĸ?ęƒYŒĸW}Åþ%‡KņØ­VKþ+ŧHN b,›š>ôš!bÐ!ģ0qðca"ļ–&ĸÏ1!BH+|qČ2,Ú˃v|īŒĨš?õA'ųĐëƒÎÔõA'ÔZZô™{}Rŋ_pŪF8Ÿ@āÐú`q‹>ˆ4= Č$ų„ōxÚŽĸõÆÃŊþüčëŋj*+$4Įõôôīķķ655ĩīī|ôŅGn·›”œÃëŸ=Ņ|8kĸ›oWŋ–Q·ņāĐJĮÄp"27Ŋ/ņ>" =MÓčt>Ēa)Ž XēEÂ2˜}ČBĀĘėHÖÝÜŨNŸYq9î;§<Š>—tœ{rØ1-ƒeŌ i?2îŠĻ:=6DaIh}Ā/ąÞI—_KVĢ5_ޜ…˜.ßëíėčžzŦŸ•Ø|‚ãÁ_dU‰ð#ƒƒũî}60<&EÁoýâP ēĖú`S‹>–ą“}õāŒÓ ÃâÓûƒ|, †"ņΑĄþþ{}ƒ žš HxL―}íōĩÁÍ vƒZTrU“·@ũOŽŧ|žNū#ÅīßúF€ũ™Đčƒ2æÚčCŊÚī>Đß/œ“æÐúāi!✨•ô#E}0—š<>iŠĒD“PUUI"ār}Õõ›uRÓЇÓĢZgÛÝ­›Žo|}ĒŋēdY&|Ļg0lkkëîîęrwûöíæææééi(Ej-a+ŠË3ģŧ>§Ēië` “yĮøÞWē2ũū9ėŌT 'šĀiöĻËĀGtœipĒaq"°Úh ŸŽD`ŅĮ\Į\ŲRßœvú(\ÃïŨmČŠv̰ j`QÆo3ęf•yCSðÉĄŒŠÏ‡'>ÉzũČ#ÁŨ„âЀ„āāŸđũųĪŽ€W?€47b ã]M9u­ŒĪāQPÍÐDÏņ}Eéé;ęÏ4îJOÏ*?80™ÓdGßļOœ3429ŒtÜ)ßē!·ŽzOUYõŅSnV1t ûEáíĒōīcðþļG7ôeņß߇$ÆFĢIýuc^mŊÎŦþðþ)Ū'A’NŠéŧÃ5 ŽÜĖܔžWūgOeiÝévŸ úō‘á ! aëņ˜ÜPđskŊŽ@ ã‘Iŋ+˜x!Ęų&û‡'Dň/Čgũ–üáōPŦÂĄ$°žKÉïĩŌþŊOŊIïTĀÕĩŋ_–{Ar +Óũ wa™ū2XŸū_ĨîŨFðĪE"I’ä$ĀŨ''.žüģŋŠýwĮ…^―üŊ΋_ŸŽŋĩæÕķŌRį#I!nÝšÕÞÞÎ0 þę‹ĒĸÉíęęË&[DÏ]nÜ^ŋæŪôũE_ðoýė}# m…-Ÿ­>ē yčA?9ĄZd`;bc LE$Āēæⷈ€-ú` Ö5†” @“Íú`/l‡ŽcĢ,2§wŪųéËéíwĶī……ĢgóÚWÞÜvĀ#ëaÖïtŒŽ:Æýސxĩ073!ƒgƒ!6äŸsNøBžfĻCįOo);106Åpb˜ Œ9 +Ā °.áPĀ Ir4Ė…–ųfɂd<V7”Ą?ŸYĸË-7&…ÅÅE-pŋ`íúŠú>äŠÛ‘YÓþYŌ‰ÚŠę­Ė/ ęą9CՐ'āóē;3éœtyÑĻĖ{ÎÖūSXsÜéaā{H|Ā9:<>=+@ŦˆÄ2– ÍLONûB\0ÝÎąąÉNn„ øƒÁ k|ŌāyŋĮĮ†Z‰œkÂ9::ęe€%Ŧ҈gj|Ä1Î,Edy0ĸ@wîî#Ìū0gĀ]füž'‚ÏĮžŽ †|nÐŌ9åæEy~>rzoq}Û YUü^? ŪhTųƒ!>ô:ԉ ÖTąįŌ‰‚ƒãþ°a<ģA–‹DYf&ĮGF>F„ _ Äóė„sl ū‘ąßú:9Đïú ŸŽšÛ°Þ/KYz‡ŅCß/:7…ûøŅč‡Ó`DøCÎ$Đ#ë]ŨkŊ<ÚđõÛĘĒėŦüķšäqnFtÃkíëŨú].Q’ŸĪtvvöõõy<†a8Ž …B^ŊwddäŌĨK~ŋŸ”!‘ũ~_ÓŧåJhŊÔp[9{CnėdßŦÚYÔļÅëó+C NEyžGNK31d~„7Į1č"Â2cÎ2§˜›N…ß+‚DéjæÁ°,9iÃFõ)|kíš Å ’&_oy[úÛģũÍĘŅŧ JƊr2ŠëšƒĒý$ŊüØ4q^ŋPZ\\ĩŧ8cûæâÚæ€ß}nÎ/Öm-Ŧ:ðГék? Y…‰ŽsLDqt7—;†ģ§ĩīĪ„d՞óó •ĪˆŽIÞæc9'ŊɊ EQŊޚ_{ģŧuÓúoïČmlŋŇ"Āú{ŠōŠn8ƒĄ@€ ņë>[™YX―·0?sË͌ ―SÂLïķŨŨl|csU}ŧÏ3ÕrĪ&ŋĻ`WÎŪó=C҈ÐqŠŠ xw~aé™OGŪÔïݕS‘“óÖ[;öļ&éáķ#ĩđY™9;ĘšnŽ}ü~å{W†YļvîøöĖÂōĒü–ÞAXýÏŪ5æäįV>ï‰IDĒQÏ―îÜēC7'‚L H|ĮŅüšÆŦQUáž#5ųŨ‡Į>Ž?PZZôÎķĖc—û5]:YWräâ %â=TđįâõŅĻĄÝýSmų‰ËĒînn(-,ĘÎĖØÝÐåõOĘÞžnÓķ‚ŠFW˜k9XvĒýN8Ė}üĮšßeï*ĖÍ+ĐûÜũ―pņ>RĘ1˕–c9š&S3ãá /A4RÂGJ™5Ķd1=|MĢ5Ķ6ljƒ Â.ČÃGMaNÏДŨ―ũžÏžĸrjŊģΚĖ՚ųėõŸ―ĸĸßßþÎö>Üŧļģ>īÔA$ēlözĒlVŦ(ŸaŒc‘øŦĐŸČ žē,“ŠĒ‚‚‚ôz―î'€­(Š?Ĩôü‘ž0ĻŋތtF‘ÖKðĢ3Ģā° Ģ•âŽú†šÆZeZžįáRÉI’+þÅS ’‡ ‘BUņ'ęÅ* Ü`ˆøĻC`ˆ\*œÕŦÐčĢÎ@Ô=áú@ķDŒŸ6ÅóŊ3ím_ĸöĘsfYąČ‹ũŒ›š_°*#éąÎ/ęūëd(ÄH―0Ėy―ƒũLÖÚėï7 WäĀļccĮN^œ•>j 1ōÁ)/Ū^•‘8ąó|ýå.NâET‘(‹5þŲė5uąņR—O&ĀMÂ22þ&TÏöņäxŸyĀ=ú^ÆýÐØčČņIKį?yŋ,ō gJo šÚ?Ý]\ôîÕgŪ@Ųtuv –ĄËōŨLĨŋhiĄÂâĶÄ9î3eyúÔŦŸ—WīēIiËĶ=<ĻîdÅmž’<7qÅđ/$Žäácøˆ…Ŧ ŨĶMlo<ôõuŊ r8tø’õËÆĮ ôuy‘Ē)ÏįM_†LXžŋzę1Üí;r2æņYđéņÞÖږÖ+"Æ€dNūzîāŪâĒũķŸi퉛8Ūí|m{·tõ‹Š.fhtÄÃOÏ{qMÁģ#ú_øĶ%ŠĶi(N˜RôbÄË2–Šá%ŽĮÃ'LÏ+(ȜóÄ­ķonãþMŸ|ĸ˜IK–Ï 7â^Ņ/äÖS›zŊذņÅ!Ļí@Ųiˆ~øÖņāÚ kĮ āÃA’Iý€AĘïëZuå+CšÚÓ<_‚ $'īęä'S“*U_ŠÍSCxŒÄAM˜Ð&Ģ„91 _=ŅŊÖGcÚwŊļÝ―>4ĮqÄIé6GFrAtø 3 ŽîE18T?h0ĶiX „fVŦ!m@@€Ýn‡MÖfģÁ> =dâû|CC°Õ>Ð:`°-2Ü60Äj7SÆ`KM뀘š%Ė6ī'ĪÕš“üЂ›zã#ýĸu·‚VcžŠ|$\ĢÆVŨĒâ/Đô!ôČ Aîdž'@sǐpu)ĸž>‚(@v*thœÃÞ]VęęÅaũFõĢ øĶõ\UŅæ7ũ|vš7(\eØ @ð‰ĄĢa$ŲdÕI,+H‚ÞŒyČ,0ΝÜō†?J0(™“16PþQd!ę”(™­:™g!•B€ÂRg7+G?aÜsó{d2Þˆā,`žŽēžã9–Ņ…MtæäåfM3ČŨëÕŲÂG<ōPh‹AŊ“&e3 Øļ|^Ÿ(ø˜Ž’―ÛOžîˆv Ķ%V ­qĢG‡ZE‡ņI”#66ÉýĢb‚ÃЍn‹Đč‘í”ČēF4Pôēķ™óg†^Ū*ÜļíÄđïšŧn1ÏŨîŌí{Ke‹#ČĻûņĀ}g9ģã·I)9y9™ĢĒmúþĢï·xāŊ—ĶÓWGNšhļÕ^ũŲ_6ŋųŽëâu‹Íâ'I!LÉp_)ĪĮP ’ˆĒ8ï?Ŧū]ôæžēSČfĄ%ŋŊI'ō,ËÂ}Âā$y<Öâ0ŌÝ>ݰčÁݗŋũ°=Ø>ėŅ1ĢYMvÂęúQZŌIęG)şŦõNPŠ耡9ãĄUŠKSĨJ~RĖ‚ Īþ5!$‰†'Ī &ŽYĶ2)ÉĶyū~ĩ>šđČÃõ?Ũ‡l 49ŧ”™āŨũĀĨĀ~LÄ`44  [­čˆđdĩFÅéÍf%ŒœðJ c6›­*ø|>háU…;JæĻXþŲ$šBLýC,BĖĄ6ĘÂvp‘ö{u”NIH˜(ŲČČ%…ô““Gà  ČéGb‰?Œ*­úpVŸíä>iLjēĘĨš91ÔQšŌ'ęä ’D đģ> w~(ŌÞÔxÞäĒį1mĀ―—ˊݏ<—’6krÉ%K2­Ģ Z͐Nâž>ė“š@JfnÞō ˜ël?îŠ41-ý™Éþ €D^æz<Ž Œõq“dsDÝwĄåԗ—n!íéhŦk<â ƒ―•éđq›ĮXŅGY"Ēiû·ØvyQŌ!Ęυåüī( Vˆ ˆ—š9A2ŽaöČøī _)Lĸ―^`€ įoŽ (ģŪ]ïa|—/\ėõöŧ'Ė 0ëaX„ņ“]ø^9x؊ ë&EGĘ[ ֐ ÐðQÍ\đzÍ+/gŒŽē žōžÅû‰éi8rxā“ąaė„‘%{Ï2áŋ‹ðu}YÝY69įų'FFq#SXÆAĪ úõ^ŋŅŲ}­―åÂUŒŒ=Ũū:^Þ:avVĘӏ#ž(Dō0þS„Į4)dī…āë·ŧß­óß^ģĮ8L4…dŨÃ0p|b„ApUý@{ũõCĒ$äŸ/Röğ<_ 4y”IIâŊfĻ@ýzHæ%! Ô!šĨgÂðÎú(=?§Œþŋõƒrđ\555ĩ}ĻŦŦƒÖ]SSšeóÉUųwíļyėčwû>rŋžîðúĩĩĩn7øƒ qŧÝð?g•••ð…XGGG[[ŒÂ§·ā ļO0Š]U|ēđhîŅĶ-§.î=~öâ’å[?\SYUy~ôĐŪvõD‘$Ä CdÅ ē ÕŠî īĨ2ĐŌŊ™B―F Mr ͊”đmÕLÔÎ}üÔúT•f.,üčÄWÉû;wv5Wþ―895ŋēĄúåĨó’æÏ[šž4kNnÁ[Gw8―tŽšĄäϛRóĸTQŨė:ēcQÂĒËjęïK~nķ3wÕþēã–Λŧ`~nÎâĪ™Ïå­ÛķïÝŨÓ 6Ÿp7*~ ŒJwKõ‘íÉ ÎĻUÖR[ßÜÔ°{KÁŒ„Ų99 ãg˘ŧēīálS―kįĶåÓþ0įŧļjýđëë+>ý07~Z’3-=Íđ(uÅÞŋ}š.cQá‡åÍõÕÛV;3Wlv·4}ķwkōĖé™ËķTŨÔî,ĖKJœ›šâĖ[ŋąžšú­—–l,:ÔØÔÐØXŧĩ ũÉÉOĨfd$<ģāÕâCð ŲŦyY/mÝY[ßānpo[î\Vt°ĐūlCnvzFƂxgá;ꛛü 9!!%-ݙœýþūÃ5}ũÓOėĀ.įė§’œé@,9míþĢUuå%Đ3_YžĸÔĐæš’ũSâ8ģē3S§'&ŋöŨÛVd­kwCKóŽŨóį<;;53ké„ôÂũÜUĨų‹Æ':33–ĖNŒÏÚī§ėÐGÎđsRs þQWŧ1/sýÛ{›vŋ‘3á‚tįüīeŦJ] õgĪŽÜýɉ––š Ïgü‡œģų‘ĒėĒøü§„wã֝qĢh1j4d Aó Ę4Ó,4fzš™ĐŪŪïŠF7ōũøë9ņäɓb(&$˜péÜđu?Î―ÏĐûĀb:Üšũˆ™ vzlxâ͙ÞôÄþ(mš*ū_6ĻÄQ%Dhā8äa"§ŠĶïŨ4ĸ ~ÐWðƒįhdģؐ‘$ ĩUU,ëŊŋúãÖ'Ŧ/îd?ĸŋËsŠIKÓÔ%ŠjۖĮõzͧ°Z­@čšt2•ØhÚú·įŋ>8ūóÝ/ĸ°ø|yōSQgåķfT"ÛMB{„ŽJfĘéᓀÛM=€ü2ė7°Ņ<ylÁF§Ð+ŒNņ8ĩōĻ—kc~-øa蚹ČĘæÅnlŦ<Ý6]ÛmóĒëZ`ËķÛ6OŲ!Ė>M6eYũCŦŨ;J·5‘*Ï6ėûÐwlPÝ }SįYQ—Õ06t*Ŧzŧ,%§ę‡ąÞææ‡ÁCįõóÕ#þŋqãæĸnÞ>|Ōî^4UVäL)~H,ûūŦëŠū”"ßcß4QfęëšÜē!ĢÜ$ÐVŧą*č’6ãísꩄŸšĘ>ýðƒūýąāUÝ8ķôĻęnlË4%=kÚķiĘ4+ÛšÉĀŠÚąŊéCW_\\ÛŠĖ3ŋkÛŠŠ*Ŧj?fv}M #1S–ãŲ•|[5M74gę:†-pðŧáqhr8ôßôŧķ.a§jÚū­!ŠČrĖĄÝ‚ ]%įĘōŠĘœfn‹MšŨuŨ7…^đ.2đ?š\ûƒíl‹JœFŽïūōĢĒūa4jAŽ†•dō~)™7b§šLÞŊ`Îđü*âG2ŸųŊÁÏg;??õÞH’Ūïųîß:Cŧ؊žaĪLŲėŋeÛ[…äq$™ĶÄPšŊÚĪ›tč%ŋüûå0 â!ŠV‰ īðuwČķs4XØÎsF…Œ!;Ų:,‘gRŧܞI~·=†Ŧ` ÂăžäG-B~ˆåčc#ļ4ô[æv†<2Õš-gįŽ õT ]ė õS}…gč’įE?þųŨP<~øðŲïŦd“ōI7IČ:äðŌ2C:Ũ &”-.J‡"ÍAŋđýŲ—'YާŨÆggx ÅØ‡ tWZ`FKĨ $žS邁æ#šŌA/EžÄw•xõ#Á$pēT}Ļ9;?KĖO°?ŅōxēVaļ?ŪR4ޟŨÝ/iƒË?đÏÞ7ĘõN1žüŨFøFģ?š_á)ĒĖwËU3ų9 Ųéé)蓓“õz―Z­pbĻ@6NyÐNbGÉhųB\‚`Ļ―`…Ŋ1°Ē4ŒGå*qkeĘķķA45”\h.1ūĒ?>Ņ~ Ĩ71ɏsÐō›Zŋ–ÓŦG{ĒģÏį'.ŲîhĀi~äėEZw]žœãšäGLüPžūz„oNV§yū­óD­Å’'ų Į‹øqZdĩ6ŠâŠ6A‡Š^„_Ĩų™ĩ?3øQrďÂý™äãÚüH&ų CoÍPCMócīüĖßæðƒ,—ËÅbņtņ”ōlų ãčÉ6r˟Å^ãY-Ž—ĮK<Ō|ðPBi*qp0äĪŲGGG<*>ØÂ$„P‹f•Y…$PčQųL ĶĐ<ƒ3 ЉhVĄ<ʙäG€<*‰ø t!ßgŋšã7?žĮü(t?čI~ôŅAæðC‚ųĄęMø‘3āGcü †x3~xe `ü` ðãdœĀā:uȏüēŏtp-ˈÉŨōĢĮÉýQ:ڍũ*~0"~°Ãwí2É !?ōxDë}=~@ŧš!‡üč°oʏ ]„ųü`„—čzüā4?ČŦøA|ĸŊÜŋŒÃÃCĄDžÉÐ―K‚-ŋĢŌ“Q~äläÔĻs͚Lļ{ũŪĢsä­óƒį―âĮP‘?æĮž·ĮėÐđũß·s.?ØsøąÓPï!?Bļš@Þ?ĸ°SĮ81E=cīë äþ§LIBKƒ’úïuėâū3@,€Å ĩ@jĪH-ZĀVü+đÕĻÞŽx‹”™–Ÿ gM·yūNÕ­x%É+ýÞ2;Ïž[—ÖGĩÍ(óļŽ/==ØûĻĻŪŪŅsÛ4ŠÄÄÄŪą%ą$ƒ&1b›Ą( ŠĒąą@D•Ē4ĶˆŠA *J—^f˜rÛ;wÆBŒßúþïĸÞ[ë­Ä3ã―wũ―Ï>íŪu>|ýï(YUC\O@T\̜ÅþE>!oÂŲÕÏM}ÕÚÁųĢŨĸ@1ĒģîSÎ+XŽÞëųJFuoԚR…(díõuuÍÍ2éVđ)ų ü{#ĸÎa•ŊŠ+ËŦ_)(öËĸ}Cþ3RZ™Ÿæ}æZcŊþSÁĻ–ē!åðđšF)Í"Kí?{TÄv„lž0fęĒ›eRã<âŽĸŌ)Óg^*lčŋŽēųÜ^į}§ĒTČŋ(ĩ,MŠ]]j†ÅpŽŪ8ÕzęT Ŋ+ bĸseh•RĄRÓĸEäpLQížcýÎ#Q·ï§ĮœÉŠĐU Øëa8.{UzÚeõļŊ'˜ĖøiâÄŊgĖޔþļ–Åq!ŅH'éũ†q"Ī}ũ&›1cÆ 2č‹Aˆû)xėÃĄęÆįĸvV ŲÃzÞģY5*!ýį^[=v˘‘Ç zmŠ$õq ĖĀĸéP”Uæ]ũsņūZ+§Qô? - HU§BÉ@5T^óĀ~ĘTS—ÐFMųį–ڏĀķåUMmeƒBÉ ‘75TÖÔķv‘(Šņ5‹NĀ9ŠžŪĄÝį­šš:]>ŸĶšÁ!-‚ōø]UOG3ŸeœÏJCýÜv8ŧ—)| éi0Hba9ïŦA8„<Ãpž.Įþ]“ƁöAŽ~°9‰īÂt…8'LŦ•VÓwŠĒ8!ã‹tā#Ÿ€zō…"øÐÃ@āáÐLÝîfj—G &w“Oāokœ@Նč|ŽĄP€ūS›§ĢÁ†ĖÞI p 㠄ðÏIÄĒúü„}ÛcŠZõD|­&zZM8ΝÍϟæ? ŪĘųãi^ÖÁ1ƒ„4Åhj&Á4ŋØĩxÉNßKÂA“WnØ4ũ‡ą59ᖋWÅÕttërŊšnwž\ÜŪ'äu—…ĶĨĐĄķķvĀčI&ÓĶB7šÂ0΃V`œŋņqšœ8—í[bKĪzBBÃyë.üĩ‚Ï ųÐY02|xWë=ãņ…œ1B.Oī^jž 9č…,Š7mÖ\ģŲ3čáÃpOuī‰%"ð7‘Å8ž„Þ_=FĐ:jjkŲ†SĶ™|ϙ2ī·.L4ūHÓð5:ž@ZMāD"Ũü9ÍYȞC3ðâuCÐÆÁ ŸŊ•ˆ<>l& ŒĀ”õaĮvnŲsFÎBMzÆó,,%“Gč`€eX˜īB‘VŽ&i5€qîåCũūIKüoXj?ŽĒ ÛĖÓÎ4„UŨ_ð=tþzņý$ ņBû7K›PŒ{ŪjzzlŨÉ|{ŸĀ”"`:Ē”ŨƇų-^īP,6ßtė\S#äŅÏî'9râ\L”ŋo@nY#ÖĢũ°‰ãūųĒ/ŽáŠ–—A~^SýqũŠ­™dđƒoY…c(Ž2%é§™K–­öJJI ðóžVøęÏ#„†gŲ{—ÛŠįK,;˜[ŲNy Ï|ö,‹ÅKVožųĪŠ ĸÕÝð<~úfaIØïk%f–{CR”ĘĶ`ũm3ģ“oą(U6Dœšœ}7ųWÉÂĨkSKj1XÝ1‚jŦū|rrī[–ZDĢÐvTQWxÜÝ;îfNvb˜D"qr Ļë`PÃqęQæÅufbądéĐË94”ŽbĩI‡―N=-‹;ĩ_"ą8–EbnÄŧ•Zc ŽÍ5]pâRbÁÜ[—^žjizžēŅvlu…uíi׈>™ø #øme7ŧî°63ÛŸš˜āĩuŲØ1&‡‚.Ī$&îÝžâv…ŒĮHƒÎú8ýūfŅ’7ne]]ķf۝Š.Ðö|ã*ÛUן”ÖŋČū°ÍÞÂöh<‹ņ-ĨnGöŊī–,s<u+í„ÛvϘLL@Īî°[ė\üėœŧÎëmÝĢ ŊåyúĄ;æüdęä’‘rÍŲqwR^š―šēĒԘ—‘’Û.o‹tĩÞâ|&_JķÖäg?V°8ún*ËĢ›ó7XYýîęũēąĶļðĘš%Öû3e‰ņi­ ›*bÂÂs Ëi Ũ’0jŋ§9 @,_ĩtž‘^GG‡‚čkþŦÝøþXÅãÜēōgՕŊ ôšûņįSóĨ*öý"Åē•>|TŌÖI"(ÖXzÃÃÕÉtÆėÝĮÎĨßHØģqWęÃ:UkE•–OÎÕóĐdēæ įåë†æŨ7ÜŧqÉÆfsfYŦWĮ^<ãėšÕŌÂ.*ņÞ+YGóóBow7{óYŽnwŌ“ünýÍᔠČJöyļ,·6Ûx $ŋø#ũpŲēïÄÓ6šl*Ų4ËbäõæÎŪ7⠞VāBaenī―ĩ]XF^}mÅqį•›]#?TgdõUE%EEåŊš0 ­-I:ėēųlÆįĢĨÞŧ=2ę{ðĨg}üŌîQÍ iĄÞë·>jbøoĮÎŊģöaāA·Cųjgŧjž|öųŸ•ŌžŪĶįÞ'*[ÚäeDÚūåø…ķ.UyyI7?ėH‰I~ÚŽĒĪ/NlqÚwþĶåUåģģķō‰Č*Ūk―xĘÓÚ|vä―zŸĻ-ūææēuĶɜƒþŅiIq;~۝UڌĒč?§Ô~Žĩ"I~['Ÿ9)›ÍÆH““ _–ÞKČÉ.é;^’Vð$+áÄį<ĀhÎ39#&%3&<80øÐD\õēŠĐƒéĩČÞaĖP}]ÃAIiķ&ƒIb ĀY Ų%#þį“ÛC’Ģöã ŦŽ*ģąĐ.îäŅ6UÏÝþ Ųwó\—ÍdĄ °Ýô";kŽļŋhEW:_ZVV’Ÿ:w\ŋäÏļ‚. §Seđ·nœØÉ“Õúŧų―T"8ΧԠïĀ™ĄĐé—ęNÖŊĮoķ›Ū’57ČTŠP xËuGïßđąfŽ~Į“ī܂’wâ/g<0{KzáýäHßþ"ųÝāCųĩ*>‘4%4čävÅßĨ' U·uū*ŠJ(—Q3’‚œ yb`ŠÃ1”O‘LĸOįÄ$ûîąbÔEž—öņÓÎMó DĀÎ-:ųØæOøō§yÅjÆhåâ 1é%§ķÚö` ûÚX>d„úÅÝbüýæīôÜŽØ“ƒxu'C#ŸĻûEÛā“ŨgdßÛ°ð[ PēÚ.’ėĻyö €á„‘ũhŠî­?dĀ@ZqŧÝāŧ=›æę‹ĀōC―ŨĒËŌ û§Q-Pí°ųqÂĪɓū™”^ށĢA4Í}.>{9Ų{ŧ„V<ÞgŒéÎ ģûАž—’|6ðk3<üS{M]ž—ėūJöōZšÅhÍA‹į.‹OÏZ9ãKŒĶĀ⟍ũ‰ļqëĒĮ`=6ŋøęĢęNį0{ÝãpԈG"$h†Pió‹īúvvČũ›\}n=ČÛ`>™jŦžqĒ ķcĢ_äKAßÂŊų&žR3č_fl7‚wŪŲÉČ,’Å ™oÂĄŽ/W’Lĩ˜Õ z}ņ•x,žÔÕ61Žâ€cÅ0l·ˆb8_ßP€ęYŦÖŲ0jĨžKÖã^B>Kkļs4ôûųĀē!―CŊ%\ˆū0ŅPČĨCąĢ•û7™Nj`lŽĩžą0Ž―ą -…Wí­$[―/Ā[…m ŦŅ ŽÜæ2aØį}uZôo8Ė0hôtóiF}X’ĶÕ#ˆúƒÍęÅbÓό t Ë|ņݚy“@É5›ųÛßŪ—4Z]_^ YEÜ,YâPXՅĄ…•Íjšũrû;‹_câ“/ÅDoZ0‹UĐGLþáëąÆy“<ŽHļŲ1PbõíJ!ŧķŨĘ|þė96QÅmþĩrÍ6ũ‹ĢPˆPķ―"ėĀJɜ9–v[r倏q!åđdįĢ(ËtëĀÔʎúŠJŒ§ŒŠ$y“ÎéĢÚ;óÛ:Y”Ą€`āz&ëkņ?ŪÕþ ‡ŪDÁ­ąV\(ð@cĨfhõ›’‹ēðC–i“ĩĻP!(Ms9DËeŌ i# ļ %ö\z4&ï[óíūŧ&n@‰Ģ€ei–…·ņ„ý5…!Üiøobpšd]@ŲYSõJ žŠˆ…JZßĐh€Ā  F2ψģĪ\­RF‡GhZ0ĀcĄƉ$)0šī °o%gŠa@ZW /p@ \uRÎīĒ“Tą,‰!Ļ–eHJsLôëKŒeĄ(nįļũ؉ ôĖŧąaG 5ŰÁ![–"ßŲĻõ•IIĻ;‹L·œĖļ·{éũÕ%YûķČ(ŠíķWŽ”ģ­ēĶļQĪîÅGyÂhûŦũ#tŒ?éÕëé$& tĖĢŧ)Ĩ þ&ƒ 47 R))ð>ÔĻņióŽLįĖĩķZ0ÄPïĩš,ĒPõž4ÃĘΧ‡Ũ―G˜8<““ēöG”Ĩĩ1Ĩ(%IC\ömAGųÐŲ^§RQC―Q‚ĨÕjRÍ!ū“Á`zŸš_N œmŽ“―Ú#ļīUMð9ÎĶKžŸˆOĘĖJo€w§Ó ŊĶ˟?ËrĄÕŒIc„‰Žē?AĀÖ{íÚv%ĸåâ•æF=EW\·ŧ‡W+'Ÿ Z>Ģ/ XŒĀšŧ…e5Š#„PÄŦ,ŦPĐHÍR/trĨ[øÍ!Ó֝ uÔu‡Ã—cQ4‚wO -Îä_†Ó•ũ}ž~;'%áō―—ífÚACLļBōõȘŠzjðŨ ‡õÁ)–ðþhÚ üŌ6xøýV.ŠĄ- ŨccŌÏEÆÞÂÏÆ 9hð°Þ}î\TFftxxfy­Čpôg†"Šb8rÍ@~ҚAqŊOFM2ЊŽÛ…­2FÚXZT\$ŨöWPÍžŨ―1 ĐR‚Ž3á‰ÏŌ[Q/;ôLmŨ̓0ĪĒCɀ7Ňdø_O­‡ƒ'QįŪĶä$G„$äĢã‡éÏvŊIÝ„ Læ-ŲG''ÔuÏŅ€ûđΜp=tHÚóģ.6ŸŠŠ!•Jp;(,ĐðđúŊR7Îųs‡k„ÆÄ7rÛVČ_­€vÐ,ĐT€LȧāĐnĸ/G5ÅÅũōKīēüiq~yÃí˜îÃn €œīËŅ)™į΄æžjŨï1ä C!Å0ÂcÅūî‹ĨÕA17˜OĮŊÚģJ’76 <ýï~ãÏ―Âōj•RZõ°0ŧ^NĸõeŠį9ég‚OÃģ Nûg>ĐQ)y?ýj1°Ŋ°ü^Z#fb9e4Š0rzÐixQ|ũ~ŧĒđŪ ĻDÉžfÆMųø:(UæĶųzZ­ÛŨÔ‚AeĨu,čĐßœ—ĸĻÔýqĸŅ‹Ze)šVw•ÅœŋTÖ JirNØó“I?ĖāqXP`rĘÕāĻó-j0ük CKkRâü_öú4@§,ØqdƒUYRč"‹ųævĪ:_đņšhŒ“4 P (šRNmĩē]™TŽķw|iôųĖ…;6ˆũũĸūū°ÓpæPŒ Ęë9ÃvÕ@Qå-+NåĘFĸ4Ą-ûâŲôRDô™ãŧO•þŪŦnäĢ„HÄøwÓU–ÏÂ`ŽvšFôģ?tæ·9ß݉‹zJηšĢ (šíž…,‚ëŊô Ýķdú―k ÉB›e1YS­·ÚđüÉĩ€âųũ_Ÿb―ýøaŧūÉ0šäaoÆaXũ„Ä0TSj1u[kÐÖ]Ö63 –ŧxüǜßZœņÚ2ū:eÍņē­>ý'.<å=ēŠĶ :üÞ8ŠðD!h@Q|GWïíËf%9›KĖ,-íÄÉđdÍžįī†6rQ„R“#LlĖ&ũŊ|zv­{D]'u3â°ĩđ™Ų‚%—öēĸÝiú8#†Ē_—Z9ÖÜņôą]Wė-ŋŋ, u[7ē/ÆĒ"œX‚yŋR’īþčþps|Ö7!n[ĖĖÍ­áNKøyÁ’ÍfSĩräôEfú―|īÆ#Ē^žÂi"€`PfĀþ-ŦŨýķ~ýúՎΏT<؟Ž@1Ί/gØJūÖ/{°Æ=BÕïû QgæÔßĩV"6ģą_}ûąf>ƒjĻ+Ā߯ Ģ^>ōt”ŽqņW 1usß?ļKŌ\ tÐŦD˜(\6°Ã:k ÝŨŊ4‹Ŋ= 2øü°ËÚĄ†―~īÝíđŲæqÂé%ÖfæÖŦ6VHŧ—Zm AîĩČ kýÍa=„ãW Xšė5ræ’GÂGóėÅĢõV+Ļ/MÏÓŦčšįŌ=Q†’ų@Z|ņFp^!͐ý†O5ĸy<)MuÚæõ­ÄFŋ—(‹?ÅzõðūM~ûÖļ\~:jÞ4Eqē|n0ÂÎĘRH–ļ:,‹ÉxŽ ĩ ÏR˜hÞŊ{ũ/7Mõ0›gæÞ`éāáūKĖSŦNYhi·$Áþ·5ģå#ü ĸ‡―Ŧéq›ŠĒ°UBĨPÕŪąBlø;Úŋ€-,ĄĒHü,ĸÍT)TT@ĨĄ‚–mâØ“L’Æē8ąŋ{ŸdFėxš6/ĢŠŦĐĖY―Üũî;įÜûlg9H)æQ·)_ûíŨkŨohÖË€O:óôãÏūvújÃܔDuŦ#E@JbK‘EđîúĄïčší$9@†(Šý 혒 n€@b쭊ĒėļAž„=Mģ]?'§‘el›ƒ€°ÔdŽģøNŸ š―­ŸÚøãfMŊžûð=vŲ}ē.N $K E ąŨÞTjÕŠÚh ƒ‹‚bÚm7j‚$Ŧm/‚ržIājÛFߏ!dcÍðÃ"ÏÝÖīq^”ūúúĐĢÏŋüę%ÁjȒēĨ%dî“- ïo·ÅjMT6QXN FÅĶiƒá˜fÉØŌ5›ų"Θ”Yė·JUĻÕ7[Ķíe v/L ô‡,qD„Ĩ Œš(6š―8#ūk7TųæÍęfŦ›Ā|–,č„f=Ģ%Š‚Pßīýļ`öäiÜ35―7ĖČAĀtR$þ@n°ŋ"ĸö›/NžtüÅĢÏ9ōܛg>úŦ3J=ģ.ˆ ­įp7‡d}Į֖ V˜’$hÛĶ1$ô].vtųö>X–åļoĻēT­Iö­Q2;ŽĨév”儐ɌÖŋûŠ}3}ëÜySo UąÓÍ!iäÏŦ: Ėõd#ËÐM;JIΊ|ŦS—ŠŽ]Ã!Hä‘Ön bURšš>ˆų*Ė7äᰖ1ƞÃ>zA û\dät%Aūeđq(b­Ąũ“ŒxK3ûq–#ÎSTđŪ6u&Į2·Mŧ—@’ZZS{ČzëČĒØu@$ÉļÝTdYÝavē˜‘™ý+- ’ø&;!’šĨ3,ũy}V^?ž—7ðsmaōˆūnæˆHũûšÅ·Ų}îä;ĩîNKDļģp°ýF.šXŋī˜nbuŒ0)áÏĩÏŲ3ý…ã'Ž=õãåÝO[nv—›Žj8HīāZ āĀ‹iéÕOō‰c'Ŋî”ģ’ÞYĀ9âĒû›ðHb€{°ŋ5ðÂWŒÞW Ü·ŦEYĪžuáëģœ~ĸãÏ.FXÐ%öUpïō.VÓ`EâdVë_ēߓžqv hÉ āŠÃ%ōĒ8{žNü,ß&þ„Ž\šlze3XŒø<þÄ,Þ넮\M@øōþonĩ‡’zŨ/^ø~ãw7"ðXBŧsĨRY_[[?_Đüø‹äƒãÃÔÛļüÃĨËn‚ōÃtšûũîtZN'ĸ•KĪā™íK•ĘÅ äķŠCūDņ8ÝÛۛMČÃÐbķ·ĀîŽĪšgŧ 3ōČþaį vÜ(‚0<ÉÚÁ‘ö@.(wĪžð" ž !)D"qπˆ=ÓUÍŨ]ZbvÅVÂBý{åT—ŦĸŠ™_g―č?~·ęŨß?|ā›J<4P;444ô@ĩCCCCC:]Ĩ†j­ÓUjhhč|lLĸîŋs>įĢŠĩ/&L‰pŽąŒT_EˆþZ@2‚Ë8 >·ôƒüE|ąąEąŒ0ō:†C·Žų‰"ˆ;t9ðe|YððZÐÃ;ÎÝï9·E$/tĸÖᷕr>.ŋyó<ŦĘāíÐÐõAv*Åķm{Ôōë)øþŧ_―RÍģ›Ĩ”ĖŠˆōŦïÚĄiįpÅ=į\ĖÜM“îRû˜Ĩ$"‰É0 ðBy+.%lŅšŪ8՞§8ļ™hgfdčČ2b’G ÅtdÍđšáM2œÃķ8SĀČđW",7*q(ļđã•zGŊž5G_kĻV>ށæ,B={― ŧĘËõLĮžށŸG4ęÎŽ*&ï{ĸŗ_}ýÍ·§ÓéOÎōo$oÞüÜfš&™Ų˗ŸŸl[ų·Ļ‘Ÿ^ŋæĮæO ÅfŽQĶKDÁZfŪ*Ûš‚eyR†*ÕóžLÕA qÔ°‚ā[‹ŠâžžOcß444tR•·oáįĄŸ=;>ÂĐéœoöčŋ —äđ:šį>oĻ…JāDö{I;–äÁ„j†t –8íR1hˆ…ėtģ$*éĶz{,ˍf ļäœÁdħuÄë9k—žÞ;:5ð ;ę9ú‘”n=íāD•ļđ s’d€†rzģˆũFníÁ›$ä:L32ZHÂqÕĐÍļĻåÉō„ZxĘß(ôÓ* YyĶ ÓÄɚs.ƒą–cHŒyÜŦތ1AíýáĀüņ~,ũ­NOũ7‡ķļ‡Ãþx ]‡Tõp8ļ;ņã VDTG˜€;@‚˜Y2ėžûĸqxįubđ4(t`ØT+Éâ]’°n§Ð‡ …ļæ*8oį@‰Ģ+æŲ)ŽŦŪzžoÐΆ69Û§ĘS#ĶĨ+éļg)_+Te˜Ûß­nsžÖÎĖq7w‹rĮo%όŠ[Ģķcfq fŒ8(óDēå'€ŪqHŸsf?&―ãlfwÅļ ÜSŠ<3Ũ§­ŽØÞS―Ó444tŠ]ųëf`ô!8CO8›$­ÛFÚĐ­s–@5SxԜE„˜í •?‰ãļjļUkÔb;°3o‹nĒ žņ‡JŪĀ1ˆ.ípڒQIÐÛô įāZxiA5YœŽÍOąķSržŽĶÔýÜI ‘5'yXą‘Q ŧ’ …Ņƒ~w”ýz%ĐdÜāP%ļ›ēïŧ’ˆŊ…Ōģ^Ģ-ŠJaŪE`”;ABRL‡†HŸËô†pŸs?†fý!!ĀÚ'Ĩúš}A’ĀŦĻjOœ8Um–W[OÄ=―ïqųHÅŪ5éēũĩė—áÍ2%#Į0Dļâ1\%‘HRģ՜ í`SÛdz ĩ(‚ ɊmeĮdKÏÞĢŊðÏĘ™Í5ËiEx_3ĖŽþ1Æļ”ą;û=Ã3XzüŅPRÝCKlYÉĩf,G$Gemcô+§$HÓŅķĀͅzMÛT5NŠ*ŲũÓú\å)kdF;6VøŦ38qâĪZÝ4ŧ™ŲÖÍ"8wR/Å_’Bå#–Ŋđ:á~Itú5EÍR2<Œ:tŽÕį‘ŽŠg­ĩf/yŋ^Ŋ>ķ-E:ššMRð˜xpˆĻ ģ’°-$ÛĒfDđ―ĐDJtlD V( Ī—ķ5ÕĘόhéÚÃąą2Je+SÉ ‘"k9 J%ā•E#ĩ.8”žTėaŋ^SDņXÓrŸ%·ÉŲũ™ J呕*'Nœx―Z ‰bC?&n8äd‡C›SdßũČlJʉÚQŲĒĖŽū.„œūŠøPýŊā-īļuģ­)ē™šĶjáî+\_î. ’ðN 4ņÅrũ1†{D†ššj]R˜)Të|‚ģ,W5›ÕzxïKBT ‘§fDŽÜW*#aĀaÚf݊}Îåkl#%}­ DŸJðîîÅ\îkE‘øŽWĶŠĐ-_f:ķąÜį>Ą$™râĉWÐŦĨØØæ\T 3Ũš=ŅĘ*ŒõãörïnĐĐVέaįœ„Ø)ąvWęcÖ+€ۘseæķm\ũÝÆ ŠŊéáCKÃöžˆ,įwŨJ°JæÚgýâ…d.GæĻœ/n €å5ÂŌĄĘš\AM›‘)PZ$Br˜­Ēðm QŪ}FŠ*%ģxŧmb SmÞo)ý44Ŧ,W„;•w6æí’„Ų螥 Š)§PÎĩGdMāÆ~SņqÔ|ANœ8ņęyĩ[W§Â)P\&ÛÖCóĖRKsNe ÔŒ€ Ëj G;V; ĪÜ]^†™JŲĨ(ÁœÍ­Ō°k_3ĘˆååThBVŽ,?!ÛQ…(Qéą(ÕāĐ īŨŽäĢ"/=;ũVÁ[vÃãrđÄũ™"Žëžą”š]ķōœģeęž° „Į‚RîĨˆĮØ:’aĨąå(iÕõ蔂u‚øTĩ'Nžš^íZģ3I)rÝũČę†53BīFö‘2ƆŠH‰Ā†™ŽgĐR EOĒC§ÏęėššÍz4?ÔeĘŅ_ėsz7ząŲ°1ŪUvhĶNwķĘUõđP3ŌüW2%gĩŠaRtŸýFmû‘óEįī:Ĩp―z8•R/́œevũvsVÛ}Ÿčü™Heŋ0†Q‘™ö&°•Ãë]ÞĨŪĩŪû=Čír™k-oŊytX82!'Nœxõ ÏÛPÕëõū(iä ŅĄ{w‡$Ļ"Xûę ä>ũŽqVÖš—ÞãË%ép–Å€Š6jŽäq5Ð.—yÝĘyÝUĩhTŽüŽÃ(3Á~―  MūkĄý)đ܋ !ĖĻkSũÕŊHQn"„ßwÅŌ–tfQ}%Í,2 Dč>+Ō;6/'WęÃĶG‚―Ó oÁŽÎ‚–\UJÃTĩ†xYuaŦÕ6Đäxū%^úĶÉįãĉmfæKĶZ%%ĨCHŠę%3SÕ"ĢM†@]#Ō ėĩ1ðïŋÛ^Ô:&eØļßŊŠĐĪ4Oe„)AÕĄVV̓īaūúčá/;ė<ÍÁ"cŧ\Š+Ķ67E638,T23VS§ZԚÂÖÆO­ģĢō_ÔĩI6mŒbCeûcU]]ÝFóå―uPMÃcÅėw,)*T{đPáŠ]ð'6ˆßLgU ôėĩlÖ#ķĨdŅ―,ՌYíÞķtæZĘÃ―­ŸÃPËÎû–ĐŲíyôëzŪØŊ\9_Ų"]НKë?„Ę”įÁ°ņ?üb|sÁ/—ąmōœ8qâ+_ųĘĮüōĮbVAĪf@S‹å­FÝÔ:ž}{á@úû€†z:Ūß*eĻ‹ĩ–Ŋþán:ð4Žą=ņąåvUâõrÉâû6Iį>å(đĒuĒŠzņeƒžš­LWxļŦõLĖ›þLĩ>ēƒk͆uýŅ3īÞ9ÛÛÁÓ― ‚‘‘îþĀ_sNÚîŋ:üð­ŧÛĀMIĨ $Šmܝā}ŋvļ"sō< ę/•;Ļ֕ČgpâÄy&Ø!_úX,"öëUĐÛÆžþ7KÖ^PĻUP‡ˆôøËLûEðÔčí=]pxꀁxäĐ0$ŧ­;ÆĀ fĮ2zo?ŅƒëëÕũŦîÞÓ<%$'ĐĻvVo;1V‰|ėuß{ƒmôøŦeuoĸZu=-K%ĨžŽęģ…kjUÔžGj―ôdŧėÝkę )­ÁûÜũpŒ‘YuŠį$D|2%Dîh$NŠý,NœTÛlÖßŋ|ÁnÐĒ%،Ãv2ëõŠŠÛļŽðėUīŊ^ÂmRT˕ŠĢ ÎĐ,ōú•^čz —:5…zw@š:Ņ?|” GļŠā7Ėâß~ö?PĪ_Gj đĻ2Š’QDŽäS&aëšŅQ‡RŲĢÖxëï“P22ú!ėŲ]ôŠÞš6ķ‘™sîuýĢ…đ!ŽÚâ…(@øŒgˆ‘øäSņČ7ë.“”Ïāĉ“j /Ÿjákę‘|\_=įÁđ­aõ[• (öēӗo6„€šŠI&Š=:§vðW-'žlÛ*ߓP𿊈&î~G-mÛ985Þßß+ĩļĩˆXnÃ}2FkÕD’dũ€:ïÉ[1øœŧ4uJfWÔM[5ÜF*ÂEԌ”RŧOw`Fė%ĀÛ͘k™ÚSðKÛdxī\(ØŨŽë<æu{QŽ<2ĸþđG~3#ōTĩ_bœ8Đ6KŪ*l?qe$( öĩP+š~jjžXkŲÓ*lz’~ÃŌĮ%Ü―U‹ÄõÓ{TŨ‹›Ų+ļ*öævŸõþzíôBÓĨЂėE3 Šūģ-Ō3ä6Ü+ˆČåŅĶŌTûއĪRŲ5™9} ’éÝ>PíuÝtčÂX—'znS9ęU*“![ûkf QFGvCēîĖģáJđPøyÖĉ'Õ~)ÚbËWÄ"_Ę>v9ŠTíĘК*ôš_ 9„ä)uW#+o`j(ĩ―ÓIJl5  Ũë^LĶRgíˆôŠņð*A' ƧSuqĖð~ŌoāáHäíëčÚ KîeėˆĖÃĒ…‡§‡ÓĒÎdG/2|B8†-—ĖØLģČWŠgUu. S‹jßúa ēƒ :Ũ\ūžŨ@xãu―WūāĪÚ'ūÔ^-@šÏŠŌĻ‘ésąĒu|Öۈ īD5VoĒ5aŊÕ0ĮŪĐČÁSëA$Đ֖kŸ ^ÏãTnŌá0Č0{<Ā‘ĶzŋSaEIkŪ§œ’ĒÞĻ˜ą—ãtÞUŽ%―oŽÄī_î.ᑒrЗƒĪ,Ũą] éË3ârĐõfėĶFõĘUoņk֋Æ0ĻŪë~ úŒŨûkJŒą‘ęEĐÛķeĪ—Ũ1ķáqCM–Ïeßy Kņš åĉ_VA”Žcb=âß'HĐëL‰D ĪÚ[]Þm •ĶäōršGŽ9Æ%ŽBkķĀėãl_'•’Ō•UvŠ[KTĻ]ŸMÉŌŨ·/36Ö\‰4U öëÞy1mqt•vđũ6Û|­WN‘AKĐuÝN6y7ŧī͚)6ú^GÉę#ÐĶtŸ))ŽZ>+ ÔÝčÅâÔAŋđUÝĢÓ éëW蒙’gŠ=ņÆkē^\T!å38qâĪÚP)ŽqlmhzčD―Q+ļVÓÔE„`%^ũåGÂĐŊ"Ax Ŋg{óÖķՆ­ĩĻPÓĒ\Ŋþ(ÜÝČÚwĩætĨYáŠčQRĮЉjy%V”eQ2|Ūę°ĄfŦÚ\ÛØd] ĄŅĄ+VÝ "AÖMŊA$ŨžÖēdxŧG.-Ü.㚉ô'JfÜÆˆúŦŦ6Â=SŒÔķ/D M„yøËîģĩðVނ‡< d~g|üÆWm”'NüŸ°Öúä“OūŠv•Ĩچé>w°h”b’QDeŨņXĻ$úDŊޓu?ŊÖk·byđĨÃt^§? Ė#cTE"€d)ÐLQJĨ&6Á.Ūu€ĄžÍĨ_Áqãr'ÐûÖîžA3žūŌ6óúa9Ūß#R@1ĮŠ^O€Šæūâņšy-Síoą>JgįvĪ— IŽ}ïüƒ”ôA„ĖŽēFŋē§ōéÄ_'ņ\uÃïŋýöĮïĸÞüāý?ZŸþ›_Yʉĸ;NUÛÝŦüāņē―Ú>ûÖFŒĪĘė>”Ięs­1Æ6ķcҌŲņpĸĻÚÜ'A’îŦˆ˜sEđĒ{?€ŊäšËëð˜=Ū™Čļ>ýÔÃTŅë^.°šŊÚ°%ijŨë5%›é֚đąŨũfC"—ÏéģPũŸ~Šj7Üš—! “Ė5Z™3/,c!ÓŨ3Jʰ 2ģÔĩÖfĸŲ$­ôx}˜uPÁS7-›emc S"EĩrĘyCÍî,Ÿ‰jŋũÖ[ßþö·%CĀøœ&ˉ'úT­—Oĩ!R]ÛŲ3ą $83K_TU7X^ą'%ŠshoŊÐB^ķŅY"uXŠö^Wáļ{ņįŋóS},nĄ—ÃVĩáĻŌģ(LI$VļŠv)Ŧx ‘q°|ûÓ!GY€”LÜzĸßĸëGą<MįáĮņ‘(ZB8ģÞИ}Í9mlĪ{‡Ã|…Ô;Úķĩ? 6XsĨGŅŽ^į‘ŧŧŧČzie†ĮZSÍ œÕõ $2Kž?\îîäĉ*2óKöęņҚ1FĢē+ĸQ;ļ QEëđKíu-=ļöÞrŧ•?ëËKb“þóŠYŋúÕŊþŋûũÞ{ïŊ=ėŽŒðÏ;}Ÿũ? Yĸ†§ĸú9?ffïŋĸþ?ųĮĸčƒ?ø}ۆdÎđÔLÕz{™ãr‰ÚÕ`ÓmŊÝ1fÖŨÝ0(Ģ™ÛÝV-7A ëhē9ýr·If„·Ëæáõ!Õ­Øë2ŽĶYŠigr_þĸ‡Nœ8ņĻķ*^―ûĘÑĮ“*$HU._ÓĘđï­s—ŊVš Ékb­§)‰XQķĶfĘ_ýÁ_{íĩßýÝýãĸļ˜č É/^ü­ŋýÛĸüŸýSŸŦöuq˜yõgAŒþ ‰$AčZÞþī”ËĒj>LiÖi0č°(N―ņlŊ:öļ1ēëcŪIU‰H ï!ĪÓrâĉWj“ĪÏJúÕúĸ@wˆĮ°Ųk·ôxšïõ:ėĻŲZĩËQ"\ ŦRbfÐ[ü*ĩgROčv\› õjOÝ HÖ<0žŨĒWJėĉŊÕFķią“Ø‹›$u%’yĖšĮ6úa<Ó ëʼnzÃĻTV·–Įð­7ūýāŌBäwÞųÅ/~ņ“Ÿüä›ßüff~QGķ~øÃūþúë_ûúŨé?ðiG"ūžœÞļæɞ2íŨ]MŠ”k@ĄęĄ|éæ‘‘Ðū]ÆãÁ6fĮz3$jĪBũNœ8ņ*RmŅgh›UՊ,Ķ SŠÃZË[Ŧúa,°õlŅëVĶ­‚ė6DxذĻÖnāwŋũÖ;ŋõ[sÎ7ÞxãaRĸá‡~ðÁōÅĀÝ{QÃýýýo>þõ~ð_zĢÍÃûÎ9{ŲŪŌÜ=’î ƒäę­4fûuïóÆØ:M jŧS ™Ōņ Þīžė”žîŧÚg ûÅt4ÝŨ~“//@EzäĸÛïý ü$*nũgyŠx„œøŋݧLÏüģ8x*›/ Ķ,3-óÕTĩîÆ/gCđVĩķŠ^{GĒiįaÝÆĄ CRET­ŸÁ€HSR—q›ĐĖĖ—öŨŋþõĸüĢęøŊMūīÆlŊößøÆŊ>üƒïE+>ݝj˜ĩūāē]žö|KæĩN\ũ°m›kĶĪĩŪŋ[žý ĐĪôŠ/ÛVĖū•ūĻv€Hī.ĶÏJŽqœ<+šåĻŠdFü/öÞūŠckŸŲvNNrâFÐ NąB h"EJą"%EŠw·4wŨRÜ]Á%4 !n'GķÍüÏĖ„öōū·ĸũĢßwï{ŧ~ũWÎÝŲ2{Î>kŊYëYÏóāō Öōž>Mņ)QÚÓþäi sÞžČ‚>ĨĖ)‚\(ųUšl .æÏAü?óŲŊ_Ī)RpĐĒmgãýcƔ•ŽTx~7ŸäâM 'ÏũÞqjŠŽ#z8Þĸb —,<]ô3ÝüŨ[á‹ŋĸïØņ".Á­Hi_Wã?Ņ!þû -ņéηho3FˆM>räF_ūž­š>úļķŸ‰û7xþðđīö8ĻÓNUÍ/ŅØ–%yFn"J"­°“Ø–ņcQ6nĖrŧ$6ÖãoĨ/.Ė‹ĪLäęęVąb%§Ÿ}ņâE||HãÉąÞDÉ5ŧßâý6ĀAķÅ(Ýß9yÅoÄý9} ņöžĄ†/T …uÓ{ũðãCü0ör‚™íóäÔĘOë7Ŧ_§ûˆŲ/,jáŧ€|bí”f~ŌĄßą˜tžĸãu9^ß<ŋsëúaõkw=ũĨE{ïdčŠâP4Z&áÞ<<;Ī_ŸˆÁû uęÎÉ üõ ēE&qÞë3‡OIpBáQBNĀĐsGœ{iß7zȋ(ëÅôá]ŧõîÛ·_DߞówEČýŽūJÍ\;ąÍĘßnAI„t›û~™Ôsâ/—GÅfČ<$›ĸã\- PåZúQ4•Q ĖUÔ=!ŠS"Ð}âMhƒ,v ū•Ð4Âo 0Nrų!ÞūūEŠ•.]Úl6;]­Á`āþ2cųbâj―n"€žAvžáíÎ<=œš$ō  o/$ō9;ƒ$莅ĸJZõ|lž.€Ž˜œëØÕÍÛÛĮSœũ!äû_v~ČąĢ …Ū…10yGÞĩžNˆ9—å]ģúGÕ*”v8€ öAŪūĨįEmØūq~öĐõQĮžHũÖ‰)·ũu}Ð/[ĶŨS†þ09Eø‡xQÏ~im?rÕķĩó-įWM^{…bÕ!đjጠŌëč-‘+9· L{|ûJ\fÉŠ5?ŠXÉĮl|O ųÂóFū;Cá/âÝwÍÆÂ‹ėÏę'!ýŠĨ‚-‚$^^ūxõÝ,I’8Ņ-°ļŊ‹ß}đŌfįc!þ‡k1ÃP’ÜžŠ)ZĒ”—töĀá{IŽsWĄŪF|ËЇ6ĖiÞē՘Ką™‚ f=ŧ0ŠïÎsŽþy[.ÉZ ™qįĩlŅĄoß5'S‘DÜĪ§Ųį ŽĪ;‹6ė=ķkuû-†FnwîĖóBÆÃó[ķhũ݀)SĶl8ö€Ïũ_PāՓëf· oŅĩĸÁ‡’$%ß;ūrËĶczŽŸ·3ð§ÖÍkÛ"žeëķįŽTh>uĮŠ1͛ĩâŨÛėáå]ÂÏðčČÎĻgíž$Љ9ówūŊŲĮ ęáþōcw9öŪ Ïđ{`ŲrĨĖVĪÚÝūíũ}ÄПU/æR•ÄH/Qû‹æu*–ĐZĢ͟|̓œ _ØŧÁ5ėÛ.ĩ*„ũ›PŅýęáÛi‚$Āwt•k>ufÏf5ĘÖøĒS݀įÏt‚*ÏÝš`„s2'˘ąhöęÔÔØ)ģæÏ™4ôŦÁóŸe**PkÕiuŲĒŲýÚŨŦРëčoÚ^]2ī{ũþãÆŽ6|ލD{ņråýbĀž39Ã"Įļϧē;jĘė3ÚĖ1ã\ŌiČÜ=QJ{BēïŋQ iąÕu‘ķxņƒpqÏįwžR’„Xoā‚KE, Ã$‚ ÞĻTč›Hi”DDe4š8áīé‹%))I’ĪŋÎÕ2ˆļ›ÝŽyVw „/†|ÔÏæ* QXMŒĀ4•Ūî!I·Đj>Ĩ$/ō„Eæũkd;‰a;˚ŋƒü‘'ÉmM§…2‘\…ô}ˆī'XQ(‡šĀqãþĒÚ‰/Š–ŨĢ/?é7qzĢOKÖðĘ>Þv―Ü;ĒdíFôÃäë·j„úŋļ“—tQĐÞą”›&”Ž8jÆēŽåqŋ­ÉQdųF.įč֋ū_ÎéÞėså“ĒįmŧûÂó­Ŧ{\ÛwMÍ0īČ8ýŅųdĩ‚ïŧTô1Žøbų‚,yŠī‹ÕûyÅüOK)wÖlr(jō―sÉöŠ‹~SŅĮðcŦČČ,VJĄÎ‰sŊXFy°ŋ”1$â\ĐÖģú|ÕDU ũæY lÚ{팁 aõŪ―é6‚ÝvE Ô§jÖ]šx/ÐtÎ\þģjâð>ŅāŦ3įåĮŸÜ}’Ô24ĻˆÞ›ÁUÄšŒ›N\Y--yĮÚE=ÚÚmG―’F―ĀĢ]•mŪÕŦœ{qâü‹­JĢ·Þ–‡ž‹Ĩt͖AôGŌšŧúīN€ØģHĐï rn8ėįŠĮŽm[kŊm‰)ÓkUŦ†gƒsĶĻ‚oŸy'š›†Õ0)Ž’ĩÛnßûŲãŦ[ƍ ;/Ï܃ƒhɏ~}X&þÞYՑýæå‹Ôž2óX|ðāÉ]ššˆœ[‘âĨ‰§ōïÔЖ ?đ=;\>q"9ËãՃ[y°ōðy­Ëw[ÕŊŽn2-æIj隁āßĘÕÅ*6TÖEÁ 4ÁD‰ē肗bð!ÃŌRĻ,-ląž`Ä1˜Qąˆ͊1€ã)ãĒ^ēt°ģ=Ėn·įääΧ§ģv‰ŋ2Š%æL gΧ@Ú 0ųéό}‘xĢ·ōeÄ]ČŅĒŠĻd95EĶ:æ(.˜ïˆIRF*É8ČIö_–á7 )&ņ@<ŧŽuMĨÝ ú0æ!o …ûðē4ĮKĪ:•Ø‹w“LĨý―]0FAĪjX6­Ôļjųœ:ŧz\ŋÐ4`æÄ,‡>zmpÜÁÓӈÔŒëÛJ26L"Ī‘"ųvƒ}õ°ąÛ,ĄC:W+âb”8 )6Í!åkģåéųGēĢąƒ 2‹ÛtĶšFöWŠŽPö“;6=HGŒON’RomėŨsC‹QƒJøûÆaŽĢc(áí% D'Ļ@Ĩ P|ŋ2.Q4Ā€Mĩc,ņŠtɏ݋woï?zĮœXSüg–Uō$ŲĒāReËWō‹ü­mĩjŠĒýūԏ]<Ëų?wJĖ…ð˜gÉ K•Ö°žŊŪ/šķëéüßúūÕîŋ4 M9 ęŒāČė­=ŧö ôųŒƒš`”||Ė’GŅĩkąŧ7yú˜>åþĄÎgvŋ2ĒEMӉSÐČWË#3!p(yŠ.ģš€‹Ų'Ô'0īŌ”Ïލ‰U[V‚@e'dóÏPĪtHH9đkūŪ^Rð3ZŧģÖÁ=kwí1cÛŪ/ę~đsŧßŅ_·üømýĀ“čj0đ‡VýĻBíîAåLŠC!PŠŽą+dï2ÍĒRŽi–ŋ‡ió#\ðŽũCŧŌ’D+šÄtÕôŲÐuŧ>þmŨšA{ÍÞĩģYEoJ“9AĘ{z|FÔoK/‡ E‰Þ5&bä҈uû:7*ĐȎÂãƒÖķĪ :{{”Ĩč ŧļˆLO 0#‘§ =Ÿ‚…„P"RŲQšUú`Ëį,á+„°ĸkšZ Ž%.•Öūx&XPūvĄŽ ADžÍp"/AZĒA ™ ĪCķ‚ĶąĪ'Ë29'öĀÃÃCŨõ{ũýûY-M  k”ÓÜ2Č3 ĸøYFëâb|üð…d=?ÍĘ ĪŨiˆRß"ĘĸEéÁh2ãóÐãā‚ųīíL†2}Ģ‘ŌëĒČČ―TJaÄU™*§ŅŨ8™%ž“x2]Äoaz6ž·ĢÍ{ päžđ~|ŨŽtŊW7ÎíÞ3hÖÚ•Ę~Ú(dãšČ@ÜėĘöõķzMËņþ<4núŠðå-ŠÔPmqcōŠŽüĒ‚›ãĶX­*uĘēÝJˆXWlyÝŦuÏ:'ĢæŪ)ãÐnï{āžüãâ—Įį–üÄ X-é·ĒŊīl]·„aņÔųK›OŸwā* ïCJÛ6›F|°e9ōæÅv›ÕáPŦ7 -ūūŨðQáŪ9î>Ŧ,"ŽR\”lÉzųĘâ)‰Ï2ģ>žv3ĩ§ŧŪäŲė!xvÐōÐÜ sËĘĨ„så/\u9ÏjĮô'jģĘ*Đ ÚíēÓ@ýöý…Å­ ŠÅŧZ:vŊēíáݖŸtÆđ™đöĒ~Ū…ÃŽĮą'Ož‘ŒĐ1ûãecßR>P@ŋÍé·ĩß6ąÕíC{ã4wœļ)Z/Û=˜üÍ}sûFĨî=šŽ~‡ó"VŪų5HūšøeŅĘSŦšđvéZ―P:'yJwdýuLԒóūĄ:4+Ó°aāŽå3֛Û^_š0Öî.`P$ļž#eõÁßn~Y/ĞõäæÃ70ũņދķÖMĘ ˜öüž…L EŠw/ēïØÝ֟īÓs“rīꙧvÅdš” ‘ÔX]Uî]>w/―tųŠ^ķ˜;ŽßĶ›Ëž%IŲBRjvVē 4›UĨJuØėÄÃ:_Ū†ÓóW]ûdLŠ͎‘–œä(á Ō“óRïÆÄ|RJģ[ĄĀ?8đýzĶ[™ÐQ‹C:—óøh'ÆÎ˜þYiÃþe‘ÏówĻ(Ŧš ÞÜÜÔŧũ\Ð|˜§íöÖ-wj‡5(áíúû"0ĄŠ4Œõ[ԝŧ-2ÔŧóģĢk*}^=4āÕM‡l7‚‚ÝIúŌŋ[ĮOœžXĘöSä-7hYgþķ!^ãŽŽIŽRŋf…"ŲŊîūžÞĶ]k/ûĢ5;n†ĩkWÎÛšyåŊšíšW+1ú—sĩĖGė$Õ4Ė—™a;ŠËDÃu7ûŸŪ*”'[ ŦfĢ ĒÍāI"8€ĄŲÃ=0°AAÉō;wöāþ‘œsŨŨ‚Ė! ąKg6CĻl„L[xŽęŽč9ð_y^UU ˆĘdŧ]'ŧ!ņBųL]dH”/†0ØŌŠ"‰ŧÉēņņÓęcØÁė‚<ŊĘ G‰đtJ*CYf0…ÍžūT _Ía“—ũ[^4MS( ”ž‘Ģ”4dę>\Ū ĶšMZ&Þžē/ŧ˜}gėØŨ°z MĮ=O}=sæšåk<ƒkïÓĮčÆ*͍üĄY“âšüqĀP{ívîšj7øŅĄ}q7ĻsƏ›u‚ŒHôûēCŧ ƒV雙ã”7ہŨđ‹—Ô ðp7ōéâ{.W8lðåGį^ŧÎøyöĪĐQ{ÏĻþ42Ó§ŽŪóÚv 0ō.Û·6™%ŽëRãķ[4ߍ›ÖnßīW/ÚļŸk22ļĶĶhEktw|įþj Ú4^ž|/õ›ēĩZ@ĢRqíÎĢ#ąŨúßķ_L+ķ,óQ“ŲĨxĪ‹TïØÍÅ_BjÕĶ-,ÁŌļ Ú“‡ ŧ ë…x"Esí6nyæÜđë—/ä\Š|[šæG4*. FJ―t2ęÖcÞ0tÎĶ&eOŸ·rãUĕŊŲ­qóēMÚu,ëgÐuXĄa;ÏēÞšöžR7iŲ™Ë·ŧ7 nÓþ ģ! ïäÓW8ëÝøĮÁ}Ģc/Ī+UZīĸšŽŲ%3ëōoû3dŪûäąŠø*/ÜŦ†ŧKžŪ;\J74ãSž:4‚åņ kûm&zģsûNJÔŽ[ŌĮ üî>8·š ۈåÜtoóÝø—Yģ·­Zaô/ŧkÁÐŌۜRŪVSģ› ŌÁXVļÖÓæÓķØ…2!ÃÛũð2kÖÖU+\Ëí^04ԓK}n˰Z5ōÓÍˈÏVeētMÏÍpC*vÁĸ+ƒĸļÕÉķ5jÄðßöï3đšpĪӟrwA(HĒĶhËE#7"΅piSgAųŠtâz˜žđŽ-^ŌĒ?ʕ*]nÂĪÉ%J”pb–.]ƚwßĄį’iĖĖâŪĄRđĘFW_Þ ‘h”·qĀÂ#+Į[8>‡‡đ<—-€,eqX}{ø7nģÛ(Ä;ƒhŦ%;õMІ5ø–@‡ĒxQ0ĪÜ]ô &`ČM Õ?į9ĶōMDŌhe‹ĨĐZ%ĀLt’ę˜i zlIZ NŪÓT ‡ˆéĒ(AH6’]hŧGNvVûŽ_OŸ5ĮĐĀĻ †gÏ^8ÃðRĨJþĸ'…€Ģū TEÕŲt ÛĻ)2‰49Þ(‰:QÅFĢ ā:!o4ˆšėÐ09ÐdYį oųĄ•Ēhˆ ŒÅL•P4 \ÁÝáМg&—ĀÎkņwŒ!ŲB'ēį™Â—Đå’y/jÁÕIGwĩŦæMFõûĄēá*d1Še‡‚A>V‰]kŠÆI"‡8 įˆSĶ;ģ“ŋ’―é­j˜NÁÃ Ģ‘§,l*JŒ'wĄŌTžbU–uĒjy ČDú D ptēĸ1n"· Œžrý|ÎÜyÎDíĐS§<˜Ÿ'ĢF]S^š―Áų•7•ĸ܃ į[ęQOČ@ü€:Ä:€Tnk@Ėų#|-‚\ŠÔ8$ck– ÉDgĄLh騨{YY™ÆÛ@ûÜ#ŪEŽï–0ýŒĐÄŪ‘T&Z肉DŽhKß."}Ņč .ĘbKÁ^˜Ļ9Pĩ4R”Ķ=L?K0Æü[[MÕ%Q ŨVk^ĮN]ĶNŸų\íŸh úësVäuų'š}ĩ[§E?ˆWtĐzĢ–ŸT- ‘þ_۝ÔĢĒęŸ9ðÏ_Ną&_‰ŽŦüi=?’Ïïå fK{ü"™ãōĩõ\}ŠðåĸëŒ=ŸÝQÜÕ~ÁDÅ U XŧĶWâ™î [yĘåJcCZŊgûˆ’J`OÄ—6u7‰mrĨJ•+BjjŠŪëŽë!ētô\īū0ĨˆîbņęfüþˆéŠnĄØ<€i H@s“•RÜ*ȀÏļ<ä@!MŨē Ņ"čĒÝĄXĄ O; &ž$ Äį’1ðãŒđœįyB.ÃHu §Qí/ž+ˆâ)"%§ÕžÍ`QŲ}é:Ņķ!bĪƒ5•ļu’HŸHþ`‚G.ČųRÚüŋ‡yĸ™}ÎWoôeÍ0ęPĻĶÛŋ63?ųӇžXr”h l„ČÃũ_ &ŋ*Uüßý‰ú[ĄðQĸÎt3Ô €— ã‹Ą|ƒ"cŦb}S$îĢÞą>+bÄģPCÂ'€•ēΧâp8›Ä*WŪę i‡ÓÕ2Ä+Ŧ02Ôę ·$žŨą ƒi銁ĀX˜Ū#ęėIŧK0ÖsŽįĻãÕ9ę? ǁ€ČIéaĨ?žįt:Ĩ ÔKYÃYáQ'KSðg,þã ĸ‰… ­•ümĸ;éfh# Āļ€ÎІģ4ēS5Ab­Pd―-J„\!ÖņÏt ĨŽČcĄa>ɀ§—w‘"E0ÆN?›––FĘČŽÍ!ÚĄā€˜Ã-eTtð?t@ÔĎ&ĸbO,y‹ī[ŧčÐ0 ųŽå!ôD·Ý“•k* iGčP€'Ø;c‚ÖbŽ`ÅraŒYžËt7Y恑‚Ó?‘tĩР֟Ķ*d#„ Š™þƒˆŅŨ Éi” þķŋíoûtĩXŨY•J5`ĒėP •ĸ&™6FĒ( ų-žΘSâOyAä`>%ŦĀ7ÄX]$ƒą\đ“ BČɗhĩZF#KŌ4,Ȃ”1Œ$Ô9ĸáʅ˜€ŦÞĄL8hu‡ÃP4ó 8ϕã­Ũ‰ŦÕhō…6"ŽKĐ#– Ģ/ ]SQfEÏPú2í^–Ú&érÆÆCŽ ž€*92VL5ÍsāoûÛþķĸ@šžã ŌiÜ*ō<ĮēiŒ•Š ĮBžÄĄhL؆"™qł@6rž(H­žc’ĐDI,_ąĒŲlvr'ūzõА›#‰1‡K Ð8Ķ þ ŪūSlÄĸįËcļ]Ļ V™KňĀý˜ĢÓØ?4‡({$R#/BčEvÆ Fžcē ^†/f4Œ Ø@N=ND %æÜÎ` Ûßö·ýšZN <Þī•gøY‰aeĻ‹"T­‘–*âziM‰Q$PHϝųĮė@“‹kHHĻŪ“~\gðP{[CüģëhŠ~… fČy]ÆXWlÕ­*Öþ‡õr„…p#Ðv\Ž•é$ĢPęn*g)2Š^–rU5!…Įąn^♀#•ƒ• f΋ΑČ+ŠŠB‰ūÎ Ģ“―1øÛþķŋí?ÐÕԘ `œ (Њ(â??ŽĢÜŽ„•ŠÂþąs;-Š 4õĻČō[ nކŒ?›ķN-V,((ș7p8ÎĀ–Ü @-øÏ‘öCęÄ_?ÏLO4W7…åßí›Ē―:}ÓČ·đ·āiGŽĸ&ȅāý†iøI"lĘüĀj}„ RŨ—óĶhUrÔ·ēąBFCâa ‡ĪQ?"úš Šœ Ō$ĄģáXŊsū­ķ d•ŲļĸČĻöoûÛþ'§a,!- ŅãœšŪŽ` ÍēˆÔŅYbŒN…tļÓ+äēŽ^D[ŦT­ææææä=pjÛhĪqK,„=Ājļ’/ÂčY°Ną\ïz$‰:_rãį[ …K^šĀ%t―Ž>ÆHž0 Æ)ēĘœĮę„6 Ý!3' "‰g‘No˜ ņü‡Ejf§<;uäbŠUýƒ €”ËĮö-\ļčWíāpäĨÝļpîė™3'Ϝ{ô*“ãá§äĨZNn™?bĖČYÛہgýÍÖĖ„ýk~‰\ļtï…2ŪhlÉLžtáĖ•G)ĸ(CÅļ”îžHą9áxœ“øëēE —ozâ8îÝ~Øþðú•čûŊ Ā…0Ą”—/\‹U!—õōþ­ĮņĒøGwϝ<}úÜÅį)đ€/<ÞēUë]&=ÍR ŦŠqP?ēlȐé‹ÓSīïŅwÞÉį’$ĨÝ;ŅýŧĐKĢ-øåðĩQþĀÆ(H„.đOŊm]ŧĢZxŨfĩ‚BīÍ]=·gێÃ1–”Û3|đöÔ-N’‰§vĸĒÝW}ĢŽþŽitũüų˜{ &w7ĢĀa øųy› iöóü\DƐcO―sėėå,ÝčivïŒPL)–ėg1įÎΉĩ>Đb€ ņá―˜ŦŊ‰ãžŦ5 5_ļōž 'ōðęŪ™kŪ+3MŽä."(<>ģfĘĶ+<íį€î°åĐ\‰2E<ˆ˜?ē_ŋĸÔ%°z)OYâ2zâžKW=ËÐ=gũėņ#fΙ8bøėUG‘ŋģaIŸoū›:oޜ9[^Z…/úĩxzîv’ód…j–oļæBO””™ōúÚņÓV ÍkC„ŒþåŦøž_ĩtõú­GCëÖ-jPA ĸxϘˆgþüóŠÝg,X”L9düœyÃ~qčÆ+åí›4ĒįũÃæĖŸŧbÃy厊œ0dôøų3~ę5lÂÅŧȧ.íÓk°AÓĶîŌuÐĄG9Ɗš?f𐉠O^x<ļð§\:ņĪå€0ëODü~\däėį)HjÕŋųÃŨSōß!P4îí™Þŧ_ũ^#ĮžŒy‘ôðøĻ!Ģįĸ<}ÄČiwÓ4&/ęÝã‡aCfMÓūÛĀI3&Mœ:ŪKŦïŨßJî_ÞÕŌ!ã.$IŨtUQh6€Sœ&+’p$ûčĖO2bQĐÏ‚(Ę5įv?'ŌËáp8Åq333Y\`õ1šÞ|ALI–ƒxŨoBęÞ~9ý”‰7!‚3ƒÞ>™˜’Rtģ•~|[ØjÞīv#\‰mï^žĸÂ*kįU^QÆ­‚ŒäũÄVũ’ÄļtÖģĀpēŽÃÂyŨ,ĨŒ*kÞeð 6~UU‰ĮĪëŠŨ@&o j$…] ŽÓ—ü íÖýpöþ–yŒEũWÎ^tûΕģ·Ød5ŨĒ–ĸī[ÏwwOüĒS·­7’%1$–­œy5ŧށc‡öŪžörũ’ßĒswˆĻRiÉĶ™Ÿ—t+Pp"žïĀąkŅOŋÜt ėÓÚÉėĄũ ũbėÎĻgsgÍō0"ŦFxüŠWûÜ#ïÆÆýįoŠZwųL_;‹’ĐưūßĶÝ=våiÜÍã/ûŽæƒx„jMËĖÉÃäœŌo‹4 ïøÆĢzÛ59Žą„`öëd^võō2ĪŨïÚ?ŽžiÝôŪF.yž‹Ōt˜uëüagÅj{†°†Me[ûåĐ]=š5Yuâ6ä…B‹Wýþđ=ãĮY{WĐQĨÄ BƒVĶŽË›\žšoŌščXUS) QYWNä”E Z5ĐîÏļŒuGrNēJō-‚zjքöÍŧóŪûÍįÁš–”øØ[Ũk,`M{pøČ°ã7یŽdJž{`Ėęsý'þē`üGW/zþōþ葥]Ķ;tpįķáAvó)%H—^[dēˆ§&―|pĸþbwž―ÉÆūû ÉÉ7/3rā·š!ĨK M7úŨä sæüÔkø’ÐÕMÆĖÕōI·ũœ‹ą ›ĩ,rø7EŒĘÉÝN!īŌ‘ËW}ó™aëöƒŪđúÔļĻ]GŒœŲ!óƚykžŽ]wčðáMũ'NØŦKbFZ‚[đvŦwTúÕŅ'Y9ww-ŲōfÎĄƒ["~[ß (räþ Îą\ŌëÐĖ~[oĨē §&ŦZÏÕĮ{bŊVýG/MÉS,XÉxqadĸ^Û.%TŽP^ĩĶāŌĩ>*puqysÃXöãšÅÍHōhP=4ïÕsæŲ3žÝ—ūnF“·ŅÛČ?9ïRŧjwÉĢTĩ WĻ­QŦÎĘ ÕÐõ_„\üŠ~ĢkŽ*ôéȧðŦZGā“°/›…øóО™‘―Ĩ{ũÁq%+û’hF7{7nŅĖÅĖū ›6ô0ųTŒ ë- Ōŧ,1I6\€ĸ: „Q>ŦF+ė‚ÄR c*ÚĻ4ÔĘ2ĨĻ& fĒAĻŠhīĨŠ―čýcbbœpZ§ÛuwwwĒk\\\ʄšHŒĀÄþ1Žå Ču lŦÆŊXxŧŒ*&=l,,%ŋ<Äe$ėPÆĮŋLqÏ5wŽ\N~V°1Ֆ™dI·’1$ˆûĢŧXÓãg.’§a6%QäČŨƒ!A€ã‹9mÔ4•îcDJÔLžš^3î.zZâÃI2—°ŌÐt—B"eV>Žx#%ýÁ,°|ë≋SIđÏ―ü°e›ofKzmþωŋŅđ§‚0ODœŽēn7ĀwŦfsųJeŸž?f ýŃkI–€"ސîMēÎļ PEW.―Õ:~ÁôPģžiąc@ß%HÕ§ÓÔķ%ųņĄs7rŨ/{MýmïÜwŦÔå‡~ĩJšŦ{Ņj­W8ģtD―wLšÖ€…˜ŪŪ*4ĻžyíƚÝÚyŦ…Į.þÎĩE_Ÿ@Nŋũ$pSĮâQ,ˆũāór1ÉüpžŦ4 H8uĸĘ ãũĒI‘SüažsĖä'%ČLSˆtÆÓë‡Îݒ1pXŽHpņō ð â,Ђ0Ðd{ņZíŨ:;Ķm‘GũÝŧ6ųi…ÆŽŊM›Ütõ€ˆeÛÐÂ~ëĸ!o2yø– ‰ŨîŲ Lxxče™ŊƒÝHÆ*/ŨVĩíŽSįw˟Ýēũ†ä*›ģûôŲó[WŒ ðõ)jUNėŋä@ؚaÃĀ‘“Īz•sš/”/Ãĩ5įÄų|›Ó―,pÃ@Ïģ:Œf/Ŋ bE853-ô*.‰Íūþ­úŒ2bãģ˜W‚PÏΕ:?xrÛø{ÛWœš—îg4—,Þxņ–ãį.^üĐ{}_/ÓWŪ% Žgåæ–üļžþėÚýD §d9ë‡\Ų2FˆˆŧPeĀ…„*ąŅw^eĪ>9yâN:‚:ï_ąķ9íYŠƒ‡Š”ķ9zåOå·ÎŠŠ—œóZũ)â& Â~@%ÜÞšKU.RĐqįC'Ï\đzú§ķ•uE#žI–ŽTŒód9<%ė8#)>-Gæ ĖËJ~‘Cä”rS_ū|##ĸEĀ^$VĨÓÅÚÃÚs—$U!‰Š-Fb^ˆÍt‘VSVyĮ쀆tôŌ@8%5%66֙:Hû―ĨĪĪ|ÎĖČČēä"Œþ!BHFHÖŦ ų}ýGVŅ[ŽEDjÏ=ÎL)ØĄ‚·ĩÚæá[†ŽļļĢ`ãĶÄ_?č1čAŊØžûFÞX@d­ĻŠŪk"ÉϊųPž`ĩtÚí& šŠŦŠĖôë™o%Ë~æF!€A,ÓĶ2ÆþEõÆ)›8mŌåXË2ĒļZŠĨŦ*„—äghƒø@Æ \ō―Ģ][ũ―ûøŌĻ&,؏%mįüáË=Ep~CŊÆaÍ6nõĪȗsÆt‘ĸT‡fM›4ýb·―ÎO#Ú š‚ØŒBC›ïGWtŧÖĻIŦ>ӋuÞķN1Š›‰$Dņ[‚ïœKŨŪ§f<úĐ[Ŧæ-—đ$IKđŅģÓŌWÏoÖžW”ˆéwü4}m†"ø•ŠPĐrųŠUŠ•ŽT4YÔĪĄš4mÞž~ûņŸþ8ó›:EU―°·ÉĶļ4íðýšÅˆ•–5QðsĨšÄ<+v\\/Ô8ŽÉŅ\ŸųÃ;yÐuŌuŊÐO*Ģ—ĮŸ…<·cŅį6é4ĶdįAm>+īŽgïĨĨßĸąsxóð–ŦNޅ’”óhOßÎM›7iļ4Æ4az?“øüÔēŸfmķ Ōģƒ ŧ…7kÖŽŅĀ=Ž>―}]$Þúh`ŸŽÍš7küÝĘÆ#įtŽPxĖ$EĻŠ˜ķé—æs#lŋþÚdĪ!4JĘĄ9Ãšn~\dÔäî įܖģ-ŧ~&j*$%õæĻaÍÛ|c/ýeXå"Ą-įh>ëŧ†aMÃūðc’ĄĘÂŲĢķôoŌīYûÎ32TëÚe[Ŧĩ+é.,ŠtMUä|+$yĀIÞŋ`R‹ĶaM4;B‡ũnĶë°åáÁņÛ4kÔĻŦ!ŽĮũaĨ 1ĻōŦó :…ŨëÐ?2ļYëÚ!EuŲŪøýn->kÜpÖÆÞĩ‰ÜxÁũ­7mþãčÍ^wŲŊ\ï6áaM›ē?DÎ)ö|s―M…ĩ·ũ/‰nėZ:?ļŠ$2yK‚‡ ęÁđ#—G'K’pcũĪ)ģnH’ôúîáAã§fa dþöT>xÐčŒvHÞģņhHgt‚$Q  î•öé"šßĪ(ĖTpTHŲgŠVŊååëK–áÔX0BWëš,ˊĒ'ĨjqĒíĩ"ääAÍöū&7Rčx˜ĐÜØŸ<Ģóütz?PŌFÜïĸZIâYœeZŅí)Í>éŋũëŅáEũ˜ï6­=Øŋþā_:M`›Ķ<q*íĻÄD(rĢŋf <Ó^Ïy^C:@ÔÏBŽļK Dâ ušđfÁ/Âī;™ēŲĘcƒŅ@Xd•.ÕE]Õói!ãųÕɃ ðHĢï+@ŽeiQ"ӕgÉëÐĐËĖŲHð]ķĨ§įð”Ž]rqũörĩådéĒŲÝ$Xģ_ĮŋÎÔy·Ōe‚ÍĻéXuäÅŋŒ·!1ĻT)wĢ^(:ãyÞaÉLHJå ŊxŽ*ēÝ&Íæ‚ĪēŒ6›Đ‰ļzxŧŧą&§§g (pDÓāï[Ū]wŪg8˜”Íf‡‚sæˆĩĪÄøŒĖ<ÉėWķ\1Ą0ô ëđ‡ÉÍ$ <ĨŌuUķČČlrŅÜ\ Ö<‹ÍjWr5{zyļĄ·Óƒ5öŨþ#O];̘–ŸœÆ=K—-aâÉŌ$/Ï";ųcöt–õ Xɉõ:Ũ‹• ô5#ĐöÜ<…óðpÓl™o’Rģmšg@ąÎОũ*Ŋ3ģōL>EK• tõ]kđŦ‹ŦŧH~$š3„]=]xÍĶpîn’lÍÉą8G \Ý―žž=Āë;o^žkioQĮërfjrķMuõô ôó„ÄOiÉ ‰đVÕÕÝÓÏÏŨ Ēڔasõō‡ņ§ŋ_yÂÄéû‹šŽĸi–%=ųMjš A%‚ýÝ]tĘeÏJ~‘Œ%ũ’ĨJš œŽ0Û[ģg§ĨfÚtÎ/0ČÃ$‘ŌŪ’ó:1Mց—_ sžĻ8ŸĪ<‡nöōóũõāu9>!ÞŠpE‹ųšIŠŪŲróDWģÄC‡5W]]’î°$$$‰ū^&Nƒ.Î9Ũs;ķZŊ_:Uåâ2čZĒTņŒkÛúmū=sōī*Þ|ÁxT›E’›‹Äž=7ýuj&ä î~~>Ū‚5'Ots—8dÍĩ@7“Ä;lđ 4đŧÖŽLÍÅÃÃ(8ō2mŠÉÛËĻĘķŦÃ9ûĀĸ‚7?>|čŲ݌1s€‡åŸå(ލzJJ:CØWąÎQė:ĨĮ&J2HšJŠøŽN\ĶLÅĘÕ \ 3V’Đ‘ĨīŠĮ y‰ĸčj˜•ĒÞø5iyß=j·*8―cú­[·ŸļÚŊĮģ-ӏ:“~‚ÄģÆõ™–4áĸcïÍã䚊;ņsÎ―ũUUŦ7ĩöÕē$o’mYķžŊØfą‡ÕBX2 Áŋ˜,ŋ„$ŒK YY†eˆÉ0ؒmɖĩï›ĩYjuŦũĨŠÞŧ˙—s[ýĐtõ}‚þ@Q}?Õ­ûn=―šUēOwîũ|ŋ*‰ö_ŒbĻãDÁĄ`į1B!ÉĮČĖ>x­T&ÝqJČâŒc;!ĐXÚæø $báLJü!AZĖrˆïNĨRyË/―íņ~ô<Þ âÛ`ųP “ã ‰dF0ņ:‚šÓëĖEdĶNâę›1kiÂĒęžLęfΞĨ‰/TŌÉĐ][ÃÂËįN1Xŧ]8ؚeĩŸÃŲ?ĩxvœ™|Íĩo3ÎÉqMÚČąõߨÞúŠ›Jĩ âDŽÚ(ōGėËŊ˜e3įLø‡žėAýë֞ʂ‰'Ô}zˆ8>Ļý€kjÚ œ>q|8-]šdķÐī™ÐÞ·/5ģŪZ:ÓZ7i/oýZę_ŦöŸ.Îԏ~A oP– QĢË{Ne)I΋ķJ”hƒį(Ën{ĄT0*‘ędę5UŦՀ @đZnŅ-™e›1*æčĐčÏlúĀ›ß˜f›ĸ”ËųöTđRNŦÕž‡ļŊ·gxh(Ÿ‡ī,KÓøji>B‚0MYļī&îž)ˆØd$áĻFEÂ0cē,CDuĶ]âüŠÔ!\\;•  4B-ģW{*Æ4DŒ‚ŠąŸ’‚—ü‘Ķ8ōҘ íÚđãĶ›ođōĘ+Ŋūúj"Š,ڜZëœËcY>Č=oúúģƒĢ'ÎDx€`Īâu@Ž‚ؘõ۟‡ŋ Å9Ņ`‚E"Ä —=/lØā\ÏHwđ2 ējV-įõÖTĐØJ5° "`ŽĀcČŽģÁ§4ĩĩĩiRŠ”óÎZ›e™Ë!`yb>48p`ĸþÛ·f’įģYL] EîVáōąÏg7‰AĪϜ‚ļāˆ@ĨÍ,Äz1aĖĢá<ŽcëŲ‡‹B|4aĒQ…‡æä!jģ’löX  ÖŲxSė―óÂC@$'š‚ČĸbÜuęęė(EĒŅcCð 5Ųø…`”–ÏáįEՆývωōþÃåQkī&d#ĸ{ËO`ä,ôŒT]%œÂœ6“(„  4jĩBĖįČFéĀlmF|C`!~‘čˆˆ—6(!Ũ%*a€ĖYĨ(QޞÓ;vėXļpMĩãL%ó„ījÓsæūįú_-ŧōáĢßÝųũ_ßųCE\õ؋;šŪ[ʌI Iaiӕ·O―ãŲÁ§ĄĒNíęýÕ[ß<ģԞũîÞý'ŨvnNĸųüĢW-đ%ļrĸ–ķŨïc‹„˜ý"ŠũWĘU/šæišæŲw”õŠŋCë—ĸ“ýļ­—ïûmßū­Z-°w!It`vÞ+QK”Ô6 JóXp>xB­œó6sc$\ĄĮÁύūQ 'Ûst(ØpÃĩó:ڋ†ˆö.ža4ĸ"ąÞ.ĢA~Ē56hzģū€ŌųĩÚ ‰)dÎēwZœŧË]°Q9ējF ĢAÔ30ÆH4 1Ņ͚ĨųÁĄûûûûf˘ÁĖãķ~0~H@y·šVÓ,uÎ/nđô·nĸbōÉgĸĒunņų[Ÿ=ē{MaĨ6šĐXlÓío™ũČÞáĢÏn:ēú’—āÞwTGGOö =ŨųܞūęWÝ9Ü7<č, BāHPÓ`ÁĪAJИnŨFÛņAlĮČÝŌöîÚé2GDIbAhČL !=#ŠÕúāãGŧ{DÄáįÆpÕũŒļÓ=å+Ï($ĘVŽPa %…’ÖÄÞgiŋËņϗûĒŌ‰ó’}įd|Îö™‹.J ŒgÏjc›ļĶLIZښšzĘ=3›*YĪð]h jYÔTЊˆL$Õ:—ĄÂ3**ČČbå‚Úh`Œ~b]°ÖEĪãĮŽ:t(ĩ“FØIó\į\ĩZÕâ”SNËMIéæyŦĶð—đčäÐþŨĩ3’RđÚjR(,k―þ#K>ĸBó‘W.ZáËöx߉ĄÁáãýĮ~Úõ4Y|Ũ ŋ 3gk*ēņÏ@ĖTÛŊĮĩ iqįëg”Rų·ÂÆ ë‡QQė.û LŠF"ą$ÏŅöŅ‹›Ė„=æ ˆþ j†Ÿ>€ ĶI3fMÄ ąîŽEcuŨ3Oė{ņxóŽ+Ŋđõū–ŅM?þáĄ;ßøÚ֒ú·FĐ0ptËɞ!ðžrŅÐy—Μ15Ww5$Eņ[nb&› Ÿ8~ŽeÞ…Þ}Oþôđk_ũŽyÍœ1Ž;Ö3ieÎ3øĀpĄFV7kĀ­ãޗC$ŒōŽÞ1TÔ+`BÅ™ƒ&ÅĪØ§ Fęí9―{ĮŽ+VäÛô Ļ°ąžP{˜Zóíþ(įššė–7­šđ|íąM͋Z7î{þÓONĸāę·ķ5·’‚ÖúĘi ŊœūpppðTĸéūþã§þÝáo8~į%7Þsé=̃åxŲÚ@g"báx<’ÆŒÏDÄq,ÔFä}ûöíßŋ ‰"ã ęQäŌōŅ‘&ųōČĮ1ÐJ­Ņ$&TCfģóWPekCæ8 S šB-ŠnþóĮūúĢãËïŧđë;„ųĸtƒ9øÏĸüÜ5žūiJ5nEŸYi”50Da-f@ĨĢ(BKíø-ßĸÐŨÖöŪšņ†ž―ĸxĒŋýÞwō5wǷό"ŒÅtÃĮũïlZļrF[I$Ø5!JgøĖJˆÎtˆŌō•ß|pŅŦßũÐ#6CâNm_óØÃĸĸŌoūĸU‡;ŧ‘ĸņÃ=Åĸï~0·đįëï^ýíw/iŅ;·mZR0Û7n8­ķ>x{óö#ÛŊļų·‚ÖE[Z†ŠcLŦIĮåóÛž„QEž‡lûÖïĶ-Ũ]ąléK[‹móßðúßĸ`kR-W\’UɈ SZÃáuģgęšüÁ{·~îí]Š$bmÐԄZ3Bļô5Zūæ?üí{ÞųÂ-ŊyxõējęęėC įYĐqX \8Ą6šrG_k+ÞŦIb„1*ąÕ‰”&ĨŒēųdðÚ…* "cŪč)<íߗģūŪđæ/†Þ“æģæÓ4õâP› Z S^đbÍĶïíR…R@eß1ģtüøá=ņŇŪū'­Vs9ŪĖÚ܍ũÁ[€âæĪƒú1j™õ܃ƒîŲą3Ë2-%ėØōAL $ķ ÄáÓkmBä "ë‘Ï+‚ŋčEŽ–HsÏB)–"ƒ„XW9QZW·ę·7wö$ÚgSV>øūĶšu…bSk‘ÚKŠ5IĶ(}ųýŋšúČûŋũ{ũąÜrý›Þpũō–vXyÝô ƒwŽžlúč}kÖýé-ÜŅ͜+‘ėۚöĐÅîĩųõĮþŅŧáöËWŋõņßX8ģcþÏ}úßxė &,{óÞũē[VÜtÛwūú˜?ōЗݱšíãûÆï۟5ģĐëéOŋīâŋ67Mk)R[Ē›3ĩŲ$'žþÁ'?52E…ŦļsåĨS4‰ęĸCõLÎ†Š† ē đFV+ĒŨÚZĮĖR7ā õ°Äh/ŠZ’†1lŽHå“6ŸĮ|Z;7æę ģóD~Ï}ÕUWEĩYĻ/ÚÖĮß<Ú&IĻ›ßÐB›9"•9D í3J‡;·üŲpũēŽ­I“óîÞ+îčhmšĀӚ”Î59;áīI“âᑑõÏ>“ûû*ÔĘČGXIE›C°Î‘thŲĖĒ҉2Jļ_h †ėĒ~d”“Ėóų ĩln‚DĄ„Ķ ą66­þÏÝ4Ðc-5ÏūĪĩđė=~ôÎΈHMŊųÄw1i2ÆŽ~ĸ—Wuu:ĘmũæŒ ĖŦ?øÄÝ\(PuÆ―ĸåņÛ§PŌ &^^ßō+_\ųKUï.īL+%Ęû ^ņƏĸhāt/“ž2uVāš7}lŅ=ݘtīMkúí/ÜXõIk{KeĻ?i›ąōŠ•d î{ÛÜЋ§ūüíŸđūšŲâī9ÍÅB„WĀi2ĘD \hY-‘ĩ™1š”@›eQC1†"D”­3į―ŨĪã.28s ”–,™IqķoŲrũÝũä„ŲXš<*Bjs Đ`pjģŊžfþUl.&E‡ĀQaajRåŪ†:―MšÞĩøĄāC}ÞZ_Ĩ­?G<°ÏÎÓmā VŲ‚ãĀ(õŲĻįŦ‘0ņ‹ō11REï+jÍh}ØÎWG+)0č§$˜h$B$@ĻCizĮĖãy!$šđŲ@ŒeĨx([–,–@–Wly6ÉuÍdPƒR3ī7C„\AF’Ö\ūæ:ŖŠAŽ[,tī7ą\V⧁ą‹'--óĪð=ɖW<æ@ÎKŽ1(‚Ļ)Ņ@”ē— J‘ŅڇeĐB"…}đ“eP ĩ€g(ĨQOĀ# ’ī‘9Hn+=éĖîßŧwïüųósįŌ6Ģ[ĨRI’Ä Ú[Ú_uýý›ėô#C‹H>v@ũ]}Ïkn~MNŦ'ÏFL^RĻÄ’ÂøŠō*í†õëŧŧŧīŅÁƒsu’äƒЊÅ$ģV!ą4Ë h­ÅÂf“$Ė!dN6ÍTˆ{į|ęŒM ĩU{{Ëh_wq^sSQĘĩÂ?› cĀĸũ€k'?mr Îí:xîkˆģ,œ‡Ė†áQ[ė혚{PcŅC \@. 8Ķl| @T8–*’’ĪĖ AgĩQAĪŊ°&`EÁŠĒąŋ"íÛēyã7ޘį9ãŽŊģ§·1_ÎeQ0R―å―úÄû†û)ēĮˆR!°Qę―ž'Kģ Ņą\‚úRlm[?3Ą\ŧgϞí[·ÄgeG ĩ.øH1&EĒ#CŅþ—9“&]e(øÂĄ•’7Ģ!Ĩ혃ƒŌZĸüÛbSÔĒÓ;ŊãÅOėÝšoÚŽĐÚhþũščIĻÅj5ëíęÃÏi]8ÕīĻQHhāBRöŌc:^jTŒė8 ðgĢ(ļ6xk‰ĪąA,‚‘] į"E'Äļ―ž$Iđ2š{įÎÜ|Ą­­‘kCí„†Ū ‰mõ‰nŲâŲ‹/›đhCïiVŠ1Šl{ën^výōųWeYĸÖŲÉõ ėŲĢ-åŠ_›^Ø8ÐßŊĩēÖ)ģÎbė…ËR8­ÅŅ= !BŧïĄBN@EÉŲóãÂ0%ĄK:LæÚ!„#ý'ķŧ6ŠXk=­ĢųŠ%ӖÏkžßn ÎWV·"J6HĐ\#’–›ß8‰Œ.8DTą˜kmīςaŽEJÅíu yïbOũéœõĩdéŌÚØšÏ"Å 1ĒÀ„ęŅßõĖÆ'ąÐ‘X•8ML”•ÓGã―íÍm#ĢĢD4™|Ėäm !„IËĩP YIΠØūm3@°– I•ĶĐŽ_D2Ú `ü‚ŅFK'3-Z”ž!Ē"ëÆ ‚õœZ­"ė˜Ē/Ÿ‰ž>kFÛHƉ Ck/éHōGs‘hā‚* pqÁ !D3ocL8S7Њž b"KĀđąÆ\DôācôŒ}JQį=Ęœ[ķlZ―fÍôéÓk#ZýķX-œsã–™Mo]vۍ3nß{ðŅš Ą’Ĩ·^ãÝ7ݑeķ6bž#ĄķāP_7ĻĐŌ>“§īQŪWI­ >…ĀY&Gˆ[,} Z›Ø― ‘QWYiåžgiƍ[ðą<*Ý–@”hAqðGÞķmۚ5kžũg—z‰ãÚRi dMĨĶûïļoĮî=Š{ĨÕí7ݒË*ŽŒŽL[qŌÁøa―ˆWí!"åšī;·mËŌ,vÛĖŠÔ™žYëâڈ(Ë2Ĩ”VÚûĀž!æž,(“,ĩ!-‰Ú8Fa>OP„-lđ˜ō;–†ļCmīðÎą°—$)ĢˆØ YžũZ ÁË{ ĸEĘ9ïK Ižũ'RHâŧĨ”ĘÍhvlß~ë­·FYÅšdvōô6ÖĒ-‚Vęæ•ŦŠ…’Hå{?sÖŽ_yÓ[Ó4ž>[‡ú„úėmcÕjuÝš§rĮÉOó“ÄÄ­-­ī֔e..>pô>@)m‡Ā>ō ŽĩÁû|?`ˆŽ[1žÁFči ‹NDŅû`­CĨ•Q$ô ™BÁ9{·čL7 IEŌCąPŒŅRēžX…c:g‘Á(́7m|îčŅĢą7!BÎŊŨþÄúo°öBý~ló§{˜˜e IÝsc’ęĒĘ-°Ø:*E,<~œ˜ĪšĶ‡_<ôýï}ũķ;î\tÉ%ą[OEĻOT1ÃéðÆcÏßūôŽå—]i”~ÓŊ3Z§Y6)yvR:ÁļÉMíLÏŒđ‡Ž>―îĐáĄ!B…"ëēĀhBĖĮ.@P$R;ŌųE ·Ē3ĐP{ïäzŒRpЉcw)Š­Ė eëļ ˆÎ;ÏAØĘgcî8 Ũš$A į- FîY™ą՘Ŧa5KIEĪ\ðÂKœŒatdč[ßüú'>öŅÏ}öOž|ōÉS]]Îų$Iˆ'Ãx4ÚôUû?óô§+Ŋš{Í=7ÝķtŅâT$ë“âúÉģ”&-;Ή;väIīļ229/ŪĀĒöā„ņ–˜$Æ\æPH !x+UctÞ9g™―ŅI>&EĻÐûõj0fúŽö"E hŊVS$YDĖ猐ŒIiĸ‡(â9äŪ8K3†1KÚLÂãΏe8hežsHXÐT`3›[—?vô™ĩO-ļdáÍ·Þūråõ9JĨŌĪ·ų1óÕZ/h›ĸąWþQ~‘‘ĄĄÕw―l‚V˄\õėƒ˜ÞÖÎÔ6ō:įÖ>ųäáƒĒ—%"áH-äc" RÁyÄ·†YB(æ“î―DĘ\ƁM!aĒúĒÖ&2(ĐĘFV{ņĄFVË@J1 D"EæœÖĘ$˜]f ’–œĻ"‚—Đ$IīR6xBš˜õÞ#Cb‰ģr}éa„RS“RjxthũÎ_û›/ú?ņáĮĸÁOäķÖÚBĄ@“I”&:đ|Æ.õiĨrŨmwdY6!ÎÖŲsd ÄlZ Œ1Åb1^ØĩkŨĶM3g }ÜÎ8ïcšOz–$wŽ‡Ø“"“(e„ý–ąÔūƒ^‘–œũ@ ―!hāâCƒĀ„ÄŅw:Š3ę0$BHPüøWĸöoóN‡œWūã‰ę˜r__ߚÕkŽĩõĒ\įÂ@ˆn4FÓXį\^(ČMÎ;;;sņï-[ķ<ģn]WįI­DßĀÚĀA#Y#ÄaBEēBÄ Š VޔžEO6y āŲ“R‰„A „Q* Ð@ \„5kizEˆŠt`vÎ"‚VÆzŦ cz‰Ōƒ{ĶĒĘ(ŅŲ{= ó!*ĪhÃŒ6€āŽCÂ<…Ó[@"T―=§ŧŧšķoÝüŋûŸ+W­ZuãM+WŪ\žxqŒķÞ{DĖĸJšĶsįέ·hÄ3` ŪkėBÞe›Gę~A>Îēlhp Ÿé9}: ŧ4-V*åĸËÞųīFŅa|ę_Ï{4Ÿ H@ŒïՐƒ9ĐŲ“hDzð5āÉÉî&$û'™šÐ>ÕôCdjØĶ™éØ=üöaŠęéÛFö('Ļ]0Wš|­VōŸ†ZÐoĢ„ZæðEĪΊåæļøi ÏĐ#c^TÓ>žŦĪ&)ɉŧ)͘â>{!ũ“EŊĢ{ @gsfĨÁ·Ą˜ypOáILƒßpÄZ7AG>XŲ™ĩRq›ģÉ#Ū‘l‹Gc•õęޘUþuōóôÕÉû÷vwũööŸlooomm‰Ú·`1āþítȈ$T sāx až\BŦÎįģ9>g1ŪWŦëÍš]šøXĢö@Ĩđ ąy:ąķއÁ=˜Õĸį!ũЊą ŒõšæŠ>æ‹]`;4ĢP)―û āĢf&rŨüj†ëā< Įïßūþ8>þðîðáÎÎÓ―}*Ė8æggŋÚÍúzđšúÃÞĸäČēõ@āP„í“õ~°+aĀ:ˆ0€5‚ÄJðuæąðŽŦŋ{čŒûžTjeWæ―ƒ(—Oüųųų™5AîįþđģęšVfšų9ôįyšúóųHí˰€RVÆPä.ðŧÜ­.ĢÁ؍V››‘ŧ6‰āŲO’‡Š9Yī°Ģï―înģ~éfY›0‘+âŲŲ]k-ã”9æ[ÕōâÅ_ĪZ•šËlĮä‡įԇŨšēKgâ>Åk­þÆxÛübgF,ŦššĖ cN„B„ŽíËÃcēÝĖý{Žt­%”Dæ6 QĸŊĸũĸóĸņûŋŸ*Ģąēš“G‚–đ!Í*Ģŧc­õđŠķŧ›đ…?ûq3óŊõ /Ëęîō§·ŠÕÜ}:Í †ĖâT.vS”z­uïĮDĖ|ÚÏ8cöM [’š}…zzÖÚÝkÞ͝ÂÎ-ĀÜ!žxņâÏe äiÕ&X•.A{?‚>Ÿë0g‘”Aģē ŊŪ‘ÍšGueUø22ÏgjMr>Ķ…ŒtģĘÄũkĩUŽFĘ9ZÕæF BøZŨe4PÂ­ŧ@}>ĸüóųt€ĸßK3‡Fę`]M:đžg Y­*!]ëÚ;'–{ČWŌušēGčĒv™@"Ŧ:‹RDôá\"Ö) kŽ›î<IžŠ ŅÕĨéþtÕLÐä‰@ë>Ŋßļ™/þĪØ+Âįī*<ÖZŲ(Ví„{åĪēNžŒG@Øã2·Z <<Ŧi”äfÝ:tĨ:­š4sĩJMģ“ŸÝ23AũýCp]‘đwîs7ŊĖĖt]Ÿ‘=D„ī—Öŋ?œō˜–Ž;ŦŠÎã™ĩ揊óyÂü›šKõYgUouːđ[-b$|ÝfmÍð>ũ>ÄíÏÞŪļHVũÎیFÓ CļŪuxîæķ~~þÐ=8^ŧģÐ2ŦŦþĒ[ėŋ·1-uKMũ9Ŋ?Ũęũ8qV·‘>ĨÛ<[Čý܀™sųÚϞ&X·UÝ܉ ŧYØ~ķÔFũ{ߐü ž­&ÍÍKSéîÖŲ-D„đíį>>€Å3ĒJ=ūĩî2Пį&ū`8īIAf–ÏÆyVZðû>A9ætÛÏ3·[~í܂@Q0æ—?;ŽXļŧĄ‹> 1âRĐzZ~žŋcĩąŪē ôučĩSûŋŨ-V’™}>ŸŠR·qęj6Ü=kC2·Ruu˜ÏJ0ãđ w=@›; Œ”0å7áūĪÔÜŨúęĨŪÓ]–ųĻ+VČ'ĨĶY—JEÃtčâVCY)éZ7—Ú-âšôÛ(cfó…―ŧÜĒē`Œĩ$ÍÕĖîį>tŲo„_îNNaOOýŨĖã0ėú~ãÎL3‘•Ā7ŧŦÕæëzö“€"Vu˜Ęĩ'k”i<$Ž/^ü5Š=äRF;2RšyĚpUPîgfÏ·xuVŦé6ø9čŊ“ģōđ>Ũú͉›SŌ°ķđM#Î!GÏŠqƞŸˆīÉÛđI-jå&Ý a­kzŅŦÛÜZ•gôö`ÕVwxý!mķĻ;7k]€ŠęôÆ53ĩũ#Æ·’ý{ŧŠjHfDŦräÆĻCņË—Ī―7đņĻÜ~ÕcôãSøģœ4V:ģ°<ïŠkˆûÝÕūxņį:{O ßąŽ.aĒšI›rĪ ·ŽÁFįBhžũMŅÊJy&â]Ėūýįŋm_Ãî)Į H·Iír‹iî2Úđ˜Ïģ§ĮLÝĨŠkeUŨy<ũoڋŧÓî|0փRGŒ‡­'‘ÖÍ'‹+ÂûqwđûPžđŊ뚄p7Ģ7Āu}HęĐðá#y˜];Ÿ>–e3vĩ[˜CÂ0ĩEd&ÁŨČ3ðâÅßÄ[xĢŠ]ā|̇dd·ž{Sróg?{?ÓCēzW%0)‹_Ôģ€t6Ð5uWÜŲÕå‡ŋvîŽt3AđũúWŨŽÖÎîÍÜf<|m{§Ņ|NÕši'zž5tųŦŦ+Ū–ēöt/v–ÔģīífĮ);á8ęýÜ8ü A§NÂ<ōhđŠea{?ß~ õs?æîn‹xîēNŊå?HÎ?#A|)USI Ð@·óüŲ]xņâÅ\ dëšēUÍdĸĘ ƒ­ļ>į[ó~nũˆkĩzōf!ė'!Þ3uIm‡z*ĮÏjÝmīŠQ‡ā딙ÍFĩZt_ÏswuD€ĻLĢ6ÔÎIÁŲCÕFoĩ$|åeóåŪî<Ũš*Ŧ[îS[[äáB3U·@óo›™EÄUY Iû|ŪýėęI;s~^uw͔šĒū wģý<3›ŠlÂėžó~žÂÆ>·Ï{^žxņũ8ĩ5ëļžØFA•ô™@3<`ļó™T*šŦšĒ…ę. c-eO âšVvvFęˆmÏ= Ï쁐Ā_û™ÃąkĖŧs€FēģĖÃĖÎŧ•›w ŒĮČð[ÔnsWë‡hŽę™ÃCRĢIitĩ’{,5ÉõđšR)?ÓčT–‘HueĐËÜiÖU ŪuåwŌ4’]Ųę ~ÝĮōë†ĖTÉčŸë3D#Mûđó7rėix,43Ë +|gF‚§Âķ[îUE˜_kkŠëč"J‚#ÖŪ2b­EįąĨfŸÜÕ_ÍïŨ?fևgÏø\RāûÄÆXqßOW‹—eÕyŒuĪZû7ĖákĨĨ[ĩĖŽZVY]Š)AubŅIXøšðIH.ģúŠ+VVf%ÐkEvýŨēY ŒîánŠ}ņâjyþŸŪ™HVõ·œŽĖĐڎˆgŠÃĨ>ÉķZvM*Íg]ÓûÉĶÄ“ P Áļb%ŲX~Íl ;›4PFÞÏMNLŒå1é.;ƒj3@­ž“+6pŒdķÜņ[inËŧĨŠóĸãqœLđÄZ!ĩ™ŅÄ~ánäģӀˆïq–ŅéyYvFÄÄøyļŽ4cOÎ.$š’4Đ>ëSÝsũ Nģßֆîŋ7ÕūxņNĩH{ž•F—šįh+œ ~yķJ†Ó­ĩ@ƒ ÆLšÕí~ža]{.ÎĘ.…N„͉’RK―N LV‚PŦ$į›>ũ~ĖRvĒG,aR6=‹&ö~†—ŸįÔn>æ1:Îį›/#iNąfI=*Hg#Ņ4Ŧ1õėĶq@ W\ōĖė­zö-īÞUädþĒšškŠ{ĒÎæv4 ũ―Ÿŋë`xņâ=3·XkX <Ūkí―ģķĮrũĖjåu]įõóŧ”ĪX>å46đÚę>‡øÓYžđŽý_qëģŸ8)^8­Ū:Ą3æÕĪŅÆ”5!{?4ĖÞā9 þđŪÉĩ-։j<];F0Šą–šŋ9 ÝÝĨ s8wû*ô_?îäŌ’&Šåf;“īˆ‹vz+ģQąą,įn •ŨÞRøüĩ$âM›yņâOR­Z~đLڙāömŧÁĪbw[TL™XŸ]į5 ‚ä~F#ĩ@͙Ō764įu"l@˜ŲL ˜hîq=€äÐSŠÏŧåCØĪf•Í.Ā}ïÝ]N7ē*ÍĮÏ6”w]óHýßá·Š=œįõ™ŧ­~óšÎĀÞ<ėūrzkÜwU Ól6Ī)ˆÆ''ĄÆ}‹‚Ķ>'ŸgįÄãšWŨũiu0}—ïŪöŋŋXxca& %"v>_:°oĶĖ lßO˜ÓŽūķÔ)øzĖðŅÍÜĶũLĘ1LwėŋWžWv oîŸԌŋ·>'TJmnËCpîa< [mXRíga땝ÝōXã.ËJũåöíëuĢÏ―WÄéūÝūŒßsšU– įĮÝī3ŪR―Ó+âūo‚nôąØŲR?iFfggŅąŠšŅņõ°•Ūëjõî"ī"þĢÎ|[^žøĢq3 ĀÍŊÏŠïūáޕfaftï.aėn4ÔšVtĨ3&fpæD:ITĶŧųwø‰åQŧŠK@ĕOšųu]tķZÐY_Ŋzč)Ŧ܌Ωþ^lÜŧNŽ5īw’rĢšg1jgš$čîîû~rOï“iäkïDC·‚‚™KČ' 9)Ue‡EøšŠrœËũūAD,˜í|@‚8_ūÖY:ïï)œ3+)MEEUŽĪĘ~Ũ/^üÕc1`ė;ó°ĪÏëáP‹ĻŠŅÞggždîļÖ1` ‡Ž5û͟į13Ï―ŦRˆR}FWĸ–k‘­ęjU…yWý·š;Īã XšG鞀]grũITũ]īkUWg“ßÁį‚ģr͜Gz·ĖxöģšĘ5SŦj>™XU,BíŠŌuJÝ+ŠčjÃ#ë{ýEžxk5:ĢyxļwõaÆčî1ïŸÔðΝ>=ŒYĒNé!ũÞæ~]—9!‘8 FŸĩ@ŦŨšbŪm4wŸž‚áŊ:ŽF0üü"Īŧu5XAģÜ ÁhÏÏ­CÖï*ýJĩúĢęޕ­Z+vn5Ķq}Īŧą|8ÍcÝMPĻ1ķˆAâyžžvô~n‚Ó·6’?’ŒĄïÓiöH‰Y. Ũi)ŸȚÆ:œ{˜}ÂÔĸ^žxäņ°ŠFīv%ÝÃl^€îņ ÐøüÜ0ÉTe‘tš~UcËŨ!jH·ã”ÅlNģ:ÜaP7hj™™€ŠžũŲ9AāŠÎÞ-Ūp ”ėÛ} šÅëė‘m]ŨÐëų<øLkÃ2'lJSč[SSōwIÂęn\ŨGnđđŒųėEÞÏmnq­}? NcTĶTá—Ï~ƅnY Č܁ßŧ„w)O*‚9ŸCĘŠņ·ðâÅKĩƒY9ķ Á‰a u_ŸÏaF ECUĨ:<ŒxžÍÆõϕUhð|‘îķB­YæķĘ-Š’įÍU-uļ…Ŋģ po/šŧ™ĩÐ6Ý<ïlVõėý,k]] ”ûÞ|đpÂj#"Ū=R\išŨT-Ā=Š‹p’YYj?y7“1æ+Ü}˜OvOg‘U’^Ķý›xņæÕ’4ãXĮφ_‡ģJnf`ޙÕËÝÍšū ™õ<›FÎbWšÖeĀQ/ĀI;ĪėîáÖjMëŽ;é\ąšÛÝĖ―[{ošÐ–ęVe[DIF ó0kɏ›Māø†?ŨÕ]]Mp]ë܃8ėŋ+Oâ-Ð:|(3ëŌøŲhČ܀Y؊•ÝĀ|ĩG·h˜0„ŪvãúŽŪíÁŲüHaQ™Úl'*íė—[uÕÍ­ŅæŒëšq›ûkĖý“xņęjĮT Šö6ģëšrIŧĖ€]MãĄ5;<[9Å6tģšðï倞―A^낔Y#jČđx…‘Y[Ýf&aïíf_ą1‰ąÕĒŦĸųįš!·Ôhԓ\aFĻŧq0âYNXŨŋ0w:s—Ũį:„rũë]U­ļ–ŅšJ(?‚ÓÍū&döŧf•ŠŠģ7h|?HxZuëš`üđĢņû9ņ=VŒ@R˜ĸ<ũĻqÕŠ* sóWéõ'ņâj…S­(~Эž-ų|ķŪÃpfķÖeþĘŽĩZĶÁŧZBÄ"Ðęîž)˜€Z6ķÔ-·0 u‡;ÁnåčRÍ+k?)a8ŦS]šU€ ÝíīÉɍ5ų )雓ĩ.œIHžĪîÆċocũԆËhĩShsŪũÏC0ÜšõÜOe­ŧÆœþÜwîqÄŠžŪ‹@VŽUŽšÎš“““Ýq…‡UgWšü„1 ›įâŽîō°uyerũŋï‡FwŠZúŪ‰iD7Í<"K f̚ÏÖÎ=4ícnFŸpE@ÓŲ3MĀ“RķwRļwV ĀÉëڕånCâĪ}>Ũ$Ԍ’!+ŧ ˜ œ=[iHUefF;ûŠjĸ,^ž- Āĸ"Ϝ[+p| gbžRÓaSYąâú\* 3’ČŽŪi$ó‘ß’ÖčÎ]­Š#ÂÜÍl?Owšqzwhž>kŠÂĄđļHŽņ!wZļ{@h-muũÎÔaíîšíˆĸÜ7Œës âō•SOiFÃļā΀ėU‡FÃĖ Dļ­ÏóˆŽ*;k֖Ūϒ0ÁŋģŠŪëŠðŪdæcœãy`õų3ÁĩÎĐÅ!ņņâÅKĩä9@Ŋ]ęð˜ú–ݏŧ˜ąÎŒ-UåĄïjībÅxX'{rdĖän#‰—ĪÎðuĮšĻŌTy,õk˚•Å2·úMq?OW9=wNZMÄw Léw}Ņĸ=Þw77WũxŽ€ĄŦx<ģįoMðųyhķېP= –™ÁÍ5{Ûąóöė  ÍąÞø†Q ĢÐøMNā1æjĖŧĪ /^žÝbUië ŌFęūÜ―vņsõŪŠúÕueuû2ĸšxÝÃŋb[_šĪô”ŦĶ(ũŋ?W·ÐH—šš1udgÃānj}õe' ­ÏįÓ*Ąq2ķgĻ$ū>ąŪ&ĖÍ8tĸü|évfUđđ/ĸöĒà }ϟÕ=ņ1ĮyœÃŲ–}þģëÖy㉗LJŨõųÏÏOf™ŧęŊjw7ZfYŨlgif.•úu‹ýIžxuĩęĘ,UAösßđE·Yŋ ídVNX@Äęt._īx~6É8aݚfōęúmüæsFQ Ü;óŲÃĄ““―"4‰­õų ĨÆĩœ~v˜=ÄĊ'·Āøk?ROïÃ]Ųk-Ģõ.~ÃÉ,ģhãÁMI˜OM\ ėĒč‡'ėÆčųu[ļW5wûږÜ}ĘĖN9cøųqļšé4·!b3ÎgÔŦÚ­WVû‡ņâÝÕۈ9XīŪčŽ:­n ĪЇ‰B”‘ÖUæf4H%Đ几ŦšRļU—ZÓD[•„ŪÏ%!§ ÜžšŲoņxeŧđ› ÉI~1Ÿ$E“ĘĖ'ØÅ–›ûÉ“‘"šmácfÛÏcüúŲro §áŅIÚ7͚Îė]%Hv5ŽŨŨŠ*tŊkMŨÔæÖšô˜Šå4NvWÐŦr:z ŦJ;ýĩkþ•ÂOĢD5DCÖ/^ž- aþ%ūëúĘΙ愎-3[qŪ°š íûū}ļĐ}o#Ģ―KZôކÁÍIŧX‡€Ž=!ŠßrYũÉĖ–šÎðļŸ‡ä ŨŦðß`Äés§EØHzĄO,€]MQĶÚŧ…ĸ†!tÉ-NöÍãæÏcLŦãÕP·ÜݏëlĘŌ‡7Oßí1y]óISYÐY_Üd\KÝÓÝ;e:ý/āÎę$)‚ÄÎüEÜNû$ņņâÅ{,v6ŠÍnĻũ―ÝÎNķõm e%Ü~s Ę>JXRŨĩԇļŦ!8ý ÝE; .üü<ŋâ" ӚķĮLœ…ÃMÚŠ]i"Uį1€1’2ZÄáŲėĄRWC=yä#ǘ„uÓ`nŋ‰‹FÓs?IOåŲøĪC Î!~fíĒņûŽŪv”m4’ÔŊjä\ĸų\­đĄ"ÍînũeæûyĨRûŽų ŧRG˜ ũļŪŦŧÕēũčÖļæĻíĖŧĄĐņĖĶņ§<þEuŠúw_ŅđÓ`YĘÝŨó+FNųDíĖĮĮĒ–Ĩi~ō'Í}đŽēĖÂ^cîßċ7TD@ØđIóå EŅčgŨ™OõÜwuGœõë.7_A€ļVIļ‡ų}߇%ā·Ļķ;Ŧ‡Ų}ĸ·_‡|îgša:•ūü4š[ęĨ[ððëZÏÏ3‰bø2.†Šzî§*ÝüŲ;+‡gÍ:ÜÝõ4ėdgR–ÔĨ9ÜË,IAðþđi>íđósÞuúz2w 2€ęšT‘L@ø[pK$Fœ€ņríŸÃ‹7ŊVpóîŪĘnEĀÜöģvýsM™đė*ÝÜhŧū,™ëÄYefŦĖž[Y7€0‡ôä6cø™ũ6ãT9ÐH`ˆÏ WWUĩ‡ Ž]w“üüóRö Éęœ3ĸîŪ.ęü0K€ŅŪ+ēRč§ųs6ŋnhĖĮ%Uķ‡ŧĮĖéîøNĘ4FK@ŊøÆ0ŠÍÏģ F„Ûī6ôĻqóyh6ņf’ĶEâyœ[<ģ­A ôÞüIžxDeuũ„ €œ"Žé^IčŠ~Āæ ûĖķUÃģËü,mA§ŊˆĘrĸw„Ðj3ŧÖ%Õ~îĩâZWf ßģþ“cÐuķ '„pMЈ9GRõ™Ww} P>[8YŽčŲ)ŧû} +–™Ũi= @eĐk Äō˜ÜūĨgĸg\­A :,îËŦ++ óߝē Âþ[xÓSĐ;5æŲYƒ9g˜=ūŧæŸĄ'%Rø“xņâ=kTuy,’“á2%ÞӜxŒđŒ6QĸÃõš1ģņS™ÓÃ=üLF7ÁoFŒ„“°eS{ð°y<Ï=Á‰4Ïl3 ũĘ|ö4‰ Öįšb3óXŸýč[­Ø™ōˆuaŸŠ*Ķ3?ôÉo ; QŽÍÆŲÝĖŽšü€īûų鞆Į–Dã·ÜėÔĶ]ŨjôDŽÍReJnŠę”ßĀ镚Ã43ĸđŸęÃÅųėnāÕüMžx oĪ_ŲÖNá^•ÜÜ-v%†Č]enîQÝóÃÏĸðÉįé†ub°#|™Ũ94ÓtVæymæĩópÍÖüЍjíį1įš>Ýa^™N,gĪėZŪ.•Ėð[â+·˜HrĩÜÂÍKÕ]‡ˆģšÍū§U,|ĒhfÆę~žMŲ?ŸkWN2OPëÍŧ°Cí[ˆ ýšhv=ũϏge·ū1ÞRvöašįÞtuذÓÝOëAîsĒå+žœÂ…Đ Њīn)SuÖĒ&vë ãß]AąÔY;ũŽļ„ßä—éalŅ BÖüß͉aýft™™ĀÜif>J†ęNĐaîyo€ëšH@‚!VĖ:›N‚Yiî-Ívxsģsä/^ü9ąŨ,@ŋYęĖžbļï[‚ŧkËÝŪuuĩĪå3?ŠĨu… ņ†™Yï†sP֍SP­jųWs! žýHZĮ 0[cĢéŦ@ÜÏ#ČāøÓp}>=éģŌÄČV'fKÝ0LïÏ―+;,š‡ņøï/Ķr§/ûƐ·âsyxu[øōčow$ÜC™€H€öė―ó‰kҘ{‹[Ú3+ãë#MīMŠÝŸĐÝ=ÐÝE„û+?øĢxņ.(’ððýltųķū1Ø-Teļđûģ j ŸÔp­ˆ ?ĸđýtJØũ#"Ū'í0ļŠËÍHŧ·z8‰ŸŸÛÍÖijžýlĩ(ũ ø<·€+>ÝęŪn­+Ššē-ĖĖę_īq^E3ŋ~H­Ļ"ðUđš­>Ŧ:Â!(FīčZį3ŦÕʍpÄŪ=m7ë\ū!zŠ6ÐÃŦæų-ŒÏ“afî™ĩŧÅ5qV f/ŲūxņĐÎðØũ>ŅÝNØĻņÍ݈ĖÝÕū͚ŧÆõôܛäŠvĻ$mĘ―atēK0 ŽKjIýd{ŦõųįSUĨ&ÍWHĖÜãZûy<Mķž|h zwWĶđ_'ķÔf<ņ€ÓXÎŲTŽĩNŒáîtŦœðoÚ7ĨLfvdž·yPVÝÝEø ŊŠî27ˆģ~Å $ÛŧÜ(ŅÍšÎZƒõäïķwgæšÖ”øŪp3Õ î^'ōË@§Đßž™/þdáŲ™ŋŒæFXũũHïûĐ뉭ĘãûšÖi)wzļk W|;fí ŒÉÕÜĪÎĘáŲėũu­Ņ`ÍÂĄŦģöŊ›ŦÉ ðŸýŒ0ÎŪģEPÕûI•Ė-ŦÎ3ÚĆĐõđ.#sïqūu6ÆæŅÕęÆaÚŠôĩ"ĒĄąØÆņStÐ[ĨŠëZkÅ~tũåũģĨ>MęŽaŌŠ:6ŠåĶ_D>Ų wï,An~FėTņâŋŋVãHŒ,ĖzڍĖÐjwũn‰Âā2"†e$ļ9…ŽyĸD/žĩ§?Ï3CœQđSÐÉčÜ}B`Ŋý<óĮ[UÜ]Bw lŌ,Ū PæŲÕ^ŅRíéþ]ėzÄx―@Ō Iš™ÛWÛ}g aš;ŠĘlâÄ]ÝhЭŠ[ãÐå„$Ė aeĐÛÃ=þÉŽ:Gį„OąMæöp“F{āĸšŠ%w^žxņuĩĸĒ›˜+ˆ#Š2cDĖL4Ķh7?„Xø §ĐáØ ÔiÜ{WĶō˜I :ėšV>[-7_ŨW‰UÝ ŧęüÜÆÖÝaÖŠęŨÚy.ˆøĘķ(s'yŪéˆ"wrrrŸ=ë‹óxÏT™MÍ䔛[We“–Ï·a`Ŧ‰1ŸėęXņÍ*ŸĐ\u8ú”ŒíúFš'3ŨėðŊ/y`á|wĩ/^üMŠõSHþÔCōšÂĖ4ĪuvŊc*u(uÉ{?EsuïgWi­―aŸOíꖅnOĘLJ}‹Ęݧ;ĮÃDŒyĖÍf(ž )íl~…ÏuŅ ð(Æ>Ģ9#ĀtĪį—ĩ ģrÍÜIŅ`­†qš~Oz™ÜiÎŽáŋĖĐ Ļ•:Âŧš2ĸ›9’‹uÎëöNŪk=ϝO9-VėûĄÁÝÍl6îkï}ĸL‚~ÅģUGøĩÖs?­úüsuéŽ_eĪpÉųđ.H4cīž.^sA•Ų•ĸüģÆŊëí]€ü|ėĖ<œB›™‡ MLûäЃ”FA|ïĮ@áŋPW›5Ņ‚Š1Œ•GԜސHlŋÉûūŚ܎ŧt˜QdĐAXDî];Õ85ûĶ­ŪnéÉô0’―[uJúß.ŲÛ^ßæ˜‚1ÖÎN_þjČiv§“Ë/U=kŊÞā4þ>?OŦ=Üijøōu]{lcâÆk—9Ã|f|2Ąķp†íÖu&oN3aË#voģcd§’=<ōΉđų\WæîîYe<ĮH&âŋQėU­ëZ~ĸÜķ⩖ԇPN§aķđģąóĄYXÐųü<8)Ĩė]gā%tNŪ–Ī*­k}ÃY`ŸõÉĖÚÏĐŧîį1ÁÍÍy?{˜ðŦ ęę>ōÞ?ÛGl&lĪŊîB_ŒęiÆ5;ÓąĻ™@GZ@3īŠOQ LHX›būôGuYåîÜOÂt­kWB-`}Vå&8u;?ĸų1§ÓT}ï=ņĒčķœîÞ=yäîöý*0!ðâŋŋVxáãSá™%JĨˆĸv‰ËÜîûĶāMõM^’z īĸás=ÏCÃ)Į―þ―ØdãGhI*Éúз/w?VīĖÃï3QB-â~Ō?ŸOK'_ÆÍüyî–8M―ElīS?SUÕĩ"ėŒĻį.‘ũÏ ŪkđYu™8á^“ģåūĶ Ī–ōsˆįíûėåWfŦeáÜ?”…–ŧĶrƌ)BYīsÁyįIh<= đbýG'fÄ‹/þÕęÎū>…y]ŨzN6íŽēÜĖhn–{ÓđĖ Áœ<ƒ\f1AYF§šs?8Įn­VÉĖč–OŠ{žaWĢc- {ïaęĢd 3NŨΈ•ûĄ™A0t6i6ģð„ęæÞ4ĒYW’v] Āýl7ó‰Ŋ†Î_JŌÜÔP—9 vaį6§[L'…7>ũ#€ā„Õ–ęZ!Mr/[wíÚmĶŊĖĪĄZáąkÆjŸbvū…7/^üMÂД­õYŠžō˜U7€ Á“3<þúޜf(uvfƒ–ĩŧõM\|ēŧÍž‹•šŧAÍ*ët˜{w}­Å™:OÉBŦ™û —Z*ŌĶĪ‹fnnĢåúÍclã1žõÎ,-"ŧšuyĀøė„zōŋĨ)ŋņŧKÝ]ßčņ0·'’FškjuüÅafũÏ SØt)ŦŒ–]Ļ6âú|ō4åBž"FąÖ ã‹É‰/^ü=ŠĨa­ÕÕ:Œøų\•{{˜„ŠūÂû†,|ÆÆÝ`8ŦÎÐý+)Ĩ R%ÉësAĖL•ÖĐ Ŋj4ž…ƒ_ŨĮĖšŠ[vũIâ3•å ‚™ÉÜ$U%ĮÍŒ Į$ĶŌdÎîŸý―ØxNÛūK†Ė<Óqd6ÍÆÁqÔl<ŒÝÏó„ĸ‹ođŅi}~•e6Tl;ŦŠOūA?{Ó}]'”6Į›ËgïÉP°ģÜ-ÜßíÁ‹6Dq‘jõ$ŠäއvCp•Mē A0 7lU6ë 7ŦL“ß:Qaæg°…Ķw+ŸÉr wo5Y§2+óš.ƃlēoÆ50Ŋ$ŧz,j1Ūģá_óŠl!Ö:.ƒē0A“ģÕÕ§E‚“?kæ­6CW‘ø.Ihŋķ.3Zw ]ĨĐu4ŪųŧL[wÍúķ-xXw“ŒËf„ðPkzƒ@æ‘ëâŋPė5CŲčüûĀÍ|ĪNš5ŊAíL3Æōę”zŠ_ŠóŋŽØýMĻņYŒJ0Øþ―ÁŠ_SQUuØ0;Ÿ}K ™ĶvwŽĀq@xuƒĒqlÆcΜ%ōtĄũĄČņ,ėÓø›™æ‡­Z€ûôHĘÍĨ>ãŠĶ(5"|ÆŌÎ>+Ũ2§Gô‘ëΚÁ$īÃĒŦI›q{ô>ŌãnĢ_Ũ‚Ô-‚xņâ/â] +"ŽæīéæËI3·u…ũģ[}’›Ūš"@VuįĪ šë9Đę4·ÏéSĻúė"ŅT7ŠjÚÆūĢīņīČĻŧâôƒweu˜é Ņ*ŧîÝUՇ+ÃOąØīiöČ{§đuWí=[;Ė~ŪĘt§Ý#Ŧ=–Ũ°ģ{ÎÔܘMÁ+–đ?ÏÓUĪŧ{VÆåŸĢ‘Č]]"mŨSU*ØŋžfT· 4íĖ*‘Œx[^žø“T[YFÍ&“EęĸWV„ˆëė.Ė\PŸĘÅk­ĘĘgCÖ­CĘpũ§ģŧ#ĖÂrge­Vý/šģ[rûŪ_Mæą-€ĒŧŸ°Z­å’έĸmυPÝl|ûÏŦqÞîlļéÉuĄđؙݚbuaÍĢ+íHÎŪ6žŪ%@úē!ÔĀygr&bōYæ†Å“™Oš{,ÏJ€f~ō' ‘˜rÉåŦŧŧZęīø†(þMžxwĩ+Ķæ Æ)ķiĩŅ@f%SU u,?íßÕ_^ĢY„Ë0Âgė.ĩŦŽVų T–™›á?ũÝĐĩžŽĄĘ8ËÐŽl#‡ŋ;Ý·Í%#3 „Ÿ›<ÏÓOŲÁw‡ EļĪŪÏ"ÐÕ4þó?|Õj ;ŒYįâ — 4–š2 r·.uĢ›ķëÚ=<„…—z?ŧģ-1A_`īÂŦģgSiDï4:œ f·(Yõ–@áŽ_žœDĩ(\ëęŪ*UÕú $Īļ"Šz fT7Fxۚ‘ÐĖŠ[:,Ï―fnFæũbžw­`ļÛ3Õ8$ïį1Ž_ 6stïÎn4Uî7ĮĄûÃõž{‹ˆsątnNĮâĩN*X·›O„˜™…ŊoY: Âޏ›ŅÄSųcîn†ģųús-eÞ·oāoÉÍÐ- /^üAžS- }oq…Ó*+ÜýrIÏ―þÏŅ@f<‘ÏSÝkÅ|ŊJÚDŦ4t܍ęôðu­#­XA·Vuö:UáĨ6ũˆ/Ļīší{KðåîŅęۊðFëÏigjNīŸíäŅHøæÖŠEĒ!‡™yU?™’ÂýÞģrupJmõų,QϓUEĒŦÔ-ŋ •ÓĶ>á^SŽÛhĢ]óARdUi0XŲÏÃŦĨNÅCæ–!ÖÐ-žxņâ/&{́=@āĐĪņŋN*3Ģý&ÕԐwënvrwuŸŠ—ððŠq \~4RŲ}Ėo”‡į7n1ö_ŌŽÔ,itsÓØ{­āį)ŲVîĪ!<}­\á•ÕYtˆRũ7KwM{ŪÍūuķÞRÝ)Ãé}Ļîv7û*.fkãÚXÝ:~„ G‹iœÆu[Úģat ­"aß#A€\áđKj7wģé73'^žø‹xwĩ€ŧ{øÞÉob?ũ]3TVg&`cÞuģļÍL{đ„ŽīßúŽYYŠÚ;)žvŠ2ģó ’ ũÕęiĻ5·―KÝ$iØ;ŧڜݝ{ŧŲ$ÞÚ·Ó+šUgdŽå€*k†ĘœīšÖš.u›tķËWUwĩŧĮŦIˆéūýejšÍcĖjuJÆâKĐ ģĐVMwÉĖúÜoē#Z–[œyV­öÃ[xóâş{Á,;OŠÂýPO›ųŠČ]ŨuM* ÕónļK=#ĄGHúĶt;›#ášķ]I_ëjxÕîþ&yŸ[ÏPéú+ŋJRG‡°ģwDāDXkА;'*ŽģæõĄû6ģĩ<Â+ģՇ"ŧjÂ^Uc9ģĸĶ›H˝đ‹VI2ĸ6ĪÕáÜ1VŒąx #Æ"qrņųįC‘€@šwíbß{Œ]ųÞžxņ'đLÖÝ4—ð›`m]MT_ß*ˆĖ=åŒ;ũÞ{2eNVKFøu]đgQ‰FįđĀ—Ÿ›gâSŦÏ €:ėÜâ°ųl'8]:gó[;iķ|č]ü'ÜÏ ÎjļŦÛãðl dCUÚ_ŠīVe•ŧ›Ķ0ĒđbĐy1…ūcåš ēģ éĘjáú\}žSņuũNų}âlNåDu·„S&öĪj}ūÉ5&MPũë_øŦxņîjĄŨŠ]i2ĖZģZg•đ7Ý2āŲ;ÜÖZų<]=6ĸęŪĪŅ,+Ո0:P%ŅÝ)Î9þŠøę č„umAŨu}YŒ0·go8­Žų ǟŌYs#į*=,ÖUguJ˜ÓļM\wÏŲóŲn~ o;;ƒnn]Ĩ)ķ—f)ŦAø:]Ōš–{ԓM‘æÎV }]ŨHŋęVíī°8{˜Y• kčāˆęˆ—kĸ&^žŧZs›c"ŒŋÓ\éĮՕ]å#Õ žýfW·NbƒĻĖĒāû~*ËÂIœ+yļ ]I"N^—Z+ÖzžÛOZ įđs§›åŪŅúÆpŦųņ2Ät/‚u? 3ĸæČ “ÔJwÆ ĩ€ŦĖ<Ŧ,ÂÂO+ZŊ†?đwĨ#ŧ†ü‘U;wŦ<ŽæĖiĀŲŨVðģð<{Fėü•7R7 î~ĸÜh5šfÝ6TgaËßĮ/þŠ17Ēŧ)˜•EĀÂL'̟Qtūþŧ[íęœŌFŧïÝ §MĢ 'F<Üj.iöĒãî•ū3{įw“[―ũsX;Š”ÕĖüđŸę6О8ģáĻēĀžŠ‡Ęt;ŋ˜­ŌōËĖŧŨZĨ&8Åbģ.ųï:ØÝÍ|ÖÄËÝ"Øęîk}ĪÖđÜOņxæģ<Ü-Õ·/™š~ĘÐ]ęÞY}ųōøúqÍU­RCfėęîÆ‹ïŪVÕhÐ °ŠD ĄŦĶ—āXiÃ,UR ōu‚ēHĐO“îÉyÜījį„ętÃČÃGīšÖēðYYĀŽH”đ8Ž|ĪuŒaK`>ĐÝ $ąbAi+ĐŽÚÂ,"+­XÕŠÚĩËÍ!u·›ŊX™-ˆ#ƒ­ FkgŸÏ?Ēî―mćqí;Ņ‹ÍDÔŪų[ggUAúÄáY)–ĖÜ08)ig6ī>éáŋŋˆw Ļ cŒ$–æ4Ë{ÓĖH;‰ąĪ™YUΟ―į,sGÎĩ<"ȝ[j‹UÕ*Ņča;SíbVŧ ũ IYú'â6'0Ąģ3sZ3ũØj œu°đë[ũĀpPŲąÜÎŧąz­øöF6⊓§˜ĨŽå{gå†čü ŋĖ ēĖ"uÂUŧ–ų™ĸÂĻÜ$ĀiÎßvœSœÎ–ÁĖY•ÕMw@įv23‘UÅSoŽjĐZ+„/^ü=Šmu˜Wn#ÍÝhųlAHÛÃ,îYÕępõxAØo„•F3‰ŌQæySøōKŲģ^?ϏZ v7ūđbŲՅžn…R›Y˜)KđÍŪ !ĢI]Ý~œēã8g_ņœ†GšĩīũĢÆĐ†œM€Ž* įëĻZŌY2 *Ąrs#ÔՐûIx€–ŊoØĢÚÜû°Ĩ-ĐZ4SéĐénhŠ}v2dFwŦĖ–Øō°|“―^žø› ĢŦnÝ "ũƈ FN ^Ũ59Ų+NŊøóH03ĢíCĘfĪQÝ[}ļg:føiKl­ðY˜:Œa:œ&ē#%M9NŲ8ÜqʎÁÁÍ&X ŦÍÄý<‡7)ĄšįÝ tũđØŦ;+ŊuņԛCˆ3ÏÞĸų™lÜ.eĨ[x˜Z‚Jöɝ_‚›î<ųģ‡ĐÝúž3Éåkï €ÆîžŨh1wžŪë|Ō48ã[­WėõWņâÝÕJMú uŦë$æŒŦĄFwŪ ZӒ Šģ@^q™ŲŲÏj#ÃaC.kbö―ĻIū5û:Įþ; ‰æQ‡€iü/KŌėđ@kh ˜°ÂŊÓ·åîs§Zaa îû‚ŧOŒ·EŽk^â8ÏÂaÓx­õ:Œtu—ĀuÅäȰbU~KÌÜŋ>ąne>á!špĢNūĖžÛ MöÕ˰Ģ*]žUĪuÕqp=é”īkŽ\$mliąn#–I%‹ð°Ę‚qåaí‘ÁĶ.ð0āÞĮSûéVîī>ōÞ7ÅÏõÏI7lãąŌî$ėž‹z7ÁõđœŽ―'ï;ŧŦŌÜWÄ}?ß7x?tˆŠĖîúįš@fÖ'€{oBãiŪl/^üEžSmþ~VëŲ;w­ Ý-ĩ[TVwĢ5Žƒîr§qž­!UWŸŅÏ: Ý͉VU‘„P%It>yæÎÎÓM "ž#/‡ÃŒ'–€{`úĘ<ÜlïGį‡îŪėI!Ļ.I<+ckuĨŸÞÝIÏYWŠÚģũčîĘdÃÜöóĻ›ˆûÞ$=ĖÝóÞ ðßoýRÝRÐþG•ð<Ïė—ikÂįói`Ę#@<õu”đđJf4/^üEžS-ānNÏnsšŊŅ„ˆėRũ7eņđaąeíq—5ũjb›üđŸË"VYĨF‡û!ŧ2ãĻr_Ÿe°{Ÿ;.ŸŽņCūČJnĮĨéĮĄŲXiÃĮ?Ņæf™5ŌŪåÖŧ;’cΒY8ågŨįúė.q%âŒĒcûũ™M4Ģ Ý%AdVŸ;áŸÏ­]§4ė„ÎÄáýV=įÐ D·ōIsšÛófuf7ĉ”ĨĖH·;ģŅ+” |]p ›čây‘9 3Ÿ Ÿļ<օų-wĢ)aæ#üęCŌ{ŨÎ4Ą9ÓöËՀؐ™ĢĢŋxņâ/Š―š xD—ĶEņ|ų―UMš3“SKt6IwĒ5ūŊ8SįsĖŊ$ũģÃi‚ĀŧŠö˜zƖ‚ū<Žž$iFâH ZäÎęėS4ŦÂÜ%ÕÏ―3ë\<ž…ŅxYí:i/17›ģØÕ·Úķ6Z4Þûyō™`ļ& †ÜÛÄĩÖôŲHýđ>°sk ĖŦ*ŧhpWš Ý=-jÝÂđĩđåđfS°QėŪNč‚Ð4ĄYæÞ*Ïģ)FÉŠÖĐ Ï*‚F;Īü-—―ÖúyÂDÆ@ęžĀõØĖëŧjũ0ZUŌ-ĖvÖīHÐÐ œœ5+āôîúŪ2@ĩTū)·Uá~ülfnÎʉą>ŸáŲjđYU:L.ų<#ɘ\4ĢÅŒŌÉųþd“ã‹ïÁ-ēÔYFžöŧ%‰ĸ4ŧžĖIyĐŽ†H,Š"`įšė„p­Ŧ…ĘĶņžÖo’atĩm‘dWˆ5z~NiãL{—ĮŽ/HÅ:W‹™u]ˈl<ĮVŧÛr'@Ņ}ÍɝFËŪŪZkEØ~2ģT"ųė-h…›S%ƒýs} t‰nqÅÞÏÉåZß•-MĶM6ųrIõÍØõ―Ÿ°7‡g9ņ`™UĘÏguŦ%ââŋ7ž‹'ņÎûy„6#ĪÎ ŽėÝÝ"Æ4%õ2p?7Äõđ uĩZ~ĖŊÓz03+ShŦÄčšv~ëu)üúV­ĸEA‚ŸÄXģĩ.U?ũ]ЈČîCōEĻΕt`ŽhÝfÔWPEiČa43VÉt™įvN ŠÍÜÍ*·ÔĪ™‡ZųlHf‘UÝč.4+ëX„8?ŠĘZÝáĨ&ĪqyUĒÚwžį6J‚dqžŽĖg‚‘Äūo3ĨⰈĀ,ÜņõÚÉhįŲda“-9 wkõy6™Aøƒxņâ-'§đóįþQóŠ b>Õįkĩ*ËšM—Ē$úœ‰áóđ,Bý-bDK‚lųŨÝë1§UėoēxVu•đ͖šúüģ:Ŧ ę&QRW…ýíå―ŪKÕŌ·ŦfŸ\.7ÆrÕMģRžĄ2WvAĀ}jkی+VuĄ$+Ó,Lėj5Ô°āđááfg;Ąk]RïãTUö]ŒBŦŊĩŠ›ßÕ)Z:e6Ÿv›ĮuEUĢÛh4Ė  lžĶÎýĪŧŊï •ĀÓ™Õ-üüįŽƒÓęã4swûĸKģĩ.đČX€š›ätšĩÚÏÕã[›ŨÏó˜ûđƚЭ늝Ž*âïáŋW0‚ãč_U5ÕÜ4>Ï―ó!éáãHp· Ŧ=ÎĻÕý Ē Šîž%ęoaNüēįZßĒÃĄž)žqũqšt7uUð͑™ø›u”XÜįŠŠŌÃHHc öĖ3w{ļóTáŅu7ÉŠäf’ĶúkžŋŦžáÝĖh—Ú}Ģį_@BW‰ ļwfįŽ šŋánUĸ IũsĮ<Õžûž5;Ûhøƒxņâ=3w#ÝŲ‚(‚ą&=ËNđ,ũ“€ŪÃY]RũÄu’ÔÝšT]áî“Ųšķ EtĐ;ՍˆŽúU_Å)ww‡$Á€ÃΝŲáæÏNĢĖ€ÎČÜ*{gŦ?ŸëyķšA;3l‚ænģō°"ÔjuũáÓĢ/ĢÍ3wwûĪ›įdÜZ??ĸņˆĩVøAžļqw7GgGÄ!LÞ{ϊ`lN ŲÓ*'YÝNæv‚w'õöOâŋŨÂÐąŽŠ+Óh+â+ÝĸMđ&čæUõóÜÕ;V {Q°°û9ķîgšÛgíš―DcĢëžĢ_ ÝÔátõÏÏāü~aϔnÏX] ž―ŧš3üÞ{f^€ûgÂ―bb ā6d75Ó]î>zâXŋ€ĖŊĒJߞsģ]'ö0ü\PáqÖŠŽp·‘:4Í äóÔÎ-hBí|IčþÉ2oIaˎ-­ŧ—‡›Ýû–īb―yĩ/^Š]ąjŽķFwŸåĨ9ã$ŪîÜ~Åĸäú?ýĸý·ŪË~Ã^ úŠŪ6p2ŋŦúyîĸåĸúõþŋü_ĸ7ĸÛĸ-ˆŨ “}mTÕÕ]ĩĸgĸ‹ĸųĸîĸø?üĸOf„ÐU Ïc”$6N$ķV-óĸËÞyĸGU=ĸ7uÓč‚ÔĨB Ĩ Ą#"ĪWQĨh "ŠĒH3Ō{ïĐŌ$tB'„" -ô !û}ÎßßĮįȝDđ{ũė9ũîÏĖ3óŅ4āĀ ėĶݍ|îķlš‰·xĢęnģ$ æūΑŲÔÓdĪiGåâÏēĒ‘‹4ŧ&KļÉgcļ%-l Ž•đ\'ģ)úņĶ_ë>˜Ŧ™$ U_t1Ԉ…C[Æ  )ØÕR,#―Ũ2Ë,ˇÛb$B™]srQ!RJpŅéĖŠ>hčð:u"ĀÆđóggýøãõŨy66ŲŊ"Ģ]`ĪĒ7OTŪ\ų#Gýą`þ=ŧM§āĢóĖž‘~ÐÛÛ§Oŋ~ū>ŽsgK6SĐŦ;ĸ"&! LTžy ĖĐ8Ŋ”ÃRõ`vķ˜RũÄ4lŠ=ā˜ĒijĸØ‚Ē-+P·éNŠņTóJËīåōŒfĢL ˆ=UmĮčŨĻâĒÓNR°·ƒB€ÆČžI˜Óę Íq/°lš1‰:Â9ð^*_ÓØBŋË,ģ,?&{)”TRÖĨjm^âÏæ:ģsj„Õúsņē.]šÞšyÂV­ZÍÏ?BáVŠ\đFxÍŽėlŧŧĪî“ÚUŠô5ÂÃģēēð4ųeķœĖ|Įúš8ŽĖôLĢ%ĩļÚ]ņĩĶîē:§Ŧ††V|ó-Tød„ķÕk†ŨŦ™ó*[õ ^UĐZ'ĒūŊŸáâ SØÕYo OS–k2^eMZ€“Āņ ðfeIɄՍ2í›`Ũð…(‹ŦGü3ÂáÔ0UĮlrGøÚD 8fb’ØkWCmóMšČŊé!—•'Đl^Ķîƒē •·Xk™eųŅŦ•péąĻOó8kŲÎWėke9ģštûĻ|ųōK/ŠŽšŠü‹ŋŸßģägĨ˔š6ííÚï@“K—.|;eĘõkq:wýzō7@3áîÝīītƒ7Úūc§a#F– LM}đjÅōeKkzŽvQÂJ―1yę·aááëÄÉãQS&―ņF™Ŋ§L ĐI/_šøëŽ_>éÕŦAƒFļ™ÉÉÏ'OœxâÄßóÔZ[#°Kĩ–Ö4HüU…Éë5Up’Ö!>4Ô]?ĐkĀEÅ74tĐVč†˜vÕāŌT‚Caē DąLû’Ytŧščü˜š}p3L“‚傌ðĢiŧKEF―Xf™eųĩGģý]ZgEéĻ)‚]ˆSąbEœŧ}ûöžLy‰™–öp|=eJ‹–­VŊZAŠ~ß~RR^ĖúéĮ “ĶXóVåJ°Žlđr3##}čāO6îË —._:ýũ ‡—ö°ÁÔąũåøZķ˜8až·—įwŅÓâã 4jÜdßÞ―įÎÆú8þÝ>ú8îĘå-›7‡T đqãš(žhˁÍ-ÜR^šS,ĀžŠuÐá k t€ Ųô3eĩ6yŨöʕÃOonœM?ŧ›xũÐŌøú`”=3MÚâz ’°ŋdztâ-ŒĮQÃfĢ,'Ũ)QGŪGX%Ōó$B@ėNÂēĘ=Xf™eųē0Ũøv#š@-ôōöņõõãDff–ČYÉæđ— 6š{ũîßO›öÝ·—.]"Œ[žD‰reËîŲĩë‡čĻŲģ~IMMRÁ!!ĨJ•ÂėØąS`Éū>>*„Ķ—ĐK†……ÃųõëŨĐS7öÍ7ßJJJâŠ*ūų&č\ķlɋ)ééAAA!ÁÁ˖,yųâ^ŠöŠÉÓ 7Okę@$ŲüY#uĻúģĒ ãŌ‚ãÎ2@ŌŌ<ā#$'ĀU$ž0o‡đ0&d0ýu4Í Ö0JáŠü }€ė’”ÆŨŠPƒÉž(Ķ=ô’Ī X |UKL5nl–Y–ĸĖōj Všīļߝð,ņMrÔãsKƒj)Éð§Lđr$féÓēîÖ{yŠ.—dt™U™™Šč-ÞŪ”öŠÁh_?ŋëŨnœ=ũðÁ}V1)ą6ŒuU™P}kËŕ+–Ÿ=wv͊i/S :zĖØ­[ÚŊoî݆ Öąs—­ZųtĀŅ#‡đNŸeÓIŧã(ŋĀ ĻߊĨī^āŊ“ą^îž$˜r^OÓüF›/z ĖīwԔ2§M{°såâü2ĄÉÆE!Ė]J<ðwĩ°ÂS—~ĨņY)V0rÚ$ß6ĮĶåsÔþō%1RÝj[ŪŅTÔïÄ2ËōĄY"Šē5D“ņÄpČ`(„‚§Nf@Ŋ^―Ûī‹ŒĻWŋMddPPĐŧņwK—.Q'"<<žRĨJî?ĀyÕBŦU ­^7Ēn‘"EāŅģįÏqę˗sŸ=wÎė―ŧw&þûŊéČLāâųógOŸ<y‡œ9ã‡õkŨ\―r%88äþý„1#Gœ8qĒzhu‚ÎėėĻĐS~ûu37lŌīnƒÃGŽáJÄëÄ/ŌiĀTõnpŅíœÓ<2tÅŊÔxāã-(ÉĘ|PS ,õÐÝČËڅ†š*ë!Ē VQpMÉ@ý‹Ž2ņÔ,7SSGČXœ`LÃÞRÆĶ™ïšv’ĖB..ˆæĀÄ:l–YfY>ŽÓ-{—Iø‡ĶîĀCôW}V­\F^Á AƒWŊ]ÏÐÔÔī6-?˜:ųŦ1‹æĖĸƒ3Ī=Íýý·;wn-ü3Įsóö>ĖČČðóóŧuýúēĨK8đmįîĖĖL8ÓģGw<;uuyOóŋþ2󧟝=gNRbR‘ĒE~šņCáB… öøņã%JėÝŧŽoß―įųģįĖ™p`ïÞÞ}ûuėÔ).îōŋzōĀîŌ’_AĶözP3L—Ļˆþ' xīÚË4Š1ÕąFøFo\šĨëhėbPɂĸŒiV­”ðŠ/ÍIBHĻ­Âꌡ'›K8šé*ęōŦíåĨJ4HKJLCSĘŽÖbųÔ,ģŠÅī‚V}[€bęŽ` éii?~ÝĐ}ŧčĻĻɓūnÛŠųƒûũϜ>Ý­sĮéÓĒúqFë–Í<€fëŒïĢGþûėßúũéŲĶÅû æÍaǧßĶesžÚys~ïÞĨӕËAņÎįOŸõúļ{ũŪ}ū‡ėÚđý—Ÿ[ąbé€ū}Ö­^ĩ`þœÇŪ^ĩräðĄ_Œ―qýZΓūý]Tn]N<ū0fþ˜Q#ÏĮÆē1%Ždž5˜r Đ PwUzÞHe åĻz!ĖÕÆbĶsš‡VNpRŒK5>)āŊúĢÜū`ęÁ\Ķ·˜‰·člb kmÆËM37 ’ °Ø’aĶÂeõpĖ·f™Ŧ Ø1@ DŪ[6ŪÔĸĒ@€Ö^§NĸįÔ)Q{qūr'ęíŧeS™ĨÏk€mÞļ˜˜–Ú773ãüŲØË/0R[ ŒL~ûöMbä?aũîÆßđíĶf:mZ·ÖÛá-ÔËôŊ―{ėÛŦąN;)šįϝ;þø.­ÐÞ_FuWIĢwĢšÝSk+Ī"Î]Ž9’ãĨ^'ĩŠËÃt™tI1ƒF!īųš9cۈiå 'Á%?F5œš2wí+ŽQk—§lƒyƒ["` ŧqĶnÄl`LþQīĖ2+€€‹g„ņđhxc?uËHttÓĖĻ―āėÁVņЁsʑæ­jKÍųįŒ‡ģŲõælë6m'Nš<áŦI-ZĩĄĻ,#îR.įä(:Ur…ÓvMõR4ũ6xšęÏŌÝKۈXP>B•ęÉæ‚cčŠâ2°Î4ååĨ”ƒi6/SCmLßčåÎŅ?ĖÅpK…đ\ģ0Wdg‰ß/žaĢQ`T`ŸoĢ}cĮ)ÆĪ€˜„ā6E+Îģv‰YؑĨUķâŧęV›tÏ5MðQQ_tg6OGžA:‹&æÖT Áω+ˆe°ÄY!ųŌ,ģĖ x˜4/øe4ŦÉī<`jâäÉóþøsĖgãF;{Ξ°aŲŲŊ >->ŪÔãc›Þ™íĖĘĖOĻfdĶãÜ]ÍĖΆ‡„nŦTŪšïāáðZoó’ÁĒú āðUU}ÆĪĢšXî*âÂyÓŽŒ_ €šåč„ŲüBÐŽl'tÄŅ~Ĩņe|FÐĐjđ2!€—đĖ )ŌĩiÃQáŌū;ÂE›Hk ŲC+Į4A[X2ĀÅXMÝ-le€Đđ°cRŠÆšP\ĸ„07ÕeÚ a ũ4^?ģh…Ŧ•€ĩęšseVšW~4Ë,Ô xĶqE§ZúˆžžžÖąKŨƒ‡lȈaCcĖGMĶmŧČ>ý„…Ũ1v,ÕôöjÖžÅW“Ķ1ĒR•ŠŲ·ÃŊUŦ6Ÿ9aJÔwïŋßžpŅ"ÁÁÁ_M™Z#,lØČQc>ûüEjj`É ÞýúGEĸŲۃŸ ›-#‡ŋĸ§ÃGīlß.ēý”oūûčĢƒƒ+~:dØĪ)ßīnÝęAÄâÅK|ŌģŨ”Ļč!C‡Sɖ‘•6ÍÄÉS+Tîöņ'}ŌËáð ­VcĖļ/'OB§LãbkZvĻ\ÚĪ7–äé­ Rč o@ ŊvÕåžF\šLš‚ ’ð]éķ˜ÃÓ[ã0Z †oŦԆïpŲh °ß(oį ßUá'ĸ™e–Y…đ"Ųęf7ʰš ęrĐöā{ïū‡‡;ëį™Ë-.P0/rÔgŸSA@%˜ŋŋĸ7S§ÔŠU{ėgãŽ>Üėýũ{õé7bؐkWãĶĸ4SÕl=úöí7ó§ņwâÃjÖd֐ŠY™YĨß(;w~ 2Œ'NŸõûœ}ûũėŨgįģpá"ŸôøĪhŅĒŸ<Ąfa<ČĖĘ*4`ā§Û}xíúÕŲóžûÞ{ŨŪ^íÕŦOũ=:wˆ,[š,ĩMšū[ĩjÕ%‹ŋhÞōûfÜŋ/==ƒƍģnÍ*bĩ°•ˆ…ņ’ķišxĨûrŊĖîŸéÞ}%Ņ@9ËFχ,Y DpĐi2m5Þ"=,ĪYs6Ā(iRĪK+›vĻdb/wžlÛkAž=&{Yf™åÕšĩãG.˜ë}ųō%q‘ėĖ,:Ŧ›†ęÚčnJ/[no”äĨ‰ÛŠ„ Ō“•L $uhĄ―ŨL3whÖĖ-Ϝe03sČXm`‘#đė7jĀåKHËHW [f™eų°áJX! 88Ö SīąóŌSÓoÝūÕļiÓæ-š9üâ^E‹g_úĮĻHvú’Ē2tP‡ÉĖHwøøÞ[·lFXŦoĸĄ5Âxī§“#†ļ{˜)k%zéÂųfÍ>6|D\Üēþņ‡Ó)äŠ[Ŋ^Ûķ‘ô[âÎq⧃ëÕo°gũ.Di;tčˆh! -YēdïÝĶyÂ2JoQ%wWMYI˜Åī-õΟ9ŲGýŽBHHƒ†ēŲŋo‘\ðLÍ0›]„:Ô°QãŸ>þũßÁ!Á/\DÚfņŌåÛ·n!d‘į2jđðP€čãPœXhŅ2Ēn―ĪĪDžĘMã]TÁþu€Ą*K<°ĸŌÅ <‰§gĪ:øđyëæč‘#ˆ° †d8Į—/^H~þœKš~ý*xæ }Ų’E(„ųø·ïØąlŲrIIČáMb™ÄDZōŊrđY•Œ10žsãĸũĪqQĨóã+Ð,^ŽiÉÎ0ÝËcNa힛k$Æ g›þFŸÁČApWšŊö_„ÖđYf™eųÍŦe?G €,ĪŸýĸ")Ād?z$öôĐĀ ’$$üûðūŊßĒ?cĖ›ëïïįðö!˜pëÖÍaC•*U·ôþ―xOáïŲØ3 xúôIFzģA=†uïÖĨté2Ϟ=õõũÛšiÓþ―{ƒ‚2ŌŌ` =ðŪq ““ŸŽ1ÐĮáƒX—Níņ6ýýþ}ø°s‡öėZąĘ҃ÎÅþSĪh1bÁéĐiėŅ=Û)ēŸŊe^Ϙ>mŅÂ>Čč2;Fķ!ųÁ„J‰ P Ą•ÂrÐ“õ[ÝõÛÚ Iķ5•Įr\ŠČVk`WEnŠ‚ÄlšŨõZ=eNōAü5…ÎJm’m3ŽX­e–åӂÔûS zÔL‚Į~þþ óŅÇøCōf}}UAüĩl yKÉlRâ#^úø8pã qÛėŽ,CaÛöFv‹F .-É%ˊxïn<䂕ŽI TŲ„ƒ)ŒÓЁt>D0Á.mÃ―ÔßtđASO[FzfzzŧUôäyý:.RøĩÐÐnZÛ28%ųų˔äÐáœÕé)áfšŸÛ0‚Ëہ)=x•ƒģ*õZ(aĪ{MÝšŅˆ†j›23 úßĒ&n4"4D`ŠwđŊ\uŠ―=―a:Æß0Æ(s5ÝÖ2Ë,ˇĻĩËŊˈ˜ôR8ðÂīĮ4Á•ó„CBpɓ1í}ˏMhC#DŊōT•_úïĒlöĀĄƒĮŽĮ,ZÚųĢqkUėāŽ1 ýYņUFZ‚;ģr4` zcô˜1íÚĩÃyâH'āe”đå…ØÉļˆĖô ÖũōðVý-ŧ‡ufeeUpNžFn„ëeƒ fx‚ dŒqÞļØÚĮ}SdėR oWcũ_ŧĶũ⁊d—ĘėB{rŅ “ÖģgoIžÍĮö•Šā€mÜÜ ŪÞē$ÞjŠTÅŨUtå ĩ/šįQŧΉIV­ę&@xūQĨą[Ë,Ë—Ļ•Ú|Ø 6`„f@6ĢĀP```đōåĐæ:uō$IZģgÏE­ölĕ/ĶāĘđP6Ųƒ˜›6n5lpŸž=Ļþ8h°ŋŊ‘ÂEįĮ,\ūrÕĒĨËæĸđ°x‰âå*ÏüeÖwÓĶŊ^·aŅ’ĨóbbŠ—(aždŪÝÞđëG[wėŽYīdįŪ―Ļ|eefFE?wÞ%ŅiųbüÄ?.2ē„7О=öó[ķÅ,\žyëv„5Xķ|ehXØģ”õę-[ūŠš‰ B6mÛū`áÂUk7LŸ1“b‰°ððųÄ 1rß_‡FŒ―āυQßM (PČÏĮïĮ™?OžúíÏģ~‹šö}Ņ"Å:víķdųŠ/&Lä/G§Î]—._Qū\.•Þy1 ųāŽ=û>hŲ*3-―N―úæJ6lÞúńŊ‰cÔ ŊõÓĖ_ƌ·iëöņã'ģæ^ÖnØÄ˜åŦŨU­Š‹—ïŌÜBĘâČãžSyüšxIŽ%Ēh™eųĩ<ðš‡tITēK~IģŌū6^…)/’Ŋ_ŧzúôijž}={ũéÔđóÏ3é™û2‰ãūœ@L XņâÍ[ķÜđsGlė™6ķíÛoõ&:QĩJhôīïq-ĐhĀG5z 5c=RĨJ•·*U*X°`Ówß―yãúËīTÝĢē5û Åø‰_íÜūí‹qc ,õýôK—.’ĻÛēU›Ā ĀÆMš"pņÂųņŋŪ^̆tÛ]ūīoŋþķ‹äŊĩgĢĮ~Æl{vï&—Ēĩrå˕ Ū]ûsągŪ]ŧZ-4Ų„ˆˆÂ3Ņū‚›7opŋÕŠ…ŌwrËÆMoūUĐsį.xÐßFE—-_~ėčQöï9jtŨšãۆ„„ôîÝïŅŋđß## ēbų2ŪäÍ7ßúzōTjØpæĨÛĢl)ĘŊ;ßmŪķģY"Š–Y–_·Å>‚W„ ˜d/iëŧ‘þ’j(/“*P°@tđܰQÃæ4Į#.Sķ,ËLtņâ…ĻoĶÄü1äĄQëĖɖĐrrxĘ.TĪȎíÛĢĢǧ|5ßđAĢÆ[6mbéÃķíšuïjâĘ+Rž?øøŨĖÏB•ŦT&xJ].óßļvíÜŲģč4V iÕšõÉ''&†ŨŠõ"##ßy§ũ@Đ.‘YQWØķ­kĮö+—/]ēxÁ:uëõėՇhėšuk6Ž[Įø^ĩZUDÅļņÆïūW―zč‰ãĮ‰ĨōĻĸėŲģГ&.˜;įáÃļŦÄO0ūƒv‘‘•+WâKxĢdaiŽ;ÚŪmkViØļ ‹ÖŽYģmÛķ\mHÅŧ‡hJ€Yälؚ#C΅UŅg ī–Y–/ sЄ,•ėã‹$ķū+LáĐÄm *Z―:þ؅•œ‹DlWŊ\‰ŧGYŠvŊ‘ÖŠ(9im&ģĐl€ĐvEĩKŌû}ÞGŊķNDݖ­Z=~üøÂųsn@ -ÕTjåИÖ_ûũ­_ŧą…5ŦW–-[ķC§.ĨJ―ąbŲbŠráÏU>}úlņÂE4-ũÐVOŸ=e*ĸŋ“ĮĸĶ8ļUŦÖMš6Ĩ\-ánhéééÔ)V ÝįOŸķjÓ&0°$šĐĐ/đi؍— đkn_”ė&—˃Đ.\x9ÃÁ­=þ”Mą‚ “ĄųdŊ‰ŋlÝē…šd‰―äå9_9íÖžÉf“-ģĖē|V˜K^­6—uÓ ­@AÚkkó.Ā'IZĩÞŪÅ^{·{„††.^īðþý„GÁÜŅÇ /ĻŲZŌąB… ĩÂkãE2Ō…JQláA›yjÔŦÖĢg/NÞūyóŅŋĸnŲļqÖoģųÔî]ŧÜŧ§ŨÃL6‚ ŒŋrųŌę•+ øûģŨ†ËI !99đOß~HÜļq“hÃĢÄG%Kn\ŋ6áÞ― RAI‰+T(/w$=Í<)š`Ý];w …ļŨŽZõ8ņ_nöÔéSïūŨŒÏnÛžđš8‘íSSSãïÜÆĢŨj4“ü ÜœĮÉvx-ëõũî–zĢôÓ'O(/6šŽ’–öŌH8^‹CX’dŽpáB―û ī―{Į6MrãĀ–ė°k,ģ,ī[Ē”HsîŨÝ\Īî+—#˜… 8ˆM°°°š11 ū™2‰Gėóį܍Ÿ9kÖæ;6oÛŅŠÕ‡ÎŽ,ü8RMŨoÝĘ~­ÖŽZĐuš6Ī Ž:ņi=cũÚļví‰ãĮR’SĻYX―|؁―{ðjÁąÃÛ1xPSRĖŧÝ:ĩ')Íŋ@ĀŠĨËbĸų‡<1nœhFÂÝxčÜīQ}ðíįĀ~WbâĢ>=?nаqpHČ­›7NŸ<‘ükæOlŦĄģ $ĩķÐŲ%t…?ĀZ3 \t‰‰þæ›ݹΟóŧSËąīFVüA|FƒQ°†MȘ-―=6āí,čzVAbB›§ˆ’Z{ŊŨ6ÜӊXŊŨxNßJõ8"„TæmRþäįŌp{$õÜTD„bæ[Đ Î9ãŲ{ƒčûļBÏî2Ą €$>|øíødÏäJRW]2ģÎ[ÔÞŦĶĮAęœKŋÚ―Cx­]U$ýóýs< qLŌž§7YFH6ŧŦŧŊŨúŨŒpû™uŠØĮ)1nÅŦžŠf†ĄĖ<įH‚™Ũõķąũ‹R]ŨŠļ^câ_ójÏiEFÄsaF\ïk<ĪökW7EšĪŠ+Bŋ†{íꊊŒPDW“&@ā}7žŊĩmũԓŪļf`<NŲ&ô ũǘúĻöÃ‡ßąŦĩW.·qPšnR{í•§šƒ’ØÝ0RŧĶöZŊ; xâÝøN ė1О>į·ŋfl+bfŠˆĩ_§:3~Ū’yębPŒX9nQbΌۑ‰1 ‰ýĮ܈xŋŋGÍŌžÞWHŠļÕД2Ōd‰ đ›`DÚ%iŊeûđ/ÛϰGBc\Ũ%ÅÞŧg DÄZŧš-æZ”š'âŪ@Ô9Ž\Câĩwû'k%‰'GØ3=ƒ>ü†o Ø3SÂKĄ™›ðR^gz&ĻĖ|Z?0@v7!=Ūsī"ŨŪ:Žĩ(tMŨäfž>Sé™îŽŒëé:wfĪšdft$Öyƒ4ŌĐãqfãô‰ĖT€Ļ:™WU$C?å+ie@qÎ嚟ÁŪ}Þ'WFÆtwOF„ĒŠ@Dˆ˜+DéŅbäĸýō AݍðýCŦŠE@ŠsBĄŒ']!ŠS‡͈žŪËãĩIßËÄoĮ‡ŸÉ^ÆØ M·Į_Õ Ī―WOyúþšĀԄr<㉕Ą°Ýc… tßJ Ļū<öĐÎ―råUė Iqî(v­5Ó >a茁§ũ ũīQ]=øémaĖĖíؐ~VæOāےĄX{čjQĄĀĖ“–DÄ}đ1Ķ DPŸ8"ŧšĪŒ8U )čöŽ= Dļ'$3ýÄĮ* Ïũ H™Iāš.Ÿŋ%>sŦkå"86Œ˜îšŽíŨÚÕ]§Cï*ŌZyęęžG…Ý]uW û&2(Ų0˜đzÜ3ŌđŒ\‹āđ.+7Iß|Į@fŽÜĀ80WvõŒónMŸī{o‰6ĪÕÝĒ~Â[—d(`w·á―Ömg$pÎe{­―ũkfšJ’Į§ŽHIwZ=€3ĢšĘļ[lû^D Þ뚞9ŋ3ĀZŧgŠz­ãTŽL۟Ūö·äÃ'ŦUÝ5Ĩ`fvũm·%étMÍÞ;"ŠŽg2b~å›0ŠŒŠ0$ÍĖ·zšŠŽD} I!uĄœîũŨ{đēŧĢĨPž:Uóy+ DŪ$q]o˜Ŋý:ŨmÃĐ UÕĢԐ zLĢŦNÕũƒūi…ü$Sí1<žSŨĖÓĀÕE22A(DPŠŪ6 …‚Ũ)ŊXÆ>U"‡3Ā^Ŋi E(ø~QzäÛ.ŊýĢNyüvĩ>|ēZ61Ūsa:VÐėžHøzŋEp§íņ„˜+ŊũQbÄ:ŨÛĶĪXŅÓ (šM2#$;ŸM…ĪũulÅZ *3ĶÆcIÉė* v.@į\ąVzœËāécíT\w°ŧsî<‰€XŨÂîXąÞį #‚"ŠJRF(㜋|ōCŠÄÞë\‡ž‹‰Óc;3Ë5c†V|ÏBĢ-eÕéš·! ö9 VdO1@âũãǏj‰é‘üĘŨßŨ‰\ayj>íę3ãJ+ęT#‚ŨŨeúNpÎĐÓßO~‚!xÜĘx_Ũí܌Ės‰õÚÓUc‚đrš{ reötۙšq՗팘†}lîŨkzĶFĐĨ<}ÆX+gƃr%CĄŪ͘™§ ïÔâ~cÁ™›„Ýk%ĻŠ3u|Ëš§§œ €ÞŨ™éüØÕļŸķÝ9Æ €SQu…’ĄëýÎ'VU-e8įĩ2ßwZB("ņ;ōáÃg· ­ũđ„B Ã)\įPZkŧėééïtŠ ÜąfŨÞŊļcÍ[ÜęÐCŲ]ķaUuQžOhƒĒ2ģ§Š[ÄÎuęT·D’ƒ!ĩü0Ð]GDĮĘŠëŨšŨđ(ĶRāĐóė,˜ ä^3 ’!ïšxōY ?đ­m’”`ÃΕÆĢÎ;{­é: ė―Ï9=–ĪŒūmیˆļÎĐnÓ3mB nÛw&ƒÁïȇŸŽv-?fŲ+Ýãa(@·-*r°đâԙņ^KĐÓĐĩ·‚į}ŒŒš‚‰AdÖ9Þ.Sc`ˆŠŒigdóüȕïëkÚAQžęˆ uŠdū–i‰ÆėÜ]5c˜Rī[ŽŸHį6qfÞŌ›æÎđO͈ÛėÔԚqO7āũVīé•ŲÕ5•Đ8Ũá―;™āĖĩîĸÐ"a_Ũ{ĶũJ’5ũ6åõC`ŨÜįĮTΕzŠ&>|øðvĩíŪ.(Ķ}Ķl‹ęŪz_°CqūūšfDØîĐiũLŸ†™qÛðŽBšjô€†xęęïąŦŠOˆ˜îë:=ĩ2ĘeXĄˆ8Õķ)čØ2aW]‘Ė\Óãn€ŦgÚk…ĒęôĐ―WŨđšÜkÕ@ ŠpŲ0náwȈļú\ŨbᯠāĩwDž*{h‹O§ŒûŠ~ŸC)"žw3"bįŪsŠ!Fũt_ÓSĐč)“ũ9ôtw@ün|øðyŲkzކ=Ķ8Ï0"ĩ<ŽŒĖČUuŪģr­LÚ *4öé)2M›dMMwffDũ(™™„(ØČXĶÝCEFvŨĖ„23Îuútæjø9ągšŦ ÓÝ&š‡Ä iÞÕ`(?ÖîéŠötÆ:3c„’`UæO „(cŒy:âŠ@j­}NŲEĒnÏNOÏā FĶ`<7x]ïņd,Øî!C!{úīPxÐĮRf„a|øðáw B‘đÎ9$Ű]]ĘXđĮ]}@€|_ė'EmÏRĀči"ĒšŠ.Û{í™ņi1šŠ*"Cņ>ï:™ä·o2tÎUÕ{å~mÛ 3eã?Ķ‚Šž2,iĶđrU@Ĩ \ïũôÕ}ŸąöŪ)īį.ž$ÏU.ŊĖq{ÆF0NÕ#Á•yGÆ‘Óm?u SXkĐĩ’Æé2MSėîɔ$ÏHJéœë}ND>3ņáÇßnÜL=hsáŠÆ8VTؒS3‚ а§]R(†ĀĩöU—ĮZ+ĨŠ‚ Ũ ā™ŨÞŸî”ö~ÝÓDƒã ĀÞËvũ‰X"Ï9‰X;Ŋũ1ķßįšŦý0ÆöZOÐ܇RwÚ ŪŊ7Œ• ÄĐóžņzŪwaú9ē F„QuÞCČpŪwHŠ=3į\#Öõ~ ˜Ęę3cI }―ß+3sŽsfüãõšNAÜąIšGøðáÃoŲÕRš™Čœîsûĩŧ‡DdŪĩŠŦĶ"#‚c°{ éöô-™]] %ļ~―R ǧŦjï=öô„HЧyĸPFûi%izðŦS+ĢŠŊĩó9>ģũšïéAčÔéEļÎ%q<ĒÜí™\i܂ödĪ=vŪĩũ“Ï*ąŪŠŪQ&fz*9݆ieŪï-‘ĐĻŪŊ\AȕJI8Ũexŋ^=ЌÐÓ ŲÆ‡~Įyĩ˜ĮJcdäŽÝ=þ lŸsÆNũuMw„æ€$ŧ[ŌĐC ÏŪ3‘ Š@ūþņÃö܅Eî:O?Ø]ķĨ°ņ<­Ę―Њ$Ĉčî™ÉŨō­ėĖĩ_/€=ã™ĩÖt0Ęó|ÝSgfí š`ßóššÎ!ʙįVTOIĖ―lôƒĖ4vŽ…T’œļý―zŨÜŦ`įŪ: DbĶïĨ)č3áÇßsēWP“|Ü"ëԓ{*âŲæŸSU3öĘÓc’ŊýŠn6‚<įÂ8ũŪŠĶEåĘĮ†ļõtŸL2žĶ”A’ïũ;2BšÛĄžÏs]=-†&ī}ŪKŠ\ëq7„ˆčųûōļ•RdŒÝU’^kw7ÅČMãîâ+ų„$df’<}cÆ š;3§ËFĪ`V]ĘHČķgH‰čj‚Ũ+{ m5Ģ4gĸüþkðáÃÞØþÏQ-ÁëšþũwũZųwl)Ķģ§šû6UtwWSRčŨ~ÖėŠS†þþúÎß3Yzú}§ŧ|ø‘ĸōɏ?þsT{ŠþûĸøŸį\ŊŨŊŠĪĻs.’BQS0ĢęDAĀã{åęi""ÖÜ}zÞ&HbÆßyBfũķkwþDŧŽ"(ø>YņL$€@pš)yühTĒ ÛøžŊ3DĻŠũ~UOn;öLƒ’Ôį("ĪąĮ3=k­ŪúūqÅLČHÃU5ž• ŋu§Āz‚‘Ó”Ÿč ŋ/Ž)ŒA(bzHweϟĸþïĸöoĸíĸīwïOM]kĀŨZ;Wr1!!@„*ũ›—ZŠP[{=Îœ™ũÏčĸŌ?ĒgΧūķöĩÔ īUiQĀ Ę-{đėĩÖsö$Į3H„ņ0o:<Į=Ę<ŲŪgĸðuąöÞ,Uå;sÖétĖÎ> C!TL„ÍÍ ØŌP(Dvģ؜ŧi4ĸ•|õŸ„žōëdgÁž. ü+8s‚B―Ѓ|čĖšĨTÍŠétjįÄVËzN E!D)á\ĻŠzðĻ->Š8eBū‰B!tČH!„F-BaÔ"„ÂĻE!ŒZ„ÂĻE!TôQ‹BHGBeBˆX,–JĨ„Īč kNWŌét<Ïd2RJR|t:ÅbąŲlŒą|Š „þē ‰0Æü~ŋÉd"ÅMJ™H$‚Á cLK+ ŧĻŠ‡ĩ,.//ŨëõExÁSĐT ‡ÃAö„Ð_–”2N{―ޒ’R݉žÆîĘÂöYĘs:ĨĨĨÚ4œRúĘ-Čī„õx<s–jôŽėëļïN­VŦvÁ‰Ņ…ĻEÉĢŅXð{mĘã™íh$މœYӄdÓé­d2đĩ­JÂ}]úĀęģ…›ÛŒŌý ļĪĪ$“ɐ=pÎĩvE!{ĄDŠl*•ü_€§ķ3ēðeęųųÍmđ{€Œ)†] Î9Ņ„äˆÎdpqøÆÍĨļīY$œjĸ‹w›*ä+cYņ‡ŋyÕ)ÂUÕÜÛóv™Å°ũų)ebfėNīþrŨ"8ėgīŊ-(БĒÐՅĐá™ėĮô:Ė:5ōÛõïŸö|rÍk °ŨDT„oßoļâóZĖ`į•ŲŠ…ļŪÄjŌ“ƒÃĻ=ZæŽČŲsɍŒüãëkýĩÏ{ËĖ<°ē3œūÜļ$Ôäę UÓÁHĀVũ΅ãęČð­{e•ïwTä?õ`įfˆP DOAH š\ARĘ7éˆR’N'ŨcRåBHÆģ™ÄV0Ëč(Púį&)RF)A˜ÁČ%Z―^6BôzõÞÝaQÕ=Ðā•lũÕØƒVƒQ{!LÛ―ō‹R–X{üxË6ô^o­Į–åōäi'!bëóããSąlÆčŽęîéŪ°ō!*szŽėø[uÆ?O3…ĨÂŦ##ĢĄmŪ7đ.]yŨï2ÅŨŸýßčD4­ZÝūÁ~–[ĪāÉĩ›7ƍĩúÚ*…Øk9ęŽðŧVƧž%{Ŋ )G›Q ˆņԙūrŧøî›=\lî=qÜã)͖·žïĻYúidb.yõãĄŲá#wÝjĒ…‡‡Q‹ÐŅÂ9ßûÛmˆ”"WÂhvúÞ=ÕÝxÚ†ýC§].gûĐÏï,R*MDR RHĢÕéũ–&–<^ŋXk ,Í>úek3ĨZx*OÍG-—:Š<Ö,—”pÆÔgũūcöÚÏ>ëą3ÉžáBÁŽˆ”’2ЎBH­$hGÎÁyĒóRg=ÎЙåĀúúöZDÚęĘ˔ō–ŸgW$W™IZx4ŸÚŽĨ‰=Í%‹Õhriykøu=’LĶ&oߎ„<ŧ‘õú‚Q‹ģZ„ðķØN +ąĨ"ģK‹kĮ›ýF…EË VŲtÂĻc™ÄVˆÜN§ēD§Ģ€<—ŋæ\gYčÅÂï3O\ąāÓDYïđ†Ųä*ĄTQô&’Ž',‚Ŧ„IŠÛ_KÂK??šë?sJO$Úm1 ŠÉhc[ÏSY^f7jÖbŅA˜žáR—I ĄõL€Ī$“BÄ#.ī~'ļó0éųÛ@ÃÄp€œKāÓ+ÔtĖwîíNģA!TŊȃī€{!„)lõ4ūÛæžž}óŧą§§~]ވ*Œ•8='kmũ'îþ41>úpÕqŠÓc`’ä|ifōæĸÞxØ:QSŪ#$ÛXüãņj„Ŋ?[ÚĶî ­ŽéGGïü0~ũ§õhVĻžÄŨ1ÐÕ˜š1:5ŦFÉa‘’sWø /nßþeúÞØôēĩēÎÆĻĒÐøÜýņ‰û·ū–Ō†ZMĨ.O}ûí‘- LÏ(O†įfį#‘čæ íņ/b7éŸ=œ|8Ļoi,•‹ũÍ->}ōۓeIĢ!Üį @Ņ5t]ûtðm—A$RĒõ|ßŲZ·dæóÝC=-ÕRę:. \ëz‹ȗ f9Ó5ØÕ\ã:~âŌ⇗Ï֝lë§ĐÖvŽžĸ“šŠĘ(ĄÚ ‡šš™ .ođÍllļÐÓQe-;}öƒ?Šu…,4T͛tRėÞūŦŸ·TXÉLÝŲ‹C―õŒ€`ōŨyl:{uû•Á+nŽh>?xuĀmĩ6wõ}ôÁÏfn:ŨÓßQiē—ũ^kŊrĪđŪí|oOK•äY[uëÐ{WkÜ&PLî2=øðp!ÜTįŊmô”ÛœR0“íTc+aļ/ŦĐÁWýVU>zsËĶÄâljsB @u%­˜°ÚúÖüģU\p{u ‘‚ŦŌ]Uį!Ā9rˆĪ›ÛŨæŪŒQ)$Bg°—·uī€$ đ@ˆÁWÛā;Ihn…W&Oc›—ä‘’ƒŲÛ\z@ ÎmžŠvoUŪVŠ\Ũ9*;æ"„8į+++•••Œ1Č)ōŲ7c,‘HÄb1mĖRĘÝQEĢŅüŦÆžũڍ1ß\‹CI…ÛNv ™Lfmm­ššgĩGBŠĒ˜L&mÂäp8 CņOŊ·ķķī0ĩÛíðĘģŲŽq$ŅjīîČ>qxýN€2-g777- . !WiNg8^^^–Rū2žŠjųXŊŨ[söŠZ­@ëHK[­Đ―jþ[PEËY‡Ã G BRĘüSĻÅĩ”R-Šī#)H‘ĸŸĢĢ6Ÿķ~a,„B7žA!ŒZ„Bĩ!„Q‹Bĩ!„0jBĢ!„[YYaŒ‘C€Bˆą\ĖNLLÄãqLÛÀœÕV‹Yōå—_~õÕW<ƒĄĸ„BZĻjŅŠŽģĸ;9HTgmIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-ready-for-installation.png0100777000000000000000000005360413761647206023002 0ustar00‰PNG  IHDRÎGæąmWKIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšžĶĄ0üëôE>ŒŊ~mmŨĩl™‚ œY$B‚X  : Pl8YeĨ[ŋX1þâ%ņGxĪæhÎ.ļð―8yrúžÏ9}ōžWĮ0LÓlÜUģŲŦešÕĨEmzōú㇟ĩęyŨÎfūdfŠŌ°,Ā4ØbYVĨRQUž‰ÝÞÞÞÜ܀ŊårŌ ÝÐōōâÛbēڒžëå{.w<ņ͐Ūk ÐųÃŅu°‚vØE öƒS þŠïŦāˆ@tÁe ĸÞđp°‰ļė€ģÓˆó.Î^0xæÓ™k5LËnÔŦ)§ÆŌó·åkĨÂč`x˜bY‘ÏÏLũøý|dęĩĒ[PÄvė͗OŧÃXl,#BdbŠXW3 öðq?ĮĮú{ĢkZËU§Đ‘úy!>Šæ‹šï;đT$)ø—šHËû§ūgŽdcŋu2ĩ°yļ-ĄNšð4ÕӉmŨNö–1ðŽ?.Õkōlbl}įüŌ1ĪgĢ8Eâ-Ė]4=eo=Ép;5ÛUø‘áĨ­’åØA Á'f,―wîĀ&fvOmïŽģž]ŠČyf”ˆ AM–UĮ6ÎgđÁ‚ßÚ/fäå“ãÔ`§ļīqR=ā(šlķJïĈ°ę~ŧRåMķŊ+Âr,ËlTLM~…‘Ųšú7ĀŨÕY§hgÂ―øJáäęĘýž6ŨŨ3ÄÅ9šTK/冚ŧY1óUwĨô“ÐÎ ąh8"æ=ßYMttôÅã<îZؐ=ÏnOf{~óÃęócšƒĖ <Ļöt^Ðų‚"č°ĸbÖz^Ģh‚hþÓ\ūÓwĘí‹QņŠˆđ|ˆHTPPbŒŲdĢÓŋ§{š{zOŠŽŊ§ÖbÝYcžYČP[õúÕë·ĩäā ČÏÍŋŊЍ?xnô‡Á[f ĨÐHĪ”P”B°oįžÞšyöāū~õ2ƒÓ€i­ ÉyJ įóųl6;??*`ŨcŒ“˜Â‡‹ŨïîýĸfũéŅíãŲ Œo=ÉXErNŅåž$€Qda”Ģļ†'Ŋ\YÅģŠóÄĐ?kzŒY•ąv ú Wo7õä8Ëü|/äSðü?Ōäœ|hGӆļ(I Ą­ėĻtÁ ­sJÉÎXšū$šAŅÆæ-ĐŽG`b;ĸlïž:-]—‡’BûĐVŽÎZ-O%­LŠá…ēąKđsķ ⭂Ð.ĄVb°ŌļZ4ōBęspRĀ}KiąŧmX@§ 釅wŠĘFQ6•ĄģüåÁ[_ ZõXßG,Åôī|5SÅūïŠWrÄŅA"áCÄĨĄB9KŠäcîšN+réSMSÕīÖĮ˜úޒ=ä6ąóZ6óųGWŅ.â% jŅķÁíS#Ô+āCέUÆw‹ÏCŒQđĸïöÎã“ÎÕvCųæýáÕÝļ?„Į]\ē?ž$ †w› |œņžØ”óïkm/0ãY*“\ōûBp‘åM_x^ŅÍTSäá؁+úģ…ŧ5X Š1GŨ—‚wðÚžÃbސĩ‹—u€ČA—sÆĸēáõą/ω-$| /ũ UĀ ð7€ŋ"'ĐKlLKƒ(óDâgŲĢ<ŽšŽ“9Y0ÄĖ`~r0ZEōqŪlôâ”„eð)–ĜԝúÃ#6úÃķc‚  rĨc—h%­Œ5ĸ؟FŨBŽ+%/îėíόąāĻʋŧŨũž―?ģÆ*ĩT}Ču *dŧ6Ļá_=…a@€Ó>ŠY äĮēĒŽI0)!Ixēoˆf9‚Ū@ JR,ĸŽ’–†r]ac 3Š0šļb#Óh(€RtØúŽ,čģzÄ ŽĘ(§–:GÖT€N jīāÉĩĸnV>Kē9þ#|2a•Ï?āyžÉá§iÂÄãņhƒ1)žqЧ˜@EoJŅ]ëŲåWSf#zĶaiũčœ2ÐR}YVWfcŪ->x,Åiņ‰ēĖĮščŽmņ1ĻųžJŽÅĮĮÉUەl<žæ#ĸ'Þĸø6=s8Ė·ŋøõvŋŸrU>!žĘ‡ âƒzDKødūÅáSŊðĐUōi›•e͋QÉïMÂĄü*M•ï™ŧ‡ŧûŸßMÆGESĐųėũ{+m\åƒo―?%„wņņØâ3aō™W~_ˆ->Ø2§eČßóáoäs1Žã0 ›aã‡#ūïú͓mų}ŨuC?l·ÛqûX·e7îHĄPF`Kē(Ž"PT!pÓL1[ļFßũÄņTڒɈS@##ž3nå.ï ^īĖ―zVāiôz>ÖâCV“-%ųÐH™7YáSÜ­ï >!>X›ïĻðņHĖ­8ŪōÉ(ųėÆ‘Æ››ŊãĶāÓoPVųØ>ÔûĨ3ö>Ý+|äcąĒ|°rrųþĪ“O č-ŋc1Z_ðŲÕïO–Ö|pĀžĮîKg‹ï›LZ|2°$F Ēô7ō!sø`Øi|ôöū…b.ãĮ‚ž?Ą]ōA‘Ę2ãšĮÓø †“1ü >ø‹ÏÏvõlŨŨŨø?: 3KŲ§'ËâēĖĢū>ÖõĨˆg~]ÉU—o•i]^^ķ––Á:ŽÍ§ĪWōQü>ÏÍw Ÿz”ŲšĘų`/ø`Æïâc>ˆËKĢīø\5ĸãÕĨ!ģōþ8ü||īäó›―ŧâZø~ÎČJ\ ! HHā  ļCq/NŅāšāâ.!ļqŨM6Ŧ#į|ģŧHî}Ûûķo/ýč―įũÐtäØĖîógØÍœ‘Í+ӄ’9?äü ĸ•A$j ‚ HÔAĻ%‚ þ|ÔA$j ‚ HÔAøŊAP4ŦT*d,þnh†U(•, 1€Ž\!Ą ˆŋ ß0HŅė'æG]PðO4•ĸþîĶ-Qgo―D O“ßÝ>ĪiþļŲdœüōVÔú Ņï åīņÎÉ};wLU AĻ%þ$âk;ĶÔĻäïįëëW%ĪE§=žs˜ĸ'fóß^˜>mÚūπLÁĸcžãŒžøŧ†ĘŌ™ÏÎvŦQcāš“þcˆM9ßĀĘá‡Û§ÏœqäY–‚å/Ž[5%båŦ\̌ĶŸG$j M^j|B–CđJ>Ni/Ūĸ~Ѝũ*ËĨ-ÍĘ­mí$J9  Ī…ŌĘžÍÖēŅ‚‘)ėL"ē’ąržãE™>I°ēRČeŸ*Ō ĨRÆPāŠ‘Ŧã.ÍŸžãhīÂÞÖžēR;&ķVJAI^§þŸšĨÆZ”Ëš•ŲJl”4üÜ2kmkkjÅڊĄ #Wj’Ÿ,ž9ųðã\[+9„@Šbemyx’ĩԀ)‹!`( 1 #"Ï3€ HÔĸ&‹ĀÞwÎæÃ7/ÛŊ ‰é…ÅBša’œž1žG=·ļg€,MÁâŽŨûÖ/ïũýũ=ú Ú|*ڈĨmĄņ‹kûzõė1zĘėĮ‰9PÃĻâîŽ[ūúā‰kZĖÐ Ëį%ïÝšîü“tKˆK­ ęÔm‹EíŲŋcÛōM?]Ó"ČBþŅĨ―{I=Xđý‚ЧiJĒ(Ļ0ĸ”ŠōwoYęæŧļ˜ģƒzö9qkRąČH=Ó ûÝ―…ÃöčÕsČĖe/Ԋ…âĖ―WŽ‹:°aËÖ]Į.Ѝ8þáåUÓ&öęÞcĀð—ž%ËgæO,B3@$j‰ äĩšü‚Ēü< äÖV,E3/ÏŽíÜgäķ ũŊßŧ>käðŲ›Ŋ°Vē„§g­Û›–‘uíü‘i? Øwų9kŦŒ―5|Āøc'Ξ8°cޚŸ@@š*ZģdæļkŸfčllā‹‹?͘YHQŸ.rYA•pũ]šīœõáŲ–Cũ9Ī9ģyNÏßžõü͝đáC{ũ]o ~õ_Š’‰…ņ[ŨÎÞ§M‡>:ĩqÎŌ§­UæÓ+cÚũ^tč\rrâ­ýŧ^Īæ ’bÅ`ŌnÞxð\ŪJuzęŒMo$<>s`ÕāaÓbâÕ,CƒŊˆ HÔŒ %m™;đcũŽ›N§Ôûay‹ƘēzUTBĄbōú ņŨv:iSn^ܟ”ü ―}ãøŅŧ—šŽũéBaöŲsĮc Ų‰;/ÅĮ―ˆT#ŅÁŦþˆ0}ÜĢGOãī9ɧNėWīúąE7câõJïÐEÓú@‡v˜õāØLpoĮ†­ytݟ.>{zã|Į ÛûŨķ­<ýFŪ`ÁŊbD^ŒN=Įnŧ|d>ŠcãŊé@ZÚŦŦŲLÝnŦĢŽQ?G_―rbÏÅ――ŠÞ?‰OĖA ĩÄWƒ1 eÎel5/3tŅĄ›œÓŠ38 Ēý‹Fī83ƒĪÜâl —ņþÞä҃Úķë0sõ1ÅP:u^fŌ{Šķ­ĄMPp}Œ1Åڇõ^ĻwŸ―yåĘņ·ĀôáK))Œ?w‹ZMÓJ†ÅÚ|Uz&ðéÐ:ØËŽrðîŅĀˆųęGu4KýÆĩļ€eåێ›3­ĩW9/Đ Ą€a@fkWäoFõėŌąïÏ3 4ÅP€@Ș–ôęþá}ŧ·ëØuýéw@ÚAĻ%ū2QÖn}ÆÏ‰Œ$Cąák7Ä,K "Ž]óÞãDŪš,=X+ji%6iÁ€Ņ'ï&vđ`\ŸŌ@KC‰FLĸ)tVVž)!]ąF“uRN­6nYЍÃjųbAøĮĨÍ((RĶÄËĘRq‘1/Hŧ ÚŌcð Īm”ÏóŸšE‚hëUkÃáSÖÍŦ Nŧ|xCĸ5ĮÔžĐ(B XÃ+•ÖųŊÏ ņ2—žđtuĸVĀ4ËB@$j‰Ŋ  `ĢĀ6ë7rD Ũė kæŊÝÍŲ” ö-tųOžūAJkšŨ$fd늋ēÔĨ˖.įDĮÆūÎ áiĒ;”ņāᩕũíX1dÁ>LŠDdïáÓĻųw,WT •7ï2ÔËNچK%žô'%áþ/7žČÝžýŦØk.Ÿ=tėÞģ›göŸŽŽ}ĩķĩeũđFĶĶKžˆÁ4ĐoĢOßz])īÓļYCŽ0&gFX0ęÁ―‡Ï?{›™øFeÄeKۀžøļxĐH|Bž†Cüåzü;‰Z‰Ā<Â<ë8<<ŌӉ>ūlZäéŽ%Ŧ7Né{paŦ°­Ût5kEąŽ|ë~mrßDčüݍtėgyûœË)Ļįð)5]íŊėX0xúķĶ- €Āž†Üū.=ãûnJzú›§wĨ§}ÆĨįĻ UïŸÜ—žÝyûÁģŽĖä1^ĮĶĻTZ―úæÆIŽ€þaãÍââÂüĸAUĻJ‰{uýęåk7ĶåäŦՅIïž\―rņ—‹—ï―x—WĪ),(Qš  '=ųELĖóũ‰yŠžŽī§>}—$mÏÍLy m›[ ĘJIx|ïÎ%éĐŧŊ>~ņVUX$ĩĄRВß>đréōĩŧ2óT)ïž]ŋ|ņÆ―Ũ)IŪ^ūx5&#//#!îaLĖŧäL•*/þųӏžĪfåŠĪĘAéfˆ) >ŪŠĖ#ÅĨīV(1ýT™ãNeYW™˜–,ĨE3•TĀR]Úũāx# +Ó-&IĘŽ_-•đw‰īŧD;ŌÆ_Kđ‚‚Â"Ëórá—eˠ͋ŸÆlnļ DGGhYķŽ|Z*øt°–qJ[-į„ HÔß4)ģÞūļ―nÃæ“·ŸååŦō ‚ QK| …EÅFĢQ§Qįņ D-AAĒ– ‚D-AÁâ›dž œÆņM˜'ōäÁņF-ÉŲĒĒĒ·oãhš‚ ūX‘ŋŋŸĩ ïĻ%(ŠĘÏW98Ø{xļ#„AßšĶ“’’U*•ÍÂU-!”ĒķT)gQAß–eΜĩ\ý‡D-?A|Â2Ý A™Ų‹ ‚D-AAĒ– ‚D-Aņ{Ģ– ‚ QKAĒ– ‚ QKAĒ– ‚D-AAĒ–€R&þÛÛßĶÓÁBS;þŽ|3ũņĩ þ[…’ßXûk@JĸoC ‰Zâ!E#C^FJrJŠFÏĸzšœČīF|ƒĸîɃÔ|#ýÛ9IŅĶĸ ųcņðÅ-oÐxņ-c”ĘüýŦ…4…â^>z“ĶBÆÂĮ1OōŠy€E―ހ0øý04j€-‰) ­jE þ2MeĮ>‰M F―Þ(üžhĶ)Ę2zĢtE ‰Úĸĸˆ9ՆÅZĩkßĩCóÁËÏóOŨ<§SЊ1ÅČâ/o5û<’1|K Ä\Þú1ƒÝHaeėŊH][dáŋj†2äŋY4iZŠžfoÖB†Eį–Œ_vþ―œĨþE™ģ‹Į/ŋ'•ųßč óō‹ ĸs+ÃG—Í:xå%Ô―š;yõóDA{ujÄĶ5d~įh!†Ü­3Fl>ĸČäŽBþäÔĶņ‘{ ÅŋėR2Žėõ–E“ÜĪäōĮQófėļŒ þ%ƒV]PŽ3Ū ÚģtÞár9KĒöĸ3RŒ:þڒŸâ§íđtáÜÉaUą€ E1Ž ÃÐŽL–sųÔ荧ĩīœ‚€Ēš‚æŠ4KS˜ķ˜Ie%/~ą(– íÓĒ*ESa+Ą)ęŸŪČ>Õe?6 -]›PԊÔ:KėŽe?vĖ”Ėn(•š°ėĩ“˜FōyU&chúcaÚ|LŽÜķ …M-S–~ĐßÏÍRrđfÝėĐ7“u2ÆÔŽT‹5‘ÚĄþéʆĄX9Z&U‡Š•|>"ŠbLϘQQÕš6ŊZVąųÔŅæĘĖ…-°ˆĻ –]›üzŠþ|2iđœúiÍüýŨ_3r„aX3ÆŌģ’dž@KÛ۔õëô]g%útÚ?ĪMŦĶšæęÐrU(·soPÓuӄUS81?zÁüÃþ ŧ(ięsO4õņUĢih ĮOoÆLƖ vh9“R?…1cM][€%ÞN–Wråm(ċÞõÛī ņ‡CŠ’jXš‡XÞ­–cĄhöõŲ%Ó#™Œb­CZķŊíå ðĒåEų\åãۆf,í@HĒ–øÚ ĀĒŅŠl)čVūz—Ð cúóy̚††6ÜqÍ É9qnŨ‰uŦFwp+IũxĸĒWÞą2yĘ―=“·^ĢålĖÞČÅևîTŊfëݗ^R4ý9† Ó?ÜÏÍĪi6ņÞÉ~M›5 mēå\  YË~đ?=đgÅĘUóG5ŪÚm_t*#“kó>DŽîØ$īIŨþ#ÞĐtOÏėŸtH”Ë3˜:vLŠŽē^n_·"N… Z.É^ūdÝâ^]ú―+ģ_]îÚĶE“ï:ïđ) ’yq~}ķM5ĻŋxßU‘aČ_ÛŧĪUĢFÝÆM>öČÁ‡åF”Į24Wð|éøéŠKA™ŒšĩsÅîýG§þ0fÃĄCÝ=ķŠCX“F n8-Ō4üĩ4ÔŦ,Ö ~Û ›rīPÎRIwôęÐĪQĢ^'bR–Õ~ˆžÚ§V“Ё3ÃįĖYüģfr“_%įÓ ū5ÝÎÝ#vĻ[ŧýņčŒÏĐ!ĘJz•’§6—™g*3ĀTæÄýL)đÞ];ÜŦqhh“ÆûoŋÉxuyŨķ}Ë#g ›ðsAÎëČąíCCũøaVlūJ3ŒĨFÚœũ ņ„IũÎ,‹\đrV§ú!-–|†ĪœÆ†3k†5iÐļWÏð Ý}ŸgyÄ4î6КÓģ]GÎ?°—oÐaHû`FÔ^ÞÖĪqĢVíķ_z đęÝÍU›ũgdīúýė۞gņ°(~ÉęĩëVD4čþÃíŤĨLđ Z6Uzqëvýáä‹<đ[đxÉ……Ôj=ðČ― ™BþúĚEŦWϝÜŦ~­ÐĨŪc`:„ESЌwŌē(†ÉýpÆðfš4i8tų‡ýƒKÚī iØxý‰Į øÅܕ{n]ÐaؒĪ<í‡ä7IF=CƒÄ[GŧKoŒÆM&n8ĢeH“z`ŲôíQŦŋkŌūgxRbiHĒö+"0|š Ļd3ĶgˉKw%æōrĶxÉБOÜÆÜđāæ–9’ÄÚÕë…69gZ`9ëäįWo$įŅ,JpĸN éŽWį—í>iÓrâŒþ>ë§―’lY"ƒĒÕi·Ū]N’Q†ÝÓ#žŨvčĀžïjú"Qøüð”—[Öïth3o\Cû=‡Ïó†œ-ÓnÁĶŧöílę­ë7aģHÞ<Üũ!ŨøčRÔŠÍ^ĶæÄ=šuųBžĢĢcËۑrjËú_â;Ÿæœû ||dÃ˖õĐŧoĘô§Yœ[Õ Ŧ~Z7ĢËņMóSôLö“#×\ŋn{x—š˜á(ŧr.0nÅ΃˜aŸŒ:”(ss‹ ŠÜĪ}―Ęå{ Ô)ŽbĘ―ĻūģÏZžcÓĒ‘;M>t;]&g€#crR–­ĸÜ%sŲģ›6î―ŦÉ2fčĘFSĢVOŽđ2|VĶ>wŅĀ‘oāŧĶØÄEŸýåĄH1ņ1gn$RúâäžĨ{ŧLĒ^―āρa)`BQ0îþ™‰ER™”įĶ2ÕšNØ@―jÁq‘Vo›™ØzÂŅ―;›ø•sôŽÚ šŦV&ŽibƒþĮm…ąG\}ðOģøCŠ6æÆŸ~P 2\AâŪ ›3Ëũ›ŲŦö™Ÿ%ëðË_6Ï^Ÿ6rÉķI==Ų<>Wkųø‰<(å7kBûÓÓOYü|čĢĘ(Å''7„/ŽąpĮ†Đm6 }$:C,J―ōėYĄHA.+æÆC•Ņ@{ïÚ'4 Â'𰂀HÜjw?zōpöíîĢŨ!ĪŌž\ĸéį‹ #WŦĻÕgF ‹“î­ŲĨ9>ô؂!?ĮÉhh9'Y/._xÆSĮĸ‹ĄųúmÛWkåLqÖåj/Û)ý}Ũ`ĸúųY Ÿn5ž|;͛ÐÛÝĘðúޅøƒ&éęˆnģęöZž{ëŒô―ó–ížXņΉõŦÏež5Ų9õÜáģo +#Qû5ĨĮÔÓ­hLĸ‘ã?dæÜVį§_Úöãä%ņĐy…zÖĩĒk؊Uýý]Ž (;$4eMÓriCŠ6#ĖïÚôŧCˉðQ|EÃߧҐ5ï۞>žtôümé:\ōōĄ˜ãڍš;ĐSX­š•ėPn⋧/ēF éWÉŧōāþ}dŠÞ•=˜ŧWï<{–Ûë;ĸwŅŨn<đ†õwW csČĐĘÐðˆÞÍŠi’ĨïšÞžØąõ؋Ôė|ĩÞOEL]*šGÐÓK?—kÔŋmmĸÚM{t ’Š­;MFÝ;ō8ņuÔŅ›]Æõw€<Â!Xķby7G{ߊåĘØ=<}ÔŧŅ ŪuýŠ7ėüC2ïžâ  /pÖ~ÕĮOøąa“Öƒ&Ö}–“˜ĸ@yzÉÔ›OĐuÆÂÔØhčôãÂū•+ ™?ØĘ QĶÔ lMõ1l;†/ŨđypP dЗïËéÏe ]§iËÆšĘT…t-°iÝ·aGÄøu§ē@iįęáâčUĄ’Ŋ‡Ģsú‰Óf-JRņ<Īšāam)Š Ø ŦŨ}øÜzÔ­XÆYDœáE\\ð Þ]CęuïQ·Ÿh0|ŪÄųāáÝZz ÔĩŠtÏÞ'Øąi•ā–}kÔŌ!酠āÖžiAÔëy9ZŅā ,ý1h88üĖé-uŒ/ĖÛUČ}ySKŧä2ČI͉‹€ÜÚÁŠe ōÔ―Ķ@°›_ĢŠ^›ô"Ķĩ=ĩpýų‚ūÝj!ĸ܁œĄliJZĪhĘŪīkÏc#6FÝļ}ĻĶ2nüČųEõ{ŽėÛރĶšR*i}z‘Ô§ÎÉÉG ö•›ĩŪ&›ÐŦGŒKģu=9}lVtžĨ ÚŅĨŒ.-ÓhŽ|ĩŠVĘ!øBDóešP˜Å9ŲyX1ØNYŠŨČð…K7;šą‚uyïãsõÚüû7ĒAöyØCGkđ)ēy#ē͖(ƒ ĢâSVDlؘ9§OŽqytx@ä!`=Į# ĨvĖ ßøA1bĖØšå\ä˜⒍•øŸ(•—A$ĩ) 4Ī NKNÍÓrÞ>OMÎgy‰ŠÉkz9TŽV™A"€Pôđ9ŲĶ0F­Z/cdRP” Ļrâ øJF đ4nA-2röåЙáócšÓ9ĻfMá)`ä8Ó˝—ˉÞed`[ŨKu8―–­YŒK(íXkMJ~„4Āļ0þ֏“VWčöÃāŪ-]EӀã4F1ËÔ:41,%r…Đ…Ķ‹U. `%Í*)(•† _‰Z‚bdĐũM ŸģegÔÚMýkT üĄqÓ§{Ü~ō*úæ™ØlģWđϏŽßq8]lmK_ú)jQȅûžˆĀʄKËWŽ\·mþīÉļFXŧęey^fHZ=bĄæÄ†Ígŋ7Œģ•uÉßtDF=gäL žQĢÓY•ĐÖ>xᯅ[wn™đËĄKŨŠ.Ĩ‚VɊÏŪÚŧIÅŠõ˜ŒtëŌ―š–—óéĩÅzÎÔĢW­°ï;ŧž:qėéģ§—ŊÜN/€hHNxwĸöĢUŌč—åw[ĶĖŽœ·pÂą7y%čÜš[Û§Úvčâa#ûØ(Ä+œd;7Ŋð:%ĻÝkíÉŲK7­Y<ë@BĐfmk0ˆĸ˜ƒæÆŋZūfõö5‹wœKmÝŠIEĸF}ÝOí?õėÕó›·ÎŦŠ ĐūoęøÉ“,Ýy•GČpz­Þ|Š8―FĢ7ū kyÁgܗ2Ú/etˆÂyGVoūø2a™ģ•ŠŽŦÓŲ#{O]‹A •—öðat|aÞýÛS‹ XŊ Ó‹ÂXäuzóFNoÄH[īzƒĘ5î(ŧrÂČŅ“gLy›ĶĒYJÂĒĶXmÐqĘ5j§šu|Β­ŦįÎNÓToWŦšĩCÂÓû–ÍŸļpÝËt@3ĻSsĀķ0736æŅõÍŲKîĶ•’3kÖŽ\―5jęī Ū!ÝKŅī5}ûĶË·DLŸäR­G=/VĢ3ĸĘ `ÔIo;ÏÚ­;øÎ˜6qéšĩ‘Žg!Äk>ÄūxóôCއčGqîĩ ‰įķlŧQP$ð2p‚W@X=:oæŽå;Ö.Ü6ĢK“–6īQŦ՘ĸfŜŨqƒoū1Ã0*U!Ë2ô™q ē3ōē nÕ&M Ŋä ũ kT‰ON’ÂHäéåWĄēŅ ŊāXŦĶ“PĀ;úŽ5ĪQ`ÕJ^NŊ/îKŦÜī–―ÜkMš:Öۆ-ýcްsũņ­äãáÄådžON—WŠ3edO7[Ö2Bé‡Ģ‹Ŋ_Yg;ÖÚŅŧbårîîՃCœĻâīô‚ŠõÚFŒėd °ĩ“§ppĮĶĩmėœ}ŦĩéÝē‚―áÏĢgKđWôũó-mEđC͆­†ÜĖ<5m[šzݐÆõ}QAŽGðwݛVevA ū ôÎÉÎ+ß°įŪ-jT ,ëĻÓ>\ĖŽ QÁ‘FÛÅZU @EųveĘÔĻßžv•äï8ÆuLøä°ĘÎ1ĀYÁ:”­äčåâ tt­äāQĶl“&ĄÁķ(KUlUķBúõÔ._˜•ëŨļK‡z>Hé\§q@ŧĖl…_u_Ï •*ûxđļ{7kUېŸgīþnØôîÍ*DđxVŠTÉĮVÎ8đV ôwuRbŒŋŌÍ2Ō‚――("ðûå{FóüųËũïã8ŽÓĸAF^ğˆžđšÁˆðG‚Ņ ­b3NZälLÅ,ėéŅŠýö菅9ã?ķŒĪmŌ‚øĨý( õŒDÞ\Ōīd0w?áĪŪ%FNZæMËsĸt€dÚføļb䱅đŠ€ðĒ _,đįxƒzwxËÁsÖĐD,õP'X*™šJĀ?vΕlÏŌ€åYHûóČÁ]'G.TŋŠûŌÃŊÞhÚmiöÓg(*Ņŋe—ąÄ‚ĨŒh9^ ĐĐ/ŸČ•|i,‡oŋé”"Îh’ępŸÎķe‹€„ŒÛŋôíÜwöšuCÃüŋē01·œüÏLåJžvŸO,>ūap œŅÔīđSÃoŸ.‰nÆũ­#ÝÃfR—"ÆįGũl4įúøŠņĶMÝ|\so\‰ūŒ"úrØH>íEFó.Ë[Žûō Ÿßfæ=Ņr_ ÏóoÞÄū~ýĶļXĸG@é?ð!äry||ĒRĐðööEüU ÓßžPY— ôrDƒŋÄĮ―|Ūtóó.k'ˆčkÜTš—ð2úyŽJƒ+ŨhX·Š;@|c E šĒ'1wÞĨX9z5kâlE‰_ýՄ4%&žŽĨJ{–+m0ķüĘpvÜŦ äXÍĮüó/ÎļļcOOŽãĸ@E@Ÿ`„=Š—ÃHDüQŽop=€EAD_įü RŠuŪTB€Dá+õōįI+ėę5ïBAi…„ŋäÕÄ"ĒĘW­BøcwH]|Š–5íB€|*Ē$ŠßėÜDýoãūr‰<Á·‹/~oüiAŋ‚€œAS Ö}+ŋ.I$j ó&,Ã@h™æCZd,›J†EKÛŋÜ5OSðŨę2īþļDģŽåÖwËv Ët暎ióįUS%øev–•Ëe4M›öĘå M}†đļ\fŲ͝Y†•ķ1ē”[ĶĖÚŠ—Š@Ó^™M}.l‘ĨĘWG$j Іy/یýūch“†Ã–ėÍ(ĶĄ>qýĪ™[·/čØĒA›IÛRĩ€ķdĻ _Ý1uŅþÛCSH{hýŽĻŦ)đoŊŽí!ÝŨÞh’íy#2Mßð:ÛČĘé{{Ķmđ'—ë͛ģbþôū ÝzQĖĘĖYIŅUüš CB7éÔoČëbæžY4͟ÔP§ą ^dp29uoäšĻís~ė^·vÏóũî,Ÿ6Ž~í į^°ræþޅK7m Õą^ÍvûŊĮ22ų‡›ŧ÷߄rYqÜÕÉý–Äe%/ZģũÐÎe회y“cĖ~|ôûNŌž=ŽßOfXYÂíýģŨFÚŦëōÓĶ øŠ‚D-M3­Œk?Jë1pũŪåēëGMØĮ˄›û6íŋĐ3cšÍ­íûį°2Úüõ‰Âĩ4―sÍĶWZF—pmËŪį] žI7 ßĩ6ëÎö1Ë.‹bņÕ7rõ<ĐÔįũïĶ@ˆß\;yäÆëŪcŦU” Ū`ÝøþQoáŠM;LčŪ,ˆė;āfz­­ŧw„Ņ1ƒŋ_”ÉģŲ/ÏÎ]ŧŸi8žõŒþÆåŲķžÐÓcÛōŸō “ųüėŌ]'­Ã&LíåķjŌÐëĐž1;&únŠÔĐĄ8íÔëģđTĐÎ5ĪV[Ι9ķŒá鈋ëþļmõ”:+§†§ō”1ãųšyŦœü{GôiĖBŒÁŨD$j )uęÛXï:St­āSŋũðķIYŋäaĨOÕY‹VķjčË~þ> ž_óĄ5/ė~viû—6#}ŠîgÉjŒëÝē|åZģú‡%žŋ–‹Y–ĩ5ÏGåĖĮë ëĄ 7tkVÃÞZ†6å{҇K·õmFĖ ĐVĐjĩj.\ÆeCĐņËúyWî3j”žŋüŪ@DĀŠíļE zķŪß,8°Ý„%sz„6íM3z[ĩ1ŋ[ģķƒ~p7ĒG …2Đ/Jöqfhbhã\ÝÆŅ―ZM_ą0þnaæ/+Ķ/ÜtŠH­-Öčƒ:ŽŸ=Ĩs•ēöðŦ?+‚ HÔP âīŽB$­i ģRАķē F'",Ÿ!ÖÖspÐSŦûÍ9Ÿßw`Ļ­ĩPЋõ‚T̰0WË8ãs•V†Ü—Ï‹(Á”b āQĘaŠV(X>'/ËÔ‚Ž1+=WGQÐPœ)pތ6% ĢĐ= ˆĀēŌ'ˆĶ`4Ũąi‹hÐq9XÓĒ("„ĪB9™9Ō’Đ0ŊįÄ,а―ÂĐû°Is"Wĸüó– ֘GĢpĪ€ Œ―FŦA|-AĒ–ĀHpŽŌķ,=wÚĖ=;VŪÛÓšéĀR ÎPŽ1Ï‚:AĀā2õ[öŽjˆËŊÝķĄ·­cåÆõræĖ[ĩ}åŽÝoj íė"ÍŠT mYģbÁļI??{eū`ĂVÃóĻdŊŽc•‘cë>Ø<~ÁÚM+W­ž•é8Žaĩ-‘sķėÚ1sáöāZƒŠ•ĶuڏSˆž Õq–{ö5ZSC,˟_š|ÍÆí f†ÓĩZķ t’[ŧŦnl]°xŲĻyŧrUjŒ‘{å`˜seûúÓFĮ^.į~:ûú]ė―čŦųFÖĻXjGÆ$ÞÚÖoøĖx5ÅR|AĒ–ĀX{Î?ļc\ˆsZŽÐcÎŪųáMiĘuÜÂųŽP€ķ]ÆFt °įŋLyí\ė=ĘMlæ,…ûŠõÛÛøÛgdsĢmÜÜ;ˆÃŽK—Ūn]Ĩtđ–=:õóāÆ^<Ï{7:gtĖóöåC"fēĮHl@ĮƒĘđfĸ ëfšŅžWčˆeģŧąĀvųÆ=Qk–øÚ ÎÕ:ŪY8ÓJ]`yÎ:ŋ·W‹Ō™)é˜ķRŌBųæŒĻx$ˆbĐĘaÃúũvQZfeüVđ1ũ?ðÆ\Šae Lgä r–7D å 9ŒÆOķ,C?úeí°wö:ā‚x›ŸecЋĢTŽ‘)ĘžyĪFÏņ"%AS/ĀLä<Ē>ŊōœA*Ë*īĐšHģr–F-KXØÝ―͙v‹N ŽeŠki™Ē2|b<”YĶD˜‘Ëh`Æ @ZcL Zæ6“1g4 â›ļ1—D-™‚8'16EcU#Ļ"eþˆáŊGQ0åÕģ"[ŊÏ/™ø‚0,]!° ÄâįœýË!„=ƒĄeâ‚øÏ@Ē–øïRĸãC ōĩAAĒ– ‚D-A‰Z‚ ‚|-F@3ðß›‚ QKüeēēē233ÕjõŊĶÏß7’ „ĸóX†ą··ũððprr"iKĻ%þĒ0ĘÎÎNJJ*_ū|pp0EQā?Ņh”þ^yĸþ}ÕŠUmllūzÚ‰Z‚Ķ锔)g===ĸ{îÞņņņŅét999Ōå­ āk#ōĩĄVŦÁĸÆĻ+’>g(Pk MΓĮo ‚Č›ūŊÕhõƒ?#ŽãD ļâžįOžýÁ6Īīý‹Ū⠂\Õ!áŋøwīī7ũÉĐÉSV,AĻýK‘8Žû­ôÁFcĨ°ąg…Þ―đߞĢVïĨb+ķZĩnn-wÃu—ēĒ!ũõ;ŲÞ=Ú7rķ­Þ/dݑ›™ģëųM‹đu‘ķӖę„âÞ\;Ōótkųð:‡/"„DĐ_(ýAš|„Ý(ÝÃôxU\ÎÂiï_ūŊ[ŊXîäíåëãQÁŨËՖ+ÖĐŪîX–•’ĄŊĪ7Œ<”Č Íc„ŒzƒmŰ*Š ģÂãū9Ūģ—Ņø›iŠĖAĻý‹‘ŦÚßüA‚ąN§sņŦū<ˆËĻ{ôÐÝÂĻtQÁ`4Īš#šķÃzAPÔįd耏ĩ_íÅ+ŽŧJu]šĨ`눉wjŽR4#„!†4ES(öÆþg`hĮw ^՚öïf-gÝ*ø ú$#—§õ đxcˆԑ3<8ļA-BŒÆĶū-—Ļ<ĮÉ]ýgmŲsųČôyÓ Ž;‡yk8ņ·ūûĶĒ– HÔ”Œ)>ļr{ķmi7áúŦÆcüYņĶČĀ‹BlÔjtzYõÖ-žŽÏZšÞĐŠ2ëd=ĄqekOš†2ã„ÎŧycĸŽĘĨw_ũ[Ņڊįī@ņËĮ§7­§uoÞžß~ââš~^Πڝ ĸ)šZųōv†ÚÖ#ÐĩBy§‹§ũU/eGTP˜ũæM\jZšæVrÓķœQäEŒ‘ Ũé sbï>õnj+mGģ2F øÛ ĩd**ųzfžMøP@õ›ĩĒmó@ŠÐvæïŌրßOžiįmkëÞlõĶ•ĮÎFgė#ÖîĻ_ĩ”᱑+š*xģÆ2="wULl\ģīžG–Ž`}?Uޜ`ÔiŽË֜ķ6<Ί‡Ļį*w°ÕÍņÜ­„ #í)gEÖĄĮˆyô™ŧi)úŪ݇ÍÂĮēĩLĸIKâ_=/fÜū2Ķ”·\ÁT0âG/[Ļ\\ŽÅ”į>xßË™" øVDm&ģĐ[M6ÓĖ2ÍĶ™|d™ïóeĐ9N5Údĩ +Ó, L3Ņø@SÁ―ũ<öÞŋđPÍÉkÍŽÁ؟uŨš,Öfßßþįˏ}ÎŲhEå# ’$ýœ ‚Á‘ @­Ĩ`QˆB€ĩ’Ô†B°Ņ­R-ø&ÖjX^ËŪŧļ) 5°ŦĪF)6âÕĢV’$!DyyųÕŦW5MƒVÏjĩFDDÄÅÅĐŠÚdÎÖhXRé9ZV[åFlŧĻŒ Q{ķw$…[­„ķĩ’$û؊ŠŠŠŠŠīīīððphõžĨ•••uėØņm8Ð8\Š1^ĻQĩO'g`€―5lgTŨđϖ_óVåo ós‹B°­E­$ÉĻõķīééé·DÎz…††ĶĪĪäįį'%%ý ?$<Ķ(Ŋ1Ŧ="ŦGdß›ÚüÁ†~2B(Ĩ ļŠ4ūcÓÃjõ@D8Vz­ēŽĮ…ĻVeÔķ1’ävŧàeFé™sĩ.ÃjwÆķöģ€oÜðÔÖÖ3$!Ž[ËĄQQxā$FgĨ%h™ÓéÔuoüSœqÐL$ŠęýT‡ŸB)4 ™ŦÞe Q)üdۊĢJčĖ”Š#§Õļ!)ņā gpĮ*omÛäe1I’„ØĻ™ÎWŦ)]·xþßō á•g]w=5'{Ęo|ü !üÐÎuģÖĸ+"DwÛ;=3cfFr,4;ņÆÜŲþĢ>MMToō"^‹7!p!šÞ%ÄļvfåüåƒĶ­ŌÞÖÜT„0O]•‹‡‡…ÐjļvlÃSóĒ RŽ­Ï™ųp~Ęo›\#A .I’‚sî#ģˆÅĒoŸ=vÞ[úëïîšzūč‹+<MÎ)@ÆĄTĄĪ1ēŠ*ėôÉCõŅ]쟸åúYã—žÜ%õų‰þ ‘xRžņ @Î9ąZ-ĪíĀĐ€Dp.šŋ̀RŠˆ-Ŋˆ5xã8B)Ó\—ÎUå߯ `CíßOKÁ†Q-–ĘÛ&­(YúĘŠ i˜UB‰‚$Pm H,íh#\ ÞDĩXÃŌČĻ•$ĩ>ËZņōá•ûÎOČ}ãÎô8ÓdÓ3oCΘĻûúÂڜ§óūļj yęųu#zÄ#gBŽ@ÛÅÅöï;ôdŸÔũ-aļ^Z8uËGE‚ÅL^ļxːDwõŲ,øgA‰-88ûÕ<"@ŠbÍæđÓ w.œôk rŸĪŠ-_õGÁ#ĖGÔ ĄÚEý…đÏ―fŊzwŨņðˉŒ Š/ZøÜ_ũ}U<ā‰wr†-Yýę;o—Ü}}åŠeøå–™ëßÍ>jâüi â\  @0ä*gŒųŠZ."ČĻmë$Й B„Đy„ÍÞ'-ÁÔ4SÆ9%DÏöÕsÞŪėūå'Jv.Ÿ<);bóēÞņ6.PĄX­Įöîž4îĀūÎ,ÚŧÁŧŌēžïéyÏ^ģxŨ衏l›ûįÕĮœĸØē5’ļ‚éW-vWÞÚY/åY–―9Ė‚\lĶڛY‘ðjēŦØ@ āZõūí[§/^ē`äÂ9kóËÆt>ý֖ýWōÞßĒ{uŒØõ―įĒÅóŌbíĨUýķíœxņþīhËC D@!þ3›ā}݈4ŒjŽÛtÔJ’d†ÏĻUPh&gĻđ5Óī G?ÜúáyûļŅ―?ĸŽčþ‰sŧÆF$ŽÕyåŒ/O^ėĀ™ œ†ėëÚ°aTm{}gÚã#.žÍ_īr“ëōURQï*ßûŅĨ~ģtŒŽÓ„E"€\—―ú/}íÓ~‰–z—Öō/†æ É˜ŪĢ Mwĩ†nÞ*ëX―3ĨũôŋŒKúæPR{bxī˜Û33âw?öû?Ü;vʄvíĒ;w 1ãcmÝõÍđã_†šÓ:ZjęđqÁđŪÞwŅðqšŊŪÖ[ įž­?˜+IŌwMYӘf%暭ŧGd?hÓۜ;YDؘŽPGÐåŌKŒ$ŧŠŊ\ãh·ĐBpŅØÕzģŽ}ÏÞ㗏§îZĸafBؚ—w-Y―ņÂæš§ĐĒÚAäčđnŅ„éŅÁtąäĄ#ĢŦöūšieÚžéŅv4ßÛÐÍvĩB|ŧd&Ļ0™ŪézCræÕcųKێíÝë™Đ 6ū™yGF‡`TŸĸ(ï•Ï ÎVÏ?X cgqíɝōlnnnÎû…W‰îa‘}gįn(Ü4yÆģnTüĄÐ=n&€ÆÜD‚(4[­<đgފM_–TøGķwZ!<)- ŽŊ_ķáx‰+ŊÞũ֞=GëÏíÞU„ŠÅ­1 ĀtĮ`Ð2ŲÕJRÛFČYōˆĐÛ;ü⃏VãIýÕÃĐē,ĖxũãK‚;;u1æŪ sFó“!` eð―şōč,uęŌĖĄ™ÁÔ―<ĮQtQąvýðÂ36æîvįĪMĄiGNĄ-ūSī_ÄĻi“ET`ŧŽK·žýéĄb‚@!ÄgĩÐ,lãsQˆgâØi9QÔӟɞĨę4$qÜīœČ(ÅĶwJIļė1×/™Ô'Š*|ĀŌeŦ?+Öüē–ŊXýɑĘ.3ē‡œ‘‘AųAĻ}íâ‡J=…įŦÞŲ3ÖnUþK§•üé'įÖPpķŪļžfðí‘―âlþV"äƒđ’ÔĶ bLLĖĐS§Eq:ÐęÕÔԜ8q"""âÆÁßBc–R;—]Ŧó8üýŽðĸFkëõ WŠb‚ŽŅAŠJQn ī=’ŒÚøøxÆØ‘#G<!ĪÉ1­įPZŦÕ•˜˜xcU`S ÎĄöLt)­-,―Ž@ĄPˆˆ VS‘AŠB Ę Ij›8įŒ1!Ä-ąãĄŠŠĒ(Í ..U›Ũ\Ėd­€ÝBcBÔč`‹ïĢÁeÔJRÛ@[Ä͜5Ãr[Í?žĄD!nÞŋÛŧc†ĄŠĒæÏŽ]ī‘z áNnþ xC\åx+Üö=H-€ĮÏ―ĮŲŋ^€ÔH-€Ô ĩZÖyžk­ãŽugķŠöÞj ðFgũÞUuDDfvũĖ\?ĀĖtwfFÄĪË ĩž&S"IENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-ready-to-uninstall.png0100777000000000000000000025311513761647206022145 0ustar00‰PNG  IHDRÎbðZŊrVIDATxėVŲSŨõĶ\åW—ĸû5ypÅå‡Č•H–”û'YÖ"ˆ} Z,•„äڜ @ēÄXČ Y[ąČĀ0Ž3ĖÚÓËtOOoĀ€PR)ûį’e§*IUÎĖ5'íūĄ3å’\•ïárúÜï,ýõ9#Ĩ šÝîÅÅÅĸĸ>ūüōKĘc:~D&Ŋūú Ŋ’ðņLžiÓŠ}†§ĐÅüŸ>Ošzė•·9éI^Ĩ>īV+Ĩø? >öx ú ýlë?­ðÛßßĸÜ /žðŌK/=ĸüó_/ãņãĮä$@ŋåę›oū!'z,@>9‹WôаdĢ“c'3™ÆĢGĻV­†ŲÆäOAžýaôüõąĪĩyīÔ]―>ī“–…œöú ß^üúĖü'ÓĮ&9ės"čĮNĀ3ŪüīūüōË/ūøbŠŪë<€ŸÞĨĨ%8ðļ°°ð°ü%čÓ d"Áœ™Ô"€H E1ܒpð Ģðīɀ­š^ÄV},·6úÐɑđŌ•ĨI{},dK„ð,ëþÕčcßUōú˜C,'•dī,īąúųA<™>(ÂęõA#MžY}Ŧԇt]O™ŸŸŸû>b †Ū‹Įx=<ÃĻŅh,&\Á €G°!x ÃE spjšFnÍĀ*pUy 0ūĮ(Š-‘[8‘fđ4ņ@Eôcoū%„†đŪ nÉԁÖcŅF&Ý$ð$ô™_\zļô`‘„šą°øžáõYÎ[ĸĐO &fqá?ęOþðOq<\ZˆÍÓú`ķÄŋē‹ä"æÁīÉëC"b&Î~, ŨŌÃ8āĸ &ÜŌ _Ē ‹†6ý ―°Zƒœšƒú €üäõAgōú  ËXRúĖ>>ÉïœŦŅÎ'Ð8ĸV­"EO"I<Ą‡<žķC‡jĩņČk?;öÆ/KЧĮqÝÝÝ---ÍÍÍ}ô‘Ûí&Đ0ûðúgꚎdxëĘŨÓj6:UîŠßĖÎéËĀ@<Ác~$@@Ó4:hX’Ģ–(Þ"aiĖþĘBĀĖŽHÆÝ\ŨNŸ8Yq9î;'=Š>›pœ{bČ1%ƒeŌi?<æŠĻ:Ý6ܐÐú€_b―.ŋ–ČFkū<9ó1]šŨÓŅÞqõV+ąđDóņņÄBqŠáĮ‡úûîÝûŽhTŠ‚ßúÅ!D™õÁĒ},m'ęęÁi§+†Á§įų˜ EâÃƒ}ýý}ũz@=5N1( 1õöĩËŨĶ5ƒš jPÉŠ&ķ@ũOŒđ|žNū#ÅīŸz#ĀÆýGf2ú €Œą6úÐã‡6­Oōû…}ŌZ<-ė‹Ēą’>`$ĐÆ@•'Ð'EQ”hŠŠ* \Ū23:―Nj<õpjDëh―ŧuӉoŒũõA”,˄Ųá ƒ­­­]]]`@^ŽãnßūÝÔÔ455ĐHN ÅmEuyĶũÔf•5ntð1ï(ßsðJFúū·†œƒšŠa'`@8ÍuøˆNBC" N4,NæA ôÓĀ–,ú˜ó˜3[rǁMâ[€ÓN…Ŧĸíš •Ž`æb^ (HûŋīšeÎÐT|rHĢęsáņO2vd$øš +ø#ø§ï}>!+āUĀ ōØüXgcVM #ĐøAÔG34ŅsbAjęŽÚ3 ŧSS3JõÏDf5ŲŅŨ;æg t­wJ·lČ.ĐÜ[QRyė”›U ý_õĒðvQyĘ1pĖĢúēx€ïÏC‚mĢ· ýucNmŦĖĐüðþ,IŪĮ—$œ8TÓw‡5 ßLߔšSšwoyqÍé6Ÿ úō‘æ  në 1đū|Ũ–Y3€@Ú#~—0ðÂ-į›čca^>ŧŊčw—ï€â˜%ŽåYJ|Ŋ•æ‡|}z~,||MzÆ ŽŪý~Yö‚ÄfĶũ gaé^ĖOïÞRûõĢŅ<)‘HD’$9°ÁõI]ý…W~úįÃÕĸhŋð·Ŧ—ĸÞqņë“ĩ·ÖžÖZ\,ð|$A#dĀ­[·ÚÚÚ†Á_}Qá?𝝝‚ `ÚD‰čđË ÛkŨܕ>āūč þĨýĒwxū5ŋyã‘ģ‚ĀG–!/=č''d‹Ž,Gl Ūˆ˜Ö\ü0ĄE Aƒūēī!% Ðdģ>X Ë!óØč#‹Ėé]k~ōJj۝Im~>äčÞžöÕ·ķôČz˜õ;##Ž1?+Ä_-ĖMÏDˆāŲ`ˆ ų§GãūŊęāųÓ[JęúG'N ģąQD8Æ% x‚!IކđÃō!ßī#‘īŌę†2øĮ3ëąåƄ°ļļĻîį­]_VÛ·\5;ŌŦÚ> @8Q[Uƒ=åđƒA=6kϚō|^–c§'œ.o8•yÏŲęwóŦN8= |‰8G†ÆĶf(‘X&ĀrĄéЉ)_ˆ Á Û9::1ÍIĀ°0tMø<ïũøØp\+‘s;GFFž °d5ņLŽ ;ÆA‚Ąˆ,7æïïĘÞstˆŅįg ØeÆï p",|>6āe1äsƒ–ÎI7/Ęss‘Óû k[oČŠâũúYpEĢBČ qð‘ļ Ũ§ŽŲ°ĶŠÝ—ęō5ôųÃR„ņĖY.UdI˜žqú2" ū@ˆįŲqįč$|#)b??ô:9ÉÏú Ÿū5—3oî—%-=ÃčĄũ‹ŽMbŋ?}Âáp īȇ$ĩgėt―þęĢ][ŋ-/øëþōo+‹g§E7žÞķ~­ßå%‰ðIHGGGooŊĮãa†ãļP(äõz‡‡‡/]šäũûIJAâ!aqßđU=[Ū„ôHõ·•ģ7ä†ö―ÚÁ] [ž>03 ÁÞā‘įyô`·4ŊĖðæØDXrĖQæsQâÁŪð{cB@[:›đ1LKNÚ°ŅG`}gōß^ŧnCa}ŧĪÉŨ›ßߖúæöĖý3rôîÅúžĒ’‚ŽīÂšĶ Ļ…F>É)=>ÅEœŨ/Vė)LÛūđ°š)āwŸ;õóu[K*~ędzÛNBT~<ęQ]MĨĮσáėn).*"QÕįü|\%)"k’·éx^ÖÉkēĒ‚GQԁ+GķæVßėjŲī~ã;;ēÚnņáļ0†ūîŠœ‚Î`(`BžĀšÏ–§įWîËÏMßē)íBÏĪ0Ýģí5ßÜ\QÛæóL6­Ę-Č۝ĩû|ũ`4"īŸŠČ+ܓ›_|æÓá+ĩûvgf•ee―ýöŽýuŨ$=Üzī:;#=kGIįÍŅß/ïĘ " ŨΝ؞ž_ZÛÜ3ĢĸŲĩĶüœžžÜėē#įÝ!1"‰€H4ęđŨ•]røæx ‰o?–[Õp5Š*œwļŠ,ũúÐč‡ĩ‹‹ Þݖ~ürŸĶK'kŠŽ^žĄDž‡Ëũ^ž>5īŧĻ.­ŧ,ĘáŪĶúâü‚Ėôī=õ^ĸÄáĖÍë6mË+kp…đæC%umwÂaîãßŨü&sw~vNQųąû3Ž8óųÞ=e{Ŧ*33ŌÞŲ™sõóïÖÍ<4p~,#ą’!H†1F―_čΧ77ˆfâ•ý~Ņ'šũ‹Þ §Ļ y}žû'+V#Åq…Ŧš{ŪžÝödf7ËáåÜĩ7œ2`!ø‡ėØ! [‰B8ŒM€`‡[ 1ōŸČD(‰•(HI$ó/Dąla;â1ī&8fĀšk―ĀēĮôôQU]•7”üÔŲYy‚§šŠï{õõ›ŊŦÂ{Á9uH™,8MiÛ"îđ1ϋ^*dõvb˜xRJ‰BH6›ĩ,Ëü<`\^^YņyÉbžZŽķĄĘJR3. +„?f’VÔdã6a<`œ…ß ÍEUJ)Čz2c >ęšX\ã!42X—‚R5҇ՁÚ` ņQ ,áG­9úĨý‰T@@t*üþŒJÕÏx|ūóïSÝW>9wųúžgŋĩ•`bäÔ6m^đdvĸŲ#Ÿö{„zaž+Ū`ϞÞ`ęÓŦķ―ô―ÂÅ^—åíã'·NžŧbÕōIÃ㍏ĖßļeóĘÅģúÏ―6„Lļ ĪR!°f<óŌV`]:~uĀ• ī…JŌøŨŠ-ĸžÎ€đÉڑVÞK5O™ÜÜ8cɏŸĸæD)˜ÖLŽčþëŸÞØõŧ?:ul3Ð?ĀScÖnØš Õ8ÛŲIjÚį·įę˜ŋnų‚―ũ~—ŋdŲÚĮ§59ðþ]FBįķ*ĩbÍˋ§68ŊĸýÍÛ·-›Õ}üoį{ \Šz܋?_;Ģ}ļ;āx‚ÄųčÄĮąQ3ŨmØēāá–āîþþö–ĮžZģ|QĄëƒÎŪëB)Áļ4MyãĖÞ?ūąëũŧOu ĩϚzåÜ݃áģ{ƒ–1ÍõӞ|nãÖMόŊšpąÛ!1 Ė [Š‚ĒLJzÄcaĀÔļ™OŽßīé…gįõ]đxWUÍ~bîĎ9/Ū{Ū.ŪōĒØČ[]ĮöžČ/^ņʎŨ6ŽĒWþēĸ$ðųËąúGķíØÖQËá?x(Ņ?0@ûÝŨ?ĢÎGÛčü…ïքŒ`Ž[ĢKĢĢ/HÉ[ƒ:aĮ(ËĒl\Eå8€ųčF_đ?%”ýāý؃ũĮ‚Az:ŲØ”gšÚ2ŠŽGG·ŌúœĻĻķF(À§ *ģm›R đŽŽ,“ÉĀ!›N§áœ…<†Ø――•eÃcîu9ļëõoūs’%bDT†îŠęķiãë3<” Û }Ÿ‡ÜJ*•đwáˁ_ýēČâņ‘T*FŠ7Ēð5―ČaŌ6%óĄ”@TØ?čKÐXކnFģ‰dŒZqŠ”ð ū~°ĀũĖę1‹ļzýšUs:Ü|ÁLŨŸ>ĨLq#ģL 2I:FUčđWpŨë}kÏî'{›s#ŒÐį†ÝÞÖVm ĮņܐäZ[ËĻŽjjĐĻĄ·]_‘æ ãl"|?Pԉ?―ðų…ÕŨníŨĸ8óéā@Ÿį8į?Ü·{Ï>™Ęeã&Ó_”Ü’đŊ/Yšzýę&5§­Šķ‰)þõrâä sfÅúšžóįŨwþöðĨžT:UIĻ"’ AĻĨĀ Ą ”JyPøŨĄ―ŋŲĩóÍýĮh:e„ElÂĖũ}&ˆPč8ŽŸĘ•ÅAŨ۝šÁr•JŲmïģ/kïoý%(Œ56óģRē?J_)Ąh%ÚeĪĄ ōßÎ=đü0úßæF›mێãļûâyīrœÍŲ™ÆÅņ.þģšņŌsuåōúäįn―î*…|ĪI‰R įĖ0 üBė͛7ø> Ēøŋ·H`šd°lóÁ‹™›åŅx6üáŲÎëŧókįæĸÁ0kĀaŽeYöūH•€ˆ!!éÂ|r ˆØ­D̊…FšŌŊĩ GœÚ$﯆æA/r›$›ŽņƒĖņcÖ͆š§žïūēŨî/=\·ãŊó…ūq#°Ūœ9Ųyęä™Óŋ96:qŦūąXėđTĩ‚ĩ{Ó}ã_Õ―Äþvą§ĢgyÛņwJ…OŽG/–·wŪž9yĒëÔčȧ2vųviá‹þ‰™]―œŋÃPĐõíŸ ÅåęŪËģļ~f'Žttén?räąÍāuėÛKÓį>øõą?=ŽØn“"åûõoķÐYėč/öôķōÍåÁžĐĮĩÄ·nĸqčüŒJãïžÍ>þhčėŽåļKScĮOôõĮ&ŊŨ,ëÖĨÏŪß|ÅAđsĢŋúå‡}ƒƒŋíš6ĸ2Ižkc׿–\?Pš}Ūxöæjėo_==08ØÕ^œš[ņ“Īšú ÐŅŅÛ?P,œū_Zw<ŌŽō°xôÃÎâ+ô^Þ0―ÚZߑ_\˜/‡aâŽÝïíhï*ŸęûčxáÆ“õéóÓ·iēøÅøąßí>ÓÝ10õĩ27Į?ín?^üėčņöáé§Û/ŸOë™ØōÜëcC“wžFIðčˑSÝ]ÅSýg/nځ__ė―ðčÅnšzW?8uũ fĩųû#†ėū9ųûģ?LËŊŌï—­DĒLÐЀ#!Fsē*ĸ~å3ð?Át.?’ÓfíKĢŅ@6 Ã00QĻ”S*mÏ|õÝÔåęô ëņ_"ÛF5ŌLӔV…aˆGü*lccĢZ­!Š" #Â1‚Ð_Ûyþ |ãöģ‹_—þXŲ|čø–įzÄÔJhKS AËtd2†‘B:%‡øöūli*ÐOCü‚Xm ÉØ„ÕNÁWĻNãāĻ|fÃČōåp߆xŪ€šíWqqĄx(äBã ģŨŪ|ųāĐaŲp™ĩ‘ģcx Šag84p@éŠ0ĩĨbPHð:˜Š hē`ˆščĀ—B!wĀËĸ8"hd8–É>ĻĐÕk†ð“ŲmydÍÂėþHĢúþtŋĻœþÜ}–}C9ß) Y~>jø‚&~í~eOĄgþĪü ŠE~ÚÐlkk Л››øá?™Â ƒīáĪ' akÉ0聖DJ 0؞°Äį° ‚GY–ģDZ3“ķ֚ĩQģǁMJŸQ9Q+üßD.?’MŋðƒÖō#ôōQ<úŲ[æNļhKGĖį‡~Âîš~ŲFŪ\~Čd†oóDōÃģoV·lÛõmƒ­É“sųɎ§ņ#išĻháQļīMCi/‚ŊRøÉߟÃóÃdAČîO.?0ޙJ.?ŲÐ{įGŽ&P"•Ϗ ĩĖO+û„VøīU*•RĐôĒôČjeÆĘō lHĸ”šžŌJĐ\.WĘxĻņ%Áƒ4,‘(<āA'ÚÁC{eeĖ>°‰‰ljĄ1K™…0€B"“ƒq*™A2!0ĀO„Ð,·9đüP–hüč‚|žý@~ŋð#ó? ―…č\~øáAZá ŠÝ?â‡āÂōa8?xe@€áüH2œ@Āyę,?ôÓ&?LāÁ9615&䇏yüp… sö‡įÍ冯lýÝeö’Ëēü°D’á„p―ߍ Ā‘3üð°‡å‡/BëüĀČ^ĒwãNáōŸøn›ĸ·ÜÛ 4ēĒyrCwũØôK”:ũQËŨœ„Õœĩ•ĐrîÜđ#ŅVä―óÏϊ Jü:?âyüÐÎ:›þ{âl•Ø­ð#NúōC„·óŸˆŸœIþŎ―Æ4u†q/įÚ û°}[ēl^>i“mÉÜ>lKöiŲío›ÎešĻx‰Ó0ãm"8-Už1XĀ2Tˆ›BĒPҁc8ÛZ; Bmią§įŽGŒéæe!3ŲóKŋœä9Ïûžï‡ޞ‘>ä0ÂP/€Q ĩQ Ē jĒĀŋGøß ”côl˜PJ Æ#Кp‚Čs Ž-Ãņ‚Āģýg čYð‰æŌӇõür.'wįáš…aņcŊýĪÃ&~LTėĸãzWwÏ?&ø‰CšüSk%pëPþ–ŌĢBïT•íĖ-;ë̇_ĒPŽžķ|c?nė˜QĢFðà AOSķŊģ&ýÛī―å͈{tÔŠŠ2 †Bč10,uŲŠ’ †99GBˆÁ˜*ūŽyŊĶ/Iũ" ʼnæaøßNo|û)ģėŠĻaŅ“PÃēßļVPb8ėw§­5íŦîĒŽÜw`·yĩĨn0a9ĩ`pĀítÝ}ŲðæÃ+ý] +fÍ>ÛŅŋÚR†ÓčôÍ1Ąž ęĢtÂaʰž^§Óh4ËËá°"+„ēĒ(ōÃ5ą9† ŋ†ũvZ—-MÝuð<ĸœžÄģ‘ããÍE{øŠ‘<äw8v·WQãIrŲ·<žpt0F#ŦÓČ$‘‘ĩāHœôŌ[“§|ôúøįåPl$Č2”‹m!2~āS@tĢZml§*CÉÕÚüŊ—d\ú} 2u|0­VŦuŽ&ˆĘ +EPE!rX%€D jVB(iĖƜŠ­å‹ūx!ŧËëÃSJš.T,ýRúD2æĻTYJ°ŨŲš{ŦięÄIŌäé۝ *$‚ĄJSõž‰Fiöâe·"„aú:ę7gf•”ŸšŦFó/ÔÓ]ļcSÕ%ĮýœĒŒÜ#ßd.Ýw°pWÖũÅÕ>…0hĻņXŅĪdI’Ķ™óŠÄôH„ïÍö‚ĖMóĶ|0-Õ|ęLuŅæU‹ ęAčiŊZūÜžĸ‚KiũĩúuYéŸüþŠ­{ęjŽëW.(mpˆ|0oþÜųiÛÎvŧï6]ŽĩÖú17āliëS­uĩĮ.Þ̓ŋZ KÎۜ―îë{ē3Ė_ãąēwįÁM\wĀ{HB>°ą ` N R nJļÂÄ05J „Ģ@ĄĨīÜL8†Ã%§&…L!˜ŧ>$ÅvbÉēedˇ${-iw-Ų’-iũu-Í ÜBþhËïóßūëũĪ}Į#ïxi0 GícÃ(98ŒéŧþžpþМķëŌfJu7ôņį&WØÆĢ_kūMîiUŅhƒqŊŽĘ-úîlfÆÉýëh·―a|\[ÎÍë†ŪÐͧoÖę*­ž Qˆ>y휞†ŠTčmÆk_]ˆLÚôę˜!B zŧ•ÏūēïÏoP3“ķ•|đ]lPgfd9B͟ŋQVzûÛŨ'FWŠģ>úĶZŅO!pũÛøņĨœŽ}ƒ=-9vD’Ī _@@Œz~ÂÉŊo|ēy)ļyÉA{Ø;ƒ›ˆ˜ôÖĶėÕÕÏvFz;GÎþýŪå/Äî>‘}v[‚O>æØ™+đߝŋœ™69ŪŋŲTÁv‰OrW†áĻÅJ9|dŒXgbÐēĄ!a O—“ņyAāģöū—øöķfLl·­Ŧ§Qsgõēß$ÎIÚzä24érÚۚõã'Ž娸‰4Bˆ”õOXīj(83ŊĸýÖíė/ÔԖ)QýH„î—IB@„HŸ‹å[•4;>6D?)ŧģžÜEĘH胠!‡‚ė~"ĀOSŨۘ;õų1?ŽTøD[·āŸØ7SŨl3qė Čˆ~JEĖïޙO{ÚoėY6knęöóęn$ųÏ&§(B$HÁÕzėŸRæ%&ŋģĩūĩSŪ  0 G-ö$„Yļfû‡‡V‡@íĶ#GuVŊ\NydsVė8ž~J]Ž.:wtīĖļwé†Û?Z—ŋŸžķõ―gH…œ&E}=] Q’MÍ €@Ž|aúėiŅ–ë‡WŪ?3ãÕŲF!ŸŊoČK—ˆĪiĨ”§$I˜›m݄L)#ŧ{Ī!9A   Á‹žŌ +ôþe+Ôۊ}B)å4…ü‰%ÍöúŸÖŒH‚š=‚OĸéDÔÜ *Õ·ß_úšénAÆþ]‡óCäTālī"īuí/ié'/)'-=}ęhBÜ@‘\N€a8jąĮGøP‡šūhåšÄ8.7cwÚ§Ū°áSÆĮ‚ËŠĘ/jërņ­eÚZÎårqہQáĄĒ­ĻĪ„Зčy!bČsņ‡Ķeß·rĸ9č!Q‡Žœ>sŽĖįr Ąģæ/&"z ŪDðõŲ7‹åąÏÅĮGŧōūÉ:Ÿ[|+ûĖ5Ąˆ|)yĒĖã Žˆ7zXļéŦs'2/V–įzėĪ ú )ũ øD1XIWð‚ŋ[:Iï‚"=ķ‹_fWrōĪÕË'Œ íĀuŠ$ ÞģŲón^)ĻÐu°@L]WQRÅØŧx‡Vkö R€ū`ŽZė?|€žô€ą+79Xqãøžۚũ§ýuŨŧ‰MWŽĖOJ~íõ7·Lw)FĖ[žjŦ-[ýæ‚JgؔøyYûs[ÄÅŋÝ<%n`Áį‡6|pq^ĘŊĨÉáëĄĒfNŸ1#’Wžņ‚ŨíA„|žg'―ądöøę’Ko-Øb ûÅΌŋĨü’ŲģaQōÂUyĘņ{?9ąvFŽŧG?Ņ+DŽ™ķóģôY1íĸøŪt Áî3đ)kvlZ7 š=)S ōþk"(ō…d€ZTXŋpȐ…œDQĪÐqåÃ-KĪÎMY’ß`[žqûšĪŸõøĻiŋ^1nšp|ĮšM^\:lpĸóûÖïË*x1á%SĸŕŦ"44°%ψ@Īöĸ †ŲŸb˜đņžĶšÖĖXY–ãYë=}uU•ķķÞÄ;:YĶE[^V_Ļ.+ŊĐ3Øė\{kSyĐJ]Zia˜{šŠB•ĘØjíāđFݏEEwŦjŽí­Fgh°°įrówŽmˆųúS*§“·ĸ–į,ũƊU%ešVŦÝŅÁ›šââĒü"õz#ëčäØYĀņ<ߎŨä}ŸsãVaiĨ™‘VqԈĩÍ\§Ņč-v–ĩ1–ķFßÛfLFMĩŪūĨãX‹ĐQĢŅ6™–csĢNĢi01ŽÝÚĻŊđ[Ķ’žw^V^eaė<ÏöVâØ:íj•ŠēĘĀr6―Ķ\Ĩ.Ū•62ŨVÕŽ6k―VSc0ķÛĪ’í}ĩĶÎhĩ? †á7ƒI +aËēþ!é2čÁVh—ņþĀ0ßÁëK.Oþ „ _|·É&õ<Šz@°|ĀĢæð―傏čgÍ`ŧo?Ä>Pö~_°ÍJ‚…|į‚ĸg0 G-&…Q]uņéĖģ·JŦĨLēĸ7`†Ģãx‡Ûíîrv<Æ\ ÃpÔb†áĻÅ0 Ãhx*a!xZaF< úQŸóēs>đ–4G?'"ēîëŊM[ōOįHÞ°+Cˆ]€X…ąXb`–`[6öŧ•ņ‡[j·Ô#{ð‰Ūs{/•/ēn ~:}2ō―――™Yõ Q1ã^ˁöāŦ=9ƒ/ãYðeņTýzþËøË/öā—áĖ―ãTčŌÕc’3čüRv4ãŊ|ý]Züjōså/ŧUđ˜É/úúՑØîÏũwNåÖqfú}ãí­[·HļĮÞûπÚ>üË?ĸÓüėgfjëȉpU‹ð*ˆˆŠf‹/‰ŠĖĩ–Gd†‰Qļ}ŦhŠēũ6ĩĐS ŠŪÅîSöĨóŸ$Ž™Íâu,wGÁÖ"™ÁÞ(f R™îŪjóĨ2RMIŲč*5ó―ũÛßþčG?ęâïh‘üÕŊ~óãĸåO~ōW‰[·n}?dĶŋüåĸúŨŋųá?ýÉŪķeĮúðÝKũÞŠ*Áīę8|ŠV@šëwßĐPÕܝĪŲÚūQER([DU”ũ5••Ũįņø`Ë.k-QņíŠÖvUÏóđl`ï˜k­ĘÜÍÍã8Ü]ŧ4(ĄfĶÚ4Ôô8!” åTfžëó I*ģaš^ ũÔqŦšũ–~ˆŠŠpōņöxËLx<ÞDčūM"Ķ<ŽqÖįyĮ!ŠÂ―s€5ïjŲņĒöw?’œ ·nÝú~ĻZÎ?7SYE<|é•sïŠU6gEÕlUaðdkM†[YĮqąlŽĻĻ„*U%:Ė%yŽĢ9•]ÄÜ―P…SYĀ•B :/ Ą\“ƒQ―Ėc•áÚ^TfĨˆĒ*|‚ŦĖk ŌčܝĻZ5M…ō"xUúÞ*ú’GL53Ëk=/Īē&fxIŪGō}ŪÉ g;‘Ęō―ŦŪČĩZŲÎôÅŲmÖ۟*Jb‚cÜšõ ęþË^$įÐ&Z(TĮĐ(˜-1ę$wŧGzÁåyI;ėŲdi(Ëų<ŦBM đ&EÍ ,ÔDęîĨ/‰üáŋÏ’™^UĒŪ9%ą>ŒÚ@]#ģcā>?žUUDPd™ŧ$KT_įNU)$Ū‰‚Š îŨēŦZú2#0ēmcÔA˜iv"–ŧ ŠÔŦˆŧ‹ȧïÂĩļ‹$ÛŧšŸ$M āj#˜wK*nÝšõĸW†ĸ[ķl2ŲŽ@ĩaĄMNŲî•nv€ŒÓMÔoŊ€5/ũöĘČíΗDÛü…kYsÎÁžįY™Įã˜S~ŪÂÏ]Ļ5™ŽhĄHžûR øÞ"Ō‹%+Ûaw'CkÍA„­EÁų|ŠˆŠäĨ ŠPįÐ,3EŪi~n U4üú%äíjŋEÝš]mŠœÞÏqųŅmÏ>éēĖw{éą"BHģ%fUĻž 03īK•Čb]ÕÆÍ›ę: )R‘K-p‰ęķ­š6ŲöģïÄ%!#3*&jûîĪ•óĖ4ģžĖĩėĘĻ”öãŸUˆhDj›íņ抈ûNf“ĻøąÖT.ELŨÄW ‰ČČP•ŽėãÄĨŠĻyŸ&”ØÞ™ēfUN‚`Ë3î6ƒoQ·nÔēq3t3ģküR5ā"DôŅüšfTÖZéáÛ§Ã)㒈pš_ jVό4ŅĨË}ûÞÞíY~á @æËgÆ:ŽĶ5õX üÜņšÔ…ÛĀɉh—™P|Z :íÍ,Ō{1Û=Tēsƒ—ÂTŧxWæXŨFķŪÃXŠĻŒ3EĨ\Õā$TTČp'(ĒýĀĐ"n{8ŸÏÔ$Ŋ"―/ëÜm·E2qžŧ"•TeŠ(nÝšõ fĩHdÓ02Šj5ÓīŪ`H@ØÛĘT’ą(°GdÍeŒ ŧä4––ú.›ČĘĉ„n5ĄĒPåÄīfįhŦ‹8ļoïî]ŧũow4n€Ũ&î—ĘóC'Ï ÃáÕeU{ÏÖoôŸþŊÞg=/ĸ7PAiøØ–o·ĩJōØĢ žū%DÕČđ“ƒgóğ,Ū GíÚđóĮÞ_FņæÁ։dxpðX_ߑūÇ~ë?;’Üļ}vžš,ËitāT+‰ĢkąŊ_Ę(pJ.šZQąDë(J“pAšÆjT#ĶɌcŦ2Æ:åÐCDZât94‚å°%Zŧ@ŦE™8[ĒX{PW‚ ī*'Lˆé,ŨųÕÛ7âü’uÂēÂaüáįÁ~Pū óæ!Ô=v‡Ų0]ģÂebbË|ÅxČU°ķŽ7„ņbóFŽr!8ņŽHml ôå°EöI†n·įÄŸnßžiã’GĶŧd’ô ŽÂÓßó؜·Ũ@ÆržaãYi"Ė~lURĨÛî|ðŲGïĒĪ{]rĖã\y/%؁+’Œ‘Þâ‰ū;RŦĄĸO0Ï>‰ĀÎ•yÃwēčīÆÖcŒô&žYežrkÁMFÆ-ÕH”ÜŲ Äö”iũ-|ōþØ RēOFb< Ue‡þXF(Z?5oQŨÔ–lŲīqÃįŊī6/[õþ†Ôhėýn]ũ_œ‘@n‹úĄwĮ-ũ<ītIŨō•‹îv“čŪĀũnûĪûÃ/í)2z‘žbUŊS‘Cðnā―"öÓg#ĶëoūcÖ3O-Šė^]6ĒMŪÂŦKDĸOĻÍ9[―xϒĩĨ(i"Š8B›…pmX'ĀXY ŪÆŊJŅđ-ēŅZ%V ŒÞä―Ĩ{f(&üÎÞw‡Gql_Vu˜åœQB Ąˆ`„Ād‰lrÆ0@ä DÎÁ€‰&Gcc“sķąÁ&G“ƒČ„$gĶCÕšnīėūÏŧŋũ}xũýÞsý5H=Ý==âôísÏ=GUUūqŲ= ŲDŽŅh€&64ÐmŌWĀVU€fU',|ŠŠ°*°•wąĀD†-îdÆa”ŧšB(# LØåÁó›pĀ%Pļ’LļÞȁ8j€ÏĪ-·ð˅ õ‡0þprģ>Ë{ņŌŲ·bã„ ný2ē_ÃäĪĪô…{ óģöĸöĚeiÝúüüīäÜڌÅo ÆĮ?ŊLYtD4~]>ję”ÔmŠ4XīýĘŅÜ!ģïÝyãž(É·oîаIģä&_8Dĸ―ŅH/þ°*cüøq_ÔŦ]·õŠũ%Ģ1įÉÕ1}[$%'ĩîÜëėóÜËŧ7 īN5šžœ^óEŊ>™EēåųĨÅģ§ÝËC2;ĶJîÖYFOŨĄ}ï{…ÖGgwīižÜĻYëåû/ ēteĸÂέ›4Ļ[+}ų.•%ۏoÚ°Qį!C·žĢ&üpZ›ž›Ng$ĐäõųŒ~ÃaYĀF#:ĩnÁķ]ƧĶ-ĸþ:Æęū5“[5mŌ°^âÔõ‡ÍL™]VđKĻ {CzĪë4ė=ûI1čïû—wh—Ô ~Į Go‹ųíÅÃÛÄ'%ũ1 mø„-VYztņČ…Ė·’L\6jōü}>ýäĢøÆ›ŽfJ’`ŧr2=đjÔči:~ŌþÐõįy™ŋöéŌ.ĐQƒÉkĐĒAy{cúgƒĶfôiÖļn›qŦķ­ÎhÖ N“Ö3›ąíü:ĢUr“õëÎüæGÅōxŌ'ƒvß.0Hė†šÞyĘ݇·w]šŽHÆžŦŧŌ&Î]45―Ab.cūQ%QŧuAZBýÆ)iýöøâįĖ(ąAĒ?oݚ_ĄûīĄ]$ą\lģĐÃSî8zá֕oįÏÞøÍēÎ]æ=-FķkŪ&!aĄáá#"#ƒ}üøÃø‘é“GķJŽÝpōwósl™;{ã–Ĩŧ-xĨ’ ;—5OnœÔšãÞËOe“ᏍĮ NKIî0núųÛûį1<­Kj‰Ëvi’1įĘö!fd éŨlÂÚ'YOÞ{0O“ÞÞܝŌĢmģĶMĶo;+HFËãkÓԚ''7Lļ>ÛLüoJ p֜ÛxóIY^oJ’ˆÃ:TŲHaɒğč5@Ļflč ĘÜŋļ+!e•&h 7tÕđĄãĨ4tąØčD™—#W`ņŲ0 j_•#ōa6“É ûŋ.MÓđ…ĻYqYą ø /,6âĨküčpÏ`…pî3ú0”ëa9æęšÆO•‡GF đþ4‡{i)‚s†#(~aņ 4Œ„•!F‰æV?ĩNÅÉÚöũå­įÅFņÝô”ĄÏĒ'îûáŦk[g~LëVýĻvӖcĖĐėøōþ…ËŊógßž}õ€…·~ÝpėRTY‹Óëo™2äÐÙCKēŊ\=—eĀæo§/zŌ(mïžÝcĐŪ–ĢEoėÜq,ōģÓڅíØ{ÜZüęëYïûuŲĩogũ—ÃV 'éÅýíũ^•\:ąiãķ_ōęîÅ3ŋþöÎÛÝDĸsÔoýī}û5kĘô9^YŋąĻÕļ•_JÞ1aŌŗVŊðšÓÖÜ8ŊßÉÍ_>5KŊ.|;jåĩßlŸóyk7 ;…V*W°|ÃM’.n\{Ī$ ČUÖŲs kŅĩ^TxŋCŧ·Š”yjeę‚ cVïønÕÔ#+'sâ‰l, …YŊixŌŌĩKCŪ}·|ËĐwYŌ†­n3mÛÚЍWOüĒðåôA#ßOØđkFë“Ó§o,―ļuúĘË"ŒÅއ?-ÛtžéĀYĢÛÚ­š·Ã,ĘBie—u㧍Įn·OŸW/P›š:Æ3yôÎu3/ϙžĸfūI4Ÿ;ļëWōĒ/Ó_.ģöŽÏœ/įŪm?p#įŲ™5C—\ŋnŨ7ËÆïY<þ‡ŦBĨ€—_m>N%ņĖĶu—―c}譋§čëæėĢkŸļråĜã+/ž,đļiÚâÝ7ŋÚðÃČÎ5n\=öÆĖŲdŒõņÃüĀøZž2aF$EƉo,‚oãvŨjķ`A_ŧũž$ņКŊ'ķ`Õū\ET _ėÛūÏXgÜ”ĪSûvž“ÛwlœÐ|ņWŸŠ· œz°ßü-s;T™;aÉÃ"Ē”G<2ųĶ|ģ{߆…Ę/3zõĸâÖóė‹Ö‡ŧįöč3æŅ‹U7xyxz• r7‰ ÎîÅA€úT%ĶVý' OŠ–ØŪk6\š'øýnī†Œ­S{Ø;ĩÓ ÉŨ_—žß)ēŠ-ŒĸĒQ͈Ļ`Wü6óƍ;đ}{tðõðëÔą―ã­ŦzPlĨ@ûS‡]đaéߡڝӇO\:jßĒ—ŊX`GdßáZT/_øėŅŦũ7Ï1bÁ–{æâ3Ę}ūjpŊЛŽŠHÖ)đzlwhýõ"Ģkĩle°ššėowiïŊ7ÏŊÞwŪûānN”MZ‚=ü<œ‚ËWðrsļtpOXƒ^ɑå+7îûQĀõ ·ËÚ`šĶ8DÄ øĒw\•ÄŪĐ ·ž^~ōäÉĩâŽ-ãú ›ĩՊLÅ/ï_1øĶĪâįSĄÛ˜îöö„‹üÝАsŧ13{5Š^ąEo­6~%8·MŌ§aœA}}ýôí[gö<ųZ~q^vŪĒëÎŅU‡Ķ~V9ĖÏ?$jô°A 5+…Đz~ÁoGG&õiáŸÔ;ÞûŌoO› ûL?đíÖÃó]ý<­•QՐũ ’į‘Ðsņüaņ%Æŧ{cRpíä]kôguĒ‚bwK ĔžOn[U ÛČlÎČŠŠF“ģ9//OïÐōåLĒïEGWų(áãją!v"*4›:õŲĩITT˜·;d'?Ŋ?VX°OÎÃŊžß_11uüŠÝ_į–[Š,–ÄNý>kߨßÃI5“„ŪĢfīMĻņIį*žÞWæŠ(ß§nđóš—ũtvŦĶ%īQÎēžkįáŋÜÍBjÞ9sA֙õ―zĶýþ4_Ó1Ēĸ†U-āÐPŲ1•>ʉųð‡_Bųø)Ģ\ĐNÁQ_DCoŸbHۅ€LŠ+Luķ4P~a.œ‚Öķš- ‹%IဠïbRp•Í?”Õ\/JX—ėÐ@Sčėī ĩ“ý8wf€Š“ƒ Ņh䇆›'GčÜǁSŠœP˜$Eėė7ävŒ›0ČļtYU­ŠĶóy ―,2‡Ûã"ާ ų*=sĸBŽßøĄøĩļ ŋXˆKlđtÍJóÝ+7^+ž:­ÓnÔō5O_:Ų.ÎCŅ,oēŠt@ÕŠZ éE—oœUėX}ĘڎđN~n‰F|œˆū?°MuJ+·O=vvŊėÞŨäYĸ'ųĄ#$ š„ŒDƒ›·›I~öô5Bčݛį9‚äPĐ^å SšŸ3œ0ēéÖ5ӗRûķŊLJ“G)FÛQiF·€€þ#gnŲsøĘųņÆÛ)g›šĶOIíVމüWw‡üûO‹*Ėš—™ĨaŽ9†~Üę#ĮÔínĩė čīęībŦôŸčúîîbvšEģ^œ…ũÚgŠU)6ģOĸōAžW˜‹Iô4y œļdËķÝGöęf” _œ=ĸ0ïÍÃý;ŦŠņýdz"G#Ð2bdxĸaWĀČ œ`töõlĸųļ5ßlŋtóT·šþ%Õ(*R4ÍJ‘ŲŠ2ØU Ôāœ{įŽ…Ý 2ßž18ŲųEÖŦ›9Ļĸg/kôháČî$ķĨbÁUÔUŠŠ%˜jr·3žŧĸ*įÝ­ÓGeŋe˜Ę[ýÔŪNrØÓÛ~~Z`2™D―āÐþã%>ŅĄvVģÕŽčēĀÎö}"1æã:-Ûĩm\·Šˆ4ŠDLā+VŠĘę ģB$ģmtŒH˘ũícWϏņ”UBÓĖŧŅ"’ōÞ„Šōr‹U_WĄ*ąjÕāSP8–o|Ÿ­GÎõŦ5ĄÆErĩŠq >_īrýЋŋôOŠ šþoH 0+Ņøð>sV4͙뮀0œŋ+Äíe1Ŋzt?wDÖÔF~—âĘÔģ `F_Üf[es—C ų|æ ČÎübÅ eĩ$"ČÚáö`ˆmŪC@€1`8 ąį€ŋ0Š ņ*å‘1xÕ ”+JSp0’éPĻóŽ…Ęã'(ï\1™·ŋļ֐K2ØøĨV: ƒķPžģ^š$°sÓāVš„)'pE>ĪûĄA’ŸĸöÝ ÁÃf͟—1eąo:Õbâ·nsyõž•›ū]ŧrŅ…į…Þa_øaƂU™EČË'čč†ŊFĨYšĸIaY6hĮ͟8yöČĄÃęĩmį­hzi#–XĻí˜7{ŅÆŋŋ0GČïUĩTąjІs*6› ž-:}žyųÄYógŸūĨ§ÝĘ{ļVŪ[ôķļVZåÂ?ō((ð­ÐĨV€Īęīl–’b‹ĘÔØA5’ût [ŋlþĶ͛–ŪþöqėåŠ/ßýýŪ“O 9q>Ļ~w§Â̓LŸ‘q43Ou„\ŌúņÂ6­[ųØK°S.Ĩģ/WÎiÅüé?]zÛĒO€|rØØéĮŽØ›[ĄyŦ*ĒŪð-E„ß=ū5kÖä9ĮŪĸĐ Uóš!‘õúEŽ;wÓÖoÖoYũÖ)ndŦFgŒ9nðÆŨļl\ģ–XUũ­ģEƒĶ)6ëä=ĀR-%fŦ†(ąũŽ8žņąÍ VoÜšråúó™đ‰ęf3ĨWR‰+2[(‰mþĐ'9<,}fƘQ‡‹#›ĩˆ•dÏĶ’NŸ|ÖąUKg‰5J,:•TRŽōWšđĻÄjl5øóJE‡RÓŌÆ,ø^Č·–ԚĒÅwHoŅĀ~hĮ^ģŋ\4qxĘėåįgč$šû\?ģwæžoߊ—}ĨŠußÚéãĮ9zýwXß :áDWÍŦN°·_đë§ũN[ļÃ-ąMŧŠ…Ë/Üže゠_Đ,5@QxOÎh/^Øôõ”ņ3G˜S!ąSB9EÅœ3!6âK7[°ĻŸ\7~æō-ŨUĻ`ïā—ŌĐÛëŦ–ŊÝžnÕW§ï―䕸Ó%Ž3ýÃ2 ĮŽ}pɎûSžËšÜ0HĶé@rQ.aA…!1]ŲTbÐ߇|rJËúHÜÉbÊT*K _„y4ĪN‰!\Į,Hþ^· Ķģ$YâКlP›.b^`rŋ1]ŨųiƒÞ• (c ܰsÅĘ*;™á)‚œ 4 ^JģÍųy‚..—ëJ܊—‘$p΄ę0+@væŨCŊôŲ9óKJQtLl― UE)kýåå―“eÉÕÕõŸĖŒĢ{G‰ŠšBýĢë 28ČA(ß aBuwsąîâUÉŋ\ĨŠ5ƒírHXDTZá.ĒcPÕԔ/’âĢýœoÜø:ū]‹ŠnnQ†Īöö3Qƒ &<*ÄW‰ðr1­Ālõ‰Ŋ7īÏ'žv?ABŧhttĪŧģ―ÉÍ?&*ĘŨÓ3ĶJí0Oc‰UmÔ~|Ï&FĒÛ{„ÖŠŨ°y­“ƒ[͉­:Ũóģ3TšCpĨŠąáĄ.FLe§Š‰Mœ Éށ!qņ5ëŨ‹wHDíÖݛ%šœÜĒâë'ÕŽL4ÛĻį€î­â##<œ æĖ?ßēOÝ?ØRzęØŪōG5< ČÃ/ĪbTÕĪ:ÕKōs―"ÓF N rV4R*ÝrŠŪQģB9g ŧķí?īy|€ŽėkwLōqÔT] ‹(Û Ab­ððęm̌/=íÓë#ïĀČļČpĢgHtå?ÎÁAvô ŦQŦZˆŋ+ŨKSŠ―BcâĒØ6:#Š'Eúŧ(ŠîîX):ÂÛÕ―R•ęĄA~ĢSlšŅÁ&ƒ]…ļę•#*ú• o’X­ä]Ū“oô°ƒk•sP5äҰqÛF\@‘ĘNAUŠÆ„ú9áE€+Ær…čŠ―"6hÞŠnØđÓ§kučánäå#‘ÝZ7MŠõōŽŠĩāí“7n+o ˆGý†Į†z Ø.<*ĖÄĮ'‘U­rX ››§Ŋ`ųØĻȘ˜wgƒ“WTtL°‡OpÅČ`OL •ŠÕhŌļЗ%‚]@…ðJåž―Ģcc|<\$I|p|ëí :­Ŧ;„ÖJ:Ļž‹(:…TĐâïÂ,íÜbŠU,įdŌ ·ŠõéággLĻ[Ŋ~ ĨHuróûãļžNĶĸĸÅĐ äææ"„\\œĸ)Gœ““ƒþa988Œ5âčáC,ôŪ"årË,x(fī+ă3ހgßjŠ å'ƒÐuËƒ5U–Ī4õ‘hŠĘ§­ ·|$Éeí,đĮ0ü‚!1Č#°6ŧqĶīģD Ņdžo€FeÃŅ>LĐÆîė`Ž€(­:Ų9C›‹Â3Wha–É +At]ã`Įh,”AēyæbŪŁKČŽĘ0ũĮaƒm6™†ņ Ķåāå:Ð―JöŦÕŌūS§ÉSg!ķđņðaĶ)$$øŸ 'ĮĒl”ENUkĖ’‚p—ˆyQcÕ2™ŒPƒZ)–Œ !Ę= FÛzuÜYĖö>ĩJ7ĶĻt1Ú\$E—&ū7ÛþK—(f}ĄcxeŽÉhā$2›á͈ĸDUŽ:A“i ]ŲÂēŅČx BđúĘhëYQÕŠ°ŧÓÊD˜|M4Yc~B4…č–-“ŧ\uk7côįÅōūv˜q=’ ģ7é’lāÃ>Āûę ƒŅ ”Đę>E-JĨÄ:5ïÐĻŽ?ëģ™û>oHƒ@ا &þBdƒˆ,pÛæ‹ýJW~­ €ËūŠ FYĩX)ŒFƒfĩč”%4ÝŠéôN•Ņ Šlg”―–ąÕŠĒŌaŲdĪ„–ÜÝũÅØï*ÅWļtúāÓÐGtyÏfģĩŒ(Ką~ņāũï6~ëœØĨWģj&6įA‹BʆŒÆŌ‚TXD&Ïb—EbƒÔöqˆÕĒ Q2ri3 H”%LUU—MÆÃzÏuk~xbG!sépōČj…_0ãW-VA6Éð€Įŋ)î‘ÂStĶô$ĸ áäũï? ”•Sõ@í öíĩ··„ŌzóYUÆÛēž(йʀƒ"_M‡‰ũĘtfþsAóGĄi&ÁRT…1ŋņy ֚·á,D@–ŌŊž„^šH œ 84°2–hbDlþ‡ķQĪâm7>ðF€ļ•˜―,/KF2X™ē†XðüŌYĢLggW ØÔ ‰ŋēĖ9&ÁŪ—ðävž:•x$ŋ ųŪA†č―Xu,+āå(Ā_|AAaû§Î˜õÏCퟎÄo2›žC}ĸ[†ĒSõéý‡vÞ!ūöšNþŠ9؂7™WoÜÉ)Á•kńļéĸ’ė!ŒÜ―uãþã7Žþá 5ĒíV^üÉD,ķɁ ýë*ÁœįrˆSX9Ïĸž―­ĩԟrĩ€<ū›%ĩðD,@%3 €AčZ^ Å<Ņ‹ũ–,ŠU➇ ˆ kŌK"ӜC ™ 8wa‘ ĀĖŽĮĻTŒX}Ę{ý„PN[-V D™-‡QãųfėpšĶp —ČJ_>ģ`tØŲÎ_g{ƒÎ+ØķYôęŒ2P.ÍŅŅA(&APũ―𘠊_ ž $ԟ‚9(uŪŦ%Д―–ųžu* e‰ŋú‡õāĒūŅĸϘY&;ãífŸōōāĸïĻÃßõϏ ó^+ų+ ËĄQ1ô/ËjĢ”8û”o.`pý—íŌPŠŒÎŅ5ęĮÕøÔĮŸŸ”ŧŒĒŋrB<ÞÕþņ{ųÛŲ‹Õƒā8 (Œ$VUtĩLĻĪj3ؖÍĘýMøŨƅS0 Âýn˜„‰ĻaY‰’qØß-„Į(ÄJ)ŨĖ šŲĖ:oėy^ī*L:ÆP‡-Ä ķ­,‹rĪãöŽ`„Ũ’Ä›ëQyĘb6c }@CįJ’!ÖAÕĖ&Š4—: ČÉÛ}Â&ɒA%Ķ`˜úĶë|"đôŊ•+sUUãĖ5h$T–ļnĄo§ąĻ4ПņŽȔdKbÃoŌ‡RóķČŠ°Oƒą‹ŧģøįƒa8ũŝËũÞÕú8ŅAÐØđéúÓ_―Ūą^Ĩļ°XsvwaWðŋÎm`ýîđĢO_ũŒmÚ-)ýĸņؗõW.JðO;ŧāĸį(C)ĢTô/ēȟÝýþ†Z‚Č]UĖJY :ïQ] ýŌe8? â–:ÔčSNīÉ!ęœŧÏ Žed ›ė||}yœ Ÿ; ”°:ģ4N‘GXĀE1ÅXpZpŠ―Ŧ åŲ ÞĀ$-•|$#‹Ų’ûö ŅtʝÎáĐɏ@(†•{ÜP8 ;›@•˜Ó.Ŧöļ8ŒĄ Qï Í1Ä]tÛXšUe5&“‰°ęP+3I’đo!‚ð Šũē0Ō 7Oíŋũ­{EgĐÛũ›ØĄšôôĸq1ÄqãĒ…§#ëÖsÆpBūĻnyõ*Ũäáëî =8ŧkŲ–ßĮŊZā#Xuú_UG?:ĸÕĪá…ŅmÂ―K({XøũÏdĮ6dZ%OgŒþ^Cí?þ°LS‰,‹üŅ’O ĨÃðŽOXƒd”ĨÂo`čƒéšÎíļ8šðqöÄNÎÎÎí:tŠ\đĘĪ0!úŸĨïā?ĸ'üeeŋý“Í$IzðāÁĒ/į―zų\2ČÜß<yV˜Š0ëÉW óÝĒ:P°—fÝ0rfQ0˜áĀ~ÉÁšÂØ~̉đ†[Í,..nŌĪIåʕŦXąĒĶi5Ú&ÖĐ{ũÎísŋþĘļ }’põ‚ĒŠÜ‹ÕøĖA˜XÝČŽÐu†Ž”élPbÖjąðĐÐWĐH$îã‘ķŒ@DŅ‚-Ú·Ôę zlˆ~8eĩ8{Ïōųâ/Š[TÞĩ+œÝ•qĶg·OžÍ_wmðĘ4ĢŦû’oöŌۆLÝxë‹ÎNĒ-æ2ûÅÝ+]˜đĪāΝŧ‰=ČÎŊwú’ïėÁmlŋÜ­_·>u<ë0ctĢj^ũŽ?ŋ|í–jy·løā{þívîpdÁā)ÃĮÅܖĸô7›ß.Z·ļΕ•kŨŊøŽM]OĖ(QvŪüqGĸÓŋMújxUˁ_öÉnķrõÜĮGM?[ÜrĘēå{ęßuØĖˆ=óë?đrę'τYģWĘ―; ›9oÞōĀqýüð[§Š­‘ĒÁĨjŒÓüm_ũ”$Øšá&ÚãeŨsŠđVŋ=˛ŊžØgāðĨŋ}óųï7ŊČ M1ƅ/3Ŋæø#,äd^=v6gƊõb|Ucäģõņ„Þ)*uývį@\T䋟õ>YŦ3pϊä•zūė·cs3Ŋž7cõZĸ/ÓŌG˘ībõðĒiã7îÚ5*įŅ•SŨŠĶŊŲ”īáðÔ1-Z,~ņûųcĩðÁ­ uîŅ4ķRføGãÆũ ą6Žß(óį+w7ČoßaĘĐķIŪŊn}ŧãJĮ Ëš7­JUý―þ IâžčeÁ (áŌ+p,„Į"X”ēLCU†Wđß pĨl{Ļ Yïˆ{ļļļšúųûUĻXQ–å%K–Ėœ93 āŊVÏüqÐnÝ{fŋÉ~üč!LC°Þ;g°SDÛÓ=‘{ĘØ/‚›[šÂ†Ä`žBÐyņ+ŧÂ#slwÂ-%9É{ģ €PúDđ.pĘŽBMF‡ęq%$OO§ĀĀîõĩ ûΆ_öĻÔ,đJųÂë{fMĸž čĩl2áũ{^FYdŌuQ`~ïLdŠįßōÕÔŨúU ށþnöĄ*8ŲŲr:īĒĖ3WIė ūþî^mšôÜubúÕGoTƒ]ã~ģ?mVũ&―~üį_K,pþB ð wūY1,Ė^PÜʧ§LŒõđā;ģgBß5ÜĪa]|šāLjĪØ;ö˘Õ0ÞxČÕģ]Ŋô ŠmŒē“ēó4ŒĀvÔęŨ?a[ûÝ?^ČÛķŊzĮtÂ{Šž2šķõvwôi›ÝÝ>Ė·Š’ƒ ÆA䚌Uo™2Ą}―x\ë˜/Gnæ 7ļĒŊüÞ]ßõļÄgRŨ6ÞîŪ)l?‡3‹­…šÞ:uRûÚÕēW9ÕnŨcDëÚgnđ;ČQ(ÍŨôOR&·Ļ+„ö™ į•Į…!’čĖnâ`+!X°dō)ïäQč[!4@zqôŽđ@Þ2ĐŨNýe>ą(Dģ’øÎÃ|ÚŦLw(JsŲü{ýgĩÅ éTfiXęð‚Ā&€5€$°īqh<šât3…Ĩē“ē𚉠COŊ?XZŒPppðĄC‡&L˜āîîþÉ9 +**ĘŅŅŅÅÕĨ,{Fēif—ؐcĖtQĢÉÄČhŦ"J|X3*Pų :ŧq7Ļåö` Eãƒd\ Œa!ņ9˜ĨøØ„Vôƒ*’$‡Ļ†IIu]™ō]G]>íóMŊIiå<Û›cĸî·áGTē}°ÏĩŒ…ßk’d(“čoģóŸ)ˆÞýí·ŧDz·txÏÓâ˜ŊįTß§oą$b]-bý5lã=Ü:š8ZĨž\„üģŸ=É.2zļÚe!ABMĩ ũÓkDÕXŸ ē 5gŋ@šuúÕ;k ƒôäÉcÅ%ƈĻFeïB-*/cŠ‹EÄQĐstïžĩ{õïiģīY}WöæBæ·įöęŲĢ\ŲčČâ5™›MJ ÎüōÄRŪŪ. XģZU"ØæļĻdïâlQoÝ|†ŠzQ]3ļųؙ Ÿ?{ƒb\_=ËĖ3˜eQƒw1=!V2G‚8'ŋ€"Tðøaą94ÄÛAĩ(f"HXđ~ýLžÎĻlÝĘM' ’ŅUĮĩ{LLk!bÉŲËþĄNēX4Ģ€ĖïÞžĖÃÁ!ž2ú;Ōó? j> 7šáv\Ј sVV$ąPŦę6bAāõ,ĀŦH[†É|”–čÄ6$fģüü‚CBTUõôô4™LYYYŊ^―BÍŌu5X,–’‚ŨŊ^ð]“É*č†ÁŨ02c†y]ŒĻfsĨaŲ‘HQ"[[_ÛÁE@ųŠÚĄYÝČÏȁ3’“ęØýņŦÎ#Ũ{ĸøīPþŽoŸĒ"–ķŌ`čúïbÞ1īžŧ0°ÕÁKwó Á~ÝÔ1ã°ũpRTYũũūPݓ0 iČ9G1 ˆ9gŜs@1`@@AEdÍŲ5}æœsƀŠŪ"’$3É3ÝU/Üó^ŽŪndŋĸ~ĘŲųÍÖtWWÕŦÆ[ũÝwÏ9“tĄDcíĩۉĸÓ―ē•ØZBø]ⷉđ_xÁÛožÄãdm“ī 5ĩĪ  9:QAœG:­āó\ðŌ0ŪžŦđ`D`ŽA@ÉD2ōĶ]w}QëÖ+VŽxæ™g/^ėtĩĸSĄÖëŠĨJÅ­‹Ė›ŦTäKÆa:ÝGiĐiĄÏ’vŨ‰éå" ‘{…ÆÓjčāØqÞ―ÜwkÏŠsĶÄQ cۊŒ3)c ĪmĖĩąÖS*ęęë>ä°iŨNß2Ä\'#Ā<މ"e…Œ f“N-MŦ'kieQĶˆžVoÚ?iš~0āRs°‘RLÄG…ļ”MŸ’Ašá/ -‘)ËļHŌpÏŪ“Ą&auÚŨ›ļóä.—ÜŽ …Ô˜HiËeL€•ŲÜĨ;ïŲ+.{lÉÏ%$í^œqŊŦ8éäŅûģz1„Íú]šuŋáÆ›:–tüōË/§L™â ĸ9^ ũCkߥ}mUeéšĩBJĨ# $ AL&“!:28w<1Góõjd&…X,Ū•vŠ äŌUcīåR:]ĮÐH80æ,Ą(bÚU{™‹ĐžgáXČÂÓe zĢBƅãđ546rØáĸTĻÝ DĻXõCöčÔÂZúĸÃN`vÏ+mNË✭õÕ[5ˆœĒāÆZēāHb&"r‰˜$KĘäžþOÖ ’‹Lˆ2 ÃĪ—74Ö;ˆ“!7—={öĘËÍO&“K–,IýNũĸ\JŧŲNÜ(•hh@Ä(ŒÐóƒ%sĄ —–k\Þʁ(Ԋ{˧‘(™ĀĀYQHo–îfz 㛒ā EāÍÄȏ ã8…šHGŒģL“@-šĒ-YŨŽA[ŪĢí—NeւgÂŅĸ=Ū0'NH`Đ9ËŋU§^­Áþį Ŋč(}?ŋ·m-wîŠNQųßúūČ0@ûŋ2–ü_Bó!ĸ›$ŋÍÁgTVƒĨßþ§K`ė…Â@„œqå―gpÎ#ZCNĻÅZ)cÆX­ī'’)ã&Ĩz›Xð+ėäU€;Mŋž―z§ĻbĨĨR Ūx<Îûj9įį^[ÖļpŒ;ŦðtÛCPJēÓôY62ԑFŽRĶ q‰Ā/ô!Xr žÞe!Aš]2&S8IFFÆhcũÁPktË 6í Kų·īt„!pœV`rsņŦ/ĻũöÔ! ÁĸpŦæóåIģà HÖb„”›Í`ķ;Lpóo’HaM‚2ģ0Q JRA6 @Ē• œĖ·ČŽ€•åÝ Ęĸ‚ #;z0øÂ*ŽŠĄœBôWw› XrũfjŽÁˆQ^6ýëÜXY…0âXūVŽ@—þ”ĨĀu ƒ1€ĩUXßdgP‹Bāø‡ 0Áĩ1ŌQžļð-\,ðŌVāDŽõÜ*āB8õ ë=ĄĢ0BC$TQäšJđԊ!ZWðMÕ%Ríī֚šššuëÖy;/øÏĀ·XųfƒÜœė†ú"ÄchīąäâlšĄã"ðkbœsoÎH– TJ#ĒģxāVÂ4'X+g4) ;WŒT‘ ā ÓÆ-”IÁœIO 'ØĐÓs&Ccô›~ü!ķd)˜Z(Ŧƒö%PŊíĄGã]WӅOëÎđðĻ!ûúþ§UvÖýøáĢâÛŽč‛īū5`U#ú°ōŊ_.üTžø>ãLöúí|MĮhüĐöämŽŠ—>íp`æßz.Bđ˜>ŅŽŧ›–?Ágm?‚bĸÉ)BíjqųæâûmÏlPægą|ˆ\ĘËՀëŠĐu[Č@þÚ#lI–šā4€č_ mÓ§Øq2sqÞŦâúļ@V@ËÝÔΉÔĩj*0ÔēÄŋišøh>åHČŲV_uū-ĘøëĖũũhxãxŦād—UYmEӜŨ‹QXŊ ž6‰Q8ĐY—:‹M\ ēä5 }ŸĮ.Sô°D"QSSSQQ!„`ĸ1øŽ–1–““ģąĒ€‚ §OėĨ žîēŸ\)Ĩ­&*Rș”\ E!C@ æš.Ž[Ņ"_3^đÆä™[5ԁ ŨZ€ˆĐČΐGSÆtˆ· ™pTf†ļÅĖÉUdÆĢ.ĒÚ’mõ)Љ—›]Đ @˜C#蔯 9\Þd@)ĀĶ đŨ#NUčōũ۟ãŦī4Čý2 ĩ—t†(tEl:ū;B`"ˆÔ/‡Ï Qq…1ˆ4 ØEïŋ0ëmß@đlóĶŧ!øŦUD!0Žß&ŊŧŦTzÞj5D.^øņ6Į]ķ?ŧûm š [ð%(N™Ð°ęÖ#8Ž]ˆ*ŌgÔDų+wãÜ[M·ÂwëÐm„ xð― Ĩųķ(, ōĀÍw€ÜĨšæĨõæ+w‡Ō ôæéķuä>Ōėþ'Ó€0é^#Č,Ō'žMEX7Ü(ëŪ™Y>ųB>k0Ā Ó&b‚&;x7ģÏ(•ūoZųïņ7GJTÓeø.x Ę[ØĒlĻ]*/‡™ŧĐįßVŋ`åōšŧ1BþéãâÉ—Ā á’oėÎGęËŪŅgAđý1DSāLpáz ļ7,§‚€ÆzÞŠ’;Ą&y€ˆÞ4Ė…6īý Ú;p&˜[ŽgČúô雗—gŒ™7ožwĸuG`@ŒëŽ €0ü'Š^:6ĩʔKD0..0d‚qmRðŽ–Čįģ†,sh^zkŸÍ–s` 2âqc­ÖFJ/îĨļSöK*Œ@)89ÎÎS€€äŽĶóŠ6ī…VĐm HķåŊĨ.=ĐP@Ēl#Κ/ļïMĻlĄ§þŲnӒ―vä!ŽÎ2g\cöÖx·öÞ]|ÖFÐËðģ/hïKôyĮ@r‰ļðĖEZÞO?|:{ņ.öü+ˆœv:O}@5ŋïJþڗPØēĪ9íRÛzƒļįn ëÉv7NáŨž?Ô@V+}͟mBþÄø—åXö –›ŽeŸþį4Úq7éC†ņŨ qÅg⒠τúJĝ &`Õ7li†܅?~7Ÿ=—æ•Ų‹oķ]WŠë/Ãu‚ö§N=ĖFþÄ-ü‰ŨAJ{Þ īð|ã#đę sŲ=6wИy –)ę<ȌŸjŧįðëĶðĩĨīīŽÚØu„šāȰüî‹1~˜>~$Ī…ÐÂzXļČöŧļq1…G @r–ŋr#ė0ÅæÂ›Ė]pþÛbÆLŽĻĒ.W'ˆŋ—þ y=ÕíĒoڇ_}1[YAÝ{ékîĨL ØŊ°(œ@ŽþVÜz [XO#ŨįŸMȞŋ]<ö,°\3þģ]/öþĢü•ŊįáÜZ{Ü }Ėhöý›|ÚõX_Ž&ŽÃÚŊÄw@qˆß, a§QÛ؋PŦô“ˆŠų/ŲöÃ(;!îž ßų öÓSĸĩoē/ßÅŊVāŠĢiņŦėģ/å‰ãõˉ°ö ķ8FKØÃŨbC~õ ֒™ōŲĶ'Î}UĖž Ŧëčā+ÕąûāÚŲbĘ―Ðūį,„~§D“φļAėõ—aŧc)Kâ;/B]Ė\~å ČïeÎ?—ĸrŧãŽ)ūŊŌũ d€ÔąÆÝc€~ĘülDŋÃPëc„1.oi3.ôÖÆ6p\TæĨŧýs΄›5k -ÕX˜ģ_ôÏÉË-.n#Ĩ ÃpîÜđąXŒ1ö‹øČE@kEČŽĶ8eīf99ˆĻAˆJNuœ4ļ`å~3ø­ČŦ”j Ģĩ”1 lZĐKéČëÅhcĀPĶķĩŽÜrLë#Â+ė?!į*Œ˜ærŌÞÆĐːk›îÝ'­WÃ$ÛĪ‹Ķuäm+œ<#cÜ'ČÎZb ÁhāīŦA+P.}k\‡_­0“nÅÛNį―K={óÉ·ŌĪLÞĮ⚉īí;ķĀsāŠdÏŋoΟjöÝO\z‰č6\ïĐðŦ·č óÍí'ᜇøõO›‡_ĶėđüėÉĒgO›ý1ŋãóč‹dįˆsŪÆšz(h€^†}fšą{&ĖÉ7SI.ŋú(þņ§ķįÁP―œ}ö…đá>üð&qÕÕfúŸmû§Äc/č}†€tégļžßy= ?E4šßu>ĸÂC,[ŽËr9T/ƒo˜ëî^‘<þ|Øëf=A‰ģ/å{îIŸÏäũžnŊ}Čt/€ŽBđ4Ě+Ūķ%‘SÝīŸy"Ÿr+=t–}s7šûĄļô^~Ðņ&ï[þėŨfÆ%`<Ąz[žĀßHÁ/€Ē öÄ4jĒ9jobjVˆ‰WÐ>Ũšļ8v<9šŠ“øå;tîõú€ýŲ·ðūĸ9ĘŌ 4]Ęæ[Û XÓ_&Åuã™Ü_?t€8ý0ņņvš[•žņU=ãaXųŸqŦ}øVˆĘØ[ošŦnģC?įoūˆûlGųÍīĮ‰æË3.cŦOĨü~þ:wģŲũqÜétÄÕzōõâī‹qþéÔ7ÂųŸC’ģoáoŊRŋŒ·Ëg<ĻokŧtÂ]Ū2‡ ų|EŌLŧšæąïVãš8 Ã%ïąŊsôu3ŲûŨąw^ģÝ2ĕ“éЙf`―8e2ÛfGĘMāĮŊÐŲŌW%&_ĮVŸhûä€ZÏæ#ŌØ_B‹}mÛD8§vƒlŧˆbvŋÃŲ’,=îxâ–úmÏÞýđā5sčųfįá€I Ú,’F‚ýC-9sÍĀ͟PЈ!Š˜Ô‘&°^úÚxõi?­Fd›ād‰KofƒÂ{܆I)CjUT<`ā@ĨTĘd?EaðÜߟ’P\’Q]ŊŽâÉŽžAũ~qޒ› €72UĮmãuŒŨpŽåŽZ@·UŒTÓað§JQhÃÍík••‚Km―rÆĒ0bÎԈŽÕčƒŊŌ ]WLDaHäũČSŋˆ1_ŽķÂiw,rgëĀã’^Ÿ‚;Á/Ã]ÞjĪˆÂ‰ĸ2RÚKĸҚ”ՐŅySöšM[ņj{ŽÞˆV1[AC[‹”I?uŨ`ęėČsôé{ƒn°Cå°g.tęgΚdÛhþîÚí@ģmg€bķßļjfŪ„]v5#:ڃރ0a:T§D­VŪÂgŪåeeļĄŒúĨýČčļËĖöÃøw…īۙĐē3ģčåωÎqų\\TaN:€Š[Øíwd_üÖE=ÜüņËíĻÁļæ}PĩðÆ4þaÝĀūüzĪwĪA hՂZįÛN ėeĻ(2H- ėˆ ^ÆúŒĶŪ°#{ƒíHýïgž ­^ĢŽû˜ūÅ` x gË?E5†J2@'€(―†Ū…ö€ąâþ™ļp–ūh:äŽĮï–ĒŽo‡PŸÄōJjmĄĮ@sė)”Kwe­_äįiS­ãũ.1}2;Ø^ýĀ4TaX ‹žä― ŦŦW-ƒĩËømįĨ‚>6ôĮúFˆ’öĀÍáŧÃåėÓ ÉĩėÎ Xg0­ Ũ}ÂąPõĩíŦO=Ãķ^G-Ö4šZŪpÖK°Ū^\xŽO@Q5ÄZQÛ hÓŅķ.Æú6”™iŧv&Đ\"CIāyĐīݎę‹eÛā· kVáž%ȧáˍؐčU”ĨĄÏ0}ډ”\@E\€þ rŧÚn=€ē8ÔV‚E`žĖaÄmv!īiE•YÔРЄ9mŠ=%ÄîÓ.„’lqĩļz<þP Ŧf\|·Þķ7Xó{ ĩÆš Ž ÐZ!cĖÅ&ë Äž‹SØ$/đŌäA–Ž'bcĒH Á™ŪȐv0MŅšté’H$–/_ūđz@^`IvéŲëÉÚÖ―2{íãÜkÁ&]ˉ 5īK@Éļ’°EŌ Ŧ$[Įĩj*†šŲ ˜bZ™%-ĘŨŊs†ū…žÏrL›ā:ĸ™ī XÁ„V Ņ@0Œ"!˜ÓŽąÖšÔUHãĒŊÓVäÆX/‡æ;ÆČ!ĨÕ֗>‘qgKgđ ÕNÜžĶŽ 0Îa‹ƒšo0āäjŽ(Abųæäíð" NYĶŲ‚’Ú ŠÆkĐg6ŊÁ…@ „ÁՋ0âU°z5 ȅL‰Kįēĩ•TúΞGÃ\“G·ęĒŲÓŦŠĒų]ĄáéU‚{vĨ0Ō@ ĀÃefkÄu•Ð'W.ÃĄ}1P`›hčĀĻ0OäįĀ’yX“Ī|‰ŽÂĩĩhT‹kKĄOŽ_"ŌNĄ+Äõҧ§ÍbíÍ5ã@ōŸŠÎņý'hiDۚ,X[  XWƀBsĀ%f—ÄĖSÅ#é3ö†V-͑—ÛÝ’ą‘ƒ•+ÁZˆ4(]õ/áŨ/ŠqWØACiÛvļ` w Y@ér8p a#OŌ㐗Ÿ|Cíšësn Þ­A#ĩˆ3m! ЀÐļZL8‘ÆÜŦũČ^ÂE[k@8ũˆ ŲÄ,IhßÚdčëĶR ™† ØØāęÂĄÖ|!Į āNŠð8ī,2G_iĮô!M™‹ëūF`Ü,›·ڗPÛLÐDCƒŧ.ā~Ŋũ@øņ ļ6Ú톕IãĀ4@F&‰lą$Úzę^Ē/đžę5ŋÃŽÖÓ ČwÕščācđũÝũ*wZŪ>7ÔJ“ßG*Š|töZÚä+ˆQ2ėÛ·ŊWE(++sÝNÂYr|ēåēaEfĐ đēÃā øģÛKˆĀü@(í:;Œ:EÄ@„ĀkŦPƒĒÜč*ŒŨ #ÉĻ#@ŽH[-Ú9N"ĶýÁˆs…ũĒ:ČīóþâĖÓä|—…ĢEx™.ÁÐ É@úqĢ0dš Œ{ˆā(Ĩ4J[tē֛kū.‰&ØĒ°F7…[‚dCzÅY[HFÔyīéŨ“ßr%î;ˆĖáįS!€uûō\6ĸ^1ĢꗱŽmÕÞ} 9’  ˜y(æJ9iēËØü|}æ(ĘhcýT\t+qm‚8u 2–8äĩ€ĩŸˆĮî‡%+qÕóėÐŅ C íÉREā퀙ŸðV}ėÎ}ÅįēŲņóg ÜŌ“ōŸĶÁĩĻwÛO<4ũ†°Ę~đ9þt\:NNg;g@—ĖvqårÆD=á|ŧoWþį‰ļ` {ïS:ėR›°0Z§ÏØOÓú Þj;ĻÏO…äŪ`_ šÞŒ.ėķ‡ōÛ.ĨíÂÄŨæė€Õð‡ïÁZŽ5D]ÛQË>æÔÝų33qÝÎ*ŧÏ Ô‚ ™DČþō.á *h„žP š–ý°zœLE  ąVfßãÅMŠžjbuīëÉvøþ4ôqqß ;ī7„EæĪąnŅĖšJQ2ž -ŠØė—Ą&“•o„·ßÓŧHŋæŋˆĶ–ĄdšĢ6ŲĘØ}OĢw/į7ÝFâÕ_Ÿz uï,î˜ýŊ5íڂZ/ĶßĻĮVŪT Ōþ‹Ôf 9y4rŪÞ ’Úî"Å  p§pĶ —/ģ=Ï IŒ ũ>æ 7ø '‹EG€^˞Ō\õ„éTĀ–īÃÏãwĩ7'íË^| ŨWÃĒ ÝžķC §Ví<ČþNåf\°@ū=ĀëÅ8―A™ķ°åœ\ëW,‘ō’+ÞS ė&=ïq‹D%“…-[öë7 •Ō&“ÉTĻõŊ^ŸÅE:X‘―ŽsC ōzfåōĪ„ŋrûXÆlSé#ßPū†B†™ĻŽryÁð ]ƒ*7D°QšJTn0@Ā€9·ā)0Ąīp ôM`RJïŽã‚=·ÆšĐUZõœqæŊa.~ÆdŒĀ: ð&=>yįNŌßBšĐŨŦ†ŧ…GC–ķtDívŌSR6"yæē;Ą]!(fNšÖŠBēYæŪ‡čÓwq}#ĩ…LDāaŠĐũÉīMg(ïūĩAcw}Í­T 4uÛAÝ{ûäs ^úØ1ķ[>č!ęūĮØŌ ĻįŨL#ČĪ.#õåÓ)ßB„fï3 ŋ+$ģėž‡á ČXÚĸ<‹…)ŧßđīKD ;J_Ŧ(æŸ D9õfčųč :ðP1ŌlŒî/ 2ö€q–·‘öŌԘ7Øō*ĘčDŲH-vŅ7>_|ŽZPŸŽTÜ.šįķäGbq}ölöûļķJ_r›>"cΚ9ĀjWī  ĪÐ ßßķŽC˜!Ųė åvĶ]>XŦĐįhõØlÎw15é>;°7@‚…ĨëĻÏ%vԎ„Úw#uŨn„ŒBj•Mđýõ57R†EÔĄŊ\Æę;Îģ]są|>~ķĀĖFÛïXšŽÉ(:fž28U$%PQ.e·VW?Ãf€Õĩę§‘Gę>@Q―vŅã†SaūęöųĘëiũÞk3Ą°DOIąZ Ō·ÞAm%Čb}íCÐĶĢŊļÚIĘÛQÝōgöélPŒštĨÍ)·PÏũ!`TÔWÝp'[X ƚŽą9ņļ9c*äCŲQĮÚ!œĖI·RŊ·q}dī –Y”9TOAAžDOžÚĮpÝbüjĐ=šŋËū‰”0ßM;ŋÏæŊ€Ú8äeã“wŠUæČąúē"ŽÍTÜ7&hĮÔ.ŧS~žizAŋs „ ĮŸĸú+/eddÆãņīœį~ĶŽ#%܌Ï:ĨÅ&Đ@â‚q–ÖHdMÛč ŸN(+ŠÂŪÝ{ÎļáÆü‚üTõāH\?éöIb…müŪåšY2vÐá­ōōl z [ í§9ɐ۷v‰iœÖ|‘@ŽÂđUũó$cdÜUQīāúĖŨ%ôE‘7ÖZ­\™ÅQ’UĪÁũn•d‰ÉEImuZ—ņ(ŠœÎ·Ü܇Ę•ŦHx%I'‘ž 9O6é<ÍT…Éðð#Į^5õÚĸĸȰj-ÖręØúv]ĨlŲ<üa-äĩ7C‡@&ük;GÄęuXĶĐGG" Í០Æþ§‚Ōð{Åß į΁1 ŋÎØ&9Ak\Þ*ÝäŨxá.DðÆąČ™kNÐÞØFkƒĖâM/2.EāLČ-+ėÕ§OŠJjājKéųúeįŋ-qģã? ōs0ŨŽ,Yoíģ)t`ÉĸŸŦ!€“ė‚ Æļ1ƀ6íL–bą8cĖÕ"0mï/NË0ųō !ļÏIëŧĈ˜okø_cé ĒųŠY*lo;ĸĢíDĀÛgsÐafĖHČf` ÜCĩIÁĸúĪĸ48†ŋĨöðoĻp?*ho{w"ēð ýoÄYü;ƒ%ëÃÐŋv1ÎþĄ]ýŋŪpæķā߄kČAēĻ cø›ÃŨú'ΚAýģŘŽÕ4—ïŸ œļœQœ ēVEŠ!đ5%Ũ^ęÉc€ šzþÉ03#ŦGžÆlâãĶ ĩBtðđØ0%•“ 6†õI™Č† ĶA‘þŨ\ē6Š"cČŅqyŠ øâŠ”ŌKôú’ŦŌÚw óÝĀũŽÎR€ģ &cđ+&x3o‹N?ŒČ8Đ_‹ĮÉ îÁĸ&LČÞz­mŒp}4?ŧ5ĸd|!Ð Ē$ÔlÄ Ū[ >ú,ā—oā·k@pðЉôI9þs—úîkļī8ƒæāĀf―Í—þJfĸ;ՕÆ5~gΒ €ėoėó—YoÏYšÖVTTÕ'ĸ―Ąó†ĩË^yoN­ÁŌåß~8gQôïip!ø?)™ÛšƒLueEmĻņŋ4ÔšœËĘ āBDJyåtZĮhĢ]ë>"ĨgʀQ6Yp3kŽõúŲŽ:ÕŪ}ûķmÛ644$“ÉTbëÜü- KôĖYÁÚå•krgîuPŅ1G·;ņ°ķGïÜrB‘Ÿ°Éŋ‘ä"ü:ČĨŸœ3æ”üZXã”tÂЭ "sąÕ_+0ÔQNÁ˕z ÖX-Īd‚+Ĩg\†ĖsÓF nĩMlÚAYcáõą‹ ëØÍSØŌzl\*'\Ā*áߕöœ}õǘzðŋĮï― ø‹ÓųsËAˆôIĢj~ÓöCöO\ŠŠäSÏįŊ.)~öšDžŸ―ü—!֖ã†J øM0õKø-SXuˆ°ÅÁ6.ä7ÝÃV&~yy@Xķëþ:#P=ę:öyŲß ĩLˆï_đuüīD ðo‡ZIŊÞ1ýÅYó€ņŋ―ÏK/ŒðäÔKyë[āþUp)ëæ}|í=Om đėģzâõĘgîQUķķž:ņæÚõUĨkËk!x ãŠę‘SŸý`}ĸĄ] Œsc,#Īp.šŽæ ™ ŧČļÐJïĩeŒĸƒ€œlŦgô˜ú˜įNÅŲ”·ÖڇZOaøgŽ‚CYyōË·+ÛŅØGÜsįðëÏé~Á1%gžÖiüäž3fô―ë”gķŠ4Á+C'ĩ5d­2d}"LčˆŠ,q.ĨÛ°Ā{‚1N™7rïMāĻTˆŒsæ-Íļ+>m8—ū Č5!íVS@åZâ˜ā\ rķ›―Üu€‰ LúíŸj%QØDh+‰!e”čģÏ <–*$ãĻôŽIûÎøķĄfņˆĀÚĶÐ@ĘPŊ6ĩ"Ą&H @„ŽVüīCj'!!ŅčV{øOTú0ôTúŸāĸ “ ZÅ CĶuT"åŪ  Ī˜"§DåDÜBÞƒžûˆ üė-hRhl @އ{‘š! !LĶ%@Ôt:ôãE‹šÞ ›nŽgRbPPŌ}ŒˆēĐįwŸÅ_ûĀ―ÅĒ&A `Ý 2X îT]û&ĢŧŽ:äŽCZĨ-2Ô* #ãC œŽI&“ĄLϒAĶDwĒôĮݖK/Ēd"Œl~,#[RĪųčcOŲk›n`°ƒ( ĩDt;3•úÛÕʈ 9Ț0ušH‘oZĖeZ‹ ÁevĀ›IÆ9ô;ƒ›ÞY•úS[āî™DMɔqíCúŲņãŊœĩĀ:‰Paęģšąô΀Ėj: ÎpÎģS.žōþzBØėÕ!sö<âļúīP‘&†īiP†ņŋ$Ôú^&%VHé4^•ĩq"PZ3ĮOKâœ)§‚ ‚“Õ–,s aÚĐŦīn]ėïŅŌĨKĨ;æÏ IôũfXū!ü杚ËvžęÉCŪ\Ō~Ž’ĖŪGu8õŌîÓÚĊ}īEøí—áž>ũ|öÏé“Ý/ēŅ/ĘķŒqg­%pIškn3œs$°–8įŽ°Ŧ2wÏH+…„Üąl)Ýkƌmēdgčvv·ÐEb`Č<ý—ČsÉ’Im0Ît!l!pbï<*Û/8j—āē™ļFcr™<ódyãÁØQÁyŨa•†>æbī?õ8&~ü€œzƒœvN°ŨyĮãĀ$Ôý(Ķđ·œ4kuÓRFĢļý:ņŌ·0þäeōÚû!ˆģ9ÏĘ_Âåßō_Eâ€Í`?žTÏßš18vLpāüŦ%‹áģäø#ƒ#ĮČûžŧųģĶ^Üsi°ßŪÁeįąE 3@ģŨî”'ïū?ë/€žĐ˜ãÜ·å9c‚Cwũ―ˆ•køįŊã7įÎ*4ÎGžíÞšũ9`1X3W\°GpÄ~rō=XĨ‰ņŸŪMWņ‡&ŽŽØü˜1ó’`ėîÁŅ{ˆGf›”Ū/oėŧœ~ģxpFpā6Á° f…ž~’˜158ltpŌ|I91–f—%ŦşN ŽÞ+8ų4ķŠ–­ų”?õ*ŋųü`ę#ˆÄ_š-8~āøƒųœĨ ĪûˆdïßLū1,ä7_%ž™ ņ42ūjއÏÎ]&%ūwËųWNŸqâqŽšëÃoý DŜ7Ï=ę€ÝöÚë€CŪY§Á hãü &ßôÕęDLTÍ8éôŧ_œHœõøÕŧė2ú°Ã}hîŌÆ &đ™ũæsģn ĘĨWNđjúĩŨīãĻݎ>įëõ 1i?|rÚč1;}Ü᧏=ęŅũ"įþZb1óŅã·ļŨžcÆė>é‰ŲBúaaþ˜ā‚Ŋ_øÞĐûíĩë{0nB™•ŋxõĖCŲgŸÝ:sâį‹Ĩ4oÞxޕŨßpÜŅûķį“—W/xýžwßų’ÓŊœųDƒē_>5㠃öÚuŨĢĸ`Ќ‰o^ūõÜŦnšpō1ۍ:ņáũuÝũŨÞöėŦOÞtøi3VŨ*ÆP5~ōéߔŨaÊû&ž6uúÕ{íūÓîûœđ`}$ûoĩäé^āœÉS0ĘžķrņYž3ņĩÓNôĨXk-ūJ!8;Xkˆ ÎæīėŅģgŠĮ+å՘2Ûž Öž\û7gs†vîĮe{{Úö‡Ä9ƒ&Ô$’Ĩ ĩЄūđCÎí|I.ÏIgxš*—VÕmĮ’Ėö]ēzĩZZēŋĻ*X ãzđ~â2X‚Ā_#8gfģŲ ŨZ‹Ū€ë<) ó>@Ú ‹Bå‰ ‚3ãú ãˆčÉ RHk,y[ kėc‹!Įē9ââ)°ÓdõÐĢīá%qí=Āŋ~+ŠôīÛiå‹|^ÖŅqŲũ kVē§ï„ĒŅæŠqøÖmŽZó;Ŋ`ËÚëGžĢÏóĮ?Ádĩj`Ÿ~å+ņƒįØó°†*üøŠe‚Úˆ+–āßZ’Ū[åVOú;Äð?MÁŠ21årluļūí|č>kmšJĀ›ózūđý}ÂĄ”Kd8–ΖSïĨãŅÄïļ“ HŪ/ÁaŨë['ģį§ąqÛŦ7írĪžt=åŪ—^ŒÃŊŨ·LbÏO+7ˆ™—ēŠQúÁ§ė€"Ļ­þébÁŸžÁĸü𙸀šįI;ī{įNþė23õ9=õ|vë1k˜öö‹ßA_=Ÿš‰}*ôĖk`á'|þJd?y‰- ôŸĩY øM v·WĀĶã|*õm/ہV<ņĩazwģ_ŪÎ= ū)n~ՌØķ#ŋþ6,ŨĀČR·Ū0ûa\T •‹øû/Û]Āę_ÜÉš ßĖĸķ‘mX>ëū§?;čü™—”yĸÍ/'“k.?áœ5ycž~á…ûï<Ą€“ĸÚĘeß-­ŦšW9geTS1ïi·ŋrĘīûîžqE— —―.]0oUY5ĒžũęÃÏ}žqÚĸÜŨąėƒ·>_°á›7§ÞüôĐWß{ĸŸŪĻZųŲ+ŒŌ­úïõČ+oÜwî_žôŌĘß*Å#S—^}æ9õÃÆ>ýâK7Nš4?đðâ/0―ÏzõÕgö͘{îŲ3ë(ķaéûũ?;gėÅ7Žß“Ý;óđĖūĢÐqĸ ŊwúAu _wÅó'ÞôÂ-ã‡Þ9õęõZ„ĨóŸšûŪŸwãÄÃf=tãúxŸ“Gũí;ôĻÛĶÞ.[ĪSwHŽ]ôՆuŠóč/ģž{yqæô;ĸÔŨ|õ› PČĸŠŽÖåĖ‘,h•憑%íféޒ_āSZų‚wģ bÞՑ,"9hÝšu·n݌1ÞŨ7ŪúPëi%zü­bāßTĩ5%·ïNVģZŌšoϘ{Ę^ũxņÓŨ5ę†ŒÚŧ耄MbumĪģ{tę ģ]Ā70k4s=ZŸwãQĪČZą ÜÕD)Ĩ―ē­KÞÝÞÂÅ_DðĢ3dürąE°éܖGQĪ\_ĪŌŦŲZĒ-Ö­ĩ~tßNŸ6†Zõ2Gí‹ucĨŽ}õų“mŋÞTā/# ØZŧÓÅjÜņvðķ$ģÐÔēŊãōwøųĮēÕëŲš āé‚FØíw‚eóųŧoĄjG%ų;ÏģÕËí6Ûģ€ėïH1du3'^nöĩû å Xö#~ũ|ųŋėRhHēĩëđ‹á€ï―dmtēCũĶö1ˆ+~SÆ:—ßúb"ãWų7ņņM-ž>•_5ë,؀ÚäPq+ÛąÔŪFÝôV#RMÖEöč}l›"{ÜŅÔĐÓ+ā 0Ĕ„Bï“ĖNƒĐm fāę5öļĢĖÐvÐ>ī Ã5K ‘Ī!éӎĩýzPĸ=õ%įØ!ĢĻĪ3ĻPen§/ŧĀöëkŲ•JŦQ‡°j”Íæ—ÃÞüŠP€,„Ū] e*ĘÁ5+`Í2~ûđüĄ§ąŠü“—:6CóųĮ/ó7Ãi`3ð‹Ĩ!ũoUfų‡NļöĻ†tíڃXuCõĘoēb'M8ŧsQˎ]šf"5}BHæH5‚ Áíšßþ˜ąÛvÛ kÛsÔ.fDøD˜:Ûq§é·\ŧíĀa#JšÄtbÝÂ?fï=jŧa­ŧŽÓop͊č§ÕŪ7|tņY'\ôø;Q<#Ž@ŋŅSW_šdÎųGŸpB—6­J:•ČŠesóû{Åūy%œpT]øqi‚@ķ:âōk5ĪKįn֖YYTÜ5̰mĮķ- ę*W~WŧæÞ Žŋė–ˆošÞÔČĢŊ:ĸˆ] Ųcí{õČČiŅĐC+!šN€N˄QÐ~ÐUW_2jČĀN‹ĢZ ˆĸl1 âcÜiē wpÂ]>,Ē3ãž(eœ―Ū‹đÚgÄÞ―Ņ5}KgĄhûôíË9Ođ7Ķ1ūÁ š~ĩŒ€åfõŌäÛėŌą  4ĄZUÞđbfĐý>ÞÃÞøō-m‹JÎÛé(_ÚŧøÐũ+ßĻēÕ –•īoÓē82šŌ]͎oŒĄ5Ę7Qx­ï@Fk!…ŋÂ0qÁŌ&äd…Kõ•VÖÆļwr$KBpï….„d ÉĨŪہEač:ŽCg”ÚäëN[Š_XPąˆ­Mw‰Ŧåƒð‰ŧ…߀Ę P \§;dQŧ}ô'SŒ#Étg’ÖÔqĘļTÜðķ9âIÛęvqŕ4ręYˆë,üôˋĢŠŠZAŲ:ddA‹BÚë,}ü2x B@@ ZdáÜeĻÖ/€ €K-RĪ&;Ž%XAYŽŒƒB{xJ a€CČeŊ‡XZ)HũÖØ+Íþýe„LWâę2Āïū†Š:@Öt ó`ŲwŽ:īų „ÂÅKQŲr(­…x` °I0aZĨ›ÛˆŊ‚Ę€§ö)}ƒ?QŸbÐHņiï‘MûÉۘÆ"23ߊŠKŨÔanû–9Dô‹{Ë,f /b" ™™—Û~?oåá}JņÓî:Ų@ĩĨŦ7”UwdĨČPåaĻumékKów{yhĀn,@Ôh “)Į”ðŦukŨT­|å‡åÃvžž—ąŠϏ;įŅÓîēgÅ3WžYiˆßø 3ósƒęÅËV@Ÿ~&Rbąš%ßþP;bDaÅęųVåÅ82‚,Žn‘9DL"ŲXQÚčBk“Û~üuũîÐ5ÃČ‘jŽŲ)• Įų0‰„^C‚Ad~yqÎļÓAvvčŋaYŒˆŽsl!}; ߥeŒ&WÕ&k!§ĸ‘{Ũ(ĨšúO­1&Ŋ ŋ_ŋþĐ/ßéå;ĸY3 ûu=DÆ š,’,ŦG·!Ð ójŋþKí7Y<+ŧEvë~…“Þ{x}C58īŽ{,[’Ø―Õn§lp§œ–ā'óōD6XcÉü”ÏŊuäĘÆA@ ĄÏg―+%ãĖ[øĢ―SY"·ģÖįģ ‘ĨôČóÕÞ N>9cB — wÁÚhƒ[HċšėHÝ;ˆIg‹›&ðį–Ų―NĨ DυGÉ7ÔlÃ1ÖÁJH(ÏaĮd™}æé°ú)qį]âÁ”āÞÜôJ:iEv›N@1Úw˜ūÔ&mŋ#Ixv|ée.@Ð"Ýü[Ä ËÅĖÉâ–ÉâÁ‡éāĢlį~æī}Ø{7ōûĸ,îŧ‹ĸĨĐ3ĖŧãQxRŽ'gNdĨUˆŠšîj{wæ7Oäþ™?ųgL2·D:1„ý؃WóĮîįĖdëĄ_üčyïý;Dïą{ĀŋuŦ’vĮÝŲS7ɉ—ˆ;ŸÆrEˆMqH˜”Þ`Álqéy⹋ä+sėvG‚ũå”)bŌfw0ÛB2 €”ō·Q;ĩõޟ+îŋHÜZĐ#ÞØĻÜÎÚ$“– Û€mėŠŨĶN{i]Ĩf !­ÕĮ”ķ@6™hôÞö:ēĄ&øßŸ0aü‚XðÖŊ/Yž()Ĩ3ÁŌāč^J)í8 BHK~ĩĨāâŽ38HÁ)ˆ§@ÖĨ·%:tðĄZëü1e&FŪoĸ';[2v#j2Š īí“)Bāú… 9ĩY3šĻ0#šðäęûV‡k0Æ1JP͒ŠÃ†ïÛ6·ĨŧÅ)ēu؃o~ôÎéî?h—€qpč‘Ý{tËÝwnĩįēÄēŌppšsĶ’jßO é" 'hI)ý”߉3ÏNvŦy^^–‰Ķ}…oÛrfŌQæÐbÏĮu"ÃÝū霗đŲ\†}ûõģËŪQ5WTUUK)ōóó‰þ)Čŧë* -ėØņf~`° •ī!ĐŨ0ęÞ 2b~ƒērĐĸęPLE=hPOh‘"›Œ ö­Đó`;lÂō‹Đwj™þB,Qũmi§=mïNŨvÚ͎ !Ŋ- ކZķLoQ§þ4 3äÆĀ%õÝÞî0Óî'č}ũRÔ?@ŧĢ1P܉zõΜ8Y(îm‡‡˜ī;g>ÐčMy-ė>ŧoŌÁē1ęԝ:v‚.ĻwČČĪwąý[ĄâÔĶuíN]‡Ņ°Ū›^/éEcvąýšÞęÖŨ߁zīxK{Ävĸ]ĻMŦteŅh՝ķߕ2v°ýPŸAvŧÞ`5īĪÏ:›ÚgAž€úĒârĻčT2F=ûSŊąĘė^ûAAŽÝï3z0ˆ,ę7:ķĪķ]ėžĐ0Č,Īž}Ļe ę2ˆZīÄXKęßÓnŋÄ@fQŨ^ÔđõLÝÛCVēŨžĩ‡žc‡õ@`õkŋ~ûóĒãčoĩõ6ŊļũðÁÝ[fķî6pPïî™"§Mm·ŌūuaßÝwÛfpąĶĖŽÝúöîÖĄKïúõ,hY<|ø€žüĖa;|úĐGnÓ§{ëķÝwÜuûœ#qøč3Ï8eXŸîđY%―účß+ŋ uĸýzwiŽĪŨ€þýzķ(đÃzõĩ݈_ŋÝbøūÛũ-kÉÚX^‡mG Ę͊ßõðãv퓟_ÜŦ{ý”ķh]’:\ëÂFÄdŊáŧéRņŽ=úöíŲ{Û―wЊ%({‡CÎ>õčm˜VÅÝęÝ-?Cä·ëđi8E9먧WvA‹ķŧôÜé]‹sEVįn―šunߊ]ę&t+*ˆËŒÂ#ķ)i[Ôē}Ïá}{tïÝ>#`@@,Öąû >ÝÛæææuí7ž{Įvq”ô2d`‚lIDĸ!Ēēēōōrą[€˜{Ņã^핮Žė4 ŽŅŽÝęŨdhŠHĢ•öj­ÎՑīDZGN›PŒÚiįO>åëŊŋ^ąb…q0›―lÃ0L$Đß:ŒAÍԜĨĀ,rzHËĖlîo—øÍ+å-Ãöß\ũ>4€.øîøE ‹9r!ą|UrîÏ_øä=·‡g}>ö‹6Ny=/3þ ĸlã<9„?ĻõŦx\ļ+"dˆ€Md\ÖFÎ[AHéŌYÃīÖĀžbŽą„„(Ð;’ų@lĮôU‘ēNåV°tWsÆZëDcÃĄ‡9íš-́ÐLß@ŧž’AāE 6‹!@ÓĶßbÂqÛÍÏDNf­ú™—ĀŲO,{åÔ˜pÓķč§ ! h iļģ3Ÿ„A4ÉčLģ=ŞKŋÅļSNðî;ĄÓ1pdųæb^ņ@Ęī üÚ[˜vözÍĮՔV{)€ĀՎÉýéÎîœ1ÝAļӗpw–~(ÆĸđėF;0Œųi­ÁŌO·ŅhÐMęþŦņÛiō˜!Ājā‚Í~VL~]ß}Ģí”Ë€>~pÜĘ.įŋS7Õt3—’ŲP.cĖ*eėĶW…Ąg“ĘŅ‘"’b`”6–ðâ^ŒvŊČ@pæÝóŽ{Eø-’kĨÜĩĮk–^tþÕÉÜP=įÚÁßvÅ âĖĶ@ƒ›NĮÐņpXĨ,JŨ„\8‘ÝžÆsxŽcZ`A0 Eît2†6R†˜’Qid"§Aj‰ĀuzÎ )Üވ\\…Ą? ‰Beisã°ŦÝũXBHīZiûß =þüsÞ}ë­ #ĮY@ÆÜ„@3ĐHmNKĒ•{Q;GB/ƒíjũˆ\ĘC[ÜĶMŠÖŠŒCÂaSo]ĻSՂĖE„ĶyĻeušū~ąīgį―ŋ:ëvhBŌ&.œwŌōÆN1+ËĢo_-›~ôįlw8|Sū|ė“į>먑‡mWÜĘ+ĩąyAî5Ë.þžjV*Ô―L—]UŊÁkšļaäú/xڐ<ˆ@LéÐĨĨŒœoãFéŸÎŽ“éâ ĩWŪáŌ’ŨýB!ĨnŠBpÎCGũ0FzØSĶ^ó›Ąöŋ[:ąĐÜš en G,ŽZ‡ĩÜv(F@Ā„dĪĩĄĸ_dV­Y>þĒÕ&ĢÅČíGīĖ”ÚXøC◡vK8æ —ÕY؜ĩ! C.ĨŠīOú† ’E`äúĨĄ_B@`Îf&Œ„”ĨeĨÕ55>Olj•RaúPKĘTÉz›aņŊVČmhmhķïÍ MĻl“ÆĒ&pķļēšÐŧ°hāðœ wÜčóķ;ôrpxdÍÝģ+?Í ōŦõ†8§‰đŪēNĖšĪ“ųĮ5㈜kļŦ†Ĩ-)O7pĩ€Ėđāhíe ˆljîÄ―ž@ļ/2˜īažēl}_-Ž*ō)?ŊŊOęĸLzŪā ™aéōÛ/;xĮGsÕã Ô­úōĒãŽØgÏ]v?kúÂjķþëįïgVjįëî{3žUĪëÞ―óĒ=wßýŊxįóeņŒŒdՏžóÚÆKŋ}kÂ1';ð°s/xGŨ­þӄCũÜwÏ#OžrŲFąĨŸ?wäŪŧîđŨ^ãĶÝ<ïŦŨ~wÖģįœxýCïnøāūé{ïūį{íqþ ÏÖ+ŲļvÎMWœrÞÅ'ŸuĘŲĶ]zïĮ?ČxÜløęäCŪ]žQKÁlÅVüB-ĒŨˆq6Ü‹!` ­öēčûšųÖQëÓRįōMN$Û&Ą5Â0Ec š€M`œ{!DCĪ7ýϐTŌŠÐšĪ5š€ĻķąČÁ§–~IēĘüyĻ5d  Ma$_&ðp­#”H„ŒqÏōbŒ"ðŽëBŠ  ‘ąiį4J?ŠŒ3d@d”ö„:/ŅëIš>Ag\ø–8ðjF@nYO‚ÖÞ’Ö]ÜgĮu}ėh™.Íģ…ï=vÅ _\zï ·LŲWTUgšĄbþüŋTknåģ?šÕéäqÓĸ4ō;ŊyjÃvÏūôôāŒï|ųģĘe_\~ÎĨmŋøų_œtöņ{ØPĮC'Ï<ãȝ―s߄)Ï_tóģ/üųŌõO_ïëßĢI|ņök‹Zė=yÆÔĄ9Տ?þzdõŽŨž^Q’Ņ.?ncc ~­ØŠßĢc.‘āB:ąZpuLWpīāäŠĀIzåA"2ĘpÎĨū ßŊĪĩk߁3QSS•L&R bõõĐ.âæģBŽ}ĸ?9•B됀H%-šxh99\Vąī1`―î"GˆÍä― ,ĩ›3_"­Œb@. .OœÝÕ§eÎãņŒ>ýû7&RuŽZã–é"íÝ'! C ðæļZ+ŊÆëˆ: ąE‘ožĘ)ØzmÁóëĒ(WĖÕŪ3ŒqHi œ# ą…B-Q,·Uë.qÖĶcQ~ÎúDcŧa;^rę~Y ÞčØž1•ūųā­“Ëíęqđ-S;Ë6Š[ä$“ÔēÕ+âÛîžĮāv™°û|%0ÎP4$’GŒ>éČ―ÛPų’ę į}}ʑoXĩjŸÅšÅsVu›päÁíŠQk0XÔ9žŅĶcŦÜØGŦÖfízðÞÛuˆAË1û?þ—Õ‹Ýâ9―G^~Îą=ŠXņÁco{ų‡_|ýÕo>ëžūÞgdķČEka+ķâwjˆ( C,$—įōÓĘđ3į#k`l 8XŨG:tøˆC;<Õ·ŧzÕĘ5kÖXK‘R)EpëĀžÕ.štX#jēĀ‚dĢ1FLh€o7ŽÚÔæ,Á@0)Q5ú\ĐĄ]fŽŋr Žëa#‚ĩ`Ą1ؘ#r"E*"äD^GÐh*Ę-ØwėĄa”Pa*°Ī õ)‚`˜LĶ8ĕ+ęjkS/:‡ī( Cķ0ĩᚷĩŠ,C4ZkđƒóŨĩčj“Ž_ĮđtŠ4 ˜”2Š"GPöķŧķˆL]}CTž@Ũ…FJŧV6‹\WßqŅqŸ‰‰Ü8|ÂąĮÕ3 ĖĶ/š< üŨ‡qnܰĶ\AáÆÅß/øĄßˆ iņÐÝKŌ*āóÝdA8keĨ•ŸãúŸCdÚé "‘ĸ béúõ?,]ZXX˜RMdŒÅbąÔvJJŅo;WDJÅÜUŦW-XīhųĘUu5ŽŪžŒQF!ACB3â`‰2 o([―Šl}aAĄ”‚1&ĨĖ‘9”Ķ9$ (ęÞĒ­Ö:‘LęĪ^QąĒŽš4K44–VUT%jBÕÖĨþŌ!7„þaÔ`MD ”óRûđî―"pūÖ)ĸˆâââÆÆÆ–.ÎÏ/ČĘÎb)ĪjņÔ[ëÖŪųþŧï‚X 8ũJõœ kˆœz—ë;vÓKĐ}œR8—B%#c-ā–Kj1ãč)ũwøôólŽ%Cũ›rÃv&bG\8å†ķ-2Ošŋxį/j3;{Ð>óV7‰uÕí>ų<_rŸđm[öÛãņĮŠ>ģ  Í ŪAnqfváESfīÍ1bčSŪ]ā;Œ9øá7‹?œ―\ƒčÓŪÆ[;áþÎ#Þ[W•ČiÛĩ07ũ˜Ŧ(ųė‹ly―FÝüÄ]ïž?§úï}ÖÎÃŧg'6ŽžhrIÛ|ŌˆŲŒÜ‚ö={wŌŪĻ#ˆÞv§…ņ­qv+þĄŅ·āx+k)éHŒI$īMÞ°īfvXkkjkæÏŸ7pР”Ē‚Ũ”itÓpāA°)XuëÚ­oŸūœó( ËęŦ?-[ōÁŌo–}ũQeļąŅ„1Œ‰„Čā5ՍŊ˜·W|DB WG–―ģúÍŪú2‹sCИ°LÄ 3rÃ(ŠkĻO4$WTŽŠ­i€ĪŪŦŦ]_Y^ÖįˆĻžūnc}"ÎIs Ýâj°\ˆ˜”2žnˆô—ęcšļŒąÖ­‹öÜkïļƒ”’9Ī2ô;oŋ@x… đˆqc­ņ―\ąĀsĩĢûKGŲÁ8óKpÜeҌÂ%ĘmÕųāÚiĨ aĸĒE”ÕŠßā6FEïļũa]Ņi3ôH‘R˜áwÞL"m }ÏaGõát"ŽÖ6§ßābĢ"jŅąkĶ‹šŠtŦ.ĢŽę6 Š”V(rÆės("Ķ)ęE]>ŽûĶ#GÉŒĒž‡Ó―ej™[Üop;Ģ"K(yôîŊöØõÜKĪ -mudķ†Ú­ø#dĩ^DÕŊáA@ŪëōŲīĄ“Į†2B ÎđŽīj!kuĻ-锊Ũƍ)7rpĀf°Ö:…l^ØĨEvÎqýv?úˆ•Õ^ZðüWĨß~ķō‹ŠÆZ 20ƒUŦƏ—ÏßĐC_&x ƒļŒĖ‰kîĀČPU―ą…đ𠍍•ĩÕÕĩ5‹+–UŨ7ˆÜĒv-Û )ēyf͌ïØvŧ’Åq‘cäB"˜,`ų}lĸŒ Č@ŠMRrÎ}0ĩÖŠfÐZG‰DÂŦÍ~ņųėĨ‹Æb5]Ũ’uú;ĖÎ8ú™āRke­áČP0åQ’ wķŽŅIĢÁAyŲNēĘˆú·š@~įæpv>?‰Ōũ…Ú&šŸ—‰ÃÐüꑭVĄVÍÝĻŌ`"=ōōŦF·(ĄHSúRC؊­øcÔjÁĨ4H’ KĪTÄ\ðĩ–ŽņüŪ&.$šŦ@Īį,āņŠŠōyóæ•”tbŒý"ÔþâOĸJ*JĶŌĪ ;īi{ƐSuãŠę•/|ĸüãßŋ\7V'W-ŸW:h7âLĘ ÄšeöÚū`‡Ïj>ß0ã)ێ-ĘČOũēękŦÖÍZĸđÕâîSŊÛŧëČü•›#óķÆxАcu9ïŊ’ÆŊ4–Ęū―·ĸÝ\šĄY{ųe―ÔšßwßÍM&]ląA ,‘6†;—ÚZD`\Ŧ“Áĩ6*ŌR dLŧö8øƒ‚,Äšöč ÖlMc·âYŦĩ@ČXĪ-œs·%7 –<…(1ŽÞĀ…##ĨtŅĖrĮ4MFĄ5fŲŌ%UU•­Zĩ"ĒæķųFó?°T7đÉ3ÔÚtÉé|ņöベŸÝ“Û6þåŌo?ûqÁnąÁBŠĖx~ĖņɆ†ōšÕ5ĩ_ŽĸbaåōÚ ;īũĻšĘš­ČÁZō i1j84ßvĢĢÍ|Üæïú )·īEóŋŨÎÅ3$"xž Øæ†D°Ū=ÃKJkü-œG.Ÿečž}2ZÃVlÅ”-ÆœĖ‹qÚ+ĖģH#K„€ë€-sd°ÂųQk-YÁĨ›€"įbõŠU˖-€ßæãēôoŊ2žL&]˜ģaĢ5°MŧaYˆ|ÉDÃ+ŸŋVZđ1ՆÕļ‰šč“;djŨÛŊßëöĸ9íæˆ•UVÔÖÔ­ŪZõAé'LáÉC…‘VÍ*€ĖŸĸZá·ŋú į<•ĸÎų|vmM ræÝ*—ņ}HGYFDKÄ8'kždƒģ:Ũ`œŒ8ÁVlÅVüņēZŋXãt­ļč ąŒ)Ģ üŠ5CN‰Ž`œ˜ cĩˆI|cEų‚yó˜ZĶ€_­4//ø?S‘4ĩÜE‘ĩ6ÔŅČ#†õĩęëėNđsyã‡-/ßõčžėœXBôjQŌŦeIMM͆ŠōĘŠęÕå+Ÿ^ņˊęÕĢ:ÝytCMz-ŪųÜßŋâá Į›ÕĘ7s+~ą—1Ö<ĸMųĪ-Yē]ā$ßņĖφ-YâRXwëœyžPJ#ú@ëjĩčj’6RÂVlÅVüŅäfŽą&RāĶôZi?YFdQ’ =ŌŧđÃ' ~čõÕĩR"đR‘?ĸŧuëÖI)~aĸFÝv“Rļ֙ņĖOüäÖOoɉåėÖ}LŒß5ãģÅoMzãūų+—%IĐdĶ*ž5õu*K?_3ûĄe|_ĩ,fä˜ÎÛĮ)Ūtô‹PþŨ1›ð+Ŋ8üj†›ęīýzΗUU‘3tKˆĖI‰ƒ%oNæė€ž‹Ÿ$ 5yęÏss*V[ą[ņ ĩžo.Ÿõ$1áP,ÎxSm1@m―(8#/m•0ŨۏœËÆú†E F‘‹DMøŧÛÕÕÕAăŒō†ō”įōĻn;dđ:2\ēÖÝ2—UÏ:ûđ+ïxëÁĩ7č(J­§ÕÔÕÍ]ũí=KXRģ5tĖ)>lāĸcïKí:ŦŧŨð<ûܛ;†8#$qdC'$”ĶL>€„АhĨ ņUzĸÄûŠWĨ”öC?UUĐZĩTT Uj!MHBĮđņĮā `ûzÎėŧũģžĩšïZĮpåã\ŌÏwĸßėģÏpÏ‡uÖ^ë7|Ķ/Á€0Y%'jëj?Ï{“™ũíÛũž]ņ†ĩBWg! !ŽÝŠøåu]§nÉČžÏæá/*ļõ8 °1ðjcÍUΐóEsvÓ5B äŪīČ)yOĶ`ĢÕ* 9Cg”šfķ?{ßýũoÜļQUW ÞĻ―·ŨjKŧõš­ï―â=Råݗ―ëæ Ũ?~ęLųŒč[ßváÉųŲ?ûÁ_§·^ņ§[?y|îäĄc‡e.h/Xh_7Đ_Úō…wŽŋöāėÁÉiĀ98g_gŽÉ6vĨg 3Ÿ~ûGOœ:AD“ģāIÄ*ƒ…7zb?Ĩ}ņ…Ý)s|Ģ4đņ‚<94P@ˆO# ―RĘčá )qNYŦ†ŠŽÉMŸÏ 0`­•Úą@ÓdNĐ.C Ī”*ԟGĒĻ.ŨĶ3ãŪPŦ˜anšÞŨëų™™R Ū9ވŠÁCˆŅD[ÚÍŨ―ĸ–Ëo)mąĒgZ 4#ÛģóŲm/í98{øā‘Ų“ŊŋūÎ6ܔoýŌ_xëÔĐ21luŽ:Løƒ… <ũÜķųųŨCÍΙĨÜdO°ąŠĘiœŲNË@7Ļ†ŨÜįwEƎéknV;`Ā0@p;ðvÝĨˆŠ5M6pÆĻAJIjUģDĖ™―)Ŧ)gFV§—’TAFÐjZõû~ÞģūnŧíķZk$„sηmrˆ .]øŅũ<ļý{x4­h‹V7lœ~íĩßøáß~öÖõ~(―WWĘE]øÉŧ? įÎ{0y Ž•LƒIîÁþýûũîÚÝu]r†WīēddŪbõ*mĐZSĘÚMÝd=øžnø‹ÕÍjcö k ]­›^'Ŋģ:NÁrWŠ&'ÐZ1đ` L3§˜”Z )qŠāGĒąĀúuÍ-ēb9617˜Žŋ}ĩeæļÉĀ[6―ĸbÕNŽh·dēdë/>phæožüÞSŊĖžzęWŋšûõ•WmÜð–uŅ•ŸW1Ŋ<É+˜|Øä]Dī°ļøäϞ8qü8câœ"Ėœ3 ř†Î™ĖĐņžG œƒģ!€HūSՔ8F1°Ö0`ĀPjÍ,U˅LXšF_†ˆQzUĨÖJČąÅŠRíÄŪč7NžXnY‡}ŪÔΙ™~›ýō›Ē"xc;ÂŨĶ-Ýû7mūí꛹ĨDEęŌR-EG—4KiöŲđgþköá§O=~ÝĶ+ījôŠŋS‰?ß<ˆöŋīoïî]Æėœ-ĸ"A&UQąl ÏÉäYÂZã[‡Üh\{8ï8ü"!`Ķ0`ĀZÄāė%ĘL9ĨŠÚu-##ļ• 5áfínŠx–R~5øN.fU­šs2W:ėßŋïÅ_žúęŦ%HļŽÕgĶf֋šĶЎõŊĸØûzîĨÝĩ3$4(ˆTCŠÜúĄOmųTO›ÜqÎ?R˜ĀʑÂĘēۋ†ŸzōÉ#GfSNZAD,5ˆDÚÔTӕÂHūghJ ÍÄCsӘĐvâK3V Ĩ° „5‰C89Fš"hUDvQƒˆŨŽ*ķ ˆ:‹ˆ)3"ÄP.’ĘĐV­ĩ2Ĩ*2óÜķ^ÖÅĖļ*Vķ·J†Ž…Ó‹mþðš ÖkUˆƒj*š‘ŋō‰/wmwNy%"X‰ "ÄęB†@áLĶāūft[Ŧę_cYŠHBN) kąĩˆƒģWûx)2&dCStþl˜‚§œ@Ą–B„Äd~IŽŲ·@ūý§HBŒõzÓ4§Ï,ū°{wū°nÝzD[YŨÎÏĮr„ąKJ)ŠÛĶË7―sãĩO?jĖæģŒpŲŪEķÜüū[úņBŨ"âĘūuēą““ ė*^"ę‰۟ÝvjyÂĨ3e§jbhášķĻiN jU4 DPƒąfl!!ąđSÂpŠ40`íað@0DŽU#p0\Ū)ųÅoœDs‘˜ËǜĻP"> Âŕ‰c―n ‰ĐVaÄcGŽöŽŊëoļaem%ĒUėÂĖÐFADBþę'ĸø‰māhCSļ‘DFԝnŋúūēþĒuýڊˆĖ1YC'e áÚĮ++ėd#Ü3(vîx@K1BJ™ÛķõũÏa€@9eüm§Ÿ\ÉafšØhĶ„ˆ%LÖsF„R;fĩŽÍ‚õð,„(:˜sV ē=ĶhxÉĢ K)„ī $‹ęYdųĐĄøj(\gfķŋ~ęTlšÎŒÅÍIĶíļČ:šŌÞ}óÖ;/―gúH35?J§SZĒ2ŨÞ}ûũßuohąâß aōWOÎ VLiŸč[ZũĸFvÏŲņƒ]Fg_CMCÁ„āČБZÃ"21ƒ…0šZŧÔi5$†Ö&†RKHZk•jjqýîԂІ) O< ‹_ĸrbĐĩëZ3M)‰T/ƿˁĒŪÞ5 S{åå;vė˜ėd'ũŪtՊ&ô‚é šũŌuŠVM‹*'ūįŪžåĒ‹ĨĘykëLvŊč8į&ũūīŧwėčÚ]m,%rÉ? o„ä^^gS­ę―-xŨæM51đN=Ü ĮæĩˆEōÐl ­-3J)DÞ zÕ $.ĩĒ.ƒ‰EjiFM\û“1’įn1sFģkįÎŧïū;l'• “gzÄ ĄÖ ã–ÍwLĶĩV$ēZ7^vŲ}îÛķœÏŪî{°:?!ŽÃiėąĮí'ÏvŲ ­ir)zmM‰šNâÍŦŦÐGÛŠ’eįŌÖĘ)Å'œYk-Ĩ „ĩˆƒ‰b­ZŠ 'ÎljaНG# šUs’O$ ĶFSļŒXņĮB‰É/· dNĶķ}ÛÓŊžōJÓ4Ŧ0jÏŅéÆü7nķ]wĮíï}Ï­·XbVī?ųüŊžü ĐēŠkÁĘ3DīzŦŧō€™ũėŲýüsÛÁīÉđŠÛë$æ +xG‹ĨTptú€QP☠v])U)qd.'vō ŽQaî€ŲËžFĐVĻQžŠÄŽ 'ũîB°œ2h.1ņɁiĘĐīŌŒü‰Õãsr5-RŽ=Ō7ķ!šÅUąr–ŠŠ9gp}ðš·Žûƒû˜žšF°Ëßvé§úxï;yíĸŋP‚9&ÏQOė퉇JÁ㊞iYĨÆû§þžT·BĐ  Gë€Æ+69ģóÔ―č ėĮk ÐŠÉ IĄÍ Ũ"†æ-)Œ”ÓH­šd–(§Ūk{Ī,R!sĢŪ§2ƒœšÐJ1>óԓŋĸÐCW]uU˜dĸNEC”Ú8]C_jŋũĢïŋōÚŦŸĸôgŊØxYÜ;9˜T"ŽÎI8įa)Ĩ—_~ųП=žš!`ĒĪP‘‚øˆĢÆ=šjM99ûB°* rÎĩ5cb0+Uél fõ_ķFM xĩ–ÜčÏRuę'ĐW b6R)BˆFf`ū…_Ū2‘žMŠ„Ë-˜Į:2“iUPSkrģÔķ~ų‹ĸÁũ·ÞûÁkŊđfÆ 12wÞém œ^įÛųmŊ>sÏ ũÞōÎ3§Ï}â39ĨķëņüåuâL(Í+ÏÄņĘg1sO{üąGįįæP՘™ŠtАáōą(hX@8…ÖüR %bLĩJÉÐÉ+qĻCˆÉÉÂ%~3Ž- 0 řD)%Ū*%zOĩ0ŪÍMƒ@R €FYŠËĨˆōXĒ―.u- qf"­ÎkĪŠĄ..Ėýë?ĸÓ7ŋņĸþę;ųČ#žĐMÓN`åē+§|béä·ĸÖëgN}ėþ?tŨÖŪÝÔvÝy%^'W)œėp 'ėÚÕ7Ņ!lH$ÕS™ØƒĮąÉMÔ\35#·Ýqv T)fÕų^BLČXÝŽķĮo\ÖhW;`ĀĀ@@€D„DKK-ōōąkd‘rnÔÔåĸœÂÐüŠļk; W'cóSL"I·Š á(ĄtĨ.íÕWžøéĢoŋæ[îūgóæũõ˜žžĮdÞbÐĪÞūîęo|ôĸŌhanî#ũýÞ9^-ҟNŽ_W‘0œóŧbXCáŸ>ōȁý/E–%:ûMúnoFDŽR%rkĖž„á2šŨýГÎÔōĻąŠáū˜R79ŊÁŪvĀ€!…Á-―š1y™“”87 ĖĪ+ĪĨÐ) Bu‰TÓ4‰đh|­*Ĩ֊MnžÎÂ2\à Ó\ĀĖó‹s/ėÞõĸwßúóo~ýk_ûŅØĮ>–RFĢMVÉ&5ïšôÝŌÖöĖ™ûķÞÛuÝ9uve‘}“ „čĶŲ‘sžšššð ũėŲģ}ûķN "`u–Cj6īŠTó&wŽ!ŪĔ›\U €9;û­3Ÿ}kq^QōH­@āÚ…5ˆ†GB2՘W2ōY25'$0§š)gU3§ëG_Įn!číĄ…I‚Hã|C‰‚8ŪÔÕrjDäåŋøÉĸã;ßþ‹ĸûõŊýÃwŋÛ+z^A0|ÓĻŽýÐNœ8ņāG,ĨLjÞ !Ōhē#ÚXé―ÎĄC‡zó™'{löÐÁÄîoPŠZ@ŧŪCĸ™Á„L<ŽcpG†âĸ(ĸ™lþO€j•˜›œc0rBCŸ0ĀĀÃՐB8Ā”ÔLĪ Bâ\ŠÄTaė—ĻÆLg'І^k^FR­ČHā’33Í)‚AÂū…û- ōņcGĖÎî|þđûÞŋlūãŽ;îžkóæÍ›6mŠj[kE\~JÛķW^yådD#ž…ÏûíĸTĩWŲö•úĪĢ?îšnîõSý™cGöĸÍ/ÎKÛ§ð.ž9sšzeŊUÐ qB†F§ÜÄ7 "RЅ˜ˆ€TÔr“ tEMûö‹,7)ũGÔ9Zr$X‹0` {U“^ŅLÄTĩF™ËđņâëĨ˜Ļ+%O$ėJK†)gWzõ‰Y*‚sĨüi™2ÕR™ÉœõTM!RØ)p“ĪČĄƒŋ>ü̃>ü“wÝtӝwnđįÞ{ŊđæšK.đ„™{ųÖå—_ÞÜß("R]Ũ‰H_ŽúÆxaĄïU?vžĸ{tųįéÅÅĨ3§ýŪđ“'O”ķSĸ`‘ę‹ū‘VEGb–"œ";ÐŅĻŅRKīÆRŧ ėš rӂJd5R1Lĩiu'*DÚ ŪŅZ;`Ā`ĒčÂüļ l―CUŧŪëËnáŋļŒ…S§æNž8qøðÁcĮŽõ]j_OOũ֍ ó}ũÚĸ,ĨĪ”Ē#ŅČé€ņeNVãĶI8v@Ũ)œŧŪóôVÛ;ä&wm7ķHGRĐ@‰ Qš‚D9e ,R°É#s·ô”˜˜5rr 7`Ā€5Č@I9“P…·'.]HÜÔZ‘Ėí °„Ŧk:7TlFSĨ ˜%ÎÄXÅmVÂ\ąH vAMŠ0cӌJikĩ”sf‹_sV4 7É}ißÏėßĸÓĸ~øšëŊŋãÎ-=Qáø‰þÏņĢGgûB{æôŌÂâ|_vcL Ĩk—ZĐĩiēˆļ68õčšNŦŽFӈVD% 3ВĒD– 8îF.ŠS‚‰‰K-Ÿ]JĨėAˆ^ī@)r)…‘™)Æ/€ČDR bNĐ+ĒZģžUjŽÁ€ÖZĐĩęËtŠå˜qJ^cëƒMnDŦų(Z>pÄ°ņĶxĒŠĪ”‘Ð=+1Ą„…B"0Z8sâԕĒ՘ˆyžGjr6ĻfčtЉ„Ą-,Îí~~Įĸ°ũ·ÉŅ#9Ï0 LU?ûßëK™$ÞhēÜũ؃Åk:ÂãKē XH|t‚Ņ˜'Ŧ[‚vΆ4TF·OŪõđ2·{oÝáÏ~ü+ϘūEúēÎ Kpz)KE|ãļP07ÎI ~Š(JĩÖšũc" ÓÉ(‰€3†(U’Tå+TPI,wÏy5w ûlæáwÞųs§[ĩ f—‡ ―AŸÏÕș$eÐPķáY9ēYïÆÜ“ūŒ<―ÁYJĀčR™•$―ĢðýXmyF#圭,sĢ!|­ë2Ļ^–­*A}>ĸüóųT%€Ïŋė­C#u°Ę" Ūý 4 ĢeŊÛŨšö>Ë=ā+éj„ÎS#t‘;M q2ë$Ĩ‰‘dãltoMĐ8nš~ļ:t "<ĒēRÕ}ÃŸĘœ šėīŠþúOÆÍžóÎ+öŠðŌ|äĩÖĐ+ŒvÎiAxLžŒG@ØãÎŲ*čۚÓ07ŦRÃQĪrï=9°*ĨŠiÍÎ(™™ ûþ!ļŪ8gïģûnžįœéHŋ>U5AšÖi/Ĩŋ9å1%Mwf?žYiþ)ë<ÏC˜G4RSÕ4ņÉŽ­*NKDŒ„€Ŋ ÛÐÖ Ŋūw·?{ ļâ"™UûÜ]ŦCļŪÕļws[??ĸčīŨîß,īÓþģŨ-öÎ;ą1%UIEũ}Î|ýđVõļGĮYÝFZ8ĪŠbģûđ3įōĩŸ­†·•U܉ ŧYXwž—ŅÃýÞ7ÔLX*ŌÜį˜đˆ“øfw•ĘÜc]Ï~N@++ALåÚsk”ilĮ;ïüĩyĄķÁ%Ö2RšyĚpUPî―3Šý)^uēTt› ZiŲ9+Ÿës­ošļ9% j›Û4â48úÉglGĪMŪØnĄÕhQól’áŅ‹$ÖšØ,pV™[)OŊÞĖÜŠ †ŅŌ†EÝgļÖ(3 Ũ Ū™yŽ―ũ1ū•ėßÛõZ*™Ĩ<#7F6Ä/_ÝôļųȍGíāöŦĢ·OágĖrŌXéĖÂNož+Ūî—Ŧ}į?G ĻyO ßĩĖJa"ŦH›rĪ ķŽÁFįߥ4ÞûĶča™)ˆėx§Z ŠāĖū†Ý.ĮÝýM·Iír‹iî2Z_ĖįŲÖÉcŠ‚(e\kú"I[îßīw§ÝįÁXö‘*bY\^ ÄÕށxs_Ũ5án{ũ/x}HęÉðá#ŲČŪ}žjËē+Ë-Ė!aÚ":އ+Ū‘gāwÞų›…7ĘÜđÎ'zHFVéđ7%7öģũ3=4 ģvģNĘâW#õė T Ā}*+―ņkŸ}Úā+čtee•ėßaÓŊšđÍ"Ųxm{ĢųœŠUŅ:zž4pųŦË+Ū’NnëîÅ:)ՐķÕŌŽēŽĢÚύÆ_ę: ó8­åʒ…íý|û)TÏýX“‹ØwYÏÞĀo$ýg$ˆ/Īj*)čÖÏŠpÞyį%N%ëšN)š 8õ+€ ķâúô§æýÜîŨšsy’ös 4î™*Ĩē†ž<ãgĩŠ2ZUČ8ÂęČˆQÍÝWÄóܕÕĶ,ä9Fk4Ô>“ƒæŽĄ,ĢO=8ĖŽo óåŪöŠĐɇ&Č=HŽj ÍÔ0ÍŋmfWžIÚįsígįŨÜxUU9[ęŠü2îfÓéëî€ōaÖŊžŸ§€°ąÏí~ ÃߛwÞy tmÍjŨË((OvÞĘl '<`ļÏ#5:›+‹Ē…ę5­b-š@Åu­S§r4R-ķí3zžg !ūö3‡cŨ˜w˜7žīæaûÕRæU‚ÐŽÞ62üĩFÂb…„ÁÐ5‘4@î|ö‹iīg7―–T•āaãM˜“·{ïsōZ—:PҌ00Ö,ŋpũß}| fŪŠĖsýóAáT:ÍÝũ>Yđz}GÞyįŋfaĻ*ĖšhôaQŦĖ]Ĩob“Œģ;†‡ĪB‘ŌčjÕ;#˜*’ësUyoĢSYFâĻší!͝f• âZŨųnšFēō”j‚_w[~ÝpÎQĘčŸë3@#MûđÏoäXƒix,ÏI7Žð}a$ØķUōp·ČLÂüZX“•­‹H ŒX;ӈĩmKÍ>gge|5ŋóĻqN–ę—þė,đ/§ē*ŨĩÎÉlʘßÎ4ƒ„wÞyįïĩ0ðTýㆎĮÕ*sVQs{ž'3Ũšb*ļĨðP•ēÜ\ ŠŠĨĢė°D $ĖýŲóņ߅_k Ļé&'Ũhķ,ŦÐï“7Ø@Ö1Œūd|rÏ+ļņŲÝt°.QyĪ8_û™ÁØ}‹VU늧+§þā~~ëÔsĖ-Â#Ï$ĖÍzï^ŨUƒ2-lØgJëŠÝ†ąˆõ-_(Eø””ŧsZîgĢÍŲwpˆ…ĪąēþāVûÎ;o· 9 %Õw7Ž’úÚĄ›õ=mį―ŸSIû $ĖhŒ'wÐk’nëÚgāáÏsæāWåę.a7ڞ…œ:ŊÆĐHî6$}yU*ĩŪ€“éū>Ũ?fVģ―>§Tø>ą1VÜũS™mņē“ŲąZŠĩÃūVZšeÉŽÕ°­ÍÃĨęd[íTN*Íg]ÓûÉĶÄðˆŲŽa\ą€†'`,ŋf6†}Š4PFÞÏMNLŒ6é.k‹A– R%øïÐF2[îø­4·åURfŋĀĸĮÉtöąVHef4ąŸdļųėc@Äũ8ËčtŽžėԉˆ‰7ð~ļÓëMÎN$*iR~Ö'Ŧæîœfŋ­ UoŦ}įwŦ@ÚóėŽ—uĐjŽķzÕ/ÎfJƒp`gØZ 4*ĖĶ™íâõö†Uîđļk蛎’RIĩ:æäĄRJú“>ũ~ĖŌЃú9Ĩ"lz'L "ėý .?OÔn>æ1::Ï7_FԜb I=*HÍHÍōߙzvÓ8 P+. §wöR>ûJŊLr2‘ÃÏvÂCVMÔŲ܎fáūũów ïžó‹™[Ž5(ŨĩöÞ'·Įę~°,ëšúëæ>v)Ią|ĘilrĩUՇøÓYsÎūnhB°öâÖg?Ņ)^hœęō‚OĐ:1Ü<+!‚4ژē@uųCÃðO#øįš&ŨīXÕØ];F0Šą ~œ†ŠŠÔ„9ô]ā>‚ ýįĮ\ZŌAXąÜlŸCZī%áė=Ņ1ÃĻØX–Ï. ”įÞŧĐíų•$âOĶÍžóÎ ĩ*ÍáØËĪ}8‚}Ûm7˜TėŠķEŔ‰UsŨ ’ûÔ5gJߨ@ԜWG؀0ģŲ@uČq=€äĀÓQõŦ‡°I<™6\€ûÞŧ*ndæ1cīŸm ïšæ‘ęŋå7ģ<œýuïݖŋy]―°ÃŨ™ÞũYÂ4› h Ēņ9“Pã€ūEA=SŸáÏģÏÄãšÏ’;FŒė™ū˗Ŧý‹óÎ[xca& %"öyūp`ßL™.ØūŸ0§• ä|=føhŒfnSŽÛ›r Ōĩýũ:ý•uáÍýóCšņũÖ}B!Uæķ<$}c'l•aIđŸÝÂÖëÔВĮwŲÉÓ*ąo_Ŋ{}î―"šûv{§ę~CpĖé–'9į8îĶõšJÕ>Xũ}ôpĢÅÖȒę9æaäĐS'éŒX™UψøzØRŨu•jWZĸSóG[Þyį›)n~}V~ųR„{å1 3Ģ{UŌcUĄ ŌĩĒō8Ģ‘ģ'ŌÉķxđ›—_‘Xđ3{wļÎsÜüš.:K%Ļé ĩˆĩžN͛ҙYߋ{gįáXA{RnTÕĢÖÛ%{Ģ„pßũsöĪņ>MY\ąö>(H`{+(˜đ„óBNJ™§Â"|•þôå{ß "Ėöy@‚hˆO_ŦIįý=…sž<”ĶĒ‚Ē2 –Ržzéƒŋ:ïžĮb€ÓzŸ=’>_†ZDfŽöþÔ9ĖŨjSƀÐ`­á7žĮ<ĖüėyD(āĻzuõođYĘĘRf˜WæÏócnáQY'ÓHĻ“UIā9yuxđÓvcÖq0' „yîMŒ™ ŧrĘŌÕĀj GÜũCŒÞŅ6Y ë§#Šë"­„Žī&&UŌ;_&'û ƒÅú1ÃČFlƒiï{šŌ§… "tϞuÛIZkEüÁ›wÞy·ÚĐÅĒÜįœčOŋÏ― [S‚[YáÁBíۖz4‹ûéę:ÄsŌĖ— €“ –UUđ<:‘ ö>+<Ķw‹ˆëšíO|Ėýé&ņė'+éQŌól’ePU;hiîКFwŋ~`n4ŠîÞ AÜœfīþ/\Á0kUyöįZyrX”ϧÕŧuÚéŧöģôĩ|ųtŊ­ĩŠ+Ė,Üsg•˜ÛŲ{™_îĢą-éóđÜŽ ĢŅø'CßyįÍ@ø ĸĢ7„ßænæ%åII}öu hk•™ó+ŌÝX>tóXUr5 \)KâyžšvÔ~n‚Ó·6’oIÆĀwwš=’@bČÔę–ōá@Öüģ1·‘}ÂÔßyį?F ía(í_­ ІČĩ.óoTvŽUę—v3óʒą”ŠŠf & ’-uË-ĖBUáN°JgtĐæyrw Ų`VUjĻŠĘieˆ5ų GR??FėÎýlŧ§ ØÃōœĘ‚DŲóó ZŦ°wđŲęWSĐRýHõō[Ō UgVWk!m˜ŧ™íįĐ:fPÕLÅgMU84'É1>œ},Ü= ŲVŦ+lkŸĢFíŠvÄĸîÆõđæü âōuŠH6îa\p― {fÃh˜đ·ĩây‘™iMģ–t}–„ vøÝUu]W„7#!3ãûUýo‚kS‹CâwÞų‹PKözîlÍėÔ·ėzÜĀŽuflúō4ôxeĄ+ÆÃ:‘Ø“#c&wIėļ $Õ)_wŽ€LM˜Į™ŋ†ą“MYL·Âo*ˆûy*ÓégŸIŦ‰øēĀ”~é‹úïxßÝÜ|Āī†Ęd#ø95ŋ5ÁįįĄŲšBBÖ4<Ú9ĮÃ!ļđ†·%ęßŪ`Ņ ÚëoÉð 0 ßäķ1WcÞ%MøŦóÎ;o·Xæ1ui#u_ÞIŽėcŪÚŲp3šŪ“UūĖã?Ŋ{øWlëKÃHJßM9sŠrŋ?a0%€tĐē SIÖ)ÜMĨŊūŽjQú|>Ĩ ą=K%ņõ‰5)lîhƁûįgŽéšÂ6ÓÍ}ų·Hφ~fÕÄĮīóø fGØĐ~øÏŽJýÂ/y(]Ũį??–āÞПYînīsjĀ:‡Ĩ™đ”ŠŨ-öÎ;RWŦĘsR™ýÜũŲĒÛÐŊByŦG‹`yÕ>t._īx~6Éč0„*M3yVþ6~óéU {ŸóėÁЂŽc5‰Ĩõų ĪÆĩœÞœ†ghGþœ-0þĩŸGŧũáÎSk-ĢÕN~ÃÉŽ%ãÁ=’„ņ<9q €N%Eo$Ņéįë6îĖï,ö‚ü īMđŧĪþqN9cxĸ‹hŽ.:Ím€ØŒóUĀ2wé•ÕūóÎæjWÄŽZWÔÉėÖ·RĻFǐD'eĪĩoƌ)%•ž:ģ(…[VŠ4MÐõđ$œi7Ï*Aö[<ž§ÜÜͅä$ŋ˜íߑŌĖĄĮ:;ĶsÅdΈbYø˜Ųöóŋ~ķģ7P―in8I#1qtžÚ™B‚deĄýļūVfĒj]kšnĪ2·^ēO“ÔNãdw=óLG/a™ĮšŸ"wÎ_)ž%ē z4Xĸ―yį·…!ĖŋĀw]Ÿ^ũÎlsÂÉݔk\Ý–Ī}ß·O7ĩï­>2Ú;…E?Y0ļ9iũÏŦð–gåžÅođė|֞ÜgxÜÏCvÐL‹U‰AØo0âôƒđÓ"l$―Чc·*‹ĒLđw ŋasF}óļ9Ä~Œiuž ę}Ü―]gS–>ļŲ}· ÄäuÍ;M&4}qoq-UMwï”éÔŋwf’"HtŲûŋcnÝ>IžóÎ;ðXŽÕbTûÞnÍɖū-ī“nŋ9i%,ĐëZŠî^Üvį"ĒQē*iāÂÏÏãð+.’0­i{<‡=M8Ü4ŽĐڕ&QŲŒ‘ Ņ"gO­ĨæCú䑏ˆbjTEƒđý&.MÏý$ýč4āSč;B<žwíĪņ}GW;Ę6IęW5 rŪĸ|ŪŌÜP~öÉ*‹&L”nÞyįŋĮÕæÐĐFs?yHšÍTIÚ Ģ1ïZ°ģÔäϚ­9•ęš„ĩūJfý1^đ.ˆ/~• <ũ3ZZũ ĸÜóÔ~ve^ĸ|ŠUUîËĖũó4ĪRûŽy[vAaFÜãšŪŠRÉúĀŪJãz˜ĢķÞwCSã™MãOzü;YGYŋ|E} ÝUCđûšb~ÄČ 2ŸĻyŧâXÔNŠDšwþĪõ ĢÁōĪYØß4æūóˁ*ÚþŋÏ&͗O€EĢ7Ũy&žęđhúu§Ŋ @@\ëīĪ?š’ļïŧQ2~‹aŧNÖ ŧïĸúuČį~ĶĶŽN_ÞŠ’jVéęMóšÖóóLĒØūŒ‹!3ŸûÉŨ󘙷ÞāŲūՊuŽUŅQN,gĪėZŪJĨĖð[â+·˜Hr•ÜÂÍSY• Ä­°ïi$ Ÿhš™1ŦžgSöÏįÚy&™ŒÔĀßzóĘ؊€!ũi8uI5&ąß:ĩu­Ęzö=ýíUß:Ë+bđKxįwþÜąXôf§ Ýî…S2 ömäāWŨÖĘ#r"­?ŠĄ~ #z*ŸûgŠĮOSĀßoéÔĐFšįÞtÕhXĮÝŧõāė>ŅōÏ™Â…Đ 2“ī*éeÓ=Ē&vŦ—ņ/W―–šóä>{G\ÂoōËô0–čáä|_æÄ°~3šĖLāŲĮĖ|” YÕl‡đŸ{\ŨE ąbčl: ž<æ^Ō°ÃӘ{ęĖ‚üÎ;ïü9ąŨ ßŽÕ9įŠeāūo î6Ū-wŧ"TYŲÄŪÏþĻ’Ö‚Æffĩ BĖAY:Ķ KYō^WÏNB<û‘īÚ 0ŽąŅZú*$ũó28ūÆ4\ŸOMúŽ41ēY‡ģĨ*%ņsï<UƒxüũÎ>ūėC^ŠÏÕžGYøōĻow$ÜCį"Úģũ>O\‹Æģ·ĻąĨ=C_iĒmēŦvĶv·ß ŧ‹ũW~ðÎ;”@ Hv[âģQ5ā[úÆ`WĮFÓŽÏNĻ@€ÞĐáZAþw{wJØũ#"Ū'­\YéfĪݍ­NâįįvģÕM ’ĀægģDđÁįđ\ņĐRUVi]‘Y]‡Ó4ëŋSÆIx9 (šųýóCĒýĩĒ’Āðfķþųė,G‡ s`D‰î Õy†ZÍģn‚Xđ§ífõåb YķŲažßÂø<'š§8'Ąr·XĢ&>™‚Ų_ÛwÞyĄíˆÝũîčn'lÔøænÄ9ŧã§š;ĮõôÜŧíģ+ŽĄ$mĘ―atēR0uPÖ%•$‚ÞŲÞ*}þųdfŠHóÏiÕĩöóx8Š,=įĄ1čÕÆ sŋ:6UfėĮxĀi,į0k­Ž1žÃny&ü›öM)“™ĩŒũ6ĘēŠ* _í ŦJsƒ8ô+:l·‚XĒ›U Zƒųœ_ķwŸsÖĩĶÄw…›đϚPpũėČ/ĶzófÞyįOޘõþe47ŠzÝ#ažï'OMlÕißŨĩšĨÜéáfĖ!@›@Ļ*í @h°6ĐNžÁŲSîëZĢÁÂĄēNî_7W“ā?ûaŪģDPYû9J™ÛÉėgī‰ Sés]Fž―ĮųV§0Þ°ĶYU…FÚĖãkEDAcąöST&PKĐĖëZkÅ~tũåũģĨęĶ ÕÉAŌöū>î ÓŊâ<§ î^'đyŊØG•Ä;ïžóŨj‰1ƒ…YMÛ Q€JåŒX%QcCčîDÄ Œ7§p2GÞ?Ņ‹M{úó<ģÄuöÔ9uvuėĩŸgžĒ―Uó1ß%T€}ëÖ˚Åu:§đÚ+ŠÛ―@š‰ÝvdĨ4ķ"I7sëuĩüŨgŅ,„AŠŠčéßzâÄ]U(Ð-ģJãÐå„$Ė aKtŦ•mĸœ“ŲGį„OąÍ9ÛÃMíĸ;V™%đŧðÎ;ïüA]íŋ“„MĖDIķlw,Ï9(L"Pnހ˜ø §ĐĄí*‚4î―óëō˜Ié$ĻØu­ól•Ü|]_%VVŽĖþū‘œƒē0+eV ŠkíÓD ý ĘÜIö5mļ8ûprrŸ=ôE?ރFóЙœrģūuæĐT|v–ŠčÏÓ―+ūYåģ•+Ģŧdlį7úĀP5™đfŋūŸÜY% onMĘLJ}‹Ęݧ;ĮÃDŒyĖÍf)†”ÖĖŊðđ.:ķbė3šģ1dŋZ;ŋŽ”(4åzÎ> V*§ë·ÓËäNsžüwÜâ95ĩRuQXÓ%ŋ‰‘#đX}^·ũĄášÖóÜįI§ÅŠ}?ī&p͆‘p_{ïûįqģk­ýlu…eX ïņÎ;ïü9]­/?ÏV–ę.nPŸÏÕ TBMóÍĐīFÓ―ĒÆ6ą`–§ō9aôvp‰Eās}rNáŋĐ.i0‚ûlIÆ'ũНÛüšđGIŊðg&ļ–kSC„°Óķ dš2î&AŋâŲZfp­õÜO)?ĸ\•júUF ýHÎÏuAš ĢÕtņš ęVóóÏ?küšŲÞ ČûdŸ“@kØ(”™y˜PÄīOvĪ4 â{? ïžóÎÔ՞œhAåÆŌ#rNoH$–_‹ä}ߝ]pđYUŠ‘QdŠ@XÄŲ;ũQĄkvĶ­Ę*é9íŲ%k— ŦKŠ‹o—ĮðķŨ·9&aŒĩ€ædņÅŊ‚œf`ÕqrųE6ÎNGäč šņũųyJÍĻŌTðåëšönlaâÆs§yŸ‰ĩwÂ@3>į@eá kvëšÉ @4@"lyÄŪmÖFp*ŲÃãÜgbn>ŨuÎŪŠĄ2ž6’‰xįwþĒØ+KŨĩ,üþđ=lŕ%ĐPšÓð”đģ°OGXYÐųü<č‚ÔНgá%$áj™AĶÖĩūá,°Ïúœsr?]vÝÏc‚››ó~ũ 1áW„TYÕōÞ?ÛGė9°‘ūŠu1ēĶŨŽ·cQģŽī€f(euQ lNÏ`e>rˆųÐYiAĪŧs?Ķk];TÖge‹ŌĶnįį?ætšēî―'ÞAݖÓÝŦ&ÜÝū&äÞyįŋVxáãSáÞįø”Rĸu‰ËÜîûĶāEÕ}Šž<$Õhĸïs=ÏCC—ã^ĸ^lēņ#”$ĨdÕðÝ]žmE+Á<üî*ũSþų|Ję|7óįđKâ4Ôa°ŅLýLûrEXŊĻý —ČûįŨĩž)W'ÜkrķÜŨ”ƒīn)ïC70‚\īILĐɜÝ?û{ąąOÛū$Ã9§·ã8§h6ŽVģąŧžį ĸwūäF§(T;šl ØöÉĖę|ƒzöĶûš:”öŒ7—ÏޓĄ.`Ÿt·p؃wÞųģ!Š‹TiÖØuönØāōÉj‚`oØĘS4Ū+Ü,Ï9ų­fދ-4―[į™,ŨpũRņuōœ<įš.4âA6Ų7㘅WŒ•5ĩŨŲāŊy·x!Öj—AZ˜ ÉŲŠŽn‘āäϚyĐĖP™$ū$ íŨÖeFŦ*Ą25ĩ’Æĩ1ŋËô°Uåð°Ð·mÁʊd\ðdĒ *MoČÓr]žóÎ;Pė5KŲčüŦĮÍ|ĪN{Š4_ƒÚį˜1–gĐĶú%ëüįˆÝ߄bT‚Áöï-fþšēˆĖĖFÃSįŲ·šijwW EļÚá―ĀŠÆąÛ |ΐČӅ^ ‘ãYØûLãï9Įœ`{ØēļOĪÜ\Š^W­‘Z TˆðYKëTSŪiNĻ–ŦSÍ`ƌaQYĪÍš=zéq•ŅŊkAŠAžóÎ;‘@ "VDīæīčæËI3·u…ũģKuuÉMe^ 3ŦÎĪ ŦõœTÖ1·Oũ)dþFV’(Š ™9mcßUÚØ-2ŠĘč~ðŽ­Mģ4ķEâޕ)PÕXÞÅbh8ÓðČ{sŦĘÜ{ķÖČÞŨGžãN7šĮÉ^·éą<ÝÏlͅa*^ąĖýyžÞ‚Ýŧŋ=.ĸīFâėŽi;ŸĖTjŽĀþõ4ĢiÐī;A‘dğlaxįjódcYNŋËdēH5âĸ<aq}Š3T]đx­•'Ïģ!ŦRƒrW@Öé0ģ°ģOž[­ęßčÎ*Ցۗ~5™Į*”ŠîÞaĩZË%õ­ĸmυU,|ûÏģÐ/ũ 75đ.4wŧ5aWŽ:I˜@óĻ<ÖR‡æj‘ŨĩÔā>hÐŊLÎFėãBn27,žsÎÓåËO€fÞų“FÐHLđäōUU―…W-ū!Šïžó7đÚSóã۔Ęh O:ĶŠŠXÞíßY_\ĢY„Ë0ÂgŽJ•˓ĨôÎ4PJfn†ĸÝw­åŲ†*ãĄ'O9øEXwßN4—Œ<'Axßäyž’Øe_·ãoŒ u}›ū ņŸĸũ)dĐ,Ž3ûâ — 4Ķ:r·JUĄŠķģvš„…§j?ŧNY0b‚ū Áh‰y†čFēĢIMâ—[—ķå>‡xįwþžŪöœL•›ŽSfF‹YÁ<ģ~{Ķõā4ÎZee$îFšQužęCĸëäVkKÍyß'8Id7sóĮh˜ņĻŠŌĖÞũcfS†xžp]Wę PŌ§ë͍l2”Ï>Íu8ø­ ŋâs”ÃZļGÓÄŲiķ‡†îņė%[UÆý ņ™ÐæA5ØģspžJ'ė1Ï]˜ąwÛyßĘĢRVeFĪMŲŧē:ÞėwÞų‹\mcŒJėŦēōäÆÄĶv~KÚ]ĄčŒ>IKr6ĘC2ÆN0%7q}í°ýŋį9Dxø9‡ôö/€ ĶĢ··f‚îv?·q°L§_$"7'$aÚgéNzf‘˜ûķŽLæqz{T*æ—ØĩÕ蔍›ĸ+•ŸERų įÍ,sƒÓÍNÓîî°EX4i{ŠfĪĩųhîũsįIþ;@?öįZ*u0‚ŪkU• [ŊØëwþj‚ŧ_ŸU§†Đ4Ēö1:œ †[”,kK Ðô끗“Č…k]­SfŪß@BŠ+"ģÆā`FUa„·ĨY Í,ŦĪū`ųŲÛhæfäų^Ė~Õ †ŧ=SãAō~žFN•™ĢjŨYáFSVcŋ9îë%<ũ}ą tķũLĮâĩ:ŽĘÍ'BŽyØõ-K§AØûq3šØ•?æîfhæWĻÏĩtŠqßūŋ)7C•$üÁyįwŦīï 2ŪpZž wŋ\ŌsoĢĸÓÚȌYðÂÐŨĘž'ë$Ý#"5i į4DŌė[gká%å}dčއŽ*wģŊâb\ŨÆōĻRû‚m,JĪqŨmliφŅ=$”ĶëlŽr…ŸRđySÛsCžóÎ;‘ŦÚtę{~ģëđïœĨ2ëœؘwÝ,ŪEsÓ^.áäąßúŽĄ,Eí}(v;ŠĖޟAäūJ5 ĩæķwЊ$ {ŸĘ2gU―Ýloí[Ž‹é ‹UĘ^™c9 <9Kå™īšŌš.Uý6é~ķËWfU–ŧG‹Õ$Ätßþ"5Íæ1†Z’ąHm ŧ‰‘,ÕØtį‘ĖŽú~“Q*”ÜĒũY•Ę# oáÍ;ïüIąĖNNÕBļ7ô”™Ŋˆģ“āšŪIĨDĢJcÞ wĐf%ôIߔî`ĒDãHļĶmWŌŨšžđŦjˆāūõ,•ŪĸŦüJIīaŸÚŽ, °ÖRâė3Qaurūnļ/3[Ë#<Ï)UCdõ;‡õ­s,gö_šđīģOG#‚@)%™Ōē1wŒc,žÂˆąHt.">ĸ|(Hó:­ @ė{qĢēÎų“…7ïžós˜ŽŠh.á›`ݘE”_ß*ˆsö”3îģũޓ)ÓY-'ÂŊë:{ˆJęôūžlöéOĨę/ŠŅđÄAóa'ąĪf~ģ―–/ĩ“ŋâ„ûđÁĄ†+Ŧ<gK ĘÔþBĪ•ōī–Ā,0…ÅŦ·æ!"b }ĮĘ5dM†īsMļ>Wõs "ūîÞi#ŋ;ÎĶ+'ēŠ$t™Øs”ëóMŪ)i‚Š^ĸÂ;ïüUŪķý ĩVė<&ÃКY8TæÞtTɀgïp[kįĐŽąųgUîCÍZUŠĢ™ݝâœãŊˆŊހNXåt]ŨÅs{ö6ÓęxƒAô.57r Ž‡ÅšēĐS’ĀœþÃmâškÎîÜxžíæmxÛ§NЭđMąØv^š9Ī“ÂWgtIëZî‘Ï)Š4w–RĻëšFzüeĻKđ…Eó0C• jč―“4ōÍP|į?Ę՚Û™`üÝæR Wõ)–[ŒT+Øüfe•:ąĀAä9Ēāû~ōĪ…“č+yļ ‡Dt^—J+ÖzžÛ;-ÐóÜgŸÎÏŅúÆ`Ŧy{bšA‚šŸ‡„™sdÂ$•Ž;c…JĀŋUf~2-ÂÂŧ­VßģwóķFVøãdîģKéҚ3§ÍįVðŽYxž=+öų•7R î~ĸÜ(ŠfU4”ÍCØōŋÚâøÎ;Ŋ17ĒŠ(˜;ö€…˜NFïUt>þŧ[îŽ3Ĩvßŧ N›FNŒŲØj.ixŅqũJ߈™nųæļö~ĩ#ģ—JÁ˟ûÉ*-ėŲ―Ž* ŽĐxČsÜúO)ĩü2óûįĐŠĩ@ĐNąØÐ%ŋtðĪųÐÄËÝ"XŠŠk}ĪR_î]<~ÎģžÅ *Ō×L•ŋeĻJUG§ŨIū|y|ýļæĘRŠ 3VVUáwÞųƒ\­ēP `fŠABƒ,‚āXiÃė(ĨäŦƒēHĐšIũäl7­ĘÁ9ĄęnyøˆVŨZ>”Ė €D™[ €Få–:dÖĀóĨčÍ"‰ âH[ÉvdĄ,Ė"ÚŦ+K™;wš9ĪŠróëœđÁæ#Ž;ԁÏįQũÞ6bˆF\ûnô"A3đs~ëS?+}ĒqVj-ÏŲ08)iŸSÐú\ĪŨIïžóÎ_$aŒ‘ÄԜfįÞ43Ō:1–43ËŽAzóžC掜kyD'pïģĨēXŲۍķÏŅDŧ˜åNÃ=č-);~EGܞ LĻÓō2R}7ķZ‡6w}ënōT,·~5fĩĘJęM2Ūč<œ•ģũÉģ!:ŋÂ/3ƒŽUę°GåÎe>Aæí_°†~ ―žó·§‹ÓY2˜93OVŅPßNf&23ŲõæČ’Š ĩBø{óÎ;/Ԗ*Ėól#ÍÝhįŲ‚ ‘ķYZsZŠčØĀYxAØo„•F3ÐÔVæķž)|ųĨSÃŊˆŸįG%Ŧę›ÏŌ ÖDM·BŠŽ7IdnÃd4ĐēĘÛ);^>ûЧiVŌޏ ] 9L€ZpæŦÕ%ĐId(ÝÜUäÞ Ðōõ {T™{5ZzP’ēD3Ĩž< Ý Eąš“ 3š[kÎLJ7ŲëwþĶÁ詂[U8{cÄ#'P­ëšœėÝ+þ<ĖĖhŧA،4ŠjŦ:{ķc†w[bi…aę0†Đ1Mh°#%M;Ņ0Š+.sË!Ŋˆ–Ü8…1Ĩpĸ^ĩA@ÓŠŨRUĖÍg'Pã—Â}*ķÐ6„Ą,ĖÛ°ûœqĘF{pĮ);7›`Ę2sũó4nRBVÍŦAĻŠūØģęäđÖÅŪ7‡―ÏÞĸû™lÜJÏ9ãakԞåÝMxįwþdBgĘd æ_/–Šl‚ĀOŸ›ĪŲRÍ]ĨTjŸ=pĢét„ŪuåĐūŌÆ+œ]@ŧ—Įu}͇ŅÃæŠBiUéNãx[BĘĘęÕÏę$ŠšĨĖ$ !S’č|Nïuš›@l ž#/‡ÃŒKĀ=0}enķũĢþĶŧŦ_Ã=ēR›2ķRåņðhķīUV!(sïQ­d`ÁÜöóϊˆûÞ$=ĖÝÏ―A2āŋOýRURÐþO%<Ï3ü2cMø·I˜ōO~enŪ”Ä_œwÞy·ZĀݜ~К@XĢ17§RUߔÅįv„Å"trŧ 4Ļ(ÃXäÏý\Ņ â™*Tļ7ØĨ[ <ûú,ƒÝŧïļ|:Æ|qō@p›8Ūu‚fÔ ĸD5—įäHŧ–[ílt$Įœ%ģp6äŸĘÏõŲ•â4JDŊĒcûũ™M4Ģ U)AäÉę;áŸÏĨ]ÖĄ3Ņļ_ʧÍ@Té<Įœîö< 0P' ™Û„Ûþ­yįj§17ŦÎÄŊø:―šnĘDéKŒî:Mšx„CČ9Ž_~Ɗ ūg‡;4;Ïųaķ Öïý…ø“·ĩ$Ëŧ“Ņ-ÜCßT0Ÿ:2 f4Ú>ŲIZK­ĩ%ØŧmÕ9ãŠÜbôv|ΞĀ(ÏPŨšvĶAý‹7@ÓVP€„eÎp€•§A|h„õ]N–ĘÍ&üÛa_ܗčā2f jŧÛŲ;ĖEŌĐĘ œ,é4ĩýįæw^cn•ö9ŠŠÎ  —E4ŨYî)SE‰ ujÔĢ’Î\Ë 4:Ķ=—ą$u–Ŧžq7+õÍĒ=*ĻDë/#͝<üĶæxÃbY?›Â ÆŠ‚īŪ0pĪpV%2›X˜ ó*ˆ)K™‘nwŨÕŽX,P‚ðuÁn6Ē‹įyDÖ9C˜˜ųTøÄåą.ĖOđMf>ÂŊj&X;ũIAš3mą\ˆ™9ŠýwÞų‹bŊ*QĐiQėŋ·ēHģ`œ(ˆ:EŌ(ï+zë|ÚüJr?;ŒÐĻŠ2ißX€Đg,):īÅÃō9$ÍHīĒ„ĀŲ'ëTÍ*1w9ŠįÞįd_<ž…ŅxYîėī—˜›NŠMŧúVÛæF‰Æ{?Ïy&Xn„‰‚áėmâZkúlĪú\X߈ķ!œJœÆÆJ7ƒĄŠĶE­Jč[›Ûé‹aÆ6ŸýļU],7Į_œwÞyĄv8„=(Áhū–ŧŸgWCK02EØšVĶĀoĄũs?ƒzcĘbŦĖŽÁëóáPŠ”ōœ―wQ@åÎĐ/KáÔåŨR”3"ÖîĖw·FĀåq}–{ėgäe_/ Öšïg―WÛĀHÚoލÁþųüct4ĄL·*eH§ÝÏÎ*šĄU3ïĖŲ§N‚€”ĐŠ4ÍvũVŪëëÚĻĘĩbri r·ŽŨЉŒ―w•bÅH|KˆwÞyįęj+k$YđR–Ņ"|ÚšūĮYJ7ũåĘĘL ÍĒn’š•&|Ö1Ų{ęg Uuĩļ7RÓūîē“čĸãn(PÍH”FQāasZĩbY##EwĘ"+‡˜ųkÅnŧÓÞũ]*ýCŽUý_ú"ۖö›StwëöÜÓŊSÀdĐę·-Om ģ’äu]j•Åüē*Uiy„ŲüIaūRģ‰ū}ËÉßyįï&{ĐJŌodÁԆĮ9įÔ1ģŠ†ĀĘŪHxö>ŨšVޚlY~OÛ§öŅÍĮįÚЉÜÅYxGfnĘĒņ[­XEr ÎæY1~öók+ąîЊ+J]€vš8ūÖĩðïkÅĩ hÜóéčĩ°ęüÓ―Ø ?ũOVš›™Ėû_ģÄ{Xl_øÕĨ þ: NąnĸđrŸ3qįËöþ—öP$$íŊ"í;ïžåäUÕåēũ~ēZ ~îĸ‘æfÜ;v­OMí‹ÓŸį‘ī"$í=đV.čŲŅV\™Đ‚…ũ1ŅåÞ^ÛjÔĀĘsüŠS‰sË}žˆĄ‰ĪŠ! æËĨo§dtŨŅØŧíY뚮†ŅŌvĘBĢŽJSˆ+Ôó*E·ļbï§sđÖũMĨ@IFßN“Mū\R~3v}溜MDã,'ėœLÏgUĐ$âwÞųƒŅā•ėÄ?:ïįƌÚ`pœÚU%bLSR-sũsC\Ÿ RõŠęm~Ö€įœRŅžWl4ŧžģ‡Ŋi?ŧģe?%åĐð‹Š™%)þđöÏ3bčĪð2ŒĒPßũ3+ŋ-ę2ŌÄ—1§đ­ŸÅš|öå‘Fė“4Ð,!ē0žóÎ;pŦÍŽ‰Ķ­Ę}æCú·JŦš$Ĩ€&ï`sN„Ž,>ú-Ķæi'žõœé­q#’°Ū+!îq]Ũ°Ĩŋ=•Uč§€/ozAUEcžDivð“gbČ}9ĀédT "$ĸvęĻo]G§ŌW|E„ ŧ‡ėGÚ)#Ýh―ðR+ÂasŽw]ë™73Ŧúšý–GÐÝÉØÂm8„‚äðī°š"ĸŪ…áw^·X§ŽN}VoĢn4·˜ĐŌÎcná+ŦŠ qmEęhŪĘßd`a;ÏCÃu]€îóĻøY mũúBgĸ ū<ũ7ô ÂģcMėVĮßļÅŲ  s—́†8û”āáējĘqŦ† (õq€ĐYĖæ Æ$vöcÆ1đUĶ“ĪúŒë ũóSÍZHŽŠA·'wå13eígWÕü)F3;žõFŧïRoĮhšBŅŨžóÎ;@č9=4FÄėđ20ąFŌlĻ€>ŨĐÚŋƁĶƌ+VVĒZĸOæ9fabeĐ ‚ûb„‡›5;Ąk]Rí}Æ5 ĩÉõKŒBĐŪĩēŠ_ę%u™Í§cÃnóļŪČ,T†9Ąb ÂæųgëÜÏqũõ=ĄØ}‘§‡žŸĸÝŅ18Ĩj§™ŧÛĸ_š­UĘEÆTU$§ÓŽTÞWŦ_jū~žĮÜûŦD•Ū+öafïžóÎßS Œ† ý+3§š›ÆįđũyHzxĢžÜmÂjŅØŦūA4oPUCĒŽðæÄ/zŪõ-:č™Âw§AwSeG.|sd&þfĩkzAœ.;ó0Ōˆýœ^Ŧ<ü›ŽØ€^Ų€ŦũŲäf’Ķúkžŋ€šåÝĖh—Ę}Ģæ/ Ą2EÜûœ:CT}ÂUĘúw$ÝÏmWðTóî~iÖ)ĢáwÞųƒĮbænĪ;KÕĘüIÏē.—åîlïŦ1ŦRКļîQ’öÖĶėôk·˜ĖÖÕ0ZjęxÆŠĢ*DœĖ_õUtņļŧ;$ 4:Ũ9îaþėc”đPŊĖĨėÆōSŠÏįzž­*Ðz‡= đÁ“§Q*•ŠŠņīõeīyæŠ*Ÿtó37ŌÏÏĸā#Ėʒ’ ŦeÚ7ÁŪá QWøf„Ã9 ĻaŠŽŲ äŽðĩ‰pĖÄ$ą1ÖŪ*†Úæ›4‘_ÓB.ŦPRŲ|LÝe*=nąÖ2ˊĒW+áÓcQŸæqÖōÜOŲŨĘuįöėýf•*U–,^;ų—Ā€€‡i+>W)vƌ—ž MΝ;óŲīi—/%vïŅë“ĐŸÍä723ģ@ Þh—nÝcF.’‘ņdåōeK—,ÖôXí:ƒĐ…–Ŋ0uúg‘õęŽĢĮŽÄN›RĄÂsŸL›^ ’ž?wöŧ9ßūÓ·oÓĶÍq3ÓŌM<ųčŅ?%æĐĩķF`—j-­iøŦ !’ŨkŠā$­ B|hĻŧ~RŨ€‹Š'nhčQ­Ð 1íŠ+44ĀĨЇÂdˆb™ö%3ēčvuŅų1u}p3L“‚傌ðĢiŧKEF―XfYŅ3 ĩGģý=ZgEéĻ)‚]ˆS­Z5œŧÝŧw>I‚™™ųp|2mZÛvíW­\NŠþ€ƒÓÓÏųúŦISĶ-ŒĄú‹AAA°ŽRåĘ3;;kİũ† ™ðŅĪsįϝøóĻËG{Ø`ęØNøhâëíÚNž4ŅŨĮųyÜĖäĪ$BÍ[īÜ―kŨГ ~.WP`Pï7ßNžp~óĶMáÕÂĸųįē(žhˁÍ-ÜR^šS,ĀžŠõÐá k t€ Ųô3eĩ6yŨöԓïeãĪ/7Î͟ÝKž{hi|}0ʞ™C“ķļ^‚$ŽÅ/™^x ãq”Á°Ų(Ë/pKÂá*ĒâŦDzĄäBˆ―IXVđË,ģŽHæ?ÐnDģ@Ļ…‚>ū~þþœČÉÉ9+Ų<·óēYģæ7nÜøō‹3>ĸėÜđs„q˔-[đRĨŋĸþe\ėÜ9ßfddаððōåËãvëÖ=Ī\Y?ŋŠUÃ=JBSËT!!å"#ëÁųĶMš4lØ7öųį_HMM劊=ĸ<č\šôŨĮÓģģēBCCÃÖþúë“ĮņRĩWMĄnļ9AŪĐS‘dCðcddÔĄęϊ6ŒG Žó9ËIKsĀG2 HN€ŦHø`ū.saLČ`úëh(šŽa”ÂUųAûŲ%)ŊU34 <“(ĶzIRŽūŠ%Ķ76Ë,+zfyĩ+=ZÜïMx–ø&đNęņyeBĩô4øó\åĘ$féÓēîÖû8U—K2šˆĖ‚*ƒėœEôoWJ{Õ`ī@ĀåKĸœL8uįö-V1)ą6ŒuU™P}kËÅ˗āŊ“ą>ÞNL9ŊÓ4ŋŅæ „H#3í5ĨĖmÓė\đ8ŋLhēqQó–ü]-ŽpęŌO5>+Å FB›DāÛæÛī|ŽÚ_ū$FŠ[m+0šŠúXf™eEPDQķ†(p2ž …P@ðøņ čÛ·_ĮÎŅQ›tŒŽ -#éFŊĢFÕŦWïÅ_ž}ë6n,ČŦQŦVDíFQJ–, >zˆ3ž<ųņ‡đ?ΛŧkĮo)ĸþkš„2ļxôčáƒûũAÞþ}ûfÏúrݚÕ/\ ŋu+yÜčQG­Q›`…;//vúīïŋ›ÃĖÍZķjÔīéČŅãļņ:ņK…t0U―\t;į4 Cņ+5øx Jē2ÔK=ô6ōēvĄĄĶĘ:Dī‘Á* Ū)Ļ‘UÆ"NÍr35u„ŒÅ Æ4ė-…alšiņŪi'É,äâ‚hLŽÃf™e–Áj1Ýēũ˜„xaęĒŋę·rÅRō †ķjÍ:†fddvlũúôĐ/ˆ_4oþϜ!íéĮūŋ~ýęÂ_âq<7mûíΝ;ŲŲŲW/_^šäWNnýmGNNœy·Ï[xvęę ō\~.žæŋûvöŨß|7wÞžÔ”Ô’ĨJ~=ëËŋsïÞ―ēeËîÚĩŽoÛąóŅÃGĖ™œœžwŨŪ~vëÞ=1ņüŋwï8y`ũhÉŊ S{=ĻĶKTDĸ“ƒkFĻzbäāãeĒŽ] ^!T·ÛK°ÆîĶuŪxsėŦy+f .!GBmýtӟ`°rą<“(ĐĩįŪŠ ĻtũSÐîėkČÕ4Ģ5ĶSyžUÐKĩlP™ŒBFíéiāHÚAÐf?Bj“uk6Â8ƒŲ5zĘYŪ–Ix_―TU/3ÍĶŽLÂŊšĶģHËĀxÏ4$įž*.˜ð…―@6Å XBõ' 9°Ė2ˊbķŅĢ3ąpba þ'áEffļ4yK §Üj˜tQWÝđnÁĐÏšßð•ė+ ÖøđĖlũˆ é#j/Lۑ=YBŽ={ÔŲd0(S~ŲĨs—2mėŲS‡—īķ5YVž"cT|đ w>8‡f_y™û―.ÓSR•™[Ļ*U"Uƒg­ņYuŊÕsUw• ŽÏTĪKËԘPŦŌė…@ķFāËÚ깚& ęÛjū0o1Ôä՚î垃ú/\/š―Å,ģĖōjņ:Õ3―jāõä‰ ŦÍŪb„ø°:vš.ļÁƒ<ümûķæMN8ųvŸwH‹ýxōGh$ĒļØĶMŧĐũô{'fčÉ?tŧóĒ59ļo/‰ąxqąŸ2ĪaUūMÖŊ[7eōĪ?jŨŪ}dÝú _Īŧ Tß{Ԉa3bcĩ4Ë=Ļß;sūýpŨoÐ Šq38;ũûï:ul?í“ÉHčvŽî DnįŽf͌‹îÚÕÏÏoîwsfÆ}vĸþý.]ŧĄ:ÆŧĶ=6 đhÚc‘—*ęč”úZu6 :Hou$ ˆ\kėÏW{9quĩ Μg§Ž‘ļŊ ąk܃p/&҆qʏŲÔ;֑†ÎÚ XfYQĖŦ…­ė)8$k œ2\?\<ÄĀÏãāÏīš1­ÅáÉÖ͛/'&ūՈ‘ĨK—Þļyó i@ØĄu›6>œXĨjUäeYņâÅ V6’áv[zZÚãôô Ā@Æ5îÜ9šiAđŋËoRīļėbééi‡ ÔaįΞM8ņ7,2uZųŠÏ8žüûDRō­ĪĪ$čU6ĪėõkW9yðāŋŽ!} léē\ÕĖY_qÁ\ï“'Oˆ‹äåäŌYÝ4TÚsWzŲr;xĢÜ /MÜV$ld€–˜Ždb ĐC í―fú˜yÛ@ģfn @å,ƒ™™CÆj‹|Éå`ŋQ+ð._Bfv–Ý2ˊ Y oT AĀÁąf˜:yøÍĘČšzíj‹V­ÚīmsðĀˆ{•*]†M|éĢ"5ÚéKŠĘÐ=@&';Ëåįwĸþ―Ï>ĸžIÓĶcĮŒš™œžzíz)ų5ÚÚcœQĸâĸÛķm]šxï]―r™}$æ„kË”˜Ō ‰‡jų™ņĀÓÓÓųũđį*s?.—/ĢóōōdZÝîĮwd,7/\~2ibbb"î-áðVŊq?5%3#ÃKĶ֙ÅĪA#<5ē;F ÎÂOĢ!Ð*:^ÜŠ(Ðj·GÓp<;íNþ6xkYSē"įM.CĘVMÉ(45u„/ˆMXÍÉ-ģŽČJƒëžŋ]dXĩ[—Gsþ}ý|·lބ°Ö€Aƒ#ęDōhO'G4 qũ0SÖJ<ôܙӭ[ŋ3rTbâēŋüüģÛ-äjÔļq§NŅô[âÎqČ{Ã7išsĮïˆŌvíÚ ŅBZŪ\đ~}Þ˜ Ë(―E•Ü[5e™ĮÓvķÔ;ýũߐ}ĖøũŦ†‡7mÖ!›=ŧwÉÏÔ ģŲEXāĀþý͚·üÞ°#þvöĖYĪm/YķmËfB…Ģ– ˆ1ʼnÅĢᨔÏI˜nŽq%zlWd{ėÂJAôSÛS>Ķúhãš Ŋ…Ú‡3ÛĢĶ―„mZ@l*}-ÔZfYŒÕÚĨ„á2ēÕa‘Æ‹œôũũĸëøą˜áÃė߇Č9W._ÎËÍŧtņžÝŧˆBQ"đŸMš~Ý”žŧvïaÓž…•+–ŸLH`ŧ ņæ~wøÐPĩvՊƒöŨĻUŦzÐųãIé§ðzÛvQ§ĶĶðTnïĒ ķï―ŽUYbßÞ=įΞáI<+;kĸū?øČ•ŦWƎEĀM0$Ã9>öLÚĢG\ŌåËÁ3OčK]„BX`P`—nÝ*UМšz—ÞT–IIņ’Ė6ŌxE&FĐ'Ė…Ąāĸŋ'‹*Ÿ‚fņbMKv†éķX!sâkũÜ#1N8Ûôw0ú F‚ŧŌ|ĩĸ* ˜Áf™e–9Ŋ–ý-ēöĸ‹Ī qäÐÁ„ĮCBˑðï[þ~‹~‰_ðӏ._?‚ WŊ^‰>ī|ųŠļĨ·n&9œÂߓ ?xp?;+›Ų ÃÞęÝģbÅį>|ā°eãÆ=ŧv†„†fgfÂ@z4ā]ãĶĨ=;j$> ŸË%°žÝŧāmý{įNŪ]Øĩb•CûöžJøŦdĐŌĂģ22ŲĢ;y2Ą{tįĸĘ. )žž5sÆĒ…ņ|1Ðdv‹îHōƒ • B+…åĄ')ę·zë·!ĩ’lk*r\ŠČVk`WEnŠ‚ÄlšŨõL=eNōAü5…ÎJm’mģ­X­e–Ņ‚ÔûS zÔL‚Į óî;ƒ!yģþþŠ þL6Ð|Ĩd65å./ýü\ļqЋļm^n.ˆĄ0ˆm{#ŧE#–äfÅGžy# rÁJÖ$ŠlÂÁÆič@:"˜`—ķá>ęoōYo›Ó–•“••Ėn=yž=Ëd%J–x&4ī›Öķ NO{ô$ý1yt8guzJx™îįv#Œāąkā@JžæãŽJý†Jé^S·f4b„ĄÚ͌ÁÄL‚þ·Ļ‰ ˜â]îŦ@b_§/LĮøÆeŪĶÛZfY4 ĩvųõq“^ 2^˜öƒ&ļrN8$dQ—B)ÓÞ·ü؄64Bø*OUųÅ ģUŠ!Ã)ÐâJüh3D-KÓķfę3ŠF—ϕŲ‚ĸz%ĀMãię•ęÞ5i.‡ÎĢvŦ•šĢ Ë\žÔˆ 7•’@ðW4dôf™MŪžzíüH˜•ÓīÕ>ä.īLVßVëb ö*En:Ø[[éĘŌ·&ÄŽšbĪÏē dĢJcjęļM7ÉĪCĀjöÍ,ģĖē"ρaŠy›ēTxĒ\ðNÓøĩË·binĐŲĪō‹MDԁð€JpIû1ũ2•ĩä°k vÂ:íú呐Ĩ,"Īóq9Mø’åŒ ÃÔÅöHMĀD;æĒÓð ß)›Ýŧßá#ņ‹–ôxómÜZ•;8kŒÂFV_ÕßēqXwnPVEpįÆkäFļ^6ļ`ˆ/`^·›ðÅÅÖ<î›"cjÐpĀx;ĶŧÔøÚ5―T$ŧTfړ‹Fh˜üģwßíįpðŪ8ķOUlãææqõ–%ņVS *°ļŪĒë(WĻ}ŅĸEQėL㐎ZÕM€ð| ĒJc·EŌ,ģP+ĩų°lĀÍ:€lFĄĘUŠPÍuüØ1’īæÎ7lx ­hČųÏĖĘĒ( NÝš<šMŋ/G•(QĒi˖v›îž+ƁðųŠ+NuYhÅį lPp‰QjEÖŅ}ģŠÏUjųjëråBÆx›GžË+TŽøRÆū.Ū„^ž 5ĄÏ#ĄÓ  āF͚֌ĻÍHT _nØ(ŽZxVn6ägõFMZpņ%K•ŠS·ÞËQ+W Įcõņu"…ÓĻIģæ­ZՎŒ„’üi!ũķzš  Ē/pšÝ< 1š4oåįįÏĨŠ››—KlƒĪīJ•Ŧ˜:…b%‹ŋÔ0Šô†’ĨËÔĐÏËÏ ŦV­AÃ(čož[â \Ī›ZQ:w8‹ĻŠ—e–YĻ՞ļ’âEÂ\9ʁÂ&ûcsã†õcb†õ·Õ_C† ô,YĒÔüø…ËVŽ\īdéü_–)[ĶrÕ°ŲßÎų|ÆĖUkŨ/úuÉOņņeʖ5^ēŨnïŅëÍ-ÛwÄ/úõ·ßwĄō•›“ũŏ?ý\6$–'Nþyá"S Kx“ꉹã?ذyküÂśķlCčYƒĨËVDDF>LÕļņŌe+ЛĻZ5|ãÖm .\đfýĖYģ)–ˆŽWoþÏņ#FÞýĮþQcÆ.øeaėį3‚‚‹ø|5û›ĐÓ?ûfÎũą3ū(Uēt·^―]ķüÃI“ųËŅ―GŊ%˖WĐ\•K%ũ§ø…|pûÎÝŊ·kŸ“™Õ°qs%ë7mųpŌ'Ä1ęÖŦĸõėoĮM˜°qËķ‰'ģæ^ÖŽßȘeŦÖÖŽ‹—ïŅÜBĘâČãžSyüŒxI~QQīĖ2 ĩ<ðš‡tITēK~IģŌū6^…éÓ._šxâÄ j|ý]ïöëß―GofÓ3ũKd'|4‰˜@é2eÚīkũÛoÛþîøF§Sï`Ē5kDÄÍøŨ’Š|ä1cĮQ3öįĄƒ5jÔxáÅ‹+Öę•WŪüsųIf†îQŲZŋÞvâäÛķõà ニ‹ýbæđsgIÔmŨūcHhH‹–­G8{æôÄɟÔŪSGší.[2`ā 7:GóŨ‚Úģąãßgķ;vKŅZå*•+‡…5hðōЄŋ/]šX+"Ų„ĻĻ(Â3Ņū‚+Wþá~kՊ ïäæ ŸáÅ=zâAWĐJ•ņcĮėÝģgô˜ą―Þ| ß6<<ž_ŋwĸ―Ãýū=tØðå˖r%Ï?ĸÂ'S§SÆ3/ÝeKQ~―ųn ī՘­ĻŠ(Zf™ĩ-Fðžšø#\Ā${I[ŋ؍ô—TCų˜TbÁÁčr1ļYófm^oƒGü\ĨJ<,3ŅŲģgb?ĸó|‡F­;?OĶĘÏį)ŧxɒ۷m‹‹›öņd|įĶÍ[lÞļ‘ýĨ7:uîýVTW,_žþčĀĮŋf~Š^Ģ:ÁSęr™ĸŸK—N<‰Ncĩððö:;zô^JJ―úõĄ^ttôË/7ä(Õ%2+ę [·öęÖeÅē%ŋ.^Dp aĢÆïöíO4víÚÕëŨŪå |ŊYŦ&ĒbÜx‹W^­];âč‘#ÄRyÔøðáô)“ü8ïΝÛļŦÄO0ūƒÎŅŅÕŦŋȗPĄ\(ai>ÔđSViÖĒ%‹Ö­[·S§N\mxĩpŧC4%Ā,r6lÍŲÉSˆŠč3„Ú"i–Y…đŠTB–JöņE[߁ĶðTâķŋ—ˆĻ] ėÂJ΃E"ķŦVŽĀÝĢ,UŧŨHkE”âÁ1óČl*`Š]Qí’ô~?Ũí;·ÐŦmÕĻ]ûöũîÝ;sú”—HK5•Z…*ĶõĮžÝëÖŽElaõŠ•*UęÚ―gųō–/]LU.žãâđĘ.^ļˆĶåmåðāáĶ 8väOŠƒÛ·ïÐēU+ĘՒo$S–••E qÉŌĨŅØ}ôāAûŽCBĘĄ ™‘ņ„›†ÝxŲð‘ŧæöE™ÁnrđLĩpáÂó‰|].níŅĢlŠ+V‚ŒÍ'{FüeËæÍÔ%KėĨ°ÐýÔmũÆFXó$›Mþ-bf™eVa.yĩÚ\ÖKƒķiŊ­Íŧ$ũ ĶÔĐ>{í―ßîąxŅÂ[·’ïÞMs‡ PĶ\ˆfkI ÄŠUŦÖŊŨ/’.Tʈb ÚĖS§Ndýz‘}ÞíËÉkWŪÜýũßÍ6Ėų~.ŸÚņûï·oÞÔëa&AÆ_8nՊåÁėĩárCHKKë?` Rĸüs…hÃݔŧåBĘmX·&ųæÍÐōĄĐ)ũŠV­"w$=͜M°îïŋmG pŊ^đō^ĘŋÜėņĮ_yĩ5ŸÝšiSc4qĒŧddd$]ŋ†GŊÕh&ųAļ‹ûũî‘íðLÖën&ß(_Ąâƒûũ)/6šŽ’™ųÄH8^LLDX’dŽD‰âý&ī―cûVMrãĀ–ė°[–Yfī[Ē”HsîgÝ\ĪîŦ€#˜… 2”M°ČČšņņ >6…GėóįÝHJš=gÎĶíÛ7mÝÞūýîÜ\ü8RMŨmŲÂ~­VŊ\Ąuš6Ī ï?ðӏ?ķlŲjįÞ}ĢĮŽ;tðÐÖM(8Š^'\ûcïžĖĖLæ”üӕ˖îŲ쇐îÖíŋoØ*Ž$fzöĖ™“'ĸd'ŽŧxáÂãīīđß~ƒFâŌŦ؞ZŧasÍZĩÄg”nøÍÎÉÞģkn,Üß―k‡ŋā―”ÔüÁ:·nÞž‘œt!1=9ųXtúȏCw !|ÐaļqýúwsūAwųĘ՛ķþķrõZ’L˜‚›•:2·{íęÕ Mœīa˖›·ö~óí*UÃ&Nš<<&†ė…B-“"9 ęō[Í2Ë,EaOûRA`g­öîö ðCVbjŋ4ŽMI―‹X8Š_DNŧFŋņĘŦŊáå%üuüïŋNÐ$bp1ņüžđßÕĻq`ß^dĀ‚KoÝĒyVf†ËwFė§ŧwþNŽTrRŌáûŦ_`€›IóÝwïÞå-oo ĖQD‘–ö0fčāV­^ á…Û·n9|˜nĀóƒqãf•Žŧ›’b:ĘėÝ―ŧÝkŊÐŲŒÄŽãGœ={ČķnՌ?Õ|ōÔtaįÏ㟑Ö3vŸ kÖ=r8=-š…U˖îÝĩŊŧ|]Æ2%ÅžÛŧ{’ŌƒƒV.YšðŨ_ä‰qãD3’o$AįV͛€ï€Ā öŧRRîöũíĶÍZ„…‡_―ōωcGÓĨƒŒcĖeH‚­–`p (/zf™eVĢ%ŲõiķÂ^ z/… )œUĄ/S%ó Ũ­] J`%^Ã}0§ĐÃcGŽR 57;įâĨDi‘+ÂޞŋNˆũšũ4Ī]ÛķÕŦŨøæëŊˆÕšĩÕæ*ā ŧyózčdÃīõŽËŨа{Đ)<ޓúĘŌ”K\ŧv-éúu†+á]ĮģÄó‰Lnú)|4yJ‹–-ņ|ŨŽZAągņ[Ÿd>đæ>—ÄņãĮév øųûQ"qãzŸâō íĩŦW9āb8O·īË/Z1šß,xáŦ0CÜy\Öķ-›Xu€Žr.a šaÍYæō( Ö?ċžYf™•`šmsYĖąŠUyii–Mĩ―ĩs‹ÝÛŨŨĨ[@’)ËyˆËpð?HĸącG/]ūÄy°b°™ÅĖÆŊĮԚįnÍ/ŦUģ&%°S>žD0ĢŲČ$pŲÆŌā^dÂEÚK]]LĘcíj,Álð‹cø ė8f—aWĐ›&ó.]?~ļēīÔÔ)‰á>A/―f™ÁĮeôeļHŽ%e;U# [“wUbc[Q4Ë,ģš“ŦiÃĸŽE†UđP uŦĒú"-^ăM ü™Ū„rė%?ļ–ãGœ3ûkķՌЁŲ’Z[čėšÂ`­™šÄÄ}úiŸÞ―æÏûÁ­åXZ#+þ >ĢÁ(XÃŋ&dĖģāYåŧ0Îr…*Ó%1æt*p!ĩ!)ëa#GžũÞ þÖĸ?öÎgg–%7îAföŅÎzųÏcû…ŋ…Gš;ũëJ’á9UßðV §ŦF!‹‰ÚDQÉĻĸđö^Ŋmļ§ą^Ŋņœ:ū%Õãˆ`POė!ø“Ÿ[Ãí‘ÔóPŠ™oIqÎÏÞDßŨzĶËD„0’øðáÃog =“+I]uČĖ:glQ{ŊšCĐs.EüjũáĩvU‘ô—ĸý—ņ(Ä1I{žÞPd!ŲėŪîž^ëïáö“uŠØĮ)1fÚø–ōК†2óœ# Fd^ŨÛÆÞ/Ju]+âūxˆŋį՞ӊŒˆįƌļÞŨxHíŨŪnŠ4IUW„~…{íꊊŒPDW“&@ā}.ŊĩmũÔãŪļf`<7NŲ&ô„{QĖ}ĪöwäçŦĩW.·á 4ÝĪöÚ*Ou%ąŧaĪvMíĩ^· Év|ŧö˜TOŸs’Šۊ˜™ŠbíŨĐΌŸŧdžš#VŽ[”˜3cĀvdbLBb@ĸˆÁˆũû;j–æõūBRÄ-J)# @–ϐŧ FĪ Q’öZķŸįēý„=ãš.)öÞ=c "ÖÚÕm1ŨĒÔ=wĒÎņ`å"ØŊ―Û?Y+I<>2Āžé|øðá7<`ÏL /…fflÂKyé™ 2óiýĀŲ݄ôļÎҊ\ŧę`°ÖĒÐ5]“k…âô˜JÏtwdŽXOŨđ3#Õ5 3ĢkÜ )°Î΁N3#§OdĶDÕÉˈðļŠ"ú)ū’Vį\ŪųiėÚį}redLwũdD(Š D„ˆ™ąB”YŒüŋ_ū!ĻŧūČ`UŅĢHuN(”ņļ+$Bqꐠ‘Ũuyžö"é{{€øðáÃo—ėeŒ­ÐtxôŦš„īũę)Cß_˜šPŽg<ą2ķ{ސî[RCŠ/ƒ„}ŠsŊ\yÕ;CRœŠîZkÍ4€:cĒĪp@ÕÐ3€ŸÞÆĖÜ:ŌÏĘü |Ŧd(ÖÞšZT(0óļ%a6Æ4A‚JācGdW“ī‘§ 4Ý:kî ĀL?öq„ĘÃó 3 \Ũ#â·Ė@øðá3˜[]+Áą dÄtŨulŋÖŪî:’ÖĘSWũ|žÚXÕ]S ffwßęķ$ŪĐŲ{GDÕņLFĖ/FՁĒB5C†Ī™ų–žŪŠ#Q`ŸFRHÝD(§ûýõžAŪėŪÁh)”§NÕĀ|NeČ•$Ūë óĩ_įšÕp*CUõHjH=ĶŅU§ęûEßīB&ŋcŋ=†Įsꚙ`ļšHF&…JŅÕĪPð:ō‹ĀاJäpØëĩ"íąĄßï/JøķËĀkĸĻSĸ†]í‡Ŋ–†A@Œë\‚Ž4ŧ'RūÞoÜi{|øH-1=’_ųúóú"‘+,O §]}2ŪīĒNE0"˜q}]ĶW.įœ:ýýæ ‚ĮíĄŒũu‘ĖČČ<įXŊ=]5&˜+§ŧĮ WfO·ĐW}ŲΈiØĮæ~―Ķgj”ZĘÓgŒĩrf<(W2ęjŠ™yŠÐČĩî ÎÜ$ė^+AUĐã[Ž{zĘđč}™þ§ŧũÛ6æĘžÁp*Š P2t―ß)‰TĻšh)Ā9'Ļ•ųūÝB‰ß‘>Ób€īÞį I4 SĪpCi­íē§§ŋÝI+2pۚ]{ŋ"ĢšĶGRũ€Ęîē #ĻŠ‹â―  ŠĘĖžŠn;ŨĐSÝI†ÔþņÃ@wyuUžP\ŋfh^įǘJ§Î3Y03Č―f$C"Þu ðøģ(~rŦķIR‚ ;WtÞÞkMŨa`ï}Îéą$eteDÄuNuƒ˜žiRčtÛū=™ ~G>|øxĩkųQ–―BŅ=†tÛĒ"ŨxK‘+Nïĩ”:}‘Z{+xÞÁČĻ)˜DfƒĄ""ÔĒ"cÚYįï:™ä·ÞdčœŦŠũĘýÚķAfĘÆ?RÁNUO–4Ӏƒ\𩠠RŪũ{z‚ęūDŽ―kJíđ‹'És•Ë+sܞąŒSõˆāĘž-ãŠČGÓm?u SXkĐĩ’Æé2MSėîɔ$ÏHJéœë}ND>3ņÛņáÃ'nĶĮīđˆpUc+ŠlI‚Î)‚™ Á†EØÓ.)”CāZûŠËc­•RUA…kðĖkïOwJ{ŋîīÆāø°ũēÝ}"–ČsE"ÖÎë} G†íũđîj?Œą―Öc4ũĀĄÔíö†€…ëë cåqęPZđÎõ.L@?C ŧ`D(UGāB†s―CRė™9į"ąŪũÛÅTVŸKRčëý^™™Ë`3ãŊŨu âŽMŌ=ÂoɇŸŪ–ŌĖDætŸë€ØŊÝ=$"s­U]5{ėŒ€Ý1L·§o‘ŲÕRëŨ‘R=]U{ïą§'DR=Íû‡2ÚOó(IӃ_2€ˆXU%x­Ïõ™―Ũ―yOB§NÏ(BĀu.‰ãånÏäJãhOFÚiįZ{?þŽRëŠęebͧB‘Óm˜VæúņˆLEuÍxå @ŪTJÂđ.Ãûõę™HeĪ€žfČ6~G>|øäÕbU##wėîņO`ûœ3v*žŊkš#47$ ØÝ’NĄxĶÎDF€Šųú§ķį.,ĘpŨyúÁîē-…įmUîUU$!FDwÏLū–oÉÎ\ûõØ3žYkMũØĢ<‚Ŋ;eqfÖ^Š öŨÕu‰PÎ<Ę zJbîeĢĮdͰcåx(Ī’äĖČĀíïÝŧæÞ;wÕ!3}oMAŸ „ß“ŸdŊ >jLōŅÖČY§ßSŨũBLUÍØ+OŒIūöŦšIØōœ ãÜŧК•+5ũb’ņ4Ĩ”’|ŋߑŌĖx†wãyŪŦ§ÅðĀ$’ķÏuI‘k=Ú !"zūc_mĨcw•ĪŨÚÝM1rÓļŧxįJ>& ™™$OĘ1ˆîÎĖéē)˜U—2ēíR"šš Āõʞ@Û@Í(‚͙Áĸ>üį€7ķĸcĪ–āu]ĸöŨ?ŧ{­üģ ķÓŲSÝ-EFtwWSRčŨ|øÏADþ]O~üøņ#ĩ§ęŋýũĸqÎõzýŠHŠ:į )5C0ŠND<žąWŪžķ!"bÍ-ĢOoØÓIĖøÛOČėÂķsíîß`ŨQ%ߋU‡‚ÓMÉãGF%Ú°ýßóu†UõÞŊęCƞiP’úE„4öxĶg­ÕUßۘiiļŠÆģráĒnXātåĮ:čïk cŠ˜Ä]ŲóĮŋĸûŋüË=§ð ÛĸüÏĸå_ĸõýöî=:Š"ÏxÕ―Ý~Ķó"!Æ0<‰"H\‰ʘ5‚‚:0>XĒEÁ°Šb N$žŅõxÆt˜Ž(#ÃjÁeÁēA!ðH óhŧ;}oÕ­úmú6ĮģƒÝ™äxæHzęs’ķđ]U]•?ūįwúķUO3š–‚ĀËÍÍéna‹›››Ņ€ÅbŅoš_ ·þūBŊĢŦDytþ.Ý9ęhQŪãîtDÝ9ZGŒ)ĄŠüĸ…mčP]ƒ €Ū)‚ `Œ4QJŧĩŨŪᔥÛ7QšĸÁAĩ‚ "jADÔ ‚ "jA~z$‚ðSĀú/F= čŋ€šGD­ ? (|Z4ęA$ Ã[jaĩ‚ŧ_䀘ŠBđ'ĀýĖŊč­zŽ8#JģŌ’Í„;ˆĻ)‚ČYŊŨ{þüųŽGMÓŪųäøøøŒŒŒÄÄĈ9J4ļčcGÏ~WįQ‚îYG%p9Cģœ}“MzڊĻ„˜ÞÜîÔĐSĐĐĐųųųVŦ]ÛEĐŊŊ?}útNNŽÍfûáÆu^ŽŸóŸ―äË蕘ž/K=įĀ'€V_{݅æ#g―Sē;e "j!H’ÔÖÖfąXrss{Ä͚S8p Ïįóx<‡ãŠĻå€Z‚üŒGq:Ģũv'›ĒïZ.\õü*Xïü#Ãc #āú–BOPß)Ž=Ũžņ4úī §l2 ĩ‚‚Á`GyؕœUýÍ ›929“’S’rg=˜â*„`“Ųi·Ēŋ‡ŦþßþozþŽ.åF|||sssÄ9Ŧ‚2ėķŦl“ĢOP °[ĖĻÐ`;ĩØŽ‘ZĩŦØh3ŅÐxüó:ÉU˜“þõÁ―‡ ĖpĒ($Œ“âmī(ˆÛb‚[āĘcÔúOû|Ï֕ëŽų%+G '―øö'dÛ"wÁĩՖ—­hÐļŠ‚qôû? ―ŽlåÂŲĄ‘đE’LˆqõTŌ"Æ&ĒVbčĒ|ý0ÝũáŧmÃĶĸ~éœĖÐļ{üälĻL#ĩûķVŊÚxĶÏY4ï#0@$Čg’?ęÎ!m/m9 åÓķ•UlðȐqe•‹ĶĶÚāËßZąėĩó ÆÍ|ō‰ŧŪį<ūŊĸkQÕŽÉ +Æ H$”ĄHšr* b •Đ!HĶïãÏÃįģ"ý0C@_ū·áũ'ĖōņkŽœ,Y°zŅôą 'ü*’ŌvŪzĶ6Ū_íĮïÖ֙Ÿ[ũĘäQéjĸžüÅĸ8ÖÐ6~^õ/Ýõožþ‡K{Ïûhöšß―õÂsoė=H°xÉē{nČ`h†#$ý(ƒhQŦ1ĒŠa‚ˆZŪC`Î4Ŋ/0døõ)IQ $ŽŒĪîO3[{ïōõˇðyÍ} úl.Į‰>q”(Ę[ՕŊŨügZņâĒþÖs-Еë6Ĩ(”oÜ_ïQ.·Ŧ-'ĸúI“óö_M―ģ“s@j[3ó~ĩdæ4ũø—ķUŒgūítķŒą.ވŠj”Ā RÆ9Q QĶŒœĐ 0eÄ―Ï.|ĻøâZöĶZŸB4†0`Š)М2ĨžōÁņCwéŊ6œûްü &|ų‘Gū}xþ“ĮdĶ$8 YYŪÞÉ,čņ~ónéĶú ß6ĶįaŠQĘ4J(a<ô_UUĢUĩŠ c ŠZAøįŦjã895íķ80súĪ<—Qƒ“{wũžZ>*=CkŠo ÐīÞØtŲ\Ũã€xŲdž}úī)î1{†ÞņæÞĸÞsh5Œ˜ģpŠĨėØF°ŲjĨū†sžķÁ‰N% E5X]œs?Û_―uũČcú%€pŦÚč+BǜáÅmūo?Ŋð‘Đŋ·é‘dÄ€lL`$ĻĻD ŨžĀ8ãLâČa’BŊĻ FFŠY7=úúÛw―·ĄtņĢų‡6*„š5fēX―YūΚüú/_Sšs„€AŨį́wRÕę+ÔMęųA `}Į/zéĐŲĨ+Ölܰîĩ/šˆŒxÖĻ)ÃÖðėģËŨ­|neũÖŲĸÏ(G:āmžK›V-[úø {ÆĪëÝę­?þŲîvų/Õ}īý“ÔÂIũäœ}Ą|ÁĘUUkķÔī4_nžŋzɌaëŸ(Ųö—Ø`Bĸ0ĀHZ^Ņ€Ėóó,yåÕu/Uo^xŊˎ(€_Œ€kĪ―!Ė5ÔŪh# U aÄ –ĩ=›—―öÎÞÆVÚ+=ÂŪŒĪm›~ûöÎCē5Ĩ―đþÐŪũw7j>ÜųņŸLƒAę˂íœqÔuĒŠ„ƒu("Få„ėįŨþņķÞ?rö’_Jœ·ŽęĶL3wäŽZ―ņíŧ|ŠīdõŽqųŨĐ˜”0ļęĨu—=­ õŧŧôæ‚Üū―6ėÚĸ•5ÍĩąĻøD―ŒîįWĸ―—ýôšþYÎ^YũÏŊHN‘û>ôęË}Þ ˜™Æ‘ŒqīĐvyAQšr͐<ėåõŊlßđįrsûˆŧÜUrŦAQō&>þLa RgfÁ‚ŠgReÕ>aîŋęĨņÄŌ_·§ũVĻ6ôÎđ•#í&‚úVĸE#öŦUå“\žē°Âüþ>ðúųĒ5hĮ_=rųŌĩÓūųš”ž{žž‡úĻ ūũĐĪ> âž0ÖQ+ĸ”Gb LÃæ”ĒiqŪŠÕ`1jé•ýHiFUBŊ ™ÓŠK͆ĸĨQĒš>hėÃyãįP(q%HpŌuũÍė\!Úð1 Šļ㈕„~DÔb$é?ŅV„@KČōoeyIÂTU5ŪÃݒT˜51ó_&ö%A%~@A–~eāM·K,Ôȕ3ēo.éÏFÝ7x4’4ĒŠÅ§š5'—3JŋmęŽņ8ãĢGÞĀĻĘĪą.Zcî-ÖŅ–E\™„ŊĪ­Nœ˜+1D–厍fššš €1ÖÅ<€ŋ―ÖÕĸó!nūĨkT’$ †ĢGZ,–~ýú]õ5čĪGÛuô’Ýl3()#^ęY'“ûUtð”ĸŦs­7įĪdÆYM˜ƒĻjĄįãœ;Îššš“'OšÝnģ،Ūm„úúú–––žž<Îų Ã$ŦäNŠ;uŅûųiĐ>Ņ&KÔ3`äõ+g[ŌãMiŲ !ņ‚ İZ­ŲŲŲáíē8įÛ\#Ÿi€,ˇĢoßūvŧ=âlq87ÓN(=ãņÛԎ0B€z óÞÃPwBGÔĘņBŒDājšą5ļA‡1îdkð&ŸvÁK} @=ˆŲˆÓãéNĢ=w@"jc“ îŒõ]Šē9 ʀqÔģHd,wóæØĸĩwĮD0E4ĮKĨˆërM œŪâ=ŋܕZĀãg^_l{7āR ĩR €ÔH-Ïã8Ū3^îų–ŋ2[UŧŦķwtvwŦę™ŲÝ3sð#3Óݙo™öĻ“‘·O#IENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-ready-to-update.png0100777000000000000000000022250313761647206021413 0ustar00‰PNG  IHDRÎbðZŊr% IDATxė•OÚ@ ÅQĨ\ŸūĸņĒmUeËV–eB3ĸč•"Î5ąxĘÚe!ĻÔw°fėįąũGĪĖfģ<Ï―ũŋ>jŧÝĘLRšQ_áÔÚív(ĩų[;å>ígݍtþįÓ]z2iō‰Ļŋäž|4ŦKC…ĸĶ|Ōšœ›ũ>Ïóétúi8ŽĮã,ËÞÏ:YȋŌņx䈌ü$xЋĪ3zŪūē° K˜ĩöû―ZUšg<~>Ļކé_ä#žM\ÅÜþ|tW1.Íþ4üþšþ|ŌÃ~ŌŨÛņ!=8Ÿ,Ë&“Éh4cBÞûĢŊEWį\ œB-W ›‚Jņ,šƒ†Ē]žÆ”Ð…˜xŦ6þ„$QMðA„āžTKĶųģXƒ Éæ>||Ríų4[D„DWË4}čĸý@ÝøB>FÃó°| ž|Ø`ŒTUĩ^Ŋ|”uŪ4f1ŸŸŸ^ŠâíõÕZKN*UĩčJgnĪkY–‹ŲįWŦW›Â*Ņԗïßū_žįÅōmI+q•"lBÍҜĄ‰Čc7á-ZÍđ ƒXI 4ôâ §^TqhÁ§ōqƒįķŌ”ÎšS|ÎïØHų+ųXį‚wåCÆļųyŌ&:[i>x­þ/ë9’QðĄóU|XšĨ Î 'ūüXhĪTܜ"AōTaӅ_œšJÁ0ąÎÎK{íũø I‚ŋ=$ÛóAŠŠÏš(Éþî|(vāCž?ō!i>ÐĀÔĒNîgûóÓojŽėđĐėxóį$S™š‡@%lNÆĀÃ/’ũÝ

dĐĒ7ŅĖĪ=m؅&ąŨü* F(+ĢfŊųvįln%•…鉑á‘'“3žžÚÚČ$ŸnO<(M54qŲ;7;;7=ýfvaIM€?įÅAŒDc}ð"đõ!Āīq…žbÂþ#CãÛûų( †ĄŠ~ïüĖėėĖôÔTÏLSR6ũ[æËņĄņđ°•ēõ†­QÉĻfĶ I‘ļ—ÜĄĨmýóÁ‰į™S1v‡úØÛm{}>~ū0O;Į^\í’'ŠÆ‡ęÆGÖc ā”ĸĒ>ŧ ÃHd`šĶ‘‰Ü))ýõ>ĩũƟB‹ÖČāëãGŪåí_ž™(]Ũ Ôaefpppll Ðáå˗}}}ĄPΈ&ÐŌķaFĒáWi}ïņ9zD܊-‰ĩZðÏ[Ķ…™€§Āší1·Ÿč$44˜!Ō`E#Į‰@īŅ@ŋ˜AN}ēuē•íšč$Ā$ņāÜĐ>†Ðýŧ}‹›}LúbÓĪÏ; SØąflĪ,O2frC^~Z|úō ŦÂk‚8@ķāD…§ßužøäðÔÖf`ī·īc€UM|ëcĨ,%zíœ3?ĸ”ëVÏŲüüâšÎŲ5mÝŌ}3SļēžēHæ ã{UWp°ŽķđĨĐķųʍUÞH%-_؈œÜė#ƒúöųÂ]Û|ýhęž]šĶĐŠŠg6ļžvußĸä§ūØöĸÃũĸųdč_#þvÝ5đûģÁšIĩ “““n·›eYüÕWÅãņŒŽŽJ’„ē™#w‡zNšvŋVïßM1™áŋ›ōn:úó.Ýn’$Qۆū ô ŸŽ Ķ}xą1ē"%@YÜ%·Î)Bķ&nĄ~ށ[ö4Č €ėäėúāYxrPg‡úč {óĖîŸ|’ï~ĩbmnr>ÏŅ―Ÿ:q!Š'ežōû}Š—ŌW“…ð­@„Č3ÏQá%ĸrœ­”9ïfAmŨėŌ +(2O–|E ī‹ĖŅQ†Sõ„,p,/rņ°/#HԃŌ&SÆüoøEÁó ĸĨēč·•{Ôŧ†E.ŌqŠĻÕý††pRmÓĪį'+œóLrk=eZ”‡ŽĮxýÁHLÖš―Ýö…Ģõš?ĘÂ{Ļ"í_\„Ö$8JSy–æ. †âœĀÐ4ÃŽú—–‚aAŪÆÓÃ0‘@0N‹"óršVŠYö/..ÆX`éfB‹Ūžū+ĐÐÚvbÔėXYÃå6đđž‚YfĐ(-(0@ð|<ã%…‹ŊB-ý+ŦĒĒolh7ÛŦ\ƒÏuÓ bŪDBâ(†ā‘&æOS—^ķLÅó°Ŧēģg6@ÉŠÆFŨ^ІŪJá`Āŧčģ ĪĶHqšE~ŲŋīoĪj;ũ}ˆœïôū}7ûļė‰Āųʑĩũ0zėóeýˆųühę#Ëō.HþĪWU.>Ųóé_ÏĸūŅųsß7Wĸ―Ž0qpûĀ^*QT•ðIČČČČÔÔT4eYVŽãbą˜Ũë}øð!EQDR’ĪtˆŽīßĐh(xĝŸPŧ_·Ÿë=#ü—Ūų3Ξ‚X< T&!˜|ŠĒˆĖÖÎÄ­ėOļ9Ķa‘ķœėĻėėC‰ģÂũFB@]ŧZvb(KVŧąC}$>~ËqxïūƒUÝÊĨ?ëĸęDþį'Kέé‰Ũš+ŦkĨ…U}Œbq‹OËëŪ†Íĸė~MUUSCUáÉĢUm}4ĩzũ|éÏũŊmšð­Ÿr_‡(G:ę.ŦūąūšŦũĀð{jŠŦI”ģí.%ĶŦĪjšĨÆúŪV–^Ũ <†aÎ=štžĒíÅØĀ‘yĮN•õļ'E9]hÃøœ§ĐÜųÜÏp4ÍrĒÄŊÞn,r4·;*Š ŽޟX‘Â'öïÎûüh“ˏŪô_n­pVž-={Ï3ŸÐĪáM•U Žš[ßzđÚϖ”Ö—–>|ę\Ũļš”/·••žŠ}ąôÍW_>š7tiüîĩ“EŽ:gEĸÄīþ›ņ>GyeeEYýĨ{ŦœĒĐ ~§ĢÓceĩ_,3,MKŠ8|ĨĒĩįIÂ4„˜·ĩūâŲÂŌŨŪ 55Î/N]šą’ęõŽęËžZėbc˃g‹‰”õúmu]CŠ.õuŨ8œ%E… ÝĢ1*xąäčū#'*ë{"ēÐßYÛå~%ËÂ7ĸŨņےģŽēōęÆ+oŨxeí]KC}KksIqáąÓåOÞý0nŲÝhöONK|ČĀ$CĢĮ>_čīw5N N‰[;ϗ}ÅĀėųēOÐĸŽ>ķ™ý7-V[Õq…gî―oŧÏ~ŊxáŲ5KĖj'.Ŧ„B)ų‘”ĪI)(QŦR–P $eWKƒō§ jĩ*R[)ü+UĢDT„TB™%”4(8lŽãíūŧĖĖéyåčę)ĩŸ`4wæ|gū9úfæÁ―ëc„Cāœ‡R&óNCÚķ…ˆ{nĖó⁗ Y­&)ĨD !$›ÍZ–e~藖–B+„øíõõÂAŪļ‚5ŧšƒĐOŊÚöŌũōĸy]–ķŽŸÜW‚Ð*Iã_Ŧīü!s“Õ#­A/Õ8ercýŒ%?~þ›Ĩ`Z3ąbĪŊóŊzcŨïþpčÔu°M_oOYŧaë‚fãl{;Đjßš{Ļmþšå n|tā―ÉēĩOŦ;rð―ŧŒ„ÎmU2jŚ—O­s/^3þû›·o[6ŦóøßÎwåđTåļūvFëp·Ïņ1ˆó҉cĢfŪÛ°eÁÃMÁÝĸüýíƒM=ĩfųĒ|ĮíŨ…RĀļ4MyãĖÞ?ūąëũŧOu īΚzåܝýáģïwMck§=ųÜÆ­›ž_qáb§/Bb˜–yE™”*ôˆĮ€Đq3ŸXŋiÓ ÏÎëđrņŪŠ˜ýÄ܉ms^\ũ\M\ ŠB!ouÛ{bpņŠWvžķq―ō—ý'Ïï\ŽÕ>ēmĮķķjĸŲĀC‰þÚïūþ6ę|īnŋð|ņ0'īŒųqitiô3z@ŠN ę„Ģ˜eã,*ĮŽ–„ }åúuPöƒŨž>F·“õõAiÖĻĐĢMĢčØqtt3­Í‰ēJŦn„2 Ø PP™m۔RhKJJ2™ \ēétîYÁkˆ ô–— ņX™nWHŨŨ·—Û™$‰—ĨŠ ÃaQ•° ôƒ!EGëŽųĄ…°čŇã_x[a6ė N]>ĪÕ§ļņĒŽ#õAyúS'/ōŪ[ôĒ =jå/Ŋē“Ę1­đLĸþ}‡UÕč†aĖĮ―Ž3ïïz}į›ïœd‰* ÃwEeËīņĩʄm†ūÏCn%ƒĖÜŧpæāŊ~Y`ņxŒČ@*#…QøĀš^`‰0i›’ųJ *ėíũ%h,V·?ĢŲD2F­8UJxy_o„,ð=ģrĖâŪ^ŋf՜ķ:w0oĶkÆOŸRĒļ‘ŠYĶ™$Ģ*ôÜž+ļëuŋĩgũÁ“ݍđFčsÃnmiĐī…ãxnHrÍÍ%TV44•UŅ[ýŪŊHã„q6ū(j€ÄžŸ^øüÂĘkïoíŨĸ8ói_į8į?Ü·{Ï>™Ęeã&B(%ũƒdîëK–Ū^ŋú…IiŦĒebʁ―œ8ycœYąžÎ#ïüųõŋ=|Đ+•NDЈdBj)pB((Ĩ„Räĸuhïoví|sĸ1šNa!6a æû>DAPč8ŽŸĘ•Ä~ŨÛ8ĒĸÚgŽ? 2cmk‰+j'2 ŠĒþŅ-Ņ?ڊ_æŸčMÐn9:ŋŽÁxíŪ"—ęühfúŋˆ‚IŠtBGˆ‘"―(f+>__ĩ>EkááúŸŨŊß.―üĩ[ūZ:ĖŦAĮ4ÓąāŠđĶŦv&6ĐÕJ&5 ß øI ŽI&“vŪëBkš&>;:sCy3ŧ#"QžĻ(OU—'+Ó$åwõ™Ņ&1uBTĒ;x‘ágQQpD)UĪMs1ðõC.ÆÃŽn19ßCĖ(baeõgT9vĒŽ"ëc@4đ–I4å~õ)\U6Ĩ>sâøđDŪ­ÜbʈĐÁkû}8ýŧK—=57kQIˆ Ĩa`KBÍ0Čŧ.ã‚ÂT€HïvOžŦ ·óÝÃG]žlųÓsK 3@)°Ô’Á€ãŒC˜ŌršÎ5Ā•*6yæ„ãoí9íÕ|ĢĩúüŅýGNû?Xý“y‚Ā“DIE)0%Ôo°ëVoĸÍÎö 7ÜüäÝ3ŋģj铏Qæq"ĄHŽWxe ðĘ0Ąq;[Ūššïöq·įÜ囙Ķ\ TšyĮó‚€)Š āĸ@ûāþA)ũ=_ī=ÆãųŌ(ʃĶEĐZkDâšH҈RŠķ†ÁTxïúč‘/ŦĖþŋëó_ÆĖ­' ŽâýfMš>˜j°ĨČ˰ā.Ŧ%J°UÁx)ķÔJ[-—x-Ē–K"°eoģ+,Đ_ĀÄôŅôKtd› ĩ/ý?LN2ŋ9sÎėã"ņ€ã8žį…þˆĒˆVČóÕxėû\ð:“úUŦüĖÁĨÅRx^h60í„°\.3 ƒ~ˆÝÞÞÞÜÜ ÝBĄ€ÓH$XŪ―{ÛČӕnüōúðâj;YœNė―bÚ äó‡aYŪ?Ú)ÍDږv‹Ę#Ąĩlô?Ģ:ĻŦØ$P˜ÁKĩâší`Į{Iî™ßËĸo#ĩ82L2ūJþõ>íF„ēGŽZ?ļâN:SâæK'‚ŒĖ.ųĮÍÖqŋŨm~j C›ÍJ 8jŽ\|%‚o›Ē•SĖq\įĨ‹>Ķô\ū~ąė·ØŽīoÂ<:XÜĘ}Xw…b-Ø)$Ũ``-Â1p\k jARšr6Ōa6ŊÏg7ęt–ŲŠ|Օļttzč‰áuæ”îžJRó|6™Ëíbæðóų"éˆė5‰Ýz Ļ™ėuŋ&ðŅj*ÎōB:0›,„ÂŦ –Ý\˜\Ý(tšr§#$BôãGÃIbÏl+É‚Ēˆ+ÏB"-H2”áÖ4˜Ú8ëJõeÚë&I›DķO%EНíâætđîÝɕøþũž všúa3pĢ`ļk>_i‹"Ą{8›Ė_^*|qĮ‰mĀãĨˆūķ_ŠÎx›Yđ§Īփ†įz‚ōøí˜;ōķŦÁ ŧŅ(rRo2zĒõ°_č›(ŽĻðŧƒŽ"gßøŽv›X]SsUN–šĮĪs6{ŌęõÄådd{eúMÎđüÆQ5QÜĸi6lŲ!6|€Ē‰@ŒĒ€€|Ä; ōxb{ĶÓ}û9 ų{ø8ššę8+H)FåęzœŠ{šŪYxĻÞޟtsĶũ=ą?J›ŪJï— $)qT 8y˜ÄĐŠéû5ÍĀ‚ô5üā9Ųl6dcðK“‰Úš.‹ÕŸĸþ҇ËOïæ?ýØÕĪeYæUĩmËãjĩâŸSX.— t]:™ˆJl4møõŲ/Žï~ýĸū[|rrúCōj[ 3)‘íĶĄ=BG%3Œ åtŽðI@Œ€íĶ@~öØd‡<ķ`“Sč&§KøœZyÔËĩ ?Ö?å0tM(óŠyūÛšČķMŨvÛĒėšØŠíĮķ-2vģÏ֛РýÐÁęõÎŌm Rų†}úŽ ÝÐ7ĄČËPÕÃØÐĐŠÃ8vyFNÝcØæ‡ÁCįÕģåÏüŋuëö;·ï>nwϛ:/ Ķ?$V}߅P‡+)‹í0öMSeĶ>rŦ†Œjģ†ķj؍uI—ŽĐoŸę ~Bĸï―wßĸęû’TwãØŌĢÝØVYFzÞīmÓTY^ĩĄÉÁŠÛątŒĄ ———åķŪ ŋúœÁöšŪŦšÞ‡Ų†]Ha$fĘ <ŧŠƒoëĶé†ĶäL]Į°%þ6<MÁ‡ō›~Ũ† vęĶíÛQe^`ílčŠ8W^ôPT4ë p[nē"„ŪoJ―r]4dr4đö#ŲŲ•8ß}:äGE}/âhŌ‚; +1ČäýR2oÄNu™ž_Ҝsų1Td>?ō߀ŸÎvqqë―ą^w}ÏwøÖzÜíČVôüü eĘfÏø+ÛþÛ*$#Ʉ4%†ŠÐ|Õ&ÛdC?(ųÅ_/†aŋQīJd …ĻŧCķĢÁâvž3)Ô`äŲÉÖq‰<“ÚåöLōƒļE č1\ &ô$?jóƒ$ü(G7Á}ĪĄß2·3摁ĻÖm9ŋļÄ`eϧJčb­Ÿę+<3@—Ē(ûņ?‡ōŅÇO[Ū7ŸlģŽųAĮ^YfHįÚīŸčŠJ‹‹ŌĄČEsÐ/ï|ü؃GëžĀÓkãģ3ž„bėˆÃ5tWZ`&KĨ $ž%S邁æ#šŅA/Ežĩï*?ðęŽŨą€“gW}ˆ@æųÚüDû“,ũG!kÆûã*EÓýyÕý’6ļü“ûė}Ģ\ïÃË/qm‚o4û“ûŸ"ÉüwųĄj&?4;;;ã}zzšZ­–Ë%N `Ë)ÁĐBė$CīCˆK ĩŽð5ķ@”†ãĻ\%n­LŲIkuLF%šKŒŊhO4‡CéMLōãīüæ‡ÖŊäĮôęŅžäėóųÁ‰Kķ;pšų{™…Ū+Öļ&ų“?ŊtĒëų1 §ËģĒØ†b­ÖâGɓüÄã%ü8-ą‰Z›?Eq%› C%/ÂŊŌüĖڟü(9áĮņþLōƒqc~$“üÄĄ7Ώf(‹ĄĶų1Ú ~æïsøANNN‹Å“Å>Čӓ§G°‘cþ[ė5žÅŅâøøøäø4<”ÂC†JÅ# 9i‡GöŅŅĘķ0 a#ÔĒ@%FV! zT>BSƒi*ÏāLt"Z U(r&ų J~]ČũŲŊįGāøÍį1? ]Ãz’}t9ü`~Ļz~䌸Ņ?äcƒ€Ą^^Ø?ü8§0ļNó#ŋlņĢ\c 3aō•üčqr”€NöGã―ŒŒ„ėôÝEûƒLōCBˆ<ŅzߌÐŪįGČ1?:ėëō#Ca>?ņ%š?8Íō2~Ðßþ#ũŊãððPF,‰g2ô͕Á–ßQéÉĮ$?q 6qjÔ9SM&ÜŧwÏŅ9ōÆųÁóVņcĻğōcϛãGvėÜûïÛ9—ė9üØiĻ·!\Ϗ™ų›}3ŠęJũøw·ÞØLÐDQc·$FLeÏd4Î$fÐQP3‘˜5.ĻŅhÔ$.#jŒ’ļo ļEÜÂ"öFš}énšĶũ…^čūũūKwÅôƒyOßžÉÄrÎŊšŠsŋsū•Šn5ĸþųpü›įøÍo @ Ô"’Z@R‹@ $ĩĪ@ Ô"âĸĸ1 p‚<Š„‡ 'ų!Ÿ"āဠøBĮ0øW€@ā€x˜Á<Āq‚Āą^ËumÎÞȃŪ—1$…=pîĸką=ïŽczYYÜū­ Ũ*iŧOüÅsrîŲaęÉŌWOî8|QŠģqĩÁ# I-‚ĀØŦ‡VŒ|qÄÐ!Ï>;xčëc&špÓÆāðO”ķþįõkŨ%$•ïþRË2ŒÝfĩÚðĄĪL9rÞދ 1Œ`Ėu ^9}Ųz#ˆˆû%#H\ßXūgÝĶč+eNŪïĸĄ §ÝjąØî EēâÔ]#GŽ|nØPnvoŽļå`ēÂęÄpTā,ŋrxãķäF­“āĘyīA ĐEX JđÂôôČ7^ųŒþŽxÕėđYuZũՖ y"oŸÂ~đ·ōBŸ.žbJR|oo‘HÄĢøNšfœ NPBĄïŒË‘Gâð 8É7Ö§―rųá3ų|?ŨFōøîāŪŋŽŧĐ8í2đ\Š42Ž[ ĐžU­Ķŧ #B!")ž€óũ îÉNðD^ÞÞÞB‘€"i–bsYB‘+ŨéNîÔU…―bûŅӝ_ ‚âyųpļÏt+lzđ\. ōĮ7Fĩ7ïXķ1ūˆâóļN―zvá<gū7OnƒbhïÚÂ8î0æš0Ŋ§ŧËÎuÁYų܈ŧóÝ[ܜݧEœû―–IŨąkBōaļ2#Ô"0ÆūCVïËLOZ2ãOR…ŅŒaAāw Îۜ<)8$21ÛÂRŽååGwnþpĘÔāĶïKÎą18I0ř?N žŧôëÂú6ÎDjëē·oŲ›tŲÄ9’”CÕtlĸķ”[2·ˆcéÔ7Øqâԙc‡·î9žifpė…Đ1S'•ĒķáÝ^fāÆājŧ'v|pÓÉJGl>ŸSv%)288dņúĻ;z'ŅÕĄĻHýzþä‰ÁkO\/—Ü‡Ä4ŌĘĻÂCļTÓgF§Þt`$ÆÔãGHL8• åĶ詜äϧp‡fF%öž|š+™ētSJFÚʉïāĀÔ·ĻôŠšÄĻ­a\čY[\hïÄp ļ›*iĸŠŋ…O™š7áŠŅÁyã\'‡9-.2"ō‚p“Žötänũˆč‹*·;IX•ÕkÏžz41ýtüÁm‘‰­6–$ÉöÚžoNžžqĸmgŨĀļOsQúįŸ}ĘÕýÅŠM’f=õûŋžF ĐE`,fÓōV™\ „ČĮ›Ï)TÉŲ!Ÿ,I(ŽŊŽ+Ûī$lMd:)â5—gė‹đhítHÄĸ|Öņ å-ĻH‹›―<íZ~vzŌ–Čģ ÅģÚýíōÍû%2ģ7”^:ūa·wïvL:R‰T š–ú“ieNÚp~ßę?[%.Ŋ’)+ŋ_7Zč–38ÜN’-UŅ["Â>ĸyø>qî•cÛWϛģSJóõõĸō·°'.‰K4đôšĮc$Ų‡NœĨš1+mmØô#9-T§&%OFYãđ) ŪY=ã“Ï/•Õ7ÖäoXōqÄĐ’Äĸá[ģAï°Ų__Q}âĐãJ°yCæöu‹oÏĀy<‡đaÜ?…­;|ĩ°ļĪäæÉœâv+ŪKވ7N*BKzųˆjFĮ—āēۙÛÖ.^ē3“sïÔTŊų8dOLR‘\ųýŠ/ŋ\ĩí‡3†ŨœúņŒčŒēŠĶúß.[K „Š[‰AĄs’.UZŽÆËĐYUFwŲ$ĩˆß‚ÆĶĻð/ƒ§M=šÞ6fņŪũFķ–―ûãeïå;/TĪFųÛWO7ĐaÄ;aŨō~Ž‹‰>īy1iÕ4*•N][úĨ”†ŊoŽ]Š­–l[ðšehŋo~>þ™Îƒ›%uĶķĶ‹įNõšīōÏÏõĨY‡M8čïūž@ŒīĶðĖZĶą &:Ö(}2­čFfęß^ó—ÄîýЊ/ Ļ ’č;|ËŅņåãO ĘŠ.äÕķ]‹Ų-UÚĮĖXWŨ\ýcÄ"_†e­6öÍā°ë9ųq'Üĩ~ūÐĪjiÕ0ÞC·~ŧŪĮĖüÓC;k%üÔdplIžš~tU?ū9íðeAáНėäĢ C§EœËōyjÔÜ / ĸhŅđë9Wb’n{‚4Ý―^hÄų5ĐûfČžģ ífííšĘīˆƒžÁIģā7•Ĩ„ŊŠúãÂ-_Í|·Xžûtņųޜ+?&Go˜įOï^ŋaŲgâJTĢgŽ)ĘgŸÚúBÂj/FóãÉŌFmčú„ú+Į_îË+ūSÓÆčšK”ÚŽ—ƆlÞwJRrųĢ1­V Ô"~gXáĀÁý˜z`OĖz·Ŋ7ŋģÃĪt:€ÖĮnš4cM 2­MÝaoŪļē`öGAã'­Þ‘äz'ˆ[Lšķ–:N ‚^FÓÂ_ë=–Å)ßwCÃĀ“’•‘™œP@ޚōļgŲ{iĢ ãîīhõ % 4.°ŋˆöé?õ~@kLÅÅžŧša$†đ`éŽ.€‚Ã&ŋýüā—ÆþyÐÜÉ06ÃÝR;āþOĸaâã|fĀ“Ð\‚PUĪ/1í/ï_ū-ÁŒSŪš\ÍTW|cë0č j-`ėŽ%ĄÓŋÞßjvÚ·T&ķį4Ī 5<1ėŦM;Μ>9åÕþ†ķŌ+?ûkÐļŲkĢÛ,,E8NËï4ą!ï}é)Møy{‘8 ÚrÖŊø*_4`Zðøþ>8‹ãŠē Ë]îëŦÜîÝÖÚĀ{cäëOøō}û ؋eÚnmģY°ôýËߝēļ°ÕĻ·ŌMíÆįߙúŨWzįžĸþƒ ïēpEeŧ‰ @ü@Âà ‚v‚Wßi‹ÖúūBMYvp厝;FðÍå7~Þß?}ĩ7ƒá”Ā/€jZ8ki&;h߁č!úœųóÂq>Ä`œöš ņŧ-J0 üŌčqoûĮĶlŸúųpÜ+CY§íŋ‹<įČâ$)äôïŌ0Y‹Ú†Q}(°Ųđ-†=Fb\t,ÐÖ oÕŌO ô-2ąFBI˜ÝjËNņ ŧEaģ:1ʎqzKÓéė°Æ3›uF€^$i–îßļô­ŨŽ\Œ|ĒåėÜo"d—Úē Ũ3`.āÉU†F~ē|ÝØgü€ð‚'ygo'L[ībcčŸ8Iäq?–Ö]Û7Į\Ž\wôÜ[ėÏa+"Œ$đÐD'čM6Ā(ĄP°4mŪxü… ũý’ŽĶėßđkԞ́ūš[·OĐ?vîM:sÞrΝ Hh;Ŧ1™i`ĩŌ†V…'pā$žŦė­ÐeËĮ vĩ.|2€GxŽđXpý|ÜÖČ/>*zúÅÝŦø`ŪðßšÕ"0'kï$F‡Î_ô”îZôÆ]‡-Þßzą?XTųŲym―ĒđĻēVgąXt–ޏûx1ęžÂB%@]ažöëûl @ÉövEïûnþæŪk&§ZīOĀāŅcĮSN‹‰özoęœÞ4Ͱy9hGS]Nō%1Ŋĸ쁁þ–ë?Şž&ÎH>~ąãũz9ø5ŠÓáöaóïûÔ°>ēs'"cNKŠģï9dÁ€aïöâ9X€Ōė '.];Ÿx*ŧQę#ėp.ņÐŪØäüŽË?eŠuvĀ0Ø>Ąó7.ýžäBÔúïãÕf‹RĐbļ/†UJnč-`Ð5ޑj‡ž:Ö q;7„‡/XīŽĻ™|ā?öōˆ§ ` ģóîjeqy…ĘĘČn%'eˆūųÁšE“Āf1ē€â?Íà BŊUĮ~óøŒ:‘ÛÐé°ÕfÅ~’‘~+coéĨ7Â?›ð.ðqðņįĒéĄKY`|hččĀÞÞŅŨk* Îŋõ·žũ9ģ‚1ð8#Fgï0Zí û@ŋįį–ķ Z'Z­NQ—;s܋€ GgßQ–œ yÕĀŦ—HCßþîXr›ÎÓIk4h .Į―ā―ý― dŅw…MJK‡Ą<í@W ĸĄÃ‡õâó0ė™1{ŠõfSëíėOĮ―.>øhę+Áč/ķ·5ø*ˆ\ų}ߞ:óĐ~~˜ß íé v}ËŪŲA" üŽˆeâĖÕģ‚\ýú Ixėؐ[2ƒI§qc2hÎüū9r^k0đl:ģIĸÃ|ĸŪ^Ģĸōņ_Ÿí€-Ý~Î`3\Úģvp`”>nQY“2zÉ[ÐbZ™B^ýókÃļö ;|åԎ… ŧ*ôņ„gúāËv^Ð[Ôg"ūčG§K–―:؏ \R§4j[J#ŨÍč*Q$  Ï°Ô õ­øEЧ_ĸ^"čóę„ģYÅ:ƒQŦA<ú<ÔR‹7ßŪĻŠ•+UœöéĩŠÛuUåå•ĩwdzĢYŦ”VådįŨÔ7Ļ5švÅÝâų7$­Jåíę’Üüü&…Ę Ũ5W—åååÜ*ŊQĩ·VVT74ķju:‹UeÏR?ā}q4ßdŌkz ÕëZ›o‰ó ‹**Ņ —7U‹ÅyŲyĨuMZĢYŨM!ļ õú–šĘœëWÓÓ2roHäJ΋S}Yęį^^ļŋĒē<7;·ĪĶ‘fΛshmŪ/ĘÏË/*QīĩÞĐĐĻm’ju]Ü‹ ŠĘĪmí\K…Åwd*N§RܕÜįĩīķLFu›īäfavnķļĻĪĶŪEåY‹FÓ*kŪĻĻļ+oåžîUĻQĘËo‰ ÄERĨŽZ’›[PĮÝKõzĢQ[_YZ›“_PXÝpWĨÖȚę*jZÛ՝ķĐĄķĒĒīōŽLÓþ‹ŧL)­rŧËÕęÖÜÔģi™—sóēũ‡ũ%Āoâšŧ*nFƒĶ­Ķô&ŨržļĻēĶŪ]Ĩio“—•įdgeįV7Étznŋ7$ĩNa9~• Zm—AËíyāiŅrļŋšéÝvũķÞ Ŋ+Lzói œ~ëۚģü/Ų9<ŌŧééāQĒū‹{uLÉų}ÏÏÝÝĶ5\îÝSxÔÖ­|vįĢ‡ÍĮŪķ[Ĩ=GĪÕölŪÛäĩũtŨéÔōŠ9ϓĀó{fŨ%øŒÜq6OĢ3xĶsÓÂdö‘I-‚“Šú*ņą˜ļŒU]w―ß­N+oĻļ!ŊŽ]ó(Š‹Zq#+5.66&æx||Â5qÎ`č’kI-B§7Z­Ö“AóÛĢÕ:ÜđMīFs‡õĖĶGōI-@ ĐE  ˆ‡–e@<Ž`ö/øo1–eI’Žëļ Ü ûeÍÁ=šMîtî]čvĀíkũ_w™{Ø=ÖŽ€Ý‹ók^č‘ŅÁÚ]?·r/Üō,Øsíy g/='āŽė‘―[dŨƒÛčA·ŅqņN§Ýfóüåņx<’$Þ>| Č‚ÓI;ŽÔ …˜cGJ%’$þ‹óŲÚ‡Ēpâë?™ļĪŌ,čuÔ7^Äk‚xŒŠE%åÚŠƒ4“ØÎïģïO{š˜ENĪÛ9ũÜë‘ú­Öų’ģ1&į$bųäˆ”Ķu}+Ĩ8įRÎĨdkloú%-b\ˆ&#LsĀ öjNIcŅ<Ï$­íģrGOī]Ι:ēÕ5‡šVf:2Œun-™l5YhK2ķ@Ū”•ŒANˆd™ÖąŽÅY§}s― %ũå ™/üԖ&âV^7Ô35Ę^?6jÉėVB>~úüåëņx|á,ĸščîîWyÓĶMįΜóÍÍûizģ,é_Q+"?oo|ĸ/"H1ÐķRĶ 2‚5]@ pžĖ3Øa€Y€·ũŽĀ)h ŠXApŌnHžOG>!#M ĩÚ4a%€@ČčC`<ņ‚ķTAːŒi!AĄ\šjëæŌÞŸ–Ä;ņÚpĐJĻÃÃHtĪĩ/€āP‹yØ2ęétĒÂ6ææÆbį#a`x’)äZ,ý,ˆÅ†‡9õRô+žY é#Ör—Ãóó~ŋoáĸĢ–ō‡‡§ŦŦ·ŨŨïĻëÎC›6mwũũŋŸ./§ŨųïfŽwŧEøUČ+ķ ïøJE-T'2Žbz휃 Ļé@-kӛ”Ą!Ōč–ÁĨ˜ä agUļ8įĀd Øņ|rցKÞ·Žü"ŋũžCiŅ]_đĻ$ŲČ`N ĒœÞTņÖęņ ÃĀYƒĐC™ÄAܚov1g.†0ā…§! ôÓV,då“.Lƒ“âyžŒZXN kÂõ·r–1:Ļ=ÆØWÖSÓûĩŧwąnþ†Įišï6m:mĻĩ1FPĀúuP gā‰0t€1üĮÎÕíHÎė6‘Rđį{ĸw=;vé'ąÔ=đ ,‚Œđk4ÜåZ/@°)ēˆÏïq#p^(ŦoˆˆfņpTe–.͆Rģro’Įq\Ũ5ĖržŽĘšŲÜÄ>ûзt…Új’•‘Ŧîŧr|ƒ[†Ī‚Y"•%eķ2RŠ@hÓ}Fęox‰ŽĩĪŅĘ8֑Y;Cjôxd9LÝŌķ Āmk7kgFÆbũ ô%‘AĄ-‘~Ž•U™ŲO<"bnîWw’Č*#įsģUū·_€üÔōïTãožėUYî!MUâáK•ŨÞUIU4ÏRÕlU―éÉÖ·ēŽãČŽĖđRĐĘh3ĀąŽæĐėEĖÝKŠĪFT–ČíBHĩ_ï‡Fõ)B!•Yõ#xۀMRĨ*|ŒŦL(ŲÔđÛQĩj6%ø:^Ué{këY˜ÕĖ,#Ž5öžĘ›U7xoÉũĩƃžĮ‘•å{Wݖk5ē•éu5 ÚŽU?” ČĮō ņāÁsˆ"€ÚDCJŠíT)1[‰ĄĄvr·{dHßpk^Ā;›Yš”yWUĻ)„UEŠ™ JjŽuũŠŌÖŦþü+ÛîĖôŠju͔ŒīFm‘ēÞMŒ9ũŲžUUD€\fĢ.ĒęũũwUŠˆ”YÚóŪ{ĩôe‘Y![Ø6š@Ė4ۑ†ŧ—UĄŒ w')ĀéŧÚÓéE­]Ý/ĶKJÚĀÕ6FdÞ- ōāÁƒßy4ļ-Oķ-PmēÐfNöop7;ˆËjŊŊóâÝ%E•­ÝĶ߈ð)8tF€·i[ý*Ū―=|ŦĪÂÝÓAˆHxüúúgß x6‰ï^™ŠĶæáfšŽåûÚP’,yðāÁ/ôj)ķŽ―Še& ûž‰Vual~n{„HI ÉÎųc4ėޛ›|%ý å-wŊbkoŊŠã8(8ŊËÖĒjøŽŒĨ­ag^Dķó{i'XĨĘŊÝ_|‘,T­ÎųâxôK—*{r5FĶ@iHĐeæMáĮZĒôkg‰*ĨŠy{lâHISÞ)ý34ë,Wf•_ķö―B‘0[Óģ D7åĘíWfõn]·ŠÏw―!ōāÁƒßįÕSĘ @s™Į ÍŦ2ImÍđAķ-Ðs0‚jŦdūÛą:Đ) äëõOÓhšĐī]ŠĖ5Ü i ë—ïl[ =ÚĐЂxzĩŸPãĻB”čôXķŒnpTPÆkVōĢČ[ÏîkTðŅ…ÝŒ|―^‰k—{ß;]y'ÚsŪi”}Ô=DãXˆH‡R™­ˆŨ:&’a­ąå],& Ęšë1)›ņĢj<ø^­ûžLR‰œŨ•ÕݰaFˆöČ>KÖ:Ð)Ø2ģÕ|TŠHӓčŌũjũēûĘã­.KÞýÁĩwLĢW™‡-[ëėēÃ0uEpTŪjlG ĖČðŸ ãVh9Ŧ!ĶûšMïœ/&§5)…ïóŒ *Ĩ+^FđÛėhîæ.Ž+ķŨĩ1ų3‘Œ °–QQUÖÖö|ëh‡7ĶžKuũóúyž^ÛÝcžæ5aᮂ8^_~yf€„Ō;}EÕ&ĩŒą;›ŋĖtē•9yŊVĮĒj"âmÜ6ýJUß V•™ĐŠ€øŽˆDˆØÞōÓd,é*ÕQįá°<ĖīæēuHvĨ=ï鄈Ïóŧ>'~Mē8Ŧ2Å0Õ Áņj+KÉõâõāÁïôj•”’ˆ”™ĩ8Ž*UËĘ1މ8ģĖÁu]Õæ#>ņþŊãũMē(ËÖũuBĻĶ―ēKIUBX’T]jÛŊáY[%’• “ũõú'ŦĶĖeŨyEGH ™áûm§xlÓ 5üEÅũŋūÛĖ53‹ QēM†Ęų.·NŒŠ‘ÜŨÕ7ĪũđE‘Ÿƒf*KũÞ(iíĖĖ„Ķ ŅŦ­ŒĖĒQĶþ ų…xðāĄÚI>ųqžžŨ·™Ų2ß^•­ŅŽˆā 4Kn€vX•DI!Ģ"EÐÍŪœ*›Qö>Ø:КLŲ5vFŠŲœŅ5ÉÜņdĨKšŅhŦÔĩ·ÏÔ~Ųņ>qņ]ëÚJ Â]ĄJī ‘jFŒč…Ų;lK!`ļøĩVfTĄđW2rôĐô6ØþEf-Ōuí-YÝđļŊģō°U"ÞO1ĩÝÆ@^Į—‡ũrĘÉLéÕ+㗆―‘cÅFŒdžïðėđjŠ4ÍĻŽTUķ“Ö%ķĐoA)%{_ĪŽlL)*ˆØ6-&į[fĘ·—ÃV+ôíėþķríÍn=ˆČågϐĖT35kn €JžW‹_Á,5GyÍ/ô9u0ĩã8"cûîÔpyŋĮ=ø­xðäjŸ9XVŊWfí}MttŽImA8(o 3ûsˌŒĖ&ąŸÖŲŧōßÔĀ·—Ī-ŧYÝŊ‰vM­vlâN8øg…Đ EúZϞRŌýārwyŸí]"ėáĢ”oÔpNUQ iŅ[UĐ4SË đíŒWDŒ[―ũ֞ƒÍ;43(ũnņNĖōûÕ)K~~č‘Y­OpŲÛo3Ôß^§VÖ|ËÔÂ@‡Ŋė§VKp*Įë…þî˜ĪûڟģÉ9:šlJÉVĶBŠ·‚ĶŌĖ~čOɌŒŽé€õjʙVÍ ­é>{{Rĩ·$XRÝCëØĀė&„sˆ{5ð€jú~ß ĨTd·û†9čKfū7äũáÁƒ‡j3ģ3öĨĘƊĖaÉŦÃIÃ}-*CĢíÕŪĩæÃq>Ô)oþŠ4ģŅķĢF}z_ėXƒjË―F+ÍÜ{ÏÍŌ03‚{;ŊŨŦ :åFÍē"hnÝė ›Z6†øŪ}mßÚÜÚLÝÞąßÞó›FĐę4?Ą`iŊãūaX~Ė“!ÜŽ§b|I#ôĖl“dæx9ŊKDēRųxðāi‹vC{âŊäGŽ“ œįĐŠĮzyFM‡Š :|áķú°óÛríë'1ö҃"íä} ŒŌŽŠ‘Ō€Lubn~— sÞB5âÆngUēki-ĀgécČE•™S2ĀÅ~4øÞ›ŠÕ$>Q‡VŲŦņnÞoīŨĖŽœ<,9ģŧœ#zûmØ:VûWïĩ.mÜOiViĒ‘ UU~Ĩķ Äþþr/M åé)<Ė/ŦðÏ Ð|ĸ/ ­P]QTĄĸžĖ'݈yž[ÍÐ h†ĨĸÅŧ E]þØ›eĪĸý9BĩšžĪBũÓĒĄPw=îVđH ҟgAœe†ŌĒRAųĸóm(î]ðßÚõĸÉrBŠĐĘJŠI–:ûÁÝčÄWčfņ·ŠUĨï™ĸïôÕJēĪ()ÞG™X8Į Íë, ‚í,Í0$ĸ ƒ5Ԛ”œ"Ek•ä|Äe%ŒgqR"ú"4ƒ„*›°ŠXÔ\aįņüBĮ°šĄÖÚ!ô`Ļ$Ų–(ß@\›@ģ,’č3öĻ"šEQNf‰AŠÜ‡ký–eņ,KÁĸįëMŋËšŋv^@6Ïþ‹…‚PÔWdįË~œĶ"ýėęāŦ"Ã͟ŲþŧBQŸ=Ļ_•›W,ʔF# Z|îÆSHÓĸ…ĶÛGH ÄüT Î^B ‘E–D ŧVbÁ•EÞIRKŦ8Ķ„#ïÞâMĸcÕĶ#.WĒ Ž* (TÔĀÔŠ~a-,Ž‹~ t%ˆÜÁØLJ\›~l)ėý€Ũ@ū1l1‘ó”TūQ€ÂBđĻâÞžTŸ5$qÔ) ą2HĨ†,ÕTô’›āíĐH`Ĩ bJFQˆL/Ï ē,’ŲbĄr‘åXBģ€fÍą$™Ĩ™/EĒiæÝËÛ‡Ģ 7^š―ô›Ū@ÂÜŠDRAXŽËúqúŽË%ˆ[â/ßvė Rā'ļJ•%ûN~ޝĄ$Ģ’DĸÉßâRXëiŠŒˆ1•ČðBJĶŅÜLý“ÖöøŨÔΈļGÜN­ųRä.4–þ”ĘĖŽĢ4ņÕÜâãüh†*ÛšbqÜó2ĻØeœ7þŲĐRīđVCÓ(ĄBŌ'ZÜĐBõh1Uô3šZŠŦŨôŅ]$Y%óÅ KølôŊ­*čr†8quÍYkü\ãųŠá.ĨaņĶe‹nŋŠŠĒĩjþßd,)ļÞßÂÚcj―ÏŋUýl}Čąũ€ŋkøYûO Ï_VŒ­'ĖhÃ)’Bč˜Ņã‚?ĄĸĪw•#q%)gįÏZõšZB+ î âołm`ŽØĻ˜Ķ n āÁČč›åØŌ{qģÎgTŋŋÆôũęúu#EéŅd y?q;eG<ļĸïgjiŠÂ2ąd}h“eÄĪEÞ õÐÆ°­„mfŅc㗠ĩŠáū’Q jūŸŨ S€)X―JY"d€P*’Eg‘đGĀ‘Č)ĒÆ_cŦ‡ƒTē(žo ðŦ6E 7Ą—D‰Bwãð &ÞÅŊīĘ`3)XĄ ͋å-KU &D#Ábĩ4ī"#El9°˜ 6ļ?BÄáËad•8†ýŽ".4ĒIĄŅ~1°äģJģrĖm› ėԌ°"õŨÅÓ]ÜÝÜv\ĐŽČŋzýüÍcûýĮMųõ­îþą•ŧĢžr͛;‡æėŒĶ5ÜŊõ›éŲĢcĸ?þŠÔZ[HS…Ïĸq9%fØÔčÓc\\‡ļŧü%Ðų―FĢ&þxxe`āŠ™ýzöūĸzĢŅg>Z6u˜›ŧÛČąãģJ“Ŋœœ?û˜ĻŅfÞ=:sâ”ŨUŽ!ûáî Ąe€ÅÖFJÏmœđ,$ā›1“ŸWōŊâ/6xāБû~~HąLRäöą#\]zw Ø. TDÝĨ]ƒ ;ßĸÜ}UK― å{ęn>Į0š‚ûŦ§/|YY j4āŨÛ/^ųeÕÜûLPļztÍð!Ūûũ>qM>ú )šïŠNŒwëÛ{ĀĪ oJ-§þđĸO7—þcNÆĶŌ[üāÚė‘Üܧ.š5áŠs<Ëž|óāU1Ê·ö-YģeÛßQÝ:<óšaϚ•c•ØÝKÞ|ĨŅhRcũ,Ø[ĢĄnî]ē<4tĒϐnÐ2R +V·ÎóčæšdÍÖû2`):;ņōīąƒÜ\zNZū―‚;G·þx5jÅ,ŋÃВTx+<ēLbŸÅ\š{å ߞÝ:Ž8%ąœXžhܜĀäƒV#]^ĩzMā‰}ŧļLž˜‡ÍČßMÆąVŅ€ĄðgF@Ą&dĪ•jø_(œņ* ý7"đPØ*CäÜDvJC‚fē_˜a Á@dė°ĸSFTâļ‡(Ėw…Jh á=žA*D,Ô°"ā3,)PĄĪ`—†áHĮŒĒY†E\šļš‹c9 b4ƒ†Z̆_4flRi€6ĒRہīðxBīāë5, ŠĖhXRJņn$ÉØtB ’ËRéGŸedņŪCķ+Hã æ*É 1iË1 v’|ådEēhŌ^ŸæÁģ=gŽØú4ŦZC—‡Í]˜Ý&(ōĮ])ßoŒ~ĢöéØ―Ũ`;6uidš›‘˜TPAAX]ü4íQĐâŨņ§Ū'·öݰ;Ðå\ð‚č—:–ĄˆÅÐ%?J(ā þ|ØŪĖA Ū^―ōMïķŠ,~8UūˆŋŅzō0ŊĶá‘ŨųęžC‚^4ðđ1Ą—ÅŽEû“ũâōó<ÝÃgN]Œĸ#3/=ņÞ―û6uĩŠBGųŲíðË)ÂܰMÖųņËïpčÐũðUksųúÎ}CODÚ:ãÖŲíoõL^ÂųĨ‡SÖ}yóīV4urvxwāä ‰aOŅ7tŽÃĘIĐ톍ëŨŠųŒ% Įw~}įßöÄGÂ8{(øÜLrÔ Ore~!pvßw|_㔋ÎÜ.ϰ`áŅŅĄ…ļ ÎĐĖ ›ŧĪÜ)(ŧ›œW!ĸō΁ģ7‡ĖÝļÂËäðÖKzšĨj_Ĩü‰ŠÞ·ïōSŌž”ĒÆé·ÏÜNó 8°uA‡#Ŧ>)Ó]Ûp§ÂéBxøØîLącģtōßyõę™ Ų7Ýy^Öqä„ū-›Í^ąxŽŧ_^”˜˜dÐPvnÏ>kŨéÛŨúþvjGŪžXįĸkđý…ˆˆ‘íŒâĮÔSeĘēqëĒý§ÎH sïĉ{lģ‚ˆÍĄį’ķŸūtîÐØ˜-ģ/<*§õϒÞ"Y*Đ2ūā^ą(Ŧú˜c§ 4n'—ųØĐ$Æ Ę&&óˆíī2þįðŨ&î;·†'œđ—eČMúųÔoyû~ˆ<á?0–cûĩsrčđyĮ†nNĶ֍{EÄÜÚ―ÐâĮm§ēųÏLÂïõÚ>}5ęā,—ß.Gžĩ];ôėŲŋßĒ=ŧûķī|ō()ģĪŠŌ―\â&õ\|5ōRK4{ų = ‹2Düô ĸĒ~óÎ]ŧ§ĻðïæŦE'H™Čw#Gü“zí 9(a­V’‘cWa T(bzo[2<‰#ė‹í)Ë2’ ĘĶĀ”+ØJĒ ]ŒFåÜŠĒė+,rQBÅĻčâLYJP…Y ņŦ‚ŦČhĪɈÕQwbMmĖ˜„Œ?Í2Īö ņc_ÞĶU’#QCŅ+Ŧ?cgŪ ‰Ļ7< I–ˆģ‚ðޒĖ\<ËĒ’ TLuĶČD=WÆCĒÐBAĪEÝĮX5ŠdĒ(ņĨTęÖvÎŲ+?ŸÚ!ÞÝ0iÆĖÔėLJ|åË+›'L^þАdÎĘŅĘŠĄucGĮšZƜœæh ãSQŅŸąz‘k§^žã).%ģėãØˆ/hGÎûÎä|ˆũŽĩ tô'1*^ô˜8c`Ũæ-YՁÅŊŸÆÆ*yL1F“€ųčeë&štnÖī… JxâDĐ}ÞČ:3īEąĻ1eá97čÛîmúzúØTfAf­lëÓÛŲõóšÐšcŅĢ"ó——L_īõdĐ@ņ<Ļë`WŨôý,šZ[˜ÁZž:{­˜8ļS§žÍYN’Jãï”6p›ådkÛ{„oŽ“?Ú2“Q‹§€ßÃï§Æ‹M™ūhdZ\ßÁũý6ïáíÝÃ6âæSŠEĄ^’ĢI–UđĖšŨø-ÛūklmŽˆBĸgŽ„ uÚv\8Ĩs덝UVėÛŧma4mÜØcŨSx@7hálZĮšQÓŊĖL8Ýŧ—ó|'mý>‡ÅÕ"ø4 Fü‹JáÝåóĶ.ŋxS2Ōj(ŠŽ}―zŽ–_5úĘBÃė0,zv?Wvšîí^ÏŠá|ßárbBŽĻTĐĀ'`ý·=;īhUÏÔđ;ôßÕí[†Å7ĨÁĀKēŒãõČ AĖ Ž}—ËrƒóĒ„ڐ•‘EBöŠŦŽd §]aW Ā_#EøP ÛYGé‚ČëyƒŒ}Xz―ÞĀóčô-Kz]ĩÁ GūVAŽÖédEĒ āy^ÄVeY "/ÔŦũŸŽUSMgÐó"Ōŋ1čõĒ(`ũ+‡Á%Š F§{Q†ČÛKKX_ŌˆÞčĒ3„į?ā\ZšÜÁdeR§€ĩ!ÐE -ï猠2ŅÚeHa,ŦHÐėcĒõĀē,QQcvgÔ/ŋŪĻφm{zė9zPĸ<ųIPOV{{.Ûüô―ĪĢÛY ’Ą0ŋJƏĒȋŠrURJž`$âmĀ’2ôUWKŠ…|ôéĒņĘŠÜÎsnėýŸĮÕ/žtīŒĸX~!ĀP’€―@ŒL,m,ØŽĖ@Yav1ÅXÚ;ũkïļ?xü}Ģ%Ŧ9,t_”8Õģ―"J5@ĀŅÐH•‘/[ĢĐko?cŲ†sWĢ“ÂŋÖĪųÍŲhäģ2dž:ļPuęšV<S@eþóWų„’‰Sß=Lįzy>uîóĩ― ŨŒ\•ĪjćŽlœĘÓÓŠŅpŦ^įpæĶÔ'―Č Õz4û܌Rë&FīĩÆzNÐÞģŠþų “Ĩ†­Ė‰OxQZð"ōRī(j>õjR*0ekŲ”?ŲE^0Ð,Ð?|ōŲgEÅëŽ/+2ĻÐŌH 8ĐBWēĨÉ@sŨÍ^ōšŨÔõóZ™3ŒH"ššõĄSėē3@DŅ€ÜŊœĐ%óŌĘ+Š‹Ndöã.,ŲķrqkGÍô“éėýM+[`ΚWČ5^”þžŌÎÁQáņz†é/++õXŠO„”)xIQĸėČÅŪoU–aâČS#ŦV;N\=ļÔãäÆyQÏuP• Ō[‰aΜ›~+7z. ]ęåaDq4 îJV[šþӂđgMÞ4~°–‘đv‹ō+™x,ŽĻĶÖöšĘŌėür@ÎÛŨ)üÔAQEOÂ"B>Pžĸ*ŊôüßĒ„AûUQīŠNHρĒ(€Õąš N{›ˆˆSq ;8ŠÍ0ɀJcĐsÂ>‹BIžEĨīF6ķķDN†Ļâķ“JM)-âĸÆĸpėH…Čc€C[Øõ‹í$ôß8=û °ā ŪĪ•‰r"ƒÞPZ\ˆ9nÓ9Bą5ōŠŠĨ &’AË8þC\ŪŠ,Ũ xIļG†ã°gƒVđĶ,€VŦUÐMeŒ•)Œ°Eš!āZq@Ëõe s)†Í‰ŋr1ĩM+ĮÜĪHŧŪ―;·iWoäĻ€#› ̅ēūSÛ4i–óËšuÛíüįOģķm{rŨ’Œú7cētÐĀrRÜŪ­Aš”‚ĮĖúyo__ÄZï­3ĻŽþaóö7ÆfĨ9š–ØO3yD^DāTĻÖëđz͇yũ] Ļ:ãëĮ·b›OœßØŠŽYÏķš]ũ ÝZč­ÞUš~=Ūŧ=#ÄŊ°A_Í!aOĩaũÉ>WOėŲRÔ·CoôÍĻŪÖuχąá—fVū‰đ‘0Šĸxóģsü*Ėų‡qŊËÚÓ2ƒFŽ;ē pļ1̐‘#,fÜÐÁėĀ–°Ŋ·6Õ>rųÂaķ†īČēfÛFtĪexŧh@•ŋI]ŋam7Óēˆ;•KõųĘLoctÓĶ7.ÍŠ›0kÚâáƒ6­[þ&šyþ8K6ķUx/)xö:―AÂRĐÖË ü`•Ļ:V‘‡·ø?āâ⠌âÔĘĩyÃúwņwÏÚ žōuãĶĀŧŦĸŽEKJ\ēŊEeōP5Š_ß4îũ˜ï Ú·Biô• n-F;60Ųŋ1Ôq…ŋģ9Ĩčõ*DŽ‚ˆøD Ŧ– õäåüÂ6Ė~}=ĸuŠ `åOŽ#cZßÕcðöóÛV† 5V™as'\›ŋÃ?P°-üØŠåÖ>_ąĨÎfÏÖ,—Þ>‰“WÆ0(mRWýy„ Á ―A…ĪS―ĒĒKž^'Š8=nåņ‡MŠŒíšÕ7ĒŽ›tvä6ï Ų;s@ýúšōÛ?OKĻ{“ĸsÄS/kNo@Ģ“―^8#[-Žžqåô}áÕýøĖsw^ĖoÚĪęþŪ Á›Ũ‡Í„ž^ây‡N#=ęí\øĶw“˜+ÉÝgŊkĀ@QŊSÅÚû(І“Ï.—ÐÜĸäŠq@‘ĸĶ–ÁķL–%Á(ĩĶspAt|!… IŌ0Ŧ&ĮË-‡ýģē$cpĖkBĘÐgœėdnnî9Æŧ}ûÆÆÆĘ_Ž Ú9ĸōG|_ƒ~û͆yņâÅÎm[ōrģŽ%üØĀö2tHŅh”Ú:Gsˆû—É‘q“0L‰‹"lœ9ÐuŽ, ČŦŽŅ"ū.^O!ƛ€‚k+< –Ļŋ!™ø—ōÕÖoÝwdŪļ\gí>gņPFvZ―á˜kTÂ%”ÆÞÁXڍ8~Ņ(ģH€’ÜŨoÃū&7Ęĩ6“ĶL+ÓŨU"ˆTĮïFuhlVÖ4ÐÍÃÆ%…CÁĐßžÎÆ’ éÔŧŧô:§á·3ý 4Eŧ$ú― €žÞ~­)+EzųĩĶ)ĀŽœļŌÜþڋŽRÏ9k‡šöbÁĶįųČŊšul ŦûÎ\V[sžôᐠ9ŦÉŦö2Ž(Did3iåq‡˜čœR―…―cÛ°#{ï$ĪÚ:wėîQĪaęĩ}ęˆõ­Ä4kgïï&Uš7ēWTŲ‚1nŲaÄā>_Ó@VjETëĖŲž§É­‡ę6ésōЁĻ[ĸ@Ģó ‡īĩ7D<Uaëī\ötĄē° *äÐB—Ž6‚Ž, ?ÝþÚõŽbūŪĢ 0ķfKģ1ŠunÜēÝ7h€2Ðog§:MAuóÛŲÍōýÁyČü}íXcIĀJ•EjČŌ­TĖUÓé3į•óÖē*I*ŨyâčĶvŒí„!CūũŒ‡šE%ŋ5xôĨ+ŠęiĖĶoÛãp3ÁÔĄÕą!i9:Iĩœŋ}oģÛÉ, Mę·Ú―ŲžlÜoꂖËÄķ#đbî2ïDĢþÏrdmé­UŧŪkˆ^ÂŅsjýõû_uŨü—~āwÞRø L}nÎRŠ>DķķČōÖo&T4 jós,}ÔĮl1!%N2þå_~ÛįpŲ9ļã;?ļïWí͗­*(yŸØÍ|AÖZe€ ~yhŨEĨDáóŊxÅũŊļú‹Ŋ8ô§!“_]%Þč[e? ·Uū,iâŧˆ \áBYâÄŋD㠛bzðšOĸæ5w\šyÎĸ―öÆ5ŊšęŊßņœäĢdm\ýóũ\ąsÕ/^õëŊĢē%?Č*:t͆™ļ§ e‹Ņ6”eP(ōŨ e)hŠ|ĄĮØëû6ï†―Jâ\ĢaPBh Kųߕʹ"6īĘHŪa!úĀŪQ―ĩd­,#7"úē$Wčß,þņ_ f< ØFô?KãĒĐz„øč< °ÖnßūCDN:iđũáĸjgýöoþú·þí_‹FYô—o؍B˜Ëā‹ĒÁ”bnĖ„č=Ļ+”•\MÖÏÆĀ"*ģ‰+DcÚųßoxÓ[_øĒ―ï}ï{ë[ßšvíÚã“Íķ‡þüŸĸŲ­7ÝÔNāåV$š°ŌķEœ˜P5Vô§ÓšĪĪ‘’*!0Ú&æ[%E ˆŽēhnV/\#ä’"gll äkï˗žėŠũ_õŅĮĶÚ'HxhũŽŅÆÂՋįˆ<å qïö W-^Й? ę}:īëŪ­ôŽâú3ÏßīŠû?öoîÚQÎ^ēęÄŲ,ō„>C Çîūûžý‡ĮŊ?óžÓWILÐJ*ũėx°kÉę…óš) ÔøOĪZûŸą―70DHyěŒ&Č)Ý’ģī%Vˆ sVÛ ŽÉyƒĻkĢō~―o§Îíî^ētÉ)kŨ:į>ņ‰O\}õÕ˖-{ē™ĨúĒŋðšŨ>txũƒ;QįnBrÎU€YÓūŧÏņ:”Ĩf1VÜŠo2ŠĻ*1 ÄĄĪ•Ā9@‡™3įŠö›į8›ždÐϖõsYc)Fæ”EŠûĸ?„eŅęõ(jy*íę ›„Ó“Áģí{įE'_ķlĄöœĶô։,Ysę“ņsÛĩčüg=ŸYŸâÔ7ĒiŽŲ˜>5þŦ‹M˰™'^Ð+7ĩïGĨ$DČ]…r5!Š$B[–å„pDēzïÁqÁ 'V[ZXđråĩŨ^{å•WΟ?ĸIĶD$)6lØ0{öėđÝsģŸ8ũ>Ī܋^p2†‘bˆŌh6Ā—ÞØlĀÍ.1 ÓN{`Jˆ|€‰ēv<ØDąĩípTk‹‚– !k„úpŠðTFŠžL'ïÓéŸģp˜v')Fø/…šj•>9Íä8.%‹`€DÝýZņbōŽšÚ‹ĘóŽŌkĄōƒDŲ Á‰­ģĖQĢFMĩhL$ījæ…R…˜—ŒÎ‰@î쯸3ĢáD‹*„E{p)UČÖŊÂUú֊ō6lØXņėŪ]ŧöîݛ•dOÕæðîîîēŌmŽ ë’ÔĐF-ĻÎčFUŠFCXōZ čyXŌÄbÞ'JČUįËbn/w"âË2/yuW …-ĻR["ēÆåė›ėnˆúÓ0Æ@ÎTœĄĻQĢ^ 0kėaĖU.…1˜Rn$t–L ‘0†Č)kČØ,#5ÔÖbū;VåhD˜ K–-]yŌĘ#GŽTTÛh4ˆžälŒą{^ũĄžƒ)ÆĒh„čAÐ8įZ­'jcÔN$M,Hf^Úæú2[Å8K}Yj%°Ä@ŽÏdIŠģGĸņÞ# +\;L’‹aFĒFšj•i…5J­ &ąäEP Ʌ%Ī„ QJÂŪ($—)€큄eéÄ9›Óž4ÔÐH―wëŨŸ:wNwĩ9Ýķm[õē’—=Đ#-Š-…0>:ŠJ=ŲėHÃČÉęXšc‰ ˆhBãĩŨ‘ÅBŦ(\Ģ`VA(Ą%CeŦÎđLL’˜†MŠÂđ”ØGO†*Ή€ZÔĨ­ä FcjÔĻ1ãĻ5ŋЄÜ=C`ŒņĐäĪI€1ĐϝkĪÄ1äq’ĘŲWZ ų„]ŠFƒšėUížþÔÓ*ŦXOÏÁĘÁUMŅ“šĻ5ÆęZ Á'Ĩ{ĪuؖmB1 Ū#Kb}DƒÎĩ qsČg–hF—Ë-ë„Xmwļ†ÓͰÖj„kŠ)úeŒšÞNģķ@˜"B5fՊոĮLÖ›%\TÓvžjȀķ kCŒYą"ūôÖZÐP–ā―ŠJMˆYETÍfG%§eN•QjĸþýđÎ žd‰UĖéš=:2*ÂEģ!€)&åŲķ ›ķČgbYƒÞÝ#Åڑ’ÆĐá ۞`Í)ãī†]ĩ‚+ø `‰ĒęfģĪKŒÂĐ'Ø{@0d‰Ô23wĩ5jÔ „Ģ!Ęáߎ›-_YcģUK›Ĩēd*XïäāÉQ,Îj)M2FW™+O^―|ųō*ļkpp°ÚÕfŧē8Õ*šššzĒ( ĐēUó į’ äÓ?uz HYHč}Đšę‚óðÎ y›ÛlhÚ'c,†ēc*áeö$I―đ*}ądɚ=!Öåä5jĖTBCÖX-.œ°œædXĀÄQé­uFƒfșsiXŽā„"m.@āĻ,KBŠīsįÎM)mŲēEþöŅS@R†Ä`4Ū žÍŅą•ÏõûķĻ$ Rl‡š[21UāĒ(bî9ËG[šL u{ïõKcöÚæ,›ÜGÉÍĶÆ§€CČiķĀJߎXã1TS]Š~ķ('ÚÔĻQcæQmæˆĪąÖšvÍLnÍã `Čdą-æ?)x0dõŪ9€U[jbÖXq“ýŧæÎYžx‰sŪ,Ëŧïūûx큈 ō°-‰Ģ4Ĩcuu!FQkûŒ ‰ dĨ/iÚhĘÂdPY9>žbtŪH)·“šīĪģZ ÚĄ ƒ† ærēÖŌķ4}՘PzŌ`.öN€• Z;–Û'9î°…'rŅbôŠs`ŦņŒDF)Ó ÝÕÖĻQ+Ē…sÆY ÁĒmļčĢkmہŠY4Š+K: 㜚ŊÐæŽÛēåœ%”.>ãĖ3CUÄ}ea0Sü•Ũ@·u ô5ûúMkÖúbíĶĶ9ÁĪŒQ6ųäjQûāƒNnD‘óķÍîŲ=û€0/:ĩóԋŧ B`ā–ΰFd~„€$Ą$@­—ŪßŅū&>ė`ˆ0FâR`T(P Đjy9|`ˆ1K jY:Ė1d([ŋļ°ĨŽĸÍ ,―·–4;†™utĩ.›2T,lrčeŘĻŃ#į^R$“[WRĩ惧"۔c2æ ?ôÐC===ÕOx:†§&ŽïC͝˜ÕïŅ*ĻhŅĒEPĢÆSoW hŽ•ŽŠUvĘ~ÝCڔ"čĢF>ōlC”ü>ŪÞgvÎYڒ7ˆūUnÜļ1§":tHÕN6“Žˆ@âÝčŪÎ+āæļgu9@~d8&€4QđA šB…âėŌŊōB`K0C–F, Ē=œb?6‡mrã-?ŠÐ ƒDŽÖšĒ°ˆ+|Ûý`bŒņĨ79T)r"/HG‘UĀĖí tk4hF\áōũ•RÔîHŠ’  %cH‰­Aį\ ‘QŒ!™Üųę-OÐ|W):Š4‰õëŨÏę‰1VŅ;wîŽŌåŦ€§Ô,_ĢĶZWÉY‚1ķó[Õ<ģĸJt€Í§@,b0ŠƒhÂoĢhäxėžôô­VeÛīéŒĢĨa­VEĩYņšĸóČŠÕ]ģũ“$ĀÜõ į˜V„Įƒčû0įŨ v'éŽp’šÁ(ųC}Î;·#6 ʃz]ęÃЛâhŌķ0Ȇ˜ģĖ9—Ûq”ė §vÄmķØ’!%ÞDƟ Ũ`°\Ō“‡wcHÉmQoN ŨƒĮ$,øQíū}ûN9唙3âYkWŽXQmĒ>\%ÃÕT[ã)֘Ëj›hëĘÜŠ1ïB4†rH6'MHĻāƒ+\…ö-6 5ķôeĶ-ĢĢŦ€tϛŋdÉĐxķúo#”ĩÅDzqm …aŲŠĶO€ð2b$ð%rî–bë<ŊŅqYŅýŠŲÝŋÔĩā]]‹Ūžŧč݋ßŌÝqķˆÄ–oĨ”Hké(‰˜9ïpąÐ‘4Æ{/ Ķ‚2f}râlŦ‹!H‡bېo’ūŌþ-ĄS2 ö――ýÍ9óg7Ý#ބˆC;>öŋ>―ų—þāâōŽ_ýĐß:įŲ‹īhú'AÎü}Jî kÔTkˆE#‹đÂåÃôvފp.ŽEĒ,Ļ2–4ģ5ķ—žeŦ•› Qí ZäėĐ6TV‚jĪ­äEQLnōR"‚äáqzՔšÆ,ĀúiÉ7ŋČš]ô8į"ēīÐP$Ãđ|–§{į}Čz mÍōÂŌh4Ed‚smä˜đ• •ŠĖ5dŽË=†Č1ëjXvžØq,iÛÐīÕcvôsWýIųŽũ^ÕÏíūõæŲ‹)(Üēy„qtĪÔķŪ,ߐjÍ#@U2:AJ,í…―Hf7˜,―Ōvč‡wėāÆ9ïzũ[†šýÃļúįŸŨwËíŸZÕe9–­2ŲĒQŽ·}ę=ĸsŲWŋþēMœ‚IŽuEá cŅK^ûšKšåþīdđëŒ €R eéMþ(Óïjž­ņTĨZ疁9&[Á_ķČØĒáT_ ‹ŧS^P"éą;ƒĩ9BPGShkþQІ€ÎŽYëÖ­OéĻ·b[k-*ōšLĀ?Ų ÖáHðĢeŲi]A&H  j8ī?ýDÂė―Đk-ÅĻđÍ"oHÐ9§ žúfÂcþ-"É@4*hËi⍚%Bē… >ē‚ÞG2hЈĪ" VDæÃ0'y2B#§ą\G˜ÕÜÞģëáÁxę%Ï€}$žĸ |åußü—Žģ^øĐ?~ĸšYþŦ_øā{?ũíNžsÉŋōŧoÚôgŸü뚟{įKN—Oýæĸ8ũmWūņÜo}æïë<ũ-Ŋ~–‰!24æÏ[ģfÍ:ģfݧĖ―ėoü·­WūimøČÞþÏ· ,<éŌk>ųþū›ŋvÍ_|ģãš}üöĮßũōÅüÝw\·ufø?ýüÅ' |ëŧŨž5ĸ”3ōnÅŲý‰ũūïoïÚĩhŲęŦ>ņų3įsdyŒĐž’ĻQGƒWHė: "ō!°)æøZ‰)Šž býŽ1ZoiŒĩ8ąkÄxŒ!,[ū|éŌĨÕÞ ÕjUį“2ŊüēÂORü‚šÜ|øÁū€K.\ųė ݋ŧÍ1?PžčŪCáH“Ó đ8Íd$đŨ YS“ÛsS$ÍãR-XõÝĶó4 ŽĒ/ÛG[’ēčÂjĘbâhÓ‘ŋÝe))ÅŽqwËŅ—d iČ:'Â'64rZŠ•Ô*;_ûŪ_þÞoþņģæÖũ^õŪW>ï|ÆŲ­ŧŊýá‚ĸņąŋøØïūáM7lĸUęûƕŸūîũ>û·›įė{ãÏ―þ‹§ĸmc`ï7ođ Sūōũđ{üéŋþ‚ŪŊßrÓúWūīMØfNū€ãå‚ug]ērųv<ø/ŨĸõßïŋāŦ_yݟýöÛ?ý7žû9į^~ÚÉŦå~õŠģc8øž_ųčŧVuýÉo―îËßšióËvmđ}Å%:YrēïÖk?þåûĸð[_}NwLāĢLį| ojÔÉ^jRŋĪdÕ—(œŒmCbQÃŪÎģG9N%‰ :Ž$Ĩv™˜25ž~ƙUŊW•{PБbŒÎđ)ځŸÖžÖîŧÆ.\ũęũmþ…ģNZ S°wlį ―Ũ]{č+=þ°C" 0$vžĪA‚cЎúĒ\—`Œj˰@Õđ0 }ð "hÛc‰d R–&‚Ұð“1@BL(*BHđĸžæ_ŌŠ]NĘZä.ð„AŦ3qÚié—m~ݗū|þ7ŋôđwŋãuwþÞßŋĸô>·ágĸðęß8}Ņč™ KŲŧ퇷ũŸüâóŨ.›ßĩâ՗Ūþâ û?tÁ†ŋýÖõ_Mspݛįîđïë_)–ŨžuR92x{KÁ—S9>°ŧŋĻ#n9ēŋwëmo}í ={ö\v>ÓŽE'Ū\Þ―`ážđÅØđóÏ>üąžÞ#‡z7=-ķZA€bˆÞáÔkÍßtákŸņõ?xóŦūõŌ·_ųÆË;Ķóy$ýC;ÞW đDĀŧ~pä”ââ/žáũ̌|ōÁlūŦ bęږČdžAc({ĀÐęl›]!ÆHH@,1B}gVĄ–vÞä­īÖ°Ąũ0Ŋģ1q;r!ÛEģÕđ‚$k 2eôĸ“€Āý――s­ûÅw}ðā]ßþ›oÞQžáŧ ”Ĩ/GUTbgwv`ãā―ũõuŋtþús.Iïûĸ+üÚĸņȟžō7>ðï—žðÝëšŲ°Ūŧ5oZ cŨéĢ tĸÏÓWÝōÝļæŽ—ýŅ•Ŋ›ÛÛ9—ËËxd,vü/Ÿĸ؟XøwŨüÏo|ø=’!í됉q<…€ÝËíšÏŋüžųÅ7žĸЧ|æÅk‡ZąžjĸŧĄQĖv/Ũ(2_ŽÉN'fÐÚcƒEÃeõRūkö>­ƒÕ°p1ÖĻĖë„uëŨWąj{P•‰cĶæv>NĀ•”ĨÜýýCÏ;ûõoŧčeSyv°éē_4k(6Î9ûŽ~Ũnßļ:ĖLūíŋðóÏ8Đs9,(N`ácķ ŽMĒķ°Ēd…oĢYøēԝ@^˜$ai;™óiaˆ‰99ë€0j5Ž@ōeČąķVc"Āæō1"0dSL"IŋaáÄd ü'Á8;úåx›™―Ļ+\ŧ­ûÅŋ{n‘îK‘uŋ0>ÖjŲģ^øģ§íï~ï•ë‹Ã7˜%ĸëŌun m^2ōĨÞÓ.9{õÁg,ŧęæŧ.yÕ3‹ŌA3vŨÍũÞw?īõū=ozĸđjéüË_óÍwüņ5Ÿj­čōŦ/}Ų+.XđéīĸįŊ>ą\~gÕâ…Ģ{nøŦ?§ÝŧÞũÐ?Ý{ņŦ9`dŽeŦ…†ßýgþüßŧ–€·|ÝÂđņŋį6ķFmĖM“Ē0LzÃ$qŠ‘ŒSĒdɓiˆ“ŠôÛB!õ­ætc/C%ŠŊĪõÕ<›kq­ĩ“<›Ą*,œnĄj Ý[ïŌtŌ'îŨf ļøŪßŋũ#ÜžĸēeÏý―—þV§-āœy—ž`áÏĸõþŋėīCe›―nÕFPČt’M8ÔqUkpbLíđP9Žu”)ÕXS˜āCˆą(Б+čŪV?ŒÉyIrÄ0QjŽÆ{ÏIlaQˆ‘SzbŧÅP1­ŠO:.|þe{ZŅüîG_{ŅŲkŌāė^ĩiq”ĄómüXĮęîÆ +>ôé?ĸöõw”pÚ5oyö†sĮĢžã#Ÿ{ą_š ĮO|ų~ýi7mšÛŠœŋƒ}Î[ĸpáĨ{|ÚŲozŨæÓWĖ+Į[+žý’ÏþÓĒïÞš+Ē=u邈ģ_ööŦįũŨŅxÚÏžųšŪU=厗―äåmŧŋ˜ŧæmï|OŨŌfĸŽwŸīlŽļþ’g ė/Ãû>ûķ‹6ž8ŌtßT-§­ņ”v‹aŅ,ˆŒfē`nÐā.Ž Ģ_0dēQŠ‚ģŽ”8ōD,,YoT.„ Â6n4ÆTęúx Ĩt|>*•gāðXÚ·―õĘ͗­œ·&0úþtŨGzxksôŦŨ,]xŌ;.ýƒ/XüōëúŪíįûv^æ3ąĸ~T[Ģ.žNSŦ{UN)gië !ænía€ÂYŦņ˜*ĄŠEå”Rũžy›6^ižēŌkŠ—˜AôĻS- ōŽf­;ål˜‚-C·ß1tį|ŨmČĒMņ―ßųË+ÎyÁōŲó`Qcņđöōĸ―õ/~æÄįŪ[~ÚŠŪ@1Ũ͝kgGŽŽņ^íyV…iÂZšŦ›VĩåxI]ŅÕϒ!dEnÏ–ėĐËF†,Ī$Iiō;Óß jĸ5H*=V.NFÉZWÃO4ÃŽÚÏT–žãôÎ,ŸATâõw ę›ōcÂŅûGpY~•ûŌ1Į)īR8žþōGe Ą°~Ž"č[&Á1ŠĀ„cāžY eųļlšßRýĨęčPÏCO%c.‚H;ŧ (ŠSð^ûlČWÐDgŦb?ģIö 8į”ģÄ:k­3ŸļpaĨôŠķīU9n__Ÿĩ–ĶóKœFËOýÁrЙõšu›a n:ōNÓÉ"Öāü č{Ļg ˆföØÉÜJ{á‡ŊzéoÏē(^ŋâ—>vúį?žé3kfŸ6ą(“gpΊˆ,@Â<€ûŌOŌkŒręyö†!fwrŠ ‘ta-Ųڛ§{QxP <ÕÄkXÝO”yĄŠ·Ø―{wĩĨi'Ĩý·"zïŦï·úKuâ‰'Ö:„§ęĐ6[˜2ˀ ĻÝ6_Ū°9“Ž^gĄhÍL1DRÉ(ëĪ!SÍYŦWŊ‰1Þ~ûíŧvíƌ'ayĒī•r9ÆX™ņķnÝ:Ķ7PyFN8#Kí oar·€ö]ę·iTSBНĢ(ËR‰ØYkž@ęYĩjU5ÛÎÞ1 ĻQãĐؘkU­Č€˜§6A@=š>" ģķķHBa„ŽE:›\Ī53Ĩ·ÎõęĖúĮĐTB(Ë2g*JHýn„;Ķ ļd.әËŨÁÄTžČXd G`čū˜ĀióžynŨoýõŊŋþ™ïļðåïÅúôÍ}7Î)šâÁĶiNZČ|BėŽ%CŲ‘@Ҙ\ÎhŒI!ē„l7ЀZPÅsŽ—e4DdÚá”g[5éĒu.qÖՂ5žŨe‚iÅ'ôÎĩ)fžšó{Ú˜›X’8›Óĸr֌eíÚķ*Ó)RŧwËč<‹ÎæĻ`ēzAÏÓûæpBuŽŠÉíAFió/<šØ 10>}î"˜‚(%AÂÁĀÃcC0Ķélš&Hę˜Bd#Ōw(îāƒ!Á`žacM8Ðæ4[čA0ęð›7ķęäÅē,AĪŅlģ/#šÂΐ‘ôbŒŽ^;ē†#ĢāQĻÁA\A)Å™YjęĐQcFŠ―4ÛY'ÂĻ­méK$rւV>–]“lK }3ęĀ$ÐþĢl‰0æËIžÍMöžáņq,ýrŧ! Ĩ‚Æu Ēæ‚c ‘#k&%F5ææöF([eķíNÆžŦ5ĒJ]RõZô!jå%'Ö}‚X-gCíÕpŠ jÔĻ1ótĩcbaõė›\,†@9ąĒvĀ‹šq9ĨÚō-Ī%1­ņ’SB€ēlyï‰čø‘–Æä Ä$EĒ„RB‹CÉĐÅ) ˆ €€(Ā 8ÖdÕųHŠM’ŽY_  īw!#g\—D&ŧžˆĻ°En\·ÎÍB*$‘Äíæ4iĸ*JZ<ŪI!fC]ĘŦ"ë\ÐIWÛú8æD=֋‚cŪ†4PĢF™˜ė%buÖúŅĢ G2˜“E$…dŒqÖyÝÆZ=I[ķ|…!;8ØßjWĩc##sæĖ*ŠÏtœuĐB„ ÂIYP$ī•ŲH Iw9(1%āÜ1cÐâ”xo–Ūcrō‰!Á,ï·ÆBĘSģ$҇•~›ÍŽ §Ÿ>6^í9†r­>ÅÜ> zöđ·ĢŦÕPz@(ŲHŒĩПõ€mĪØöŨeĨ=šÂÅE˜Œ)œcZk F32!kfK% —sYØT ŠšýĄ~0Nœ,$œt‚2KŠņéįžũō+^ŅÛÛŧozˆY|U"8+H‘ŦvQĮáˆDW쐠5–RˆˆãQāۃ{jÂīB,9‡“–ԅ,ëėj°‚#åðx9‚Ā c­ą.Ûåƒ/hDr§`ŠēpΞ―ęåĨÕĸÆÆŠ&ÄąņąēÕŠėž}―G†‡†Šĩ!ÍûēĖ_­ |Ë·FĮŠýƒXã-Ã`Ž !{ ŒiÎęŽ|GV­n1Å‚ũ>VH DŠÁ|hp`ûķm[ïđËëœ 1ø<šR !áģ„+đÂ!Rö,TmÁã >čĪ 0YëPĢF™ĐŦÕÛpRõk[X1ä›â”bR"å\AÉ"€ØsāĀŽíÛŦjþʏODFĢšŪĒóĩsND*ÎÝŧoï}?ú҃{võŌðˆĪR@ŅņHb€E: ,Ž=īoïĄóįÍwΊ}Ëuđ.iÛZ ‚Ž]°4ÆX9"b+î:ēëÐ@Dëé?Ō?>4nÃÐpõZ,M„ö’QN^æûÂ2ĩ"0ÛŠþˆÅ‹íØþ@wũžYģg ÕîĄY―iĸÃm―įžĒQXcJ5æj]đ&UkA―-`ĐÞ'MԒgCË'f@ĻQĢÆĖĢZĘ8ÏģĒBĨÂ"}ŨpĻ…‹“Ų+ ĒX✙­úÓÁĄÁ{ïÝræÓžV™qģ[ĄâĐžŦ5ŠĒ8JV§Ž9eㆍÆïËC#7ÚöïÛïÜyÏwûĘÞąT6ÐŲņÐaÆūŋkËó›į;Ŧ{dwÚŽM7ũĸ`–1I`lœÉ6įwĖ)―mí:ēwhpZqxxč@ßárĪËúÃ#Ã―#ãM#Ņ Í}b#°FļŨl "óS͜ž —ˆ-Zøžįŋ ĐpÎ‘ĒšÐĸô“ŸĖŪ…Ō—„Æ6LbÖôEg….s#"ØÂÅĻb/2”āŒNŅd`&ĒFšœü((ŸáE!šÕy–īA@ˆbŒ)&ëÔ0æ#*I s,#KÜ―cGoüx!-kImar/lŒY0ŧëõ›.{į3_đgāā?ßũåöÜuӞ[Œ Iҁ4Æūĸā―—ŪØHÖŪhšæ™ÝįãCŸ@ŸĪ$qĮü9sFĮÆú††8ēs`dÔÎYļė„ĨÖŲŲĶģÓ5Ÿąô“,nڎÎX‡Ķ 7š7ðéEĢp…ģGáœ3Æd2eæ01FŊĻüÄŲ9vë-7oāþFĢP?‚69 ĮĨvwbcČc`N -…ü+ Á\˜yĻQĢÞÕĻqJœą,‚'%_ÖĐvÝ@Š"`Ž@ĨÜX˜B| ÆPašGŽÞēeËI'­Ę2/œ‚üę1T,Y Ī­PŪXēô—Ï~ËXÛ5°į+[ŋü7[ŋ:ÔL[{ÜŌóīįŠ!įŠFŅ8Ĩóԋæ]|Óā 0nÞÛû– ^ĩ°Ģŧ"ũC―ũïĸށ[8ÚOŋõƒ/Xs~ų™§WÏ})§”- ęęLĖĨīręMY–Õô=™ƒ3ĩ§kōeöóą^uîwÏ=w·Zc’"…emĮ1p Ģ-kˆ­M“†Ņ€51ĶāĢs‰ĒĘã`fĒFšœ Ũð1HŠÖ"ËĒwÁÎTð-OsAÎ3pÎ)›ąQ§i˗œŌÎíÛúûf‰ŠČ$Ã1ų*U ÜVŲ*}c:đkõï\ôNÄâ#7}fÎŌæķßuÓîûžÛ8Ë:ÛŲlÎĩÝŊ^öÆ ïđéöÝÏYų3ï|öZĢ̇{‡n=pëý}^žėœ—ŸvÉpßð` Ē`–,PČa:™:3@1õÚ“ĮíĐl;y‘ĢģŠķīÝŧ5úHDEá!ûĻ IAbÎ―n‡Õ&NųGjņ:ϒ!˜‰ĻQĢv‹‚šø9ą!Ģáߞ5ēŦĒ ‚ Ē l…\ō(l AģWŒÝ·wïΝ;§ÁÔhð|cŽD]Js֍C}G†‡ũõïýũž(ā›ŸþZčcEævĪü…ņEóõtŋõcL5ĸÞvËÍCƒƒhČXCŠxCÄĒYdQp>!dÎNb!c„SŽlЊó ĀHhfjÔϧÚ|X‰­5™þ0/b5ÐK@ar^aaKFČ Hâh΀é=røū-[Î<óĖę˜Įï ĶŪōŦ“VĮýÞ{f.Ģ?Åyį,Üø――·Ï^5įķ~ðŅëOxÏs^3wvWĢhXkO]pŌĐ'œ488x°ĸp_ĸĀūÃ{þaŨ—v ėŧdåđÏ\ýĖŅÁöYÜÔ{ĸüHF^OæMz+ŽyŸüV"š:ĸV=iÛķ=€Jœ‚o@ĀI―v,ÆYÖYēֆÛDbÐĻ0Į-öÁ# Ė0ÔĻQOĩȉ“ꑂbūYÖ›R”zœĩÂZxc°ÓdJ‰!ØÂ4!xūũÞ{öïßnW{<ĸVSmŒąģŲyãî>~ã5]ŪįŪ}vC īÐ―ĶãĶþõ―Ũ~öÞ=;ŦœÛāC˗Նwpdø`_Ï-Ýü;ŋļĩg#đgŊūĻ)Íý1T~<‡âåÅĢNļ•ŌööÛ~Ðßߋ†ÐPN5CCĀ’ûŠĒȉD€V+ @˜MšāœÍ>7k @ F3Œjģß tžÍ&1›PđwҐ™Ø-FŽ?nĮĶ @ŠíGcÜØČčîŋß{eĒ <îuÕEXEģč8G‹NéÜ9ð―_ýĮ+?õŊ_xļũ`ôū:Oū{ĸ]ŸŲöųmƒ{0ÂĘŪÅWœų’Š‚Ûä8ÝLýļ/õUcĖķmÛîŧwK~Â! jdĢ–7īÓRÔÛōÞsLD&1BQĖ Ņ〠F3PW›đB ĪzQį4t†…%jíŦÎd yĩš"ƒ6<Ķ =1ĢĢ#wÞþÃg\zé… ™yęĒ`šņ4^Ŧ å…Ŧ/|ڒ3cŠë­Û0Í ?@ëÆ#/8aVĸpÏýÓ'ė‚%ŋqáÏöõ8r0Ž@gŲ9RJLoÜüړšWíïŲü6ās^'ŠãĮØÉwÎ<ÛßßÛ­·ôõ[cSŒ,R9Ų6s­‡˜Œ | í \ïuo  Ųi–!fjÔϧZë\ûp\c­#4Öę°Ö>įaáÜXž*cŠë ĮýVi†9áÁûwíz5G1cę[‰(—;įķ™s~ų’Ũ§ņŽ> GS8Hpįý·ęí=täpϑC~”ÏïØ|†;õÔŲ'ŋðŒįũ ôŅņŧācfÕĮ^,LũÕ–öGũmĩÎäß(…+”ÐģNōO#zYërų‚ĩÆYĮ‰ģ‹ŽpEˆąîŽQc&RmNĒĘeÝÆÚtLz,CH1V#QfZēYŸ0‡Îī§BNQ]QTđ^wÝyg§€ÓI ëōjĒ åYŦŸūqņÆP <^J#BҐ{ïųámÛïÝßspĸĄžþÁÁđ2ĸ4·éįžvAs~LņøekÆô˄Į_,dáÁwÜ6<<˜Ýų&@5ģä § 6’˜Ĩ\į“ŋQ ĻÍŊhÎïQ„&Ķ{…5ęB.åÎqÝ!Df) ' ŠQkmL‰E,ãŒeÉ:gÐä2DH1E0œ„ïÜö@Ĩú:ýôÓSJyĖ<^„pĖãeYæI9› šģžæsoĸ§{M̃QF%Í_ØąoßŪŦŋöđ+6=ģlĩŠ8.ÂėŲģ~ö‚Ã1ƒG―8þS•ĮkvėØqĸ–­Þ{Ŧ Ŋ<ʒ€°rŦĘ(”!qēÖq֐õŽįÕĀ_LVK4Sđ5jÔS­†^[åYÕĖ‚°ĶRÎ §dÉPnovÆæ]AH‰Žą‰'&j⁇Ŧ{î§Ž·78žËē4ÆäW ˜Í'?―‹ÉG ė[[Ō}bĮŪwþï›ĸá–=wîx襥‡—.[8ÎÜ<•?Šc"æãuĮŋÛņo"Ē‘ŅŅ›ošąŊ·Ũ 5ÎēHJ Š™­ŦAÕĖ:[XgU@ÎeÍFDŌÃ1fķÖäU ÔĻQcĶQ­ˆXĒ,ÕR#rЗ bĶDæ˜R"4ų+ÅĪj'ĢŽ~1V˅E„Žo•ũÜyguš”įåŸPŠP–eĢŅČđ6eðO?ųŽÓ—Ÿæ[%DŽ1ĩZ)nĖ+Zķį‡C?øVÏu·ܰúä%œ8ÏŠëDČ/ríØūíþ­[ÄÕlé/4Ä™óZÖ͘ó|­ą\ŦĢŦsÕįžHČï ÂPĢF™˜ėŲrÖ&fïKƒDAĢdĻČi֚Ķ€’Ōœ'ēÞIÍŽĖ‰ģĒN‡;ķýčG?Zū|yĖ"\ÅcïLEĪ2…E‘Ý]Ý/8ûō;ķoM^ Ē@@Ī”]Ā|ŲĶgþüæŸŊ„bĮŸqMbšMBÆņ’ƒĐī[™†ođųæC‡zŽģœ ƈ ķ(bŒđ­Ų,|IĮ@Ul­ÕNˆČ"Ū(D˜}ÔC3Ã1;…eĶ)jÔϧZæ6EāĈFM 1*'`â(G™gŅ:ƒyЊ Ô~-›§” ŲãwÜVŲšŒ18Žos)*FÆF/?ëŲs;ŧ9ąD/’pd‡æí/úe_úc蕈` ŽB<ū‘arĪ―ĸþûïđëÎü; DŊ‰ĒF˜į\Œ‰ō7@āuĸbqŨcF-$OúkĖÅcŠ„ÆZ[‹ÕĻ1“―l;Į‹Ņ E#(QU?›CÁ­ģB mó―%f§§@zúOđ 1ŊE16>zßÖ­UųÂÜđ݈2•ŨĶÓceRӝĶÍėvōâ“Ũ.\uKïa1Ft—‘SķSˆ›7œ―ąZ/ørŠûvęXš‘|Ôö1,žDT nĸámGw &„h 9•jböÂų2°°ģVÝX í›"H°&ƈ†,R u C3“jU­•įÂÁœrHVo~óƒ(jS[” BŪφœâjČäãua°†RŠņČĄÃ•ękÍ)§LåV―ž6!‡ęĀĩtĮžãgß|ãmŨcc~L- +ßņ[oïž=·:ķ""QÏĄĮÛrjWū>ža§•‚âžŧïℐŽ3eYęó79œuøãIߊ“CDØje&$@ 9dÝ9DÉÃĖÜÕÖĻQ/Ī‚ķ`MÄ  sŽ9‹íŅæ‘īš0„@˜ÅĢ$ ™=C<ú°aÔĢĄœēxį· ä“Ūc cųÕã•ķm’UøP^°áÂsOžĻãPŅnØ1k[†Ę Î8ũŌó.ö>L~Ÿ\0õKŋ7˜ēĨ―ąi5ĸfÎķßY=`“Ia,œH g‹˜RŽˆīƀä,`–ēå9 ÖbŊ5f,Õ§”b–|ĸŪŌ‚ė c@Ýx ―ĸ5ÖĔž/EØZcRRUVũŪ ËžÝŧîūûîé&،ãų1ßwį!īģĢóō‹/ Þ3KĖÆš‹Î;ÎėۘâĢrëtĮOŊĻ8æU"SåŌn―ûn_zT·q đ‡‘ô§ĄÏ4ë@yÖĶÄ:ۂNý ŠFģțk[Acp‘°-aŪQĢÆL Q$-͎QģŨÖĘ!č$ĻŽAH&Ī„|†LŒ)ÅX4Š|ïOdīwËS•Ņlđįž .ļ`2Vq:GNAÞ!Ī”ōĀļųŽsšN ‰$Ĩ…‹―éŊ)ËrÚýė4 „ĮÖ'äëœ4öýï·jœœ˜ē0JQļ<+·ZKÞĮüäY] ĻŦmfɖeÕŌĶdŽÍ?0ÎpJ!„ZPĢÆL QL‰CˆhŽqFXrĪķk4bŒYf@n.@ŌdfĢ™Ų2W!J`2Ī·ÛœąÂrûm·îŲģ§(ŠéĩS^*ōþ7ŋZzÎO;sÓFąÆ0ĘÛ^ýúĨ‹—Ä#ĩ`ę#DôØĢîÔ cĖ―ũn―ëŽÛAļp.ąÆëXcēô˜A'Z !æČ Ę7„ē$ĐDïCHLÖäÎ0ÖĻxjcn3Tė%Ę$Ė RͧóŪĀYÍîBgp\2Ēn„­ģĄŒ@H?0i}ŽKÂ!†C‡Uƒm6Ýâô8f—ĘĖÎ9PðÜ9sŸũŒË:šēø„_|ų ŦôØãïý '˜âøĮ‰ĻöVƒƒXĘÅãĖÚi™b"ĖϟŠĮcŠ Q1&`Ė?"@­ÖΟąp–ŒQŦĢ5AÁčõŒCĩ…8ąUARöŒšÂĪEG61$g,I-ģDÎz_ Đ`]Œ 8S°úĐDĀŲ"{Ĩˆ þā–›æō˗-[–CēŨҐĐ6_d_CEĩĸðõŊėŲ·ũÕ/ūbÉÂEų­Óí Däx]ŨãŪrÄîÝŧođég ĄVþXē B~bĢЌŪĪýÁdRŠ˜s)1d@$ĪHH…˜IŋXĒXĢÆ ÕՊՠ?ąIĨŸÄĘdŒĮ QHDOáēLnÏÍCjĖ)·H Zëh '–­ēÜõāÎþ§Ŋ\xņ%ŦVۜ?~ÞÆfš{ÔímFNz.‡oÛûƒ‹NđxãÚSąŊxŅKœĩĨũˆ8-―N}D‘Đyę#ųzęGc*éØ ßĸîðÐ2‹1†BôĖā,áŅëČĀ9B%īB ·IȒA›RĖB2ԅƒU&Îî2Ībáŋ2Ė,ÔĻQ/Ģ*ˆŽĩ&q yödÉÁĩŪ((Ķ †Ó{g1DŪmQÍģķ| HÆ"9Đbވ‰ytdčKũ7šú>~ÍĮŪŋþúƒ==1ĶĒ(ˆ “$čŽëkõĸÉ xÁĨÏ}æyžēęäŌûé,^Į=8ÍJašĩÃŪJx°eK5Dk…° QLÚ lÉhņ8ŪȜ+ÂĒĄą;ŠNŒ)ÆD’ę―"BƒIÃj+LĶ"ÔSm3T€VKe[­ 5Q=ēHÎ,Žö0Ææ@Ðŧb_zÉ.擟 17éĶ‘°ah øPU—ïÛŧįÆï}wÅʓ6_pŅYg]ĄĢĢĮũ-f™ÔŠđËŊ~þķ124ôœg<똎–cfÕĮÖäņö˜Ŋ•—y)ü―ëŊßĩc{îēDUŋąJß@ã͈€ČpL1ũֈ(… a…vtŊæ%’^X\̐Ä9}ŅZ—†LáÜ œjkÔĻ[4P؄ȐŌ\īÖļ‚Hôēh)û!ĐEŠ( kLā”ûĩR )%(\Ą< GĄV@ččė4Æ Ý·uËĸųË/|ôÃúýũŋĸë_ûZUûBh4Dt”$hS7 ēOÞĨ"ĻVJ?Ė‹†RHƐĻę) ƒkا` C<°ĸáƒ_ßĸÝëūģîīÓÎ=wóE_žråĘyóæc*ûÖâŋ+t:dăÂ{c,ËrĪŒGFŠYĩ·ũHoõŋÃG_ŽŽķÆĮôMCýý}Ą dĻzį“ô581*Ž11Dc -"ĩ'ÐF̈‘C y4ŽéĮ'Þ— āŠ8æŪFĘB a.Š‚Dd,sÛ Ö\[ĢÆ QTc~ū=G”ÜYëŽVæ0”M ,,dHWŅŲFî+D=5rEbð™‹sļbž„uÎ2–cŒeëē-ÐZSzotl.Ë֝·ýāþ­[Ŋûöŋšaãģ/{NUPÖ­`fï}EŧՍĸčQŒ õũõ<ļĸȑ#ՔZņéXÝ82\MŊÕË‚ĩ6315T(đūLÅjĶ(,ķÐÛÂ5DĘIÞ{mŊ1,íxW8_úvD:ĮDd !FČY„!$,\CXDKnČÎ=9‚‚*„›ĻQĢV BŒŅ:G@cĖqVÁ‡(Ž)RJHĒņrŦzž*fHDŽqd0EYÉáŠ!æÅ.°ÄÁĒh„PĶ$Ö9gLÛüęKDԐÜíÛØĩcĮũþýšÕk֜sîæJĻÐÛWýÓ{øpOEīãc­‘Ņáĸ―ŋ͑؁Fą’ĐšwĸģŊİïi)I†1ÉęđÞC+žs€BC]Ōô(3>~~~fMûđîŽšŪ•™n~ýãyžŪþ|þН0BĘĘŠÜ~—ŧS‚ c7ZmnFîÚ&vg?IōōdŅÂ"ŒūũvšŧÍúĪ›emÂDۈggw­ĩŒSæ˜ ņâŋŋFĩ*u—ŲŽÉ#-6‚ŨšēKgâ>Å'#qbžm~ą3#U]]æÄ*v[„ŽíËÃãŲŧKnæþ=GšÖJ"s›„ĻĸÏĸũĸýĸúü?O‚ŅXYÝÉ#AËܐf•ŅÝąÖú\UÛÝÍÜŸýøWP1}‹ôeYÝ]áôVĩšøÆqĄan0d…ÏnŠRŊĩîý˜HÃt2J"āŒŲ4nIęöjĻ%ķŧŨž›;…[€đCøsxņâÍ@ČÓŠM°*\‚ö~}>ŨaÎ")ƒfe^]#›uęĘŠðedž ÎÔF—Ęę"éf•‰ïŨjŦ”sīŠÍ„ðĩŪËh  …[wú|þųįóé.Ÿ··ÔÁšštr=Ï@ģ0ZUBšÖĩwN,ũŊĪë0teÐ Dí2DVuĨ‰‘äáŲ8―5­æļéÎÍÐá*Â#ššÔ§oøÓU3A“žYÕ}^ĸÉļ™/^ąW„·æ+Žĩē PŽ0ZfŽī <&^Æ# ėņN™[-žÕ4Jrģn:ŠRí―'V­RŸĩæÉh™™ ûþ!ļŪČÜ;ũđ›WfNGúõéî Ōĩ“öŌúũ‡SÓŌĪqWĮ3kÍ?Uįó<„yÄajŠÏš8ŦzŦ[†ĖÝj#!ā+č6kk†ũđũ!nöpÅEēšwÞ]Ŧ†p]ëð>ÜÍmýüü {4pžvĸfĄeVWýE·Ø‹oc.Zꖚî;s^ŪÕîqâŽn#-Rwól!ũsfÎåk?[‡BÜVu p#$‚îfa§óžîũū!ųx[Mš›—Z‚›ŧ[g·æķŸûøψ*õøÖšË@ ž›@ø‚áÐ&™Y>į5Zuh=Âïûå˜Óm?ÏÜnųĩs qDÁ4š_þė8báî†:,ú€ÆˆKĨę hųaðjPüŽÕ6ÆšĘ2ÐWĖ0þGĩ/^žną’ĖėóųT•šíäždmļ{ֆdnĨęę0ž•`ÆsAîz€6w„)!Ŧ†û>’Rs_ëŦ—šNwYæĢŪX Ÿ”šf]* 8_ĖqŦĄŽ”t­›Kíq]3Žlū°wOeoÁkIš=Š™Ý§9ˆŲo„_îNÚÎ=ą$f‡aŨŋˆðówfšđˆŽūŲ]­6ũXŨģŸėąŠ ÄTŪ=ųˆXĢLã!qü5žxņRí!—2ڑ‘ŌÍ#քŦ‚r?3ĢxūÅŦģZM·đĀÏAœ•ÏõđÖ7Mܜ’†ĩÍmq9zV3öüDĪMŪØÎMÚhQ+7Éðčnk]<[āę6·Vå―=XĩÕ‡FH›-ęÎMāZ Š:―†qÍĖcí―Įˆņ­dĸÞŪŠ’ŅŠđ1ęPüō%iïĮÍGnDÜ]î>oîëš&!ÜÍãč p]’z*|EøÄHfŨ׏e،]íæ0Lm™IpÅ5ō žxņâoÞĻjŨ8ßč!Ų­įޔÜüŲÏÞÏôЀŽÞU LĘâW#õė  t Ā]]~økįÎJ7”{ÏĄuÍáØaíėnÐĖmÉÃŨķwÍįT­›vĒĮ[C—ŋŠąšâj)kÛé^ė,ĐgiÛ ͎SvÂqÔûđqø‚N„yäŅrUËÂö~ūýęį~ĖÝÝ&ņÜe={ĸ}œ?#A|)USI Ð@·óüŲ]xņââ] dëšēUÍdĸĘ ƒ­ļ>į[ó~nũˆkĩzōf!ė'!Þ3uIm‡z*ĮÏjÝmīŠQ‡ā딙ÍFĩZt_ÏswuD€ĻLĢ6ÔÎIÁŲCÕFŸzp|åeóåŪî<Ũš*Ŧ[îArTk hĶęhþm3ģˆļ* $iŸÏĩŸ]=ig.ĀÏŦîŪ™RWÔw#án6ūîĻē ģóÎûyûÜ>ïaxņâïá] āÔÖŽãzbUVxÐgÍð€áÎgRĐhŪjŠĻŧ€Žĩ”=ŠëZŲŲ5Đ#ķ=gô0<Ï:<@B;|ígĮŪ1ï0? ˜efvÞ­tØž[`Œ8F†ßāąĢ‘°X!a8tMd ;Ÿ=ÆbíŲg―–Ô]āaãM˜“·{ïĖšÖ%°2ÍAcÍð wĸo77ĢŦŧ*Ŋ>hd—ÓÜ}ïŽŪ}exņâŊáĩ0t7f\4úlQŧÍ]­oĒąŠgv I&ĨŅÕJîA°Ô$ŨįęJĨüLĢSYF"ՕĨ.s§YWļ֕ßIÓHveŦ'øuËŊ2S%ĢŪÏŒ4íįÎßČąCĶáąÐĖ,7ŽðI ž Ûnyļ[Ta~­ ŽĐŪĢ‹( ŒXŧʈĩĮ–š|rWW|5ŋóĻ‘Y­þÆĨ?ŧZî‹@vuŨšVfÕYóۙfðâÅßÃÛÂĀėþĮ ÕŧŌŦuՌǿöēĘ}}ŪĖŽϞņđĪĀũ‰ąâūŸŪ:/ËŠóëHĩöo˜ÃŨJK·j™ĩŽēš+R‚ęÄĒ“°ð5ᓐ<\fõWŽŽĖJ ŨŠėūžšY ŒîánŠ}ņâjyþ(2‘Žęo78Y™SĩÏ5†K}’mīėšTšÏšĶũ’M‰7& ‚qÅ0JēąüšŲv6i ŒžŸ›œ˜ËcŌ]v,Õf€Z='WlāÉlđã·ŌܖwKUį þïã8™r'ˆĩBj3Ģ9ˆý< ÃÝČg§ßã,ĢÓ9ōē댈‰7ðópYiƞ"œ]$Ht%iR}Ö§šįîœfŋ­ ÝoŠ}ņâjö<;+.uÏŅV8Aýōl•4 žL[kA™4ŦÛ=üxÚö\œ•] œ›7$Ĩ–z˜ŽĄVIÎ7}îý˜9ĪėDXÂĪ&lz'L "ėý /?Ï ĻÜ|ĖctÏ7_FԜb͒zTÎFĒiVĸbęŲMã€@Ŋļ$ä™Ų[õė[h5<žŦČÉüEuuŨ$v)Ią|ĘilrĩÕ}ņ§ģ <<­Ū:Ą3æÕĪŅÆ”5!{?4ĖÞā9 þđŪÉĩ-։j<];F0Šą–šŋ9 ÝÝĨ s8wû*ôŸwriIaÅrģIZÄE;―€ŲĻØX–s·†Ękï )|þD-‰ø“i3/^žTŦ‚_.“v&8‚}ÛĮn0ĐØÝĮS&ÖgŨy ƒ€ đŸŅH-PsĶô $Íyf6(&š{\ 9ô”ęónų6ЃYeģ pß{w—ӍŽJ3Æņģ å]Ũs·Õo^Ũ؛‡ÃWNoûŪjašÍ†4Ņøä$Ô8 oQÐÁÔįDøóėœx\ũęúþ"­Ķïō/îj_žx o, Ā„ĄDÄÎįKö͔Yá‚íû sšÕŨ–:_™>ÚĢ™Û”ãžI9†éŽýũĘóĘNáÍýóCšņũÖį„ BĐÍmyHÎ=Œ'aŦ KŠýė#l―ēģ[kÜeYéūÜū}―îaôđũŠ8Ý·Û×ņ‚cN·Ęäœãļ›vÆUŠwZ`EÜũMÐÍ>[#[ę'ÍÃČėė,:#VU7:"ūķŌu]­Þ]„VÄĸԙo Ë4nĶļųõYõݗ"ÜŧŌ,ˌîÝE#ŒÝ†ZŨŠŪtÆÄ ΜH'‰Ęt7ĸŋ"ąĘ0 BU p\v>ĖέÆ)ģéМ‰°ĖœBr˜eXđ‡Žy äaju €Óæ.ĢŪýųŋ~~íė,vļ>ũ^+’―âōu˜]mN@ĮüĶĩŪ‰NwssŽJlü`ã§ dí§JŸÏ%`gԌn;7Ð Ýý] žxņÅf-°Âþ$Þ`@nßîXúYđfŦa0Ņ0’úü›ŒíÜđk“‡ §§Āš›ß=.$MõÃÔįüķ6<Æ9™óYK€˜B_w;AY­nsũ|ntwHĮA°4Ō=ŧ:Ïäî“Ļî#šh)ÖŠŪÎ&ŋƒ9Îgåš9Žôn™ņėg5•kĶVÕ|2ąŠX8„ÚUĨ딹W&€ŅÕ$†GÖ+özņâ/Ö8jtþFóðpïęÌŅÝcÞ?Đá;}zģDŌCî―Íýš.sB"q:>kVŊ5Å\Ûhî>=Ã_uX`øųEIwëją‚fđ‚ŅžŸ[‡ŽÞUú•jõ7>FÕ―+[ĩVėÜjLãúHwcų8 pšĮš› P+bl+‚Äó<=5ėčýܧom$~$Cß§Óė‘ģ\@ŊÓR>;5Æ:œ{˜}ÂÔ_žøcxäņ°ŠFīv%ÝÃl^€îņ ÐøüÜ0ÉTe‘tš~UcËŨ!jH·ã”ÅlNģ:ÜaP7hj™™€ŠžũŲ9AāŠÎÞ-Ūp ”ėÛ} šÅëė‘m]ŨÐëų<øLkÃ2'lJSč[SSōwIÂęn\ŨGnđđŒųėEÞÏmnq­}? NcTĶTá—Ï~ƅnY Č܁ßŧ„w)O*‚9ŸCĘŠņâŋŋEĩƒY9ķ Á‰a u_ŸÏaF ECUĨ:<ŒxžÍÆõϕUhð|‘îķB­YæķĘ-Š’įÍU-uļ…Ŋˉ'ŧ§ģ@€Č*I/ÓþMžxójIšqŽcTÃŊÃY%730ïĖęåîf]ßĀ„ĖzžM#gą+]ë2āĻāĪRvũpkĩĶuÖŋŒtŪXÝínæÞ­―7ÍNhKuŦē-Ē$Ģ…y˜ĩäĮÍ&p|ßëęŪŪ&ļŪuîAöߕ'ņh>”™uiül4dnĀ,lÅĘn`ūÚĢ[4LBWŧq}VWöāė ~ĪŽ°ˆĻLmķ•vöË­:ęæÖhsÆuÍļMČý5æūxņ'uĩc*U{›Ųu]đ‹Ī]fĀŪĶņŠÐ‰šž­œbšYMøũr@ÏÞ ŊuAĘŽ5ä\žÂČŽ­n3“°ũvģŊ؀˜ÄØųæÞÕĸüs͐[j4ęIŪ0#ÔÝ8ņ,'Žë_˜;đˀësaBđûõ‰ŪŠV\Ëh]%” Áéf_2û]ģJUÅŲ4ū$<­šu]0þÜŅøýœxŒ+F )Ėž{ÔļjU•…đųŦôzņâONĩÂĐVH?čVϊ–|ū[ԇ"ŨšĖŋQŲąV Āô"xWKˆXZÝÝ3PËÆ–šåfĄîp'Ø­]Šyeí'% guŠKģ Ąŧ69đą&Ÿ!%įĮč‚ÝđŸmĀpũ4{Xev5$ʞŸgØZ―ÛÍÖy7ĩštĐŸį‰“a‹Öa|œÂ›F ĄÚÉó§ëŠņ/ŽõĐ{…ßgsēօ3鉗ÔÝxņâÅŽqėžÚp­v mÎĩâþy†[·žûĐLĢuŨøŊxRßûÎ] ŽX•ŨuČĘąŠUŨYw2brē;Ūð°ęėJ@“Ÿ0æąasâ\œÕ]ķ.Ŋ,@îáũýÐčNUKß51čĶ™Gd ÄlTóŲÃÚđG€Æ#°}ĖÍčŪh:{Ķ xRĘöNŠũÎj8y]ŧēÜmHœīÏįš„šQ2dew”ģg+ ĐŠĖĖh‡c_Qí‹ķ…ø/ņŊ!ōĖđAąĮ§0qV Æ+56•+ŪÏĨŌ0#‰ĖęšF2ų-iîœŅÕŠ:"ĖÝĖöót§LüÂõYSÍÅErŒđÓÂÝBkliŦŧwĶkwŨl'@üïūa\Ÿ‹ —Ŋė&'Þ ™ĐžŲŦ†™ˆp[+žįYUvÖŽ-]Ÿ%a‚~gU]Ũá]%ČĖĮ8ĮóĀęóo‚kS‹Câŋ‘jÉs€^ŧÔá1õ-ŧw0c[ŠĘC=ÞÕhŊņ°N$öäȘÉÝF;.I-āëŽ5PĨĐóX ëŨ0–5+‹enõ› â~žŪrzîœīšˆï˜ŌïúĒĸ;Þw77WũxŽ€ĄŦx<ģįŋšāóóÐl]!Ąz-3=‚›köķcįíŲ,:A›c―ņ ĢFĄņ›œĀcĖ՘wI^žxņWŧÅŠŌ<ÖĪÔ}đ{íâ9æę]UõŦëĘęöeĸđxÝÃŋb[_šĪô”ŦĶ(ũŋŸŦ[hĪK]ݘ:Hēģap7ĩūúēP‹Öįói•Ð8Û3T_ŸXWæNfš~ūĮt;ģŠÜܗ{Ņa€„>ÔÏęžø˜ã<ÎáėË>ĸY€uëžņÄK&Ĩëúüïį'ģĖÝõWĩŧ-ģ‡Žkķģ43—JýšÅ^žø“šZue–Š ûđïÜĒÛŽ_…v2+', bõN:—/ZžyúnˆÉëšOšĘ‚ÎúâÞ ãZęžîÞ)ÓéwV'I$væŨ(âvÚ'‰/^üÁcąģQmvC―ïívvē­oË-+áö›cPæððQ’šŪĨ>Ä] qŸ\D–ė.ÚapáįįqøI˜Öī=fōā,nÖTíJĻ:Œ‘ Ņ"ÏfŊ•šęÉ#Å$ÔĻ›sûM\4šžû!Hz*ϧ qîAðð3kŸļpØwtĩĢlĢ‘Ī~Uà įúÏįjÍ áđģš-ÎÂDåFáŋŋ‡wW[ģN5š{V’4šĐ‹īY,ŒÆ üԂåГ?kķæTŠŦ3ŨZø(E˜UWåoÄxŨš<"ūüՂðÜÏhi݃8üį^ŲûŲ]uýóivwŧ/3ßÏs(•âØgÍWؕ‚<ŒhļĮu]Ý­–EļG·Æõ0GmgÞ Md6?åņ/ŠSÕŋûŠÎË*Pîūۘ_1r‚Ė'jg>Ū8ĩ,ĩHó“?iîËÝ`•eösĸ&^ž "ÂÎMš/Ÿ-ŠF?ŧΜxŠįūŦ;âŽ_wđø ÄĩōHúÃ=Ėïû>,ŋE°ÝY=Ėîûŋ~ōđŸé†éTvúōCÐčnĐg”nÁÃŊk=?Ï$ŠMāËļŠęđŸŠtógïŽBœ5ërwŨ7Ō° IYR—æp/ģ$yÁûįĶųīįÎcĖyŨéëČÜ%Č`ŠkRuF2áslÁ-‘q ÄËĩ/ÞžZÁÍŧŧ*ŧsÛÏ6ÚõÏ5e6æF°ŦhtsĢíúēdŽg•™­2óneÝÂŌ“ÛŒá dÞیSå@#!>3x\]UÕv‚ēvÝMōóÏgH؃$ŦsÎüŧŧšĻóÃ,FŧŪČJĄ#œæÏŲüš9 1”TŲîg0§ŧã;)Ó-―âÃ(6ĸE<Ï&nÓÚÐĢÆÍįĄŲěIš‰įypnMðĖķÐ[xó'ņâ] •ÕÝ&rаĶ{q$Ą+øM›/ė3ÛV Ï.óģīū"*ËýßyBŦÍėZ—TûđŨŠk]™)|ÏúOŽAÔŲ6œÂ5Đ æIÕgf\Ý=ö-@ųlád9Ēg§ėîũQ,ŽXf^§õ€4•ĨŪ)Ëcrû–žý œqĩN-č°ļ/ŊŪŽ$ĖwʂûŊðͧRwjĖģģ sÎ0{|w!˟Ą'%Rxņâş<kTuy,’“á2%ÞӜxŒđŒ6Qĸįú Ý˜ŲøĐĖéá~ĶNĢā7#FÂIØēĐ=xØ<žįžāDšgķ™…{e>{šŒDPësM1™y,€Ï~ô­VėLyÄ:ƒ°Ïˆ U•әú䷅Ð(ĮfãėnfV]~@ÚýütOÃcKĒņ[nvjÓŪk5z"ĮfĐ2%7UuĘoāôJÍaš™ĸÜOõáâˆ|v7ðę^žø›…7ŌŊlk§€pŊJnîŧà äŪ27ũĻîųáįĸ|ōyšaFė_æuÍ4݅•y^›yí<Dģ5?tĢZûyĖđŪO·@†G˜WĶ‚“ËAĐŧ–ŦK%3ü–øĘ-&’\-·póRuŨ!âŽnģïi$ Ÿhš™ąšŸgSöÏįڕ“LÆÔĀßzóŪlEĀP;šĪ“ØoÚšVW?ûžþöîoåąÜ%ü9žxņ‹…›™ĐÃiũBķĖß}éö=a‡ä5 ‘vūŠĄ~ÍF4ŧžûgŠĮģē[ßo);û0ÍsošĮ:lØéî§õ ũ9ŅōONáÂT…?UEZ·”Đ:ë‹Qŧu†ņïŪ ÎXęÎŽ{G\ÂoōËô0ķč!k~ŒïæÄ°~3šĖL`î43%Cu§Ô0ũž7Āu]$ Á+fM'ÁŽ4ũ–f;<đŲ9ōŸÃ‹ŊØk ßŽuf^ą Üũ-ÁÝÆĩånW„ššZŌō™ÕŌšBÐxÃĖŽwCˆ9(ëÆ‰)ĻVĩüŒŦđ‹Ï~$­ã˜­ąŅŽôU Hîįdp|iļ>ŸžôYibdŦ“ģĨnKâįޕÝÃxüũSđӗ}cČ[ņđ<žš-|yô·;îĄL@$@{öÞųÄĩhĖ―E-확ņõ‘&ÚĶNÕîÏÔčî"ÂýĘ^žxIxø~6š‡|[ßėŠ2ÜÜýŲ5ÐOjļVDПĸÝ~š %ėûW “v\ÕåfĪ݇[=œÄÏÏífë45HÏ~ķZ”{|ž[ĀŸnuW·ÖU]Ųffõ/Ú8 / ‚Ē™ß??$ŽŋVTøŠ\ÍÖ?‚Uá” #Zt­ó™ÕjåFļ bŨžķ›u.ß=‚@UčáUóüÆįÉ03ũĖ‚ÚÝbš8Ŧģ—lĸ"^žT gxė{Ÿčn'lÔøænDæîj_SÍ]ãzzîMrÅ ;Ô ’6åÞ0:Ų%˜NPÖ%ĩ$‚~ē―ÕúüóĐŠR“æ+$fn‚q­ý<Ž&[O>4―ŧ+ÓÜŊ“?[j3žĮxĀi,įl*ÖZ'ÆðwšUNø7í›R&3;2ÞÛ<(Ŧîî"|…WUw™ÄYŋâ’í]n”čfÝg­ÁzōwÛŧ3s]kJ|Wę wŊųe ÓÔoÞĖŸÄ‹·ðÆėĖ_Fs#ŽûŒ{$ŒũýTöÄVåņ}]ëī”;=܌5 Ð+ū ģöÆäjnRgåðlv‡ûšÖh°fáÐÕYûŨÍÕĀdøÏ~`FgŨŲ"ĻęýĪJæ–UįmbÃÔú\—‘đũ8ß:ã óčjuã0mUúZŅÐXlãø)š hŠ­RÕu­ĩb?šûōûŲRŸĶ uÖ0iUÅrÓŊ"Ÿė†ŧw– 7?#vŠ‹økxņâ­q$Æ f=mƒFfhĩŧ‡{·D á pÃ2ܜBVžĒÏÚӟį™!ÎĻÜ)čätî>!°Ũ~žyŠã­šŊų.Ą;† 6iŨ(óėjŊhĐv‚tĸ.v=bž^ iˆ$ÝĖíŒŦíŋ>‹ģ…0HÝUe6qâŪn4čVÕ­qčrB愰ēÔíáĸdVĮĢsÂŋ§Ø&s{ļIĢ=ða]Ւŧ /^žšÚï—h›˜+ˆ#Š2cDĖL4Ķh7?„Xø §ĐáØ ÔiÜ{WĶō˜I :ėšV>[-7_ŨW‰UÝ ŧęüÜÆÖÝaÖŠęŨÚy.ˆ˜õ+(s'yŪéˆ"wrrrŸ=ë‹óx›OÍ䔛[We“–Ï·a`Ŧ‰1ŸėęXņÍ*ŸĐ\u8ú”ŒíúFš'3ŨėðŊ/y`á|wĩ/^ŠõSHþÔCōšÂĖ4ĪuvŊc*u(uÉ{?EsuïgWi­―aŸOíꖅnOĘLJ}‹Ęݧ;ĮÃDŒyĖÍf(ž )íl~…ÏuŅ ð(Æ>Ģ9#ĀtĪį—ĩ ģrÍÜIŅ`­†qš~Oz™ÜiÎŽáŋĖĐ Ļ•:Âŧš2ĸKŒÉÅ:įu{' Ũĩžįל+öýÐāîf6 ũĩũū7ŧÖÚÏÖа ‹Ų{ü9žxņęj}y>[ÕFčtqƒú|.M:zšoēËf•Īˆ)&”ÃŽēëÉ0úqp‰Mās}jNáŋĐ.e0‚;·$ãŋĻ― Ē›gn@îŅ’Æ+üY ŪĨÁ*SjöoÚ„ŠÆYŸ&AŋâŲŠ#üZëđŸV}þđštÖŊ2R8äü\Ī š1ZOŊđ ĘėĘþYãŨõČö.@~>HvfaNĄÍĖÄ&Ķ}ōÔAJĢ ūũc ðņâÅŦŦ͚hAÕÆĘ#jNoH$ķ_‹ä}߀b]nÖ]:Ė(ēÔ ,"ũŪjœ‚}ÓVW·ôdzÉÞ­Æ:Ĩ }Šo—ĮėmŊosLÁkg'‹/5ä4ŧÓÉ削žĩĀWopŸŸ§Õî45|ųšŪ― ķ1qãĩ˜aūwÂ@3>™P[8ÃÎvëš“7€§‰°åŧ·Ų12€SÉyįÄÜ|Ū+swũŽ2žc$ņņâÅ+öŠÖu- ŋn[qUKęC(§Ó0ÛÜŲØųÐ,,č|~œ‚Rö.3ð:'WKR•Öĩūá,°Ïúdfíįԃ]ũó˜āææžŸĮ=HLøUauuyïŸm„#66ŌŨFwĄ/Fõ4㚝éXÔL #- ZÕ§Ļ& $ŽÍG1_úĢš,ˆrwî'ašÖĩ+Ą°>ŦrœšŸĸý˜ÓiŠūũžxQt[NwïžÅėü›…7/^ž „S)[ëģT=å0Ŧn1‚'gxüõY9ÍPęėĖ-kwë›ļødw›y+ 4wƒ šUÖ!č0ũîúZ‹3už’…V 2ũ.ĩTĪMIÍÜÜ$tŨÔęø3Š1ÂĖîŸͰ čRV-ŧPmÄõųdíę‚xEŒb­ÆĸŠÉ‰ŋ‡/^ŠĨa­ÕÕ:Œøų\•{{˜„ŠūÂû†,|ÆÆÝ`8ŦÎÐý+)Ĩ R%ÉësAĖL•ÖĐ Ŋj4ž…ƒ_ŨĮĖšŠ[vũIâ3•å ‚™ÉÜ$U%ĮÍŒ Į$ĶŌdÎîŸý―ØxNÛūK†Ė<Óqd6ÍÆÁqÔl<ŒÝÏó„ĸ‹ođŅi}~•e6Tl;ŦŠOūA?{Ó}]'”6Į›ËgïÉP°ģÜ-ÜßíÁŸÅ‹7Dq‘jõ$ŠäއvCp•Mē A0 7lU6ë 7ŦL“ß:Qaæg°…Ķw+ŸÉr wo5Y§2+óš.ƃlēoÆ50Ŋ$ŧz,j1Ūģá_óŠl!Ö:.ƒē0A“ģÕÕ§E‚“?kæ­6CW‘ø.Ihŋķ.3Zw ]ĨĐu4Ūųo™ķîš=,ôm[ð°î&—Ė*áĄÖôĖ#ŨÅċŊØk†ēŅųũ›ųH tk^ƒÚ™fŒåÕ)õTŋTįŽØýMĻņYŒJ0Øþ―ÁŠ_SQUuØ0;Ÿ}K ™ĶvwŽĀq@xuƒĒqlÆcΜ%ōtĄũĄČņ,ėÓø›™æ‡­Z€ûôHĘÍĨ>ãŠĶ(5"|ÆŌÎ>+Ũ2§Gô‘ëΚÁ$īÃĒŦI›q{ô>ŌãnĢ_Ũ‚Ô-‚ø‹xņâ] +"ŽæīéæËI3·u…ũģ[}’›Ūš"@VuįĪ šë9Đę4·ÏéSĻúė"ŅT7ŠjÚÆūĢīņīČĻŧâôƒweu˜é Ņ*ŧîÝUՇ+ÃOąiöČ{§đuWí=[;Ė~ŪĘt§Ý#Ŧ=–Ũ°ģ{ÎÔܘMÁ+–đ?ÏÓUĪŧ{VÆåŸĢ‘Č]]"mŨSU*ØŋžfT· 4íĖ*‘Œø“- /^žT[YFÍ&“EęĸWV„ˆëė.Ė\PŸĘÅk­ĘĘgCÖ­CĘpũ§ģŧ#ĖÂrge­Vý/šģ[rûŪ_Mæą-€ĒŧŸ°Z­å’έĸmυPÝl|ûÏŦqÞîĸnļéÉuĄđؙݚbuaÍĢ+íHÎŪ6žŪ%@úē!ÔĀygr&bōYæ†Å“™Oš{,ÏJ€f~ō' ‘˜rÉåŦŧŧZęīø†(þMžxwĩ+Ķæ Æ)ķiĩŅ@f%SU u,ŽTĩĮ—Ũhá2ŒðĀ$ŧK-Â*ŦUū‚UĢeæføß}wj-ŊcĻ2Î24+ÛČá/ÂNũíDsÉČĖáį&ÏóīÄSvðÝáBnĐëģt5ĸüŸOĢZma‡1ë\<ā’ÆRWĶAîÖĨntÓÂv=@ŧ‡‡ƒ°ðRïgwķ#&č ŒV˜gˆÓH–jÔ$~đ…{UíLâïáŋWW›YĨv3€mfī˜áQĖŦú·7aZōðŽu•QfAōįūaĪÕų4 ĩŪŽ­Vx˜óū38ITĨ›đųŪ4šfLuw™9Āû~ĖlĘó)Ũu•–>§ÞÜH'øė<ŧŋĩáW|R5[ ũ8kb42wō°Ą{<ûAËV@Ý)ĢŅļŸĪŸ =aÔ!{žœ§‹Æ {ŽĖŅ…gķ=Ÿ[•jUũXæ`DŲ”―Ŧ:<„ŋˆ/Þ]íá7īxŪŠŪŽ‰=,íú6$ķīO…Ē3ÎIZ‘3Q&É;Á”ÜÄõĩÞĸ=Oáá™IúŠiÄ!ĶĢ·j‚îv?·qļLyÞ$"†7'$aÚgéNzU“˜ûfUCæ‘gzÔ TŽïbŨ֙@§lÜÜîŸ[R|IÕ7œ·ŠÍ N7ËŠŪrw‡5(Ââ,mģiFÚŅ#§æ~?weqDįą?ŨR++%]ŨęnAķþŠØëŋ7ÁÝŊÏęėŲTŅ;'ĻŲ-JV―%P8ëŨ/'Q- ŨššŦJUĩ~ )ۈŠƒƒՍÞķf$4ģę–ÎËsoĢ™›‘ų―˜į]+îöL5ŽÉûyŒãŨ…ĻÍÝŧs…MՇûÍqčþp―„įÞ"â\ŽĮƒ›Óąx­“ Öíæ!ffáë[–Nƒ°ũãf4ņTþ˜ŧ›ál~…þ\KŲ‡ũíø[r3tKÂċïT hßd\áīĘ wŋ\ŌsoĢĸsīOdÁóTũZ1ßĮŦ’6Ņ* 7DĢ:=|]ëČc+VЭU―âTjsøũ‚AŦŲū·_î­îŠoô·þœvÖĐætAûŲN„an­X$r˜™Wõ“))Üï=+W§ÔVŸÏõtßfķ–GxeķúPdW@ØŦj,gö_šđīܙŧHh•$óoCZÎcÅ‹§0b,'Ÿ> ĪyįŅN ö―ĮļŅՙēðæÅ‹Ũ˜ ĀdÝMs ŋ ÖÖՄ` Aõõ­‚ČÜSÎļsï―'Sædĩd„_Ũ•{•htž |ųI°Ųy&>ĩúžĻÃÎ-›Ïv‚ÓĨs6ŋĩ“fË€ÞÅ_qÂýÜāŽ†ŧš=Ïķ@6TĨýĨHkUVđŧY` #š+֙šgSč;VŪÉ ;ËŪŽŪÏÕį9_wïī‘ß'ÎæTNTwK8ebOŠÖį›\ÓhŌuŋþ…ŋŠïŪöøz­Ø•&ÃŽ5Ŧ%pV™{ÓŅ-ž―Ãm­•ÏÓÕcóŊîÚIÍēRĢUݝâœãŊˆŊހNXŨt]Ũ—Ås{ö6Ó꘏Á ú)57r ŌÃb]uV§$9ý‡ÛÄuũœÝđ1ŸíæĮðķģ3čæÖUšbņØyiæē„Ŋ“Ņ%­kđG=Ųiîl•ÐŨuôøŧĄnÕN ‹ģ‡™UɰķŽĻŽxđöoâÅŧŦ5·9&2Áø;͕q\]ŲUn1R­āŲovuë$8ˆĘĒÕĩ–…ÏĘf @ĒĖ-ÐĀaå#uĻc [óI•čÍ ‰ âH[IeĨÐfY hÅŠVÕŪ]nĐŧÝ|ÅĘlAlm0ÂX;ø|þuïm#†8Œk߉^$h&ĒvÍuvVĪOž•b9ĀĖ ƒ“’vfCës‘ÞYþ"^žx‚š0ÆHbiNģž7͌ī“Kš™Uõ!AúŲ{Î2wä\Ë#bÜđĨķXU­ķ35Ņ.fĩËĀpú‘”Ĩ_q"ns:;3§1s­ÖĀY›ŧūu 7•ËížŦŨŠood#Ū8yŠYęXūwVnˆÎŊðËĖ Ë,R'ėQĩk™Oųņ/ŒĘMœæümĮ9Åél˜UYÝttn'3YU<õæĻ–šĄĩBø{xņâĨÚV‡yå6Ō܍–ωī=ĖâžU­ũX߁„ýFXi4™(eî‘7…/ŋ”=[āņóüĻ`wã›+–]]čéV(ĩ™…™ē™Ûė 2šÔÕíĮ);^söÏixĪYK{?jœjČŲčĻrNąŽZ %%Š*77B] đŸ„hųú†=ŠÍ―[úВŠE3•žJî†ĶØg'#@ft·Ęl‰-Ë7ŲëoâÅŦ@0ššáÖÝ roŒ˜`äęu]““―âôŠ?33Ú>ĪlFÕ―Õ'{Ķc†ŸķÄÖ Ÿ…ĐÃĶÃiÂ!;RŌē·ū‘ æÖ%iļU-ĖÝŧŦs fÓŅ+āT+Þ';&ށĘ$đŽĻķš@Κxį3VïFNqzũlWUĢčîqŒmR{8ČĘ"eÎ>ÕdvĪŧóg›ÛoØ#OŌ9~þ0"~[sdæ_§ƒÜ! /^žTÛ­ŠT•O4ŒúŠËÜj–W`DKnœÂ˜Vļ/€ÂCŌīęÆĩÔÝ sóÃģ“čð—Â}*ķL*MW››‡į“㔍ãÁ§ėÜl‚šÚĖAÜÏsx“Š{Þ BwŸ‹―šģōZO―9„8óėýŋŸÉÆíRVš…‡Đ%Ļ”aŸÜų5!Øļ9āΓ?{˜Ú­Ï;“\ūöÞhėîxæsĮëšÎ'Mƒ1ūÕúŦbŊ/Þ]­ÔĪŊP·šNbaÎļęjtũá Š5-đ : ä—™ýŽÖ126Äáē&fߋšä[ģ/ņĄã  qėŋӐhu˜ÆĸX’fÏ}ZC[Ā„~ū-w'˜;Õ sã8uß?Ü}bž-b]kô‡Āy›Æk­įyŠj.~ž]]'sU5”J"wėšŪqâNZØtÛĖįÁ}ßƊOfÚPÖwxwþ$^žx3hĖ]-˜―Xęķ Ï—Ī™RÍ]­RjįšŅt:BŨš*û\iãĮ•ÎS@ŧ—Įu}͇ŅÞÚO·r— õ ũū)~ŪNša•v'aį]Ôŧ ŪÏådí=yßŲ]•æū"îûųÎļÁûy CÄPevŨ?Ũ2ģ>ąÜ{Ose‹ø‹xņâjóũ‹°ZÏÞđkEPčnĐÝĒēš­qt—;ãmĐšúŒ~ÖYč&hNīŠŠ$„*IĒóÉ3wvžnņņy9fôĻJîé+ópģ―šŧē'… š$ kuĨŸÞÝIÏYWŠÚģũčîĘdÃÜöóĻ›ˆûÞ$=ĖÝóÞ ðß·~Ёn)hĸ·J xžgöË4Ž5áóų40å žú:ĘÜ\%3‰ŋˆ/ÞĐp7§g·9ÝŨh  DvĐû›ēøÜްX„ēöļË@ƒš‚{H51ŒMþÜÏe+ŒŽRĢÃý]™ņTđŊÏ2Ø―Ï—OĮø!_d%·‰ã:ĪNÐlŽīáãŸhs3ĖiŨrë]‡É1gÉ,œ‡ōģës}v—8qFŅ1ýûĖ&šQ†î’ 2ŦϝðÏįƒÖŪSvBgâð~ŦžshĒ[ųĪ9Ýíy6`h ģ™Û„Ûþ-žxņRí4æVwNüŠŊ<3 āĶ*īū‹Ņ ÓØÐΉG8„šãøå9VÔ8ä›;ÜéĪY>ų=Âj<.XŋũCXœ,ğšíHēüt2š…{č› æSG&ÁŒFÛY€b-ueNYTwgŒ+joˆaFĖ=/PåPŨšv•Aߊā,ŌVP€„eÎp€]yH|Ö;wÉjĩ›Mø·Ãūž/ŅÁeŽÖv·Ü;ĖEŌĐŪ œl)ÏjûÏáŋŨ˜Û­Đî8đ#áēˆģëlũˆptS"CgzTRÁyT•FĮīįŌ#–Ī“å*?ž[]úfŅĶjŅNŽ—‘f‚ē’ßôÂoX,;ÏĶ0ƒąŧ!­+ iœÝ…*Ÿģ:ģâDĘRfĪ۝Ųč‹ Jū.8ÐÍFtņ<ČΜ…‰™O…O\ëÂü–ŧŅ”0ó~õ!i‚―kg šÐœi{Œåj@lČĖ҇Ņĸ"^žxÅ^Ý<ĒKÓĒxūüÞŠ&͂™ÉЌ%:›Ī;ŅßWœĐó9æW’ûŲa„4Aā]EûÆL=cKA_VO’4#ÁÜÕ-rguö)šUaî’ęįޙu.ÏÂhžŽvī—˜›NŠÍYėę[m[-ïý<ųL°ÜCîmâZkúlĪþ\Øđ5æU•]48‡+Ý †îžĩnáÜÚÜō\ 33qîĮčÎLRnŽŋˆ/^ŠBFŠ”`4_ËÝóŲ}Ļ%U"l]ŦJā·ÐûđŸa―1eņĻĖYƒŨįÃYĐRnĻĖ―wS@ŨŪĐ/+!;AųĩÔ匈ĩOfŧÛaĀåq}–{ėgäe_o Öšï§ÔfGņZMŌ~ón öÏįĢCpšuŦŠA:í~vuOZg™ųɜ}: Ī*u—ŅhķOoåšūŪîZ+&—ķ!w;ņ:}B"cïÝ­X1ßVââŋWWÛÕ#É:œ+U-§­ë{œĨrs_Ū꩒āágóHMŠĘYø2ŽU;ũÔÏ@ęŪŠ ?LMûšËē@ZļŧĄADk6§U+–fĪčþ Ļ­ŪŲNt·™ŊûØ œFðūïVƒ4Øčb­>Ïņ]_Tv·ĸæ”ÝÝN{îƒéŨéŲ€dŦû·­ēŒ6 ÕEōš.ĩĶĖÆÝÔęÖōģų“Â|Ĩf}û–“ŋxņw“―Ô-é7ē`jÃ#3ģÓĖšvŠ„gïžÖĩbõdËō{Ú>ĩn>>ŨCĻhÎĀ;Š0sS5ßjÅn’kxķrŒņÜ9æŨĢÄšŧ;Ūh4ðΉãk] ĸūX+Ū%HĀá=ŸŽ^ ëŪʄ0݋s,ņsĸT—ŧ™đÁüüŦ>[ˆqčšŲü‡ŋšīá_'ÁoąnDfíˉƒČïķũŋī‡&!Áh•i_žxËÉŧû”ËÞûĐãÔõsĸ4ũ0ãÞeīk}zj_œþ<Ī!iïÉĩrAÏ~ŒķâŠ*5,ÜÍr§(ðãĩíÃzCX•éWdĖ­vyģ&6’ęCY0_.};%ãDpMðgķÍĩŪÉj-mUWũ8Ęš5…ļB?ÏcÆ3wåDôÚũ‰5Fm\=‹A™ É=ÔÚĖ>§$b­ŦĄã†Āi áq­PãlTÚÝ_ķ}ņâ/R­‡}þY™Iás}@uivĩŠę’››ýl~kMš=?ũ™‚bwpB„–  Í2ũVxžM1ÂHVĩNmxV4Ú!åođėĩÖÏóˆp@&2Rũ&øĻĮf^ߕPŧ‡ŅŠ’naķģĶE‚†nĀātāŽY§wŨw•ŠĨ’ðMđ­ęũãg3ssVÎHŒõų ÏVËÍŠŌarĖįIÆäĒ-f”nLÎ/ð69ūxņ'n‘ĨÎ2ō˰ߨ-IüoŌėz2'åĨē"ą<Њ€ëēÂĩŪ*›ÆóZŋI†ŅÕfīE’]M Öčų9Ĩ3í]ģū ë\-fÖu-#ēō<[ín˝Eũ5'Wt-ŧšj­aûÉĖR‰äģ· nN• öÏõÐ%šÅ{?'—k}?Tī4™4ŲäË%Õ7cŨũ~Â"ÜDžåăeV)?ŸÕ­–ˆ/^üÁhð.žÄ?:ïįڌ:08ēww‹ӔÔË\ĀýÜŨį‚ÔÕjų1ŋNëĀĖŽLĄiŽjĢëÚų­ŨĨðë[ĩþ ~cÍÖšTýÜwĐ""ŧÉĄ:WԁąĒu›Q_AĨi ‡ŅĖX%ó Ƨj ė,’ãāĻŽ)EŋĸũĻÅáÖjGÄ6B‹–žýˈ:―č+Öd2øÉMP;Ï­gŧ2AæûĐîÆËī/^üIŠeîėi­>ãÞÕĀsXÁüð‚čīëš"H7̈́ĶC6ĒöV·ãxŦĪvók]Ï~2·ŧЙ%'§NáH§úÐežÛ9Š6s7ŦÜR“fjåģ!™EVuĢŧÐŽŽcāüD Ļ*kuw„—šÆåU‰j#hÜyžÛ( ’yLxÄy:2Ÿ FûūÍH<ĖŽû[hö[Aw'G` ·Ų!4$? •›ā:õw- /^žną“ē:õYguĢđÅ [ŧŌÜÂWuw)"lE:Ņ\]ūO…,Ÿ‡†ëšÝųĻųY Rf~Đóü" ūžö7ô Âë<ƚØ-°ēÜ"wĪdíÖ4ÐđģPÝSŽÛ=ˀÖ9Î05‹uvcËý˜qLn]å$Đę^q…ûųéģĩØÝ+‚nOíŪ43Uïgwũü)F3;žĸíūoHg:ÆYSČ#Î5/^žøc „AÐ3įNČĀÄIģYüóđē{ îS[Ûf\ąŠ ­ð Y™fabWŦĄ†ÏÅ7;Û ]ë’zïŨ€ĪŠēïbZ}­UÝüŪNŅŌ)ģųœØ°Û<Ū+ŠÝFĢaNĻxaóü3uî'Ý}}OĻžūČŽnáāįwœœV§™ŧÛĸ_š­uÉEÆÔÝ$§ÓŽÕ~ŪßÚž~žĮÜÏ5օn]WėdU/^žø{ „ŅGĸŠŠĐæĶņyîIG‚ŧMX-ÎöîoMxTuũ,QGx sâ—=ŨúõLáŧÓŒ ŧĐŦē€oŽĖÄߎĢĂā>PU•FBągžņļÛÃ՘§ ŪCļąHV 7“4Õ_óü] ô ïfFÃ0ļÔîó= ]%‚āޙģ.čþ „ŧUý/$ÝÏmWðTóîóÖėlĢáŋðXĖ܍tg Ēƚô,;åēÜOšguIÝŨ=JRwëRu…ŧ[Lfë:4Ú:4ŅĨîT7"ēęW}§xÜÝ’;wf‡{˜?;2w:#sŦ@ė­þ|ŪįŲęí˰ šŧĖĘÊPŦÕ݇OūŒ6ÏÜÝí“nž“qhýüüÏ#ÖZuāđ7Dw7GgGÄ!LÞ{ϊ`lN ŲÓ*'YÝNæv‚w'õöŋŌÂÐąŽŠ+Óh+â+ÝĸMđ&čæUõóÜÕ;V {Q°°û9ķîgšÛgíš―DcĢëžĢ_ ÝÔátõÏÏĸāü~aϔnÏX] ž―ŧš3üÞ{f^€ûgÂ―bb ā6d75Ó]î>zâXŋ€ĖŊĒJߞsģ]ŧÔ~.Ļð8k UVļÛHšæōyjį4Ąˆv>$td™·ĪøĸąũÞĸQ•Ïĸþnē›l*DJ‚J „ :(JBGEéHŊĒJŅ"ŠĒˆ‚HïĨJ•ĶĄ@JEBM }Óö{ÍÜŊũįņýöLǜœ―ũūÏŲŪ3ũĖs|œ>Z–&A^ ˜ļóå<.ķĨWëĨf™…Z ģšR[•ģ‚A*ëĒū-F遟#$4”_6ëĪ!ã…ŋN2ˆ1šßœäŅ;Ⅹ'OiŲš5 SđnÔ4úŠę‹LNˆĒxÉý <|Ī–ĨŲ8Åzâ]Âfí#)‘Wfāĸ Øs⁆ öŅn‰Fūw[6ÍD‚[žQu·Y’ ód6õ4iڑAFEđøģŽhä"ÃŪÉ>2ĀĮnI ÛD‚‡ce.ŨÉlŠ~žéBÝÓb5“DĄę‹†ąphËx4ŧZĘ!‚eĪũZf™eÞ@ÐFškN.*$0B*P .šÝ9ĩĢcQŋ~,Ø8}æÔœŊŋūōMöŦĮhĐč-UŠTyäĻŅŋ,˜ŋoŨNÓĐļĀč"ģgĪoôũčÛŋ`€kÁOs%‹Đԁ՝‘ “&* þžĪīÍ/WĘaĐz0;[LĐ{b6Õ pL Ņ4ĩŒėAŅ–ĻÛô‹„“˜sė-CЖ?Č3š2- vŠÚŽŅŊQÅE·Ī`7„‘=“0ĶÕš&â^`Ų4 bu„óā―TŌØB?Ë,ģĖ“―J*)ëŅĩ6?ņg ÜđyĩĢëþšdYũî=Ū]― akÔĻĄp_ŠV­vLœÜ\ŧŊĪî“ÚUūÂsĩcbrrrð4ųeķžė<|ĮFM›ŧ\ŪėĖlĢ%ĩļÚ]ąPSwYÓ5ĒĒŠūð"*ž2BÛZubjGŨÉËÏU}‚üę5ĢęĮ6 \œ§a ŧ:ËāMáijà LÆŦĖĄI pļ1ä>ÂŽ,)™°šQĶ}ėūeqõˆ 1#ÎA SuĖ!w„ŊMĪ€c&&‰ąvUq0Ô6ŸĪ‰üš~rYE’Ęægę>(ËPéqod­e–Y^­„ LE}šĮYËuįģŊ•ãÎéÞó­Ę•+/]ēxzü4ä_‚ƒ‚§>Ūð|Åø3^Ūũ 49þėįS§^đœØĩ[O§|4“oÞĖČČ1xĢšt>rTŲ°°ôôgŦV,_ķt‰ĶĮjŨL-žüsSĶ}°Ž??uōsÏ=ĸéÔi‘U!é…óįūŸóÝŧ―{7nÜ735õɔI“ŽûKbžZkkvĐÖԚ‰ŋŠ"y―Ķ NŌ"憹ë'u ļĻxↆÕʝĀÓŪšBC\šJ@p(L6(–i_2#‹nWSũáÐ7Ã4)X.Č?šķŧPdÔØ‹ũ™e–YĻ…8šíïŅ:+JDMėBœŠUŦâÜíŲģëYÚ3|ȌŒg€ãÓĐS[·iŧzÕ Rôûõ˜–ötÎ7_Oœ<5$4dŅ…/V{)$$–UŽT bfeeōþĄÃĮ<ņü…ó'ĸ:æōÓ6˜:ķã?žðF›Ö“&Nðũs~1}frR!‚Ķ͚ïŲ―ûôЄ—+$8Īį[ï$^ž°eóæČŠ‘ĸþ{E^4æĀæn)šS,ĀžŠõÐá k t€ Ųô3eĩ6yՖïÉc€ÓáύģégũïZ_ŒēgæÐĪ-Ū— kņKĶ@'ÞÂxe0l6Ęō Ü…pļ „Ļ8Â*‘^$đb_–UîÁ2Ë,óĘÂ\ãڍhhĩPÐÏ? 00ˆŲŲ9"g%›įvþlŌĪé͛7ŋúrƌ/>?þĩfŊŒg郇3v\ëvíÞïßŊŨÛ=‡ÞĨ[ũÖmÛ }āáCđNŸeÓIŧã(ŋĀ ĻߊĨī~āŊ“ą~ūNL9ŊÓ4ŋŅæ „H#3í5ĨĖmÓė\đ8ŋLhēqQó•ü]-ŽpęŌųŸ•b•ƒ0M"ðmólZ>Gí/#Õ­ķMEýLžÐ,ģĖQ”­! œŒ'†CC!zäˆįþ0 ï{í[ŋūāįyLôõĖ/Û·i…WûóžßîÞõâ…s ‰xį“G{ŋóöÛ=šļØßĢ[§?ŋbÅԁýúŪ[―jÁüy#G [―jåĻÃ>7fãúĩœ'}aúņ―zv?qüčĒ…óĮŽu&!)q$‹ĪĻÁ”KHšŦŌóF* T(GÕ aŪ63ÓZ9ÁI1.ÕøĪ €ŋęrûf€Đó˜Þb&Þ"ģĐ)Žĩ,7Íx|t€J.Āb#H†™ ŨöpīĖ2+V+@ąc€@‰\·l\ĐĸE­―N;úũ‰ĒöâÎũ%ęïŸtŧfS™ĨO! Ā6o\LLK‡öÁ-ČÎ:s*áÂđsD'ŒÔc“_ŋ~•˜ųOØ­ä›I7ŪûĻ™Îc›Ö­õwų õŠÄýsũî}{vkŽÓNŠî™Ó§Ïœ9ÍūG+$īũ—QÝGŌčÝĻn7ÄÔÚ Đˆó•cwžäxĐŨÉ@­ęr˜.“)fÐ(„6_7gĖ1­œ€áä!xäĮφSSæŦ}…5jíqĘ6˜?ļ5!ưgę&0@,ÁÆX"ŠÞi–Y\<ó ŒÏEÓøĐ[FĒ{ ›fFígķŠ‡ÆœSŽ4oU[hÎ?gjĖfŨ?Ā0įA*C4CKš0 Hŧx1ĄļĘ?­§‚Ūĸ ö%˗K"%Võlȍe ģéjūœÔâW),ÖgsÍ7p8Ų­RŲYf'ššÃkJiq―õŌĖv–GWÖļœęÄ{ŒÚƒFQ4%V<å"Æó6uMDBI§vE'JŧšĀE.—]ÞņÜ$ÐæIųŊŽÂ°>Žņs™ŲîŌOÔ^ ˜ ķ" zē„{8öĻģÉ`PĶüēKį.e"ÚXaūÃGZۚ,+ ^ƒ1Šþ\†;œCģŊ|Ėý‰^—é)ĐJ‡Ė-T•*‘ŠÁģÖøŽšŨęđŠŧĘÖBéŌē4&ÔŠ4ŧF!­øēķšŪĶɂúķš/ĖK 5yĩĶ{9Ŋ þ Ũ―췘e–Y^-^§:bĶW8°ž\‘aĩŲUŒķ]û“&O™øÉäÖmÛSԀ –ũ(—óō*đÂiŧĶú)š{cŌQ= ,_qážiVÆŊ@}ōtƒ Âl~!hNŪ:âhįk|ŸtŠZŪLāeg.;KŠtmÚpATļīïŽpŅ&Ōãhvh嘿!h KxËĄĐŧ…­ 05vLJŅØ@ŠëWsS]ĶÍÐÆp§ņú™E#(\­ŽUŨœ+óÆt/Ë,ģP ƒā™Æœjč#zffF—î= úāþýǎ>lá‚ųĻÉtčŨwĀĀ蘚#ĮĢš€Þ^-[ĩþdōīa#GūT―FŪ;Ïå jÛķý‡OœĸÅëŊ·*QŠdDDÄ'S§ÕŽŽ>jôØ>|šžV.žOĸņÓŋŠëØ9(8”ĀÄfËČüþˆ‘â:uŒë4õģ/Þz띈ˆŠï>yęgíÚu€ząL™ēïūŨ{jüôĄÃFPɖ•“…6ÍĪ)ÓŠT‰čųÎŧo―ÛÛå ˆŠY{ėø§L‹G§LãbkZvĻ<ÚĪ7–äé­ Rč O@ ŊvÕåžF\šLš‚ ’ðYéķ˜ËéŊq-÷UjÃwļl4Øo”—‹„ïŠðc™e–y_aŪHķú؍2Ž&Ļz<Š=øÚŦŊááÎųvöōÅKB‹…āâáEŽþāC*Ļ þlÚÔšuëû`üĄƒ[ūþzïūýGzųRâĖofŦš­Ģ_ŋþģŋ™•t#)šNfŒŽš“SáđŠ?Í_ˆ ãącGįü8oÏÞ݃úũÁÄų,QĒäŧ―Þ-UŠÔƒ‡ĐY8hН;wēsrʇ‡ô~—Žo^ūriîÏ ^}íĩ˗.õîÝũí^―šuŽŦXĄ"ĩÍ[žZĢFß–,yک͗_Íš}ûVff3Œ7vݚUÄja+ #â%mÓ4ņJũåōÍîŸéÞ}%Ņ@9ËFχ,Y DpĐi2m5Þ"=,ĪYs6Ā(iRĪK+›vĻdb?_žl[Ą Þn%{Yf™wzĩA-Ōšäc„ ė„AņF˅—§ėöíÛĄÅB bšü\pƒy øûŽíM58“pę^ï’ûÉĪŅHDqąUŦ6î?čŨįÝáƒMšð‘۝Û ŅĄýûHŒÅû›ĸؐAƒęĮRåÛhÃúõ“'MüëČá6mÚFŨĐ ōĩAšŧ@õ―G2#>^KģÜúž;įŧowÝzõb6ģsøūCûķS?„„nĮļÎ@ŅHävlßnÖĖéq;Ėý~ÎĖéŸ?|ø°Sį.ĻŽ1ÆŪiĪ H.šöXäOutJ}­:›Ī·:’DŪ5v€įŦ=œļšÚRÎģSĮHÜW†Ø5îAļ“hÃ8eŠĮlęëHCgHm…,ģĖója+{JAÉZȧ ŨņðÁó8ø3­nLkqxēm˖+‰‰ŊÄ6`déŌĨ7mŲÎĒ)%0ĨÕō3でĨĨņïóÏWâ~\.FįææĘīšÝïČXNn6ļütâ„ÄÄDÜ[&Âá­V3ęáý”Œôt™Zg“ðÔČîU08 ?UŒ†@ŦčxqŦĒ@ŦÝMÃðėī;ųnðÕē4ĶdEΛ \†:•­š’QdjęÜy öĩš“[f™ŨJƒëžŋ]dXĩ[—ŸGsþýü·n،°VŋĢjGóhO'G4 qũ0SÖJ<ôüŲ3-[ū1|ÄČÄċdýå·[ČÕ aÃâč·Ä!â ũ‡4lÔxŨÎ?ĨíÜđ Ē…0ī\đr}z―-0-–Qz‹*đŊjĘJÂ,Ķíl1ĻwæŸ ûčqT‰ŒlÜĪ)B6{ũė!’ žĐfģ‹°ĀÁš4m6ðý!Gĸú+"2âÜŲsHÛ,Yš|ûÖ-„,ŠoSýFīqÝEŠŨ"í‚ÃČíQóUą4- 6•ūj-ģĖ cĩv)aø?Yę°HãENþ}âøðĄC؏Č9WŊ\ÉÍÉ―|éâÞ=ŧ‰BQ"đŸO™ēaýZ”ž;wífÓž…U+WœJH`ŧ ņį~äðAPĩnõĘCTŊYģZõęÐų“‰č§ðFë6ą ÞŋŸ"•ŊÚxU°ýîcEĻĘûũí=î,Oâ™Y™öĸÉ[Ū^ŧ:fÔH"l‚!Îņ…sgSŸ<á’Ū\đžyB_öÛb‚C‚;uéRąbĨûũï‘Ã{ŸeRR|$ģ4^‘‰Qę sa(xįÆĸĸ'‹*óAģxąĶ%;Ãt[ވ9q„ĩ{n‘'œmú;}#!híĘ`* īÎÍ2Ë,ó6Ŋ–ý-ēöĸ‰Ī qôðĄ„“'ÂÂˑðßÝہA‹]ļāįŸ‚ƒƒ\þŪ]ŧ:|čāōå+ā–Þū•äp O%üúčŅÃŽĖ,fƒz {ŧgũ žüøQ`pÐÖM›öîÞž•‘éŅ€wK˜šúhĖČø€Ū”Āšw턷ōßÝŧÝ:wbŨŠUïßw:áï’ĨJ ÎLÏ`îÔЄŪqƒƒ(ŧ€ĪðzÖĖ‹-䍌þ ģK\{’LĻ”ČÕZ),ũ=I!PŋÕW? Đ­d[SyėģāREīōXŧ*rkT$ž`ÓžŪBõ”9ÉMðŨ:+ĩIķÍēbĩ–YæĨĐũ§<ôĻ™,Žƒ‚ƒAį―ŧw9 C.ōfUAžP6ÐüĨdö~Ę=þ páÆA/âķđ99 †Â ķíėy–ö”<:œģ:=%|LũsŧFðØ5p Ĩųy8ŦRŋĄ…FšŨÔ­aĻķ)c°1“ ĸ-jâF#BCĶx—û*P§ØßéÓ1ūÃĢĖÕt[Ë,ģĖ Qk—_0éĨ pā…i1h‚+į„CBp)’1í}ˏMhC#DŊōT•_œ0KPĨb0œĒ !N Ä6CÔē4mkV >ĢŅčRņ\)-ø_Ŋļi_ņbÅĐ. Ŋð<„ -Q/ķAÍčÚšoVTáųŠÍ_kYŪ\8ÃÏ=Žïs*ž\ŋūŋ++ĄoýčóHč4$$īA“Æ5Ēj1UÃWę7ˆĻ™™“ųY―AĢf\|ÉRĨjŨ‰y%ķaĨ*‘xŽ~þNĪp4jŌīE‹ZŅŅP’ŊroŦUŊÁ␐ņR §ŲÍĢĢQӁ\ Đš9đ9Ä6HJŦXĐēĐS(VēøËõcIo(YšLݗëAðܞ܈ŠUëՏ…þÆŧ%ÎĀõð@аĐeĨs‡ÓKU―,ģĖB­ölĕ/ĶāĘyP6Ųƒ˜›6n=|HßũzQý5hðāĀā’%JÍ_ļhųĘU‹—.›ĸëĒ2eËTŠ1ûŧ9_˘đz݆Åŋ-ýyáÂ2eË/Y€k·wëņÖÖ;.þíũ?vĢō•“?ý˟~þĨlX:-M˜ôËĒÅĶ@–ð&ÕcÆ}ļqËķ…‹–lÞšĄd –-_ý8íilÆ˖ŊĒnĒJ•ČMÛķ/XīhÕÚ 3gÍĶX":&fþ/ ‡ĩįÏ#GYðëĒø/f„„ úzö·SĶ}þíœâg|YŠdé.=zþķ|ÅG'ņÍŅĩ[ĨËWTŪT…K%ũį…‹xãŽ]{ÞhÓ6;#ģ~ÃFæJ6lÞúŅÄO‰cԉĐûÍėïÆŽŋiëö &ģæ^ÖnØÄ˜åŦŨÕĻ…‹—ïŅÜBĘâČãžSy\Hž$ÏE-ģĖB-žæ!]•ėԃ€_ŌŽīŊ„W!EÚÓÔ+—/ōč1cĐûëðĄęÕŦŋøŌKŊkņęŦWĸ―ō,#]ũĻl-ßh=aŌ'ŋoßöŅøqĄÅŠÅ9óüųs$ęķiÛ>,<ŽYóČ#œ;{fÂĪOkÕŪ-Ýv—/íŨĀ›ãøķ ölĖļ˜mŨΝdãRīVĐrĨJõę―r:áŸË—/ՌŠB6!66–0ĮŒGīāęÕđߚ5Ģč;đeãĶ^|Đ[·îxПĮOŊXđōļ1ĢũíÝ;jô˜o―oŲ§Oĸ{ĸÝå~ߌ‹ČCĢ֝—+Sååņ”]ždÉÛ·OŸ>õ“IøÎ›6ÛēiûKovčØóí^Ļ&Ū\ą"íÉ€Íü,T­z5‚§Ôå2ĸŋ—/Ÿ>u ÆŠ‘‘mÛĩ;~먃””˜šuĄ^\\Ü+ŊÔį(Õ%2+ę ÛķõčŌiåōĨŋ-YLp ~ƒ†ïõîK4vÝš5Ö­ã |ŊQģĒbÜxģW_ŦU+ęØŅĢÄRyÔüøņīɓü4ïîÝ;ļŦÄO0>ƒŽqqÕŠ―ćð\đpÂŌ9rļc‡vŽŌĪYs­S§N‡ļÚČŠ‘v‡hJ€YälØšģ“§€UŅgŊ­e–Y…đŠTB–JöņE[_ĶðTâķŋ—ˆŠU  ėÂJ΃E"ķŦWŪÄÝĢ,UŧŨHkE”úhĢ-æ‘ŲT6ĀTŧĒÚ%éýŪ;woĢW[?ķA›ķmü~ʃ*U*ËIO3'EŽûĮï;ÂÜkV­zō7{âä‰W_kÉ{·mÞÜMœļNéééI7ŪãŅk5šI~îâáƒd;JĀzý­ä›åŸŦðčáCʋM….Ŧdd<3Ž—–Ī+QĒxŸþ mïÜąM“Üøâؒ―v­‚šeVAŧ%JY4į.Äčæ"u_Á,lā Ál‚EGŨYļpÁgS'óˆ―`þž›IIģįĖŲžcĮæm;Úķ}ӝ“ƒGŠéú­[Ų/ĒušU+ĩNŨ†4Á‘þé§æÍ[ėÚ·Ԙą‡Þķy#ĮÔë„kîۛ‘‘ᜒšjųē―{ũŌÝķ㏍ۄ•ÄLϝ={ęÔ?€ėäņã—.^|šš:ũŧoŅH\ķr5ÛSë6nĐQģĶøŒŌ ÁÁŋYŲY{wïÆ…û{vï ~rĸāŸēÎí[·n&']LLÄCONū ~ōãPÁhH#tnÞļņýœoä]ąjÍæmŋŊZģŽĪĶāfĨŽĖí^·fMBBÂĮ&nÜšuӖm=ßz§r•ˆ ' >œė…"-“"9 ęōk™eÞh–ˆĒ°‰§}Đ °3V{wû +15_ĮĶÜŋ‡X8Š_DN;Į―ųękŊãå%ü}âŸŋOÐ$bp)ņžđßWŊupĸ>dĀBKoŲŽifFšŸËFüg{výAŽTrRŌ‘ƒk@p›IóÜũîÝã%_?_ ĖQD‘šúxøā-Zžųâ‹wnß:zäÝ€į‡cĮÎ*=ý^JŠé(ģoϞ6ŊŋJg3ģN;zîÜ ÛēEū ŠųåĐéÂ.\Ā'>+­gė~ŨŪ=vôHZj5 Ŧ—/Û·{^-8vųŧ† `JŠyĩgŨN$Ĩ‡†ŽZš,áïŋÉãÆ‰f$ßL‚Î-š6ßAÁ!ėwĨĪÜëûÞ;›4‹ˆŒžvõߓĮĨ>I5b8^0Ž1—! ķZ‚ÁĒÜ2Ë,óū. €GKēë}Ä$VÛg…ûR’ÂYú2ÕY2ā@‘pýš5 Vâå1Üs:‘:<~ô(!ęPsēē/]N”đ"ėíųûä €ĻqOĄy߃Úīn]­ZõoŋųšX­ Y[íaŪĒBą[ķl€N6L[Ïšüý‘ {p?…Į{R_eéüžëŨŊ'ÝļĀða%žë(LžČä͟ÂĮ“&7kÞÏwíę•;pŋõYÆģ‡grI?}šF`—ÐA@`%7o$ņ..Ú^ŋv.†ótKŧréĄĢųÍŌ‰/ē 30Ä]Ëemßš™ePč(įÖĄ–Ņœe.bý n™e–y_‚éķÍd1ĮŠVåĢĨY6ÕöÖÎ-v_—nIĶ,į!.ÃÁþ iüĮŧ|å2įÁŠĀf3ŋSHkžŧ5ŋŽf”ĀNþd"MŒf#“H–ũ".Ō^ęębRkWc fƒ_Ã_`Į1#ļ ŧJÝØ4A˜WéęøôéÓŅ#†­^ąÂnÎē.kÃ|øqŲ3đ’ÔUĖŽsÆĩũŠé1d:įRğqï^kW @ĸøßĸB“īį™ E–’ÍîęnĀëĩþÝn?Ý1Q§€ pܙcĶo•WÕĖ0”™įI0"óšÞ6ö~QŠëZũ›Ũ؁øw_í9­Čx>˜ŨûĐýÚÕM‘&ĐęŠÐŸ2°ccŊ]]U•ŠčjŌžÏāĩķížzŌŨ ŒįƒSķ =å^3BÕþD>|ĶZ{årûĨé&ĩŨŽPyŠ;(‰Ý #°kjŊõšĢ€'ލï”Ā“ęésAR5c[3Su@Žý:ՙņ{—ĖSƒbÄĘq‹sf ؎LŒIH č?kp#âýþۚĨy―ŊqŦS)eĪČr7Áˆī!JŌ^Ëöó―l?e„ÆļŪKŠ―wψˆĩvu[Ėĩ(uOÄ―Qįx°rl ‰ŨÞíߎ•$ž`Ïô >|øðï@°gĶ„—B336áĨžÎôLP™ųŒ~`€ėnBz\įhEŪ]u0XkQčšŪÉ;Í<}ĶŌ3Ý+Ö3uîĖHu ČĖč7H Žói ĪSĮãĖÆé™ĐQu23"<ŪŠH†~ËWŌʀâœË5ŋƒ]ûžOیŒéEUˆ13VˆŌĢÅČĸû䂚áû… V=Š€Tį„BOšB"§ šy]—Įk/’ū·ˆ>üļf/cl…ĶÛĀãŊęŌÞŦ§<}?M`jB9žņÄĘPØîąBšoĨ†T_ ûTį^đōŠ v†Ī8UÝĩ֚iŸ0tÆĀ3{†{ÚĻ.€žüĖķ0fæölHŋWæoāےĄX{čjQĄĀĖ“–D„mØÓ "(O‘]MŌFFœ*Ðt{Ö"Ü€™~â㕆įŧ(@fļŪ Fďė@øðás0·šV.‚cȈéŪëØ~­]Ýu:$ð^EZ+O]ÝóϰŧŦîČū‰ J6 fŪũLD„tŪ#Ũ"xŪ ĀĘMŌ7ß1+7ðĖ•]=ãžGÓ§‚vï-҆Ēš[Ôoș! ØÝmxŊuÛ œsŲ^kïýš™Ū’äņĐ#RŌVāĖĻ.Ī2îÛū7@Á°įšŪ§įwf`XkũLUŊĩ`œ*Ñiû3Õ~øð#ģÚXÕ]S ffwßv[’NŨÔė―#Ēęx&#æOū ĢęĀQĄš!CŌĖ|Ŧ§ŦęHا€‘RũĘé~―g+ŧk0Z åĐS50Ÿŧē@äJŨõ†ųÚŊsÝ6œĘPU=J É Į4šęT}ĸŅ7­ÉïÚoáņœšf&˜Ū.’‘ B!‚Rtĩ)žN|Å"0öĐ9œöz­H{l(BÁũû‹Ō#ßvxí_uĘãÏTûųðÉjŲhÄļ΅!čXAģ{"eāëýÁķĮbŪžÞD‰ë\o›’bEOƒ č6Ɍtî|6’ÞŨąky0€Ļ˘%%ģŦ0ØđsEÄZAčq.ƒ§īSqÝÁîÎeļg@ĪXŨÂîXąÞį #‚"ŠJRF(㜋|ōCŠÄÞë\‡ž§Įvf–kÆ ­øîBĢ-eÕéš·! ö9 VdO1@âǟĮGĩÄôH~åëïë‹DŪ°<5ŸqõéļԊ:Áˆ`Æõu™ū“œsęôũ??Á6ũë5=SĢÔRž>cŽ•3ãAđ’ĄPWSĖĖS€wjqßąāĖMÂîĩTՙ:ūeÝÓSÎ@ïëĖôüÚÕļĸmŧsŒ §Ēę %CŨûOŽŠ.ZĘpÎ jeūïī„PDâǟČįī ­ũđ„B Ã)\įPZkŧėééïtŠ ÜąfŨÞŊČĻŪ[ÜęÐCŲ]ķaUuQž/hƒĒ2ģ§Š[ÄÎuęT·D’ƒ!ĩý2Ð]GDĮĘŠëÏšŨđ(ĶRāĐóœ,˜ ä^3 ’!ïšxōY ŋđ­m’”`ÃΕÆĢÎ;{­é: ė―Ï9=–ĪŒŪ ŒˆļÎĐnÓ3mB nÛw&ƒÁ‡?‘OVŧ–ģėŠîņ0 ÛđÆXŠ\qęĖxŊĨÔé‹ÔÚ[ÁóūFFMÁÄ 2ë o—Đ10DEÆī3ēÎy^äĘũõ5í (^uD:E2_ËīDcvîۚ1L)Ú-ĮoĪs›83oéMsįܗfÄmöjiÍļ§ðû(ÚôĘėęšĘŒTœëð>LpæZũïh‘°Ŋë=Ó{%ɚû˜ōú%°kîëcŠ įJ=E>ü@>SmŧŦ ŠiŸ)ÛĒšŦÞėPœŊŊŪ†ķ{jÚ=Ó§afš#‚Ķ= !žšúŧ`UõĐÓ}]§§VFđ +§Ú6%=[&ėŠ+’™kzÜ 0cõŒB{­PT>ĩũę:W‚{­šHA.Ý2"Ū>ŨuØđ1xí‘§ĘÚâ3)ãþTŋÏĄÏ―ąsŨ9ÅĢ{š/ƒé)ŠTô”Éû zšŧ >|øi|nöšk‡a)Æ3ŒH-##3rEUëŽ\+“ķ‚ }ú@ŠL“€Į&YSӝ™Ņ=Jf&! 62–iũP‘‘Ý53ĄĖŒs>đ~ތØ3ÝՆénÝCbÐ4ïÕ`(ŋÖîéŠötÆ:3c„’`Uæo „(cŒy&âŠ@j­}NŲEĒΈ˜žžÁŒLÁxūāu―Į“ą`ŧ‡ …ėéÓBáAK™†ņáǟ „"ssHŠaŧš”ąrŧú€ųū.ØOŠÚžĪ€ŅÓDDuU]ķũÚ3ãÓb:uUUD†â}Þu:3ÉoßdčœŦŠũĘýÚķAfĘÆķ‚Šž2,iĶđrU@Ĩ \ïũôÕ}_ąöŪ)īį^|ø‘S-Ĩ™‰Ėé>Ũą_ŧ{HDæZŦšj*2"8öØŧb˜nOߒŲÕRëÏ-Ĩ zšŠöÞcOOˆĪzšũ eīŸáQ’Ķ&eą2ŠJðZ;Ÿũgö^ũæ==:=ĢŨđ$ŽG”ŧ=“+[ОŒīŌÎĩö~ōYĨ"ÖUÕ5ĘÄLO…""§Û0­Ėõ}Ä#2Õ5ã•+(đR) įš ïŨŦg"•‘zš!ÛøðáÃOėŦÅ|ø™Í^A|lLōqkdˆŽSOîЈį˜FLUÍØ+OŒIūöŦšIØōœ ãÜŧК•+Ȉûb’ņ Ĩ”’|ŋߑŌÜå=xžëęi1<0 €Īís]RäZŧ!DDÏwíËãVJ‘1vWIz­ÝÝ#7{ŠwŪ䒐™Iōôa@Œƒčî˜.‘‚Yu)#!۞!%ĒŦ \Ŋė)ī Ԍ"hМüĸāðáÇĸðÆöj ^ŨõþųwwŊ•WÁ–b:{ŠŧoSEww5%…þœgÍŪ:՘ačïŊ/AāüóؖÔÓïs<ÓåĐ+"CųžŪ*Qk­ŊũÄŲ3”úŠýÚ_ó5ÝaāÏR#’āp’qČžéŠ―öŨ{šāĘøëŊŋž| 2ž`!"üåîÆý{ðũųŨ― 9ÝÕ-).=swfÎíôņÄ―iũ„Đëý~zyæï限@JŠjk­žĐsĻXkýë_ČĖ\}0Þđ þã_ïį ĸķĸųÏŋþý(ÉîÆ‡þ{‘ĸöÉŊ_ŋþkT{ŠþĮĸü_į\ŊŨŸIQį\$…ĒĶ`(FՉ‚€Į3öĘÕÓ6DDŽđ5úˆ=MÄŒŋó„Ėî!l;Ũî>üvEPð}ąâi$€@pš)yühTĒ Ûøž§3üėÝ{pUEžð_Ÿsî+7ÉMHHx%A ‰PdģrEeœYĩ%%3AÃD&š€( B”Pwp(u@FGgYGy y 0ˆaț<ČûqįŅÝŋMÎõjÉ!dw­―KúS•ŠpnŸNũ?ßj~}ÏiYîÎ>{ũÛŽY∜3 Rf’lۚŅ?ãÝ)Ié—dÎYð01Ī”rä]žâtaÉŽKÁˆÁĻL$D –8‚7RNcð!\n–ž ˜=#ũuvŽ›jôƜŽŽ:ūĪĐĐA%Œą1cFõuaKš››á*ˆčrđĖMs$Á+ÁÖðčņ:\ÕĀâwKØÛ_éKÏÖ―Y\'}đúÚģՍ„šĄŠ+ķ݇ę*2"‚RJ™a}Z!ô`§Ž }ÞDiA~dĸũQ+‚ ĒVAQ+‚ ĒVAP@!Đ~Óš?}Ģ€ B(áˆÁģ!I؂ŊÔ""jûA|Įo€ĄR†Í~^ßÉÚœsAć+ņ’ÛNšˆĻ―ņ BðeLUUU---šŪ‡þhÝnũ Aƒâãã !V9{撷ĪÎŨĄ!B(ēI8ÄcKMô ą›i+ĒöF'œóōōrY–'NœčņxBīĩĩĩ%%%ē,wĨíÕŦVŋĨęũÕm‘îۆG9íö; ąĩÓ_^Ûü·Ęv—=&)šØd‚7öƒđ‚ hšvęÔĐôôt‡ÃĸO”™&L˜@)ý/[aÕ­ėÐŎ–N-=uØčĄnëz(!ņŠß-ϚBø_ÐĄō}gÎV4MN8~˜#ĖN8ÞÐŦZA(ĨŒąëÉYÔ:+kęuJܑ1ąąQ…€%Ôý€ŠrÉ!CŊð‘bï1ã=pbbbNŸ>Ýãž †~ŧÂ\Ü6K H5ÕlfþÃðûĻ;ÜŨ€Þߜ<öî!áüI„ ˆtSlQ dØ?ķÅA@Äko4BŠþšú…域maoۃ…›ĸ5+c4 öܚ·mZąlũđ·ÍÛO—,šwsŽûšýÓÏ_~ū8sˎDŲŽ―ūZ›áh9%BHÉÞũŨïõ<;Čôō,Î=œûÖōá.@Ŧ?hÔŊ]üėė­I Gžōðķ6éķČh·ŪāÜĒŠqÃG­ ˆĻĩ~…ā™ý‡Ï9OÜ/%DRóíÏG$‚œq„n’Ž0ĸÁcû<ũ-]˜Ķ͟ĸëč”q+~1ŅlÉ9ãĪn€Ýˆ$3g’”$ƒÉėéš9ÛûÛî‘3BEn­Đû\uģ;öÞŨ7,ŋ=!üōÅĢ…Ųmė6*mýoŨKļlcmį^]ūÖ9}ŅâG:ģŠZÎyŊÏpä”R„Č "YF)c c KŠb“Oní“2Ķ֞8xøōƒ‹ō—<1]áÍۊō‹>ývÜÃķú§IJG顂…G.úâRĶ­^›oŋðŲ{[ķ7Ļ9ģũéuŦŌw―ķþO‡M/ĖÏūu€ƒsė1j)ãØWĩ‚ p“Õ‡^ŊŨ3$.9ÁCUUgȑHŠZū8k)Üŧ`ۚĐoæÎË\ý—·šes"Ëû·ĸ~ÁÖó•ŽĐ…ãĩķŌĖE7'ōžĮf}ôosF΍Yą óâČđïž>GVá\íŽ;^UôŦWũ·dünÕH]5ðŋ[=BŽÜb‹#1ĢŽ™­Aj­8ēņƒō§^~síäCÏį=|įĐG^ycį…5ïžo?ĸáą}ß0Æ ÉņOÏž™;˜Í{xÖĮû\œ~ũ”;RxÆã9OL>š9?o‡ĸÚķsî#ˊRþðō?KœÃÕ >\ý%jA&—ŪëšĶAO$™ãÓUU— Y1ķŪYisî))ũ Z9į§ņņ>ųĀ—O_h™wŧ‡0ÂŪsÆÃ#boŸšQšgßGŸnZÜWŸm9ų]CuMį}ZccååC߆eŋ:ol‚ŧSC(Ûs3#’øpëģ‰ĶjüĶ”öZ 5ĻĄi-ĶĪéÔF8§šĶ1ĩë‡QUW~6ņąœ•MF:tĖo>=uņb랓|ėüŧ’‡*É?ŋ덝†#\ßþfÍ{U›‘ęŨėŅĢÂm‰IIC];ū8YSãÍ]° öoÕ°2ŊĶ99ÞVĩš†ôĘↈZAŦZŨTSýéáģKfŽu:IÍŅŊ―žIÝcũw64ķÉr|S}ÏĶØ 2Žœð.ŒēīéÓģþåŪÚ/>yïÏ{•ĸýÐåØümË+GB{˜SöVÖÖŅÔ[™áïnm8§ĖœÓúÍķßtϋófÉ<Þ Vw#=0Ļ-nHlģïčåvýց1—JNŒ!‘vŽBpø}^ _{‡fĪļlšÄlz‡Æą―ĒŽŅŊ:ęÖe9ÛøÄÍK§oČ*QPnø4#œ2Bd—[I5qIÎ\OļÃéō(Ô°Ļ€įØúHAn\ˆ<.eúoģî|7ïŲŅë6nØôÕđ:bģG MņžÍE+‹ÖŊĘ}ŦxÄsnА9Ã5]ÝóÁÆeŲ ĸ\Ņ9óÞīpÐÛĘŋÛĸŧåßŨœØĻYđ5ë—Đž–ŋzݚ76ý―AĢ~5ę'™Ŋį-8öÖS+ÞýĢNl §?úî ôë•/åmÞX”ŋáŦ·'Æ*’-L:ķåíĩŦ‹ _xū1qüĖq#§ĖšÄvŊqÕ+Ï―tžŽ@ ģ7T~ĸåį_–{[‹ė*mƒ„a1o}įÃÏNßŋčĐáރŋûxρŋėÜąĸ %z'Vĩ‚ПX@Ųõā3›†ŲuølYC3ųYvÁÝSGkčÎÎ[—ē{Oe}ĮãK_ŧĸÞq22$ŦÄóÜōŨË*ętŠ+Ũ=9ib*ķ&bôþî\ķýý3'j(%ģžy32yWim‹cØðØŨīų…iąžáÉŲoŋ—öm­ĘšĮCŪwĻ=īËfœöØ1ŊlüdŨîƒõMí“2_z(cē‚œŠ|ÄŽô›b”ķ?+Z6+Éar6D9xæōČĨ+õy‡F…EĸšėÞës^UôÎwßWzdNNsŨŨ,ā‹―cö†‰;ũŅđ2,1^6g`12ļjn"jA)ˆœr)mÆėq3dY6tÕ ļbfĸ|.š 4Mㄜ“ïŧŠ,™đF5UÃč›Í)™'ÅþdčŠÎPšņðã@PÕ@܄ ‰iŠ_ŋiüôwĒPą/CĩHd‹<#€œ HL›—5Ž#(5ݰŅ- ĸdÖ#„sÚ=A†`›þXÚ?"2NdÉP<"ų‰ų)ˆĀ9w§dhîIÉüåÎ M Ä%ĸÕĻ „0ÝŊV_ö Ķ­Iœ˜+ýƒŠŠĮŸ2eŠÍfcŒ!âõäąŲėʋˆx]iŽ$ØšđŸ|;Ŋ RŸÏ=įw–ûŧįHrŧ݋‹‹ĸ>ūüōKÚc:‘~D&Ŋūú C)øxĶÎīÕūÂSŌ‡fþ_Ÿ'Ý=öĘۜô&ŊRZŦ•šŌüN{<-}Ð~fõŸVøøÉóÏ?ĸâ‹/>ũÜs_/ãņãĮä$@ŋ%ôÍ7ߐ= €ĖÅ‚ö ,Õčâ8 ÂLĶņčŅ#ëĻ”aķąøSŅĢ?„>€Ģ>–ē6–ūŦŨ‡vŌē Į^tÚčƒßAŋ‚™ĸúØG‚}MýøÃéxÆõŸÖ—^zé…^HÓuýÁƒðÓŧīī'ãņøĀRð—xH O3‰ --z 6ÅtK5ÂÁfáiSG5―ˆ ŽúXĒ6úÐőđRČ2Ī―>ēe Bx–õĸjôąŸ*u}Ė)–aÉJqZÚXýþ žLaõú ‘Š&ÏŽ>ˆUęCšŪ§-,,ĖÍÍÍąxÜÐu‘ãŊ‡g5ÅbĀ„œx‰Į0 Q:§Ķi$jvtå6ĀøBĢĻ ŒDĒp"Ísk⁎čĮŲ,|K s_‚e$Ļ­æĒLzH$`ôYX\zļô`‘Īš_|ÏA}–ëĖĀĸ?ęƒYŒĸW}Åþ%‡KņØ­VKþ+ŧHN b,›š>ôš!bÐ!ģ0qðca"ļ–&ĸÏ1!BH+|qČ2,Ú˃v|īŒĨš?õA'ųĐëƒÎÔõA'ÔZZô™{}Rŋ_pŪF8Ÿ@āÐú`q‹>ˆ4= Č$ų„ōxÚŽĸõÆÃŊþüčëŋj*+$4Įõôôīķķ655ĩīī|ôŅGn·›”œÃëŸ=Ņ|8kĸ›oWŋ–Q·ņāĐJĮÄp"27Ŋ/ņ>" =MÓčt>Ēa)Ž XēEÂ2˜}ČBĀĘėHÖÝÜŨNŸYq9î;§<Š>—tœ{rØ1-ƒeŌ i?2îŠĻ:=6DaIh}Ā/ąÞI—_KVĢ5_ޜ…˜.ßëíėčžzŦŸ•Ø|‚ãÁ_dU‰ð#ƒƒũî}60<&EÁoýâP ēĖú`S‹>–ą“}õāŒÓ ÃâÓûƒ|, †"ņΑĄþþ{}ƒ žš HxL―}íōĩÁÍ vƒZTrU“·@ũOŽŧ|žNū#ÅīßúF€ũ™Đčƒ2æÚčCŊÚī>Đß/œ“æÐúāi!✨•ô#E}0—š<>iŠĒD“PUUI"ār}Õõ›uRÓЇÓĢZgÛÝ­›Žo|}ĒŋēdY&|Ļg0lkkëîîęrwûöíæææééi(Ej-a+ŠË3ģŧ>§Ēië` “yĮøÞWē2ũū9ėŌT 'šĀiöĻËĀGtœipĒaq"°Úh ŸŽD`ŅĮ\Į\ŲRßœvú(\ÃïŨmČŠv̰ j`QÆo3ęf•yCSðÉĄŒŠÏ‡'>ÉzũČ#ÁŨ„âЀ„āāŸđũųĪŽ€W?€47b ã]M9u­ŒĪāQPÍÐDÏņ}Eéé;ęÏ4îJOÏ*?80™ÓdGßļOœ3429ŒtÜ)ßē!·ŽzOUYõŅSnV1t ûEáíĒōīcðþļG7ôeņß߇$ÆFĢIýuc^mŊÎŦþðþ)Ū'A’NŠéŧÃ5 ŽÜĖܔžWūgOeiÝévŸ úō‘á ! aëņ˜ÜPđskŊŽ@ ã‘Iŋ+˜x!Ęų&û‡'Dň/Čgũ–üáōPŦÂĄ$°žKÉïĩŌþŊOŊIïTĀÕĩŋ_–{Ar +Óũ wa™ū2XŸū_ĨîŨFðĪE"I’ä$ĀŨ''.žüģŋŠýwĮ…^―üŊ΋_ŸŽŋĩæÕķŌRį#I!nÝšÕÞÞÎ0 þę‹ĒĸÉíęęË&[DÏ]nÜ^ŋæŪôũE_ðoýė}# m…-Ÿ­>ē yčA?9ĄZd`;bc LE$Āēæⷈ€-ú` Ö5†” @“Íú`/l‡ŽcĢ,2§wŪųéËéíwĶī……ĢgóÚWÞÜvĀ#ëaÖïtŒŽ:Æýސxĩ073!ƒgƒ!6äŸsNøBžfĻCįOo);106Åpb˜ Œ9 +Ā °.áPĀ Ir4Ė…–ųfɂd<V7”Ą?ŸYĸË-7&…ÅÅE-pŋ`íúŠú>äŠÛ‘YÓþYŌ‰ÚŠę­Ė/ ęą9CՐ'āóē;3éœtyÑĻĖ{ÎÖūSXsÜéaā{H|Ā9:<>=+@ŦˆÄ2– ÍLONûB\0ÝÎąąÉNn„ øƒÁ k|ŌāyŋĮĮ†Z‰œkÂ9::ęe€%Ŧ҈gj|Ä1Î,Edy0ĸ@wîî#Ìū0gĀ]füž'‚ÏĮžŽ †|nÐŌ9åæEy~>rzoq}Û YUü^? ŪhTųƒ!>ô:ԉ ÖTąįŌ‰‚ƒãþ°a<ģA–‹DYf&ĮGF>F„ _ Äóė„sl ū‘ąßú:9Đïú ŸŽšÛ°Þ/KYz‡ŅCß/:7…ûøŅč‡Ó`DøCÎ$Đ#ë]ŨkŊ<ÚđõÛĘĒėŦüķšäqnFtÃkíëŨú].Q’ŸĪtvvöõõy<†a8Ž …B^ŊwddäŌĨK~ŋŸ”!‘ũ~_ÓŧåJhŊÔp[9{CnėdßŦÚYÔļÅëó+C NEyžGNK31d~„7Į1č"Â2cÎ2§˜›N…ß+‚DéjæÁ°,9iÃFõ)|kíš Å ’&_oy[úÛģũÍĘŅŧ JƊr2ŠëšƒĒý$ŊüØ4q^ŋPZ\\ĩŧ8cûæâÚæ€ß}nÎ/Öm-Ŧ:ðГék? Y…‰ŽsLDqt7—;†ģ§ĩīĪ„d՞óó •ĪˆŽIÞæc9'ŊɊ EQŊޚ_{ģŧuÓúoïČmlŋŇ"Āú{ŠōŠn8ƒĄ@€ ņë>[™YX―·0?sË͌ ―SÂLïķŨŨl|csU}ŧÏ3ÕrĪ&ŋĻ`WÎŪó=C҈ÐqŠŠ xw~aé™OGŪÔïݕS‘“óÖ[;öļ&éáķ#ĩđY™9;ĘšnŽ}ü~å{W†YļvîøöĖÂōĒü–ÞAXýÏŪ5æäįV>ï‰IDĒQÏ―îÜēC7'‚L H|ĮŅüšÆŦQUáž#5ųŨ‡Į>Ž?PZZôÎķĖc—û5]:YWräâ %â=TđįâõŅĻĄÝýSmų‰ËĒînn(-,ĘÎĖØÝÐåõOĘÞžnÓķ‚ŠFW˜k9XvĒýN8Ė}üĮšßeï*ĖÍ+ĐûÜũAP!3|Ī”c–+-ĮrtMĶeÆÃ^‚hĪ„”2kLÉdzøšŌSŅÄAáäáĢÆĶ0'ČghĘëÞ{ÞgÏŲĩŨYw•Ë5ÉŋþŧũũýûÛĸųũ>W\Þđ>ŽŌg’$)ÄTÕävEY-Y6rĮÎŽˆáŋ~ē  UUĨ†aõz―îgƒ8 ž,Ë?§ôā‘^0ĻŋބtF™Õ+ðGgBAĄF #J‚(I@‘ú ­*Œ1x2 ^E’–ˆ!ÁƒĪÖh:E)ÔĻT‚§íf‰Qm0EņÔ(…HĨ‰fí.|ëĢÉ@ÚČp‡úĀ6‡Ÿ6ÅõÏ3ím_ŸĸîĘģgZ°,ĘũŒ›š_°2#éąÎ/ëūïäÄ)―–0Žy―Cũl֚ėũ· WԀļccĮN^”•>j 1âÁ)/­Z™‘8ąó|ýå.AeR‘ŽĘĀĸ\öj`]lžÔåQA hS°ŠŒŋ Ņó}:Ņcpū—3G?46:b|Ō’yOÞŊĘ"ŅĖč LWûgŧ‹‹Þý úĖh›ŪÎ.Éõęå­|RÚŌiŠ;Yq[dŨMė?dQãđÎ6bÁĘÂ5iÛ}sÝ-ÉūxÝŌņq=].NfXÆõEÓW†!–åŊšú@Œpû_ĮŽœŒyü™ÜôxwkmKëc L”TN―zîāŪâĒũķŸi퉛8Ūí|m{·rõËŠ!fhtøÃOÏ}iuÁs#ú_øķ—†eYhNXRvc$Š*V8†AÄÃ'LÏ+(ȜýÄ­ķooãþMŸ|ĸ˜I‹—Í 3â^Ų[Č­§6õ&.Zū~ÃKCPہēÓĀ—~üÎþāšõkÆ ā— ’ĒŌþ€ķߝû‡xmįÓķ!þϗĪ1š<ÓütiÚĨڏÚâsjĻNXQ  i‰§īĘi@$Ņ…þãúøTöÝŨ`w_V "Ã͈!  „b† aÃŅ―ą(:þ‹·xŸ€ę$åĢtŸúøÆš^$xES­<ˆIrŸ~ĒëŌ'ęŦPÓĘŋ^I– ;24.ŌÖ]VęčÅĄũFõc ų$Ūõ\UŅĶ·ö|~Zô302@Uļ€ yäŅ·Áyöģčž—IoÂ"d–ļ įNn~Ó˒ŒFTŒ Œũ(óĀzÄ˒“E§Š<Ī"Žtvó*hô Æ=7@~&ŌÆ2įæÉFDAxN24Ņž“—›5iĖ OŊ[g ņČCþXbÍ―N™ŒÕ€°ÂyÜYōp%{·Ÿ<Ý9˜Ux‰ĩčb‘].ÎĢ0‘ąąþHíŠnt{xĖDnadž0bAĒ›·Îœ73ärUᆭ'Î}ßÝu‹sđūq–nß[К#šŸ:! #”Ļ=ŨÔČĒ4›ïųú/ęĢ]‹Ūĸy}čĩĀŌwY ~,q\ čĮ…FCcҰ‘pÕʑ1—,6ÃĻ8―ÉDhô]_iĄcL&“EcžN§ĢŊ’9*8VüQõ“ý‚ýú››Bތ™ï"lũęIH•@@đ$ žč8}óøh#\ŠĐ 6'ÅÃ,ņ49Ņ@ëCŸ“‹V–|Ô*§–åÓú MNdÐ$„rįúíôP„­Đņž_ä˜`―ˆYî―\Ví|äų”īg&ę‘Ę0ŠĒē:Ø*ƒtŠāöxDIF0`Tîæ-·„…ÎöãŽúGÓԟāaĀŌŦBË%ˆ$€đ>mЄޑQũ]h9õÕĨ[HĮš:ÚęÏGņŨ)ĒĀõÜļ-bLęCķˆXVÆÞŦŪ]QVtˆņjáŊ,†"•nARü –P[D|ڋ…ŊĶÆĸ^/q Eðš“dÚėĮkŨ{8Ïå {Ýýî ĩ@Ėŧ8^„ÂxEC]Ä^5hØōõk'…KGĘ[ –␰QÍ\ąjõŦŊdŒŽēI"ųž%z…éYI‘DĖĢbÃØ #KöžåÂ~7ā›úēšģ|rÎ OŒŒNe°ŠĶ õë―~ĢģûZ{˅Ŧ{Ū}}žžuÂŽŽ”§G"'1*ÉÅyß2PxĖē˜AFK`0ūÞqŧKōÜ:ĸÝ5[LĪË Uįvqœ ˆa(ļĶĀß}ĸP˜–rįóEķ=ÅÓóEĖ'mZ*•hð9ÚŊ‡t]J!ĶĨøl‚ĐQ…wŪųĩúĀėĸŧ>0‡ĢĶĶĶķÏęęęĀ;kjJ7o:đ2ĸâŪ7ý~ßĮÎWÖ^·ĶķĒĒÖé<Ā(ÅétÂĸ9ŦŽŽ„ëččhkkƒYøí-Œ"!ĻvT}ðéĶĒýđG›6ŸšļũøŲmÅ%Ëķ|ļšēŠōü„ĐŪvôeŅ$4 St‚‡€îBŧĢŧ1Č@=°ÄÐEÉļÏÚ=ú(ņIîĢßgGd-R[­-ا>^ ÚúT•f.(üøÄGÉû;wv4Wþ­895ŋēĄú•%s“æÍ]’žôĖė܂·+Žî°/|ųXuCɟ7ĶæĸĐĒŪŲqdĮ„…Ÿ”ÕÔߗüü,{îĘýeĮŨ/™;gþžÜœEI3ŸÏ[ŧußŧoĪl:álvðƒä„„”īt{röûûŨô=OŊ°ŧėģžJ秃°äī5ûVՕ—ĪÎx|EņþS§škJÞOIˆŸoÏĘÎLž˜üúG‡7.ÏZũöæoäÏ~nVjf֒ é…ï9ŦJó-ˆOīgf,ž•ŸĩqOŲĄísf§æü―ŪvC^æšwö467ė~3gނųéöyiKW–:ę+>ÉHYąûÓ--uë_Č(ÜöŅŋÉ9—Þ8Š ûŸFaÖbÃKQ„D FQ@@ žxē!Û=ý˜îÛÏ lČïásŽ8ę\ÝāąeĪĢru=NÕ=],y3AmzlxâÍIï:ą?JKWÅũË•8Š„ ‡Ūø™ióSc߆ŠĻÛgÛĐkĘ|Óö]ŋ)Ŧūŧaęš2g‡0‡<[ŨuÆVo·”n‘Ķ,Öėû8ôlPčĮĄ eQ…š§–NuĶĐ/rršaœÂĶ4?Ž:?yšú‰ßļq󭛷övÛgmST%SŠëačCh ĐĘÍ8 mÛeĶ!r떌zA[=n§ĶĒKÞ6Œwžš~BS|ðÎÛï~ų]Å júięčŅ„~ęę<'―hŧŪmëžĻŧÐ`5Ý4š@ÆØ‡ģģģjÓÔĨ_}Á`BÓ4uÓÆĀÃlãvĪ03%žmÍÁ7MÛöc[qĶūgØ žÆķä€ãųí°íB ;MÛ ]€ĻŠ(1Įn6t՜Ŧ((ŠKšõļĐÖyB?ī•^đ.’ÜMŪýÁˆöGķE%N#Įw߀ųQŅų―p4jAŽ†•$yŋ”ĖąS]’ũk6įŪü*âGr)~ÐWāgģžžÎõđ‘eý0ðÝūu†žķ[ē=99ÁH™ēŲ3þĘvþm’§‰dBšCUhūj“Ŋóq•üüŊįã8Š_„(Z%2ÐÂGÔÝ!ÛÎŅ`óvž3*Ô`äŲÉÖóy’Úåö$ųAÜbč1\&t’ĩ˜óƒDü(G7Á}ĪĄß2·sÎ#Q­Ûrrz†ÁĘPO•ÐÅZ?ÕWxf€.eY ÓŽÕƒûũĸķĘÖ9Ÿ|ÍųAŋÄafĒs­b"@IÐâĒt(rŅô‹[}zïAV”ļqzm|v†—PŒ=ã0ã€øýŽ0ĢĨRÐފĐtÁ@ó‚Í頗"OæŧĘžú#Ál.āyv&‚!ó$3?ģý‰–Įû̐ĩ įûã*EĢýđð~I\þä>{ß(Ũ;Åðō[ôáÍþč~ÍOgūV~ĻڑŸ=šó€>::â—S~3ʼnĄŲ8åA#8Uˆ%c åwq ‚Ąö‚ūÆĀF3ŽĘUâÖʔmmƒh4ę\"pĄđÄøŠFüøDŧðc(―‰$?ÎAËo~h}!?ĶWöDgߝœļdŧĢÓüČ/Øģ<ô}™âJō#&güPüD'šýhu\–›Pfj-~”œäg>^ďÓ"›ĻĩųSWī :Tô"ü*ÍOz.Ϗ’#~Œ0ߟ$?WæG’ägšv~|4CY •æĮhi~Ūļ? ėÂē·\.‹ÅĢÅ#>ČãåcŒƒ‡ØČ!ĸ,Î5žÅÁâððpyļÄ#Í%„ð†ĄGņCNÚá‘}ppĀĢr@āƒ-LBØĩhP‰‘UˆA…•ĀÔ`šĘ38Á€ˆhĘ̜$?īāQIďA  ų:û…üŋųņ<æGĄáäGd~H0?T]†9_âG⿇|l04Āåøá•€=ã'ãÔŨĐįüČ/[ü(AŨØÂŒ˜ž=&ũG čh4ÞŦøÁˆøÁŽßÝl$?$ĖųQ‰“q"ZïŦņÚüyƏ{Y~dč"ėÎÆü]œæy?č―oþ‘ŧ/c_Æ\"O2ôõ áQ‚-ŋĢŌÉĮ(?r 6rjÔ]ĶJ&ÜđsĮŅ]äÚųÁóFņcĻČócÏõņ#{î<ũßĩsW~°wáĮNC―üáUüäuņƒüĮüüÍNÂ@ûÖŋՎėˆāšp‰ˆä°,ģ €Ė+T  ZÕ ZÕÐáW՗―âúũ=Óvv°"11ą›Ø’XA“ąíRkŽhÄX X  4vP@šE@PƒŠŌĨ—]ʖ)įŲÕHŒũÝþũūũîKüáēĖĖŊŸïųÍ)óqDb‰˜áØŋȏcøïĄũé'ÄRC##Đ˜ÆąwæÃÂþĸ‹ Į‰ĸ—~cΈ–ˆEĸeāĸïÅņ?šÔū'LGoĸk’PS}1ð€äŚfHāØĸF?š†>L[Ӌ— -č™ßgýß'œ Z+;ęš`šÍâm"^*Ųö]ZWŠ0•ēĐŠēēŪNÉaí*öZĮþDĸyØĸä@õËē’Ēē—*þŧúą·čŊ‰ręŽøPŸ—kZXtôW ãzΆiFo+ŊQp{_jĸŲĢ"Øžføā13Ŋ*DIŠĻ[ĮįŽ7álN“˜Âĸó–UŨÚæšýhdĩûJ-ä­Š­MËC‚$*ó’ėĮŒąņū âũ?— ÏiÔ*–û/īIĻĘ\7ŪØī/ōæ―”čiå*œĀõW ’Tū,8æķxčÃ-Æ?bÄã'­NyTIÃätÖî­aœkÚēÚaðāÁýúôúĪ—@ēY~*‘˜xwS―ŅóߎJ ÔyŲOmĩ ­\#Ąˆŋ~"+r̆ <°ŋ^ŊB‘'=ŠGüW‡ĒPyÅÏÍįRE3‡ĸĨËhZUjđáÍåũFąt ĐŅwlĐ}OĀú—å%Õ*ĩ0|ĀpŽđķšĪžĒĄÁq‚Ö-$…æĻF†·Ÿ·ˆ išã0Ž'‘,†‹hąĄĀjd ›ÏBŒĪĄ"ÄÏcĢŦgĄZLXG“^rÛПũ"1ˆð,KDA"CAý›.MPbýŠĒgw’ęJHÁ˜Þ+―§o\ÅIJ"S$AK Ð%)M!?i‰ý-Qú`h1"‰Â4lĶ~yq 'iŠü―Ɖ%ČmÄN %büÛ"7RöÆšDL„H,A$ī`‘KŦēb·opŽÎm0’Š0―A2„―ŦúЂ'ˆOôš[ëž=ÉšÏõ\”þۓĖī]ƒ{I8–ŨÕLŠŊ{ūyÖėMūg%―F-\đzĘ·CĘÓÃlg-ŠÎ-Vf\rßā|.ŊÉH"jo |}muEEEA#-ƎA4tPŒį1R„Ē „(tyĢI]’Ęô‹n֞ÏWI(ý(îũt‘ŊrˆQ4-‘Ð(YĻehtVŸ=’@ģs!‰€}V%šŽ"  čÆNœb5i|#’åyኁXRŠÄ_@ЉMóĸœ1VÓR^Q;˜ŽkņJßΆhīT‚`øŠŠYĄáĪzý‚įЇ€â9žęú6Å$CÓz‹%ĒQ7ät0ĀŠPW…Üīvë‰f‚%™Oĩą•`@ČCZ‰ToGZBzi”ÞŨ°$ߗÚŋ!a8ÚÍ< ýLàķęWß=§Ŋä݋w°‘ÍpZu­ '„ëšÚ'7O—Os:˜ËĮЛ+bBýf͜!“YŊ>xŠķ—ˆļ§ũâũí;|*:ōļŊFa ŅĄsŋCŋüĪ+Išú~Þg’þvû‚Ģ•|þrßÂF–$pįóSŽÍī–Ï[ėŸ˜čï·ũrÎË?Ž0ŠĀПÞÝ6ßQ6M>}Þی’&J"jĐ~z`ë<™L6{ņŠkŦŦč_eîÕ―‡Ž]ËÉýeĐÜĘv[pĒZ]äđ^neuäĖuˆ‹puuĪĸ1ĸĀswo'üä Ÿ1wiR~Š;AąeįŽl•#sV„&år8ŠWUæōôđx-ýn\Ļ\.wņðŊláqœ Iöá3ËŽd2ųÜĢįŌ9d'*ēãũxË}RxņčđÜfhCˆī Ežũ?}ØÏ78æN3GrŠŠýÎ6V2đlzh\–Ģþ°Ēƒ°Ĩ"ô› éķ^™ô€ÃEPSzéE- Ø['üýr_ķJ ÅB!9@›sō|îsņį3Ã#‚ÜÖ;‡†đ. JîzŧD”–îũÞëŊģrųn3ƒŋĩz0ņ†Ã—.^<þÂ^·9Rž+ɈõōņÏZxÖw›\në{ú.GŌęÚįÞûöœŠ:|Ø7ôJz+/Âđķ?™lÆÜe·ŸÖĢúEÁæ„ϐýÞAé™ÉëæËÂï<­)ĘōÛåy%ýŅå°}2đ|gpY+D™j.ÍðŲå›zįRĀÆ%ë·Vjhó/ūüæËþ]h9ÕTzÏō(|ە›RrĘ0 ^ö0eÓėé2™ÕÎcW”<öö€îÐÂqyäEʅóįýF˜—ƒļ{Ÿ*lhCaâȊ =čŦ„l^ę…Më–ːįkÜn ČÁõ*ЂPkeaŸĮ‘ów9œ„Ч'ú‡_i†$dę tš; .ņō/oԊ0æÎđïč°C;―=*U ŧAïQŸęÓ]„œ"Ŧ~ŧ―cÝ4™ėį žYÅ ‚ '…wÎyú=., Ûã"·ē;v6‹ĮŅųũĨöŸS„™ús>ûŨŊ˜g;Ïųú­[—"æĘVÝ)ÓÐę"ôŠŨą·2Ŋ+ÓžÚ{Đ*ĖöņņŊnQÕ?Ė r_ģédËjēr2•,ŽĐ[SϜ~^ŲÜ\–įýˆ=į3Xœæ•EÁG<—Í™,›ģ1åFRÄɝ^{Ï)~ÉG6Û%6õÆÓĮa.Ŧ–đlõˆ{TCķ+ĩ$ģcNąœ~øl\öƒœôëgŸŋŽŊ}–ļĘq"ęu9•MÉgÂfË~8ũ” čÆÂk{Ü7Ú[Y툊IŠ‹õ^7oČ`‹Ýŋ&ÆÅm[ģāfąRÄ+OpųeÉĖŲŦŪ^Oŧ2oÉú[Åm ņŲŠEŽ‹\=.Ļz~ũŨõN6Žûc !RÕxėÛąÐ^>ÏygÚõäÃöFß ÄTJĀÆ9ģ–'ä=}þøķë GÏĻJ$Š–ē{įÆÉß[šx§&^vuÞŸYŪm*+).GÕdƆ'f457FļÛŊu=‘Ĩ`Ęģnä=RA3•quY+íė~qũ{QSž—saŲlûí7”-5q1É ,āj‹ĢCÃŌsŠ8‚Ô‹ðZÕó'é*@Í_4w˜™QKK‹ŠęjýӜa݉âG…EOËJ^"ë•ũbN'e)4ðí"aÉoyŲŲ9æ7ķ2NÔ\õrwą?iËÁS)Wc·Ūڜô RÓP\ŠŨ“~étŌ}Ĩē.Ðuþē]!YUÕwŪžupXs̰ABjϟ9áęūÎÖfNdܝ—Ę–šg9>žN֝=nĨÄßĩîįåG•„ļđ:ŧ—Û|{ŦU;ƒģō~ÓðÍ1^nk·~ŌČ1ĩųŦ'ÚėˆļRŨÚöüjLö“bR")ɈrēŸššYUQ|Čuᚃ—™wÕeUinv~vnnŅËZ‚Ā+ōãũļ­9™ú'ižĨĀg‹WljUZqō€_ō―\ķŪ:9Äg™óš‡ĩ<ýûؙĩV<Øåą;įEÁØôŧų]‡É“ģ§ÅþXx݋óLŽNžī{ĐyQZÛÂwšéī|p_cCÓ^þņɎ―Ã< !Ðí’Q<‡þø`Á†ā„Č$h+,―QS[yņČþFMĮ-ĮcïÞÎtŸ7"€íübZËCũy>oĀï>]PX˜Ÿ•4eh·„ā―ģÛl\Žf\ŋzx“HYqÜÃï…#IšÕ‚Ū='„$ĨėšÛh[M؞đģfÎ8ēŪZĐÁpŒå Û.ÛïÖÕ%CŒ['gdįßŋs.õaIkSrî%Døv—6ßڝUĄĄ)‚áX‰IOßÐ ĮÝ:æaYcëËžĀČØ"%ëu&5>ÐŔjŽ Hl&H§Y†ïþáĸčß­vž6ũþģ‚ūßīzЉĖņˆJ8ļæšųIfž–7[8ketJþŅuޠЇŊ‚ĨiâwņÞcóoÖ$§dĪ?ŌKTy$$âąĶ·_Äū!9jEęÝ;+g|TjĻŋE2-åOŸÐxïžrčĮrûôčiÂĐn6™|―uõc)˜ŋûLœÏŠ !ĮÃ?ŒjfĢÃwÃGŽųåȔĒ.æ8ÞėcŲÉs >äœ&;ûŲģ.ƒ-7­œÔUŠ-Ø{6þĀJš"ÕëxR§1ó“.Æy.Rūļ{+Ÿƒ§{Ņâˆ)óbRŌŽĸŒāX @ōĢaÂŊ^?ãÕÛfå]zXÖJ‘góū[ý"Ģüũ›‰ŒaĮ‹ŪĻ{ž\Õû|ģÚýĀõû™+­Gą%—ÂgWīŽō‹ļz6ðŦ^äeߨ—Zĸӌíj —ň!#GŒtņ‹dŒĖĮ~?ĩ;Ĩ9u2ķĢ bÎå4ąÓ–XŠA§-gŊ\>žøģÎuU5ĘVæÍœä‘.Žļ~§‹GÉ`QP†fÃÂŪÞ8{*ôD„ï81óĒžN…wqXæúU_#šÓw1Égm>7Ņj8’‡Dĩ·ęB°_V)đtÏéâĖ” åSÅÞ'ꁈ$h”Ī}fDÄ&ė\ų#Ŧšũ īYú[•Úũā $Ā~_ŠlŨÄĢ1ė;ÂŅvŌ'ýĸøíD1ŽķĩĄDĄÔ‚nߨfBH?JĪĮqĶ:ĸčæS-'9.۞Ŋ4‰Ą Â^€°!Ļåyv bųŅäŸ79ĸyL·(ÆkšĘ"íŸ üĐHD™u3ĸi—Ũ4–zh_5#5crÐÔšÕØ qžâž+žVY ïmlfŪįĸŪÕūšRÄ@‰ķÆH‰T,5Ž–įīŊK.҇oTÖkÐ`8Į ⚕€”p*E „ ÛĩwîþčĖŊŽ7øni„%‰9%l<†0&Ą#ž ĸÍÖ @›ē­ĨĻ[ËK_ŠöŽGI Ō(ŠZUbQã —Ō$dšĩ-ā D”Ū‚§ˆLˆÁ$Ã2€7$PTþÞ)… p‚ŠĘ t@ ĘĻTĻHZLqŠVF!C`ļ^į‘T$ļW‡„ČœœãžíāáĀ”·Ï‡î3Ąī,F"ĩeÞÄ(üU*ä;ÄĖkĪ^ŋļeî7eųiÛŨîLÍ­h·WŽ\ˆ­Īž‹…Q’îDã" ãõũŦ·ˆ  Ė?„ÅĨ+)­ !‘ˆ ÄüÃۉŲ*ƒî―MĜ0  #‹ÞÕĐÉąSí,'Oą·›ÞĮÔč•ŧÂqd‹}+ އJ+ø%"Ņqį.ŧö…D§ß―žô;rú6eY5Ã!^ø{AĮi1hmŠÔhXŒg_;9­–Ņ Œolð„҇îAį’Ē&™ÜMŠZėTРĨhAģåÜå>‡ĮÄßHKŠfBęåÚSŊÏGO›6Ņv†Ýø‘ƒ%Cš~j?lļVyo^!ëÅŽ…ÖfÄđÜ7x†•ĐG œ?ū+‚3AíÓ!Ŋ_—HE%…Å ƒ Xáâ,ôŧÖgėē“ŧ->֞؏PFKt;loˆ‡ž ……ļTĪmŪE(Äx)I`‚ pŒ,Jûþ „ŋ%Aœ0ö• įŦ"BŽÄĨĄ—‡ųÄāDï}šh9žĪ(eéã ó—’c/†Į&CÐmTŋM{˜uĒ@E|Č>ßcî7ßUƒN3mŠTĒc—Îðþ­Ž‚JPōāæ“ēzÔĢšĒđĄî|HøĢēF„Á·ĄÄīïW249ŪPäÝïūqųJ·ƒ‘FęԞgԏýđ’{ūŧw]đ™ž{î΋Ķá$ ::ėxl•ˆčāâ*ķũ3úu!Yúū„>ƒ~é;<úýŧ]œĀ[ęŦŊœNŽ;qþ|4īĸĀ^―ûuƒĻS§"SoD……Ý(АšúČTĘēž Î nĢ_œnPÜéƒOGôé8MÚ͜%ŊĻ)ČÍËmÖßŊ!ŽëöÆóŒF ŌN„Åe?Uĩ*ŪG†ŋh1ēt\6m0Æ3Š5^†§ŋ7Ȉ#O]JLOŽÍfã‡õíÓķŊIíDˆ-ĶÎØÅ =Ä}ë~ĸ{ũcOvß―[ŅņĢnJ)–gÔjp304>į™öēWOû^ŪS#l[aŠÆAF­7žė'†Ý?dN•įåÝÉĘWqęĒ'yYEÕŊ―ãÛŧ Ō“ÏE%Þ8u"$ýe“q‡>Ÿ˜JXžĸ,|u/V”eF_å?ķhë"c$^S‹ŒŋþVF"=wrŠĘ4jE郜ŧUÍró-z–žrÂ?čz—Áąã7—kÔĒïēéŲURt'đ†°°=ĮøÖšÖf:ũ0Ļ~žwû^“ŠŪ2;7_ÍŋR&LųhœÆÕɁū{í–mŊmA AAðŠĘV:w#ef=,•ŋÝ{øžÃ!ËqÚķÂčÓg Ŧ•ÃYæ$?ųíd…$$^ Š<]Ŋýŋ°1•BNMÄóþaŊŋ3q=}ãū•v…ņ!3mĶYÏYĐ0øÜcŸũs’A@Rĩ%]gįļ0>Oëäę/ĸĖėã 36Ū”ĐjîíøeENŦé„ūx\ÔqžãĒžŌ’kÍPú~xãÝ3'S 0éGÎKæ|ĻŪ9îūØĸjNIĨB3]…4D_8  ~šFusÚ}âįÉ_ßšø„™f7Ų°lBˆ‘Æ ũ†ŽŸ=îNôq{ų ‡yŅiÅcėŨÝ4ĸņeĸéēiŦv\mŋáО9]1†įuŊĮaD{@Ū+ĩ„ķą!pÝf{‡UĐÕ&óÝž~øēĮ€ŊlNxŊV–ļdšlÞšÝGL8ę3° Ūå00š3‰c"ĐXB ē,mâėîģaÞÄļ@Wkô ƒ­“Ë΋ÍÂFēn^@ ^Ģ‹8Æj™VĢš—<9đÔ3žē•―ūĮÞÚĘjúės:9ýâ2nĻÏrŊJ­Šbí|ėāF“ķ NķēYÎû˜į…x,ؕ€ļ”ĪĪø·+%ÃmŽOü2Øc­•ĩĩ=Úi)?LŸ―Æj ŊU7Ójx·—x…WаŨC8ĻŦlēéŋcíâe?ŊXąbąģëĢjˆÄņ‡(pBˆâģņŽō/Œ ú/ņ ŨtûæŨČSMŠm^*—Y98-‰šųH7Âfj(&!|ģ„ĘūxļŨYūÄíļŠĨ‡įŽÞ Ãá蒁eUĮˆ€" ‚h­Čņ\ąÐJ&›ĩt§Æäã=nKûšvúÎqËÞ5bÍķ·ēķą_ī* XŅūÔęd\ŽXđô§Ÿ—Ŋ@tčB6ä˜N'Ėþn š4ÕIöiŊÎZû™åŽ ƒ;å^Þ;wkĪĐ|P”đZŲ „ŽP€ã™nýĮXĸ0ŒQ$đŽũþJî`ÜI ēEķ_Üŋk­ßö%nįž|:uŽ*/áxL&i2`Ž­„Éw_>/:õ)Ņē„tęOÛvĖ·L ņēšjåVmŧÜËsģLĪÕð‚ģ(Ōv !þݚYĸžþÓĸbïZzÜĶĒ0Ž@ E•PéTĩ+@ŽbGŧā°…%T‰Ā‚â ™*…ŠPiĻ Ĩ@Iüˆd’Lėø'qb;~ßsŊĮˆ7—ÜĐF]ĩ•†|Ŧ›sÏ9ßųÎ=ķg1ē1!8 : ņæ/?ßžu[1F8Ïr„ O>úô+įoÔõšĀË{ ˜ ÐݓD^ŽÚŪïZŠjZQ ZŧÎóōĀ‹Æ}]āÍĻ7 PoÉÚæ§Fk YĄÓŠI•rYŪ7G^„ģŒāļÓŠW8A”[Nų2"ÏVšÚĀ 1ŸŪÍõcĀ8vWQ&i–ŧōŦįN>ûâË;œQiO‰ÐR'’A:čķør…—jÖØÏ§ĨNBOQ”áh‚'ŅÄP“ęB(›æIč6ëR™ŦTkMÝt’‚Ýņc āŧ#8ōDSė ĩ*ÏŨ;―0AŪmÖe‘~p―ÖėD@wąÔ}J’žÖäyŽŦÖL7ĖĻ|@iötEít7`6Í"w(q·é§Čŋþęģ3/œ~þäS'N<óú…þhcGŊr|]é…)üƒ’e*kP5ÏQä •ŪîTō]›ÚĮ“BE_ĸ̓ó<Ÿ 4YĘĄÞÚ{>­ąoŠjIJóOįĪúÍô/Ó7.]ÖÕWæÛ―ņrØŠwŲÕąĻ'@264U7ƒĨīÉûíŠPĶįÐŅ,„ uÁYFįMi58ū,H E†l– YXôČ(‡ŽE:^+.*jluNÜ7ė0ô$ūRWQ‚œĄĄčƒ0I1^†ČbUnĻīCïęf/Ą‰Pl( Ž“Ė=[KäųŽåÆ(šī’(Ę}*' -…ĶӐ,C‘ÛnÐ ä=u’ā|uЁ3 íuÃe{=gļŽÍŽéëf6Ā“0†•…Ī#þMzŸ;ûVĨ‡ģœ:ÜqžŦ˘ąþkÎ1‡ŨĶ9üūõ)}Ķ?wúĖĐ'Ąü/―ýqÓN–n, æÃDk\…ąp€ŧÖ8›åNõÜéĮ;uöF?ŸįäŽ̈ąŪ’°˜’Š€#Ø į57`yÜĢ ļįĐfy;ƕ//ūwþÝ?đāŒđŽĪ)GũQÁ†J™§óŒÛþœþ?Ék·€älLsØ@Ķ(VS'v—=&vB.Y}(+6Žx€uÂ#&äðÕˆiïĸįVŧ ØđuõĘ·ŧŋÚˆƒoķŊ—JÛ[[ۗKĨïR―4Ãpĸøpėė^ûnįÚŪa€ãü0-þZĖfųlú°TbŽÞÚ)•ŪKÚrĀ6ØžDqƒðėāā`>À$€dóƒ‹yNî7=ž/(æTæąP<ܑ"Ų‚ÎTN6WŨßėœÏŽE‡{ĶŠ{v=Á‘ö@.(wĪžð" ž !)D"q‘EØÓĸøšK&È=øÐ?KvuOÕŊjåK'ąw öŸ44444P;4444Īî&5Tku·ŠĄĄĄĸúĩ1ý·ßį|ÏGUk_8L‰ĶKŒXÚV_YˆþžĀĶûØ>%›ëõþ%ÞķȖÚþUGsčÖ6?‘ąŧ3ÛĮû„ë{AŨï€9ïš?qî ÛÜéÉ[‡_Lé|:íņBŠ2x;4t{u)åã3 –Oųӏ?üüö­ŠĻ%įyžsN"Ęģ}­^DJŨ„ÜTāJ)Þû”s)Ygæ)Ķ(ģ€ ‘™É03ðBzKNÉlŅķm8ÕūOēqĮvŽ]Ι:ēī˜M‹-‡d:2Œz_KƛMs6ÚâLK WJ%‚1p#â^sïXjņę­on7Ļ9}zpæ…|jKv•ËõLGM /āįaš3ŦŠÉãï_}ýÍ·ß}:þâ,ĸGōþýŊmæ[ŌÐÐPÎų͛/ĮÏbLĸĩ"ōËŧw|l~}ą‚”Ü0“ešDŽY1T%nØX–;˜hČaqĩ€,@SPà ‚k”&UÅy;Ÿx†Œ4‚ÔZÐD*Bư,Ā“\Жˆē“1E ĘÍÁ•Ĩĩv0—öa )&ŪˆkĮĨ-(ĄVfŒDGZ‡Ō Ĩģ˜KF=ŸÏThgnî,öÁ3 3…܁ĄŸ[ŌČaNŧ)z‹ WĒšVQå^?~|xxčæ'ŨE9+}õęóŨŊŋ Î ݆TåÃ‡ßø<ô˗Įg8Õ" þþ€VøÕđ, Ŋh@!tð•†ZĻNäpybÉ>˜€ÔÏӜ24ÄBĶšep)ó=äą,ũęÕāâ―O!ogŊ\r―w,äĀ/ėČ!°)ÝÚM pĒJ%nĨ sēÉ åôĶˆũF%·ĸHÂ^‡ĐG™ØÍ‚ļk^YĜđĐånđ#žō' ýÁīŠBVžéÂ4v翜Ë`ÔÂr ‰1·ũĘ+c8Ļ}XŨ~f§ĶOÕ―8ÜŊmą ëz8˜ŧĄĄĄ[A­Ūë ˆŸĩ"Ē*8ÂÜÄôâaįåïã ðÎÛÄ|OhPčĀH°ĐVvÄKé‚ģ€5ž"…Ð# …ļæ*8ĮsĶIėčJ ūCÖŲqĀÕâ:ÛŲ0ŧBYÁĐōԈY2Đ+éļg)ߜȂ§Ā.ĶTK>Zfķóxˆv@îø­ė3ĢâÖĻ]0Ëv f ;(óÄfÛw]퐞§“Þ1äœ/Éļ ļŠö}fŪœbÚ°}Ēz‘š ÕŪįüq3° ú œĄ'œeÞb#€vęœ%$žÔ{!ĶĪōJlĮՌ[-Bð'{g“ä8ēÃ`Ė”ŦïŲą’?Ï$ÃoŲč<Ŧtˆ•áâŠî0·°t_íSŅCŠˆ™ČĘ*…@v^ęÖáØĻ<@ĘņĩÞ`ƒTdšMąęĒd[įéDueŧ)…Ï ;G›gÍ}Ķ­ĩÂ}5cÏ’‘ģRb]ÉÎ―'ƒž?GfĪÕU+rÍV4™~|6‡ ŨjęĨŠ`‚cüŧzôčĸVečtÕ[HdĮĐHŽĩðąĄNrO1ĄOÞZĖ+ēŪõngiSæýū3]— X‡,o…$rĒ-ŸõÔæÕÏ{HŅqg„ef§Ļ{ķdäęeÔr5x·1ÆÜũzeĢŌdãv$ R7ųė2ƒ"Črp$t°īũ]5-lŊ%ĀLˆÛķQƒ 0ŋ īęÎUEkˆ™‘„ČÛNvĶÓCBš]­ļU–n$:ĀÕF0ŋ­ˆâßÕĢGÖßūÛk2ŲŽ@ĩÍBÛ9yĖ2l­ "~ÛĒŪŨÏ'…ާÚ/ÏąŒäDNļBmøuĄė―„göūïŒøXÏlų!Ōé*ė>‰Ü“ÉRYXzn’"*€CNËČhÂî&Ck7™î-Äý~“T2J.ŠZøļ3Ÿ•„7“æYïÕUŅ:fŲNRÏęöVy4éĮ––Âýœ{–fAÖ1Dė>BQŠ[}I‘ßHĩ=T›ÕzMuģ.ßtmāݛŪánķ>z•ݰb,ĻDFy( Ūō-W!RēĶ ÍA&^Šûš„"dzl]ŅČŪm5ڊ4Ïþ'(QÄ#<@;īJøÜYÖZ}{ŋ:Ø=sčYOąyüĻ‚TũІíaó„4;a.‘‚ITėÚ{&'ēwb{bJ!@ïm›*#ĢŨ‰[U‘ó{.JqgĘ™1 ÂÚþÔ ~Ģ=V+m7ãnå,SÖÍ68wR_í_uĒÜ{‡đkrex‰ĪLû5Ąk%2<uë6›Äšžeeg">Páûšrvó‰k_HČ·ņáčÚÂ"e’Ņîĩ(īĐ@tÚ‘JIÄÔfĨéQ *ĒĪ7Û.ÕtmËÖ}-Ʉ(•CĶČ`Mƒ™‹ ū)ø…Ú%_]{ļßïŽŦ2jHĸ]Éû4n“ļï“*2{mˆGýÂŽh7ôðĖœœrčøoĩĄĘKʆDŠl[æT_Í#õ”[Ÿ”ÁÕiˆˆķ·^ë‹§î­Zųķ…ĢL­|[ĻθĒūØ{ŧGdčŌĨÚWŠĩTT{€_ûEaī”õũĖüÂŧ! JÖîð’ŧ)Ëūŧ#ąDč=!îsĖm_;‘^nR3āæþüü95ĀĒMüôdj]ÐÜÖŌjæšn+?Jý`aušKæîžŊ”("æ―ÂŌ­ĘÞ\‰.G&DđĶ Č]ũŊóko(í>‘P%2Û·'&ö@,ÕņýAéĸ/ÍšËU_PųģöĐ IVŌe5PT(ý͜ŠōØ‘―ÛwQ|Ėë ÅøxôčŅïËjŦvÚ.BČGíeļŪYšgFÚĖy„ėX ũ`d‚"$cގĨŪķ'ĪHâįõ§mīĻ5)΁9Į[ͰvۉŽÂꜩ)°°jÚ$ŠĨxÝ3 ëžH!UˆÉš•üyóėđ‡‚Ŋĩ ~=^Ŋ~ŸØũ>aĘjtæœĘú|é^>ōÖĩ/Ąx˜(Đ[4ï}M%ci}IēĐYęŋĖĨÓlÃj/S~ĻöŅĢߙ՚é$%ðūïHW]9Î(åYDb—ÝTːUĢÝ~”Š„ í šõxMËô2;ûȇ.31ï/ä>…īÝĨ•ˆø{WŨ#ÉqóŦz– H’ü@|ā‹ųäĸïa˜äGČË~āÉŧÝU™écDßĀį#e·Ā-āÎåÍeOMÏŒĘŒˆÚbÄ;ĖDęÎ4ē\ũœKA0KTˆǐ[)čŽÃ&€ûæąMœ§ÎWĐÓĒJáißģŌÜ/8ØDģØKįŪ,ķĮ1•ú3hŋtŒ0ŨîīķųŠ ÞĪyŨ|­ĩOjķÝns­•ė5Š…Ŧ[åŠŦŪúĸŨ@ČŪą wßũ'@Ō ŸĒûĖTi5ŅujNIė1Æ8ŦũÂė˜\)ĨÝEIUƈšĮĀ)kĩļÝæ~&Mę6ũÃÝĢręgýFEļˆû.ŠNð]K1čoé• €VQé.Į™‹+Ļ ·TELó‰[ķĪŧýøi‹ˆ‚WAB IïØ\Áĸl8dĶŋ.SkxtÕMh sw ņvá@īMŧŲxū/=y*W]uՏۀÝý‘ĄÖ!0Č,áėä°ŧÝĢšØdĀjŊęUŅōØÝãųaûq0Ö&#ÆÓąŦöÔBœę.k)she͚ň\Ų"ÕåęlōÞnŸT7mÁ6âØlŌÝÎhŪĩŽĘ5ϖqÉĘNQ0[Ãæúô_OhæÆ›ĘJÁT ~°RģÓLŒˆežę*21'ĪýŒ]xÎÉāÅ{ÐLWû°9§ķ€;š$ĒīBāb •QÕ&īĸŠūũ_ßĮÃþ urÍýŧŋýŦ/ŋŽ*đ꩗QsÎĮĮĮŊūúę›oūYk}LĻ°ũŋ ũÍÆ0ÝīÁå ĸ·„Î?b$ąAņ,JīÝĒráfSÕÉ.ŠÝįøŠÍŨJķb^x—ņgéjļ[xeZĒŽ&DLlīoЛīĖy˜9icI›Ŧ)ķ€ÅPę|;ÂíäãēÅļƒC„/PTC—ä˜Óāz‘cÆgVĐ*ð`k*hûō+ĘĨåŝ€"G‚R‡ðØķ-+įšP 7$Ú-ÏĩoŽŋúëøųį?ҁÖ"úh~Ā::į/~ņũ_^PûÂębĩŊ^―zsŠ~lą—ę}V]ÛíޘNlŠ&2ŌuĘĻ­îZ„NBL!đņÝuvZþ=U…$ŲŽ1€†ĐðŦē?0ķëęĒ-·Ÿíá•ĩjōAEÖÍ3—K!Ū:ÜÝßIĸūéėĒ >ŧĢÍzĘķÜ pŸŠÖŽî^bƄ-˜Ý[Ü#jF†ÛvŽ;Õ#ūĄþ:Îđ2tūœķMnĻKã1·–įĐã?ó;ãâYŽ ûëîwîĸĀu*įíá*iy1uÕUŸ~úéwß}ũņĮb!0D„ãŊį/EôîčeN w˜šūÅЊfF·î›Š&*â C0iwô@pŋÝnļŪČ}žĻ ’ÓĖî, oĐƒFĒï„ß;l‹ã/ŌjĶ-<i)Á#~ķJo‡E-9RcčÂ䯕)Ę ĸXZČÁÏö…Úq,UcĄJž†T_§ŽÏTÔÅ0 SÜąšĨŠøĻUŌŲBŠô;Žö”OČO_§Kŋˆļ öEÕĩD3^üB|_čq3#â;™Šûūŧû6nŦēéĄ@įbwŠÞwúaæJž„Ūįp‰Š)ÅŧŦ ­žų4;Ϝâ*0yđũ?P„ëbČÅÝ – ą›Ý5 \ 3‚R oŋã>zÍV]ÜĪ<`T\8œrŪîžóĀósGD؝ä]Q…Rągģ9­RU#<ņœ‚ÐúÛnĶj™éþøĪ°ņ&Ā‘ČžkRÉä̟õißĐ^ \†;}kâbaĻķęė’ívK”ˆÜÞvÍ-ÜyÖCÃÛÉnŊvũĖfCš“îwÆAÐé@Ãƀ+[™ŸK(WŽM†lė{Ž Đœ4ė–4ū™gŦ]% (ĐũŲžX‰j“ŲJó{—jBŠ”joli•{™Ļ釮cmÛČKƒÚŦ.Ļ}ną•Ŧj™}r(ûփ”URmn…)áōÞQ5wZNņ*ûą7f\*BôĄĪÓ*3č Š7gŊ@T€tÂÓhČFÕ4Bũý’đāŽFŒW €nU ŧŸŠŦ'ÁŽäNŸ}dU;;]]MŊ-Ãˁ’GUņΉyķho–å#ÐŲFéEWN#VJwmá ðāŽŧϕ"ķ—gËXī)dðđæĘõž „_}ęvB­‰9 а7ÅęVÎēšīK*•Á•üĨ xũŸģNuˏŽcHŋHíŨUWŊVÕT”~VG­îœË -ĀņYklĢ & E ƒoUÅ1aG4Ė™ÕBÚsw=ˆīy°åĘSÁą7·M(Sopīpz:Ė5IkŪûŽģ‘€~lÆáY ÞUÎH捁LįíáVY-mb6,W*Æ`hđŠ2ķ›JįĘŪšÝoĶŌtj§€þģ'Éoā ŠûڏsÐķ?í-5Æfæ HÝķ­Ŧ―ŽąŽï‹G“õsĩTŋø™Jœ{|%VRK ļ`5)éĸüGąØ(ë|•~Č:ÖšÅ05ą–ŦŪšïsqLlö ž’ĮT3ÁsķTk‹ Ü[4ïē?Ðnáf+Kĩ·ą•tf՚cÜę4ī6 &ģUęĻĪ 6Z܍F`ußHQ]՜öŲ–fneEøˆąæjíp7Ņc?ĻS3ķ8hĨ]™LģíîVQQĮĘ-2,ZŨÝq‚°ÉŧōmÖn‰Á#xSAŦOA›[æliQiŅ…ðYiU| WQôÛėT#ī Ÿß՗LĀŌ3”Â=ņŲÏĪĸ•Å+<ãŧÕøÃęû­ïԇŪĢ­[Eã\^L]uA-Ô/€Õ‚nÛææõVŊĶUšsŽˆÛķ͜"bjĘĢÂąįR-ėĶU4€ģk­@óhėÂ= C@筈&Ģî8R„ų!ÉĀŧ­X4y‹Ãu5Z ás-5āĐ ÅŠÛØîŅYĶgč RÆÜũną1əÂAYŪ5wĶ(dqšŠ-]8Ú‡Ų€43ŪŨÔ"‘‹#!ķ 7ĨÆKUā“Í3ŌyPęŧmãņĐ+KžĨTĩû‹ņÝþéÏEZ[Dĸ\Cmĸ)GýĪuīÄþhō’ęŠŦÖZŊ_ŋ~Žv9€#ĮD“Ô!Ž*˜Ya“^hŨžōXuiå‰^ĖÉzš{0vŦVĒ[:Âį>ó-Á<5аH`ĶÚ-nUĀRSĢqėͅ_Ņóƅ ó֑4t%~:ķHÜLũžĻa†€CôŒčÍF372WuQ€™Ũ w‰G8ÅdŌ%ÂA_w›ŦīŪã þA@―đĸŪ’Ų0kpål·û‰ŋiĶÏe7üËßþöŧü‡ų/ŋãÔŪĨåãVũ?ŊĸðęũýbXíUŦĨũęëŊŋŪŠÍjA*=FFÂ@™#1k‚‹lŪ5ÆØÆvÍDœ›{Š w55xÃ2€‡‰šĒĶÆ|€\ŦĖÖ\‰ÃcŽÚŧЙĩõø˜•Ūæâû.°G.$lI‡Įūï-MĪ[kVõ6Ɓëˆ!Õ+įĖÉÔÓãĢÂݰA^&Ý1BšŨLSņáМ%…îxÏ(-#†ŠB3kŽņWŌ‘Ė Ķ1愖6"(TČöÍŅfYÛØD•ózwč”ŧéc6‹~&Ļýõo~óŲgŸI—ž˜jĩ—†ģW]ÅSĩ>>Ԗžķ“31J€č\†Óáâ‡ėÉĄ1€—éā-ôm$ČRí8ęVŒđŪbãá“ŋøâ 'Cû'Ãa!ƒ?­ī#ĒP˜ĩķ.„„Ņ”œŌęšĢüšģT‡tf3é•§Į§ĸøũWĩēÏĪóĘŽóx„jGæP§ėkÎcSŅÎĪ8,W Þ1ķíl!ŠkŪÎĖú>yxxĻ.ąWķĘZ Į”đMx=LĨšAޟ§Tõöð ēŪšęŠî~b/ŽÖŽ18ŒjZþ \ÚjĶ02}@Ču\Sn7ôgs%Čņ šāãYTEíŋŲ{89Šã{žŠÃėîerÎBHD9ŒąÉ`2c° &˜œ &˜$’ÉÁØD“ÉH€BĘB9 p']Nŧ3Ý]ĸ™ę“|>Ëû'üĸĘÚįóŅ·;3;w}ÞÖVŋzŊĪĪäGG5rä6ąwĪsö[,ĒūÍŌÃ6Ïnð0ĨԂ îüÝ­ŦV~Ģ DQd’;–Ęŧ—Ēö―ZöN dēwŒRĘß·Ÿģ<'ĪŌOđŽ&‹"›J@äÂA*!b~pŠóuø64ķNš‘TŌkr7―Cyä‘ĮF ZņōÞWÖY$ðiŊÎQ :ÃÞ1‚ŽC)Ē0­)߯Wš„@ūXó"V~œĩ čŒãķĶ$‚Ą[+,,œ>}Úá‡ÎLôý~^Čd2|Č3|ĘF†ýš„VIÝjž‰­#á„4Ō§Ē‰Ö\ƒ―@Í9Ŧ•Jy5J­sjÂģÞęLŦuŽ‘~Ü#Q/)Á9ō“ĮÂįŸųQYž7Č#<6?Š%áĢœjåĐֈFžōú īÖþĖLĀņ_ĀíØ­ŠÍ “IYG”,A2åZ)[%Pý Üzë­Ŋūúę^―zÅ6―Ƙï›mw―ûŨsį|>qĒH€fŅ ŪsŌ‘^æß3 ȝX›Ō)vÉ$!ƒ õT2þĘeyȍG<âAå}žxč-PĘËu œ–*ĄuïčĩÎęŒũ؀ <ōØėĻķÕ@‹yám%ˆëdü<Č`žŨp "ÔZqš Žāöfœôņ_žwä=JËĘšũč>hð`­õļqãnžņƞ={~ßJ·øE;þ'k*Ũ,Yīý qrÏÞvKķ~šũö:^jfa/G6üf˜0tŽØGX_üJî۸ȜÖwį§ã|“Ŋķ~ķx?ÐYo‹ÎYmyä‘ĮæGĩŽZkXO‹Þ\ ™›$6QīÎnÐųö īĸ0Nd*oœ(hVeųĐc]Â8;uŽŧīзoß7ß|óĘ+Ŋ,//'Ēï+ē1lذĒĒĒŌēRDðŋāzDŒÁþđ~ķQ˜Čße sĄT’?é;į―Ĩl­|…EÄČk$žc™·[lĢTŦ―2Āą‡ ĄŸkČ#<6GŠeútÞhÆGÛ2YDϰēđĒŊUmkcAøz–é5pÎy ? áŽSZ9žÚÂĒ{ž}ûõ‹ĒĻS§NétzõęÕŦV­‚ïÖZoԐÍf›ę+V­ðŽ6ņëFQäÍvĨPcØ ĪötÏþ 6°sôųžÕJ"ä‘ĮĸÏU­ĩZikŽðÂpĒ·dzõ‰Jz=ŽUz]Ž d›Dĸœ|GŌ8hí,VDwiëëëëjpüWðýĐ:žnYŅĄC‡5ŦW:Šá8W<ēÖ ĐbDl_ R–}ū(>@HN\·N‰‚˜€”’ïßOņú…Ō^90ÓAĀĖē3ĪöskˆČYd’oÆįũĪģ]„āýĶYGĸ‡äãQÓÂĨ]ûõ-”‚þó*—VfÓútĒuė·k0)·láŠL—2ĸ·Ų‘ß–āyŠEÞûÖ9nY?Ãø&ĢÖÞÜDZIēÓķũĮōZd#ÎÁ6†ã!Ý@g[ē1å 6<æŲŋ/[ķĖ+Éū?Šu\֕•åē-M Ü$Õōޝâ–€’žŽ#ß@ ÉŌXö–Ņ Ïrņū΋Öų­ÂČøôrMDa.į›žÜ+ @(DŪđØŠQ·zßø`g―°īvĢEŧ†goŧęÝU˜Š­îąËÁĮø€"ĩąŪŊŌÁâũþøðtuə?*îß/h•›}Á9?ŧôŅWwíQjŋó]ĄJÍũšk^Ýû•—NÂlô-§Ų0g”Öĸte ęošüŒmNūņŽCFÛ0„ĸģ “mŽdÖb“ï0å!ū­.r8𖗎Õ\ĢĀÎULOŽuJh"ãŒ< ëýK…~Í$ĪŽž§Œ@ŅZâ!”węÔ―gÄaj1ÕĶR)ņ―=—u(ŦŽXma'C Ô:ȅĄ‰ŽũlŒL$―,JĒ#[M͉]u|^/JvŒŒ˜{!ZcHą—Ģ·Yq@Ü+@Г†C…Þa‡ _vŦáö mÔŠm8gŌûĩ]·ŲĶŧ~毋ŊynFR(TšĄĨ`ݞN:HĨâG)U,ԁōä΃ī‡bs·ø ëR*AĪÓ%;–ú‹ö§Ķīô/ŪųG†?ŦþДFY˜jÉö&'yūđõ•ü‘|“ -øGíRž‹ˆ"Õ\Ē…_ĨÛū(HÅG2Â%sn{čÅå”IŌŋĻ?ý‘:^+H§Â°‡‰ Ú6é_n{3ZĸZþąîYķŊ’ŋÄšŧ]ũËŽĸ;ð!Ļ’’Dm𘔒üĢ ŌĐuŊ EØžüūÛĮÕjū#”ëŪ'á yŠ%ž6•JÚäŋĖĄÖ†&ō< €‘ĩœ†"ȁÐA€ā­\ RŽØįÏāJúá1_ؑ%þ Ū·ØbhiIY6›7o^ü]k-ŋøØocĢĻĨĐ ‘Ýŋ8Ï7HiöēIÆ ’ZMĘĨ`oķHL(Ō8#1Ą–( ­ą:ĨČq°@%―wĒHþDÎo|I­þČøāëy)ŦƒĶ%~bōã•Oūdž°ú/üî՗9ųĻCO9w܂đN?î°ĸäŒų•ŲÃņŊ=õÜëŊžyĘQýøĪņóŦtrM+.ûåiņé§üėŅĩYԐýā•'^zûÝŦN=æĢNųdqMōf_·čԟŸ8vė!ŋo–Ô:ŽþúŅ›î~áņˎüÁ?―óPd_ŧíŌ›îųÝąG\ûáėZS?ũâģO8蠃õø$H„<þWFˆP ą R†6į,;ËFąN'RSįÝcĨ”‘ }HžA ~‡‚T`žp…‚-†nŠUTŽŽ'ļ’ę@ˆïĩQ+،Q*p%Ó= é­―lK D‘ąä­ ČÏĢ@”˜4m[•ž­ÃlJD^ļ–ü8ĄŌO—€NiNjHNÖk>1Į!=Rjg―ĸY€ūøÝxý=5͜üákÖžŋšï.'5õģÎ?æqæõįþōš .íũ—?še_\ņģgĮûģcÜâž#Ø}ĖŽtō…ũė}ÆUĮ+/íÛ+ûŽ:øĀ“NđEÉó—žýÛ%ÝîžæÂÛ.ļö‰^Ý/›ũ‹Ë>:úúˇTzÞK e ŨŨģŲåSÏ>í4uŌų§î’*í–[=åü}Ï(?åÚ+Nu·þę’[ï―ęĖ~㟞ęų’.>æ‡nūøoí}Îų‡Ėxé†'^œróyŧĖûā‰_+:ïW'ôšõė™—ßōōļKÞ―îĪijũKŪüÉëw\}éÍÍãŪþ邟žö•†s/úŲÐ/}āÉF^~âýŸŋŠũŅ—lŊŋäüþ/žąWĶú™ëŪğœuâĮÖAjéŒ%l fƒsZÅųá/Á!ęÞD‘uģZ+Áö’æ™ā0du%Zk€h#nðŦ°nŌswøÕƒŪxöæ#·Ž˜úÔ[k+ĮĖý|ĒZ^ģbáōę-Cv;ãž.–ÓŸđãŲĨŨ{`8M~ũá·Ôþõu<ä·'0:ÜĩįGŊþ qÉÁ[ŸĸÜ;įîīíÓģíŨî“?-BXuŲïĪG{n‡%đïĄ;ŦŨŪþhöĖ}.?ûČýwWŧt|üƒŦ!2þ†ÐT8{ÖÞgžyØūŧŦ:<ņÁõ›fŸ8§š~ú§Ūýzé5SjĒė?čé&|8°Ï‡oUŋü―wŦÖ2įóÏ`iÍ7‹ŋЁr($ĩ,ų›Ĩ];Ïþā3ŠYĩtU]ÕēįßŪęuÂeg_*J―ĶvÐĀ­VîžÏƒ:T\ŧhžÍŌ'ï|RUđü›åŦū\>Đį?ã˜ýJ݈įߜ•mi†T°tęø);ĸéâ öčD—}úāä^Ãßžô˜þQÕПÜ5ó―Š†Óre[\rųĩgïT}ņęĀᗝũÓmŸÏÎ}Ŋq­ŨrņÕžĩ}ãžâ·Î|tÖīÏ_{ŋéļį/ØkŧŽýĢ“ū~œ•5čc.ļåōsöųâđ5~TWģvޛ/O-8rëņįΚ7cþĘ=FšÂĄ#/ŧö7;e–õ—gĒô°·ÐéÍ}ÆîÕ­8ŨģũĀĘgÞ{ýÏŽ>ęH„<ÕnjøvEÉFāëĄŌ’ûōĮ6ŊÁGŊĨeĐŽ1|ßžq y+­ˆc@Hv\ī}ôĮÃZZZęęęÖŪ]ëĮ%ūĮŠ–7…ŦÖŪHÆ ĀFQŦû"k/óŧýóģOô ÂÐ&7K °í"MMC&”Ę{_Ō€kÍ.īÎÏ­*Ĩ%Í-Dä(ŸÚˆ3ÕĘeČœČårEŽ=(--ĩÖΘ1ƒþjÃ.ŽĀ;ŊŽĮW ų_>þ<ë­c3™ôŨģg°$ lk›U(!áØúÖąĸųz֒ē5 žķÚķûvŽæ†L:m3ÆjíÍ―"ķ°‘ā(ĘqrÅ`;))ã ņÕL„ žĢ mÄ}떆æFģÝ 1=îvŲ™§<ĸĮßS^>õÃųûþrũæšåÕđíÐRSmčlcSŧŲ°ĐĄÅ”ýāäÞđũ–‡įÜī—föŧcĮ^šK·wlüųC“ž|ï–ĒäžÃ–œ`9`ØØ$ Ũܘm:ėŋÃnÏ\vëe5ãW~õöž=ĨëšĮĨĢķÜōčĮŲētíŽw^øbzĩą™m;čÅóŋ^{ØØîĨ+VWZýųgŠE§A{Î^UU6āÔˊĶ~ļ`ïswmŠïy$XŨÔԂ…N:âĐ·ĶūûŅØļjE=îwꑏ{íÅ7výÁð‚æ’m\^õŅĮÏ=öė€s;nĮŅW<:―þÐý:`Ýę†Ķa[n7ņáįoz ž`á„Ũ?Y°ũ/S°úítĀÞ]ļþŠkjߥ6ę°ïČķ7ÞxįĮleĸÃÄ―O?­C:Š•+!‡ė…Ų0Į<…ņ2^ĪRŲ†gŸýíN˜öÆrčv;íļ[Å~é?ß}[įãvųëïŸūÛ Ãŧ}Ü57Güra6 ™ÎÎøÉ°įfÏŧˑķķķŠĄĨ]ØÔäđ\KSäHé‚ĶšŠ_|ģËvZ1ũĢđU™-†oņėžE„bęs7žņpíË―ŧō…ŦÎ|ļîåŋÞUņ•?}ļþÏoÜÞ7ˆ"yl2Të9ÂZKœiØ3ãU‰.øÐ0oÝíŋlēOķâOÍF(Kõ{MR$—–tëÖ]kÓîīiÓžö ?J!Ð •ÎPš2]Eq1ĒjRŠZRƒ$LVü]Ā?cÞ(ŠÖ•åZZŽ1ZÖFāˆžĘӄÞ/†kä2:^ Ĩ“čýŋywĖ;ėA)Ģ\(ؘ‹­―-øTGēˆ ‰e Ā=l`á=/Ĩ1!‹įb{F!$S6ڍØŦéQ)zĶŽ+<õęëŪ{zUMņÕđĸÞ[o―ïŽiå―ØõÐ΃ĮühŋÎ`mĶÓGŪ ĀŠT—ƒøQũ ÚúļŊoâÉG0UpóÝũíÚCöøÉugv]ūįv―­ĩeý·;ÐiđnĄÉĘēGĸÎR;þü'{|gjåžgŸ·ð FÁ^'\ðË%Ũ―ũŌŧ;ėrėCšĘDX6tŸŧo―áúqũ1Œ:â ŊŊZþô ÏĻēūW_vA—ōÞŨ―qÏýwÞ}ïS:ØbÐŪw:ö‡aũÐĨNäþÔļ+ŧwœÎ=bŋ­v;îū;Óŋ―ïÅ?Í;1Īīũ.§ýō°w'>?}Å~^q“xãƒÏ>č„<üœĄĮėwŌõ§Ž|ũWlqčÕŨî8Ļ[9Ũ*!ï2ô–qũßzįĢÏüéųþĢ|Č!ûÝþäosóCŽĸÝ9?ŲAd+vsDßÚ:9ú°\ŋRkiÐČÝ( ĶÅĶ;õ) Þ{þĄ:Ųũž+ÎîS^rÚĩWßxËCũ=ÞĩĸÞ7R‰ ·ýĢ\Ŋkm·Û폐 ‚“Ūx úæ[ŧïnYØãĪÁ; íÞëÐ#~XX2%ŧŒ9b@ĐÔ]Füüž#þðúËģw^˜Ŧåé'I^qí}3Öö°ÏKĨĩå}âÅēxŅąÏĀxĄ|ĩðO–VUUÁ? vÛšäWūöōK…Ą"{w!Š@›Ð8Á•›MāA*i"ã‡$&úxsKĀyđžéïĩbý ūōękúôékîđį?žû·"4ųó3ĩÕéę™-Ü"<"]ØIĶ$Ų, Aš&!„Ž“X/E­‚éjEë.ƒā›[šy€‚â"šĐĄķrU…!ƒë tX u ÁūæVÁ-ĐTČųįRHDÁvĩ·løNŽ$ :‰ë •äßb}Š!?î,·b„K`ĩ0Y["ŊSuĩ5?>ōĻnš9NāF*•Zļpq\†ũëŨũß7…ĀT:&—3„R§īt&ŒœLQ.K*þÉeģ ŊrŲ,ĄL§īÉe %§ĢįH…\þ+VÂ\ÖðÍæü"‰Ã*QD‘[ðĘģ7―5mŨûþô+ûŸûäígJKĀāëÃ:DaÖ:āŧó/EŲlĪR}YåŒÅD"ÚÜs:6ūįķ—ēIĪĐ ­üdģ9“N'å*_‚tJÚldýS΄Ąq°B~”û‘’ßE:Ø09HþžžŌĐīkš+oŋāh·Ë㗞<`ý-ĄPĐ@ƒĸnß ōYü[óß­Í/âĒ0tĸŋīk}­läÐßŋ‰BZIôũ Ôi-“ûÄv‹äĩāûCJĐųóQŸ>―Â0ÚTûŦ ~ųÆŦŊ•” ;C”~xÄ|6ŨZ7ãëEãëÆĨlF>f1ŒüPƒ€v}ó-·ÆÚũÞ{ïõŨ_ũŒC >ū.ŽXRë<ī`ččŌ@ 8pīN! Z$ Čqãd@Ũhđ<+4Ô ŒárÔTÓ7‘ļŀđsgÔÔT#‚ũmā97įkŸŧ•ŠxMņā…kRJ $ ])ĄuĀöģ\š*í‡2°„‹]lYėEÆZâg ô!iÖD‘qr‰­‰l ŋ455yôąŨÝpã?§ÚM(UÓĘyũý•ÕÍ%rØ] ۏNüŸ(·p#ï* 2 Ķ–>ĻÜyäĐößëÕúCŊŠd%~%és·€•ėåĘĩ!ïŨûctąė)†ũŌfšQÜįĘ >Üŧ"TVVZkýԃ €u‹tÓ₠E Ktïm‹5 kK5„h,/YLÜB…LQ.ė’•YŊDĢ‚:TkŽĐÁtƒēš%6a(yēĀĨd(äDēx\Œ{įr)eb.ãMuPÎþ’b}ïũ_œõ6]JēŅ é@ûßËÚ$Û&9‘ŽTB%ī.1Đô#ãĪīūįËķ›6Ț‚ný>ņLΛ'ŽsĢöĮüß0߇ ‡jāķ{ đ<ÏæņïS-ÃÅō^‚Þ/†ýĩwŦōsSDÎï9?gÅ0&â€ÃÄO€€Ž5ūéfģņØˆ[Į%m6›ĐÖ+^―?‹W­..Z)ĨĨJ·Čt)‘Yó6ˆqB8ĸ˜2Keú ”†•Õ‹:ė1u)ρÜęŠī­ÆĻƚ& §õ€Œ!Tdž! ų‘9k“―tÖų́ąR0ņZÁü™Ō)Į6āCzü֟”‚É­Ē^v ũ–!lú ēÖĀæVÚä‘Įš-Fä€h―—ģ\ŲEF~ŠČ9(ÎOĘ:)ĪÏ)ðĶ_đ0‡Â—†­&eĘŧwïND1ÏŪY쯔 !ü˜Cķ Ę" BŨģ_:ī€ð™Ã!P嚧(c0ɒitnžmž‘ ?@"fÃ,°pÂŋYÂŧ‚)Ör‘Ŋw}îĶïŧŨ·ķŲ-‘Äxž'ā$GïŠ@>$D Č#<6C)Db'č,Ũ­ZJađiĘĖ>8Ĩ€„PŒķ1Æ"‚@d‚6RH­Á;ïd’Jzč°aņ(AėļtéŌ Ī”‚á Ũ8n`zƒ*øš~äŊÖĮäOã… EÁ‘§Tr†Ą`\ï Æ=°Î!Bhk­`—B ä`r”JĨđ<§äÆYŊ/nĩa$ōíBāóīó*1"áe yä‘ĮfHĩB)ÎËÓĻŌëgŊMaŠ’R‘sQq ï)ąPAimáŌÖiþɟX)2d k“yÜ”B†Ÿ˜ ú۟ĢYýŠYˆŠrY›#ēĄË5Ų͈Ėd;ä\†Öã ŋMĪS€ā›ŦZkoŅë[Ū‘1^) BøiĐĪpä8HLėã…‘*^ €0dĢ/%‰Ž—@ĪŌiĘũúōČcģĨZŪđœĐTEŽĸūŽã1@0Ö°t‘€b(n=†đÜšnáŽsÞ?›G§zöęÕĢGļoÍfãÂV)ĩū #ÆwąUE&ņ‹ŠŨ~SžmÁØÃŧœp|ÏSŽėqüޝƔŦē—ý–"aà .?Ĩ‚ü^8kžW˜ËņŪ æVŊ Є!°1y·)Ĩg[Ķ*EÜdPJ ðģÎނ‡Û/Ļ’"g„<ōČc3töâ2„”\yÏY°ÖģRĨu„BúÆ%o§b‰'Ž|‘ë'zķnĩõČ8Ũ+ö=ˆģmŒ1Zë6ÚúN·+aUEvÉWÍŧ9öꝎÛķÏ`hƒeÍ ?ŪzĸÍʗ*Â55xYĀČ:-!$ ——íÐjõ%|\‚” DŦ |&˜āRW`…%"pÚcEr5/MÉÍkŽ”:!_c‘X„`}þy ķ­Č&>ŠQlgó―‹―Ögī.ū嘍ð2ĸþYß~2ˆÜri?Pē1î><6~UËZ&ķī8Ĩ5{žFÎQΉ 2F žô— Ȓ”"Š"J”’äŒ#'ĪäXŊ;”wčÚĩ›ßĸ™?þzí"~GŲĨļfunę;uŋÞãÚg~|ĨįŲķčS0ðļÞg\:ø†îĐnEūŒĩ€_}ą67c؃#_xxäSÊF„.lŨķ~ȘuĀE:‹ÛŽ”ŲÂ$^ðĀŪ(@øĶ %OŲRŦÖLX·.’] Ė"@뜷\ðãŋD~Ö9Ąåx‘žtâÆNðJySíVpÃđíbðOý?Ü’öíE―PJ[ßÐYÁE!ƒ@ĸãSėėūû Čãŋˆ<Õ{Xādō6ēJ /œóUž/ë {'úVŽcĮE–@EKā,I•\ĨŽC§![ląhŅĒX{‡‰­ßkÓŪývƒ+ĘåÜī*Üî˜3wûqZ X‡š–lES=ŽÃð’íÎíq‰,_iŠž_{Ü =úôP8īcÐɑkŨUp@–ĩ\›ep“ŊUR%äëŦoô=YžGˆí‹Ņ°ūâŦsëÃŋ{ ĨZöÅÓ=ö…Pō;܉˜ô܃ž4]ōÁyäņ_Šj­œ%)ĩΆ‘#Ãŧíū8õōĐx™Č“ËđHøTGrˆÄ ÐĩkŨAƒYk},ŪŪzŠõāŧÁÖPUR,˜ZÓÃöđįįJë0§áŦģĶ>öÁ^ôÜMÍ&ÆĻŧÔå°—ÄÚú0j.Ōo8|Ŧ\Ā „ģF°ÆĀëën2 #rN%ÜPA:EÆ;ÛrņČG+æ_Dðŋ%ë§ę‚k­me†Qd@H­īwģåjrĢAÁÚYŊŸzÔĄ?{hĒÔJŽ]ōÕ[ÏžØ"eýŌdŅ„R`FâāúĨÓß~öÅ&HžBęĘûW(.ý‘þD!ĪŊŲý@ V•Ž>ųãĢģWÖų?…f>Ïõ—TļþuųĆ%Ýóøkõ!ü!moNKüâíGũę”ÃN9i(,|č·7/j@Nqþ&ãĩЊiáĪßÞýÄü:Ąų~ü㈊ō뷞zsĄV:hsY!•?`}V"§ŅČ9ï>üčëӄĘ7Îĸ[ČS-ƒt Dbúįœõ5(Jö™Q،ŠcKĪs6†ßãŠX™Ŋu4Cē2—Č >\J§7ÆĢbÖZąíúql# šfŧ|~v§íöíÛĄ;ŽCmT}ßâÛ*ÜĖôĩ·ŋwŨï?~~―?ýAݎč‘îBÂÎ^ļĶ[‡nÝ;õ†%kČī#\„„FŲ·Ö°ˆ"ā0G˔ÎĨ•ä9…\6 ÖrrŠK}ĸNã­jx›ËúĄ ųarÖÛĻcŦ…Œ—hYP&‚Ą ~Â;,XÛ2õÅ?ĖŪG)Uā#žPō<<âĘų3>?þ›:›Ę$O)ĨÚå'ŒĸėËi9RŦ[0ŊŌ @ĘU,ųš>GĄŪj嚆lõŠ•u ÕóĶ|ôéœå þ7S ĒÔ.[ũéĮÆôeUh%Á…KįL?~ÂÔY DĄ|3cō„Ï'-Đj)čP(ĪÛ4mŌÄņ>›_Ņīž mÓڙģW– Ų―koÕq‹ã.žtHæš*ŨÖ4Ö|óņĮ­ŠuÎ ÚųĘ NRŽĒy3§Œ?þŦÅՈ$S%Å=ŠW.ž5áĢOWÕE‚ģäjW͏ïäëUĩJ‰„ð]óĖO&Lœ6ŦÞ™ŌÔs~8<Õē  uÆ@PÚË Ž)dÅū!V81%A ?þODüŽĒhþ4aâŌe#FlkžžŌËÏãŠ6@ąa?D! ķ2ÔĒpČ í  fÔOžR?ĩPu,ę:ĒüŠũžXÕT ŒŪĐn;Ļ1 įĩÐyĸÓwûQŋâNĀ(ÕĨĨŠœudĸVÏē0ÍEzC2O‚€˜kÉųzÖGē –ģ"ÖøĪJN">@8įëY(|í/Xĩāŧ―A Žģ(Q Ąīō‘k’ÉÚ‹°q Īh\2ãÕŨœwÝoš­þâųfō$ ^īUO=á៝yōMŋýÍ}?6WĻ”„ŠŸ_|áŲWßôŧKÎ;ã‚ŧ_X―|ĘŊŽŋlJ-Fߌ?áG?|čÃeU=pų…ï,Ū|æâs~úóģŪŋņēŽ>ë™/W Įņ‹ÔļrÜ5g}Åõ7_uÅ//điiĢÖ.xðînŧíÆŸžvüŦS—)õÕG/œyÚ9·Ývý žū,JĶ^ũˋ}Ûmã^šļDiå?H5VÎyõ•ũVÎųðŪÛnŧõŠkŪžōî•Y•ýæËŦÎ>ųôKŪ―čǟž|ĘM_ŊvŲ“oøÉĨÍļdʋŋžðüÛïžýĄŨ§ ‰JĶ—ÏųóĨ^þŦsûŲuã0Ļĸþåį]zëí7^xÁŸ/oÖTĸøļŦÏųųewÜuõmo,‹RųpÚĸ&ōTËąÞŧ kl†Ü aŒ\ˆZiGÄõ)zžåzV3g‘ŌJ)M į\į.]bĨW6›ÃqŦŦŦ•Ríx–ŋûöæ†7ÄÂÕđēðø!;AL\û^,pDJbyĮTSQ[ DYÔ<āëÏŝßzý~UĻ`œØû§wnõč­#~?°h˜ËƒĻõÓ}h"į{ē^ ዉS||ʎ‘Þõō ĸQ%ŒÉĐœŨĀ ŽŒ1ÄHZØ’Ģ(üĪŊBĒtncšįKĪÉž4:œ|֙§ïŅéĩŽá°€ n™ÆEw]2ŪÏ1·ūõæ_Ï=vL/g‰ėÝðYíčWßzãÏ_ŋäųŧ?XT:Žĸ”Þ[:oüããg,ûä­O*}ōöŽÎûŒė\đzĐėąï͏ŋsõŽõoN[ėĮJR˜úÂïžRøÜKýë;–N}ęŪWĶg:õ=ûʇž{úąĢvčōŅgÓĒúEOÜõčŋļãÕį_ļöÔý:ęs ?|ŋÃķ‡ßĸäCį48 ũ(é=ę˟=tĮcîýýý·\r\wģŽŅ A-SŊėŋßÏÞ}ųŅ‚?üj‰ģđęšįÜėÏßŊ.~ÃýOĸîôŅ֒3Øēžō„ŦĮ―úĖ]Ų_YÝTûÄĨW~”Úã‘GÆm1û―kŸTĸõ+·?8ũŠ—^ûÓļ{OÛŊŦČ9@Čãŋ…žØË0y–"$āq[_|é@yOHÖZŋDÞ!SĨŌŋؒąĸÆ˜É“'/^žx#ƒgaO:ÉÎ2AĘ™íārUQ§ h`›î­Ę­”Āą‰J2ÂEMk›j`JËšĘTaRÐåA—ø ĘtđßCïöāœĘ% !zÂMøÔđlK‹T*ĨÓ\ÎZÉāđ[ðžß>uĒD?<ĶīōÅąŸôÂȑCnj’ŋķ6ČŲ—OŽ.Ž~ũÕGjē#îýÍo+*–Ė_}ķĻūŸ–öĸËV-ĻL0"^ķU§?†Móf/ķį~EE}†nß-]Ų$wŲsïž{čŅlÃ]7þjÎ'/ĸþ‰†ēĢ~Ý' F>āĮ?čSV˜î.ÓbŨG5Ŧ+ÃÛu/ PũÞ{ĮÞũÏ^Z[ ·ĸėōÅĐTKíĘ­·Î4Ž^øMuã‰ÛÄŊ з4‹N§þüĘ)\sð/wŅo/b—ŪÝbžåī1í&g1,Ã/œsč õv‚Ą>ëj›LŨþà r.Q„€ū,iæW­­ØąËĀÞeL{sįþĢví6•ÍÕÆšŌ Äđŋ5ĒÃýTP"é/äZ;rVĄĩBg=ÏēĖ–ï 8īŅO=%œãŒá@úlÎŧä_ÓÏ/ø.„ r~ÜCkĩ‘v―QĻĩsÞû˜­oļũ歋‘)}ņ›oO>e°Ø“!*î\TÛēp~ķ)ýþŸ^_•ļé 1øÃ oĩ\žsÓ♟Ŋl8ągQývnūáøg‡\9íčÃo™ō‡Ŧo)~yÆķĀQ.Ėy•˜h―"Y—*ëÝĩÃŧÓ+ĒŌ‚Šw>[―óý&ýņÁũ;î?éÉs―ðøyY*éÔģk*œ2yæþýú}üŅĮ•QoŠZŌÝķzáÍũĸxãIŨ=8îÄÃöė*Œ%Ŋc[ĢŋĢIįLč °Ũ%—î|ëcŊ,yĸÎýÏûíé§Ŧ(‹ČXÛLä °ĸ°îƒSc^~øŌ ˜æ&WõÅxZôþW +FĨį―=eĨŪZĶūũWŨw·­û”ŧïßg;|bŪâŅˆūj#ä]…(4ņŌ9Nm!‹äą^Š aéCb@pĖL.TZWTVÔÖÕ9įځû–nL7ÞS‘"[Ģ]Æĩ—ōp9įrvdŊ!ÐÆæ"gĀė@hR|]]ë°ey—‘;_ø‡_žļŨ/v=â2`<õÍŸVR”ÕšÕi™^ïWF §•Rø‰!ĨôáŒ2^DÆQäĮ Ø Pp Ž1ÞրČår†7Æąa+‚ðĩ­5Vø‘eįuĩ $Fačũģf#ųK-?úӋÝ;ãÄývÎ ąÓé'þóW^ĸAÅlÎ+QkÕęŽMN— šāâcÎŋæä}žéÞC‹Â’þÅΚtÂŊŊÜwïýlSý#.Ûŧž°&S>ļPe_}äĶG_†MqĮ”Ģ<”.2ÓÚŌÚ§zH)‘_X%ņÚĸ+M)˜1áÉóo{3M ;ĸðī~ŰHu”RzxąJOšųæđ\žĮîo—HęóãË:íä3~ôÅYGũž―<1rđ­JŧBŠüÖƒœD°ĒđÖ!- Ō: d3mˆŽ‘Š+ÍŌZ·ZĢ(  ÐŨ°Æ€Ģää46a_‡\üúŽ-›ĨcR–ĨŌ)r.Ė”ī‘%DÁųQĨ•PŌ‡„ØÁDBÃÆmŽęɄđ~ußū™"—ÍæĶšâƒĢŒÚv·Ģ Â\ŲnĮßūýQČyÓëÄvĮ\õž§­mĒž=ŧ`dŌ.§{m{Ũ}O._Y)RĨ―zuKQÎöŧæĐÏP„þāüqœ/‹”Éå /yúe™)ĘåƒŊxæYËÉKŸ~%~Ä(}ö Oēte$tũž―‹SĒ|·#þōÆN QŠ{į’šęŠ‚.eúûŨ­k4ēKŨÎba9ė„‹vS#tIž]D:HąïqŋÜí(īđ\é°17ÝĩWš0'†pÏoũÉÄŋ xðÕ'tĶ ]ïų힙p{žü䐃"JõčÓģĀæķ<äŨόI‚āŌ]ķŋýÅgŌéŽ.Úî7ũ?ĸMÅ‚ ĪSgŦ ~zÍãö(ęØąHLåręĘ>€øeōiˆß?ōTë kę$ÖÆJ)$*öŸZ)ï!8â„mĐ9h–[·&H&ēė‘1ÕÕkšõč…a[i—Ÿzð‹Vúg{tÉR‡‚ĒŋŋAr@mTąÉUŠLîïeOþ~2B‚ÔĪDŠÝjE:Áf‰đÐ9Jé€ËRc§óĀ斜Ėą_—wKȅ‘āaoƒĖБ5ņ‚ß+­ÃIH·äsŊlsë(―ąĖđÓĨečÏü#ŠtyYšR)ŽnÓéĒ /ÚL-‹ŽÝûvōĐŋjƒÂēAC:pÛw›1SX Þé"SXėW€%ĨÄŦ °”/­8 Š ß Áü ~nYtéŅŋ+Ó…ÉëtíÓŋŸÅ‡QaIĮĨøŒÖ=t:ð(ƒĒâTōœ Š‹RÄŦâŌbū†(. ˆHĶKú ä[eČ  ”DĄŠJKýfŊ.(0`Ý1Îbé7hˆI~ŠĘĘōšyü—zĩÜbïŅe- ÜWwûĶ­d'ZgɁC"^ón{*“Ō2āîĪc žČfģ Qų­üķlÛB$_@āŋX@üCĀ-ętÛČqGÎáߕŋ`Lm PÂwą°á Ÿ\˜“1Øö0 Cp” ō%'g+YĮÉ"ŠŒ ũŠóýāû‰XúÆV“RkGÄÖéĘ%%Ž!°1QžPIgacĄ=GŽįē ?íŲ°ý9Œvī_mčA"ÚðEýĸ0ÅKßúĒ~Åo_lāŠíWÄø–ß?Oģyüũs…īNõĨ”ˆŒáÂQ”Öï'ËF_ÆÛ°æ’Ņ)/›ŦļVŋŦ„MTccCKKsŧŲ0Ïķ‚ÁðƒDüh Zŋü34‡đõ<ëÏšïĸ _Ęų„4NXðv݄Čūāh"㌓JŲ䆜WžŲ„[…äŠ\6gÉ)íõ[ūW+‰•š‚Õk&Lþ4’}ÎļŸā3" 9’Ēĩ5l…<ōØüŨÕĒũˆá\éƒÅP$‡g„äņJÁZ}v wū,uÎ —Ęķäœĩ åēaķŸ c†”ÞČŅ™ä+ĘQ”uQÎŲŽģ†€Ļūđčo%‰D!ĄýUÁßS­%ÛŪT!@ō]aä:ĻĨ%'xÎ9'„TĀ4FiĪŠaã/ŨšœF­oEv]ð8ŲČ Į›y‹^?Īë tÁ­m~œÍjx[Ï‚1>RByl†Čũj‘HIĨŲŽØœŽ„`Ŧ@ïZUgšr6„âīčYĶŧëīFČcSBžjuūž%*:ˆ&4ĪS Āzï`QŽðžŲ^į_W_7k֌‘Ûlãúi…˜§|ŊV2‚ !ŦA –ø+†aŪēąö“Ęy˟špúøę\UģÍĨP ĄZ,@FÖÕ6īxÆØôŽ-ZqYoY8âӚ/ ĨīÍ-NĻtyĶ$† M-MŲÅk—ÕŨ5AÖ44ÔŊŠ^S›k,VášÆ†ŠÆ–ī$#Q Ÿ’hĀąÅÎčīH€čoÕsš'ÜxÝĩk—Į”f$,#ŪÐïŧį?ĩ sĨJI›Ô°Fi­R7s "Ļ@óČ(!…ß‚“\E đQęŲæČ}SÍ^ŲēĻ2[[nŸŠĨKƒÁÝŌÐŧŦTžmóØīŠZ™@ø=œ ˆ;°\Ïķæēg6cŽąlį* ĮÁ"ŧšœqd–,XPUĩ6N#ĸG!­·sĒlá*;Ÿ8bß ö:ziíęWfĸųˊŊ&.ý|ms=ˈÚĻųĢEģöė=\(č ­Ó#ËvÆoĀÐRMĢu™ō’LISssu}mm}ÝŨkÖ66В.=;õPZɂÞĢĮŪ}:vKŦLJZ*2šƒ(æķĘĐ@Z%ÐZK)=™:įĒ60ƄŒxžØOŽ}þŲ§óŋž“JÎ:äq]GÎDF* ČZ'jÕÆDÎY‰•ˆü[‚–lđðĸŒläVÔDsV6Ï[TæĻ(`ŨþúyđĄuĩ•s[B-@Š{Đ$B›ō―Z@œ"-•#ŠĒP0ų:G,üЇq‰@* €Lđ& )‡&’R2―víš3fôéÓOŅŽjÛýč‰Y2.HģQŪwũgmwzģi^\ŧôĨ™þãĖWëÓ֙ėēE3*ķ؟ĪÐ:HĐACwë0zbÝĮÐ"WÏŠ:}—cšdĘbrŊŽ­ZQģrŠϜQœqÓAwĀßđ=ķôGÎZ?"ÄS]œý•ĢŽw―Éårqõí}püũķÖ mä ä·õâ}ŋéÓ§eģÍd 刌ĩ’ ļīuˆ ĪēÎX6Ģ%ąQhīV(„q7FųYÝdįŊ g/Ū Pėĩ[ïNåi-Q" øŨdë]þ[Ø7ãßûAKέ^ÓôŲäeģ–7(…E)ŅĐHmB]ę<ō―ZN…&"k'w;âOÁZÆģĄč󞟁֚ŲĖIž4͆9gíÂųójjŠ;wîėĘ3lûE›ˆļ›ÍesaÎ; ļĸEŧ]€Ü6ņũ%=Ō_Ėĸjâ’Ųû§ķUZĪÓĨŠė؞§ĖmX:qō’ýúpÁ>'e›šÖÔUÕÖÕūęó9ՋFũuĖŧ7T7ԙˆΑ(īšécƒĢDRJ_n·3Ęņ oq§Ĩ͝5ӄFüœ‚ÄzA"8–gxģZëŽĸ“Æ_ay?oøFCÖŪm4kŦ›wØšwaF™œqâŸ8ĢŌB+ đÞö[Ũĸ)d{2küŧÔŋĮŊZKĮ‰ËþžþÛēŊOYIŠS§’ekzv)l ―„/<6g/!xŠßYįEĩƄĀ3Đ­.*HHå‚{ ú<ą”Jr·Ø~I-_ķlá…1Õna7XįcēŲŽâΜæ\sAŲĐįĻBzŒĘ@ŽŽíģ7ķîÜGHYRTĪRÃJķŧ~ā=_-ÛoĪmŽ–WŊĻŊkX^ģ냊E„§mDšĻMƒļj!€H‘žÛúûņ ĸxûG˜ˆãw…IŸ}Z_W‡Rpį9~ƒīf&&ŋCč­,§9ģÞēÕc€CŠāĸցqf­TēŲĶ$ ؞ĄPaóô·Þž1oYqũ-GíąIӗ/ŋī`ĸ~Tš‘ĸąØŠzņWË+ęĀYЋŧôØ­kđģ҆’m%ņŽkû:6WĸõŌeĨ―‡fÖĖýë_?ÝþļSûĢuô/ĐÖY-I-ÃÐZ>%<6ŠÖoրuJų―/ƒūˆ^ ūa&P’C"§„$ĄØīÔĻ”– ŦÖŪ™=cÆČ‘#ãmz`ü#ÃúöBÛcAkžÝ†Ąs.g{ï8ŠËð Ë&õ+™ôõ·ØéēýŽ/­G‚”RjhĮ>C;õĐŦŦ[]ģĶšĶvųšĨÏ-~~qíōÝûî°Wĸ―šęšýeÛĨÄŨQĄ?`ýlEŧcüģBˆķŒüõŨ_ϛũ5F„āo €““ĸI­ĸé„üæŊ=ŅrŊQÚe]…O kÃČå,:„öŨEāįwžûĀKËķŧË7ļû|ļ‹žũÚëŸmĸĢ# ĩģÎ%”~—M`!ˆ­t8‘>ĄäíÕ%Ų/žųõƒïUíķËŦgýeyuéAįÝuÄA{ 3Bh!øŠhϙ^Ôoûî2‘qzoʔ/kr˜ãûoĸåŋ "Ę· ōØŦZ?oūžå~Ĩ’ėŽ  HšŒÜĮ€Ą‹$Ëô―!—ˆ‚ĩý(Ĩnnlš;gÎāÁC”’DômU-ÃŊkkkŧvîš2kšÖÔ6Õî>htŅ„Įęšëī],ŽžðóœīÃá§ėlώ]›ē-u ÓV~õûy6g#4зīۑ#)ØuíúëáïįÛŋ·;l―^bÞžyģgÍð^9.Š"!dý‘uĀ28r­óuŲ0”ˆ‚ÓwĒ0B؃Ęēwĩ€ -d Xō~<íŠZē"UÞŊó;ï>õö6―wÜf dmÆÔ}ųômKŦ–ÏŽËô?ũķ? ĘTž6îžũ§W— UÐoŨ“þãwšĨӘkÆlM/^ybí.WŸ{枟þÝŠÎþðˆýŅD  "c0#K|Ę%“ÆúåüUŠ+―ûŌĘ\Ɔ]rÝíÁâÉ_MžĐyX•mqÄÞ%Ŋ>~ÓԊ\íÚĩ‡_ũâčÞÍŊ?}ŨÐ#nÚ „q’Ļ[úÕãŨ\šˆR:öøŅÅũö/kßð?8‘cųMyäuĩ~›+2‘ûŨšMg 2Œr(•ĸ’ü’ģÆ'<Úërbšš§Nþr=ũėŌĨ‹sŪ-ÃþģōØ^+åvíŋë6ÝGkķč:dXųĀkŋ@Ĩ[ŒëØĐ°ĶĄâæ—ĮЎÝÏÛõЊúšUkW›F(Č4æęČØSv:ĄOYŋ•+Ût6ŒvûuÄøĮ2Ö/Öwikjj&}þymu’Ę㈂Ā;Û:™@đČXÉB„ĪYL­FļaČ}Ndð“fÞ6RĀErLĩ ‡tYŒūāžú{ŪđũĖß>ü'sn fÅŌN‡\rÚõ>qĸߎvóuzÁeũüĐwÉڏÚãĨIû .U_MžžEFMúdb…œrÔ^ESæOąÛeιȀ0K(ģ.č4Ī_YŸKĸĀÂ`Ė…ŋ>öƒ;ÎzûíONýáØGýđãąũžßČ([ŧßYš·ï8sú—Sķë>0[ģ6ŨŲ4aåÂ/ŋœšęð_=Ī; j‰þY‡Ú€q›fU›G~0WiFQF*.a…áœ'k–„ná!§ãX™*ȊQïPÃY[WŊZđxņǘj…íJËVÞēė?ÔZ§L:2‘stÖî'ŽŸ5AĪ%4X' 6š:gråŧVÖUUŽ­ ›Üɝ–ØeŲtóÁ[­Ū­ölËķĸļĮÕŪžFŧÂö‹âļK;wöLĨĨ1VĄ„ä—rĀ.9É|z9[C°k8đ0Œ”’%ĸĩœT Įˆx―ŅÆTÉUgÉ6’LĩĐÂaŧ\ø‡ýõŋ9ũöÂmÎÚŦŲ ŒēnŦ=úŊĘęĨŒŠ°Ð°dî[·^YŸÉ„õ+;ũK­l†fŦŠsXAØh`U=?ō þõšÃßðãžs~ïōô†ķžļŠĩPz;Œ<ō؄ĻÖ;Qų°n?ÅO ŸJDˆÂČđĪ éüðŪÏč&bįïVÓ(|ާ?ąŊŨWS§n·Ýö~ČõŸTĩíĶŲl6N{į…\”ÛķĸöÃŧ ŸU1_ ŲbDĐĀ EģĶ9iø,E°rMEM]])•oĐKķŲnHĮtyKSËzŠô‹õŨĸ–fÂŋl,xáÁ”)“ęü4Áŧ>NK%Ņj‚Ī”ôí?€f#’BōĀŪcŸ_ŸŊņ“MĄ„@Ä@ -“ oHīÖŽZ]ÐĐGßÝvÐu_ŪZ­īÄHH°JIî6]ÖŦGúģéÍ9ÛAŊýzúĘÎ'öë1bpáw}ņ%þôĪÜ―ŋæųÚmN|ŽG1DÍČŨJXr€ęŋþâЋrÅۏ1pņ™ōūG|óEĨA2i —É 145EÅ0ũGgv<ðڛϝxÓąŦ,Ķ!„SR •- ˆķ8úúm9üžcĸxŸqð°lÖnĻŠ% Ø|U›Į&Gĩ>”ÛÛuG‘qŽ‚@°b”đÕX눔RËČįŽŌZĒôB ÂXƒÁYrÖ-œũuŽúÚjŦ­ŽĩBˆ ÖģíÏår–jýpAqŠpėČý'ŋ°C41UPTœÁē,Ië%‡úÓą ~ú‡sũΈæ’ýɘĄEÄNĢ:~XŧįŽCKë:ð…ïîyÄîĨÂÁRUÖ)―ōÝûî;õ g:lđĸŋŧd@ũŌÞ'ßPsÝņũŸúF&p#OđåÐ1ĢFí>úŋ?'ZpũûP|ųuœóIũŪ™ïßēhÔ E…‹2Xœ’éTPV"ÔŌņ/_{KC‘ē[šßý 5íŦtŊnÆČ@­†rG›\UËĶŨ*Šâāūđ„f)ЊC>―‘Ŧ9!Īģ6ēVĄRy7q­ĩp@€UŦVğđ·ÜrKï6ÛNÝåĸČŋ1ÛAā” w°}ąHEĄB†ABįĖâUSïoĻVÞŧ$(0ÖėģÅčō’Ōú†úv:­ ĘđÚ)gÛķÁĒļĄąņӉŸTWUITRóŸČ‘DŊu‘1BBLnQŦ@jÉÚ/Ô] 2"ôö`\ųâF5áĒL€Ei øh l/‘*8ä†ûvŊZYŌ―_IIĘEû\qįžĐ ,<öþ70UĻĩ<ôŌ§w[đŌ ]ÚđW:…ÎÁ!ŋyûJeu>ðš;öž<]Ļ(jÏģŸÚņ”k )í” ĀZ*ė7äÄûÞ­ŪĻ"ĄŠĘŧĨ…Úņ„›ï_‰AĮ oxzĮ“*+/jŪŦM•uÞqÄvB§%îĸӛũÔiÂcöðĻ–0ĖtęY\"Ēīޠ؋B)ßËc­j…ˆĒPk%ĪĀ( ―‡Ē§"äzÉđĪ*SBų],$œĖÅ2~ŠŦ<"$JĩdsÓ§NÝsÏ―bÁŽoM~)BLĩą…w0(…ÛØvŦ^[~6J:HŽwD‰ĐA–*ūŽ_e­+PâīG:ë6Ø hĮžíĸ. !ĂųóæĖœ@ūÜrˆR8g8= đ?ëý| t,üJąãđWĪbōũšQŌį°m,›Z!!Ķ )B Ú3;uíŒëm^]RĻÉ_#SâI Sé’!Öŧ ðYE~”žFðāg;t( ?‹AiŒ6fJŠûŋtqß>þņŽ ų9ū&_œL•–ôjwĩķ ō$%)aŲ$h“3|Č#ïėeœ”B+e ÜD!$[ÉÄËĀģ rĢpĪÔû X”\6úĀU­y&hÁ‚ysįÎíÕŦ—1æŧŒyv‹]]’Í}FYqŲAۍ™2Ķ $ˆ…õSāÜū#ö:l§ÃbĄØ?Šg=6ÜRhö’ƒõwwi?ûôÓĘĘ Ĩ•ģ`LBø*â…O@K§ƒ0Š$ âz’UN)řÆé r.4ži&ņ“ÂaK§ ĨiYZZT_ą:čSZ\J"§[üOšÍø OĖ…6„MkŨt(-*M‹ī›ōȧ0`kÉ㎀(ąĩT’‹2ģŽ‚˜g•–Ž­ŊŌĀēƒ•āū.HĄŽ1S§LÚa‡JJJÖŦūū―žõõrlÈŒÆæĶ1Ûî3îĩGŠj„ó· Ĩœ#-åŲ‡œæBnÛÆkŧ-þvC_þāo*ó%íœ9sĶ5Õ?Hžē^b,Ī`áã‰BŌ•Z8ë’ûãmF?Ę,ĨRE­ R)õĸþų·žPö+ŨÕ=;.ZēbʧÓŧõčȉÅÜCøĨZJĖ3ģŦWT‡đhDĸŌ>tqJä ylJÎ^ŠÕĮËĄD…’ 9dýŽ7WZE‚Óž‰€#œæ] c ĒðIˆLX‰ėīđĨiöĖ™qøBii"ĩĨÚv]í [ĮîĖná€nwéũYÕâ`Z@ô.Û62; ÛnxŊ-Ã0įÏúvąÁ Øoa[!Dėø5ųËIĩ55JÉ(2’ Æ"cŅÏ…đȑÓJqĒŧCŽžÂúyƒÅ (…BaĒ“ÂPˆūå:2œĢĨ+Ŧ-]°\‘RšžCņ]†ũ,ęUĶR 6䑟CDŪF­.ŨˆBņ‡_ĸ —ÐĻôÍÜ(ōņYāĀĩŽHIŋ―N”Ö‰ļķrMŽú8hP[nõëVÞz3C­5û0 @ų‹COûdŌ‡˜*"%Hˆ°9ũ‹ Ï.+*mljōgĩŦ[ĸŲØ‚snƒíZh ū“XA1}ÚE$P(-sđßŋðB+€þ FiœDä{QZr FÞd]kDˆlĢW+–ŠÁ]AŦNÝš”5n6) %Đä=ĶoyP”ÞԚ%yäDäS°œs>Ė[kíÖõ ę4ŽCd90Ķu07!h°ž=ý܁”"†ąų ÆšĐS'ï·ĸþ:ujËhíúí`ŒYyFđ]†íšCįÝæ.XĻ•„Ą%ĖíēÝ{î8: ĢķŒųmĸØ7hÓĨý$.i―]Ŋä^ ÂuēŨswRÛ  1ī "ņ3‡ģ Amé,Ą‹wĘ2r‹ŪĒ{‰ ŅæAĩi-ŠÓ"Ģó<›ĮĶIĩ…ģ1œØ"žSPJûŲ0Ÿ]ˆ„ėļJ õXK<Œë·ā}{”§"ėD ’œ]šdņīiÓößkí·[―øuÛVĐ'ē‚LÁ˜ŅûΘ=G I@–@*đێ;ĮķŠMþ”o•mĩŊaĄ ÚžÕæ–DėK;sÚī0úiã(átÁŪĘï ú7˜0 Ĩ”J*kYB_ó#•’&ƒsŠĖÚØ*aÞH‹SXž9ÕwÔŠRČ#Mj}Ā5†X―ÄE™ððÓPĀĖb­UŠ^ÖĒK ERîYc‚Tā?û !Qp2Ģ™1}ú.ŧėâmÛģĸĪžõ=‹ ĪÜiÛQéT†­rYÛĨkŨS:>—ËĩĢŨoũ=ø—úŋöNc}4>Nœô|šÔģ)īßÚRR)%ÂÐø›wD,―Bnm;GÖë ĒΆĩņĘĸe€ĀŦn9ðóԓG›‰Ēĩ.Š J%ĩ$ĮԃB§RœÕ͚ÐuÓ\€‚;’ŌĐ4&ðS ū ŅŠ5&B-9š<éóĨK—úŲ>ūíšÍw†ïĸúsa8jëmFŽNÐŪC:óØ{tënŽi7ąAïDŲ šÉlО\J9kÖĖŊĶLrÖÖ9ā:Zēô˜îD‘ö‘A–oð’8 ) &QjÖ %…žĨ’,ž„|t@ylvTË@bŽäÜúöŦõ†ŠJ+öîB ­48oļBŠČpį€œŌ*ʙ@‚OīŸĢ-đČD•k*ãÂÖÝâ·Ēí֙sNk <\ZRzāûfŌęÖĐóĮ›ķīÓëoÐpö;Ðkûöq,ė…ŦW­R;/ÝēÆ ôũ/âĮ5āœĩ.Đyú? PrŽóW x$„uŽ'z‘S$Ŋ7;ä‘G~„œuÞ-Åόę@ÚČ—lôPh•rdydV­Â0€2†ŌI +Aˀ3“khđBHøÅgŸ0fLϞ=}Įö_N4xŠõ ?ŨSísŊŋītųēcxdũ.]ýģlīk)|ŧ&ĄÝaJĐ%K–|6ņc­$ @"TB9°‘^øˆĐ ~9ËųÁBZkÐ:@”ZÛ(r,žĒȁb] Ķå[gǘGylv&ŠJ;ëHY–~ēߏų įgHņ.|Â2>=ŨĐÆŧÜĒā,“äL)ąŽŸ:Čær‹-|åå—v―{ŋū}ËËË}7öŸI`žÓkCŪaŌē/v4zøāĄZŠĢ9\+• à Šg7 '`xj^ĸˆ_·;KJKĮ>þh|C}=ē B „Ȅ΁ũsIčœlĩÓ_„ÏwJHTÖū!73ąŸRøQĸʐGyl^ Dc%Įji‰|íéČŨę @ÆF”JiþėLRÝ:Ēęk5ˆ9@!ĩBgY1ë]ScýóÏüņ–oļûŪ;?üðÃÕÆØ „ļ!Ž'A­tuķæŽoŊkĐ=hÏýũÚqŨAýä°]+ĀĢýƒßÚRØ`Ûaq,<˜1#.Ē9•‘Pc9˜Ý +ÞxÎ%rĐ åœļk,5&aRŦUŊ…(ŅZįýjÐWú›iU›Gy(6Ïfs(P&ëÄÄV Ð:päxüž‰—Ũ7 )Ã\HÐIēAļßų‰Č8rJjk LĐJˆÂ(Ž._ūlé'ÆũîÛg§]vÛvÛíbd2™ ~Ėũ•ŊRŠwiŊĮÞ_Īąū~ŋ=önįÕŌŪVýv/oŨ?ŌnŨ3áÃ/˜ïģ,…c=ÏŅBž„ÎXã8·†ˆ)”&ðÖ―ė—(B’# Č:ïūĻ”ö )d uūŠÍ#ÍŊŠ%R ģIBLsF)ĐD&ŒĀ‹– ŧ"‚åĐ ””‘ģYę”Ä 0ÏBža„LA”ēĄĐ~öĖO?ņØí·ÞrÝ5ŨžþÚkqėcEĐTJlČĒ4PÁÎ[˜œÍĩīėąëč0 Ûņl[’ýŽ _MK†Ö:NĮÆ ģf͚O:ÄšŊð]_Ļķú! UWWïŋßþQý3SŪooø4ÍðeŽ1&nÄ!įŦV­ŠÍŋ§NúÉGUŽZĐ$ûðÖÃąc$ņͰpX |‡ˆŽ"þĨø%„Ïdã_,Y!“Ö7Ķ•VHČČ#<6ÃŧŽ―"øÁ)”#2I‰JęČßUhõKäÜuUBfgkL â%J>‡ČiĨÁ$%Æ%dŦß&ŽUĩvMeEÅôŊĶžøÜģێ5j‡·ÝvÛxķĩÖ"&§ärđ=zī‹hlįSãÁįýí?ÎđxĘ6fęFžðūŪ6~díš5ņWCSƒÉ…MÍM--͖™ÝZƒ įJðÍhĨĸNÃķ "ē‘@žMáŒ#hŽëČĨR)ŒLē”ōöá@Ļīô%9 Ø‘Gyą—u­ĒWÃLB 뎧9­&_Ķb!Â(ō…' ̜HDó4 ģïĨ"°VŠOÓ g Y)ą brA:ĨLj9+P&2ŦVŪXýúĘņïŋ7dË-wØa§ÝFîÛ·o‡Ī”Ųl6ķ wý΃‡1&b„aŊc:nŒ ãÆÆļV­ŠZ[ĸMō―đĐ)ÛŌĖOÕŨÔTGđHHlŒåū”ģJJĐ*DŅZĶR1.ē‘/ýÛNāĸĮÞŲŽFQ8õŨ­;_AēÝ*îÕ§‰āR*D ļ“H’1$3öÏ­žë=UóÓ'$4$ē:TŠN}…Ä[ÅØ9ĮøK”3ˆQó&[ˆ™EđĖŽZ―vÕŠã„(æb~þ{NÁĨVĩ įÎĨÔģ0TÍ™öĖ„ÖmLŽÃ=/szqÂģŽ:·ēčŽXÚ jđķ‚*–$Ęæi?úøíüüėÝÛ'OŸ―zýĶ({Ú[>ã8 ÃÚÞÞÞýÝl./___·*uøpØmï[õÚūÃAӉ‰đ8Ä î)DXMšNé@@?ŨOðRŒģL™%•=Yāq‘Nžũ1&B;›Å{žfęŽŊAKWėãbĩYå­Zĩę8ŅāîŪfL°ÎŠJ™‹WG>A:8#ŨĀPIkė>ĖĨĀģúå^U1ZĨŦ&\ąx6v‘+.B]Ũ—2-KU39,ŋšĩïƒú +ôŸ?ūĸšļøðþėņééó/[PáfÓ>nŪŪþ4ĢþÛÝý8ŽŲ&ð2OãäËŌuæîÂĒĒMó<·ŋ°ïÕâŪ þ~~qM‹Ä~m6wQÚ#ĖīH0ÃúĐ,…N ļöėÔÄøtGē˜U™Ā:ÎöKÄaĮ‹\‰Lu.Ļx͌)9úzŠå(ĩj%{-1LįŽUQ [ĖĐ’ĪV`°§8|`pÆÄxsžÜUIRؖ bõD((Ķjū1˜`ē…Yä0GęĖ0FŠqΎDĨšÝݝų§ŋ‹ĀNAsĮ5„le=ë?{›=’ó ĢÉTõģĸ―žą”Iâ&Ë}Ÿ=XžĶ#<đ$ûŠ…ÄĮZŸ+sŧũÖþėĮÍĖŋÖ€ūėdUĨG8―”Ĩ"āîP07ÎINåbEĐÖZũ~LĪÁ˧ýŒ€3†(U’Tå+TÓģVîžójîöŲĖÂ;ïžóį2N·jĖ<.A{?‚>ŸŦ‘3IĘ ĄlÃģrdģ'3|yzƒģ•€ŅĨ2+IzG+āûąÚōŒFĘ9ZYæF BøZŨe4P―,[U‚ú|þųįóĐJŸŲ[‡Fę`•E:\ûhFË^·Ŋuí}&–{ĀWŌ՝§Fč"wš@âdÖIķ[·siˆX]V7]?IvUĻŽÔô *s6hē#Њúë7næwþĪØ+ÂKó‘?ÖZ§PŽ0ÚéÄIex€°Į;œģUŅ!ķ5§anVĨ†ĢHe·ęŌĖUJUӚ!P23AũýCp]qÎÞgũÝ<ÏiŧšŪë3ē‡ˆ°N{)ýûÍ))ĐÝY™ŲgVšĘ:ÏóæßÔ]К&>™ĩU%ÃiЀˆ‘ðtښáÕũnāögoW\$ģjŸÛŒFS‡!\Ũj܇ŧ𭟟ĸtÚkũoÚiĸŲë{įŋؘ‹’ŠĪĒû>gūþ\ŦzÜĢãŽn#-|J·Ų,ä~nĀĖđ|ígŦ!Äme•7B"čnķŸ-•ŅÃýÞ7ÔLX*ŌÜ<5înuŠúžÎÜös·`ąWTĐÆ·V•ZøóÜM(/6)ČĖÎģŅ_Ģ” ë~ß”cN·ýŨįZß4qsJÔ6·iÄipô“9ÎØþŽH›\ąÝBŦŅĒæŲ$ÃĢŠ ŽuM/zV™[)OŊÞĖÜŠ †ŅŌ†EÝgļÖ(3 Ũ Ū™yŽ―ũ1ū•ėßÛõZ*™Ĩ<#7F6Ä/_ÝôļųȍGíāöŦĢ·OágĖrŌXéĖÂNož+Ūî—Ŧ}į?G ĻyO ßĩĖJa"ŦH›rĪ ķŽÁFįߥ4ÞûĶča™)ˆėx§Z ę·íņkØírÜÝßôp›Ô.·˜æ.ĢõÅ|ž==fŠ‚(e\ëdVöãđÓ^ܝvŸc=ØGЈņ°Õ$ŌšųdqEx5WĨŧěûšŪ @wóØŧÁëCRO†ŊŸÉFvíóT[–ÍXYna ƒÔŅa=\q<ïžóÎß,žQæÎ p>ŅC2ēJÏ―)đųģŸ―ŸéĄ™ĩ;˜uRŋĐg?é, ręŪļOeĨ7~íģO|îÝ2ģŽŽ’ý;lúĩ@3·Y$Ŋmïc4ŸSĩ*ZG—.cyÅUŌÉ=݋uRŠ!mŦĪY;e'GĩŸŋÔuæqZ˕% ÛûųöSĻžûą&&ąïēšŨōŋ7’þ3ÄR5•” tëį?U‰wÞyį§’Āu]§”Íœú• @[q}úSó~nũˆkÍđĩĩI6šĐ9`šÛĖ,"Ū< ’īÏįÚÏÎŪđ ðþŠŠrķÔųe$ÜÍöóĖn(OfýĘûy ûÜîŨ0žóÎ;@@ŨÖŽv=ąŒ‚ōdį­Ėz†û̇áy6PáXák?s8vy€y#āIkķ_-Õh^%0Fī‘á7xŽ5+$ †Ū‰, rįģĮXLĢ=ŧ čĩĪŠ”oœžÝ{Ÿ“ŨšÔŠf„ @€ąfų…ŧĸîãc0sUežëŸ §ŌiîūũÉĘÕëó8ĘðÎ;ïü5 CUaÖEĢ‹Zeî*}ã›dœÝ1<$Š”FWŦÞÁT‘\ŸŦōčČ{Ę2GÕmiî4ŦLŨšÎwÓ4’•§TüšÛōë†sŽRFĸ\Ÿ2iÚÏ}~#ĮLÃcĄxNša…ïs#ÁŪ°­’‡ŧEfæŨšĀšŽl]DJ°`ÄڙFŽĩčl[hð9;+ãŦųGsēTßļôggÉ}8•UđŪuNfSÆüvĶ$žóÎ;Ŋ…§ę7dí<ÖĻV™ģŠšÛó<™đÖSÁ-…‡Š”åæUU-e‡%J aîϞĸ.Ô øZK@M·09đFģeY…†xũ˜žÁēŽaô%ã“{^ÁÏî̓u‰Ę#uČĀųÚÏ Æî[īŠZW<]đ8õũóX§žcnyF anþÓ{ũš.Ļ”iaÃ>SZWė6ŒEŽoųB)§ĪܝÓÚp?mvČ&ļƒC,$•õnĩïžóŧÅÉi(Đūŧa•Ô?ÐÝŽïi;ïýœJÚoT aFĢ`<đƒ^ûtóXŨ>Û'xž3įøŋ*Ww ŧÉÐö,äÔy5Ný@r·ét éËŦRĐu}œLũõđþ1ģjœíõ9Ĩ Āũ‰ąâūŸĘl‹—Ė~ŒÕR­ýæðĩŌŌ-Kf­€åÉJÅ ‚” ėXtū&|’‡Ë,ŋâŠuōīðķ֊SųŸeáœat·ÚwÞųs[-ûŋ†8ČD26ØāšįLÕvôih.U'Û"h§rRi>ëšÞH6%ހGĖv ãŠ4<cų5ģ1 ėS΁2ō~nrbbėīIwY[ ēĖ•*Á§€6’ŲrĮoĨđ-Ŋ’2ûþï8NĶģˆĩB*3Ģ9ˆý< ÃÝČg"ūĮYF§säe§NDLžũÝ^ĸkŠpv’ QyH“ōģ>Y5wŸā4ûmmĻz·ÚwÞų{[­ŌžgwžŽKUsīÕÛĻ~q6S„;ÓĀÖZ APa6ÍlŊ·7ŽrÏÅ]{ϰ@GØtÜx”JŠÕ)0'•RПôđũcæNÐÏ)aÓģ8a!`ïgpųy: pó1Ņ Ôyūų2’ækHęQ@jFĒh–ĸÎÔ웯ZqI8―ģ—ōŲ·P*xxe’“ų‹~ķējĒÎæv4 ũ―Ÿŋë`xįũXĖÜb­AðļŪĩũ>đ=Vũƒeé\ŨÕ_ï0ðąKIŠåSNc“Ŧ­Š>ğ΂čė˜söýsC‚ĩĸ·>û‰NņBãT—|J•ŲĄ3æY ĪŅÆ”ЃĖ†7xÁ?Ũ5đ6 ÅęĻÆîÚ1š€QŒMðãä0TUĨ&ĖĄïũTč??îäŌ’&ŠåfûŌĒ- gFÅÆē|vi <ũÞMmϟĻ$oÚĖ;ïüIĻUiĮūX&ísĀėÛnŧÁĪbWĩ-*ĶLޚëžA@ÜÏhĪĻ9SúÆ’æž:„™ÍÚĻCŽë$žŽŠ_í<„MęāÉīáÜũÞUét#3ĢýlyŨ5Tĸ-ŋ™åáėŊ{ïķüÍëę…―ØčūÎôÖļïĖĶŲl@SÏ™„ô- ę™úœž}&Ũ}–Ü1bdÏô]ū\í;ïüÅ 0a(ąÏó…ûfĘŽpÁöý„9mŽ\ §āë1sĀG{`4s›rÜޔcŪíŋŨéŊŽ oîŸԌŋ·î*Đ2·å! č{;aŦ KĘýėķ^§N•<ÖļËNžV‰}ûzÝÃčsïŅÝ·Û;Uũ‚cN·<)Č9Įq7­ŨUŠöąĀŠļ‡},ķF–TÏ1#O:IgÄĘŽBEÄŨÖšŪŦTŧ’ЊøŸęœ·…áwþhÜLpóëģō˗"Ü+Y˜ÝŦ’FŦ •Ū•Į ˆœ=‘NķÅËÝüŧüŠÄōȝŲŧkÄužãæŨuŅY*AM_īŒW5ðt2݌ÎĖú^lÜ;;Į ÚûrĢŠ†ĩÞ.Ų%„ûūŸģ'ũiĘâŠĩũAAÛ[AÁĖ%œįrRĘ<áŦôï /ßûą`ķÏDC|úZM:ïï)œóäĄ4•i°”ōÔKžóÎ_=œÖûėi”ôųz0Ô"2sīũ§ÎédîļV›0„k ŋųó<æaægïĖ# DGÕŦŦËĩČRV–2Þ2žs Ę:™FzDŽJ’ÏÉŦÃË œķģŽƒ9I ĖsobĖdؕS–ŪV=âūfôŽķÉJX?‘P\i%dĨ5É0ВÞų29Ų,֏F6bL{ßӕ>-dŲ {öŽÛNBÐZ+â-žyį?ļÕN-íä>įDú}îM؊˜ÜĘ j§ØķÔsčĪYŽØOW'Ð!ž“fūÜHœT°ŽŠĘå҉ĩũYá1―[D\ŨĪhâcîO71@ðˆg?YI’žg“,ƒŠÚAKsOÕÄ0šûýósó QĨpũ6`‚äæ4ĢõႆYģĻĘģ?ŨʓÃĒ|>­Þ­ÓNßĩŸí Ŋå˧{m­U]ųcfáž;ŦDĀÜÎÞËürmIŸÏåfÆ7DņwþdÂoøũýŧ!ü6w3/)OJęģŊc@[Ŧ|ðȜ_áÛž’$ ë; ÆOEšŧ‡ftÛgŌÝ_áwþâąXÓŦņkö ÛÁ€&&&ÜūÝąôĶ\OĐ`0Ņ0’ŠĸMÆöŲgį&-< §§Āĩ‡Į…ĪĐ~˜úœßֆĮ8's>īˆ)ôu·Ę*Uy˜ŧŸįV# ŧCjÁŌī@Đ֚bŪm4wŸž‚ÁŊlTkŠ FŌÝ*‹@Ž ŲŲ‚ŅžŸ[ ÖŊLýJĩęĢŽÚyJđVėģU˜Æõ‘îÆōq@ ›ĮЊ ŦYāęHYÏóÔÔ°Ģösœūĩ‘xK2ūŧÓė‘C. V·”ēæÏ˜đėĶþÎ;ïü1lŦhDiįa“—#ðÔļĮƒ@ãósÃl$S-! ÓõŦ[ūĻa ÝÚ)‹aNOVļà*ÐT23™5 ïģρ+ëÔ.q…K dßî[Ð},^Í#ÛšŪŨ~?øLkÃ2'lJSč› ņō—$aV6ŪëĢB•Ü\ÆóėYEÞÏmnq­}? šĀ1šy,Ã/#žýŒ #žđZČ܁ßŧ„Węt*‚9Ÿeexįŋ5/ÔÎ åX‚')Tu}>Œ’†Ė<ę†Zây6 Ũ?ŨÉDýAþđÚ •†Ė-e§qö‹+KŠp _§ŦĖ| Î>*MĪlj:—0„DÃýxĀĖÍėđošĄįdŽJtubķÎ―/ũŸûgBiÕ9ÖÅžđtÍOžÞ e6 a+OÓkŲÔðu]SŊŦJˆrMĮĨČö㞂>Ũ—ēmUeõųØãŊ1ũwþĒØëjčÜ; ]ëRÕä}­ŽŠ2ũā•YŊFƉÄþï$M(xîŧæc5pΆWęūoÎVIË*Ā`vrØ ―”z‘ÔT'DØúSðð][Gū PŽ·øâ+Æ]n˜ÓķŽ‹5Úx…'ZĄãÂ:nž ‚ŨûÞhn&í˜dV‚XvÝÏ ÐŒ4JU™æÁ۟č”ēŦ2gįFb?;"bÅÐÁÆ š9ۈý°*_ąŨ;ïüE ÃÎ]UÍ#•―?ĘÝT%ēu,d•JE·gåsčKūĄ-'ÓcuŠa ERýj֒Xd6âČÍr6^zØŋÖÁÜíW—á*IšTš’Ė<>+<Î>%ļƒdĐÎŲ-ķ}† po/šŧ™•P6ÝėWķ.Nö~–ĮĩŪĘʈ}o ū\č°ÚˆˆkWšî5e pŽ$œZ›*ïž›Éóî>ȉÝS'A€8MōūHûÎ;3Ŋ–ĪĮ:FüjĖJđ™į>'kđŧYå70áœ|žM#‡Ø•ŪuÐę8i ĘînĨŌīÎú·“‘ÎÕq\îfîUÚ{ÓŽC[ēýŊe)-šÄ-ÉÛÍ&p|ßëŠĘęu{]ŦïA4úï<x ”ef•? }Œfķb*`>ÚĢJ4LBeđq}VeŽö đ‚Đ","ōm؉<Öür)ûQÝÜ eÎļŪY· đŋÆÜwÞų“šÚ1•‚Ę―ÍėšŪģ“Ī]fĀÎĒņŠPGÍÎæ™bšYNøw›VŸ―A^ë‚tNŽĻáĖÅ+Œ<ÝfföÞnö“;ŸÜ+ëŸŪYrS…B>‡+ĖUzF<ËIŦüwĖÎģӀësĩ0!ÝýútÆX)ŪeīĘĘ[BÐÝėkBfŋ4Ŧ”™Þ ð}#a·ęÖuÁøs?Fãũ}â1zށ0Ī0ĸyîQ㊔™ææŊŌëwþäV+tĩĒ@zO•j(Zōų l]pfķÖeþĘŽĩJýŌnf^Y"RUÕlÁTēąĨnđ…YĻ*Ü VéŒ.Õæfô W4=Ó<)e{Š]šsē óšvžt·qŌ>ŸkjFÉpōT%0A9{XiĻũY3Ģ5ÆūĒÚwÞųģ- ‰‘―į&:F6Ð>…‰ģ1^Đé°É“ąâú\J 2’8'+§‘ĖG~KZĄęĖęj-Ī s7ģýŨœŋA\ūNÉÆ=Œ ŪdÏl 37áķV<Ï#23­i֒Ūϒ0ÁŋŧŠŪëŠðf$dæcœc?°ŠĸMp­sjqHžóÎ_œjÉ>@ϝ­™ú–]ŧ˜ĩΌM_ž†Ŋ,”bÅxX'{rdĖän#‰—Ī:%āëŽ5ĐĐóX óŨ0vr(‹îVøMq?Oe:ýė3i5_˜Ō/}Qĸïŧ››˜v`BĀP™l?§æ·&øü<4[WHȚ†G;įx87ŨðķDý;Ã,:A›c―ņ #FĄņ›œĀ6æjĖŧĪ ïžóÎ_íË<æąŪ mD îË;‰•}ĖU;nFŨuēʗyüįâuĸŠm}iIéŧ)gNQîßW•PH—*Ŧ0ud‚ÁÝTúęË: ĨÏįSJĄÐÛģT_ŸXeæNfļ~æ˜Ū+l3Ýܗ{Ņa€„jčgVM|L;Ï`v„ę‡ĸ,ĀŠÔ/<ņ’‡Ōu}þũóÓi î ý™åîF;§ŽsØYš™KĐzÝbïžó'uĩŠ<'• ŲÏ}Ÿ-š ý*”·zīö‘WíCįōE‹įg“ŒCĻŌ4“gåoã7Ÿ^EŅļũ9Ï -Č:1VSXZŸÏ@j\ËéÍ `x€ÖyäÏŲãßYûypD°{î<ĩÖ2Zíä7œĖZ1Üc IϓŨčTRôF@ ‘~ūnãÎüÎb/Čß@۔ŧKęį”3†ũŋˆÆęĒÓ܈Í8ïP,s—^Yí;ïüaŪvEĖÁ: uEĖn=p[ …j$ ItRFZeš›Ņ ĨĪ’7@gĨpËJ•͉6óš>—„3MāæY%Č~‹Įó”›ŧđÐ#œäsĢý;Rš9ôïXgĮtۘŒQ, 3Û~ãŨÏvöŠ7Í 'i$&Ž€ÎS;SHŽ,īŨŨĘLT­kMŨTæÖKöi’ÚiœėŪ gžéč%,óXũSäÎų+…wĢDDëwÞyįïĩ0„ųøŪëÓëޙmN8đ›rŦŧÂr‚īïûöIāĶö―ÕGF{§0°č' 7'íþy`Nî Qü–ËÎgíÉ p†ĮýĪOųˆ(&ĄFU4˜ÛoâĒŅôÜAŌN3>éˆū#ÁÃ{ŨN?qĄŅwtĩĢlĢ‘Ī~Uà įúÏį*Í ágŸŽēhÂDéFáwÞų{\mj4ũ“‡ĪyÐL•Ī ą0ƒðŪ;[@MþŽŲšSĐŪIXká{ aÖņØŋã•ëōˆøâW Âs?ĢĨuĒņÏ=OígWæõϧXUåūĖ|?OC*ÅąÏš·õ`įäfDÁ=ŪëŠ*•ŽėŠ4Ū‡9jë}745>Ų4þĪĮŋ“u”õËWÔŲĮÐ]5”ŧŊ+æGŒœ ó‰Ú™·+ŽEíĪJĪyįOZŸ0,Oš…―ÆÜwÞų› ĒíĸûlŌ|ųhQ4zsgâОûΊˆĶ_wšø ÄĩNKúĢ)‰ûū%ā·Ļķëd ēûþŊ_‡|îgšaęčÔņå ÐĻ*Đf•ŪÞ4Ŋk=?Ï$ŠMāËļ2óđŸĖãæÏÞ'ÏâÐŽČ]•ßHÃęíļ7eIm,^ĢrS'-žnšO{î<Ɯwu_Ŋ@ž‚  +'Ug$>m .‰ÄˆÐc ^Ž}į?—W+ļyuŨv•"`nûŲFŧþđĶĖÆÜV&nnī_”<=ŦãŽZ#•fÞ^Û@˜CzÎ6cøyîmÆĐr ‘ĀŸ<ŪÎ1(ë Žw‘üüóPö ÉŽ3gþU••TóĪĢ]Wœ+*”™jĪ3oøä·…Ð(Į†qv7kNŲ{HŧŸŸŠix,I4~ËÍš6íšVĄ&rlH•)đÉĖ.ŋÓóhÓĖüį~ē‹#ÎģŦ€WðÎ;ģðFú•mu LKũ7w‹ƒ äÎ4·ÎÆŪųæįĸ}ÎóTÁŒęė_æŲ‡fšîÂ&85Ų]û4ŅlÍ7ÝĻŌ~sŪëS%áÕ(āĪÁRĸN?pv-WĨRfø-ņ•[L$đJnáæĐŽĘâVØũī ’…Oī͢UÏģ)ûįsí<“LÆjāo―yålEû4œšĪ“ØoÚšVe=ûžþöŠoåąÜ%žóÎ;îX,ÜĖL%šÝ §dþėÛČÁŊŪ­•Gä DZŠˆ ýFôT>ũϏŸĶ€ŋ1ÞŌĐS4Ï―éŦҰŽŧwëÁŲ}Ēå+ž3… Sþd&iUŌ9ĘĶ/zDMėV/ã_Ū {-uįÉ}öŽļ„ßä—éa,Ņ ÂÉų6ūˉaýft™™Āģ™ų(ēŠŲs?ũļŪ‹$bÅÐŲtŸšôYibdģfKU04JâįÞy*,Šņøï}|Ų7†žŸŦyēðåQßîHļ‡ÎDīgï}žļgoQcK{†2ū>ŌDÛdWíþLínŋ $@wîŊüāwþ(@‘ėķÄgĢjĀ·ôÁŪŽ ŒĶYŸP―SÃĩ"‚þüïöî.”°ïGD\18NZ#ļēŌÍHŧ[=œÄÏÏífŦ›$ÍÏf‰r‚Ïs ļâSĨŠŽŌš"ģšĮĖ,ĸ2NÂËAŅĖïŸíŊ•†70ģõχ`g9:#Jt­Î3ÔjžpÄĘ=m7Ŧ/ß[†Ė2°ÍóüÆį9afîį$TîkÔÄ'S0{Áöwþ"ÔĒąûÞÝ턍ß܍8gũqüTsįļžžŧûbc…5t‚ĪMđ7ŒNV ĶĘšĪ’DÐ;Û[ĨÏ?ŸĖLiūBâ9­ĢšÖ~G‘Ĩį<4―Ú8aîWįÏĶƌý8åĶb­Õ1†wļÓ-τÓū)e2ģ–ņÞæAYVU%áŦ―aUin‡~E’íVKtģ*Ck0ŸóËöîsι֔øŪp3U îžųe ÓÔŊðÎ;nÞÂģÞŋŒæFXUŊ{$ŒũýäЉ­:íûšV·”;=܌9hUÅĄ} Ö&ÕÉ38{ŠÂ}]k4XC8TÖÉýëæ*`ēüg?0#ŒÃu–*k?G)s;™ýŒ6ąa*}ŪËČģũ8ßęÆÖ4ŦŠÐH›y|­ˆ(h,ķŅ~ŠĘŠb)•y]k­ØÏîūü~ķTÝ4Ą:9HÚÞ·ÓĮ]`úu@œįTÁÝëĪ 7ïûĻ’xįŋ6o#1f°0Ŧi4 0CĐžƒŦ$jl―Āˆ”‘āæNæČû'ząiOžg–8ĢÎ>‚: Îہ―öóĖSī·j>æŧ„аoݚYģļ.@į4W{EuŧHũ/ąÛŽŽ”fÃ6@$éfn―Ū–ĸú,š…0HU=ý[OœļŦ šeVišœ„9!l‰nĩēíŸs2ûņčœðï)ķ9g{ļIĢ=ðĮ*ģ$wÞyįÎŦŦýw’°‰đ‚(ĐŅ–íŽå9…)@ĘÍŋĄāâ45īÝ@EÆ―wžc]3é1äõŧŪuž­’›ŊëŦÄĘ*•Ųß7’sPfĨĖJAq­}ú‚ˆĄ_A™;ÉūĶĒ gNNîģ‡ūčĮ{Ðh>5“SnÖ·Î<ՂŠoÃ.ĀR=âyšũaÅ7Ŧ|ķrect—ŒíüFŠ&3ŨŽņŨ—ĮŠÓcá|đÚwÞų›Pë]HþäCōšÂĖ4 ÕÜë˜JcElHEōÞOŌ\UûŲ™Z+Ā_oØį“;ŦdáíÁ­IYô°oQđûtįx˜ˆ1đŲ,ÅÃŌšų>ŨE'ĀVŒ}Fs6F€ėWkį—•…Ķ\ÏŲ‡ĒÁJãtývz™ÜiΓĸŽ[ü"§& VŠ. kšä71r$ŦÏëö>4\Ũzžû<éīXąï‡ÖŪŲ0îkï}ĸ'ŒÞ.ą|ŪOÎ)ü7Õ% FpŸ-Éøïä>ĩb›_7 ũ(IãþŽÂŨŌ`mj(öoÚ„ĖBSÆýĀ$čW<ûQË Ūĩžû)åįŸŦRMŋĘHĄÉųđ.H4cīš.^sAÝj~þųg_Ũ# Û;yŋ‘ėsh …23Š˜öÉۃ”FA|ïĮ@áwþāžšÚ“-ĻÃXzDÎé éá€Äōk‘žïŧģ .7ŦJ52ŠL‹8{į>*t ÁîÃīUY%=§=ŧdíRau)CuņíōÞöú6Į$ŒąМ,ūøUÓ Ž:N.ŋČÆŲéˆ―A7þ>?OĐUš ū|]ŨÞ-ƒ-LÜxî4ï3ąöNhÆįĻ,œaÍN`]W#yˆfH„-ØĩÍÚČN%{xœûLĖÍįšÎŲU5TÆÓF2ïžóį{e鹖…ß?·‡­ļē$UJwž2wöé+ :ŸŸB:ĩSā,ž„$\-3ČÔšÖ7œöYŸsNî§ëÁŪûyLpssÞÏã$&üŠ€0ƒ*ŦZÞĀûgáãˆ=6ŌŨBUĒ.FÖ4ãšõv,j6БÐ ĨŽ.ЁÍéŽĖG1ú#+-ˆtwîįĀt­kįJĀúŽlQÚÔíüüïĮœNSÖ―ũÄ;ˆĒÛrš{Õä‘ŧÛũĢĀ„<@Â;ïüĩy o"|| ÜûŸR*âŋ.q™Û}ßÜĢĻšO‘—‡ĪÚíĸ}ŪįyhčrÜëߋM6~„’Ī”Žūŧ‹·­h%˜‡ß―QB%â~ Ō?ŸOI/ãfþqãYPĸRJæĶ‚*ÍI°ûlsšÅtRHpãs?NXm*ŊŌ$'ðēuįÎ]fúøjē;g­ö)fį[xó7įWÐ•ēđ>KYS^ģŽĶ&GBðœY}VN3ĪęÔ9ÚÉ]ĨoââsŠĘĖ+™'As7ĻĒYžl€sŊJ Ūĩ8[g—,”JđŊpĐĪ$mJšhքCŒ–ë7ąŒmxŦ}Nh§éáËÆgĻ&ĸ[šōßgWjĒŧg·íĢ-{ÎCŌč@UN­Ž?Ģ#Ėėþđa ó~%LĢJdq}>§›r!^#‡Xk…„nžøwÞų{PKÃZŦēԈøų\uōėía2Sø ï ēðYw%€ÕqVuJ@ÕŊĪ”&H―^Ÿ â9GĐÕUᙂÆ&üš>fV™Uē>Ü'ÕĀgóĪ3vž€Ė­)āÃqģ#ČE›Ä”šĖŲýģŋûīíK2œsz;ŽsŠfãāh5ąëyžðį›Ant€Bõ·ĢûÁŠmŸĖŽÎ7ĻgošŊŦCiÏxsųė=ęöIw ũ—=xį?ĒļH•f]gï†] .O‘ކ!ƁĄņ†­kijĘ5ÍéÕŌcuŠLB™1,*‹īY·Goā#=Ū2úu-HU"ˆwÞyį/DĊˆÖœÝ|9iæķŪ0ã~vĐŪ.đĐĖ+dfՙ”dUĢž“Ę:æöé>…ĖßÁJEU!3§mėŧJŧEFUÝÞąĩ `ķc€ÆķHÜŧ2Š+ÃŧX gyïcnU™{ĀÖŲûúČsÜéFũ8Ųë6=–į ģû™­đ0LÁ+–đ?ÏÓ[°{ũ·ĮåŸÖHœ•"mį“™JØŋžf4-šv'(’Œx[ÞyįOBmžl,Ëéw™LĐFüŸ'#Ž#ŪOUÂ`悊+Ŋĩōäy6dUjPî Č:æbvöɓcŦUý;ÝYĨ:rûŌŊ&óX…@ŅÝ;ŽVkđĪūõŋíđēŠ…oĸyúåþŊáĶ&Ũ…æ`·&ėŠU' h•ĮZęÐ\í1ōš–Ü Ąú•É؈}\ČMæ†ÅsÎyš…,•…5bf_<ā’ÆTGâBîVĐ*TŅÂvvÂNũĄƒ°ðTígŨ) FLÐ$-1ÏÝHvT ĐIürëŌķÜįïžóũæÕ՞“Đr3€uĘĖh1ËĢ ˜gÖooÂīœÆYŦLĢĖ‚äÏ}ÃH3ŠÎS}čÜjmĐ9ïû'‰ĖãfnūóÍ3UUš9Āû~ĖlĘϓŪëJJút―đ‘M†ōŲ§đŋĩáW|ŽrX ũhšX ;Íö°ŅÐ=žý d+ Š#ĢŅļŸC!>zÂ<Ļ{vÎSIã„=æ9Ģ 3ÎnÛï[yTĘŠąĖÁˆī){WVĮ›―óÎ;‘ŦmŒqC‰}UVžÜ˜ØÃÔÎoCbIŧ+Ņ'iIÎFyHÆØ Ķä&ŪŊķĸũ<‡€?įÞþÄtôVAEÐÝîį6–éô‹DÄāæ„$Lû,ÝIÏ,sß֑ÉF‡Ôp‹’em š~} ðrYĒp­Ŧ5`ĘĖõHHqEdÖĖĻ*Œðķ4+Ą™e•Ô,?{Í܌<ߋŲŊšÁp·gŠqk(KQ{ŠÝΆ*3ëgđŊRMC­đ흊"IÃÞ§ēĖYUgo7›Ä[û–ãbšÂbE•ēWæX(OÎRy&­ĶīŪKUŋMš_íō•Y•åîŅb5 1Ý·ŋHMģyŒĄV§d,R›Ânb$K56Ýy$3ŦūßdG” %·č}VĨōÃ[xó'įWėģS§Sĩî =eæ+âė$ļŪkRiŅĻԘwÃ]ŠY =BŌ7Ĩ;X§(Ņ8ŪiەôĩŪ†gîŠ"ļo=KĨëĸ*ŋRR­CاvD # Žĩ”8ûLTXœŊîËĖÖōÏsJÕYýÎa}ë˙ý—nn íėÓ҈ PJIæß†īlĖcÅ‹§0b,‹ˆÏ?ŠŌžNk'ûÞcÜĻŽsÞ›wÞų“Æ\&Ŧ*šKø&X7f‚åŨ· âœ=åŒûė―ũdĘtVˉðëšÎĒ…:}/ï›}zãSĐú €jt.qÐ|؉F,Йßė@Ŋå @íäŊ8á~npĻáĘ*ÆŲȂ2ĩŋiĨ<­%0 LaDqÅę­yˆˆ˜BßąrMY“!í\ŪÏUýœ‚ˆŊŧwÚČïŽģéʉŽ* ]&öåú|“k Eš ŠŨŋðÎ;•ŦmĸB­;É0īf–•đ7U2āŲ;ÜÖZįy*klþY•ûFģV•"Âč@ĶDw§8įø+âŦ7 Vđ]ŨõE1Âܞ―Māī:žĮ`―Kg͍œĻãaąŪlę”$0§ĸp›ļîšģ;7žgŧyÞöĐtkŪCSl#ķ—fédðÕ]Ōš–{äsŠ"͝ĨęšŪ‘ęRîcaŅ<ĖP%ƒÚzïã$|3ßyįrĩæ6ĮD&·đTĮU}Šå#Õ 6ŋYYĨN,pyN‡(øūŸþŧ[îŽ3Ĩvßŧ N›FNŒŲØj.ixŅqũJ߈™nųæļö~ĩ#ģ—JÁ˟ûÉ*-ėŲ―Ž* ŽĐxČsÜúO)ĩü2óûįĐŠĩ@ĐNąØÐ%ŋtðĪųÐÄËÝ"XŠŠk}ĪR_î]<~ÎģžÅ *Ō×L•ŋeĻJUG§ŨIū|y|ýļæĘRŠ 3VVUáwÞųƒ\­ēP `fŠABeN .ÁąŌ†ŲQJ%ČWe‘Ru“îÉŲnZ•ƒsBÕÝ0ōð­Ūĩ,|( ˜‰2·@Ę-uČ6†-į9JŅ šE+đķ’íČBY˜Eī;V+V–2wîtsHUåæ+Ö9%ˆ#ƒÍ FXwĪŸÏ?Ēî―mčļöÝčE‚f"rįüÖ§:VúDãŽÔZžģapRŌ>§ õđHŊ“ÞyįŋH *Â#‰Ĩ9ÍÎ―ifĪub,if–Y ‚ôæ=‡Ė9ŨōˆNāÞgKeąē·9=lŸĢ‰v1˝†{Ð[RvüŠŽļ=˜P§åeĪúnlĩlîúÖ=0ÜäĐXnýjĖj••Ô›d\ŅyŠ';+gï“gCt~…_fYŦÔaĘË|‚ĖÛŋ` ýzyįo;N§ģd0sfžŽĒ; ūĖLdfēë͑%UAk…ðÎ;ïü=Ļ-U˜įŲFšŧŅÎģA"mēīæīTŅąģð‚°ß+f Ļ­ĖmySøōK§†^?ϏJ VÕ7ŸĨމšn…TYo’:)Č܆+(ČhRe•·Svž}öO7<ŌŽĪ―šr˜ĩ*āĖ)VŦJR“ Č^-đq cJáþ―jƒ€ĶU7ŪĨŠ*˜›7ÎN Æ/…ûTlĄmCY˜·aũ9㔍öāŽSv n6Á•eæ îįiÜĪ„ŽšWƒPU}ągÕÉs­‹]o!zŸ―ĸũ3Ųļ•:yÜÂÃT”:aŸģÏŨ„`ãæ€;;ķ‘Ú­ú•I._{o4VÕ,žFóˆđãu]ýNSāDŒo•^ąŨ;ïüUŪVŠŽ5T•*;ąðĖšę*TUcUš–\Puä—™5?ŦÕF†FC4–1|/r’oÍūĀĮîalcĸ†DóČ`ĸCIš=w īķ€ +4ģa@ܝāŲÍöšCčĻûþāîãmëZĢ—hg›Æk­įy2s.~ž•9‹ĖH%qvėšŪqâNZØtÛĖûÁ}ßƊ}žsÆÃ6ĻÝËŧ›ðÎ;ïüÉ „ΔÉĖŋ^,U؁Ÿ>7IģĨšŧJĐ2Ē[ũĀĶÓšÖ•§úJ?ŪTpví^Ũõ™FóˆĐ­5wRgïqņöįņ›> f`ôÅį7ïė›Syâ[lģaÍüV6o€k]}’6ĩÜÏŒdß―ĖL€Jc1xžįۂcVŋ> ‘ Ņ] ũIs~>Ũn2·“ĖŪéÁ―Ö2„ŽÔäĨï ú›n.čœ$Þyį?Č՚é>jDšŠRāšbō dXąō|KÌÜŋ>ą.ô~ÂC4ĄĢ:_æÏmČ&ûjvØQ•.‹ũJŌ*ģ\A:%í+I[šGėŸƈe-ÉĒd–'›ļNĢöČ` S%Øļw{j?U:;­O€žũMņsýÓé†el+í>„õŦĻv\ŸËÉlc1S•Šģ"îûųîļÁûy b(ÏĐĘŪŦI’üÄpïMh<ÍyJÄ;ïžó·ÚóûAXĨgïģsEPĻ*ĐÜú˜Ŧ ĨqTĨ;ãm)+ŦW?Ŧ“Ļ"hN”2“$„LIĒó9―wÖénąxŽž3v,ũĀô•yļŲޏú›îŪ~ ũČJIlĘØJ•ĮÃĢŲŌVY… Ė=žGĩ’sÛÏĢ*B î{“ô0w?ũ!Ȁĸ>õKTIAû?•ð<ÏðË4Ž5áß&]`Ę#@<ųu”đđRf4ïžóÎ_ÜjwsúĐjaÆ Ü@œJU}SŸÛ‹ÐÉ=î2РĒāRN c‘?ũsYD'ˆgŠPáÞ`—fl€ōėëģ vïūãōéoðÅÉÁmâļÔ š•6|üenæqNŽīkđÕÎFGrĖY2 gCþĐü\Ÿ])NĢDô*:æąŸŲD3ĘP•DžŽūþų|PÚŲĨa:ûĨ|úÐ D•ÎsĖénÏó°Cu’đMļí;ïžó· vsģęLüŠŊÓ; āĶL”ūÄč> ÓXÐΉG8„œãøågŽĻŅā{vļÓIģóœïV`ŧ`ýÞaŅYˆ?y[Kēž;ÝÂ=ôMóĐ#“`FĢ퓝ĪĩÔZ[‚―ÛV0ŪČ―!FoĮįė |ō<u­kgÔŋx4mHXæ XyćHXßådĐÜlÂŋöÅ}‰.cÖ ķŧ―Ã\$ŠœĀɒNSÛïžóΟ3æViŸ.=ė܀‘pYDsåޙ2U”HĀP§F=*é ĀĩlĀ@ĢcÚséKRgđĘwģRß,ÚĢ‚JīÎņ2ŌLÐÉÃozaŽ7,–õģ)Ė`Ž*Hë GgU"sˆ…„­‚8‘ē”évw]͊Å%_čf#šxžGd3„‰™O…O\ëÂü”ŧŅt`æ#üŠi‚ĩsŸ4Ą9ÓöËU€X™ĢŅßyį/Î+öŠ"ā•šÅþð{+‹4 ķÁ‰"ŒĻS$Ý‰ŌøūĒ·Î§ÍŊ$ũģÃŠĄ*“ö˜zƒĒC[<,ŸCԌDK Jœ}ēNuŅŽs—Ģzî}NöÅãY—åÎN{‰đéĪØ4ąŦoĩmn”hžũóœg‚uāF˜(ÎÞ&ŪĩĶÏFŠÏõõ­hÂĐĪÁilŽt3ŠjZÔŠ„ūĩđūfl3ņŲQÕUÁrsžóÎ;j‡CČŅH҃Œækđûyv5ī#S„­ke üz?ũ3Ļ7Ķ,ķ*ĀŽÁž>ĨJđ!ÏŲ{TîœúēNP~-@9#bíÎ,pwk\ŨgđĮ~F^öEðb­û~ÆŅ{ĩ ŒĪýæÝėŸÏ?FGĘtŦRftÚýėŽĒšQ5óΜ}ę$H™ŠJĢŅlwoåšūŪŠ\+&—ķ wëxęČØ{W)VŒÄ·T€xį?:ŊŪķēF’Õ˜+e-§­ë{œĨts_ŪŽĖ”Ð,ę&ĐIQi—a“―§~RUW‹{#5íë.;‰þ?î†ՌDi6§U+–52RtũĄ,ēr؉ų˜ŋVėķ8ā}ßĨi°Ņ?ÄZÕÏņĨ/ēmiŋ9åAw·nÏ}0ý:5ĖH–Š~‹ŅōĪŅ&2+I^ŨĨVYĖ/ŦR•–G˜ÍŸā+5›čÛ·œüwþnē—Š$ýFLmxœsN3ŦjŽėŠ„gïs­kÅŠÉ–åũī}jÝ||Ū Č}Pœ…waæĶ,ŋՊU$ŨālžÕãgŸ1ŋķëŪŠļĒÔh`§‰ãk] ĸ~ąV\K€Æ=ŸŽ^ ŦÎ/€0݋s,ņsĸdĨŧ™đÁžĸ5Kž‡…€ĀŲųŁ_]ÚāŊ“āëöŸ+ũ9fÓŠ;lïiEB‚Ņ^ĪýŦóÎ[N^U].{ï'ÛĐęįþiîaÆ―ÓhŨúÔÔū8-üyI+BŌޓk傞ýmŕ™*XxQáíĩ­F―Ž<ĮŊ8•č1·ÜgĀ‹šØHŠē`ū\úvJFGpMð―۞ĩŪÉj-m§,Ô8ĘŠ4…ļB=ÏcÆÞŽ+ÏDôÚũڏÚ8ëÔ ‚šMPfFð针ĩŪ‚Ú ĸŌÂãZĄB3*åî/ÚþÅyį…ZûüģÎ9þ]ĐJ WŦĖJõšGÔwąmýÖ6š t{~îނbUv8Ą BIЄf™{) <ÏnŪĀHf–š6üd4Zƒō·\öZëįyD8 Đj|ÔcģŊïƒģYrģĖã0đ@žįIÆäĒ-f•.LÎ/ð69þÉyį%ÜâĪęĪ‘―Ã~c·$ņŋMģō9$ÛCU‰Õ/ÖŨ:Ūu•§hėŊõ›d•eF[$YYbžŸSÚ8ÛÞå1ôEĮuũÕâ9y]ˈSŲĮRđÛr'@Ņ}ÍɝFëÜ\kEØ~Î9ĐÉgoA+ܜJėŸëĄRt‹+ö~:—k}ßTz”d`ôí4ŲäË%å7cŨũ~šČŅD4ÎrâÁÎÉÔų|V•J"Þyį? ^ÉNüĢó~ĄĖĐMĮĐ]U"Æ4%Õ2p?7Äõđ UŊĻÞæŨi=xÎÉs„Ē1ģ@ŒŪkŸo―.…_ߊÕŋ“ākķÖĨŽįūS§ŠA> e_IƊVeF}U”́F3cĶ˃ŸĖ H4°N’GžœRôûJlÍqDl#ī(éŲÏŽĻӋūbM&ƒwnš€Ü§oíhve‚Ėũ“U…iĸäžóB-Ï>U"­T―î]< æ ĒÓŪkŠdd Ý4šlDþė­*7F{ŦĪrók]Ï~ÎŲîĶâI99u -Š†ËÓ·s™eæn–ݝCš51zž É,NfŠÅ<Ųáú;AeZĐŠ"gbø|.‹P}‹QRAķüëîõ˜Ó*Ö7YžÓÜ[ģĨĒ>ĸŽ:―ĪV‘HĐ2Éúöō^ŨĨ,éÛUģ;—ˍąÜ@UŅ,uzĐėœïFRMúNjžë†ĮšVąÏ3Egĩö+Í9+vSkŸC3’L<ρŧ‡)“%”Œ–{?åâL8N ß[hœýššSŪRSNũýâwþÜžĮb#ė?ĸ˜ŧģƒ_ÍÃZą$}Áøđ7AĢ)‚ކąRŧË&;fŸSv!XŅ―‚ CŊVķvM™>+F?P]ĨsvfĶwýũŲIänmVĂ5YŨđÝ‚ö$ãšîoÍ{ÅFļë9{ø ™öģ;[öSRž ŋHĄ˜Y’âŸkĸ<!†N /ÃH åÎkų}?ģō;ŅĒ.#MėpsšŅúYŽËg_iÄ>IÍŌ) Ã;ïüÁy·Ú˚hÚŠÜg>ĪŦīŠIRŠhō8įD8ÁĘ"aáĢßaajžvâYϙÞ7( ëšéŨu [úÛSPY…~Áq øōĶTU4æI”f?y&†Ü—œNF• Bōo§Ž:ņÖut*}ÅW4@øŨ°{Č~Ī2ŌÖ /ĩ"6įxŨĩžy#ņ0ģŠoĄŲoyݝ-܆C(HÞ ŲI Ŧ; ōĩ0üÝyįu‹uĘęÔgõ6ęFs‹™*í<æūēŠšŨPĪŽæŠėņðÝAf°ó<4\Ũč>ŠŸĩÐvŊ/töÂāËsC"<û1ÖÄnyŌ-Î>i™ŧ4 4ÄŲ§USŽ[5d@ЏģLÍb6W0&ąģ3ŽÉ­2$Õg\WxjÖBbU­š=đ+™)k?ŧŠæO1šŲņ,Ļĸ3Ú}ߐz;FÓōˆūæwþÚžBÏéĄ1"fϝ‰ 4’fCüóđNÕþ54Pf\ąēÕú2Ï1 +K,Ø#<ÜŽŲ ]ë’jï3ŪĐMŪ_bJu­•UüR§(ĐËl>v›ĮuEfĄĘh4Ė [6Ï?[į~ŽŧŊï •Āî‹<Í8ôüüÁ)U;ÍÜÝþĸŌl­R.2 Š"9fĨōūZýRóõó<æÞŨX%Št]ą3“xįŋ7Ŋa4íč_™9ÕÜ4>Ï―ÏCŌÃõänVÛÎĻUõ Ēé|ƒŠu„·0'~Ņs­oŅá@ÏÞļû8Íš›*;rá›#3ņ7Ŧ•XÓÃâtŲ™‡‘Æ@ėįôz\åáßdÅôĘÜX―Ï& 7“4Õ_óüÍÔ,ïfFà ļTîó5 •)‚āÞįÔš ę+ŪRÖŋ#é~nãļ‚§šwũKģN ïžóį=3w#ÝY‚ĻVæOz–uđ,wg{_Y•RÕÄu’ī·6e§_ŧÅdķŪ†ŅRÃPĮ3VU!âdþŠŊĒ‹ĮÝÝ!I0 ŅđÎĐpógĢĖ€ze.e7–ŸR}>ŨólUÖ;ėÍÝž<ŠPĐTU§­/ĢÍ3WUųĪ›ŸÉļ ”~~þįk­ėņžÓqãînŽ: ˜žũŠ`l:ė)Ĩ‡“ĖŠ 'sëāÝI―}į?9Ŋ…ĄbYfå9__éþoĘ5AïĖ֟įÎÚąbЋ‚…ÝOWØšũ6·{­Þ@ĒąPŲŊčŨB՘ŪúųųœßėįH7ˆ―V'ĻgïĘâ,ŋũžāþ™pŊ˜˜ļ ØM`M7ŠŌÝmIīõŦy’‘CdęÛsnķģcÃû‚ Ķ5”'ÃÝFęP47Ï“ûė†K–ĘúÝHBÕŨHvÎ-)lYÛŌŠj5arïŧ##֛WûGįjWŽŦ­Ņ݇ž4gtâę>ÛŊĸ―óþŠzþĸnē›l*DJ‚J „ :(JBGEéH ]T@)ƒˆĒ(Ē`Ī7é(UŠ4 RB(’ÐHßēßįĖņý}|þ‡ÜI”›ŧgÏđwxîÜ93ŊqóËf―‘4džðŨ)P1F󛓒yeþ"=hČ`/í–hä p·eÓL$ļÅUw›%Y°ðiĖĶž&#M;2ČĻ(–\ĪqØ5YÂKļ Ã-ia›HðpŽĖå:™MŅ7ýTũÁīXÍ$Q°ļgĻ ‡ķŒ@S°ŦĨ"XFzŊe–CģķÅH„2ŧæäĒB#Ī•āĒ۝W72j舑 Fƒ“§NĖųōËKĸ\âŲØdŋŠpŒv‘ŠÞ"P•*UGóӂų{vl7€ Œ.2{FúF__ŋþúûđü0Wēą˜JXÝųŲ0 Y`ĒĒāËK`N%ĀņxĨ–ŠģģŔš'ĶaSíĄĮīMSËøĮ.mYšMŋH8)Ɵ šŋī A[þ Ïh6ĘĐj;FŋFÝv’‚}]Ü4FöL˜Vgh>˜ˆ{eÓ4ˆIÔ.€ũ"Pų”Æú1Xf™eÅ1ŲKĄĪ’ēíPkóķН_P7ēþϋ—öėŲëĘåËķV­ÚA ‡ð…5ęFÕËËÏ·{Kę>Đ]+=S7**//O“_f+Č-ĀwlŌžĨËåĘÍÎ5úXR‹ŦÝŸję.ŦsšVDDõįžG%€ũAFh[§^TÝČzOōUŸāIÍÚ Ģ›øø..Ð0…]eðĶð4ĩa…&ãUæÐĪ8 ÜōaV–”LXÝ(Óū v _ˆēļzÄO1#ÎA SuĖ!w„ŊMĪ€c&&‰ąvUq0Ô6ŸĪ‰üš~rYE’Ęæcę>(ËPéq‹ĩÅŅ,ģžZ ˜‹ú4ģ–ï~ÂūVž;Ŋgï7ŠV­šdņĒøļéČŋ={ö,aÜråËWĐ\yĮïŋ7wÎ7™™™@*,<žbŊ8€ÝšuĐPÞßÏŊZĩp’ÐÔã2UHH…ČČ(8ßīI“† áÆ>ũÜóiii\UõįžK—þōčQFNvvhhhxXØŌ_~yüč^ŠöŠ)Ō 7'Č5u ’l~ŒŒŽ‘:TýY҆ņhÁqg iiøHÉ p‰ĖŨec.Œ L Es‚5ŒRļ*?h ŧ$Ĩņąj†”Į`ē“ÅīC.IˀĩĀWĩÄTãÆf™e–?Ŋ–`ĨG‹û― Ïß$ŨI=>Ŋ,Ļ–‘ž­R…Ä,}ZÖÝz§ęrIF‘YPe𑓛 ĄˆÞâíJiŊŒöļtņŸ‰'oßšÉ*&%ֆąŪ*JĢomđļbųē'OŽ^ū<ëqæÐá#ƎßķC‡wčófïá#bŧõčŲķ}‡áï>x`?Ũiâģl:iwåxcõ[ĩ”Ö\âu2ÖĮÛIB€)įušæ7Ú|ÐidĶ―ĢĶ”đmڃ+į— M6. aÞRâŋŦ…N]ú‰ÆgĨXÁČAh“|Û›–ÏQûˇÄHuŦm…FSQ?“bh–Yf‰(ĘÖNÆÃ!ƒĄ ;vœ}ûöëØ9&šq“Ž11ĄĄŊ'_ŊTĐRtÃčĻĻĻ^xáÖÍ[ļą ŊvDíÚuE7*]š4,,üæÍ”qĢG9rĪND‚îüüļéÓūûv37kŲŠQÓĶ#GãJÄëÄ/ŌiĀTõnpŅíœÓ<2tÅŊÔxāã%(ÉĘžQS ,õÐÛČËڅ†š*ëŅFŦ(ļĶd þEV‹85ËÍÔÔ2'Ó°·†ąiĶÅŧĶ$쐋 Ē90ą[14Ë,ģŠÅtËÞcþá…Đ;pˆþŠßĘKÉ+:tØŠ5ëš™™ÕąÝkÓ§~ī aŅžų?q†ī§ūĸîÚĩ+ NĀņÜļõ·Û·oįää\đtié’_8đå·íđđđpæ>oâŲĐŦ+Čsųđxšĸö›Ų_}ýíÜyóŌRÓJ—)ýÕŽ/J•,9tDėÝŧw˗/ŋsį8ūuûއ2gJJʞ;û Ø­{ũĪĪsĸÞđíäÝĢ%ŋ‚Líõ f˜.QýOðhĩ—iTcŠcðÞļ4KŨŅØ%Ä ’ĸ+ÓŽZ)áU_š7’„ P[…ÕCO66pôŌUÔåWÚĮG•h–”˜†Ķ”ÓÖb–YfU‹i­úķÅÔYÁēģēūü<ū{—ÎņqqS§|ÜĐ}›[7oþ}üxïÝfΈĸęËYÚĩŲŧwš­ģ>3jäũsŋÔĸŽm_]ðã<&úræįÛĩÁŦýqÞũoöė~þܐDžóáý}ßzóÍ^=ü\þûöííÕ̎ïOXū|ÉāýŨŪZđ`þžQ#GŽZđbôČŒŧ~ÝΓūĸY\ŸÞ==ž0aþļ1ĢO%&ē1%Žd‘5˜r Đ PwUzÞHe åĻz!ĖÕÆbĶsšC+'8)ÆĨŸ”ðWýQnß 0õ`Ó[ĖÄ[t61…ĩ6ãåĶ—PÉXlÉ0Sá)ķ=-ģĖŠÕ Pė P"Ũ-WęQ @kŊcGĸuė˜Ļ―ļŸxõõMū†]ąĐLŒŌį) Ā6Ū_ LLK‡öÁ-ĖÍ9u"ņܙ3D'ŒÔc“_―z™˜ųO؍”ëÉŨŪzЙÎcÖŪņuų õŠÄýcįÎ=ŧvjŽÓNŠîГ'O:ÉūG+$īũ—QÝGŌčÝĻn7ÄÔÚ Đˆó–cwäxĐŨÉ@­ęr˜.“)fÐ(„6_7gĖ1­œ€áä!xäĮφSSæ­}…5jíqĘ6˜/ļ5!ưgę&0@,ÁÆX"Š–YV<ļxæAŸ‹†7&ņS·ŒDũ@7ÍŒÚ Îl8§iÞŠķ$МÎ8ԘÍŪ€a΃T†h†–4;`@‘vņbBq!•ZO]ĸ ö%˗K"%Võlȍe ģéjޜÔâW),ÖgsÍ7p8Ų­RŲYf'šú‡Ũ”ŌâzëĨ™í,Ū(þŽq9ՉũĩĒhJŽxĘEŒįm$暈„ ’NíŠN”v5‹\.ŧ&|ņ'/“@K8˜IX…aî―dđðâÛðÆ2ËŽ‚ĮĢlõqrĻ­„ë3ļf„Š'F>^&樅ę2@uŧ―kė>aZįŠ7Įūš·bBár$ÔÖw1@7ý ;!Ë3‰’Z{€Jw?áí.Áū†\M3Zc:•Į[―TË•Ā(dŲ.‘NŽĪ dmĶņ#Ī6Y·f#Œ3˜]̧œåj™„ŨÕKUõ2ӜŅaáČ$|PŽĻų`:[Ąļ ŒŨLCrÎŦ₠_Ø eSސ%TēˆË,ģŽ8`‹1: 'Æāŋq^deeâņK“·ÄpĘ  †I%q՝įœúü§ų _ÉūÂðaŸËĖvļ>ĒöRČT° IГ%äØÃąGMƒ2å—]:w)Ņ(Ğ>qxIk[“eEÁ+b0FUĀ—Ëpp €shö•—đ?Ņë2=%Uéđ…ŠRe R5xÖŸUũZ=WuWđ@ĀúTEšī, ĩ*ÍŪQdkūŽ­ŪŦiē ū­æ óCM^­é^Î+ĻĸÂõâŲ[Ė2Ë,ŊŊS1ÓŦFXOūȰÚė*FˆÛĄc§ÉSĶNúhJÛö)j@ˁ{”ËŠN•\áī]SýÍ― žĶúģtũŌ6âTĢ€·DĨzē…āšŠļŒÖ™Ķžü)å`šÍËÔP›Ó·zy3Bô 1ÜRa.Ũ,ĖŲYâ·FĮ oØhð•ākīoė8ŘóÜĶhÅyÖĀ.1 ;ēīĘV|WÝj“îđĶÉ>*ę‹ÞĖætĪģ8abnMĩŒšļ‚Xk@œÕb™e–˂ÃĪyÁ7(ĢYMĶå€S“§Nýņ§ŸĮ―7aĖļņsįýY72?ĸ ĪçÅĮ•z|lÓŧóÝyđ9ā õœÜlœ[ĒŦđųųðÐmÍĩvíÝUĸEþd°Ļū8|UUŸ1éĻ–·ŠļpÞ4+ãW ^šÁa6ŋ4/ß qīŸh|ŸtŠZŪLāeg.7GŠtmÚpATļīïŽpŅ&Ōãhvh嘿!h KxËĄĐŧ…­ 05vLJŅØ@ŠëWsS]ĶÍÐÆp§ņú™E#(\­ŽUŨœ++Žé^–YfĄÁ3+8Õ ÐGôėėŽn={ 6ünZÚČØáĢbG$,˜šL§Î1ý ŽŒŠ?jüxŠ číÕšMۏĶL1jÔ 5kåŧ \Ū€öí;ūĸáĪiqŸ―új›ReJ‡……}4mzÝČČØŅcÆ―ũþĢĖː ĄýŠ‹ĸ"ĶsŨ€Ā` ›-#W`āŧ#GuŠéŌ9ĶËīO>{㍷Šŋ;o—)Sæî―{Ô, 2äÖ­[đyyCCy·[įŨ/^š0ũĮ/ŋōĘÅ úöíĸfŸ>=šÆTŪT™Z‰–­^ŪUŦÖ/‹?jÓîó/fÝžy#;;‡&Œ·võJbĩ°•ˆ…ņ’ķišxĨûrOĖîŸéÞ}%Ņ@9ËFχ,Y DpĐi2m5Þ"=,ĪYs6Ā(iRĪK+›vĻdbožlÛSAžÝJö*žf™åÕzĩžŒ„nį˜Ū@ŅHävîØaÖĖø˜Ū]ýüüæ~;gfü§ũîÝëŌĩŠcŒąkÚi’‹Ķ=ųSER_ŦÎ&A魎d‘kāųjO 'ŪŪ6”óėÔ1ũ•!v{îÅ$šĀ0N™â1›zĮ:ŌÐR[áË,+Žyĩ°•=Ĩ‡d­dS†ë‡‹‡øøāyü™V7Ķĩ8<ŲēiÓĨĪĪ—Ē1ēlŲē6me4 ;īnÓfÂŦVŦ†ž,0+YēÄĘA2ÜnËHO”‘ČÂļÆ;Į0-(ũwųáMŠ—],##ýÐÁ:ėė™3‰Įĸ†ĨSĶNŦXéYĮON𙜜 ―ʇ”ŋvõ 'ØĸŨąÃĪ”/[žŦš9ëK.˜ë}üø1q‘üÜ<:Ŧ›†ęÚčnJ/[no”äO·  Ī%&+™HęÐB{Ŋ™>fÞ6ÐŽ™[P9Ë`fæąÚĀĒ@r9ØoÔ <€Ë‡•“­@·ĖēbhVÕ°B@ppŽĶN~ģ3ģŊ\―ŌĒUŦ6mÛØĸâ^eʖc_úĮĻHvú’Ē2tP‡ÉÍÉvųųÝŧwũÓÏ>kŌīéØ1ĢnĪĪŽ^ûŦ”ü mí1ΊĻņĸ­[·,]žˆW‚‚Ū\ūÄ>sÂ5ČeJ Lé„ÄCĩüĖxāüûėģUļ—Ë—Ņųųų2­nũã;ē–—Ÿ .?ž41)) ũ–‰pxkÔŽļ—–š•™é%SëĖbŌ žŲĢ g᧊Ņh/nUhĩÛĢiļžv'ß ÞZ–Æ”ŽČy“ËP§ēUS2ŠLMá bVsrË,+ķŌāšįoVíÖåãҜ_?ß͛6"Ž5`Ðāˆš‘<ÚÓÉ CÜ=Ė”ĩ={úTëÖŊŎ•”tž€ėÏ?ýäv đ5nÜĐS ý8Ī3@ōî°ÆMšîØþ;Ēī]ŧvCī†VĻPĄ_Ÿ7ĶEÂ2JoQ%ũVMYæņÅī-õNýý7d3þ―jááM›5GČfũŪ]DrÁ35ÃlvØŋo_ģæ-ŋ;ė🆅‡9}i›ÅK–mÝž‰E‘ĮĻåÂCĒGŒCqbņč96ås’Ķ›c\‰ÛŲŧ°RýÄö„·Đ~#Úļî"Åk‘vÁá äöĻi/a››JßbˆZË,ģbĩv)aøŸŒŽGuXĪņ"'ýýýĸ:v4vø°ýûö"ēEÎĀåK—ōóō/^8ŋ{ŨNb P”Hî§S§þšn JÞ]ŧũ°iÞÂĘËO$&ē]†‚øũsŋ=tp?ĻZŧjŁýûjÖŪ]ĢfMčüŅΉôSx­mŧčFÓŌRy*7wQÛûĮV„Š,ąwÏîģgNó$ž“―oïžåō•ËcG"bĀ&’áŸ;s:ýáC.éŌĨ ā™'ôĨŋ,B!,0(°K·n•+WIKŧCoËĪĶzIfiž"ĢÔæÂPð΍ĸߓÆE•ΏO@ģxąĶ%;Ãt[ވ9q„ĩ{nĄ‘'œmú;}#Á]iūÚĖ`ģĖēbg–WË~ŽYH?ûĸER€Č8|ð@âņc!ĄHHøũöMŋ€E?',øņ‡ĀĀ—ŊÁ„+W.ĮZąb%ÜŌ›7’Náï‰Äŋƒƒƒïßŋ—“ÃlPaoöîYĐŌģÜũ ØžaÃî;BBCsēē` =ðŪq ÓÓï5ÐÏå‡XÏî]ð6ƒþ―}ŧGŨ.ėZąĘÁ―{N&þUšLYbÁŲ™YėŅ8‘Ø=Ķs€e^Ϛ9cŅÂÞČč2ŧÅt$ųÁ„J‰ P Ą•ÂrÐ“õ[―õÓÚ Iķ5•Į9 .Uä@+5°Ŧ"·FEAâ 6ÍëzŠž2'yĢ þšBgĨ6Éķ9VŽÖ2ˊiAęý)=j& Áã€Ā@ÐyįömŽƒ‚Á‹žYU*hūR2›–z‡?ýü\ļqЋļm~^ˆĄ0ˆm{#ŧE#–äfÅGžq=rÁJÖ$ŠlÂÁÆič@:"˜`—ķá>ęoō^o›Ó–“›Ân=yž>-dĨJ—z*4ī›Öķ ÎHø8ãyt8guzJx™îįv#Œāąkā@JžāŽJý†Jé^S·f4b„ĄÚ͌ÁÄL‚þ·Ļ‰ ˜â]îŦPb_§/LĮøcŒ2WÓm-ģĖēbˆZŧüzŒ8€I/€/L{ŒA\9'ēĻ€K‘”ˆiï[~lB! |•§Šüâ„Y‚*Ńá hq%~īĒ–Ĩi[ģBõF—ŠįJlá―āĶņ4õJu4—ÃįQŧÕJ]€Q†e.þԈ 7•7’@ðW4dôf™MŪžzíüH˜•ÓīÕ>ä.īLVßVëb ö*En:Ø[[éĘŌ·&ÄŽšbĪÏē dĢJcjęļM7ÉĪCĀjöÍ,ģĖēbρaŠy›ēTxĒ\ðNÓøĩË·binĐŲĪō‹MDԁð€JpIû1ũ2•ĩä°k vÂ:íú呐Ĩ,"Īóq9Mø’åŒ ÃÔÅöHMĀD;æĒÓð ß)›ÝģoïĄÃ ‹–ôxã-ÜZ•;8kŒÂFV$–&Nþiá"S Kx“ꉹãß_ŋiKÂÂÅ7oEčYƒĨËVDDF>ČxÝļņŌe+ЛĻV-|Ö­ .\đæŨ™ģfS,5ĸ§„ĢFïúcßĻ1cüž0îģAÁ%üūœýõÔéŸ~=įŧļŸ—)]ķ[ŊÞŋ,[þÁĪÉ|stïŅkÉēåUŦTãRIāý1a!oÜķcŨkíÚįfe7lÜÄ\ÉŊ70écâõĒę5û›q&lØžuâÄÉÄŽđ—5ŋn`ĖēUkkÕŠĀÅËũhî!eqäqÞĐ<~JžĪ 8Š(Zf™…ZxÍCš$*ŲĨŋĪYi_ ŊBŠŒGé—.^8~ü8ĩ ūþŪwúõïÞĢĮŨģé™û2‰>œDL lđrmÚĩûí·m‰‰w|―ӀƒĐw0҉Z5#âg|ŽkIE>ō˜ąãĻûó⁚5k>ĸ %J”hõō˗ĸđô8+SũĻl­_k;qōGŋmÝōÁ„ņÁ%JÄ}>óėŲ3$ęķkß1$4ĪEËVČ#œ9}jâäëÔ­+Ýv—-0pÐëcøķ ölėøũ˜mĮöídãRīVĨj•*aa žt2ņï‹/Ԏˆ@6!::š0ĮŒGīāōåļßÚĩ#č;điý†įžĄGžxПÆÅWŪZuüØ1{vï=flŊ7ÞÄ· ïŨoāosŋŊĮÄ 6|ųēĨ\ÉsÏ=ĸņÔéÔ°áĖK·GŲR”_o>ÛBm5f+Ū"Š–Yfm‹|Ŋ&þ0É^ŌÖ/v#ý%ÕP>&U Dp0š\ nÖžY›ŨÚā?[đ2ËLtæĖéļOĶ%ü4äĄQë.ȗРxĘ.Yšôķ­[ããâ§}4ßđió›6l`éõN{ŋŲÕÄ˗g<|ðņŊ™Ÿ…jÔŽAð”š\æĸįâœ'N ÓX=<ž}‡Gđ›šUŋ>ԋ‰‰yéĨ†ÜĨšDfE]a˖^ÝšŽXķä—Å‹4lÔøūý‰ÆŪ]ŧúŨĩk9ßkÕŪ…Ļ7ÞâåWęԉ8rø0ąTõuŌKĪĨšJ­"ÓúcũŪukÖ"ķ°zÕŠĘ•+wíÞģbÅg–/]LU.žãâđĘûũ,^ļˆĶåmåpĸÁ}Ķ 8zøOŠƒÛ·ïÐēU+ĘÕRŪ§P–M qéēeŅØ}xĸ~ûŽCB*  ™™ų˜›†ÝxŲð‘ŧæöE™ÁnrđLĩpáÂsIį}].níáÃûlŠ•(QŠŒÍ'{JüeóĶMÔ%KėĨĻČýÄmũÆFXó$›Mþ-ff™eVa.yĩÚ\ÖKƒķiŊ­ÍŧŸ$iÕą>{í―ßęąxŅ›7SîÜIsũï'PŪBˆfkI ÄjՊՏj€É H*eDą…mæĐ[7ē~TdŸwúrōęåËwþýwÓúõsū›Ëŧķĸþû­7ôz˜ÉFņįϝ]ĩbyp` {mļœÄŌÓÓûˆ”Á?ĸ\&Úp'õN… ëŨ­Iđq#ībhZęÝjÕŠĘIO3'EŽûûoېÂÜŦWŪž›ú/7{ėøą—_iÍ{·lÜØMœ˜.™™™ÉŨŪâŅk5šI~îâÞÝŧd;<•€õš)Ũ+>Séþ―{”› ]VÉĘzl$/$%!,I 2VŠTÉ~ÚÞūm‹&đņŰ%{ėZ„bh–Yí–(eԜû)F7Đû*äfaƒ‡ e,2ē^B‚OĶMá{ÁüyŨ““gϙģqÛķ[ķĩoĸš;/?ŽTÓu›7ģ_Dë„Õ+WhŪ i‚CûöĸøÃ-[ķÚągïčąã8ļeãz ŽĻŨ ŨþØģ;++ˁ9%ĸtåēĨŧwï&ĪŧeÛïë·+‰™ž9}úĉŋŲņĢG/œ?ĸ(=}î7_Ģ‘ļtÅ*ķ§ÖŪßTŦvmņĨ‚ƒ~srsvï܉ ũwíÜîïx75mĸ°ÎÍ7Ū§$ŸOJÂCOIđ>ōãPÁhH#tŪ_ŧöíœŊä]ūrõÆ-ŋ­\―–ĪĶāfĨŽĖí^ŧzubbâ‡'­ßžyÃĶ-―ßxŦjĩ°‰“&%{ĄH‹ÆĪHƒšüGģĖ2KDQØÄÓūT؇GŦ―ŧ}ü•˜šÆ/cSÓî Žâ‘ÓŪ1ŊŋüĘŦxy‰ûûŊã4‰\H:7oî·5kEėßŧ°āR%[·hž•éãōũÉŪŋ“#•’œ|hĸ>ĀęāfŌũ;wxÉÛĮsQΧ?ˆ:ļUŦWŸþÖÍ‡Ē›ð|ÜļYeãïĪ͚Ž2{víjũęËt6#1ëØ‘ÃgΜē­[5ãËĀĄš/Pžš.ėÜ9|âÓŌzÆîģ~͚#‡eĪgPģ°jŲŌ=;wāՂc—ŊkØÐAĶΘW{wïBRZ`pÐĘ%Kĸú‹<1nœhFĘõdčÜŠyðÄ~WjęþïžÕīY‹°ðð+—ĸ9~ôHúÃôŅ#cņ‚qŒđ I°Õ åÅÏ,ģĖęÂ8pī$ŧž# ÂÂVØ ŌîĶ$…ģ*ôeŠģd"ášĩŦA ŽÄËcļæt"uxôðaB ÔĄæåä^ļ˜$-rEØÛóŨņcQãžBóþƒ†īkÛķFš_õ%ąZēķÚÃ\E„b7mú:Ų0m=ëōõE*ėnZ*ũĪūē4åWŊ^Mūv €áÃJxŨņ4é\“›~ NžŌĒeK<ß5ŦVPėĀYüÖĮYïūĮ%qüčQ]B~þ~”H\ŋ–Ėŧļ—ĩuóF–E@ ĢœKXC„fXFs–đ< ˆõ €€xņ3Ë,ģ2L·m ‹9Vĩ*/-ÍēĐķ·vną{ûúšt H2e9q>ðIã?zôČÅK9VŒ6ģ˜Ųøõ˜BZóÜ­ųeĩkÕĒvĘG“hf4™.ÛX܋LļH{ĐŦ‹IyŽ]%˜ ~q ĮŒā2ė*ucÓa^ĨŦãĢGÆŒąjųrŧM8ËšŽ óĖ1&š|ĩ…ĨĪ ðF„ūŒ ĸ‡æÚW––š:%1ÜĄ*č%Ũ,3øļŒū ÉąĪŽq§j$!pkōŠJ,pl+Žf™eVsr5-cøßąĘ°  ĨnUT_Īŋxc° d‚?ӕPŽ―äŨrüč‘sfÅķš:0ŧ@Rk =BWøŽ5ģĀC—˜øO>éÓŧŨüyßŧĩKkdÅÄg4køŨ„Œ9Āc<Ŧ|ÆYŪPeš$æĀœN.Ī6$e=läˆwßÔýĸcï veg’ÜL2"ģíĮ6üpîAwĸ§”Aũ•ÎðvœúV!• mX•IýŊĸđö^Ŋmļ§ą^Ŋņœ:ū%Õãˆ`POí!ø›ßKÃí‘ÔóPŠ™oIqÎÏÞDßŨzN—‰`$ņáÏ㠐=“+I]uČĖ:glQ{ŊšCĐs.Eüą{‡ðZŧŠHúÛĸþÛxâ˜Ī=7YFH6ŧŦŧŊŨúWGļýtĮDb6ĀqgJŒ™6ūĨžŠf†ĄĖ<įH‚™Ũõķąũ‹R]ŨŠļ/^câ_}ĩįī"#âđ1#Ūũ5RûĩŦ›"MRÕĄ?e`ĮÆ^ŧšŠ*#ŅÕĪ xŸ ĀkmÛ=õĪ+ŪύSķ =å^3B?Qj?|øļZ{årûJÓMjŊĄōTwPŧF*`ŨÔ^ëuG’lĮwJ`Iõô9‡ Đšą­ˆ™Đ: Ö~ęĖø―JæĐ‹A1båļE‰93lG&Æ$$ô5ļņ~WÍŌžÞWHŠļĨS)eĪČr7Áˆī!JŌ^Ëöó\ķŸēGBc\Ũ%ÅÞŧg DÄZŧš-æZ”š'➁Ļsü@>;ė™)áĨÐˌMx)Ŋ3=Tf>Ö ÝMˆ@ë­ČĩŦk- ]Ó5đV(N€ĐôLwGƊõļΝĐŪ™]ãIuÞ „tęxœÁ8}"3 ŠNfF„ĮUÉÐoņ•ī2 8įrÍï`Ũ>ï“+#cšŧ'#BQU "DˌĒôČbäĸýō AÝFøþ!ƒUE" Õ9ĄPÆ“ŪÅĐC‚fD^ŨåņڋĪïåâÇ?ŪŲË[Ąé6ðčWuiïÕS‡ūŋ&05ĄÏxbe(lũX!Ý·Ī†T_ ûTį^đōŠ v†Ī8UÝĩ֚iŸ0tÆDIá6Š  g?ÞÆĖÜ:Ōï™ųøVÉPŽ―tĩĻP`æIK"Â6lŒi‚”Ā'ŽČŪ&i##Nh šuÖ"Ü€™~â㕆įŧ(@fļŪ Fďė@øðás0·šV.‚cȈéŪëØ~­]Ýu:$$­•§ŪîyΰŧŦîČū‰ J6 fŪũLD„tŪ#Ũ"xŪ ĀĘMŌ7ß1+7ðĖ•]=ãž­éSAŧũ–hC QÝ-ę7äː ėî6žŨšÕ œsŲ^kïýš™Ū’äņĐ#RŌVāĖĻ.Ī2tęØū@Á°įšŪ§įwf`XkũLUŊĩ`œ*Ñiûãj$>YmŽęŪ)3ģŧou[’NŨÔė―#Ēęx&#æOū ĢęĀQĄš!CŌĖ|KOWՑ(°O#)Īî"”ÓýþzÏ WvŨ`īĘS§j`>ŧē@äJŨõ†ųÚŊsÝj8•ĄŠz$5$ƒÓčŠSõýĒoZ!“ßĩßÃã9uÍL0 \]$#„BĨčjR(xųŠE`ėS%r8ėõZ‘öØP„‚ïũĨG|ÛeāĩÕ)?Ūöōá“ÕēŅ0ˆq CÐą‚fũDĘĀŨû-‚;m'Ä\y―/ˆ#ÖđÞ6%ŊžAŅm’!éÜųl*$―Ŋc+Öō`Q™15KJfWa°s:ኈĩ‚ÐĢđ ž>ÐNÅuŧ;—ážMb]ŧ{@bÅzŸ7ŒŠĻ*IĄŒs.ōÉ){ŊsōžLœۙYŪ3īâŧ ķ”U§gh"Üv„0Øį€X‘=ʼn~Đ%ĶGō+_]_$r…åĐøØÕ§ãJ+ęT#‚ŨŨezå"pÎĐÓßo~‚!xÜĘx_ɌŒĖs‰õÚÓUc‚đrš{ reötۙšq՗팘†}lîŨkzĶFĐĨ<}ÆX+gƃr%CĄŪ͘™§ \ëÞąāĖMÂîĩTՙ:ūÅš§§œ €ÞŨ™éûĩŦqŋmcŪė §Ēę %CŨû’H…Š‹–2œs‚Z™ï;-!‘øðá'ō9-Hë}.ĄDÃ0E Ũ9”ÖÚ.{zú;„°"wŽŲĩũ+2Škz$uhĄė.Û0‚Šš(ÞÚ ĻĖėĐęąs:Õ-‘ä`Hí_ŋ t—ĮQįQå Åõį Íë\S)ðÔyNĖ rŊ™ɐˆw]<ų,ŠßÜŠm’”`ÃΕÆ#wöZÓuØ{Ÿsz,I]@qSÝ Ķgڄ:ÝķïL&ƒ~"ŸŽv-?ĘēW(šĮÃP€n[Tä`)rÅĐ3ã―–R§/RkoÏû"5ƒČŽs0TD„CT„`L;#ëœįGŪ|__ÓŠâU‡@dÐĻS$óĩLK4fįîŠÔĒÝrüF:Ýcdæ-zÁÜ9ũÐŒļ•―ƒZZ3îéÆü>Š6―2ŧšĶ2#į:žO'œđÖýZ$ėëzÏô^Iēæ>Ķž~ ėš{|L5á\) §hâÇČĮÕķŧš ˜ö™ē-Šŧę}ÁÅųúęj˜aŧ§ĶÝ3}fFÐĻ;"iŠŅâĐŦŋkVUŸ:1ÝŨuzje”˰BqŠmSŅ3°eÂŪš"™đĶĮÝ3VÏ(īŨ EÕéS{ŊŪsu!ļŨŠ)€áēaPŅ] #âęs]ˆ3€ŨÞyŠėĄ->Nũ]ý>‡RD<{3"bįŪsŠ!Fũt_ÓSĐč)“ũ zšŧ >|øi|6{M€ĩðĮãFĪ–Į‘‘đĒŠÎuVŪ•I[A…Æ>} EĶIĀc“ŽĐéÎˌč%3“Ëī{ĻČČPfÆđNŸÎ\ ?#öLwĩacšÛDũ4Í{6 ÆŊĩ{šŠ=ąÎĖĄ$XU„ųƒ!ĘcG\ÕH­ĩÏ)ĒH@”ÓÓ3x‚‘)Ï^Ũ{< ķ{ČPȞ>m ôą”a?>B(2Ũ9‡ĪķŦK+ũļŦïë‚-‘d{FO{ÕUuŲÞkόO‹AčÔUUŠũyŨéĖ$ŋõ&Cį\U―WîŨķ 2S6þĢėTõ”aI3 8ȕŦŠ*ázŋ§'Ļî{@ÄÚŧĶD`О{ō$yŪryeŽÛ36‚qŠ\™wd\ųhšígÃÖZgj`­ĪqšLÓŧ{2%É3’R:įzŸ†Ï Aü8>|øÔÍô؃6ŪjŒcEՁ-IÐ9E03!Ø0 {Ú%…Ra\k_uyŽĩRŠ*Ąp͞yí=ðéNiïŨÝ6 Â_ö^ķŧOÄyÎĄHÄÚy―áȰý>Ũ=Û/clŊõÍ=p(u§―Ą`áúzÃXđ@œ:”VŪs― ÐïČ. DÕx—á\ï{fÎđFŽëý6@1•ÕgƒúzŋWfæ2XįĖøŨëu‚ļc“tð#ųðáãj)ÍLdNũđˆýÚÝC"2ŨZÕUS‘ÁąĮÎØ=ƒĀt{ú™]] %ļþl)ŅÓUĩũ{zB$ÕÓž(Ģý˜GIšüqĘ"beT•āĩv>Ũgö^ũâ==:=ĢŨđ$ŽG”ŧ=“+[ =iĪkíýäģJEŽŦŠk”‰™ž EDN·aZ™ëûˆGd*ŠkÆ+WPrĨRÎuÞŊWÏD*#ô4CķņųðáÓW‹yTiŒŒÜąŧĮŋísÎØĐ ðūŪéŽÐܐ€bwK:u„â9u&2"TČŨŋýē=ũÄĒ wĮv—m)l|š―‚øĻ1ÉG[#CdzrOE\ßĮbŠjĀ^yú`Lōĩ_ÕMÂFį\įÞUÕīĻ\ųĻ!€Œļ“ŒĮ”R"Hōý~GFH3ãÞÆó\WO‹áI$mŸë’"ŨzīBDô|Ũū<ÚJ)2Æî*IŊĩŧ›bäĶqŧxįJ>! ™™$OĘ1ˆîÎĖéē)˜U—2ēíR"šš Āõʞ@Û@Í(‚͙Áĸĸ€ĸ|øð7ķĸsĪ–āu]ĸþũŋš{­üŦ ķÓŲSÝ-EFtwWSRčÏyÖėŠS†þúúÎߏmI=ý>‡Āã.O]ĘũtU‰Zk}―ŋ îȞĄÔWíŨþšŊéÎĶ‘‡“ŒCöLWíĩŋÞÓÝWÆ?þņ'ˆŒ'XˆđŧqĸüuþyOHENwuKŠKïÎĖ™cï\ĸöÏũó…ĸÛĸû?þõ)ÉîÆ >|ø‘ĸŌ“_ŋ~ýįHíĐúoĸýœs―^f$EsŠš‚ĄU'"ÏØ+WOÛąæ–ŅĮö4A3þÎ2ŧ‡°í\ŧûð7ØuA Āũ`EÕ!ātSōø‘Q‰6l?Âũ|!BU―ũŦúĀP„€ąg”Ī>G!=žéYkuÕũƒ+f@FŪŠņŽ\øƒĻ;VD8]Aų‰úûƚ„"͇A)þO{ũþՑÅžŧï<™‡3Ė0#oĒ â+„ĻÄÄ<7•Š­Ú?#ĸKþˆlíŨÄ,ĒĻ!F ‰J‚‚FPÞ óæqŧÏŲ›™5e•Î(åR;)ÎĮō–އKŸûÃŨĶïi@H%š.ŸÍYŊŨ35u?Zgå„Ē”jooÛėĖŊŊŊģį ĒÝnÏß4G^xĨPýGc/|=[PúÏE`éïēĐ3)(Ņ ßĖēMžđhģœë9=“I?;ą5ēÞdŌYY!„pÎĪTšŪo>jËAJŲ2FČĶoĒŽo1B!lBE-!„PÔBĄĻ%„ŠZBĄĻ%„RöQK!ÄÄþĖ!JĐX,–N§•RŽėY,g^‰·d2™x<žÍf€•“Éäp8\.—b_Åþī!ˆ‰D„uuu6›•7H$ĄPHaĪ"ēį蚇,ŪŪŪ6›ÍexÁÓéôĘĘ "z<öĘ#„üi@&“ ƒŽ$þ,öE+‹xÅR!„Ũë­ŽŽ4ĶáœóAf$l (™ģܰĐũČū|€ŊÜĐÓé4.x"‘`ŠZBķČģZ­%ÖæB™ÝˆF†X<™SX2MX.“I%“ÉԆLþēôÁÅGžŽmÎ_eĀŲl–!Ĩ4ÚŅ4ÃĻ\:ÅÂ_PĶ7ēPz€þmffmž ZéakAJÉ Ûg‚y%Ē3ššxi.Ŧˆ„Óßýėíý5ˆðÂXÖTüûĄŊ'GMšō5īũöžYå°??įBM^―m=Ýt(‰ŊĸQJ˜WŽLÓøâƒņĄÉ܇ïõzė&=ō˅oö|t>haXl"ŠÂŨŪīĐ :ėņŲ+“Š­KS…Óff›GQŧ―ĘY•WtΙ‹\þû— ÎÖóŸöVŲåĘÂzėRIþtã’ÂҐŊg\τ"+Ū–·ŽïÔ/]đYUĸnW#C`ĸ­Äg7#āȔfafŽ ų‚āu:âœe2ÉåčR)2—MĪB9ĐÐđó?>šsÁ9*ńÅ*gF―Ÿ6ÂĖfýæ!Õpb -ˆâđŦQŒQCQŧJÛbųÅđH,Ýŧ—r ūÓÛpå$ėÞëEĨ1ķ<322Ëe­Þ†='jܖBˆB>@wTí|ĢÅzûĮ Ą‰txņōåáõ iķųNyŧÎg‹/?úũðh4Ģ;ýĩgûE~‘B&—.]ą6ïëŽW Š…Ô+Îj‹uPØ@‹Áï@áãûųėø•;!ĐĨWC™Æƒ'ûïÕdrâÆÐíĮq·Ëēš‘máZryęۑ‰DFŽšÓïôiĄûŋNÎlüM/čm―üólØäĐë;uĒÚi.1N!EíöB>UėßõlÆæqy=v]Ï)`œsÁ3kÃCWŌÁCįŽ4ütõâ…KĶŋ}|Â*ŒzĀütpaōÖ?~‰ĖËúÏZ‰ėíęŪô˜Fūürzķ―Ęąãę… ĸÓýû„’vĄ€qŅŦ_­ŠÚw[k”TXrĀŊģ$‚ČōŋžîþZøÍX2y0ģÞņÖÉĩó#cÃޚ:ßÂČøĢdï™AmåîÚjYũîŦvŦoūúįŲöÞ];Ę\uĮąŪĶđ.N'Ï}885tņō ĸ_ũsÄŌÃÛ^QK‘Rĸq•D ō%‚į&nÞÔýûöÚÂĄ°ĩpŊÏį=ļgŨãëVŌĮëm 8rD°:―uÁĘăđÛũ–O6ÛVæĶîþ”ZKë™NÆÓ3QĮéŪ†€3'3)„þčæ7ÂÝüÉ'=nRák. ”ėˆh•ĢĢ”čÝučÔĄVŪžã“ó+ËËKp·ĩTWiÕ~œZĐ ›yýÁݙôF,ÃÜYi­ð8œV›ÏČ[ËÏˑd2=víZd=!sŦYÕj.ĩ4Ŧ%„n‹= MŪtdjnvig{U‘•ų„ĻßŋËjŲD*‹ 62é3™8 rdXāŦk:zĻjýɃ_'ïûbĄ‡‰ŠÞĢmSÉEÆđĶ™m,O$$:”Ô™…šŋŪ™…į~ž;Ýx™nŲm1@Ífu‰ÔãtNVđmĄ•U=įp˜0ːĄĖJ0e3JéVģPœesJĐx$+•ŅïØwŨï$hŠ" †JJ@А ģÆm;jūyČnŅ7k°™ča/B(…}owúĮŪ]úæęũã?ÏŊF5!*žÝÍŪ[Ģ7~ūģčŲs(`Ā P)979vé_ŪĪv5U›KĮVgŧ·‘ˏæ6ļĸx‡gâûááëßÜøa9šSšŽĻíč>ī2~qx|Jg‚ģ­Āvøkj-Oی\ûiâæÕ‰yg}‹KpMãņé[#Ģ·Ū|;Ž•mÍuMõĩ|~lhäęŨ_·Iýž§‚Ëdxzj&‰Ū=1ĸbn›ųŅą;Ó+­öUÂė­ŧÓģïĸrØ&PÔBû\!jĶķîóŸ}ÓgQ‰īę8ÖwĪŲÂ~ėÄ`ρFSŨņóÝop†…r%‡ŧÏv·7ųvî:uöýÓGZvwöŋĩŋŲĩĢšĸĢö7Tqƍv·ï°Y|Áj—ÝÚvž§ŦÁYĩũČ{ïÐėģ*(5TÃët„ ,î`ßđOÔ8Élˑ“ƒ―­‚ĄRhŦk ļLîÆƒgΞņ› ĶýØŲs~§ģ―ŧïƒũk]öýG{úŧęmîęþģį6x2ŌÔyŽ·į@ȜŦącðsM~j6•‡o~xī€@í jŠkÞWŧ0ŋ9?*Đ@ ›kÏūD&8JĨŸVsKmã …čÍ/›2‡w§1ÎëQÅL4·vž­’Jš›(ЃŋĄ%ĀPJ‰l  Ë_ÛéŊD!8(@† LwugŨ†  c–ÚæķÚ݌įWx•’h ėë ēdíÁöʝˆ Ītōĩ KÅ^ŽvĖ%d{R.,,ÔŨŨ !0ŊĖgßBˆD"‹ÅŒ1ĀóQEĢŅÂ[K<ïõ.-ŽŽŊ™––_XTëųóW\cNRWÁÕãŅÍÆļ·đŸŽžfderruåüĸûðÚūĖÕÜÄŦâęė5ûīÂÎŊ •„ ÆŽ‹W?4ĨŒiÏäųéØÅarƒWMFóëäöčÐđŸ„ÞÍŧ\fsœ§åāŅ‹Œƒ}ÜÕĖĄ·Ë1‹ōþúÝëÖķA?]ôöįģČÞØéņÖš™žĐ—Ļ–…ÛøþATl#…ųm`Wk “‚ƒwk“yaÔāéFb}" äņę,:LĢ·|k_Or“m|ē˜pîåÛz‡‘mKEu{~ÏÄļžÃ؎ŊĘŪđÅÐņþ< ŠŅįđŊ§ )ũáÂĮēĄ—~tÞēŠdVXPxįïálj„\]†§y]0Ë:™oK}žķËūĻ[HcvD)Į u€gBÉåíāØÚi‘ŪzWS4$FV…Ļ.Ee*d !E`({ēŒO;Q2OęÆžūŠWØŽ…ŸÅIVœ?AzĸũÄZ—Á5bŠþXVWĄõđ‹wÁæülĨÛûÜĶ"M|ęlāÔīŠgh˜|]xŌ “ïIKŪäųm‡ČšŅ))zH–ä,7™ūúĸ0}ŨŨĶh]jŧôÂxļc86|ģ~ÎøÚtvNģ§ËŠ…Ã†K―NlĀjtå …á_IDATxÚžSKn1 ĨRËcgÏÐ\gĘķæ=ŸŸŽ)ī,xQâOlŋą‡ĢŠīÖĪwéËŌzoΈÖE [ Ø'i—öđ,ˆeJ”™Ô‚I å \ā„ā―0ŧG€)LøÁÅ4l–@ðkč―“4øIŧSRÉđlų#Y~Üu“g„~b߇Hõļģ,§čÕN4ķØŲ"ĮķÓ'H9šó)ĒÞ#[Bęû@ŌęLˆ–}|ķT °ģŊBÞðk…ïđ―ø3ād: íājŠģÚŽŪÃ<Åd†ÓFÞxnWˆššÍó !F@ĨEĪĻˑđĘ*PÏ`ė`˜+‹Ã‰mĪ Čkâ˜ōRŋ1g·[ycÓV*…߆ëcļËíbÕE'Ŋ‚5ķipĸmð]tJÍmÕÉ6įįúV)‡š ķ9ęíĩðŦ æĶæÆŸbOðbģŽˆjģŧš‡`AƒĘ3XDĐA=âr‘­ˆŌļ7Ë·3úÍË` Už0Ŧ\KŦÂą U°§ĄÅE°ƒ/]]ŋīÏ! §QŽ›Š+üSuT!_­Ŧūú79Ęeũþoųd„5•ē5 ô}Ŧ^ 0,ˆūj­N* ŋE}ųŋЛu$ŠˆüðRŦQA4)Šz_ģŽö@؋Pgsņ#úú4`P $DBdÁę`6›ŅČ螊IûŌGĒšÔ j朙–ŌX(„ŧ–5eóɒ–qOxļĮįm„ô &?nšQ# V;pĒ ęš§Û–eņAI:iũ֙…Ĩĸĸčw’LŌÎÛ(0ļ DJïĻ™eátIq—œŋÕfdIŪąĀHôģųü‡ó™' Ø76ÆãõáXhšį6ūđČļ^xæ[ÛĶuI5 *Él§,=HĄRÜÜsF}#ü;’ŧÝïû;ûûí‹b‰ÚW•Āf8žÄîðÍöŲ–§ tŠ*ƒ0 jo D‚9âø|OIUÂÄ`óƒ}L5•Ø‚ üá;"euA@`•o_B*Ļ4yõޟ~>éļ#Ļ]‚·_O_ïė|:č:LĢIS `'Ž&3qÅdpö|Ë)ŽþņG{!QŸ=Û&LûũåũĒDÅņÍæ:âĒ^iðĨ˜ģ—Šˆ^ƒ RÁ-„&›šitSa6ŌĻ™ŲėĄ2EĖikÕDSXbËĩÚ~`S=ÕKADoýú‚čŨĩß=FDŌũ2ĖåΜ{Ï=įÃå\jč;Küm}Į €Ģöëi‚ýŒĀ.øÂßYöģū{ø< õüõÓĄŽÏ)4„āu9NŊÓis ßh€Ņïo~Շī@ĄmQnï^éĻüŪėt+8nbËúwŪĀi°Ý<ãĮĒ5ūŽÅ:=ķL2ffņ&‹ÆWM„ĩÍÂĊßīÍÏķíŦüÁ|Uevû⠍ĐC~TęÛÎņ Ã0;—™-)@ۂ°æįģóŪ|{ eՊuG―U­ŠĀ ÍiÖžý`ýKĢî9P™âyŸÛoĢ­Û­Ö™~+Ál[ĩjqp•IØĀâ€ÉšęŠę6K`‰™nČŦËáÕ8 X˜VO‘8hTr›m l·‚ĸYÖ―ˆUš)ã-bõ Žo)Bܞ1‡ÓëEļŽŲ€Zo~Ó{aBĶ{fu*pëėæVUčŒá=_ВLS­|'ÚäĖXĶ"îķuWũ+ŧ”cė "Ļ”ķÛŨQŽĶ)cŽ'iH`Čj–a‹QĨ2ĄPÓČ'Å)ÎĘxĒođdމĘ~myæh–Wĩ”‡—0ąŠ­æu!ÎØú A&įj.ŊGģRkAĄï5™VUlĶņAĶ“ØKÐŦnī A ۝š-tJ­–Nõx=Qï5”ļÅëó%’’y ÖĮ{҇iV+E ÛSģ4å7҈ˆŪ―|ŠîÏÚ3ņ3Ē ą‘Îȟ ï"ārčxýÕŨ€4Ž―NĮT§cĖE fŋų] Ú0Ðāč Ē=tĸĖÞUޔOž ·+ŲØģs┠HGrQ>'š2ĒŽŨâ―ë{!Ųđ?œí„ēšQä;JLk49 #΄ÚB-ž ĩ„ĖåÄšcē\š\/WÎäĘĮærJ5rý2Đ/ÔĪ bRų3[‰ZŧžíVē|ĻÝŦ”Õ‰J4sáėŌ’ÂÝkÓ äČЉōK˜đŅĄpÆ6Ņļū.WöTBS‚;éčŧÂÕ\96ˆÔŠBYÚ'ÄûáæŅœ. „cīũ/ÖĪÏ5áĒĩ+MįQ9UŒH­’č›ŋštOIĻëIn})2­'Ī@wōŅåF–ÆĻáđš8―ōČ―øÜäékvŽ(А[z­w;Î+ð^ӛ›*õYM2ŅÎ<› …jYîHeWųäĩŪ‡:œ8yãę̓láÔícƒh}fpŧÞMøæËą–ž• AO,„"ayšš_(+ŠŌž…D!Xí^8?ŪÍ+i0Ú9ųÁ!ŦĪ›$ųS !‰>‘.ŧcHęÕÏXŌö?j€/A!G·‘hÄj§:yvóūp8!”ã7ĘąņACm$§ÍÕ;vœEÄęiB-­bÎĢ…x·Ē–Ęœm―]'q#ú A 7íšLŽ(‚ øô`æđŪęōæe―ɘÞá(mþėaáFÂ!ŦŠžmĒQ‡!§ĖæKļ|U…ãŧy…ŧÐôLĐß7c(Č37^Ķ].iš=°õnJãEqR2/a†:Wķ_zĢëđo>l_îöũĶ ëVŪúÚVŦwÛÏÍ^ӊfX~5ÝdĻņÖįå ÞaŠ?Üŧ2–ZģŽž{#&Iđ'tÞöųōdûÚīé'†uđũðFb˜Ü}ÉkķßrhýeōíÕĄóQ›ųr­–{îjđóčÉÓ~ÚŲ*Ûp?åi#’oԟfąėãÝðõ―Ŧõ1~øÎ7ÜÖŪjđīÐÝĨđÚŲÛ8VýĒ)îvôBÔå%Øļ“{Ž}Ûįi™ŪŠß-ÕGQ˜û)ķXôĸ‚e.!čd™ģå.€ž°2,@)īVŦ-Ā*à @DÉóßÁšX[j.6 @l>ëŅÓC&i;Ąk={ā}bMíļOZ6qbOŠ2]Õå_ĻYØÁĄ!ģŊ&O;Ö@N›ĐÁHŧ'ūíŌvƞŦdĐUú|S·Yėáz‚MöšöyðõëZō-:ŲŲ ^maŨöRPvÛsÅá@Š›4WåŠÃ:zcŪ@ŪNÕ4ý"iÔĻýķßoZ3WÖBįí“ýxÐ(1QÅ.•> *7Ã7u*“‘9ņ ÓÞ4ButýÓ@ žčkō7@ü%č€ŒĐY)΀`ŰÆWļÎĀåÎVnýąā!  š‹  B€Wj`ý…aŽC‚}îh3ÃÆŧ"abpEHH Ž íZÔ듔aE–įãÆŧ:[}“1Uø°0ˆ(072đFHķ41Ėbō!ē1ÉV9E%_Ė9„ēÖsØ@äīēŠĩļgžHp˜ķ$MýËF  mpÞ50&Đ‹7mĢÕÅnϘ=j4Cŋ“76tŪHBUīĄH‹ ÁĒž’Óâ:Ðbž- #Ջýw LüÏā/ •ã bszzvúgŲĨ +V neÖ°$–—ĩXü\œŊÁßøïĮŸUĸæ@XÞŦþÅMÕŦVQ[ —å|œĖ' §đ/ MBß@,§t Â-D,ī’°iĒĨĨM!>‚O㷓°BČėßėaæ0ĖÎl ËeYŸ}ûō†Í ž‹ÂGöŦÂĀÍ`äÁ°ĢŊÏ< G.-ÜÕ[ņMóuwüúņ‹—g—Ģ/ąŪóïŋCŨŊšýŠ0›aé A–œ û@ [%ĮPŒÞÄ $7äŨŸ]všKŦõ…FB>–‡=ÜFҌėŊ0šðäâÝïą0Ā;<ķZ Rš‡&ĶГóZzÝá`-iĸGôÏļĀ\―ņøôvo…úðĻē’œÁ178Đ$mw|š/ŨfÄę$ÍIŅIï§'?OńbBðå|ûBģr$Ž"ũɊé°é9LļPéžÓÓW |ņÍËWŌē’t\|\ĶeĀáÍčj3 CpX~>ŧ ņ. Žî $@PčÜU§$0L%ŦRŊÛ-ŨÍ4BŒĶĐ­Ũģ  4ĄŠQŽzmá°q`Éi%”—ŠKÓŽiE€æÝ]dfį"r(Â)–œŒœŽąM§!9ĨGÏÐdrNg`;#&æŽð'chPÅ0ŸvðķŋČÍkõ/ûV°›0 C‹4ØšNQ&.Hđ0ņQ=õPqKĸĸļũÜ·,ĒHVi€öhíØyķcĩŨEį"Āŋ €Ā# ›Áiå›óĨTSė hūä|rÎûōų=~ØÃF4Žz°hŧ>08xAųŊÜ ïIrÏ< ũˆ—ŲL(›Ģý— ļžĘ•C\§ÞûiB‚O§OɅčŨ–Ћ`S#S@ĩēQ0ĢU{XļļІݰ#Ļī–=LŌŲžāœ ÞTęMKIPđ Įėá(ïītQāðí>ābt‘N:Ûe€|'ë Rũó@ŪEõڌóÍõžCī}‡U7yžæ>IMnól5]7ŒĶĶä9'ŠŅJĮũö―ĀļÝZ'ucÓŧmkmZk4Įv5ŧ§ãė=.šÆōaķíÆĒ(hēÃÄo‹=5GÛÕ-‹ÖŒīČÄølpD#B x5ˆ·{~ƒfãÁLÚQ‘ŠčĀĄŨęßôóø5–CĩØū&mĀ’k!oAęðO]BrĨ+aGĪÐJVvțûdĨLÉĪÂ?ĘČ4&*Ō*ˆJ·čR"ËuÄ*Ӌ‘ —Gɜœæqą­6ÕrĄ/ŧLNQî|<]ß*–į3–ģŨþóũ†Õûïęjq6V?ād‘yÁ—ŸšęŸė[LUĮ{āĖÉ<øāj―Ž,Ģ4téķ€ĄYk}ðĄÐ™I:gˆ…Ž0Ō …ĒX&(ā*6ÄJl„Zfi—KËĨSÆ+†‹šÂb#ĩQ’jIjLŒ/ÆôŅïl­—D“ÆYĘþŲ™9—o>ûË7ßų˜YV„“ÕMĀęĻŋýNĸ­ǰC7ķĻV„0ŠyX]V"Äp―qŒjEXÍ]uZVâāÅa`ÄqQVWŠ Ø―Üâ*æ€ĘÁī1·Ė~úĻþ­qÝ·LXÏą9ŒĻZĸœ8Gcî-%âÚ ŽFü{*"‚ "Ā+cUD)Æ!ŽÍ"6C€ēSfYũzŸ9ķČŋÁ$< p3<Â&ÂŪĀø†OöböĖCÄĸēnUąéki‚E$ļ\.AÅpŊcdō<Ŧ„ûøšLŪ[€}Ž‹Ï2ž0 ‹lŧnþ[ĚlÁ k6‚ĄËĖ4ĖæõAv­<,‘ˆ° ⊈eCxîūøáį=Ë^xNŲT āĢP,|φāD™ˆáųO?ŒŋûY7œĶOŅDE”ˆ$3âˆcˆ‘ĮI:–0Ė(c–m␀+ŒĀ‹Īƒąāō"‘-)Š"ƒwāEõĸ r€ČÏW162*>/° Þüj§B$ĪŠšœy™vM{eņz@Ö%Yã‰j(mþJŽeÔhyĸ°/LÏGŲ(’|É@ˆ +IC/#E6ˆŽéHRDƒŨG}z `Û0ŅeYöéR ĄsÜôą0n`SWLNq”Õ›ŅJdU$’zh‚ŨPįQ՛˜ú`r–ž=ŽfdĨ=‘œå5$5u݃qąîW'čgžQũ ÕsÔÉĩhwģÛðŪOÎK7 !#sujf~lr\Ķ‹—IŲ––™ūm›Y—šüˆŠYOį%oōōšė^—•§IōšŽU›Ōbųž‹öbkž‘ūã‰ĪXYï㐂q„_‡nQW|ÄģŠąīóĒúĘÓ0AŊÝï{ĸÜúJOR/íŠM8š[Ü,ņEug‹?îŸnéĩéĖx‰Ū töø―įlšp:ĸ܉=ÅenWCӆķw^l<ðJÏ>w]įøžXUĒ?­īÜÓSÉ{ÏuWŋP<”PĪ]ý(ũõfOþ@įޑ={†< SVĻĸ°Pq"ũõãų™%)WoF+‘U‚đÕvh\^Ý8ûēM)íޜ9ĀéŠh;_”ŋw’‚ũēnũ /•i;ãåYŲŊï­.Ī Ą”ęĮĒtöØųöŠíP ‘9įčCøÍž·ķƒãÐPÎ$óúîáy{{čįZu‚ >Óy]]݌V&ŦūNJ9 IĀņéû朎ÛßĨ‹E—­āhðÎ^kvËϖÓßn;UmWóĐ?[ĄĘ$ô•– LÐ#Ķčėáj‹Ö·Û4Ô‚†žžbÓîƒ'ĻģųK›7ÖÐ#­ó–ÓŅ Æ|č€5S =`,ýČ UUNŌ#•íÛŧjUNŌ.ĘęÍh%ēŠ1gīTœīXžžh…:v―K3“VpΐÖo<`9ãčų·ģ+šö}=AŋņĢ\ęĪ5{8wLLĩ:ģîk›Ž·YÝÏ$Ņó›ͅ‡ļúTĖ{SīcĖZ<󖜷Ës>ĄAČęwĩBÏÛ ĩ_*‡|õtÎ$@ūqļDP< (šŊ.Hė2`Đ&ŊÞvĮČ ‹.Bx,(Ü^°§Ī—ą íÂÂîƒ'Qofz*[[IF@IBWį'֍TöZ3ÏļsjhU›5ģ5{ŒŽï84Ú|Åm‰iœĒõčBBvÅ\čĐykÁ“ÓKŋŊ°™Ï‚™AĻM›Ī—v\īg§3ë& ,ętH/+&§ Ļ–@˜ÄîŠxV‰ĻĘþē·c^Ģ?U[ÝeũÜ72\t™?,tÆ(ŲuÏ &Ī 4•„ë‚"š :[h.vÚĄ§6A\=ÎXÍđ@?V`ÕŠĐ› į!ŪÖ&U[ģgŦų―4Xa;_4Ä ģÚKʁÕÚīÆŧãũŨÐÐVq FŅĩÕÍhEēŠÍô^ęÔohŸĢŨޛs‚{;·ŦwĪ]Ãûá“Õ&­P$›ßī\ 3·ō>oŒŌŪŠĢ=_ ÉhäŦ[ŠguÎyœåŦMŸ[ÎÐ/ķSŋŧ†vĩšåųh*]•í5ŌÕc9ŒÕjÛéĻėíîļó]+TâÕu…(ŦK ŋēJØ.ōþˆE”>ũĄ1‹‚ÞܒÖ^§ĸļs{+\čh}uŠ‚ŽœÉƒ"3čö™BݔÅĶšj3Š YcČ=i͔0VËæÂq• ŨOįœev3›sæé‚įôRŅ6ģï)V·B\―än€"Ãų·,ęP'ØŠéšÍW—DĀęÆ?X ?vEļH{'0Ņ‘·ŊÍęTUIŊ]ý>ýĖ“ŨpvØLičôŸ*3―îÆvŋĸā1^íéܰÕ0LÉÕļßôĨē€ËÐ:ý=Ã;ÕŌÝefÆUĨŦŊíāô{ķy?œáMũĩųýMû<ފģŽĶęöīœëôũ7'íÍĶÚÐ?,kĨŧ›Ŧïwžęn•CÂQV—D˜Ž‚ûWĸč‘Hž“X}N3―ūüļ5 o$ÆšŌŨŠJbŠKöļâbcS…QSH]›‘åRągõú ^—dÝWäNQ…TÁG<ŪŽ5Y)įY•Ï#ũę ïNÜôĨ=ŧ%)/QЍ@úú5é†,Äy™ŧm<Ÿ•.<žÖÁTÆÆƒZĀĩ>ÓX—‘čvéŠ,szä]zV‚H8ŪF ŸÆ"‘Ī€Čk°‚dUEc$jĶ.TŒj’ĄĐH’8ĪûDŽ*’Š™Bē ak’Œ 4€i21čũ•WKÖĘĒ$!EÔDYĮ2A*æ4Q7DŽįeMTL^7dEÖI@RĪĻņ 'r`―+pIDXÍ*|é`\ 5$Má01tÍļ°$*:ņĻnpœ°ō(8YēLČ(ņL]3Íg"*õYÖEĀ˜/Ýg †O3Gu3€D=Āaˆ1 cM“8EŅ4Ž(‚!М„E1ĀėŠFŸý•―ģYn†Ē°%Yą  {Xd:,`šcÁ†=+ïŋäœ#5ÔÎ0PB $:ąõc] ›ųzk_ĐņŸ—ĄSU§2dĩqÖØ;üĮ ZŦũYëF_r4sĪ8Š‚q…5ÖíīæriīĄN[û Íņ(Zs–?ķo1.ú] SŽŽ’Ú5 þ…°Ö•†Cē`]~wŋðāV>Ūþ€ÕøJgėÐ\JlīÂ_ŦĻE –EԚ N &ĘPĨā4;ø`ĢÚE t„=…ŋZI°z8ņ‘Ð Ą]ÃĀ éĘ->7ŠÆ ŲY‰U4EX­l&–ĄöOn’;9;ŠåVėNXÝ―ČŸ&ēƒ”î˜u&”ÍĸķŌŨUœ‡Æ‘@ ér9aĩī’k”ïØGÖ;nĸ6Îø<éÔå―ŋQQ Į:eĩâ.R|$YmâVœšëŋpq'Ý$—,6CÞ&óVU]ōýę4 ąR(ŲĢ1ĒUÜþå™X“ÛGIg§ŊKŋķvĘjmk\—ðŊ%Kß=Ž@5ŨUŅ;;æ*}ŪËøúM3į;ë“NYóqõŅÂó&`4Įú&›å@ŌÚ*Ąš°ŅÁ [nīš„SČFXŅ&Ąz$™uųæÞÃĪģŌģ§ÏđóvĘęŠa|@ēōŊžŧ–RjœDh%R­3!*?šÄjŅķmV$ŪÚöf-{ļļïÁĢ™°šĐ ï?ĢĮ%„vV•ŽŽŨnV›…’ŋēāHŽf-Î[ŌЊ€îDVkÆŽ.7uîpõˆÄg~°ŲĖŠ °†Å;€f ˜ĢšOkb5éOhąČ―uväW_gËåĘzįˆŦ`EŅĢEUšƒå3—ž*6íNVÐÚ―gŦÄjŌĄ’_õĪNY―ļ˜9` D ëĩČ+MėˆWkīKĪ ‹4ņ$ąštDVņŠÆhV)ĩ!5qzÕŅŋJĩâöZ𓠨Ɛ‰KŽ&‡Õ/Ųæąîž‹„F9ÕČpĻRZëu`vGkÕX“cw,ė/…uQ‰ÕĪýęĶŽģ|Pßđ‹AuH"ÁNS ‚Ŋ|ŧ s+!ĒÚÕbFÓýuR‰ÕĪXU|uX7ĩ`*<ĨpŋhŠhS GFaįˆXė’AW{―Ž@ĪĘŦI‡ą:+ 멉ąWgš0YE4…ŊóôģÐ Ē=,#Ļë1ŊĨÖÉŲäW“eĩŽ•]3ōâĻØ@Ðd!BāƒB|Ā8–ôë~>›— uđš!1–"ANŦ`'+~ŸÕūϊIÏ"’_mŧ=Ûū(x)҇ gÕéäðaéöýu&3)ïŠþĶYŨÁ”V}s]ÖÉé‡ũŦĨÅhĩžĻ|øýĸøųý‹U ĻÆð€°Q9 –Ëe…†ģš˜mĪúXđRÉÁŠ a(Éš1šî—YW]A J†ėįęšĒ“õč`1ī:֊ÕáöxMÁo „oßŋÂEõm.LęÄZĄz]õ.‰jŅXœŽ?dĩæœę|ĩY–Ž fOžŠ›*"Q$îīËio9™„/ĸ9'ðV;Ņ{žĐŠ•ÕéþxÜ Ɠ`(#uô}äiB8ĨˆÛÝē†H“ŠZĀ<ҚŽDĪ9ûXŒÄö_þĘîö]e&"(‹VJËý &؛āĩ3[[•‘šĀDŒ4ķÛώ„4,˜âƒß_{OŠ„#ÍSÅŌŠ žÖÜáš2Ŧ‚‚ū 2>xėŠCģ\ýƒ6þwŽĒv e­ÎāÆ~2Î+īæÃ~u盨jgZ7ŒÃ"āqž[v!‘GĀA&6Kėw^ۛNŽ}ÝÏ*"-­'ēūv^EąÜ3$đ†‚ŅZmm˜’ze `ýÛO\PÉWœģgS–E„ÝP…fłHÕā'þÆŠó“ÐYĶ(ã`ŧYÚĸŠÕh(;ÝĘ:+Ëj8˜ŦŲ īúģSĐ&p<72Ą?ˆÚx$VÁlÄŊó―kÐÅčÁFd2°í4ÝjāWGÖÛ%‘ ĩā?ÐÕ&Š“ũÛš*å< ˜lðÍߝĪ2ŲŌ\ĪBtðĮģšSĨeíÉ^Ļ RÁxēVs>°|,‰T·&~:―ĢÁķüüj/ÓƒēNÆģÉü,XM°Vã~ķ5–hͰ~Ã4H‚ĪåÉ0I§{l($‰EU úŠđÂđĮ…˜ĶĻ}8ŦŦzéėęŠŧū^ZZ˜ý’Ĩ-°6·?ąúļvobԍŀņāla­f“ īucVóMŅŅņ-NSІcí,;›Ž,ķ%hs_6VaņŦ[_?„#<Øc–K}ĢÕšxéuĶ~†‚wYm sŨūü#…ļpОz]_YųQË=Ķ %ŨŸV/ïVķ˜ĸÜøe}ĩPE'NÍÆÃģÃþ`Zį ŨŲģ3―öą^'užvt55 ŦĐ›{\ß;ĐjЎÜ2ÞvåŪAM­}u€ĢmVÉiüåŦWo=ĸüQJ$Ï8”†%^Hâ*-37FČŅ‹wŊöbŽMŠ•|y·n–ltž^ĸōėÃHˆTrŠÞÐRĖ Ī ŦˆRŠĪQÄ1bŽGŧˆ-ļ&‰€° j·Xß{xĩŅX°€·ĀNõ•žsm)ŠãxŊx-+ŧSĄÍîZīĩÞrãĩ°DW"đäF;ąÆ5ģŌąU6-5]MYŽŽ6Ųf+Î#[UŲč˜ĖŦ’M=†y&"Ä3ˆŋœs6­GÂĸüš{r=įÜ?>ųÞïýsïMäč <)tN‰ÐhNJãxrĘ#lg\"ÁGPķ2twEąý“ē„Čā@Æ–ëód|ūjuI-…vUœlŅ_Ë깑Ė1·6˜*õÜūŲGö;u'œs4EÆé]ïš―Óßj€Ÿ'˜Óea<^QÅvķVėÚäUÃpĖvï‹ZðđÞO%–&ûØÎëĨ9“Ë nmÖeszüŒAŦzúîÜCKôū5•°_cJB’Ķ å`vØ"=ĢóŲŅ9??Ķóļ—đŦé)i‰ĸÏX@&bĩ_Ŧ#ã‘Ā &‚k ĒŪâąüžßœŊ)šū^cš\kÖŋré Ázĸô äâĸ†UĪŦĖ戨QTÄ*\Ē1ŅÓ36€^äŠÁŒNf4pHŋŦÔU˜YčQqMÕÂ.ŅąXŒkũęoyūąú89įh™ÉxrburĄsOiMNčúT[Mö6cV›~[ŽÎ­–ņUw*ģŨ•äVzr*uÞ5ՍwļpōŠėâUI`:Ÿ-ßV;6…’ļœÐķÚ\oŽ·ÝČÉaŠDtih.Ęķķ}ĀĩĨäĘíŪÐ\‰ųÁüŽÔ”ķÖ·ßĢÁËĘ=§‹ĩŧÎŋmēĀFđÆæKĘŪŠŦæ°Hðž}õ–J!ž‘[XgjÉ?ũB ž:}'_`VŌŲsGŸd^^yxcíÞCɗŸų/ķĀŨ-ë?^Û,F†ŽēįiÁ§mģ%ŌÕö4ŧémVsáęzƒdïu­Æū?§ð@멟Tö^&þũ„õOŽâ'˜]3lōąXXĢԭßČ;ũ—ĶĒ8€Į1z؃j5˜―í‡EĩmÖ+Šj$!­‚ŽŌÚtĄ{ļl2ĨĖ^l6Ķ{’ėĄÖæ,'Ķ{PsÚt3ĩ LH%z@TÐ/sŊ4°þÏåÞsÎýárøÜßû=ßËݰ*EÕĖ°Šû “â<Y|õ?ŊR-1\@íä3‚üš7,ØYņ+nϟíU”'bŋ“AŧŦÁsÚãžz ýû—ĖlÝvÝų3ėīïÉ;Æ9ĻðŌÛUts}ĢØĨh8Ëęŧ·eũv‹( ŨÖĐjRÖnKA^ÅŽēˆotýÝ~Õĩ‹Íŋėu]ŋŠŠŋDÁĢžēQápŋ&EüôŅËčv`ë­n7ņŦô_ÝĨ†ũjČóTÄķ†ĪF&kÝÞP_Č=•âûÍŅĶNŸÄ•ĩ“Lā·jvrŽú^įÕЖmųōÁ‰bä8ˆ[EČŦ)›ũÁLžžOâđ‡A*Éj9·Jþ&§Âåíö1Ĩüą‡“ŒNHąŠ9ĩ”þŸ0įXEž[ķ •­Ð–SQĀ_·RGīðŠGë–āĨQLk‚Ur% ņqálŊ&E9›OÂR3ėWÄk❠åļëüĸēšō üŸï čīÅd:ZįĪ7øķ0>Så•]ĸq!jŋŦ;ÏÞÄęĘwuö:Þ UzÍ&ÅÝLeģaMÝÍÂéŽ^ŋE#Í2ÕlåBÍ!YýRTfĖóä›vlÚwYnĖŦŧVI<1=ÖZÏÛHV؁HõðđįÞ_‘MmęŌŸŠō•Ý_Ŧ‚*WqnĻV-bnŋ' óŲCCŪŪN?prýŲ€#ešTâõO”HŊ—Û[-öķ}îā€#ŧą_H”J–#ŊJG„ ŪŌ|7ūޑt*mŽÕPS{Aâ•Y˜ëWōŠ{›š%ČÞŋ*äZР!fMNzuðv“gR”:·bd/ēō$yAE^ĨŽJĻl+ŦuÅŠÅK1@ VQðœLÎg{u> p+ŊbJqųëL7îðY/“9‚eØŋzĐ\īø H‹íŦ(MÉáŠ;>­æėe‰›ÛxÃ2þœ1ý*Ž5Tŧƒ0l ņl8šđíbŌvą %ŧ šÐ T68ļ1Ė’0/w `}Ûöû͑CiĐ\eÐXŲuģ…%9Ūė€Pu"mޑt…B+“­‡0W˜]öbGAũY–Į"$úÍP]yIŲáHÍäÕų8_ƒP—óq yURâöGšĢ(ĸ`ÆæÕėÁČ{ņNÕ ÂzŋDs1cSķ^U--J=ŒhûJÄšŽĀ#[ĶĶoä°äðÍ2=l4œHOÝĖŪ:3…ėmh…F']ūÍ#ËĘŨþ8ŌKž•Š’æŦXŦ$ŦČđ‚§a jâ jwŧŦ햖Ī>­H·‡’C„öÆuÛ3؇~\NüĸÄėðÞž(ūņË$ņx&ۇ'Ëõžôų‹°:{ącÖq'PéŪ*üøšÛŌZ–ãWÖSa•`ĨbÅŽr€Ļķ…Säj!rŽ ļÍŦ"…æBë+S#V―ÃåGĒh[ėxÕ”uËōĶËå2š” ŦĩVv8ĩZÍn`ėܛ:h\;4\ûā{… ámWÜ ÁáŨėâNƒÅbéz*Jl‹QėtoQõķũũßū~ŋ=~(ŠVÃA0ýÔs8 .Ԏ‘·Ļrčb%ųŦä(írŊč5ĮÏēgOéĸÂęī$Š&óŦ+ƒŠöŽxXp%Rņ0 [M4\W^i1)‰7a” ϰjƒĀK\Ģ™Øå žGp-á‰Ýjĩ˜Ÿ[bVŸ\r]u#WZäPēâ―Č[FŋņŅđŋ‰ĖãŲ—E…―GLĮûĩ”R­˜ˆ#K*lŒŲĮ+Ąv.Є$<ĩï_û:ŌōLąĢĐæ’į\Œ$Æķ?>ĸųýþþíņŪqœKīņRíĄ‚ˆļŽ ýð!)€DëHÚ#äà ÜðŌōÔB2Ó=>ĻþŦð‚|šÂv•8i@!NsMKėėÕųīīĢVĄðlqņ$‹aÎ€KÉȰó*ýó ZŦ­ŊOaLȔ­°p3+ ļžŠeûÕÄ Đ*ģĀĨ•@ÓÞHĻ V €HŨT‚O;MP]’ËņÔ]‡—L˜úŅØ_nĨW)E_7?ýlķ§Óö]ÏųįՖód|@‘Ý^Ā™*ģ‚ZÏÓĒöáņåþ’s6ËiAŪ„?#pŠ1ĨHŽHqĒTđ8šĪ8pņGČݏ“7NwÏʃvrƍĖĒÕŪ$­ýéߎúļ&øČ?ߓS,| ÓNĒU ŨÜaEÂHÜēl Ü$ŲhtõĮņøVlÍēŽ,‰c™Í—éi-„U Æw7eY”s”Õ,ŠØe Vi’ŽBÚēāV_­ðĨŒ9vi?Ē;2―ī) ëv·ß~ofā XœĻŧ}2ÃŅ~îvÏÏÛýĄ"ĄîŨdýŽ8ó‰Oí -<ĩ+ \ýV§duŪŪ•ëSšþK+ū…ą*ēUaØBmYÞNĒŊO@]DTŒ*80ãSrŊ}­ūmf„ĩ›’E lA†‹Mđ@Ԋ—Ē 7_ŠĘŠ!•/ŲSæ1ą”‘h Ōû‘SVå[Ķ4ŠlûÃaŊ]é K=XéõӏęÏčX·Ö/åĖÎÎã„ĸ&7)đæûz_e•Wfąę]+,Ί _•<ÕxĀŽĐ9ĐE1ŦS•ŒFôĸ ĨyМCš[c<0öĀe’) QŽN}r€/ ;ÎŋÞÜT7•IXӇd;―­Đœ‹i"ŒCVUļ·Ũ`#Xĩ}ģoØį‰Ŋ˜‘]+ęëpØ›ķļöŦĄĀp ëĸ&øö~YóĄŦ%f+$WuXÐĩ`mĩÎįéÃŽð™X%Њ쿜ŪũōRŊÃ%ÏE+Óûu‰û`+"ĩÔĨ‚0;†D—#›=~§pV—QB)äp)1“ %N=ËņᇎBYÕĐÂoƒ|&QŠFuköŋëÚM;°@‡ö`u]Áƒ›fôŦmM}ŅWuJ=ögđÏ―â&ĀmŽ!‘.v­hŦë:žkÝ į“-·žCós6ö1(x*ÞÁ FåĪ“ŒJđH%ŧJWëÍrâó‹lƒíE wsA*-øazŦöj52§[qÅĐģÎDŊ ·ģÐhĻvˆ―Ą(|BĖ9Î SĐ·ܝ‚NûĀ↚+õ"ƒ:ĄóދކRÞÛęÛŽNĮėŽÍUAšxÕPë‹Å2SÝ.š$lņ/{gÜÔuÅqéIēäáŲ‹„ÐRTmv$5Ö6j·fïS\;xÃ,5·ķÛ@llˆ1ļ€ 'ā$84@°fmI!mCŌfŌ6i§Ó6m§û§þÏ}O’·ƒM§mzÞ~õÞĩ0?Ÿwîđįž›”˜˜Š 3PfžęfLKdÏēhm,ĖĀ’YXĀ+îJĶŊ„!īdŦÆÄĮ#Đžą!Ta°‚Õ‘UŅĘ3ŅŊĪ^ÕhÊgô˜vâ -ãY$ĢÛVã}LŲ3„Jpų隐Neí$"ŧž^)ģ(Ē@ Ӟ E} ķÃŽŠŪZÜ ― 5 šRbRāˆ†FNŽ!Vc™ÄŅQ`5Ôķâąļ Umčí˓[į؏óy’OeUj Vg@S’v%DW‰äŒÐI’•M,hÉĪéņq Đ(œ‘œ J!â_lQa7B·"Ī+PÆĀD ÏT|Œ’5Ä Ą‰UQąŌĶ VeĪQÁ+q*8@Ŧ”RoIÁ+&Lĸ§}ŽŸ'ųôAčĩĒ·w<@$"GĀJ ’]"ŽÐŽÓŲĀ,ņ žÎÎļĐԆðÄúĐBju<Dj<*$&stJŒ6ęhV5Z ‰"zZqN°††HÁ+#•^Ōĸ†OēÉ=ÍiáNáwú7[ X+›Ðy‘Cčõt@Đ'Ÿ@E–fbRâ(T ŌīĒ^eŠUā’ėRė{Š6)•LTpˆ"āüéŽ2ML93p;õ Pï?ļÄŸ:é",ąōŦĖ2eīŌTÅ\ÚQäxHSថgSvŊa•MŠv< wzMåD&ēČ6ybŚhE@Ģõ4 “6XäBN0t| Î:―y eØãwÐfœ,ŦQlV€dj-f5bĨē% kbĢTd•Ņ™J–* {Ž īŽEVlZŲÉ1ĐrãU €XĻUŅ`Ž ,2V!Ėˆ#hŌHđ2{•ō= ų}/YeM+þîņb-ŧŅý^“åul{2\6Њ‡đSÂn>Âę’ öŧ&–a 8ō2‹‰Č$Kðtአ°áfÁJ›4ŦQBÓ Ž“éã `eī‚kŌĶdnEĘDš™·€Öņĩ*XMM•ŒÖTŽBĖĨTŅĐ*čXS’―vS1š*– ŦD^ĸlZTAܐÖcö-F_0ŨÂß;VED§ÕÝÆHÁjĻ[j2JGETw~\M„+‰ôfčé}Í%1xÜ>ģ…šrģ\.YūŒe5ēļ|Čŧ`ŌfÕf^GnĨ)ßlšvÃ2iV)€­Ŧ m\TōSVÜKæ) ―*ē !šÃŽŽoˆĘZ•PæŠĒ䘍Į‘ąJ˜É*$АFUTpψX-Ä{―̈́_œËuoYĨîWõ$TĶJ"ÕÉĶĀV‡š;x1žE WUõnφŋĶDd™6ôČTä§Aįþę <ČđŪ^čūŊû|$`”ðˆ„ČŠs‹ëksó].—O›•Ė7MšUrūĮ{•1)ē‰-ēĪRA’DĄ`, ØČ3@ÂîXÅķ†ŧPNÞŪdjúĮÉi˜6BUņâ§é5Đg§ÃíÕQŽ Gô Cī äŠÂ’Ē*Åęļ…ž ÖđWÖ=Λ °ðÔ- û;šŸŨŠ:P$ įT[ïJðO‡P#V^Pē*6ĸÝK 2ĶĘx,Ē^%V=ęM55ýÝĮ0Ē‘’…åK\&Kmo~–ËgvÕšzee–ü^uuß`z0ßSkēųzųü Ų$YUJÓð6UÆP”ã{HjHKŽ”ĪŽ J› éÕP9Ū€ęH yąˆōņJSJBØąļŠXõöŽ2!DðÁšvá\QTīZđPæA֟|“'_Ŋŋ§ö*OĪâïû.EÁæbԆXeJŋÉ ^DÔg-ĄĀžŠ–Į ȂB‚îVā%'‰—Ē65Ï ŽŌjT›_}ęĨ§^ú bÄÍ^{Ķ;Āi'‡ÐqE<‹HÏë\}Nū•e)lĶÉڅiirEtü4Ą+€6PHŦˆ#íaĮð9[!ZÅ霑ęÅ:F VĒÅLY4æ›&ŲMąrVĄÔĪlô@Q•+`wdɋ,(Ōz|6 R]æ3ŨhgÂJ§JH―ā/EŦE§!aáKņcņŅ ö›‹B-aVAūDŽ„î ÝŠk”Ļ…ŧ›IĻT-“ĮŠØ?]$VšĒä1ē@§™ĪČĒcTô}EVɐåö―rđģsÓæØ6§g^é?as %ũ ūpšĨ~WæPN[wsYã‘Ŧsļķ‹oÍđ|e–I?É>VhUš}u:af qČLTNÎ$ą„8Ķ E8y$d&,"Įj‰ 3VSØĖn`ī25ÎUŌ:8WÆFdŽ ĀXUU2ī}îĸnsAŅęÕžŽÝM6s™3_o‘č`Jt:ėÔ:ƒQ‚ý”ZŽZđęķf îv—°u*iÉų’ Ôt›[tĻ@'SE…ZÔ-МFÃMFĀš*FĄŽôīŦ&uÅ+­{í•öķeW/x&þĮå+Ę/"ïĮüO=|ýÐÚÃũϟ3nãõÚķuå+žŲiČÏï…W`*XOub#Ё6>q֟âĐ!VEˆŲ.ÄjęčÞŊHØ aJŨTÃ,€ĘíÅZQ1Éņą ÁĀöi~áģNGŽŊî}ũĨōĨ+šUq qĄ#ĮũšĨf·GĨ•ĻÍiØiå&p+-4MŠ(BÉpˆ ‚úŒČ(%Ģ?ãdq*‰,û"•ŽO!Ý*Îø˜ę$áāÏNīqPĐĄķ•6ZĄÖXu!ä4V 6ėt4īŒ.h •S)„•ũX…ûuXģqĄQ(ĐÞŠ"ŦåÝĸėąžĩ+[~rÛúãy럮[ĸöĢŋøwîȇuŊ―ôuîČūúW{_y§aûQdFðU[Œ“dUQ”&ŦÉĐŒēą“ČŒp*Ēą LՆ$|#ÖqDpjÁ\MˆQ cŪh 73&E)î·útŸ•J+eæj\Áķs71>õŠrÏēgsŠ7öĪĸęéöcîí/Ŧu ôĖýíÍþíýßL/=óíïžÐJôSĨVĄąÂ°HÜ~ó†3(ŒŊI’ëĐp:Ķ7ņ·Ûã7H,jƒÁݘ:€~nƒdr •:âR…áóI Õ ĐK ģ݈~1Ŧý+—X ‰Á_Đ·ĻÕÞJƒŲä1øÕwĨoĻÐĒËlŦóo]‚aâ=Ŧ\ĮĮ2VÅhó˜īl·Û^― !œsއSįÐA ~‰Î‰ĢCmÝVŸÃtVÓíw8žÞlÏTép:―ŲÖÆ%Ŧĩ1õm=œÓÁɕŽÎH_€ ŽŪxnKëC\éŦ/].s\9pĸ†'›6þīá'ŋ–·öÉĶ>ŒĢÜ~ĐõČO7ŋú΁'Ö=ŧKmË7™&Ųķ’ÉĢ(>Šˆ 9­šīPQZ†šø )§b5ŒČqÅÄęĖhÆŠœēŽ*ôŊ2JgUXÆg•úW™―ššũÜģoœ9ÚÕēĢõõý9k}ëŲ—?Øđ{˖å|žĄ―påúöîkĮ;7<ÖÝĩKmœVąhÁjH,Þę3]55M.ŧŅ áünĮКo€súý·Úėā:kęōķæļáG4uX Ũ'ģęÖįUŸ­ÉĻЏózušėĀķ–ž‡; qTš―Ѝ^ũÐĘ9œß,q{7·4ŨZóvĸ>ïJ}šCįņ ÏóÐī`åÁŠ"ÛéFʏųåóÏŨižNÔ 3žĩgVRēÃĀO>xĢk‡ŨĀ4)·ŧ9{ڛÍýóZgÝÞė'įŦŠŅޚÔūWšĘ82Âíl_ũÜĐWk:r}ïéŨŦ? pÛÏßÜøÓĄŨyö›ÍZ âÔGŲč"še'ŽWK VÁjR˜Uâ4"tÉĘ#f'ÚQãHؒ…īŽ/Tž”˜Œ^!7X%<ŅgEˆ2[õ6ŽĘįŠ**N`ĩâÜĒK۟?ũö‰WŸÜų^OųāÚkĮÛîkYþŧÓÚŋÐtæ­ýI‹ŪwnhĸfsšdĘž#Y tīœHŲ| đģŦ.°Y‹úšr4ŽĒ˜‚2‡Kg(ķuvŨ5öÕïfaJÔą"ŦáŽzĘ27Õ4Åa 8†Ē Ĩ-õ œ/zMc0―Đp{ņ &J°83Ÿ?ÐĩKduŽC-ēŠX…ŽĘ­:7ũ›ĢƒīŽ;ŋ‹ãķ& XíyCĐM•vMuâītî'Ÿ<ĀŲ7§Ķxí\éĘÄt.ĸÝö“nŊÚÁmÛð_ķ—ÍN X•ÕŦߊ䑹Þõu/žōâ͕įžÜÉXýrÔė\ûŌ­ģϟ8r―ãČÛMgŋ]o3ZōG ƒ`Aë&6OŌY-(a―› "ŦLŽa•éÔpó~,ŦT >”„5b0ŒF–Q ―<=EIÄ*ėe°Đ ŦUZoÊL`U˰`ÛđöSGŊo=ũAâîú%k{ķėkÞԕzŪýėýWKV~áāĨš·šfî9œö…§ÛsÔũ‚U‰ŅmíhĐã8ļį4žĐé:‘ų|ĸs=ÚMÐīuŪģMîŠS͍5KÚúŸ;‘ŪÆjÜøŽH+p\ĖęjĻߕVŦOuŨœ°Ų·Öôg4ũméĘņúk­Õ§22šÜÄęŲú]§'ÏÃö(VĢŽ~ũށ―HĖĩînӆĨÕqmæÏŋÜPýōüōÖ―ÛĀęŠ'–îkæė‘SąîW/~ãÃ8ĻÞŋ~xðÃđÜéþ‰U‡•ąJaUbþŲŌųóĸîôÓĮKŨ_š·~þŽöŦu}—ũž^ĸõž3ŋ^ēöí‹VôTŊ―œÞxnŅüû›ĖČ7*Ó=uŌēIš€ėDíUÆę á)Œiäý/ŽÄ ą6Fħ#@D·ÂH^ņkZÅē‰ąUÄ*éR˜qŠ0Ķ·gUÅLÖ o|ëf`cyýžýƒŊõœzĒĩĨ5õûËũlļÚÖÝuðƒŒƒí-ßÞŲŲ]óôō:·~ęY%šēÁŠŧ’Û48p%c`kMӅ–ŒęģÍ%}ƒ úN”eķÔ7ķ.^]PОŦFwįžšģVÃph^x*ĢķĨūöWƒ›jvvķÔÏ;›ą öEšŲ`Éޜ‘óü‰ôŦdŒĮjšÎïåÞCZîôŦŋh{ëæÖõÏ üė“ĶŨž{áĩK=gūuë'Ÿ<ØųÖþšƒýüÏ;n]yzĸėw—ŸŽĖÎt–ūr5oÝqîôŌŦöĖėŽB˜ûÂVčŪģĩŽây•ÁYKVōÅŦõ†…éÕęmGþ؛8Ïâ•ŪŪôw$ÎRĻ11ƒ Û― JyÄhņÖŦpĨŦģFēnQA„† Ą*š°FĒJ1*‡Ņ6QGģš€6?„%` ØÄČUČíY…€UxWV z/f4īÜ|`þŽßîæÚëŪÝ Ū]VūüxõÁEåõ•ŦŽ.}ōÆƒKWÔŨLwd2ŽŒīWͰz2āĩoŊoj\ērO}ŲŊN4ä%ΜL9Ó\VÚVëJqĶ™ŦC 0ô…Ū-]ŦWĩ6―yŠ{ ĨgaË`ōƚúUr’ŲîķûærhŪå­j­ûUMŽą:ĮþĐzU“ Vï tŪĸÅÆ/Ÿ=xļgãáŪæôęwũč+ĸŽnŋķ?õ•ÃĮūŋŋŒ+šgý[kƒÆĐãNoØ_‹œ_§û™ ĀX6B‚ýd2žPāųϔp‹Ûšï°Û5ŽŠ ßãqšģ܁Ōūũ)·Å`Ūä+ívĩÞĪõyĀĶāœ•+B_@ŦėlĐB`5uŦėéŠđL!bëJŲ}td>U‘Vņ!ŠqtũNĐ|&zS… Ôē#ĩš"ÄÆN˜UEÁ^āęM“åŠĪ™:ÆlEÎ šsÃÓÂŲœZĮĄiŦķ—ú)‹P―‹žĸņʇģęV`ÕŽŠŸą§ŧĶĶĶÎͧyĻkúŧæáŽīŊ§Ž^iķŲ#mŦaöŠŒąŠ‹P\lã4ýõŧû[kjzīœļ°g jķŠ~š„žmßĖą›MęÏv]ėÞÉ­Ŧé{ŦâĻHØŦv‡6R˟þþ­O^zøRN)ō}]]ðîSó—îļEŽ.ZīÎ7.8Čߞkp€ÁŨ–ŪØēôýŽFl€ÐŦšōÛ@LđÚ )ŦBæ ōz_~eŊó/ĄëßĖæũBkĩÞdÉŊjó=ū^ o“UÛō1ĒŪPN„zTĢbi:&l, {‘u$ĒŦīBã°ąŅĨ8ze8ŽØŦa\VĪ–a}ĩâž6˜Ŧ`•å|ÃBMĸ˜d0sõģmÖÁŠdŽËӊŠ…ˆč°Yē‚äW48\K…ŦŌ ņ8+ƒz―Ûôäš îŧ _—Uĩ6V†UĒëhirúžï>VŌW°'žAŽnŊ™Ëíū?ŨŠŲ‡ŋ6Ÿ·č{yWEY.OҁYŸ1+(3Ē^Ŋ–ЍĻvĒŽ"øSĐLIŸUˆÏ f%.i ĘHŦψ=ŠÓ˜öŠ!*ž„+OBO@ŽBHĒA™J˜°WqÆģ`|k(cęéĶýĖ”ŅÍ2œMFādPiĮ‹S!―*ĄÕbąWĩtßWÓ}bNÞ֚Œ–šĸ™ĩ-]ßÜsyWÛÅŪû.Ö_čnĘŧŌi[‘ã>Néc ąŠÞãÜ\Ssߞš7ŠûšîŦé9„ķÕvŠĩŪũJWF}*ŪËōVœi-ģÚ7u ühÐ{öūt·ĖÐŅó"Ŧl•0―š]ÉíūQūlþūcÆWʗĸð/ 6Î_ūî™~īlÅēøÉ'_.ýYųēuÏūðņŅVÜ*{oé‡s8ûž@:äžŋŸ$čUWCĩ"ŦfÞã‘!Ðbņĩ掠+‹Å°j-ˆXÅĨ>ßÅgđQIÂë]F3†œëõ<Ũš=|°Ōdƒ Ũäó}.ÞĻCæ/LŒ3QV‹Šč=FčÝĸ4VCÚQ zÚL6䏭a^ÁŠā)ēôŦ(â  W hæ1JĶW‘Ę•MãMa+䰚@ۊÆ]ŦJĪ`Cŧ(Ä"!e6ƒ™*ÁØ/l íx#d•<ŌsTé5ŋ‰ßЛ]Ģ~35)Åí^PéX˜ššu 6?!iå› \ɅšŽYKLšaýO •,œâ%l@<ęĖÍc1Û­)™ž4+=/y7ïÍĪĪ”€―zFŌôBŦaóīÕjkó’€ÛŅ›R84―pžÍ –ýåčdJ•ē~+æģŌtķÔtw pŪąĨ{pŨŲŨßú(@ïï†1}bŨŅŨO9ĖŌlã2ûnÎąë†ĶïōkėÍģSv•6Ïár―E|$ä`zLžÄcąð2› j4+ ?ÐÅņē7y\`PËg}YĩA“ÍfŪöð.=’&å›\ļStUČīC‹‹ÏŊt’gRÐķlâcŪY”sŌVq=š2Ķ?1úÚ y€ë4Ķ@ɇ…r‘U ,l1XiDŠ! =øđ!V́j4õŪNĖVĨÔ'›‚§ģ•v„:K%f՚Œ° ÜØ)Hũ›oBĒRĻÃâõX:L·ŨāÐĀJv@Į N{ĻppvMž7 qŠu 9$"ŦôåŌHģË`ķsîėl‡Ûí°s°@5fĩƎÎPŋ}ŸjƒŨËęą[=:‰W“íīŠ·ŨŽöH― úyÆ*,•˜"Õ)&ÏÔxýÃōŠ­80ņŌ‰―ÔÉŅÁŊÉF Ýb=ÆiœNŦ5NaUÆĶóØ|jŦNgąxéËés­ˆ!2āŧÔŦÆnvŲrívÉäöĢýåsI:ŽN·BģųbƒC†éïü§ßmßë0#F{ĒŽŌ åp―q”аŠĨ„*Ģ1!†oÞpZÁˆތWąņ?üåa'č `9iî Æ*…­(î„UôŦ‚ī`•ŠĢM:%"Ķ–åĮÜ#ÔZ…L#RJĖ:§ÅâÔU˜u^/[*ô ƒÁĢ6įĒ)ŽÎ•xŽĐ:6Â*ÏÐŨ„>sŽÛũ•štĨO_‰nZÚčũŦݕ†\o™Ųýéæą'u*Ņá čyÆ*VU\$ŋ‘šŸ―ĀÍ9―n]žÃ ÖvƒAíũj^§šBít栚u‰Ų  x :o  1øŊŪRâũ;ÜfŋNᯠNŊŨk•ăՐõ.ÃŦœōpf6ۜfģ[ŦWĶÎŅdj[›ŌŦW6ŲœÅŠĄÄ—ŸŦ>;muķđøÐĶæ./skjN°Xą5q—ĩz㍓đ―‹ûÍSïœÔļlĶ;d5ņHÄ įüâš1'īŸ„!(ÉŅ4ôęŒeýcÉ* ZÃ.ŠŦLįŠ"2+V5 &YEQwKÔ/$ŊšŦŽL\CŦŌXmQâÄ \Ø,Ž“)DL·ÍĖU~,Ŧ|Ž\FŊm„P0鹀#SÉÔŲ$ŽlŦÁëÔų Nï`ßíôútšBč+(ŽĒŊƒFē–5Š$Ēsoæ,æ \€_äÂļļÕØŅŲÂļqEą bâšJpÍĒÛÆÆĒ'ļua.ØÝ •ófĨĻ„7 Í·iËr4ž{ŧ§oÅņũæ_ūōÖûÚĸ⨯ĨOĶ|'ðÚSûŸ}ßĀÆ—–œ:š_ņãÃMg6üeû·nĶž|­áÕEĮûŽþ4ýg7LWûd܏–ýã―KsųwÄjŽí Í\†ú˜1`&-˜ā" fĄbkDģ2V§EXÓķĒ âIŊ\ÐŪ x%‹ąþŽūžDˆŒCc<ą*ˆRHuR§FTBÖnu,Ŧ2(Ö(ü˙ņÝ>{6ū.æAŅÏNQΎŸįaœÃėøøŲ1ļˆ™=QĒĀĀf!Ņ‘„•j­œ~ yņņó°á!%ėĒyģgGϋs6.gĮ+ãЖ…ģgϋĮ [q@ĩoâGDãe4}‡č88,ĩĖj!\yĢjތÄi+™9ÆL4á8>Į•bĶęáIÄ5ÛSKƒ%ŠĒķ">fũ/AĻx•,ō{0™‘\Ücß~þ–5?eóËï—å­}ŧnãûÓËoqŦv4žößc…ŒWĸŽĪõíˆfąn{ųƒĩåíįžúÓÁó{öÓēUßĸįã=öŨ–;røļ]'ö* ‹NN}ä‘P ÔHdERŲdÂôΟ•° ]ĒąŅĘxQģŠ=\‚ ŽWąE4ĩØ@K=VR9YŦĪQĻýLV)‹ó@[ā?аÆ2ĸmS+ĐW…T_=67€ÐæŠÎ'.Zqčęˆ VTÃÝVHJĢ$•}hŲJÂGN!ėtL9Õ$–Ņ)“‘)dÁŽ,W­sûų /ĸÅŠŲ―ĢĐå}ŪíŌïđU?l8ō―Ūí‰îŨĸĀŲßk?qä§Ų˜úhãüōÚßxųŨe{~ZķûƟė2Y óÝī?ņâÕ2?ožVÉÁ9AėhIÎ@ĨôhL…Âķ$‰U†rŽNĮ­ĄA…X!ĐĢû­XāŠā]ĨJ”ĒZdšõģl†Št8ŦÐmXcIŊb%_Ā”ˆVĮdžéš|Þ†ÐĪS’€ębŧPĄ^6eđf"ŽVļŽGŸŲÛyņøÏöýžņ•_*ü‘k;ÏX}mŅ—óÖ~/qý;ÜÐŦí `ĩtÏų+ä†šíÄęzbõ᜚ĮœēĮ;þøüCœĖ4aVéuŽ9R“ŌO7-&üōøĐxÜ6œDĶL#c€YðsÎ •ÉXĩjh4LD„!\â˜Æ*XZ€ËÏfÎÕQŽŽX„‰ÞISK§H`>†YW&5ä^4þ"ÂO~ĸX_0ËüaBá$j›\ïōdų,žŌßÜXīč퓧ß]īčðÛÖŋÏmŦŧŊí]{mfQ’œ^ũŌĒÃĮŨĸ=PzņüĄõK—.šî=wĐĄ3͝ūņÎ1Ŋ{ÛđOöÚ5Û8h5OØ^.pŽĮĮ'‹Ų|áÍÖi8§Ē„dH yˆ”#!™üĒrH“ °’f™’0-‘Á*Jx„ÛS°I4,0ĖŠ’V4xōŲŽ ņ€h›„X…íFM, )U9ãl Čgē2ØōYđ‹w#ąĒ[îŽ$zTUĐøĢ&'üĻŋ—G†L ÞLšÐ;āhÛÓÚ\–·u§·ĢiĀ>tÖŧį|SMýŋĩmKMģ-skšâÍÄĀÐĐîŒ―y[§|[ëÜÏÖųԙ+wš3sŦÏÖYŒwĒWãČϒûAƒRJá€Ē™ā­”ÐŦ1ôŪ…Pu𠁃ŽÏ‚VyIæ*ąĘÂW™đšB1W4"ðöŽ )XĄX)0Ė*YPøD*óŨþÛôęXb$cØÅ~\–Į››"TÉŲļ&ÐÏcXÅį“yŒýĶFō„čyū’ƒ?,7ŨJà ,:ÎĒ·{ƒjNģįą2”ðÖ·āq:<&ŦÃX‰Ŧž †3{IĨ•sÍjŽC%Nįâ'Üķbĸó,ŸĪÐ―N€BhOęT^ĩJēMa˜*Ĩ┮ ëŌPÓãx`Ņ€uøëŸą:‚˜ĮŠŏÅnw{VyްĀ*îģšÃ`/*ŪĨļX*Jķ‘§cýcoÜu[VïZ[ņ"Qē)5ĻÆņYåQ~Ũ"'% RŦ –ĘĮŧ$TÃÚŽš YÆ ËĒ f9·&–ģ,Ķ|“ßÂóF―+ËgËõ!ņŠ…Ŋ0#vÅä“` Úøjc–Ė‚ ŸEŽ*Dģ‘$%†ô)Ü'LHų)a)ÄĨáĸU(3Æ*\īdēN‹ô~ApAUdæ*Ķ­bÞUfŪĶPŠ ‚jum+u°gBn„9sįæäÔaËY-­’FIŦ ĨrœIĨ‹‹Ē a”H Øäqlþ Ā•FŽOč#`ŨĪŅ?Ž$ ųą&ĀęÝKôĐŠI(ˆq,ĸSÍ*Ģ Aþˆ[Aā f…·qbÔgåæƒÆ2]ū/ßD`€lSVÐcĘGĀ ËäC)QĐڗ…kdém6TtgŽÂ\Œ†Ļxˆ‡ŠB<ĨˆŸ9SĻ"äó”č—ēýÖPÐ6Ð!bžŦĖ €yŽ’ęēš€―ŠbChfŽ &@Ņ‚?ZóïŽÁōðG_‰Š†%PX â‹U ķjņøĖŦ /Č€Î"ų!iZIaAÕâĻ"ģdq•ĒΰðBÁâ" s%`uōÍö{RëÔþ”ņŸ7™˜{‰˜IT< -™Pl•Ėˆ{VdbqÕâÝ”›ôF~ŧAÓÄûˆ‚-FĐ$Į>āģD-ŪĻ5-HÍn‘Õ„i›ęG°Š§ Vj_ÖQģb-LÉâәÃXCÖuĨ8ÎęģX%XY< }•0ŦôWĨėČųč;k˜<þøšzWWUŲ|›ĶÍáKÉåUUéZŸķŠęPUQaĄīŠɰ‘Ŧ ðPI•ęBIIUazUUŅĄŠŠÂÅ―[gŽöUɑŠfŦĸĩ"ŧGipz=͉ ĮƒZ€'.ĐPBĨ8Å,u3•ãŒnÅĩ0G)ÎeF 1ŽÝ„YE#‰5rČSĘú;‰Y8Ļ-u+úýÁ!ŒĮˆþŅz•ŅJžN2wáf …’DÁĻ’XMÆägÛŦĖ3-˜Ŧô&Y&Vc;vŪyø?üðš‡ŋöҚĮëJ mÛ_ßąnĮ–ęĻâÚŠŠâMM° Ōk‹‹ÓԊÓųŽ*í…CŠ,ĻЂÅÚC/.ŠRuTÚŨoX·ü YĮ!ĐôƒÕĸhÁĀ oķ˜xþæ Œ’°ģĻM%éQA+uĄÂDš0VcUPK!ĩŠ*°(°Ruü<X,žÛčžm‰Ø ÁĒoöoŠRLbЌȧąŠåégŨÃYEŽę‡ðō‡|įké_|øņ‡ŠĨĩ›__ÔÚwôðqŲPÚĄ#WßčÍrŲēīÚm–ĄW[žØWmV/ŪŌæfŲ\ÕĀī°xņâÚ#Kũožņũ9°þÏę―!6ķ;ÉÁ.—3ĮCāOĒceĮ”›_xplÅŦQaVYSŽËņõ`Uf솒_%FŌb€_*œ‰*årĸXšxȰ@i% cY 0Ĩî·û―'Ũ@^óQNÝĀjfGïÚōãˆ~úæėĩO\ŧ™ĩ{éöïš°~ݓ;mÕŧßÚŅ:ļİé`y{]ÅŠš§ŋ]ÓĩZÖÖZŽęÝÓš—ûó'9Á ãéUö3âøųú-Dp^åâ)~AwĻXe°zųŽ(*tfˆhņČہ°`0ƒU|83ņŅ―Š'ĐvÖ)Œø–YëX+ 1ėą"öąÆ!ퟚĸĢŌ­…ÎGûWŠdŪŌ·"ViXýôęš5_Úõ‹ïŽyüĄŌâꋗ Ķwž9Ðwôŧ5‹zڎūýûÆ+jž>ŋsÕš}­ëÞ9yú­}[Ž~øÆŸ_ÜWĸōũN–þxß\Y2Q”õūúþŪ|ų8Že4_• "ûœ %RĮÜFœY$zˆLâr™ØH@j(éM ãIȄX…ö#'j<č[vÂ|ĐÄ+c5!FŽĮTa{•ĒEq„ÁŪ$XgÖDĀ:Ę Ž5;­Ŧą”ˆÔĪČͰ„́H>+PĘV֚cīĻW…`l€ĮŋþÐGÍyȂÕôĄƒíŧīŦ;$•›ię|ņzí‘Ŧ/|\~}^ßŌįúwœäÞ{įØî=ÜĮŨn―öäInûŠß5~ĸđ†ÅR…ÖÝųĘĩžÅ%㰊ĸĄÏ-ĨĢ™5ęŲ /īïMBÎkĢā ļ—Ž>ęøÁJK`GĶNIkJņn…đŠ$5lDĄ˜ĄJXØ,ŽP­"ŽXGZŦÁJɁĒäĒđŠáŦØãD*IY‘X°ŠĶī#X‚đĘX%T‘Ž>þøŨæĖ;ũŒÕĖ‚Æõ—r$UZåėMʗ=uõXýŅšÃ+ĘË[·žĸ(ũņ'Žý ŽÛvmĸÚ돖–žkŋō―ãÅlëxË^5>Ŧ&„Ã›ÍæLÃįV2}˜’!hÂÜôceĘõZœN…3āō™ôf§ÆåÂh*“þē/°ÆÚN –ļŸA  ĸ9þΉŅīÂC†ą*Y…0 Ä·L #}bÜJ4™ŦÂÍh‹Á6ĨuĪĒ0ŧ@ĐHædBŽÄ„+aVąbNx° Ïę…s`0―Z\[~Ų“Ų֟ąe_ýĶŊZýŅËŸI8۝zqĮ1û‘wvBŊZtíōkÏĖõYÞ{bŲģsK ŌTG–Ýjð-.(U$īĐ0Ųæ|žeŨœtP)ģPŠYĩVäųC–Ąyĩf›ĨweSĨ-Ÿ·ų{ČęBđ`YœŅ;áE=KŒK9™Ŧ`59GˆŽJ)ČSdU ŧ‚ŋ‹9ZEXCã à 6AÁʔ08Œãqõ*$Ä*OīŠV!VĢCŽ"pÅũÐw^ó‡Ŋ} NVÆj”vóÁōïö/[þ…=;žû‹Ũũ9|sčāŠŪ-˛W―ĩüđe°WÏ-î­"Vm{ýĨ[ڎī*ūïÅEßÝŌúčļ6ģíŅŊ~åó,ĸ"ïÜ̚ŽÃ8ÎÆx{! gšÄ(.\\1ŌđÚžLĢŽ01G L˜–e%o\Jdh ÞĘĪ(2͔L+ĖÓÕēēēûíX–t9ÝĖSįô_ßįyÛÔLГý?^x/{™üðžÏý™˜i2 ­&Ž)-ÁĻÛ6ŽzŽbņ†-ęâĐwėø=Ö3,†ðÓ97P/l#(Č÷™ ―FĶsŌI)ÂĒ9Ŋ#Č*î [8•…Ëa8ëŠËE§ËEĐŦįŦĘč56‹ĀæqåŠ8ŽåŠĪ°Š-Rč”ļâžüžēĩ,ӊABu; Ÿo,ŦŲQļ§ę)ÓÜÎĮZę*,ĪēgÓCÎĸu\ÜÜį ëįdžüH›[Vïjęvæš}ō*ÍÖķų:ôĮŨ ͉))—žđ+%elĩ~(ōOŧwiųŒm…ĩ+ZÛ·ĻģĮ4ojžŠšnړNįŸF‚óŸ éÜnŋkĩÄ+ŨTu>Pßhr{KœŽÄX;| ;ūÏĖōÓŸOv–tøä\ÍņäŠ6udËucĮūæŒ]ÆĶdŽķčīVC†Ã‘•žÝõmĩš`Ũúį;óėücų/<4ã uXōĸĀ* Ėr֟,ŽBpž5,ÂlgÁ*YWŒ,čÁUf°‰ōVáD°ƒ€'ą|ōH˜õDę‰å*H%^9Āʝĸj$ģJúo‡·ÄŠ|@+mî—ĘïFčTÖäxr!Rý*W.ēUôþ\—IĨģŋFŒ:Ékß§ÂW“wšOÛãWåļ+%Ÿ·ĮåÍŅ/Ï*=pœ`õŠÃķ3v˜˜’é ģ&'ްø3 Š>ŦV/ßՔYPuĻāÁCÏäïģ.Ј;rîUķĄd°*Ķņ*ČĘbOG@—äjü0܊…UŦB ČŲîgÄQ,’DK°zË ÐɖQČN’ŠýŦD*™VĒ[qVp€•ī:DŨão†ēþž*<ÃUnO.Ž]ücÂŽŨ{$°Š—ŧ"›Ãtđ*Ƀ›|ļ?&ē:ôÄ'^ôHptāŽg[iGOđŽÆäÅÐfģõbgģåÅäåŲb”…=Δð€Zķ<’Ŧ‰á†ä0ōĸk3ēŧ>kƒ\­]“ķýPÁÎCŦó^wCš6üīą‘Ŧa9*“-%ÅŦb.+fQ+$Yņ|åŦðX VU†åē„h……EZëB ļę*‰UžķÂqĘ|eVûŦÂđ˜hÁtFr2€Ļ_҃V ũrãÚÄ.ÉĐnI"õ“ÉÕcÓk8ƒ•6^JÞŠ^īúŦ Æp…U5Ķũ +Įøúķ:ŪčÅú-ŲĖŠúœó/úRŪ=mŽæäꅁDœâ“ŅÕV‰_"‘Ū!‰3œƒSöŪŦąĖ*vôŠï4š2_ļbŦą%ēĀÎ$‚™[2Ŧ Ч\e@˜V!VŲīânîė`_ö*~Häęņ…žčý\äqÓÏBVÉÞûáÚë`oož*ģÚÛ{ ŧ&U`5,‰Ę VӈՂU‡š<ôųŌ—ķï>­ŽVæ u•å`Uņđ‰ģ þ(ĀÉŦ*ÁŠÐĀ3ŋr'ÁJŌ’3Y˜V(Lë Á\l­QŠ_90čēŠîSŪ’ËŠbÍj Î08ËT%ģô”$čn―‚mŋë5Š䄮ژUęõûũ_ŋŽ7ðļ·‘8=8é(혁ķŽeÕ8zṖļĒÅ Ölúđč韗WÍ,Ŋ]q:uBŪDP’`’Y%`§)‹PU0j-"Š‚UÜ+äĐ`UĒ!@ėšbGŨ€Uj€‰ÚíaĻ1`Vų5Ūý#ąúĢŊĘD9“bUĖs9ž õz–ī=KKþԟĨWþTeIę‹Õƒ`•“3'ÝđŽb4ëĩû§ūqŠloޓŽĮ°šœå6Ãý–!rNķ§ō*ũ―CÛļ;ÁéóŊRû“ ”LĪ‹ PbQŦX„#%e% Ðíی‘û@*ā E`0-n…A^FāG)>UNč[Ū2Ŧ*ž(p4ŦD?P―č|Ĩ1!ô‹"dŠX A}Š‹ƒqý_Š‹CĢïCŪæUEø­zō~°#―bkôý< YMBÓlZGFŲh9$ŲQ|ĨÓ0:aHšzLTY%I0YŒ Ï$úHÂĮÁ-éTX•„đOb‘ũ\Ļ øH]†“ÉØņ‘œ KgGMė+A.üāZ°LĢ‚‰œÄļäX+"$V VĄôKŪŠ8]áhVĄUM;(:,. 밈 Ēt.&ɰéĐĢŽ^„ļÔZÝŽiÜb%:Py‚Ž(Ä—QšF‡Šūl+ÛAčЈč^W|ŅÝސe՛·ėõņ“WĀ;€–dÆĨW™ÃģŒeDŦMŨ(~CZdP'S5 vF*ąBÁ °RJ°’q…^Ãe&%ŦJD°ąã‰äĨ"7ˆœõĮQŦģeĒ7"3ÖĢI)}Je~ƒŦ8ĨŒZ_)8Ŋĩ dß(7ēĶAÁâņÏūåŠČąÚ*đĘôËÆ^Čsï°ĐÏf–ž‰ßž·mëú}ĐVYöûMÓķ7Vú―ßã~“ÉÕ ›KōšāüwöTš<^Ÿ7Wåë‰ðzLq?æï9ËgōøNČ*d'ë)WÜŋß2!Vņĸyí_mŨėo;lË#++f ­ ud 1hQ8mL,Ņe âšĖęË2féĘRy^€.ŲnMžę,ą Ëâ(ģĒ2ÃnīgYĩN§6+ÉétX­Y†„Sa5‚cäpQ! {™ð|xQM€ŒÄ“öüx ”•|Á*{'•rCJd@Dqš Īi„(AāAÁŅXœĶÚđJÚŠ°ŠE 6…ÕøĄb@î8°ęÎqÜũęÍKZþÄdÖj ĐþŪ=Õø}éŒŲmÐĶf;>m‘ÎėôÚG&jÍVwŽŪYëÓxŠflÝ0ÜŨŅ“Ó—ÏŠYkJÉ4F lŦ˜Įę'įôjĮ/ķÞށf^…|VZäŪ­ĩL›åКc~‹Å(ų38šÃœvcŠŲĐ-KÐĄTՐšTF5­ČĻ ·čėÅF]*昍NŦ1üō”ūēpč CI°*ixŊwąˆZ‘XĨŋĄüNP˜UA7Ļß(ŠĸąĻē…›a€I2Ųąp‰UŨ€·*š_rUxÄ ēŠ#éXV­zûâĶņ˜å·ã‘aU‹ÞzÔīrëķï‡Ũ<7cífÓ]‹önŽíķŪ| tmcęĘΙõKŨ―^4ũąnŧÏÓ#ŧîŲâô@č›Õë—Ÿî;―r5čĄēŲ~+jC6Ōôkā`Á€ Ŧ(æŪ<ü‡ĪĶĶÚSk‚Ál6g•$Ą-€Õŧ―Ãh^@†Ö Aœė 3šuYš m(.6‡'Ÿ"Ŧ`5Ua•ČĢsŌbÁšiØI{l˜Á|4ĸEpd3ēüĶŅĒčÜĀ“ø‹P:*ERX,Sû'We1†›…r­#qþOVUÍ;ŋŊÖEËÓ.ŲÞđ`U鿚Ýk7ŨuŪ―xGSãöEõģŸx·ûū'Úï~sí„ŨJkoųŠéɂÚ_·šs+‹wmøÚïõđNČ*„'ËÕeŋMH9|§`5čøË Ãę/ßÏļk€W!ÛJkM0Z’­‰#Æd…ĮŒHÃóâFŽžZaހlƒŲ’žvezÍ ˆ+Ũ&ŌøãŽ!W§§gÅÕīŪI Įx‹“gUĒz€<m8U 5•“J”"Ģ­l%a+ƗHĀWšˆlW(―Üv ŽBŠ*-ˆ3Îm!“HxWû)WÁЊß‹y%}UaUúŦ:—GípđGķ˜žž―iýžēŪ—PÃŌ~ÞjÔ°|V–ņ ›žÁ5,âžyeOÝ ŪōĒtóŪ -%’Ęub?ąÚKÏþÃHíÆš?Ļāú_ãq]6ņg›m€Ąb•į8 ĢkžūļmLúãO_>ݘŋivÛã·<Ւ>-öÞįuŒQ7ĖŋxząuZėËģįŒČöošqÞÔŅg ÞtcEFÉŪ­ãnHēhĩ§ÆŠÄi(ī—Xކ|Ķr0É õ+ŪŸ3xp,ųü%M(Ŧ FŊV9Ÿ…{ @ŒēøŒĀÆŽBފAÁ''W%ōX…äj$ŨŊĪUÁķ:†Õæõö2ß―ņOßZ>jĘWŨÕ.Ú{ëĖ[/[úB›RÃēBýų[{^{{ēĩĻuÔŠįĮgwørTV°ęŪôzúŽ[Å„€Qe—•Ā’.Āĩ!vĐ:°LŦ Ŧ˜T ævRĸßšå…õOf/œõPSíƒ3óŨĐ·ŋ2ęŪ—2ęvP^?§dņŽįšÚ3—ÏŸYūvsöęWFķOĻyuĘĢsÆXíI'Ï*/ fŽÐCžY=B …°„M >Y;ÅóœĨŊbUyĻ"ĀČĸdöXåsŠ“ĶīõOŪ’ÃJĻGéŦÄ*W0ÍjžNcĸnŅš õ’Îŧ7ķW|ūõmđęíŊŋđëmó’{žZÝԘ]…–Õūû Õ”}ļ;]KIĨė‘KvmĻvŦ|MŽr>@`’!ЈS|pĄŦ \åyiuíóķßÖøZSãĶÎO;>zgΊüڛw`^@éū%­ÏOïzũgwo8ŧjïô—gþ1wÔfÏânņ­'·ŋųEŲâũƚŅÆęäYĀaBžb5B4 -•^éä€#2qÆOzbU%2ÉQĶZ@Ó*f•=ø`UÃņUķÞÁb(bÕW܊G[‹Þ@Gģɍ Ŧq4įŪŦAą:―üøęŌŌüŌĩsæÏ˜ąqëĢkšķĩ7ŽÎϟ1kECkþÞYïŒĮĪðĨūþŅ—VSÁ‹Û>1{ákuuŠ(č$―’ŽÜ%•Ë<ÉK@Įėņg5DŲZŧpĩę!ėkd9Ŧ'ĘnÐę·Ž6ŦÛŅe‰‘ÕŌĖ‹ģAčû Ģ5|č°1ŒĒ†hØÐļg#ōS…ÁÏY8þ0TuÓaˆŊÞ4š!%Ðd°?Ļá‚QcFá|“ŽŠk–ŅÆz’Œ8ķáČۈIÅÚĀET€pä-"Ž.+†ĄČĒėhšėČ-,éēsûˆęÔû&ĖgðYMh·‹ĮZÍî:T=ōuáŠNœ4ÚRîØįī]íôą7ˆĐ­vĩ[ïÚggŧåđCŒøą7Ö%ũÜÍÄ*Âß`ÕS‹8ÐŅ]Q*†8ãiØ(č· nðÛëōBVĩĪUœCBäąō`ũÔ, _aŅÅÁ&ïĒ){ôˆēĪd&K3IˆëGžzīR'‹f}‘z―„’äÏûŨøwxeBÓhÆ2Sy`ÅgĩĪĒĐAІ~FPHåēĐ(•TÏ đž6{û2ĨQ•„p S…l2ŸPGHĻ$‚Č ČfĒ)Ä\säßb•Û§ų ÐiJ’Ö5áĘ΅ÓÎ a’Ģ9îeƒ=Sæs|ŠÅ/9S‘LHšacZUņ.SÁū*áé˜23MI―ëâ‰wÞ­ Ŧ9fVęŽFĢB"֜ÍĒ|:(Ė…3™pīPĀšTį†YĘfƒņ ލ B}ےųRPĻĪ‚Xû—ēđx!“@ îûûŽnUÓūđÚčZ^iÚČŒđþŌ wųqŪZVÁ`_Íō8ŽÛep;Þ€xôYýSbimE6(ęģŠsÞÝ.[°J|š„úČâeI—ðäCoCþâ7 úƒžAAáwŽJŠ­Kû_íí ˜rðÕGMQ5‰‹"Z2{úÆõ+˜héJë#ÏwĖyfÍ0QčÅŅ,æ‰j™ĒH“’åð‰ÎóæŲŸ11þŪÁļČĶ"IĶ=ý™g]sՊ^Û )˜PĐëU ÍfĐ(`*ZjŽlͰ[ 9X)%ŲT!,äRŅpĶ” ‚ĐJ6Y &‘[ĻĢssŅJ śĄ‰ĢÁĘæĮ­ķ&øo5ˆõŽNýœú @%+œõ*Ė—V`ÔgÕýw[‹§uđŲĘŲæ ‘ °Āã/ĪÆŠėąJÎU?y…ĖUŸÕ*0$V…?cé++ÚŋŦLb\$Í4‹ûx“å‚ōÆUwc•üņĘÎoŸ8ēûžó•Ĩ;v›žę€ÎëoÉ"°šŊ=bM™ĨŊ8ņ•ÅÕũÞžžÜýÐklUíZķhĮö+áQŋð –=õÓ;—ïÜŪjS' cöœë`3Ož‡ęqe6ÐâÛŦqAČd’Đx<šŠf2“ïüðüKîëÉðÜ|!•ƒdõT)/”„đų`6‘+%ۄHfX› TáđŲX6Ÿü-VáR"V]ÕŌāŧ@˜§WIÖjŅŦûCOũy!ŲPÝUЇf}ï] ÐðĀƊ[Ŧƒy3‚~ˆËj3ČŊo ôŨVMđöŠ}§{ðįúbčkŅū3þ―\„xAQáXUũŋšÚh\vx •&|Vr­"ģ.|uŲ,E,§Ų›K>hí·äƒ7î=bÖЏžxį―ë:æąxŋq§\ôÔŨ#™ĻtŊ―yÖ+ïķßþÂmO―ûėįŊ,^ŲųČU ĸãļ Ŋ·ūcÁão―|^ũēû—Lšn1kí9ŧ#m6n“d]Hwœ åŠÏj8Č$’ÉŒØÖVČķ%”ékŨÜuîĘŊ—@ uÞŌËÉBĐĪ[™Gs)QTKY3ÕæBđjŒ€PBJv$kWØlVąīâą|ļO 1ũ§;ŠHyÖðŪnÃÝu―JÓ ü˜~î•ä< 6kŒz{ čJ‘Æ+’_gxô—UãĒÚĀŲtMnâ O^օÔ'•þŅøœþá þž!g5°iVÚ{ïŦ7(‡_}XUeOŊšķÔ3­ãû%#ÕŠÄ~šĻƒÍé9”ýøâáŌ9—ŊDmâ>zũĀ–k֗[^XÎ4öæ“#ŲûÜðčŅėĢ—FīŽū›―ĸúČ›ðКŽ–žõíŊĄJÔ#ëf?ĩĻĖÞZöÁO.gÅĒÂXŨđ˜˜úĘ/Xņõj  bK)eęz$b˜ ÕŪq+gŒû.’-ÅÝēôBTMëšZ°ŠÂrķ^JdãšS,H&.fĀq°’ËFÛËjSUÎô_øyÞošŌDaÔ:ŽžĮ âRSî ­WčRnķōÏĢô@^ˆ§ÕÍ`äũķ\ÁîB7vËWïĸŠ^Dæę&YÝkčÞS†ŌØēâēŠëÝįūžôĐãîfF™ýtR{㑕ėĮ%_'6ĩ‰ß~āģ‘ÝKŋd-ȜŅÕŨ>ëĀ=ÅŪgŽŧũĨƒ:{.UV߈$…—†_€Í~\7é)Ä0Ÿ^ÚūņV|oãßO{– :Â—ÓæŦŽë•_6ĀR_[Ĩ’+\ę:{dËÂ5åNš4ž―ëÜ/fŒ[‘Ζ•9įwĘz•܃ųĖ–ú *ÚŅø3{õēoVîû -°āˆHŪ^UZz_)g ĄÛbß/>ˆu­VG°™koÛãĩõĖyg^ũÆlöú\ûãē%;ũ|ķóuK&}ĸŌþ­=ÓFūqëš[tÃ9ã—N>ý”ũWÍZøäōéON`›óÔĮ+%M,ķ>rĸLJÏg Æ]ÉX|Vs1°jt>2ëŪŨŸ\9ãģG7N˜9ŽôŠži9į…lÎ5ÓÖ.ęPŧ.]0þÖyZyáŧåÖ§ŸŸ―‰WįMÛĄįËΞo™…­ŅÍgĸĐ―ž[ÕëXÏøÛ Ųž"…xÎXš 3t…įUýMĀÕÓËô6%QÏZåg@ĩŋŽî2\Ī@€ïð^‘LĀuíŋĄU)”€ -…­ }XÕd[/DE‰ŅU“XÝ0ī(zöŠÔ}íWLe37žáˆlÎåËŲԅíė5SĪô§kO>ŊÚēÏrCÚ8I1•–'NáĐOŨŪšî§ßR]pÍøUË˝WÜzöC?ÐųÐÉã_íč~lYũ3ëŊT ąxÁuĮ aü –ÕÛŌŽþÚ {Ļą9%ýômŨÎÚgŅĩowožt&· ™–_3{úuŦ–ÝRVX圉#TfēĮĀęŒ5—œũ % >;ã_û…eS0acÔã n6‡Õ­ŠjŽzV('ÐŊdĩ;™Ŧ|ÆuûM˜ŊāJŸŅz(Áe5äđk‰U Jj•§ēÁþģšíî`æj―JæoČË xnQA"ÁƒŊ}X•åŠÖ2ôāËēĒúkXd%‹Ķ§WôVÍĶ!WķJZq%ŧzҊø9;:cÚâė!78*NÕAĢ5ipJŽ˜ķzėNómĩõđƜ™`đmÎtŌģ‡b?8ëū§–Ž`GîrÂ0iˆ9Α Yn+ķ\ŒïáŪå9k‘īĸˆU Æ{VĘ]§žÐ~ęļ“ę†^uŨVéóū`oœÛk_Đ>ýeŨ)oģĐK;ÞĄĢóúuĮö|ĖÔë/\1sí1‹ËņVę2CÉFu`ī*VE-ŲpLŲąÍHÚĖV|Vabō–ŸŲR€ÂŽ…*ŊB>œr•€­æ!–H͍ĪąTīĖ mÁxRŨįĶō™pžąX\@ĄDâ,đ\8ßoVĐĀgĩŪ5é ―ŸōZÕĩZ֐į'ĮÝŨ2­ÉøuVéÕ­ā–ŊØj•WeÝoÚéÄÆÞ;Üu=·†°Ŧ·ļfÝ4ŦP†Ž”:B/ÃDÉŠŲŦÃ6e@hD4]4eÉá›kFIQôðÎĀ9Į=â"]ŠŸÛ’Î$Gæ·ŅÃÓÁbLÆđųGâĒŸÕ%ôÄR%°*Ä0ŽĮƒÁzΐ?…Ŧ"ÏOˆĢĮeī9̓mąR*%bđ\<L•2­3ÛÓ(d%ĐdsÛ_…`nŪĻ’‰TÛķ*MGÂYęɌgīŸŽnåąĘ]UÜŧZ_"5ðž8!M[ïjåedŧŽúŒú=‡p1 ɟD― V\U6õ7žę; ŦĻW›=Vƒ[œÕ ýüÅUßļ•Ķb_„âhþ6Ėī@gĪ,ûoŊ6yŽnÛWŊÂ^ ĄÎ%‡jË ijîĩڄ― V{ï @ŒÕŠÅĻyÞøÓoI2K/‡ýŊĪΊ€Ā‚ bŠ%hë8č)[Å!œ™ÂŌ4cŠFÞb­OLRh(ŅíĐ^EĪž}§Æ ÆÔ*Rr‹į3ķœ‡ûÃ*UðũīĢĮŠÛ/OD_y'öÝ·vĢĸ>Ŧ„Ī oóŦŊO)ąÚEŨ-Âæ–Z!æ 'đÃjsYý•―3nēNãxxSJéáˆī$ 9öh6W1 4Ũ0l™Ņ$ËΖÝ,iē[īØZĄārĩmA[ZŽv[9VnŠ‚a…‘KOŽ‘uGeÐ]]Ũ]gũý>ŋũ—ĪØaGėŒÃÓ6ĮÛī8ӏOžßs|ŸĄIý*þAY‚ÕäŲÕėš?‡[™ōŽzĀęO~ÏDØą ]ĩ ‘ũZ įælz`ÃŌídĐÐßĸ―2Î*dĐIŦÚ]―đtm­yÉÐúŌŨ[CKZęKŅkģepÍÂÖēU%§<Õ5c„-“§5<yøŪÎkjΜÜu{K; ŧŽbFMčÂŦMO(žØbōûS`5įgôŨO(ŪŦqŅ ŌŒíī T㎊Š nÎj·}Xüžîļˆ%“ZaĪĶČ*Ÿķǁĸ;îJŊfeũ‘"―Ę+ĄŨQ-åúßļUã+þĐeÏĩŨâWtŠrņwũ`Õčķ`.Ēk˜ (žûïč]‰ũŊڅsŦZ….īHYŽČ‹ ß+‹ũĻŅÁŠũî­zĒýĀ3ģ'X5ãøcomZ|ĶĢröą?žšmÕüĮĸéÍĮöÎŧcóÅÐéu‹ÏœŲķŊäëÐÞĨ‹Û;|îõ{›>™·ŠęýF°ŠūŦåŧ˜Ėš1Ŧ~ӗŒ7Y‰[óâm)iž!0 Øv_Ät“.i‚U LŒē‘&îi{XŲbKŌđ„7 ĪSn‰ÕüAIý*éodgæŅĶÁ–ÔōøMâ)ÝŌįu ĸ*>súr'ÛĢnĨ Ŧ`…ķuôïOucĩX%œkŋûW+ö·r―]þýd•ŽBĻæGžæœ]ē{ökĢÍģKĶm~óRčØÚ‡fŋYëÜ|f·bökŧŦį,}p;dVOŋxŊmwã+ĸM ÕŊ­={ú‹ÐÁýc7|XũÉ?_9Ý|ĄĀIålõØoņŨįúĐ<`âTâ"aņh•Ë;þbiÎh‚ŲôŦXåĒ–<@ö?'/íą‚ôAļ^ëÜό=Ō9īcČ]}“øÕŒ>đųY,XūĶĮĪjÄØãqéiÏô郗ŋ?~<[!ˆûŒqÉ ŋ7+/Ų€d쁖YÁįüÃĸú;b•'0˜|öđ‰ĸðá%°ęÖX…ï•qVĨzmPmr„Ķ·—Lœļ{öB ?Ė™<óŸB iĸΟ Ą—īLJqļ°ü°Z―ᧁŲ—þã %?,˜~ô‹ÆÓ()™xĄë“Ž―óðÁ‹N—ĖĪN!^}†9+ō—„“ĐŨŠŽ’˜ef"\š1Vc/øHĪŠÜxžÓī$åQâšhåŸÝ­Į°5—đՁƒEVÓūáWÁRŸ$qŒ!axį.VäðÅ‚\qãQŸüūÄjþUA°`uø„‘ĩĩ˜ VCâïÃļôđöÉCŊÞX XõßWVeþ`ÄfûāĮCkĘ[ gŦ›/L ,ß?cöį‚ó―ÎKÂō9ÛC'ļD~õ•ŋfoûîËĸų`ÎëÏŪūPŧüčāyō īžŧðŸÂ’OF,<îöJ аúø[7XjâÖ*>kĸ•NŲÎ*— *ãƒŲļĖŦđ f‚U6XČiDĀ)í•õëá_Å5pŦCéáWŲėVzfócŨ1ԉÐņdDÉÞā4cßĐAMH㖝č01Ø=F;ŌęIAUQnT‘ÃrŽ2é7ãUäW‚^ë‰ûžę–p/o›*„jþ†ŪyÔ)|Ŋ,Æ*4‚šÕ–đG:–Ô”ï>7ącRû…e›ß:ī§óĀc+Ðŋ:―óã=.,ûōĩŊl\ŋ VmÛVK.6ėŧPÛpôbö—í;^õi5ōeŸĸ·ĐG+ijúŦ\v‚ PqÕtb5í_á*+·į [‰UÞņ’–ØiWYEĮœßsŅ/ĐõHÕ Vģ{øU ˆįõaĘĀŨ3‰Tï4ļULaĘv5r$’äŠÐ=…îŠĐšœU2đ ˜œUäŽÄđ€Ņŋ@ČĘfXėâ‘ß"G cØÞ#ŸĒÃäûšģRû E!o\ŅþčâÅĮ//ÝVUðÍo<}d^KāpG RöB{Ձŧk>^Ø:hÅĻē•ŋ(šþxmcý§ũŠN9QP]ÓÖŌļēĒęĀčÆ>3 õwx°E(•üj?ö– Þâ›DVy’”žbnúðx•ā$ŧĨS1ßác5ŊB‹u.ÉWĀ8Š \e@ģŧSÖķž{į Ī~5ŧ’XU]—UEÓâ#N-V•ÓS[ßZ WûîĮ-äË@0jųÉY%Ŧą90I-€Íüãũ|.ĀėŒ9dĄé•ŽxžÕ#Aw‰Bø^Yül…CŧÉ$q-šįūēĀĘĩÏž:ÁŠyGúęc7Ýíuę·žú˜SóóVKð>e†MþÃBrœĖïįq―zÏ8“;rß=Jũøþy…FõŊ2Üs7Ž―Wár™t政­ČK%šŦD/ÓĻ f€<ęeåŽēîū°•·š›ėðvbžˆ&V*sŦ|•G•nšôˆXÛ [8xĮÁœÕŦýjŸŒÜ>Īu] Æ/K–VYï“Ņl―[Øwĸ6ŠĒY•Et“ĮĖŊ*‰UX’Ŧ‚Íāö—‘†@Ė?Ģ‹Åc$ĩ{4ĪQ}?YUkIËÂdō˜-šĒĒž˜jTŲ_øýŒzĩk]Z§ĮŪŨȋĩ>·Ü_ÖDüŅĻŨkÕz*·SãŌĢ{LbGŦšÚ[äÔ?ødXŊ”d)ą KKļÃîûĀ(CŽSņ2ôųz~Nu"s…/Þ'ˆoģ°ˆæåįp+ōŸY"§Ũģþ<^…[ˆŲ=ü* k óoĖęą—Ė<{Ŧ:v!Ôs7j~šúî…õ{V(Оl―–_UĐĀ*+ ÖŽUw3fäOƌsĐPeąóxgĸ€ŲŠRŦ_îķSũšūĩŠ€‚ūtßÍ ŋęÐŲÐ C_ŸL)ŧÏ] ĩržÞĪ Ę ē Âl•JŸūĖa’â;č`ąųĨzvąi}™4"Ãīĩ-:ĐMį3ķô3hĪZTfSŌēČĶIVĒ‹XåĄg5ÍŊôÏ Š)3Q/ Žâ{%ŸtIįÁCBŨZ” iqKp6āŧ–_MÆ*ÂÕžüÜĄC8ŦW[V_°š~Ģŋ—å܉]‚S>Ĩ‹GtŽųSųŸŨĩ—N™ßŅXÚöDŃÓĻPŲUŨĀLÄýŠėŽŠ<·™Í FތxCük5ĢĮ―VFųYI@Ílĸķ`…ŸVĐЛ…īcõž–…ÎŦDDįpéÛ?âvýŅJ·Ô$‘ÚÍÍPÐøƒ>čYœŽJ­ŪŌ“ú|•Í~=čTÛĪ&Ýxš[‚~_ĨÁįÕøõz‡Î”JžšGž\°X·e°øN‹ėŦ&ýdĒē VđCNôð=m4ŋGފųR5™_MB.wŦHXÝ18Á*ŸĀ'ąJ1ėú1@ųšųmĢ>˜x>0ûĖöķÎĩm7?ŧóݒBSÅy Ÿ\ëøÃY―ÆŲĘęôϊÁ‹%āFu }ĸNĢIaŽ%",f•Üüm•ZĪ—ĐBčĒĒNXU/öŊbgĨMŠŨ Ē2Gt‹Oc––9|:§Þouë$Q§Û­Ũ:‚Í6ĨL-3d‰WæWGÍ&Nexč zeđôIĪ6D°G! eVđÜ?g•úĐIӔí ĘĮL.pVYŌø+y™ č~s·E:BÝlŠV™Œ5JĶäWEXsĀꝃâŽvkēĶeJŽŪ=īgRíWŨ•–—ė8ŧiŒð§Ž]Ŋ^-ĖÝw(lF+ßõŽęœÕņŠÂcõ؝ˆuŅIåGĩ3* N8hRÄÓhãČxö­\ĐÜĻ€ąœüjïąŠöIÔJYĪúŲ<ōČāû‹ËöĖÚųŒÅ/ģY·Žx %,·”―0ëÉB‹ÍäÝ2ĐĨHŦ yM/X›Į› néĩĩÍR(ZŠ^Vkð"Ļ@·ķîÆŽÂéug•Ä„”Čj&ðcį{/āå„slī5Î*ŸeŊ§uTLūĒ?—Z#VSōŦtÖ"·š— ·:čjŋĘYM“ĨĀŠåØ BóŦu‡–<ēģāƒy#…?­―"l9þîįĢp\Ŧađ9V“ÍĘ5ˆČĻ[Ղ°—ģ .A‘"îáånÅ·`ð…Tƒq'{ÏŊjeZ­ūh҈‰%åÏĸ3īz]EÉÆkexËūĨU%į…ÆƒŊU•2E*usœĮ{KÐã âī8üŽŅ,Qā‚ūŌ ŒnBZėjSëd:5ĩtĶĀjg•cų~ Ïóģu9ā6VË$YĢ5^šh\‰KXņ}Ä*Ÿ]E‹5ßŧ.žðSöŦÄęĀAœUîWŧÍŊĪÆjĮ%ģ3Ü8Þ+§ÜûÁüS›JįÝÕþúŧ>cŽZœP5ŋyVLïiŠ0Ā­ÐmösV*nbŽģšÂ·6ð‚ ÄÂ`UՋŽ*%ŸÖÕ`ŋŲåĢš*ÎGV,môšúŠáÕ5o†—ÏyŋõKP3ũĀЇY&žzŋĮŋālŧ™6.°čÅGģ†ž8é~“3R’ ÐJ1ŪEĪĶÎ*'ŊÛūâ ájŽRqVÓ)˜›Sŋą/ [Ū ßbŽ‚tķÐފ‰Đļ_―ū[eŽĒ/åÎ!ƒ‡ āŽv·Ęf37bĻ,__k–k…ŪŠ’ŠÉ&ó{gķ /T”<ØōîĶaËK;íØ”nšUüj‘é'Aï ŲŊ:ûbŽĘgæa-æoÏÂk[Ā―˜ŠŽ―ČŠZÁ>ŋ_!h­{Ī@h8Ō"øËj6A2ķü‹cGū:w„}Ūđ#ÚŠĘīūwĪ54{ë]åŋœW;wCIÉĶVč`)žÉ!í>š’ Ŧ™ī~’=áïčžŦÏņ˜U­2āqÉļ„%g5ŪÁÎk<éÓd§9kæVÅÝë0ÆjV*~•PŦųC”ÜŊfHS`ÕŪ·a8{˜ĮũO“Áū•‚â‡Yã<™S!WJŽV·Å~―ŋļ4yžJ*ĄKĐī‘õũOŅū{<^õxäB܂Aó‡L0ÞôÄJō)#Eū?ĖC›ēÖ ôâĖ5FúmČLéаÃ̆€ÅūĩĮŽę―&Ąá蕕ûÃ8 ė˜-jšß6ãĢųĸnšóuõÁŽ?ÖžĩŽlïãÓ;ß?ûÜûuÃfTjXFõĸb5ķ8ÞŽÂæOûįįãRŒT€ÉV[rV ðũüxЊģ 7ÍÜj\ū‚ĒՔýjXfn> %óŦiJ‰2Ŋ/ąq―Ö}AÅÂÎäFvŨdVqÅjąxŒÉ“DšW$rÖĘÝCÏJóûnsËâzVFaîš (,fĢeųäÖđŦ6ÝKėÅôŊ:Fzh4ęŊbÉ,œéŲôߖ…ā (æŠÕÅ kóĶąāšđ°}Ä aîKŧ„â^ÓĒDōĢžÐËïėR8<ÕŦŦķ#°:U˜ VŦë§F"sũŸ5o…VoœûčEý›BWįšmĘĸ]wtí❅ö›ßÃBk|1^E䉉U^H#V3Á& ŒĄšÆŨēâ–ŦaRÎ5Î*î cų*oH1^åŽÞ9ŽHæWÓ1f•“Ŧni~?j·­ŨŲð‹Ú °Ä;ŧΕÏ[\ņÚvĢÛ-TwžŨ—`DĀ(1UAĨGc™ŨkTļ N‡\ã)–fx° @­T ÂōķÁh–e˜Q›ÕdļÍ~KąDi#Đ!đLåŽÚU‰žČ|ļĪĢþ(öõþ‡ č5Vej!ōW<ýĖhÔē šrEA{ĪfÓ.Š.‹1€Ö i:rĘĻxï-ÏėΧ7 ÔŋėuÛoÛ.4―ôhÕzĨ†záĩõMēJx‘wOņ ēû&v„Ūņ€Āėg5ą#(îų^ ž„&W€`ĶX`42Ÿšš_eY€!°~5›Ú0ūŌwh~†üZFþ >lšõš–hZÁ\@ëîŋc†EāÜŧ…ËÛZ…:ĖĻėÐēÜÝ4į—Ũ|īgÄÅĐË;—žō(†mxôÉåčoU<ÂōöōCSMŦJŨķVwþē­ÅŒ–ÐõĄnoÉÖ=-áššŌ… uwíēsf­PöŌÎĻÛüėŽĐcÆ ģ_›*|į–˜cՂUUÝéwv…œe5oz,ĮÝðĀŪsgFÕ―üføė۟6ŨžņP‘ÉŠāxӜĸ]GŸĮvý/[W/\6wïĩuËä$―†/uĘŽbfŊŊø~Ÿ˜ ‚ VQ ˆûUÎ*^Ý­3›k°§óâš)°J-Ö9b+*>nĘŊ"đŠp•HMęWiÖJ*ë?tč€[eƒ ―ch?ĐDčūŦ˜béý;í 0sV‹1°}ŅLš Pa_ĀuOEũ―6oƋíSž(?düētÛŠ’…ÃÞþũ.ģSqųČžšŌũÕĖvôÓ—ŸïXöQÅ֕ĢžïŲšúđCÞ}m[OĻm*m[?`çB4ØĢ–ņ?ŠWX]ë/zU#fĄh5b\Ôų|iiÕCģKŊTŋ\Rē9ŦšōŌu§LnŸŧkDÛĢ%mW„ÐÁ·†…ĶįÖ>4ýdiéƒcŧŽ–Î_8ÚĩĄB`#ÕÁ›`5[”ŽˆÏ‘ŦeŌđāģŧ_+ŦŒMŠ0]kū.‡ŒUÚ˜IûĀ*āÓŦYĐåWû3ĖsïDV‡\íWy€$ûdcÍå-°œĖZõš!§L{ 9Ŧ#G>õSãOqÄB  ŠÅŦÆsoŊCóûÁ]ëY­æ™û ĖPxlŽŲļ ŲÝK_nžÔUqQøęocEc'4؟1nÉīeĸúóŪģûïė{ãĄýpŌÉžwžxöĖ(ĄëČųĶĨŸĄĄĄ-|l!ÖaøBhóRhģ7―ýuïēŠŊũ?c :š— yņlđĢÐ\ũâĪ–°ÆÚ|x،B•Ũ)›ũâÎãfĸĒ ŨZ$î†Esũė\cõüvÏîuht4Ø$R`M•ÕŽūÝYÍæÓŌėZUPÆęæWcĮĸ˜v:KˆO‘ЂÆSŒ‹VÅlÝĪėW*%W0VïčáWģēÓÁjB[ę-193 r3âČUrVąėîÚ{ųū€ŦVüjnÃęwj'XÚÜķĖ|r―PWshŠðUÛČŊ.îęzbļð՛w ÖÆ#įéÔUķrþŌįþÜzķ­%ī.Šäõ™ŧáåY‡?Ŋ7œj8Ð"gۇï›Vđ=æú#Ÿy Fܛŧ-°”a&öVʃŌJŋ@edMĨ4^­•ēk6æ\Xņ°rËÁĨÛĢ›CüRēÞŌ0n,·08 ÉĒ—iSf5—bąÓ?ą=/Ūˆ uz]ÜŊ&V[fð|,ņ ã[„Dæ~”%+žķ_í-…Ŧ,đŠĢÕ=úŽĀŠ’Ü*>Ō­0öūÓu―Æ~+䩆 1ÄÚ}_üëå)­40V° ĸÚī ŽÖš?YđĢĖŊ^ÜõÁ6buŒ` Ü8Uh˜ķ§}G!ųÕĨ- mĮ›Ÿ=ÞpzGļkΉ$Øŧ*°a`4°~šmÞv#N]–sŸyOŊî  4)ĨČ\RĻĄļŠ?†Áåˆę|2ĐŦL/3™\Īӎ5W譂Xû‚Ã; m>ŋĢ ú•ī’Aß*čCÖKrUĨLoÐJSf5Ž2éÎĻ&ۈájĢ~Æ ä5*s%6gˆþ™Å”Ü­fqSôŦ –“ÃęŦ"Ŧ<HÆ­•ĪãĢĪ)·VĀÉÞø•xHÄ^ãlõÔSĢÛPÄį­ĖĖķũĖÅĐŦðåŸĮV^Ļ <6žŋuæÄž/;8Ŧ#…ĻįrIĮáōŨĸÛūuįÛîjšÓŅ:{þŽ;Ï?SģtÖęįNTž>ōøū7Ū4Ąy!,\þÃÆVģÛ!4<ũÖú†=ĶøĻü‹ÞÍHŠ6(Õh!ūâ3DÐ t‚ŌhØ_Đũŧ 6=]TÚ (ü{œfŧÆįW—é ĩrEīzčú‚AVĢŽj‚ð:š”Y%ÁH6ŨüĄ{&œŽMė}‰Õ„_eMÔņDAzb_@bąĘŠžá‡ÛâUî)ŌÍ„BĀÄ=æXyļ #§wŦLÂŋpÛĢķ„îFÕęĐŋ2T1’c)ÝĶ UUëÃfÕŒhSqøņ‚ĀĖFOŅ Ĩ'háCkÝĪáƒĩfĀ.wVှĒbmÍä‚Ðæ…Û#—;KOī [fÍk]ûæ/l1v­‹ŒðŲ9ï{Ļgë؊ŠŠŌĩ^ęŜ•^æshÁŠßÐŽƒ~•Ėgpšā8#2tĪÚ€ĪZÜFĨ>m2ýA›Á !!ŽhÑX§Ķ5.:_Poðk*mD―Z’r žāEÉQĀSēĘÉÏĨ Š„_åŧ ãZļDōqVŲ$ņ„ēSžŒĄzcŋš#vfŠõÕA°~5~īĒhōÖãó::QEĻðŋã‹ŪŸúËSžÆ*·ĖtÂBĄĄ8ĒyŊ){ŧ]0Ē6ŠÄ)îÜFÁM=u ŋ@uhđšĄ\‰zŽ…ē™›ĶÕŋvË+Ö  ŋÓ˧Ŧ.)P>0Sށß>―ýë^Ô ”Ęä:™D+39ž&}PíõęLŽ ÏPĶWƒJŊÆë’*―ØįŌkËÔ&ĐÉdÛ2h‚Á­ô˔PĩÄũlZh †;øŧĖ€íŪĐēšÏX…%’Ĩ”ƒ"dŅ%50“‰ē_åW1{!_„EŽōįâü1MūÐĸݧģRðŦž@ +jąŌÕīØG6­Č”äón―%ß`)ļc#éóR%FdcŽ:åĻM™ŽFųĐnZBew“ ›ÝCÕ2+éRcŠ b.ÆU‡I.đßZŽðđíF…[އÅÅĄÃSž˜rŠĀėķ8n­ ]ēĄå#žô *`DĐËvÍŋd”;{Ŋn%SŦu‡Í Nl―vxĖī›ÅVĪ·É4Î`f"A‡]ŪÔËu:Gą 4MĮ„›āũbų…āöÛĒvs@j0 ‡7Œ5Ë jļáÔYÍ"oÅĮú(uÕš@Ķ^ũŦ|N:gŦĀ9>… · FóōŲ>ëŽĐųUb•EŦĻŊÔä~•ÂUrŦ’ïÖä=Œn@Hīsp °îv۝nĒēØęģÔh"n9ęЀÔ-œÐSŨyüX€Õnhbk0\kw9Á.6_ŧõv4ý-ļÆ.ļĢ,ÐĘ-rwQó8#þ7Ó ―ÖNĢéā^cëÖÕ:“ÄYöę}―4#g‚C-‹ļïSVF5ŋ1™•ũ˜]%û™?âęcģ)·LpiÝÓ<™5ÁŊ‰šķÜShÅžËo'Ø#™ã>:y% ũQŸUĘŽBfxĨĨuŸė{WA\?ōÝâU.ÍʕWøaŪšFN—ęĩ”[ÍÍωëW‰cņúu+žŒđÕĄCČ­&õŦ}iSČ*W·Ö’ëŊŠ Øĸ˜‰EģĩSåwŧyŊĩžEЉ/Ŧ‚ŨÝrŒ`‘Ā?3€PR)ÐDŅĄmĩĘ-QIąĨHĢrÚAp‘ŧM˜TpRln+dÚ5„fī}6nLÝR‹5·Ęåö^Ô`wĀŊšīš•ó˜WÏ\]ąvtTã—vÜ<ũ“]uJæm.™Uhn˜tĸô•'ũ‡íō†…›*JG ÕõóKOĩ†>š2âЄúŌ…/ždÆūk]Ęy:Ņ\―Ós-ßi‘››Í–X%üjzwVy =åŧ1A§9íž~l€ģ·øU6gV`Ž€üjŋŠŦ@œöŦ4`Ĩō—@ųF|b,gåö[,3&€ąHn‡—õãÅ*đE}xP9&9õ+ŧåļķÉåʍĖ~aã nŲTL4JŦää|‹Uv―—åÐĩ–ËøMÔdAņ[ĒÏJĶ6ø,Õß8Tsæ|ŨŅķŧÚ/Ü+øė‡ŦF…ŽýíûÚîZÕ6íð™VóōmÛ7—lÝé‰ę§—nüÁę·va/âĖöĄšįŸVžČŅu—Ėj― °ĶĖ*âJ*[ōũ–ðŸŲ4 î]%ZÉxïŠ(&@Ocŧ-Ļzg•ĪZ˜|P|1 EĢûz‰oR@LŪŠôŅ#čËYí%ŋĘũĀ߁Y(bČAœÝČYÅ?.’ĘŋĘ ė°õ9.-Å Ęėô|Ųr |ĢÓ­)ŽĘpļV;<ŊÅbtãĄĮėÆÚ<ˆFýEøqĀŽ_‰ýYf§ã†4i`„ū;‚`C/j°k genB)#Psa҈Ą7°EðjUœ˜ûĘÅģåW„ĶÎõ/œi ,ßôdýë­ÂxY`úþ'…Ūįū-đĸŲW.6Ũ|.TŸFSÖæĨ_˜m^—ã&XÍAž*6ŪpąŸtąųŸŽV9"œ}âŽē*1Ë[\ˆUŪĀ"ôĨæ,DŦh‰Éå7ĢQēþW{V~ũ@üo’ŦŒÔDžĘå°PĀãÕ^aįzft$‡)pģj$AA†+9ĨWģ;#ūĢâōĸÜTl>隘ƒĒŨãËJ_xĀ^‹[v™Š\ôØH/)îmWΊ41uƒąiĸ(!PĸƒmĢÍÔkís4oÞ:lþ•såŧ„š—'ï_=ŧu{ý‰B‡OĒģUŨÛ_7,))ŋØøŌ„š“‡ÂÐēžbņ9°C›:ŦýˆāFäuŦAe‹"Á@0æWņá(WÆ=å xƒv|E0ĨVásĻŋ* Ŧ‰č5Éeö€XĨÎÕ!ˆÕÁWģĘ)cUÖgŦï™BÅĸĢg…)T{Ý,‹]ýįđS† ÄŠÖizījãÔģoĸB˜ŋZ~%pláŒúŨ ė~/ÎVĢЅ ‚]Ŋ€Õυû>ÞúSÉ%‹I*Šo"`ŽfÄŠũåėĪd•›EƒųB}.b)2ÚMD€ßŦ ‰)įRĖŠŦÉŽāG‰Íœ$ČfæP u5‰_eG+†*/)%·ÛŽ ·ŒUŊÃï’ÚCïŲīúĖðŪ)ÃÄjģKcþŨvxW/…„ðØŪÓÎÄX@ý‰‚ĒB[ŒÕúųģž.!ŋŠ›ģðé9Ĩ—ŠžjŊ-å<@& WĒ_åäĨąJoē‚ 5sīâMwVE• ūz=Æ*wŦđÜ­Âz°Ú3z…uŧšh[!ZŊÅŠ’W­nûÕïÐ~5č’øœÍ—7Ė›ÞōČ―ßNZc‘I­e5kŅuģeåĢ9 훆ÍXÓ0ĢÐā“ęí\ã\°rlŲĘģ&ĩļ°•-_ĩõ{Z‹l šj•û@žŧ3V­Ļ|WÕ^I€ 0VŲÆwķwSĩĀÏÄÝ*åŦŪņšČrËá'ŦAČŠÉXMSē-ŽŽsåÚņęmV…[Å*:þŅķ"ģÉíƒ=âÖę%Q―FâS/ϟâ™"›Õ"uØÕNĢŨ„ņj,`1ųõj‡Óíō…ąÖ‹Œē?ŠņĘŽVmØR› .™!õüjg•ŒŊcá}֙éČQņdg•QKlō#UB‹=…ZōĶ@• Ļówú~)°·œÔWb €%’°ĘÂU%­ `œÞfõŧģDO ›aAåJ#wČôčęS˃XXU·bÖ·ËŦw8õRK–ëý›VëõiÕ‰UY·MBÛ:e6Í'584I™I[Ķ5Ĩœ_ÅöÅXåJëœU@ĮæWŌcŽFĘ ÄY…ņ˜žjECVYĖ­fqíŠĐ)Kpó„Õ dŽ­qVeŌÛŽ~·–ØoåpH]čę“a3 WĶÖáMÎŨÜėúÉ•J―>tJ―^l ôŅ―Á+ņãŊĨ—ú}zŊN1hË|/XL:WŅ„)åœUŽČ*(K4YÁŊēý+i,E•`UŒkŧuU‘wY…[Ífę~pŦ,•CĻĶk"@ÏËÐdŽâ‹ũ-ÄY•JoĮŦߥ%ī‚ĐÏJ"MFÉrī^ĩGA6Äĩ•6—[ðËĪ&ĐS(rā}Þfsđ4.“UÖėōEmA/Ē7ôĀędZ‡ _П­ōs‘ŨDÓ) >ųaĒuŌ\1:MÅ,J :VŒÕX™+ÏŪ:ČĩRōôĶPMä^é\–?€VÜŽŌą7Ŧėdu;ðÝY‚U›TŪCÓ)W‘_š3ŨH|6’īLŋÏOÕå—4{%ũMpĘÔ6õøžqe.GØԛ°Ō2b2éý6x\ˆ­`ģĨC+˜Mõl…đhŠ0å Džūýrō3Å=lR…Iã“ļåïý1 ,.a…* QĖäCS9ýnÚ2)€ļ“’ÆŦé"Ŧ7J­Þf•Û-é ”ĻeGeģ>4óuLĪbpØjízú3§Ûāũ#6p9B+Þ ImŠæė(ēHƒzĐęÂAŊ:ėÐĘÔüžŽ\e&ŧŊ:Uŋ Vû3Vąm:ą‰=/ŋ?_& ã]ÖxNmLÁŠērš‘Ūʁ›†Wa―iãĢÖpŦÉYåMVĘÛŽö†%ÎVÔgåÓQwíKï^œ–9cŨ'ŸzŽ~—ŪYé0 ĄũþEĩYQ·įxØęPF’"TÚ°ÍŌk_§•ÁRÝMĖąf撎yJ|ōĩTüh•ÅbQĐéÝēoũõŦŒUšąČvŪ€ŧ›wŦ| €šŽ“ēšÆ·[Ãnģú]["gÅzuEe=0iņ;ž5E+žž\PũÉgBÃäÚHĨĶú0ūņđ°č‘I;ïđ?ĢĄEp5L3UïYBßĸA:ßĖʑ[odTčÅē';ƗĢÉüœų?Š{°ĸ›ģĮeķã~a(íSÅÏ.ąo ­ųØþdïZđvđđĶ€”1ëJÓøũÔĘm%°Î*éęģU€ÎjƒŽ*hīF•UvĐÜx“āIŋÁs?NJ,-Ž+°š9ŧĘâJž/ŠĻēúŠwiëGūÓ( VÉģšHW1]ëŽ>§öXĩĄQ‚"qÕ'Tƒ]bėĶåtyðonŊ ŦāHVĩ^ĩŪũWI―{•\$úVˆķnciC֕:€ąZŠŦû.ÕöX•)Š]ļ(įX˜Dģ=öÓųŧō’Žî_.ŧ5Ā`qKtP―ļ- =€Š>V=úŸKTï3+*XÝhËj(Î8Yõū՞šd•B€_ļX·Q&aČJûņJÉ-Xõ2€í>õ―ËĶŅUiŪVĸôcĩxX*|~j“pÓ++…ĩũXŸP{ŽþœĖÖOFEVýš:ũWˆŦņŠ]oÞ°:‡5Ðßō―•…UXXÍT·zÄjĶ`ĨíÕOVOþSaõåĩĮÕ}ĩĖŠ/Ģō‹…zzĢ)ĨᜠŦžx%‹ÞaĩdLWbyX…ÔŊâŠ9Y­Žö|uWíą*SäĶīŒ‰‡čĸnœÏ—°ģ·{­Î*ĮĖ―ʛŦ,­dUŽ―Z2€z\-eX}éģ+ûjÕũ_1Âjœ Ŧ,ų™5€đĸ~sĒeĨ*°ŒU{ ÆŠN­f›YɇYĨĀÝëYÕãjøņÚY}^íą*ŅXĩsŨƒũĒĶIæl‡ŦRî ïB°Ó–…ÕÁQÅM~R9Čę⇂Ok\―ýÔXíģ+ûj“UšŽ9}ֈ“•r “| Fíĸ·ây5`)`sģ(–„U‘ƒq•l•íUŒŠq•y7ą gíŽþfïlrÛb( Ģ’\Qš ‘H@Œ.}ĄëĶ·čyzŦō=r;˜Č#u7Zĸ$›‡?­@Vƒ’Ã&ĐŽ6Üü?Ï GŦĻ2‘!°1_ÚրÕnU—Ō*ŧÎVĄũ$€GŦiŋJ·Ju %ĩēšeē ĶDËųXÕ Ų} WÉ*čäTĩ-ģ°T•Mę§ĮAD#€Ø^ÝïĖYY3 ĒÕ5ŋęJVpŦYÁjeĩ#ÆQŠâN NŊUąkÝĘY5·:ŒĻXņ`e™Õ=ŽŌ­ÎËtēf@―Öü*B―2C€ĘjyŽþųÝ_˜ī‚PÐČ4€6ōhupV-eĨŋš_íЌÍ}+g1éŠ―&‚‚WOœVý*7ąŋeŸŽ*Ŧ%ēŠŽÕÃĩŸ^fĄÄJŨEV•Ïļ°õVeuĀÁjZúĀâęLŅđjŽjīŠāéË<Ā <þu ―ĸWVs­(HVõāåýÕ(X1ģ*úí{õģēÁ§­ŸŠn føUkĻ~5ÛĘc5\k DéŠØú–…ŠīČ*ŧԆ€N@|'FŠisb“ŅŦÜ*“ Vy€îŽ*Ž5^ÍīōXĀDVQfeũôb}ÖjïŽú"+e•âUÓÄÜãC·ŧãþŦŽ ^ņežęŽšö:ŪlR+Ŧåąz Vƒ€UJS! @‘u lāW­ÏZ Ģ„ˆ\(ßäöd”sYToŽâąîW― ke5ÛĘcõz!xð•ýÐũįižîWĐbÅÅŨšðĶÕl+ŠŠÝ ŧ, „OjOÏŦ~õeðl[+Ŧēڛj_˜LęOfËfUOŊŌZŨaó!ëIžU*ĪĐLÚÝËTŊxï|äWUÅĻVV7YyŽ."LZõØøcÉ+…ŽÂ(mm Ô!|YÁ•Ō°L–ĖB EįGú †Õ‹ĪĶŪ­õąúûŧVũ2đē"ŧVŊÎŽĶ3Ũ\UÞ0ßą"T‡X―õۄÕJ‹*ÕÍĨÎĻŌW?‚Uŋ%õ2Ŧcĩ>V[°ę1€ĩl]R+OúÅŠŪĶEWØīZųąMŽÚŋ ü:ĪŦƔŒŦ,čøęæęk˜Ur 0AëcõW§€•wĐEĒö@}ÆŠä”ĮX^WœLÂ*@(oąj^ZŦ;,ïøę[l\IÕ՜[MÐúXeôHė˜\ĩMŒûÆŊ[Ŧ˜Š|8‚°’'”ųji> āÝUõŽv·|•ŽūI—ZM9k•Y]ŦҜÕV[DŽÍޞ_+ÂU_@VÍŨWú>ÏĮĶúŠä™•.ē“ŧ;ūúœķ:-ŊĘŽŪ“UHގŠQó,ļ|ĨgÕó*gÕ§ŦtlĨĐÓ}•û ĢÕËõÃūšKŽūvV=­Ęņęh­“Õ` °ŦЊ ĩnœōĐ‹ÆÖJŦņU 5įz•b€ TÅjïŽd5]ü™ŽæŲ•ąZŦÞcĩŌ“+ĒZ“UëVą€nhiwĨ•úŠÎŪ6ęŪšę_Ž>ã§WœÕ\ģ­õąƒģj˜ņoęý~ÓžÖ ŠŪ ~ q}°æŦ /†^øji‘ķ:–Õ X}žY]‚fgĩ!yFęŠV·†cxŠW――JPýdKlĩŧ p ÃŊ†Øp‹ĩĒÕ'°ŠÕģ<x{b5ũÆk}ŽF‚Jce{uܔ\ūâu€täZ+%På Ŧā§'ŽZčuŨW―ÚÛūŠÏˆÕ—ŊūÏņęh­˜UŽĮÍąĻ<`MĮWāŦhWÕt ,pāĪvfÝĨÂIw}5\tWŸÚjĸš Õ}ĢŦ^ Ŋæ:Āh­—ÕĀQ+°ZVðU°šŪ]gð΃՚Áj:/8åŽâPß;“Ŋ‰ÞīUŽXë†Ā›ÎbĪNüï?ģšRV-ø ;nĄx‡q'@_x—ķW6žW™…Žú*ujïŊ·äąjŠWmûûŽïēęūúŽ"āÚĩÜ·ŊĩēŠ‡Þ·ßÖVTŽ:ŠUP°Ę$žŸ=KÄJQá4ązųļ­mĩa―Š"I·}õƒĮŦĖŪ2Ŧī^VÝXÁjc/ZuVß0ðVŽ8g‘/ƒÄęYWöZę‡^ŽĘĶ]kŧSb%J‡ V$ƒU  Mã4ģšRVƒy…5ÔŽQ―öĄUÎWë,`ÁīÅ" J_HÁęĩšðDĨ?ąŸ°=<Ų·úoŦJŽ&)ģšVVCFiĪ’ŽzëŠQmÛ<;š&UęíUߔ9ŦHŽjŸŊ"ˆ>:Čę—ėŦ‹ÐXM2_mYKÞ Ė€•ķZG5E…ŧēäŦČŋ:>Î‹—l5uWޒzz°·Ũ!V_fV'jÅŽZ ĨÆ*+·Xú€ĨíA% @Õô5Ô蒟vIšY9ÕŦvWŽ^OĶø@ŽþŦ5ģ:ŧ–Å*ŒĩŽVø†5üđ&V-YđmŠĶũ%ŦT§_õŅ*Qu‰æfHDTĀĘWjŽfŨRX5Öé{Výę Új‘šæ~„1ē^ TņÝ{]i%€+|‰ÕaXýú€ÃvwŦŸŌęÕg“”Y]3Ŧ$ēlđ‚­Đ\X…„ŠoKŨúęņī*Đ"ģˆ[=ˆl(ąÚĘͰÜt 4pÝþøôųóėájfuAŽj1Eô^ŠöÃUÞŅŦStf•Ōi€ÏgŽ [Žâ _ÝÝW3ŦókvVKřJŪxɅŪŧdkÕWTĨŒŌÂ2“ÓķMĢ–)ģšĮ*ãU°ZĸøôþeöÕhvV-HÞŠUQ―ƒŠpéē§Ģ'S)―bŽÝnŽŠ`õ/T·Š€ęáØ~Ŧģ§V™Õ°ÚžÉĒąĻ°ē_•~îíŅð°,™6ïfwUĻޒķâcPíŽÎ^ēĘŽ.€Õ&X ÐŨZų Gĩ­Óę*3{Ïë\+ķhœŪēJ3Ŧ·•XmšoŸÐ ČŽ.Usu|ņ„`$ \ČJWĩýĀĘãē Ō*mUĪÞaUU€b‹Č­fï°fV—Ájį2(xråU*ŸhŠ)äüoVkްüčœz’Kd5õ ŧŽ. d•Y]Ŧ2V ­Ŋ ēHfK€îēJ[õhu;šUˆĐÕĶ Ŧó‡Ŧ™ÕE°*õSŌM Xū-x  ģĮS+™2YݟšŦ#YÅg‡}•Y]ŠÅ*ŽîknĩðjU"ļģĸBÕgŲ Š|Fēz€·ï2ŦKŅėŽÆkV­Œ5ĩįM VöōÕY þÍÓö GuT Ā9ŨŽū@ž åŲ•iZ;ŦĪ•ëW`­Ļ6ąúXįĘú`ĩ­đ€ĪŽaU+Œl#YĨŊ>ËŽNÔĘYÄ1bĨŞ5V;ņđi:ŦŌīóŪĩqŽĘVĮĀĀũYįúęD­Õ NõŠ@ĩķīf]nڝô@°ÁŠv­dUg\ÉjųZŽæxuv-ŠÕČŽĶ`•ĻQ]° uÝDĩŌę#Ō΃2+rz‡Õ­XÝí ąúlŠ2ŦkfÕe [ŦBõ/…NøÚxg5ļę^+ԔšËŠÎ ĩĘŽ.Gģģ{PýÕ@mÃK„Žī!uI–4‚ÔČA](Tï°Š+YÝXõÚr °-…U‘ŦČ!Ý·n ÔÉ_…äÜ*ķĻ+l= cXÝĨÜęh…ģšgW– °š‚T?dÚ4|9Š6Äj°Î&“†ĢXÓĩŦˆDęxV +þŌū,_—ÉWsÍjvÍÎjc1UP jCéWDáwņe§ßė•ú`7éb €sŒžc5Õmbĩ.ÜWßįúęīV!BņøžŠ/ķ!ŧĢÎ%VĐØÔm_Ŋš ĩŠČę‹Ėę"4;ŦŠĀ lS@Ī…'ūúOIŽZ/ŌώÕdVUēúÃÞŪĶ Fa8[ÖeŅ*Q™ CbĩeŽ0-þčšÚ1؏þéo/ 7ą›čėVũžó―•ØEAōAōķĪ–=žžįœï|bAĄaÕŲĀŠ˜jÕĻĩŦĻ"ķđr~·Î·þ^‚ŠËRX MŋjŸžŠŽ^ÊEМUdeu$höØŪ*ČŦ6ŧÛo#E @#€ā”f•{mÏ{ŨiXĩD°*Ļ‚UĒ*ŽRe}u'ŦaŸû€ŲK)ßVCÏkōŠ=МUTĸpUEuđēB lĩžŊē°R[EðÔe<ĘąĘ`ø~ŧÉöČVĄ%Šá#†%ój§Č€ĢHûUL sÐ-ËjWZ#Ū’Õ^ÊŠžUp*ûQ_sNũôÕÎæ_Ē–™ðþ*2:(™WÜĩj Ŧ>XuV-PåŽęū  ęóĘ*vôwĻ„ŊRš Џ7[Ŧ%Ye\íĢī:=i5ŽZĒęY§PŸwZČ ëU\Kųj‡í*9aͰš'ŦZÂę›NÊ%МոĢ|É 2œĘ‹œŲmlĢ’ū…zph"@°/ŦA ĨōjÊ=ŠœÕ °ÕQHÉk)Ev—ąūšWĩ8؟Uīšž°úūaÕŲĀjÄ&ĩâ9RiKŊôYhŊžJ[ ØZ5xŪëýUNpYĄ5ŽšiÊa5­ŠUe 5ÖÔj$īæËÝÃ`đž Tĩĩ:,›A)TĐÕ$  VQ[đV°:ŋđ~ɞęÎęĖ™'S§PĮgęÆq‹r`Õ]EīT>sd‹}•ĸ%ŨŽä7V_5ŌMV[žŦ°jÅųÕäņŽfßþū­Ŧ>)Ŧ—“ĪēÚŠ ļ Lqą@–ÐæÜę‹_5âlĄ›—UûąŠ_Šē‚„U§įVÎjâÞ>=Ęîî~ÔVwYöëËó­›:…:~ÏĘDKîŽWŧÂÕ$‚Ģ+ÍSpÝōUžÆõÔjŒ”fĩ Ūji…>€ŽšÉøų Žf?ëŦ§ äÕéÔŲđĐyüŦ$Sđn‚—óløkbóH§‚BE‘9ģBVƒYÅN€ß>ą‡Uwî^_=dŲE}•eß_ã›ĪBVYDĐŋX2Y'–€ļR;XåÅC“Vŧ‡°* ēĖWÓųãbz~ĸPgÝĸđ\LæiUĩŅ#„rŒœ­öH WFX&‚í&ėJlW­·VõÕA§íՓ7ū-Ž&“YïæŠÞú<žÍ’īʝkތðSîKĄž5°ĀÕ’Ø5{%ą< (gV”öÏģŠUw:§îŲbrV[Í&“ž;žö*cÕ'j­ePZM)^WWûŌ_ņÝ_ëjmÍļØŪŌÖŠdՃ|ՔVhØÄj⚘49…:>Ŧ-Ïįi"]€Haω@e`ÉŦheŊĄúŦI―p_nYÖ`iÕVX?XÂ*h$ĩæÕIĮn’VÉ*`õųyŦđSF–ņSíēäRfóĐ,ë*WQĄšWeÝúÔ;mŸØÃ*•85Ö?öÎ%Įi ŠĒXÔ+įãn9ō!QØ+ĶL@BbȐ=ąĮ―ŊŪ*ã€i ŸTüáÓúpõŠĘN]ð—ŋĶŦw d%)_ÔVa‹ŊíÐ'Úʂ #`Ą PėŧĨŽ/ËÕMŧ@Ïjđ4ûŨ\8ĮãŧZ/—hØ@YīīH`öWž—z(ËCãūuđ:XÔōŦ}Ŧzõ‚đ–Ŧ\hó_ĖՉs<ūŦÍ{äW“„­ÁœðAąKlų:úæYšæōQXˆ{9!Ž ―þäęū=­žúĮđŠõWætĩÉ]ļA2C{ÎįŠ!ūŌ‹ÔDšUŊ‹Ï°ðŠÂ>hY‹švãÓh‰6ĄČs6/jUŪįK\‘YSÉUÞŋ2q{ŒĻšzzÆÕđ5'– ÏWÔ…ą‹äŦÄåŦķ}EāšâŠRVøVMÏ!Uu°æú‚Û9’ū1ģYûŽV“Ļ·Ęązōû\ýāĻŲ2đę›"`I!+Ųö9māY(öē'đĻÛsœ>nE%@ŧ`MâŪ"WqGāäęm’•ŋwÕūiތVė1däšbsGĪ,‡ý―ŋĩ-Æī^@5øđ\GÛŽVMfŽŌĶy.ïZ!Vų_‡đúk=™‚õYĄ ‹ÞÕ‡}ŦwvĒé•ĩĨ’ķfĀ%c°Zóú°;ųÚ ÂBÐ/ Ö>\ũyíĘF`åhŲJĄý&+šjÉUö §Q€ĸˆįũÕĖ čĀÕWfĨ­Ž{šb–›šc.a;$ŽÏÎåŦę€ĖX aE—ąĢk°ĀÕ#КŪ^}þr2õ&yšQĻ Wą‰1”Ū~‹æsT ˜Ęđ*ę KúŨļ­|#p}^ķMūĘUnēRķuÖg\mw5§ TÍë=Ēzŋ™øøž>TC‡ŪbŧąĒðŨŊþîz\ó/Œ7’•Ö-$ÅötMšæĻcÕjÏšĘ™ÄŠŧl—æÅžMÜĮœō'ęĘ ä°^}$k ŽtZŌ‰‹VF ą^ÂŌYŋ Öû_†ÅŽlï+čCV銝4ŧĘ3ïZĨ\ÅE­ŦÕápX&nŠ^Ģ'+|ŋŦffWŋ"W#Hž”Åđō5/ Ž/ ü Îf RQkąðûYôŒ@ CO(`ŅrcŲÛę†―^ðV[âOŽŅÂčbc‡ÄüûŦøģŦ<‰ØgŠԈäŠ(gđôĪ`?D I.<ķÍú\ÞÜŨbzKŪŪ·tÕŧy üjâ6‰U†NĐïĀÕúSr5ā”[xnŅũCe3oUĖk”ũëe€§+ŽķŸ+ā›Į!@üāU”Ŧ> @B5ņŸ Í ä°^}OWIēXD#ēątū$+šÂjŒ`°’Ŧ*ž•īþŽA_Âú+éš6>ŸpW—FWƒ…)V•xÕŊãÕ7„r.ā)\áUU ŸsBVh_ÎrIX§-ëŨ-46Įŧ°b?`ã7Y_SðhH,‹óûŲúxó8ŒŨ0ūŋšŌÕïoÆ]Mho§Ō@Ę +YĘBŨÓã1ŲZ0WƒZí ËĨ =Ö^ÓÕĐļ>ô‹*ĻS}Đ]p‚ÍzUé‰N/'Œ^’\};æjÝóļ2áŨĢŌ ģ5›™…ĻÕŌ ė ]K_wzž+ųšî]MïÍý]ÍĻöŪÕĪęõ •yįÄõbē^††2˜Íā öŲŅŠ/kÜՏįrU”gŅÆpWÍNÃZ,^ŲæžŊŲō˜.Ŧōø,ŨÂúĀ€óå &æ^Ļ&Ū m` ú?.“ð2h”YïĶEīŧK„ęžŦÂ/ëÕj€S:(Vð6-’ßGpzþÂ/ ü€ÂŪiėš]ðũļû&WŊO0z]# ›áGf―Ā,ÂŽNĩYeÜü~9ÜHûĄŦÕ đ Ēėu%ÃÔßēېMēRŨúŽÆŠüFĪÏÁÚâ%ŋŌT<5%ûŽá{įâD`}&ņÔ*ŦcFVĮ]e]=Ũ]ÄÆþŅ b ^<°ũvė―#ö†]Î.ž―7ŽØąwÁ, –ŋū™ĖÅc7ú'Ÿ›Ëfvģ{xß―};ïÝoö,XčĀĻâOóÆĪ™ū"EŠþ… įēpA\/čL ÆđÚÃę/ s o Ęąž˜šˆŊ%2‡åÄLiE•Ŋ !ŌU?ÏÕSŪþm<<§ÄK­ŋp 4&a$ŌTŅa›#Đ°š$ðŋVšŠKQ]øÐyIúÄ5{ŒKŊä€nĀė“놹r!Ô9S1 ÝPšĖXŠŪúŦĘÄ2ÖUäKWkÃĖ“‡Ž^žóČÁôÁ.č ëĪv‚ ÎĖŨÖQó+\ ôší,ģL Gk^ššĶ4ąmӑŪ\Īø ššĪĄēÏ0OWaĒ€k­Ę >'Ŧ~þÆTē*I†ŦEō\5 ÓváōÚl€]įĀ Ë.N7‰åīĸļāÆómwŨtČ9–ĐÍkđjQƒÐÔũ0oV.ūį*qM2üÚC<äޚ0qÄŪEđlôóiŦf ™9ĒuΎA“ģMÛÔá~ŊŧSëÃč‘sܙ#v­ėÅôĘŠm‚€ĮÕŊ{›VH’Šx*™ļ"qÂJg―ŌŲ8äíYęÆ*J2]CÉrfŽĘ…ĘþķÝánë ië{΁,Öþcĸū rnÁ•ÛŪoŠwýüŦÐŅ;ŧūŋÞųü„Ŧ‚ g‚A4x<âöø‘ģz]o}Ŋýōs'žéĨ-8ėœęžåņĶÛ3ŋ†ëWswozĨÝxēCģmÕČsĩt~šqŪōéÕĪ"SÄuŪžGýÂ`YąJĩX% Ÿ'ÖUBfėŠSÕZŲāӇ°{Ų­LB';‡Ã-/T íŽ>ēߖ#Ï0h;ci˜GŽFėŠeŽÍÖtāÔĩ·0ú\î  aÞÆmÃ/Ū€Ïē†ŸÝZ°rÆóŨ0ójî‹ÎÃĘ/ŋ4lž"]Å ÎU/ÉŪÆŨĩ<ŌDDšã*_ä^ĐÎÕ$áóJW#Zļ–bäō'Ģų E-ÞÝßã—Ë6ØėŦ}x<ŦÞĐą“Ɔë]— ĀB{;äœÍÔŽhūŠ|vÕũĨŦ֟XŅ{áĐÎ aôþéĮÏc"ąqÔðœDļ:ŠĖ?<āy=áęöýú=kŽéš­%@ūájóf’+ŦïKĪŦž‰™CJÕ$á Qč*— ˆA-ëÆŽéÍ6LXŲčqΖ6Ãûå:zfû““7ŋ9kúå%ŲóŨ;ubzŦáŦ›šp<|Ĩ*ˆ)V D!yŪúxyŧJĖīaÐĶ+mĮÍïöōúÉzįŸ8č|ķ6oÝÃ=įįčę’QÚüÃkí>ĄsîõMđNïū•4U·mĘ’ØÕ |āßáģQßu•ũUĶŪĸÉBšęq• qMC -ÏéŅ­įąėāōp·nKæ’ 't5ÜĢÛØ% o„ĮÔęQïîōýÂWfw}ĨMoeL§‚HW―"ð‰ĀŽk7Ąg~áuŲĄŨzœļRuˆŦgŽXŲkļˆŦÁų‡ŧ ŨZ36·ýČĩNžŊīË2€*”$ÎW7Tû§Ūúū4þYšęIđšDDĸ~~Q PĄžZd0ūúÔa[Ŧ6`čÔę+SmPŨŪ]û†C‡•/6ƝڷZ0Ð B;;1ŠRÂKXÜÕēŌU 1%}DbØíĻŅ~ßÔĐŦį‚6nþÔū•Ȇ.Yd|§ėÐÓę§7t2§ôŠĶČÆ\jó`0OęÚŊ[‰ï>€ÄŧÚ1ÉŪ&nԒĘF§ ĒÜb(UH*hVÄUŠšRW§†Q­5 PŸčŠN˜†Úp‡˜ pS# 7EaTļZ"Z_ĀļŠösĻng”ņˆcđLŨ5•ÛÖ hæāŪfĻīK(€f9üTķ­f„âD- ŒŨßŋ:Ĩiō]ýņ}—lí]ęĐH2^á*ŋ`+(IŅ$jÚķÅkýš‘i(UTCÅ`KIFŧ*Uģ,ĢĪĒ›™Ä4MęŌÚ w•ņÄRZļī<Ļ' ÛaHīÔd–eŽŌcīîč*ū_ŊOÍPŦčší*ķ§P d†Iņä*ĩ”& ~"ĘŠ(€Ō:íëßŧŌķc…ĸÄō ģ1đŽĨîŦ’ŠGtš””‘=~ē͊iâ0MpÄDĮ ˆF@·ļÁ Iá3Ô_ŽĻtŋpée―$fÛ'vŪ]·mІÂÕ › AĪiYĖÍðāŽÉėÕę@xôPĀÝ2öšõ7ú þĀžKŌcäeD0`‰—ũA{8&%HÖ$ÞÁšŧđO€ŲĪÏŠ1NIû› ņCu7ŦÆ(#ƒ 2ĪŪÎÎO™ŧũXŊþžĖMŊ .'äY"*‹O ėŲāķąøÔų…ĩ kvØþó›ŌŌ‹õËÖzƒ!Î[ÅŨÁm­ĪöóųŧĄÖĒįe^X4Óå†RÛÂoú…7BĐūžūīĶ&âŪV›?ČôÞy>šī[žVíD$3ÖéÅãtšZaLŨÓÂ`RĖ:1h4‚›ŨßI'kŠMóåQÅ!k%u4Â)~ˆŅðÉZm4øVģÂm­þ:i–‡0—ÉžZŽî+C û"°ðæ€Æ‘sæFhÃĸb™2­þž‚V ú!Äs1ĮŽA'tĄę’ƒBŽĀ†ēÝZ %GĖ6E&a—Š‘4ˆPÐHvc# ÁÓÓũYAŦķhõ(AÐ+ŋ.OtԃPĨėŒ`žaɇČũi$Ęī:weé=J0‹Yž Ûu•ü>2Ē䱙\Ŧ?ĘīzÄā=ņA„ąËĩZŧĒՂƒG|~uk^åd°+œ4ąüúũjĮY1‹rð‹™žš{”“]ÁÚv} Ųœ{Ü=’óN˜ŨŦ3ĸÉ5—‡†B€–•°Ÿíŋ›ÕG§EîQėų―„Â3ąÞ―ÞĪ,•醷AðjômĄĻŪj!,j7‹,§Ī…Ē4„2q@š6”ej9یKËhĻ:;üŲ‹WV‹Xy<ŊÏčËfĮeá’wņ^žëCÂP˧1Dd„ÓVĀĪŲFs›njõ0­sŠŦÐŪúŧßôŽïôĢēûJ+―FKOåĢũv2wÎä#2TÏĖ;Žmõbi ðK“Ĩņ9ÆgpęŨö.Š<[9OqķqœO{ĘĀ2ūõrëR.'‘gt,4ņĸ,ë<æ‰älĶĩgõ·ä?rŦíH’„-U ę@”ĀE‚ų˜ōglÐÅqÁ­Ā―Öåh%3]Sî—1ˁ ūÜ…0 Ŧ08?IÃ-ÐOé[–æėHs6Œóa!K‰ĸÐ؜cGmąÓQ‚îóJãáð d{KqÉ ķˆčÍ+:V$‚’ĘnˆíČ^ëB2L6QąĪlnXëo)w­’cøÍéÖí― ·™`3i†'xsvPa*#æÁ8ŠĢ0ÕŌÄēxDŅØWČ+o|Ÿ1üšá?ÜöýŒŊ€ĩ{^č۟·øŌqUĪuæĩ]ÉįÆ+EŒāũ―Å^ŠIžoĨ6―*†žlLîYķ=ŦŌīl9/ÛÛ\Ļô­…uy%„xÏĸî/ĨĒŽÁô"Ä)'îuØB„I„a`ĖÓ\m‹Æ|™€į ę–Ø ĒIŊĶ(äšĢÁī=•É+a^‚ÉŸ=ȀŒ{ĩ:XÓ|ÄáÆ<üåí~AėŲdEœ\ЅXF JĐŲ+íóh F™œäs‡üūcĶzô„ü>ÝzŽÉû įŒmˆĄJ$lQ\CÁŲįt 1 Ā\ Įģ ļH‘ûēóý+å]Ÿ§Û}jĻþ"ĸTóy 5Á%ösũ 'Á+*–"îs[Ą6=ķ,uQîm‡sC­ƒUm՛YÄ2ZŠĒiœN&i“ =)Jũ„q$Fö’Î꒞čĒސÉräyÞúâŊ4`ZĪ`ŨÔ7  0L-Ĩx•ÜïÁtcĄ;Žeļߒė/Īé <99~aTaŨ.ōÐč–ā [ĖþKŦŠ#ÍPįÃAĻ Á.ãCŪĢØ ÅPT "?å!4"ČRš‡1)â_ˆ7⯭ųÝT!ȊēãØógsT\îîįïōõÏŦŲ5ŠųûÕJÝ USN’â6M`HĶĶž+Ķb™c9XG=sŊ™ļČF`ŋįlI›zŅcĢĩ`°ˆcŠŧ HÏäe{õēˆļšsŠ1-i–ŽÁã―#AQ‘h}ÃŋÕč•X-M‰Tg/ŅÞûýjĒ‘‰ÜqbÖ2{ĩTИrôŧGÝËC[{ šÏ–q°îæaĶhd2úÞa=~iĶʒ=æūÚņ3—Đ _īR]U72ßr–NšÜm“―;ÛýXīWV)}Ę.žâô;öäÍ·ën·O_þ“;öķ Å0NāŧS“"?uĢ&xíU7AĘ·Hpí"do:öĄņHœÄïýáóųûåĀĢÎ!›Ü‚'à $™~(ē„{ˆáQÚ­ad$ą1č ģjuĀDÉ5_ŊÖ ƒDĀÉŨVcĶ-rÝf.ĩ},yžė?‰’UÍ "gģbnüąd8ĄŒ#LTë\‡mMGĀSMÁ.ŅĘTEļÍŅß°ĨY3öV=ŌYtg›‡ģŲÐ–Ō›ķÕŽū|tã_)§b‰ž+{ûéœCÓEÄÞû1rÚG$þu·rŦėÓyA<――ĸ–;ÅĻÄ00Ŋä›F/Q9Ղs‚CęÓļqČV)ƒa‹°Īs™"Ï˰—_ÜYiæúðôģËē,—ËÛŊÉnsӘÛfu’7Rhl­XÏ4Ïßnč{ÃÐ.†Rw›†˜'5Dņ9Ðį+BŦ­āžA$‘“­Ėš)žēöĶĄÞp~3qŠÖoJøtĖPŠ…)*T)þBāĀīNJa!ęvÔÐÕ§ïtͧh/Žš:Í JWÕâ­Ü*vÆZ<•Œš·_[BĻę B–QŽĒik+‡ę§)ÓŽÁEš }é‹Ę^ļ ŽECÝđ}ŨČŸ˜3'ąx?q!–åųåúøĸ‰’wÛ|~jIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-select-components.png0100777000000000000000000010777213761647206022063 0ustar00‰PNG  IHDRÎGæąmÁIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšžĶĄ0üëôE>ŒŊ~mmŨĩl™‚ œY$B‚X  : Pl8YeĨ[ŋX1þâ%ņGxĪæhÎ.ļð―8yrúžÏ9}ōžWĮ0LÓlÜUģŲŦešÕĨEmzōú㇟ĩęyŨÎfūdfŠŌ°,Ā4ØbYVĨRQUž‰ÝÞÞÞÜ܀ŊårŌ ÝÐōōâÛbēڒžëå{.w<ņ͐Ūk ÐųÃŅu°‚vØE öƒS þŠïŦāˆ@tÁe ĸÞđp°‰ļė€ģÓˆó.Î^0xæÓ™k5LËnÔŦ)§ÆŌó·åkĨÂč`x˜bY‘ÏÏLũøý|dęĩĒ[PÄvė͗OŧÃXl,#BdbŠXW3 öðq?ĮĮú{ĢkZËU§Đ‘úy!>Šæ‹šï;đT$)ø—šHËû§ūgŽdcŋu2ĩ°yļ-ĄNšð4ÕӉmŨNö–1ðŽ?.Õkōlbl}įüŌ1ĪgĢ8Eâ-Ė]4=eo=Ép;5ÛUø‘áĨ­’åØA Á'f,―wîĀ&fvOmïŽģž]ŠČyf”ˆ AM–UĮ6ÎgđÁ‚ßÚ/fäå“ãÔ`§ļīqR=ā(šlķJïĈ°ę~ŧRåMķŊ+Âr,ËlTLM~…‘Ųšú7ĀŨÕY§hgÂ―øJáäęĘýž6ŨŨ3ÄÅ9šTK/冚ŧY1óUwĨô“ÐÎ ąh8"æ=ßYMttôÅã<îZؐ=ÏnOf{~óÃęócšƒĖ <Ļöt^Ðų‚"č°ĸbÖz^Ģh‚hþÓ\ūÓwĘí‹QņŠˆđ|ˆHTPPbŒŲdĢÓŋ§{š{zOŠŽŊ§ÖbÝYcžYČP[õúÕë·ĩäā ČÏÍŋŊЍ?xnô‡Á[f ĨÐHĪ”P”B°oįžÞšyöāū~õ2ƒÓ€i­ ÉyJ įóųl6;??*`ŨcŒ“˜Â‡‹ŨïîýĸfũéŅíãŲ Œo=ÉXErNŅåž$€Qda”Ģļ†'Ŋ\YÅģŠóÄĐ?kzŒY•ąv ú Wo7õä8Ëü|/äSðü?Ōäœ|hGӆļ(I Ą­ėĻtÁ ­sJÉÎXšū$šAŅÆæ-ĐŽG`b;ĸlïž:-]—‡’BûĐVŽÎZ-O%­LŠá…ēąKđsķ ⭂Ð.ĄVb°ŌļZ4ōBęspRĀ}KiąŧmX@§ 釅wŠĘFQ6•ĄģüåÁ[_ ZõXßG,Åôī|5SÅūïŠWrÄŅA"áCÄĨĄB9KŠäcîšN+réSMSÕīÖĮ˜úޒ=ä6ąóZ6óųGWŅ.â% jŅķÁíS#Ô+āCέUÆw‹ÏCŒQđĸïöÎã“ÎÕvCųæýáÕÝļ?„Į]\ē?ž$ †w› |œņžØ”óïkm/0ãY*“\ōûBp‘åM_x^ŅÍTSäá؁+úģ…ŧ5X Š1GŨ—‚wðÚžÃbސĩ‹—u€ČA—sÆĸēáõą/ω-$| /ũ UĀ ð7€ŋ"'ĐKlLKƒ(óDâgŲĢ<ŽšŽ“9Y0ÄĖ`~r0ZEōqŪlôâ”„eð)–ĜԝúÃ#6úÃķc‚  rĨc—h%­Œ5ĸ؟FŨBŽ+%/îėíόąāĻʋŧŨũž―?ģÆ*ĩT}Ču *dŧ6Ļá_=…a@€Ó>ŠY äĮēĒŽI0)!Ixēoˆf9‚Ū@ JR,ĸŽ’–†r]ac 3Š0šļb#Óh(€RtØúŽ,čģzÄ ŽĘ(§–:GÖT€N jīāÉĩĸnV>Kē9þ#|2a•Ï?āyžÉá§iÂÄãņhƒ1)žqЧ˜@EoJŅ]ëŲåWSf#zĶaiũčœ2ÐR}YVWfcŪ->x,Åiņ‰ēĖĮščŽmņ1ĻųžJŽÅĮĮÉUەl<žæ#ĸ'Þĸø6=s8Ė·ŋøõvŋŸrU>!žĘ‡ âƒzDKødūÅáSŊðĐUōi›•e͋QÉïMÂĄü*M•ï™ŧ‡ŧûŸßMÆGESĐųėũ{+m\åƒo―?%„wņņØâ3aō™W~_ˆ->Ø2§eČßóáoäs1Žã0 ›aã‡#ūïú͓mų}ŨuC?l·ÛqûX·e7îHĄPF`Kē(Ž"PT!pÓL1[ļFßũÄņTڒɈS@##ž3nå.ï ^īĖ―zVāiôz>ÖâCV“-%ųÐH™7YáSÜ­ï >!>X›ïĻðņHĖ­8ŪōÉ(ųėÆ‘Æ››ŊãĶāÓoPVųØ>ÔûĨ3ö>Ý+|äcąĒ|°rrųþĪ“O č-ŋc1Z_ðŲÕïO–Ö|pĀžĮîKg‹ï›LZ|2°$F Ēô7ō!sø`Øi|ôöū…b.ãĮ‚ž?Ą]ōA‘Ę2ãšĮÓø †“1ü >ø‹ÏÏvõlŨŨŨø?: 3KŲ§'ËâēĖĢū>ÖõĨˆg~]ÉU—o•i]^^ķ––Á:ŽÍ§ĪWōQü>ÏÍw Ÿz”ŲšĘų`/ø`Æïâc>ˆËKĢīø\5ĸãÕĨ!ģōþ8ü||īäó›―û€ŠâĘĸ~ï”WÄĆ-vM4‰‚nĎEcŨÍÚPąĒącÄØPDą ( (Šb†Þ…Ũž2å‡H6qģŧ'ĸėŅä~O˜yŋ{ïïņ{ïĖa ĸŦ~Ą$ö?đ>øú`PüÁ0 ðßĩ†aŽZ Ã0ĩ†a8j1 Ã0ĩ†a8j1 Ã0žį0 „ā7"ąD"“ðĸ{qâĮÅÏĆ―ŨQ‹$YFАĐ4NČ=ð$-ŠŦgO;§ãÉĸ"Ąā_f,E„AĢ’É”j―uu>4ĩ|7 ÃQ‹‘äÜŸ6ėóÞ.n.Î―šö›|;K'ĒÉ_Ĩ IręāÍk·í(2’ĸ)ž5f–ûuĖ’ÏJŽņņîõEogũúõųŽkW ũJHšžį-f“°ÁwÃ0ĩ$Mi>Óüã^Wv2vœį€Õ#L _…b›ęĮ ŲÖĄjÞišģÉb‚čČZ ­#ØŲP$Žd‘DZ}ŌN*Ki6ýÞ9ĸŋ”˜l$4øąˆ|•9f⎈Ø,‡Ū.“gĖåŅĢuSÃøę–ÚØUŊnKS„ujšú㠊ĪęØÚĄWÄ4 ŠšG[ąĩĩ$AÄ4-Š.ąUŸŊyÉĶnugŠ”ČF*Ĩ)RTýR1?ĒhąmuĩTLĸž˜",–JhˆĘ$RYZė–Õ~įŌvRŽ^H"\ZH8ƒa8jņ'īUŠÂƒÉąKß#Ûv}·ïØũvũų؎å ūJīČËËëï‹Ũž.7’Ī·°H$o‘EïY?ÁËkÆžĀÔB- DHPÐĒŧyzŊprúÔ―‘·KģŸ†lŠˆŠ:v$,æfKÓ5)M™äĮC7ŦØŅKw]=stã*ŋ PôĻHÏœPQ‘ŋó7hõŲ –Ý{#')4―ņîųðĢĮĒ2s^ŽX8sâäo.>Č7Ë3w.™0qŠÏ•ô2‚ĒIĢ,:<ėØņK)É·˘ðõŸ„WåŠ[’Fõå°MĻ1Ŋis#^ðh?$ųöyüîā#3ōãŽí˜0Á{ýîïMmR4Č||ÉŨ[XĸÐĨŽ$!A–eÜÜ|äeNÁõĢÛ'L˜|ꡙYÔE{wmßđïȨ$Cņ&ųА“„•ūŽŒK5AB€aĸ#ŠũĶԔe^oÖHHqO/ŸŦ3dj^§•įgޜâjo+­Ũąƒ­TÚīŨė”"•ĄėiŸnMl›ĩĸþĩR_ņŌodûzķŌví;HhI[7ïĪ…ĶøÅšŲmiŠÛÔŊW·u'ß3‡ڊõZLY,ŦŠR)j­&óV„3 €Ý°ŧYrF8ĻÔj­V››vÁÛŲQ"ÛĩûԆĶë7i―íü3cUŅ—ŪbąÔĄ‰Ģ­Íi[ŋqģ–N í(@Ã~ËxŦÕ'9ws‹m>úĻI]ZXũӑŨ^”k 3VNu—J%íÛ;IëÔwēáī\_õ lžDd_ßąĬB’mÃŪgTY ÎoîØČŪaĢÆÍ;ØØ;.;šĻ7TÞ;üĐXTŋaSk1%ýâø­Ũ%qn­l 6 {O]—–Sš —”ĶęõčÛĩMýQþA؊JĩRaõ›―0ĩRv-lUgG{U§Áī€Cđ2õãs›mč:ysYEņÁU“ŅKcžËS­Q{5K›đ€ ŧĮøŽrÍŅåhóėņÅ­uhðągüģB•Ē,33W#ËŲä3 ßu=CĢ’+jhīęôŦĄí \e–)”ĘŸũóöß—ÐcW†)+õÔ§@óŪģ^ĐKV;wPÔÓkQŌÓ;“[Ēīĩų|~Ðã‡ßOrn Û­,Ĩū$ų‹ÎI‰íŨKff$ÎęŌÍ~ãÎéh;͇úŋ– Ó.ĩvI›u>•Ķxzb aĢÆÏ^O>ļn<`þþEQʂá­ ÃîįfÝnÓ@ôņg+ËLæ‡a‹([ī—|`í8Tž $ZkķÜÜãÝĪøæĀZ-/y1ŊzÅíKoååē ™\“Ã7{a€åIŊ1Ï­›įÅW*o\ļîhü[Ĩž€Ē{ãGßzâ*KΖŨÞ F 8+‡„ ?5qĘØ;ϧPž_QX.—=oR6 9 jėØ@"|*BChõ‹Ï‘ $Ņ)^Siáĩž5ĸ@]—Ï?Ąq7ũ–ÍęčôŠ• ißÔkķÏíÛķlkõšĖ™ôYÛķM›4žŲ: ĮrvMÛN›?ąmÛnCf ”·hôĘ Ey%jlX_ŅĻí§ýœĖ•Ķ’  yFô‘ĮŊÁݚ:ĩ@ÃIę5Ęō‚bÁnôtĮ•!%seUēLĮ€eÄ3ŨûÔ­i ĄBX}1Há?" @Iô:ķ(Üēt֘qF'3€Ä·'`øģZ á9žhÝkĀęíĄa[f`Ęü!ŨČčĮîƒ|W­ßčzŠÓzÏΆ(DeAŲī]7ĸ€ĩAû"ããã§õ _] ,Gą$’ˆ%"šŠžœĒ–‹Etmä ë7iÖąÉŋŒū˜øŠK%húCĮp,ÅR"ĶSÉX,€“PĪ0š€€ä8 ká8ሞ3ŽðÖØģ‚€‡ IĻ“W­Ē„Â`ĶÄbēfÆĖó,M@žGiR*Œðëš·8žäҐąs|ūÝô},z ífĘÂrS4Q[l…JQ3:=ƒšįĄtčŌýqŨNųŽéþúa|Āâõ·ÓJ š†ĢöŊ~‚ėeXXä•ŦwÓ_>Ï-”Ģsqģ֝›Ųƒ7Ŋōå:;û:*YiBWf,cáŧõÓ€ĒâŠÜ"K={Ž°HĄwlÕū‰ļļcĸÁˆóĐĐũŪÄĶXŌŽĄ1ąŅŅO^äYQóޓmØšĮș“IFđuÞÄ-ĄŅO’Ÿ=š,tũå'ĨÝŒƒōč3ĮnÝđ}!æD^ĐŲĐëØ hŠT^o`År,'LxFČt RŊ’Å_ŧō á\Tt<5íÖŪsŦ6;ڂӑ§/>Lš}åbBNĄĻaûvNuY–ŦūW Íû#ÛõšvęųY_Ā›Ó3 HQšSåH@(f­ËŨ‚,k6V‡Ï&žĖ5Vj]ūĪ9M˜ë?ū'dŒĩÁ0 G-ūŅf/ņýfôČáÆ ÛzđÍßū^;ÍĢ{ϓ‡·õŅ?X:mėā!CÆNœr9ĩ˜$H†áxū‘”d>žŪ“ĪĖoö0AĢ―§GÝ)ėøåøˆ€nöÏWÏó>|ø„oŲšƒ†Œëé`ģĮßgÃn-ðœ؎œžî›æDI ß”!C‡æđpųÎ-ŨßËoŊïĪgįƒ‡ 8guTυ{vNoHrË1,ÃA40H)Д‚$) ðuŽ7V$aQ)öÎ[ėé9įzū―ũęMƒzķčÔgtxðŠNŲ—§ð=ÝŊnŨa!ûvđ8‰fp–æ…+!Ė‹pœļņĪ›|'šĮė[î1hðĄãæ.?Ąķ…9ĮpDmą€ĩX:ļŒöyĢžĖÐ)GKôæļƒÃ>jâ™$›‰ó—ļ}ڔgX€aø„ŋ6Ĩžžčņƒ;ąŨ.ĄGÃ]ŋuũe~™FĢQŠÔZ:;=9^xhnü―‡ōŠÞŠäåéÏRSR_•ÉJĨJŦWg―Lŧ{-îfâý”œ‚·JĩFĢVe>}tCxŠgüÌ7 ĨJ)ÏL{„]üčIšLĐRüDŪD‹(*^>{t3ö2zļÝåk7>yVT&SkījeYōƒŧąqčAáē‹å:ZДįf<͊ė2ąÓĖóŋę\ĩaފ ŅŅ Öå!!IQ4BQīūíE"š$ĄõÝ-Ē’ ŽSQt5ę!æąRÐzh‡ĶŽodDN •˜āyž@"5X;PX4/=nãĶ=•"1IÔþe&ï]>rôÚSTN@ tŽ+ôJĄ‰­ ŸMø‹ŽjfķöĄuĢĩ• (í}A"”UPÄO/ -‰ŽæÝÃÕ5$Q{ëŠÖCŠæzh”Aęŧüz9'“„īОu#5 U;ŋpĐ)øÓQ'$„Öšš―“ĸīk’ĶŽ‡ÂšimH8 ë 5ßĩÚÆDՍ@# ^ž_Κ>Ŧ-ĄÓVYx‚`MĘĻm~înýGú‡ä€ˆ`böŊuéïöe?ïS·óhšÎ|iڀĻ`ĸũ ‘Ø ģÖÛÓÍuāü}WLM@`c`TžÞļÄÕÝ}ôäYŊ5ΈdOïÓß­ïŨþK $*âWĀđObfšŧšöŠx”‡Rœ0*Ïíöwvqéïę}ųnRäķõáį#<=7―V0„•DÅëÛaAŧw~;}A” JH‘îōąƒœûLY"ģ’$r’.Lwsuâ™THdíÏÃP[ĩÓŊo?W—9qÏäŅŲ0s@·Ŋ†ūYN‹éâ”ļíķŪïė6tũåÄ û9ũu]ąũŪ™•>Ûē~ãĶ cúöîŋ6⥊Ņ; 4|L› 4ž(ųúöM;wŊŨũKũ-RYJ,‚æë‡|đđ ŋ,ģÂDZįvŪ8rlïčĄn_ðųAÎå'ŸýîĖĨĀņ#‚N&2•Š]óĶđļŧ{͚_jē@ŠĻüa―ŨÜKéj„UЁ‹W‰ü'1ģGũssíŧbũI5'"õŊŨû‡ähYŠânZvŋE!€„˜ÐÍßt6ĄEŲåģŨž %âœØŧĢßf=˜ę9ØÍÅy–H5CŠ·gvŽ8rt§‡ËāQKr”|NŌ™―g.m7bwä=’BhÖߌ;vþČa?ÏŅ1Đ2MÁ“€ŲCÜÜ\g,ۜ­1Ũä;$HBUú&Ŧļ\,fŊmÝĩ'hՌū―ĸýR† ]Žg7ðpuó˜t)]ŪÉO\ŧ;rÓŌģ6Fidy ĶŽAģyzoČU0$ęŸį­éĘsrĘâĻÅšRg=ŋļæ0į4°Ģ _ r 'ķlW>}Žsə•ŧby:ut=ģdpÁwë.T‘–“+6=í9ëôÉãÃzuĄÍķŽ.î2>"tiYĖŽč‡…MUŋ‡‚ĨIWÖš?sWxȆ•mȒ'‘sƒnĖ=đĻCÎŌÕG+I9+æTÏgûö\ēqïŦ U·~údi`ȁ•Ý;:õ4žw›në֏oQ—@roßžK?wŨŋđXķļŸ aŦK>{ņąaÅ6ĸĒ+ŧnŋŅęįģíp^âÓsÛĘ­9j3BLąĮ—/Úpč™ĸö}{æwoC_=šZ/ðHÄÂQįúlH.0ršĒ‡ë:zû{8kęyUũuӇF†ōÖČh ĢŽ„CŋÞâ;&jŲō+ß\ßp ―Áķ°ˆų#;Ė]ļ!ĨČČꊎ‡„8zLq‰=}*[Į―ūvpÕ)ĸá“#ÛWė =k Đ'ŨöíˆÎ›â·Ē!!ō|Z“nÎ]š{ŊÞ8ÎĢGABÔÖGFŸāˆ UKėH†ē†#ë7oĀžÚyô, č”ČÃŅĨõīũ&ÍŲÚÔkKøĀ7Ũö, ū-ēøŧ‰ O’0}īYĒ%xŠė2ũÎ'<ēĻrÃÎDo Ž7°†sGŪé /qXðíūß-7Eïŋ_hP–GßïÛS8cųōʧ.Ī7ûäËA]œ&lðtï …īã-éŌąGïÞ―þūiģkKýÂoü2;~âHýŠ[Ӗ…éXû#Eųóøëéy’Åiwöï;ÝÆ;pĒý›ÃĄYķqkPÛaó"Ž:·ŨųĻíЎ-<žûMu~ōž€3§v6. ‹š” Ī4ĀpÔþ9‘“û2öVžĄ“GxÄ2'’eīé 1Šœįþ>Ë2hMV1ĨŒĐxƒŊĸé„b3SĻbéSFŠÎí˜ŋþ`‰‘Зgū~t/ãú ß5‡^e‰25 49Įō :ũų™ý^ŋEû ëHaz|”ŠļpïĘEGoč5ŊJ•@)Yōō^E~iôŪĩköÞĐxĨW+åĐEŊœúŽvéŅūKŨ–MšīnãÔļ~ƒnŸv°Ĩ ðá%v­Z6qjÕĶÓĮMEœZÚŲ3dĸÆŊÜöuhĖqlŅ 4aITК€āŧåŊīōJVČôĮĒNx›ßoņ’QýztíŅÝQbypóŅļ)súvl=ĘkJUÞÓ…:ģĐŨ˜YþsžšĩmÖĄũĻ ~sœŧ4æUZĢÞXÕg˜y3ĮôžōĨģîîÓÄÄøŊĐsút†wRæ>}YŒ†ũ3ëۅÞ}{}ŌļĮY,đåđåĨĐû–ûžšņDg0UU™ÁG]ŨŪĸ•{—NNƒœnÔēUĮĸcï­ãĢļöĸĸsÎØnÜ=„$$HÐ!Á ÜŠŧŧkq/î ”hđ-ÅęH)ZÜâš6vÎųílÐûĄßÛûŧímï―ó|ė3ï9o™Íƒģģģï·KxdÅūãŸ.;rëųį ŨrDUÝÚMî‹ŋÝw)õ—­ŸüØy|ß'_íýękŸP*ĶÞĪÎuî|~š1pŽ+ˑáõĮy*CģnõŌ.\>ųÕŨ!ÕS„ûß~ýųũŋĩjúŽÛ5oėš}Đ( Šücf.šÓŪQRųȐKŽāVB+ŽRxį‹ïó)XÆ/šB ›qõA‘ĸÞÂKFMÐVųņĮGfŒāë/-ݐ&E„tžīdPr―Š•Œ‚ް^Z5=ūeé”%[r1kt)íZ&ē„Ŋ›§óŲŊöŽĩúZz‘EÉÁw=Ũ K­ÎŠŽ”KJ™2u݂™Ã+–pØ@!âÜBĘԛ0yúÆ=›6.éš{õĀčųëëõÚ5Đ>Įō0uúŒ?úŲÆšĘÞ3ķX‹ā\ģy)ģæėĸlSũúe°Ž8Īý#glßĩ|Pýcģ'Ė9™æâSi℉‹VŊ>žŽ/ PJ€“Ŧ2”ė0pÄôy NYä,°|vzŽD‹&öxŠĻR–ÕÔō%D’eL( Ī 4úDĐāäæÅJuĪ<}fiއ)Ð`X'Ädgh‘ qînnųéđŽoފ U•8 ‚„ (Š ‘,ĘaƍR$ŧ ™ =}C=Ý]‹ÝąXTˆUÞîNÏCÍ]UY Ą"–ĐŅĖäU[ö-ßŲ…Ø8Ä83`YUrŠfŦd‘(Ô9ī⚃Îï^ãĀī ŪįrޛΔρå5Œ#:wžÜĪGœŸā@ēóŠ$Mōóē°ŅĀP"JW ŽTÉ{xíJG p@50ŪelŅįÃæŽŽiķxH'ÚÐl—’å+—— ïõ\h8ĶÏHoĻē,ĀČpN ŠŽĻ*Y@ģUīĘôÍï„(yEnjŅ݋ĩŲōó-€Ēü,Ëð Īā5ÅÛ* &<%2æ; šwxĮR·į_ÍÞīŋˆŠ’'Q āČķY§ŌāðŅCŦ‡GCAôũ7gíÞĶĒ|•ĻK­ÎD‘ĻUáY„QV1%ŠÍbÁÐ)ĐkoXpöØéŸ._8yî§ŧ*PԂīG7ŋŧøÍ­œÛWÎýpíČÆÍŸýtĮĶēžFƒ‹đĶ]›ĸâðŊœýæø―ôĮĀ00óÖũWėzœgs杜Y&6đw)ŋ§û?<ņËõïŋþæ' €Šh1[ŽÞ‘‰IInŸî>ríÆå3ĮOĶcŨõZeíX:a֒UKVĸp+ÓÃ; ;í—uk?͑^HŒ·ÏW‡ũí=vŲXkĄĻhjJ%‹Y’$ŋĻĪš‰ÎŸė:zíÆ•ÓĮŋÎ.öĒ„ ũ·xūyŅÄ9˖-Xs>UlÐąõ7G—.Ú°eڌEđqęT-D›,ŠÄĄū6‹•PMéĖŠ(Sčf0ûdĸĖyëVLŸóÄP!đ^|Ãķɧ/]Ēđ/ÎŦŌļv\(ĩK“Ms§XąØlāj&tM―úÉ'gŪ\:wö—›V‚$‹IR1€@‘‹Žē77FÞđ`ņ…Į™ÏŪ~―uįgi…ē įläYP ĨŽģrÛĶ—Ï?jÝĶ­/KKÔęPĐôĢÉÓnZ3sîĄįuķtw tģ­Yš`zŋqŸßū)}鋉kDƒ:.Đy8ķ~LL|ÃÜûéņ›8ÛģãĮïþxþÂwũ3œ9›'Ûk7k…ψēE&œ“‡+ąí˜·øüĢl‘ã-ĪnAÁߞY―h}Ķkl“Dãęås6o[7vŲéÝ:–vaČËīŠdĩ:öÂV‹,+/,2攜]{vūüP坝Œ<ï\.šÔÅ/vî>ð“$Ķ=ļtîÄãë/s6-ËŠ(TR Ä^͌õņŨýš7;ûLxþg`&Nœtþb°,›Ÿ_Āqއ‡Į?œG)åœ=K–ŽōE@[Œ8§ RQáv"*7­Z:õŅ‹„‚ÂĒ*WŊQąĪ_v–ĩVÏ>uĢB87ĸîøÞ̧|™ŠuôsuŽŠTŦ‚}ö#ŨĻØX?wR !‚XÍyœúĖJöÖ'Ą4įÖš^59ëIzÍÛŋ\td§wpDdt°oP“‰îķĖ'Yų‚KXLųŌ%b*ŨMÎÎČÃŽkl… eʕ‹ũÍΰFV*ïÂ9îNPX:“mŠ1&.ŪlxxdHĐČčrnŪ>MÖsĩÚ\Ã*V*íäørcV3!ĄvpVF4úÆT(_ĨzBYîŲã4·’ÕįŽíSƝeŒîáe#C}F(ûØþŌANF—ðčōUĢKÜŋp7ĩ°RL b >nx\˜[HŲ*>|šÝ=žÆžą―KŧąŒÁ―t„æÎņÎ!%˖ ô+Ó qKNFžI -]ŪL‰€ReËFļ Œ‡ĐĻØō!ūÞe*Wr†GpDIOã“{ũrdķųāa­ė­bār,~|įëŦNÃ's‡ÔÐ$ĐVQúÃ|‹ÐvĀĻa # r­]1R,0E·î2Ļ[JđČĻ@w}ņ ,_+ĄNĨgęUkÖkTՅwŽŪZ“*ŲŽĩá]’tŠ(^Ēd™ēeĘÚ ó /kĸŧø–‰‹r†gpDĻ”Rbp‰ˆ Ėܐ˜:m›ÔwRóŸĨÅ·yoFúÂK§”=ËFƆųyx„DWĻāãádôī[*” ōĘÉxšö4#ļ|ƒAÝ[yō(ŽLyUɗÛvnî+ãÕeDwKDF„—Ž,[ķ„‡ģOH؈ēe\Nî~‘QåËļpˆRðŸB(//āîîøøø›đđđ@į/† <2 %K–ø-ÃÉËó $™ū|–QāYE1œ`` p€EQ |­Ņ*…,D•e•ˆ Þī8€ 'pLąY–dBÃP‰JĒÄ–(Ē‚!à  8 €žA(NUYÁ@xøâoTŦE–1Ïģ’$Q íuER0ý?ÁKގŽRƒA°bODīũ„’(CmÉĒh7īDĘŊŲzŽ\aūLÁŋˆ„ĻŠ5)Áĸå:ŦĢK­ŽĨšĘþY`ŽýđZ]juttttĐÕŅŅŅŅŅĨVGGGG—Zý ŋB†aĀĸ:cJ)øũĢĢK­Ūģ’$eĶ?ãY (øŊEY…þÁ‚ čjŦK­ÎŸ€,šũ|yí§ OŅß: JT🃎B`ĩ€üá]ÜíRû+ĸįþŦ ”P BTÛxg!%„ūmĒøC„ ÐJŌĨöEĮĀ3Ā%ô–läx |Ũˆ.(Íŧ{š}/ļæ{ˆáĀ:6UsyĶý­ĸ/`YR)xö· [”žCG‰ōčÆuÆ·\Ļsýį›>å*đą˜ÐWã(Á‚žôO‹ļČē%x€iąŸŠ(ō< ĸœđ™(ãöõgĀŧrŲ@Ļ.ĩ :”H1T’ŨFŒ‰ŲFd…‚Ũ0 #Yåüž…w 怌 €þÆ Ķ,: !Hņ;/9ŋēkÁĮRå™ýšs€üŋĸS!ä FžĢoƂ%Ŋ™Ė&l˜ÐŪ3Ūö–cý―x,c‡—j*īp‚‹›+wãÔūW—.ž(­^@íüėŪëˆ1=݁ôoŋē„,Į__;wžWÛSģŧ ‚uĐýwĒ)V―mđuĒĨ}žĒ Ā4}ΊâĀĘ]މ ޅĒRúķΚđ°‰Áėõ49WĒ„ÚRþ€Ļĸ+uB€ĖiŨoÉÁÔ1Ũ:F\"DUEÁ„"ŧ‰e ĨŠŠlý|ÝļüĻA#:Ԕ$‰å8!ĨDUU ró€. `°WõðÕĮs’›ūzžJsŨķqåXËō€ĢķĢŌ€ČꍂxP)D<ĮBˆ=&oęļVBÛó`€{û!@Ŧ–bĮÜI(uļRû.TKĶÅcÔĐæ]|jU!Je&˜–dĪvcņTKāČCô‡―þ`t Ā61ÜCmÕ6&ĐIxÝFáĩ’īWbãðûO/ä< ­čáU–Rð.(2VöŲ?8dũ íC>ēoHЄšN“:ų”ö„ ųýŋa ‘…ĸB„#û―Ū‡ƉEąjÉŠĩŦĶũŦU#yāamØ"ó˙m­›&&6ęōé•ӓo§-Û5lŸ>ģ?*Ė}<ĒwûÄDmØâƒåŨ†-"„n}ŋwՇŸÎoŨâƒO`9ÁúüæĶ)­ã’WŧgËI―{ï)a™ĒīsýŧķHJj8zû…Ũũ ĒķôuӇ؍^uÐĘōé>iŨ{âų'ŠÁ Ų0}ÞĮŨÎēïýņukvrėfū āϗ―ŋrÕōņÝęÔč8ųŦsß-Ņ,ūZũ―?>b?ītÁ‚ŅujWkŅïðÏĻx„(ˆeģî};&Ĩqb―”ÕĮ uĐýĢŅĄŠėęŒ0ĮŸ8sýÔ7·ŌģqN!8qææķ-{ʕ‹ėÖąĢ"ŠŋŠQ„Ķį*Oēe֍ a2ēå§đJžˆŒT1ķHD”Ļ*5‰Äþ’ßž\"ÉÄ*SģHŽ ĨX%mY"Š#ĄÝôĶÅ,ę1ž ãEÂ*x ÆZĮ2JĀäÅŪÅą[ÖĶP›Dd…ĘŠÓþ’ČËC2)^Ŋ8’ōVR€Ī‹L,Ž5"~ąĶxŨĶRZžŦÅqxÉZ ÃÚNA5Iā/‡&’(íŌ™Õ+ķķÓÁåÖæƒg œ=gÁâāïmÛž0>Ôāä]ŠIDHÃķÃÆôĻ$ܱ߄={–ø§oýčð}`āĀŧ „–‰kÚiōŽ QNwáÔéė]&īŽųdÏÞĮ"Č|tý‡ŸoB?Û―ę‰sÅ {v I •ULČ eĸÜą{î–Øĩ{Ĩiįû‹>đSĒFb|îĨ1―æÚĩpéĮįÔ,C%1 Jŧ}ïéLŊoąŨ ™'OnØôq•ūsã Owï:ŠIÕÎ;mΖŋĸtbũþŋՙģĻgPöĪ.ÓŌT€4=į81uİ)B뱛f·Ú1wîwũōéRŦó‡!%ŠĒä[ðŒĐӇ xņęį9Ķ7 1ĘÃ?”`ųŨ|‰,-<”9|_ÆĄÛrzķeîÞĖ{ģ>IÄĀqÞŦû.Lņ 0åËŧŊėļĒ“O@(âWđaëDïŅ Ýgw /ðNėČ6Ŧz-iįSÎ **uváG―ī”1ĀÐ@įþIîĩâ}f·ôŠfiąLK–pžÝ%Ðūli{? ‚ýœtģïÎLvuCÔālîÕĢ–ĮŌžA‹SÜâÝįv \ŅÕ§rvÖõIðZÚ#pyGïxWĻ*ÔÛĮ0š­–tAKÏēFhU`r-ïIõ=§t \ŅÃŊcI†ĻÔßÏ8ĐĢ–b@ŒAĀvaušėŲŋĄÏŠžģšúŧ &5―ŠÅxLéÐ7ŽS0ø ("ļã„ÅÃSUŊd$™ņhßžņĐ]Ŧg,ߖYƒ[hDÅōþaŅáþn^Ūŋ>4qėÚkÏ ,r.Ą ï‚RŨ€Ð’Ņ.eĘĮ…ųx˜læÍÔĐV|_/Žbāø0TŠ'$į]>>vˌÛĄ—#wqæũŸ_z|ĸÄøąģūŧĸäæõ{€ óáÆÎÛũ;>tޖÚa.™žo&O›u85“gY í2myũ&õÂ―=šN˜ÚĨiĨŠ>|V𠀉Ō.S—wh0pæÏ/=•2,“yĸ§ī;ŋÛŧvōŌϞÝīfį[)ÔÐĨVįB"ŦēĢö:™‹ W/[žgũžs§OĶīmWĒB|ūÅ‚_Aā ‘ƒ9hā KĐjÚUq ˜æ |šųqå‚ÜVtōr7É%Ã=&7ð a_ķ%„ F%Ï!M}ŠûŽ Uäm9rDYũÝÝ]Øöüūētrũ2QB ŦB5w‚ĐŅË0―]@ûr)’Œ,õ&t HôĄE…Īq‚ßôxĢ›“’ā;>Ų#L 5ü–vũ‹qƒÕË{ŪfpsfZ&øŽj⃄8Ŋ9mݜ]ļÁ-üÄpÖđfeïÜxV‰píŨĖ'ÁV,í6ēą‹ā láß.XLpx'ŋšþŒ‡3ÛŦ‰ïÚ.!Fķk3Ÿfūœ"Š +cN&‚ŋ&*ūķ(ūýāy‡ķ,rI;>{óG…”W”|‰ZŽíœsüĄÜØĀšĨc BLņ°ÅwBU“Uķɚ\Ļ<Ďé–}-Š #kw9°ksƒ°ÂIS&ĪZ9ŪXš!kp1ÄÖN=vĘÞïNŊ Íļ}íŌsŦ›gęƒûũÃürdęĪ9Zũ xÍG€*ŠD†ĀxQ䘀ĄĨ–€˜—‡q ?7ŽJ)08đC.ļaĮ>ãĶNĸōôÚFå}TY2[ޘR]juþ( &Y}T#Ûu}oÐýkWnZë\Ŧuï&˜'ŠŌRŧĄðš=ÏFÎđT€b|ŲęąŪÁ °°°ĀDÂÃgHčŦôðᭂ›Ó?GíŠvȚq4{áWųnĨ=û…šÅ―ķøDxFšÄƒW䜇E OÝĮ@Vit˜SŽ?\·ýųäcųĢ?.”|ÜãÉGs&}œ―ęĪ%1Þœ… %ĮŽĶũؗs>—f^Éî°1óøÅÉTˆũïÏčą9}íY‹kļK’ŋÅn۟mOšâģw„g3wĪbó0Ŋýúôƒ7mÐȄúuĘōŲ…ÄĀâdhČ1šÂHKķ?óYnŠÄ•s…—îZŽ6qÍÉܝ·ņ_mü cØĒübØĒøjØ"á”Ü―ûöþpãtr5ðÏ:GD•šüÕî=‡~ķYō‹2žÜšōMęÕÔ+?œ=lhÃ^Áŧxļ(Ķï/ŧþ<Ļēl“(Ë›Ļ­V$E’Y@~þæÐĄoŪМopâPąncŒŧmkúyĸũWïýōÓđïnᘟ|1ēëŠÓŋšžwðąŲ)ŦÜGˆÍÏĘH―úË·OÍGOĸ)―ŠYV‹OĮ&ĘP“rŦÉq íÁ å+—­ŲķsŌäĩu:TðF’―\‹Õ―dÕF-ÂO}zėÖÝŧįūų&S$ų7ŽĪtw5Cfԟ@ÐųC ”pŒęnTå’ŧôĘÏNĸöŦŊz ė_"LÂĀĀQJ0ĸ IđeÃ*dŧƒDRŸĻÏÓóŽÉOmÐnw`ß O‹”l eĀģJ1ĨĒB\(0ĀĪhIĄ*AFb1äoũB@Í6Š) ÄaĮTV)ĄTT ā Ēę/yPä„čĢ4U!!@Đ|ĮŠEL%•Š„r äĢ @E-52@턊rdĮ < rsÉõõŌÁŒ;ę+`ģ|KĄá vĘĀ@Ļ•þZϊ™2b„Ē*īå°)jpŽÝe·P–s ôqŋrëiD>­;ķæˆÚ°û”"áxÖ3KũžģUŨcŲØiÂÁ=—ÏĨ™mLJÏqÄÛ[eA·‘ģý9E%Åmԑ!`āâMŸ}õ}Nū)ĒvÛþQŒ (ĻlݑïUðaUŨÚmúGqF€=|ƒčĨ Äŧúúåí‚YÁīxē}ՎÓ6U;qîfrŠðr­īÝže-ÛFÐÔõëĢZM-ĶŊ\þņ/9ęˆ+›ßđ‘S ķ5M -§( ųČĐUÝ#E)ßbĖ’šþ@DJ›V))f?/ÕzâäŽÉžĒD·=•’ĐûŽũ?Ļ}ð“ŸSS NĨƒ* ïëęÆRJuĐÕųC  Žâã T™ēŽÓāqãûč#x‡Š€šqÐYP)ĀāÁ0Ũ$OB ðˆEÚĮŌÛũ-ĶH=ûŒ”v‡FŠ^_‚§‰WvĄrîūÚđĮcČÖŪîîlēė~*Áj—†O[§š›ĄÐtÜD!ZŌĐŠŸx1[•āXx;ÍöÜä5 ƒ7øŅęî/>ĩÞĩš ŪîęâJŧÖr}t;3ƒ<*N‡jŽ‚ åúÖó9k‡X'œž.GšųtičžÆēm*9óĶãEī<‹―:ņðYž|鉯ļZÄųð ȃĀĀ#56B *”š:uˆp2›-Đ@āŊÁ8(Ūi Į°ÅŠ[BŽJŠTĨØĒ&·é‘ÜæÕ°El ˆî3:VÛSAïaŅÅóÕIŠ"3aI€Čēę4mŦĘĒJ(p€ (›0ķb]ŽČ•AT’d.0*9Œ‘EFTFT”äŌLŽÜ°8“Ļ`ðUE•’ZĮ%ĩvÔjÚ5ØU Ŧ4í\؋$-ú i4&&ؗ€ĻVÅ##c›īŪHĩóō‹jڑ˜ !_%đûøvÕīȊĪbZ―Y) ­!‚wģūCš'•% Ģŧīý#‡EęRŦà &ģ…“MÁAŪđÚ_*öWnĶĩ +“r>€þƒ;Ï3Ž?ĐŠäļīŲðwl…2Ā đ|ĮbÉ'WîŒý ŽĻî5.äeX~|h%"(Ĩ7X<ō0bĄ­HÞv,ÃĢđOĸæ‚$Ëģ>Ė―ŸĨn?–áųŌ2óÃÜ+ūqŊčjY>IæÃŲ—dČ107Ë:ĸHö D·Îõ yEÖŋý˜?k_ÎøÆn#€)―hėqKâÏßķ<·Bč•f\Hî>ģąēJē[ą‹Ąg#Î7M;Zô,Ŋų,k`=Í 6‹eÆ'đ9 ―ĸÜÆŠ*D -C< TŅ$Ŋú4kpCAmüÍ*9ž-=ĩĻßߓĖ2P ąįz\DŌrď.ˆÕ*y4Ė7üÅî!`YÄ@CÅŋ숚å5DUDUyąFUÞ ‚Eð E–^úHøÅ†"b‡MqXŠ…Oï‚ĘoÄĒúÂ.‰Ŋ2bð&/+Ņ_gƒ ‚='ÎcüKŠ’(TéE}-b€ĻRWŠPþ͈*ęõ|lŧÞÉãđÝ b@ĄTNþ§ĢK­QEĩ(Kð6ˆ7r.ÞHpþ―~Lĩĸ/0H[öŦBĩÁŋNFø›sQJ.ü°úŪÏœĖ$ āߕņNũf ĄÅ5čRû?†>œ\ `jē…#ā5

n℠óWïýzõ’1;N(žĀ_Ú1wōÆ/T€ĀVKĄÅ*ĸ#đ„œĀĸīuÆÔmg8ėž7áāũũaŅÅÉ#—ßx,#éRû/ĄĢ̃Õ+$īïĄƒ{uð 9ne’‡ŌĢ}cïPŲ˅ãNk2Ã"UÁĄU4ŽB€BÄð‚`08–o!ËņځwīhŅvĩ―ŧ1Ž6ÁÏ14Á~TƒeÞ8ÄŋÖnsäØbąƒˆãĩU‚ÝÄąÐaēŊŅ–ðœ#dĩŽ"–CĮĶNZøsŽ―øÆÖąšáļâ\1 %Ŧ6nT―,ĀH)<õqƒ„”ęRû/ĄĢĢC)qrũĻ_ŦZĩ*%K—ˆŽŦ\đJ…Ļp'aÞÝ5 ։o°úĀψaL9ŸeeC†ËŧũãØ6öq ‰óķ–`ą 2Ě·cAŊúuęÖmÚãÓëy*Øļ`TBbbƒãŋ―•ÉqÜÍS;n>0zX߄šõw|ýóŽ ęԎŋóáų[§vĖßļoäāĩâk-Úģ, ”ïö/Ni˜Ô`ŨĐëįléWWN˜ģyՐFIņÝ2S–ƒŌÉ-ó““ }ĸN!å@֎)ģķėXÚĢyíšý–Ü7ģyŨ>_~āЖa}f,Ų]Ļē"Š>Z2úÐÅlA Į>˜3cû7Ž Ü?w`ꆓ…EÏÓģr‹§&ĀÁï%ēšÔęččPB$IR%IQdU‘Ģã˜ĸxïuCýQm―7ÏÜôŒ ĖŦ_þų>ρĢsæîAUÖnÞÜą~ ˆU‡AIG6O™uTų`Öâ―[vįüõÞeénA—Žūōõįjuttþ=(6%ķËļMã;~—aÜyē@!w ãÚ6ŸēmōŒž~ãÆ—a!&(e|ð›>ï}Ô1)NU KRđ]bä―‡|~ĪÛŨŨģcX\ĩýԙCÛÝ=ŨiÎÔĄôî—7K(ąR-eâäĄ-ĻĐâų“_=ļŸeýþhtĢÁíâËŅŋÏÁÏÏýxģn+ęUĄúüéĒÄ_ūÚŋSĄōåûóžJó'LĖOĨE.­ ‘zŽmŦ8ŨgąÎ7ąĘx”*íŠĒ*”/,Š*€6ūQį― Ž}wė†Ðļa”’{ōûS'Ū–™ū$:w9pcô‡―tttþPxŧ;E”CÅFŧYÁZ8øé–ÆžYC&Ŋú%OeīÛÖāęï”]­8. )eļb ˆ­Ķ‚ht(P9Ģ‹ãŠD`<dE‘€„)Oý―Ž9ŽApóôē<ÏÖLT*°!žÕVą" Ŧ %”ĢŒ“Ŧŋg`ÕA#F.XĩbũúũIT0ðjv°M– -ø•RQ@B"k–aė:üÖ}&vĻė6`ïšɱŪHĨ€‚?]jutt$Y’0TŲj2ۊŧs›Íē Ö&5Ļ'ŸþpũŅów€]5‹,0ÖÉ·IÏîŸîœ?aŅÚĩk6ž}`ė9,áގéëwïzî\sTÍzeøų*ŠJŒl1|8†ŠâVŪŲÜEՂÅŦųða86$ÐïÆĨ[RP•mƒ:Dz0*ƚīa”ÐfħBč™kÍl€`dãz,]æ{čôOĐîą)[;uâeœ4xbL€Ē(Ņ fN°ēŠâė;jÆÄŽdBŨÞgĪđUØģū{ŒžmwŪņ>üÕY“!rįöņáNæœōĢfLðgāÜmøŒ _číÓęČ6ŋýĮūđũ…GÅ@äÝoƜ  ĢĒĒïÍŠjÏ’GŪÉ þ,/;Ÿ”+ĻvĶ*rjÜ}Áúli_ŠÓōÃ-åkĕŌ&5ī5…+ l;b *]ļÓIãú”õį ĄšÔęččü>$TĐÓŠēäļ* Ū–\Ō1›ĀPĄS$‹"Ž–\Âa‰Nn›\ė̈2ÅPĒbĶVŦnĩZ‘$ Ä'ũŽåXé‰@‚ĢJ2Š(ŠîÁŅíK"Q”X’Û•ÁŠ*‹yÞŪ-{МĐcÞ ēZĢ)Õ9üUQQ žĨĩ-kŊ„ž›ĩ·û(ēę_!aLÅ ADQIlŨŅqīBÃÛW` ōĢÆÄR‚eYĄ/Ũ‡Æ&”ŠH%Q>QÞ‹Ņ\0ŦŅ<Üq‚qÍÚU‘1hĒČŌïsaŦ·ŨûÕæååeeeUŽXüWĢsõęU???//ŊŋZŋZaþӏŠ<âbC(&zŋZý^­ŽŽÎïĨÔ3,ĶjĖïŦģüŽ@dį?ûk1J&ü~`EV1ýįåūËÎØēï_ūúëRŦĢĢĢó†6ʇæ _}扁Cŋý&†,šM&ņĮr9WŨĩßFÔĨVGGįĸ?ÐŅŊāuûŌ š…ģ Dž 8ŽóÐŅ€}ŲրgŅM ī5Ú1Äžæøb Ïž‘ëEdĮĮ.gwå^Yė0œFņŠâDÅÁ 0 'zAāY―ÎEØ I)5Ęx*8z.8|9iUŲĢūĖĒ%ĩĢayáÆš%ĢũŸģ› –qd0‡e3ņubėFŽƒ/NĘ^4ĢK­ŽŽÎo"dÉØŧhlÝÄĪä>ãūūSČō|á“Ŧ F%ŨMLLxoŅÍ|"åߟÞģCBbRįAĢ3óÝķų{ÆóÜ­3Ûf~xįų[gv-ÜüҘa=ëÔŠ―ô“ËywwŸēęą0 ûøÛCFVxMĪ ÃŲž_ž3ĖÞBĄn‘ ™Č°lÝĶmÛŨÕIĻÓaČž›yŠĀã/V-]đdéøÄ„š-ūœ-ÄnYņþžũjwýätČŧ1cP{„îÓÖĨą°ðÆŽnÃ>úáą]ï|đküĻ}–ÍÏz˜[$2 kįīY›·,éÚīnãņ[ŪüôYŊÖ uLŧ”%ó,üþĀjûÕ­ÓaÓßîâüûë?Ų·oÞīÁ―G>(„Ō“'ö­›T·åķŋ]šķR–cģn|>uáÚg&Ę ÂÝSgoüRH—ZßĪģNÝ=nāŠ=–…kÖũ(>Ī̈́ĐãGÝų$vþōUs{4ð“ÓÞÜõą`Śąý{š"å΅cgž ÄdÞûúûïÓBũÏ-šÜ'ēãļ~ÍÖÎņc—óÍĶ]gsœuû†KzŧĀ>(ŪÞiÚŪ­Ë /l;øíUDm'·.[ŧ#mÚĖYÜ݃í#ˆI=|Ëö•'Íęč“>ąãô LŸœ?ūqÛĄZc։ɟԾÛUKŌ†KK=Øß·ũ*ŲģBâō ―>;ņņÄđ;ÚTwGĘÕ3N͚+;ļuûą[―'Œgퟰ§ÉĀ)%RÎ;|ąÔÉĢôę{'w0­ē)ĮÉŋvx‰ÚSú āĮ>žÐeÄóŠÓ?˜ÛjëĖņį3 ‹!ŒŊũŨûķđōŒ!YŦ( n<õįjutt~“Ô9ûØSĩã‚AņĒj]óÅ{_9uĸ\pht*þÓýŊŽŸ…#?—įĄ(!Bä 7+ƒxM@‰\ĩńi#RĻđō…S_=Č+5ąkĩņû· (UæØõð­kjĻē  „šøäėX5???݄E"šËÖMiãQ2ŋaįmÏl€˜ í4uEŨäšjŽšûōÐKOĖV@;N_Õ·m’øčo_3ak–ô‰ āzïõŅļ―iÖąMF,yðļKÛÆúŽ=>8đ,Æ!7ĄØ'hÔÂ5ÉåsųƍžÓ­yÄóļ3ā]Üðē9sĨŽGVI0!Ũ21žALDÕļōĘĢc_åf^;ó„-#37§—„ĻēshŪM|>Úpžpđ!GŊl\RĒ_ÕęččüFórōL,æJ"uvũ`l™E… H dxŠyĶ" „PJ0Ąˆ˜öü5jrCĶu|õoËĖ)€ŸŌÃóŌĮmúŽĻÜŪsī·€Đ–Hā•ýģ'p—éÖĢw\ pĶDՂdedËBU@ ÆĐ ãūn‚B(‰B Ų2ģŠd€dÎ!˜g äĨÝŧų\pōš”úČŽ€—ŋÖĀ€rEU( š^ĐŽ?@ŽQÉü~ä”YeķëÜ ‘‘sáX ĻjūEPó4B>ĄuŸa̧î?úaÝ0NŅŠ§6•ģ—mþiÕ é›Ë7kęBÕĨVGGį7@0áýš'ÔøbóŠĩŧ?š>}ŅĢIrÝIÍĘL™>aåÆMK7|šgˆÜŊÜæŲĢVlÞēfý–;’3ïúŲGÛߟ;fþÞ[&ĻĐ$GwNūŋ|ûîK}+GÕŊ` ŠŅ!đÔÏ·]ÛīIā!Å@ϊÖė‚üGn=*Ėūðãé4Ŧ ũėôúõó>ÜģyōÞ{õZŨuНeWŪ^―aŨÞiSW{WoSÁG-YV!|PåöūïϜĩwïæËԊïLÓŒí•ZbØÃGÜū[1rÅ> °Šh5a&ŠÅŽjBIdģYT0PR, TŲdÎyjĘ{ðË7 ï_ĸþëTßraW6lÞ~ôŒXcPlÔw{Ž>ÉĖžuý‡§&‚(ĩXĒ(nšw ‡?<.l˜ŌĀ…Šü&tĐÕŅŅĄē›NYīuRrÁÃ;ŪqC·ė›åãä6eþÚ―edPƒ‘urï:yóė>mYÏĐŅÕÅčÔbŌâĄÕ^Š˜&RÏĄûvL•zëVn‘ęÄĻå;Í™,@LĻGDbPĨ˜6MĒ|EÕ{ čččüf(QĄĄfŦþņÅí TYVíߔ~ÃS€†"‰xīï5žÜĨî•ÆNŠ/P…b9ŨÓĨEŊ­ވ*•ó|ūíjó9CŒ@_ĶÂØ58fИ ĀAí$ <ý5ÓøÆÃë–4ÝwôÖ*L•äî“;Å;‚I ĶqÍÚÁ—―sPÛ“ÚūŠÍ3ĒwÏhÕîĐ*ÁöĐ dQôjØŅŅÔëÐI•E•ļÕëܕ:ú#Ä$tŪ@Q&՛õŦŅ h4ÔÎB’@ßÁãē$ĘÐ7đëød ĄÚSļVîXH2ĄųŋŽ;ßrxwψčRŦĢĢóÏ@‰$ŠoßY―æí]M―Ā+ D›MŸVÛCRdŠIą .]—/‹ŽĨĘ xōĶ/DÐ-nÖBßPY’ĨÔnRdØ}ÜčWJt˜€ųō(QÅ7ÓÓŨŧZė·Ũ‹/6ˆķņöĄ·OYãuXúv ,‹XŦV.SfŪ‹Ūæ}]juttþy „Å ~ÝōîŔ°ØjūþšˆRÎ9 !1ˆ`L4A„ŌwJ<<ŦVũ&ŋĖB1Ae*U„h.)(aÜBęÔ #SýŨb:::ĸ4”ĻŠ"Úlö—Žāâ·BĒææä˜,"Ë0ž d`-ĖÍ-īPû!Į1Ąh)ĖÉÉW)zaĒc }rãęÝ 3BðWs á[G5ĶüqœÔ?_™.ĩ:::ˆŨ§Žč7pč°Áýz-ÜũAŸm;īQJËÆmzo;û1ž„aÉĨO?hÕžq“Ví—í>‡!‹6ũögÃŧķJiÖbôžm*„ŊD™#ŸO=ûŧĮ<‹~ĩų€l1›E ó_,ĩ:::"Šäž}"īîØĨkŊ^Ŧ—xzjŲŽĩ?ÓOūørRë€c§ß+$k'/>:>iڗí—ýÛŌÛįŒĸęAŊĶ7žŦ3ųø[č•Å3>―!ðĖŦņކ5”3­óĀ ˆXŽįؗŠÍ ‚pgýōQ~Ï Ȱ‚ÁŽðēÃ4þūá„,/4_tcxÕ7cÐÛ-øŅ`qčč~ðšÅ–…w”äĻÁ^ZqV—Zß Ē0ą ‰õ[Īī­WĐ4äËW%ĩčáïÛągũęõ+OMÅjÅrčæÉO2JÄuŦZŧW·Zōî3,ūđúŽ|ß~}ƒ*ujXóâÓôú"–A(ũΗƒŧ7­“ÐõŦ›Ũ,ž―á°ÃĀo.[ąý쭟ïßŧ`æā^Ãï僧įõJŽW·ÃðãwōXžÏŧwv|›”úõ’îü\f"čPFbËÛ>ŧoRR―–{]N3ņûāŧĢŦW~°fzë„z-֝ļjڊÔÂŧkfýņĄÉ.›–ī ģ—myœg={hYJƒĪΆ?úö6Ãséŋœžŋð°ĖóĪðáŪ•ÓŪfS9óÚŠÉ3— ėÓĩíNDP—Z éoƒúöŸąlÛÃlŒŋ/žĸÓđ‰<ŧų(§°čþ“ėâ‹G€)ŨėVĨ$OT•P_ ōŸd˜ō39b0 ‚UÕ§d ē>_Þ}…%ĸóÏODwŨģĶ8sÄðBƒppÝÚ 9”ÉŋļôýO}cck– ‰ŊŸÜsä`ÏܓÝF­Ļ7{õ„Z…“ĮŊ(‚øČėŲ{Ø*ŦÖКNPUJĩ<?^;eÝũųŦŨĶTā{ Ÿ?‹Y·ŨžŋäQpûÁ JėÛņaЉ )gŊ‚‡g·|ú…ôëũÜxŠd]ÚÝm֗=įŽž> ņėņÃ>ŋœoÉļņų7ėT,:ûý™T ERÖĄĩkîúE™T—”ęģÅtttþE(V€WåMÛ?*L―ĩŽß{ýSÕ#Ëûĩ?þޜšĩęâęĄoOgZüԁäE ;\ÉnĪ rč ŠZ Ŋƒ*AũVĢÞžRą šė;2ËZŠ}ģČíŧ7ĸÄw˜J·jYĩäÅr^!8ĒV\ôÅ­KŌĶX=—7e\ĢÏ-°JŦĶĄÓw͘_ÐoĖØr,ÄXŦAĖOûþëKÝGŽ]!ĒšOŋ>œþó―ĖYŠÝi؜!Ý-_KûžÞTqqz‚œZviŨmꑟ”8väFóũ'Þ?Ô+ŠŅðĩ+[@ŊOŽĸøÃR1.įĖ8Ū‚‹ï)HēäWĐæļIĒŠĻ`ý‚ŽŽÎŋŽŅĮŨŋLĩĪΝãî^ļQ$)Íg­Ų<{ęĻžŠō>ebJxЊląH*Þ!†Žkũ%ĀēHķĐÁážþ! ĖΕÃ2ũîp†RFøú 7 íĻ’B)æŒūýzķųaûāŅÛŪĨôl •<ŦBpvóâœJĩëÕ{äĪ™GĖ AļbûÁ~P[xœ\GGįw1lŅĢó‡N5 ۊcjīëîeāóïœ>q)ÝÕÝŧæÃ ÖCj„šeŸÝŌ°Ũū…Ÿ}ÚēųĻØý#f,Û\ |ũ…âķŽiycpé^ą;§ŽŸ?ķĐįŒ#™ÃĶTU@đ(sĸŽ%U@ókĮV9ŨlZ%ÄāęÜЎēôã2}›ÄGR |ÃŊØū%ūtĮÚ]+Į^8~ėb—ĶåÞO/]ÉũÜÞý‘›“웑B°C)ïPŋUŌė}‹ƒ…6NíË­ÚļjĪĸĢ‹VÉĘSĻjW_‘ÐŨŨėÐ3j`ý íWïmģny +·čhŧaŅF'—ĖfŪnëo~jyūaÕĒ%™ķþl6ðPbb!ü>čRŦĢĢC@ޚ‘z+ÓzŽYÚ:đT†ĮŲOo_+ ‰ƒįtlVaÅ%ŽÚ”éΌ;ŞqÖ­Ųīë“TđlËûU8IáŽĸĀoÓ۟ï˜f-^ŨŠvˆüę<†uz͙Þd>ļįYĩŨÚ=ÝН=Ãk‡öŠÚ"ÚÏ(ËrTóÉóĖû 3Ę―wnßt`ũ§WŊÞöð‰c äãyõō-9 nÛ ŽeÝQņøg™°É=§·ƒ—oÝrŊØúË.ÂĀÄ·î-ðŠâ^Ūî°^üŒŊ~AUĘDÖõ.ýi“ņ)ąŠ$‡ŨėēsĨߑįóđē;wLŦUĘĻH ·.(øæVNÛÕ[;͇x!'RqĔ1~Ž‚)ÕĨVGGįw€bÕ%,aÔäDðŠŦ€ œÃŽœØ8%‘``ˆíŅŦ"vīp‹›2ŦjąŊ}Øqé4qF'‡I’ðB`ÅäqƒIĨ0óîS}–ÍŠÍEĪ:ö4Ū8ð-Ũg”Wŋ -ŸŌĄB аŊ”1p@MZu~ŊÕ˘ŠŠ–ŊÆPQ”‚cSJ"­f 4 bqÞšËĩíÅ`LËĮ'ĮÖJ.v0ŪuÛ Ž[üߊ,bÞĪ}„,jAtĐÕŅŅų}pô%€ūþ .UĨŋ·`MŠÁЌUĮÁ·ûž6―FÓnžBjôŒXūduÍēÆ2íð}gw"jūï€ūîiðJÄąōšÎ·  ízÏó‰Ž0yõŸĮŊG+ÆQŌïˆþĩ˜ŽŽDvþoŊjü*Ú1ŧ„ošÞŽ áŧ܈[`dbí  āáˆņ/Ï=g\Š'Ô.å펝Ο‚.ĩ:::ˆAđî\ŋŸAĸRÛíëŨ2L*‚ĸũĖzpãÎģ"AŒUL(xŒĸËĩ›…6BøkáąÝųåz–I|s %XÁüsPüį6UÐĨVGG‡ãø›,ķåļøí@āœė}›jbĸ^k!ÃáC3_þ ĮƒĢ F­>™*pčÃ<(ž8iøâËũE†ų5Đey?wŌ Ũ †gČ―ļwЄ―&!øÏA—Z Pž\XŽáÝ^ī08x:v9;ž œĢwoā9dtņ͘€ūýč˜`XdtõÆ (`Ēë4­ZÆKÅTóŌā°ØËrB$<óķX3œfN…Ĩ1B„Ų5›KÉ ­ëT40Z=År‹XŽg™bŊâøęRŦĢĢóWąE7.Z·NãuŸ\ayþųåã[5Đ_ŊÁÄåĮސ7Ĩž[·aíŠyƒYĶðč›į%$Õ>nÖĐ ôæ―ˆ‡į>鞐ØvðĀ­§ó A@ rŌ L"ÃØNî]PŋAƒz―ßŋ•#kÚJ)âÛóŦýF.øæAá ĩ…ˆGĘĐ-Ã&ÖëÓsåÓ\Y08<øÁž}ŲėþC&Ū)0[ā‚Ė[ĮŽÚ–avņŋq|íĒ―'YˆOnŲĻ~ýN}įĨ™Ë@]juttþZpÎĖųý;/ÐøA͜6LÝðÄĶJ2?xōâ5s[žX―üŧë&jyū}ņž]9eŧtowũÐĒé2cqJy/Ŝũæ]õųũ݇.)óÞäIjYĄ„ĐĶwŨÏė=žjAį'žŋđóøų+FĪ)!ō9įÖĖņ}Øāļ’ÞÅßYq<šþ鯉+õžąīsĖ‡OYAP ŸlY4ĸĢĒčΝS”g§žäæá~|ëΓŋī^ ’Hqg/WJ€{éæ5ĢVΙ}øü]Âó€qc‹.ŒŌåŧœöŦ&ôvC ĄđÆķŸîތíÜĄCƒ*MÞë]­ziIąUôĐŨiĮô‘u+—ä8—ŽÞĄ!·ïoß=øáļ Vė\Ŋg·ēŌŊn™7ïøų_róMęRŦĢĢó—BĨ>ېE)08áœ9SG§rĄÝÚ·ô €Øņ4 ŒĶŠX”G*…@)Č7K2€āŽHūĻĻ€*æüž„R8—ššxËĘŅ­|0iã‰ŦˆÔ3°FÝø§éOÝČ`yž‹ŲjUĀĶ<ģɄ $xŲģcJÁ ĒÂwíŌ)ïøîé+?-ŨļAd +ĩŲËVëØŧߎå›g ieÄĒ$Ë*ĄšÔęččüUĀēÕdąQĮĻģE–ą\˜•*šóŌî\+|zĸâŨ-’l1[0!”ęĪT_Ū^ļvýŒ>Ģ_ū 0&aUZ€/ÆÏZēlþ°U§n˜‘ĶēÍ"aDsŪn=ðĨ N ŲTāÝ}āĒU}ýšũôŅđĮ BŽé]BÕJ5ŋ=šöŠ5ã',8õóS–å)VĖf+vč&%ÔbU°ĒzWmӄ―đïÛŧÉ-0։oå~óęų+O ēÓî>K S§ôkŋįlšÁĀęRŦĢĢóįƒĨlōāÁ-ŠļE49wpgÐīkkށWí\R šų5†ôęčDYĐÔaÆÚĩĢa^fĨc6ïÚZ)ĀP,‚D•Ë4Ų°þƒŅnӖmÛTPZ·ŨԎUTƒ·3(ž|íqŸņ+5ŽĶŪåÆïQ2Ð―Ã°e;F'ŦĐļۀ,ƒč&ývÍîáZ˜[1iÐÞ―ËbƒŒŪáĩ†ôėčo$XQ<ĒÚOŅĖU…xõÛ°yÏúyĩÂ]dYKę°íÐäúô—ۏ …œ“wģv]Š„đ+ :úsutt0ÆĄ5RJ"Jē!°R·HEŊŠ­&Tk4TQI‰pÆŅX€`ŽŅz@ÍÖ/ÝeI!8 * ŊÖxZõÆŊG|KjÅÆ–EÕģĸąŊÛ,ÚķUeQĒ\ŦŪÃχ QÐĒSŋāķ  |ËZvŒąSp\—’@eBp‰ļfĨŦØ·EQpXåķãâÚ‘d5đcĒĘēŠK­ŽŽÎ_­áÁۍˆfy Ž*ã ^óëČ/‹"~3ÞËÝ·ûžÛLjXųŋ­Ôĸ=;Fu((:ExîĮý/Āí‚čü:铐ũÏéėDáĒĖó&_–sNc1ޕZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ€GðûÎ9{ïāî·H-ßr]ŨĢũ·ÆZŦ”Ÿ‡Ô’™ĩÖÖZüķ™éĪ_KĀX @jĪАZĐ@jĪАZ€?öî<<ŠęŽĸįœ{g&Ëd™LBö=„,ė‚ k4. U[ÅęÏZ•"u)T@wÐĐZŦUŦEmݐMA@Ö@X kBBVČ>IfæÞ{Îų|ï3ŅßómŸLˆUû…éyý™;į9gnîû~ÎđæL€R!āHÄÎačcųáÃ$„PJ}à LÂGFm ‘ššš:;;―^ïđđ5‰Ē(!!!aaaVŦĩ—Bc.—ËįüžŧÛŲívsĪp6555æ)CĀÜy.666))ÉbąÎeÔĘzÖ Ķ–––ððp§ÓI977looojj2Ŋ@J)øÁ9onn€˜˜ó*=ïęŲĄþ"†ŌÐÐPYY™šš…­y ĐŠŠ*//ïßŋ?ĨTF­ Ė3sÖžn…?<đĐ €Ÿ}ï>B)éã|Ųfģ™_mm­ĶifŅŨã[!æŦšŪ'''ŦЊˆĸņA!~$Ýãgopppũé0Ģķ—[ĢYϚ9›––Ęūų đcĮóÞcþ …­|,&ŦZŊŨkÎ[Ϛģø-ĸ‹Ą„ ÓŠÜ―ũ`‹Û ĪũÖØéښÖNƒÐģŊ­"ĒÕĮ0 ð1―/21œ =―čnmĻ;Ý}ĻIŸŽģ―3m^JŒ†šš6ëåMBóD˜§Ģ—– !­­­ņņņp6ˆÂ„ðÆŠōęĶNø‘ ÖY~üd—!ôŪÖã5S/w!„ĶiSķËĻ•‘ŌKíž%ŊŌØntwïûāo,˜õÚŠÝp6Ė0žë酚'ļ{ÉÛßķ€m;gßņXi%ïØđöķyˏzúþ„P. H‚sîĸę%@ÍŌŽū‹D]˜Û|ĶþØÖUĮ+uÃeáŠĒŠ EÁ ÆĀ™Ššôė‰ŨOÉ7  U(AÁã Ļ*rƘ?œ3$ ÁhþbÃîüņ“3íLgé%bÎZã "ũņwÏh<ųÍĶŌ3#/-ŽÅæfbáœq*Ė.QBgL‚!(€ ÅbĄ|#@ĐĒĻ ņŒgę6ė­=aLl0j†øŪ_DxOïØĩïĻŧ~`~fnb.ĻA‚ČXw5Íör"úø€ž1=#Њ•ŧWWØoøÅļä’u+_}ä–/žúÎŨ…Đ‚|8c Š*tœ üĸĸSpΊP―nbh  ĸŨa@ˆŠ(ðŠŊ^{ï›øßßw5pÎū GĒĻJݖwŸ{ņå°lęõ#m ļíVģyû…éAæįĢøn (āČĻ•…­ĸB $ŽäüŅĢģD~ZÔ{ĸÜyäÔ°iae;7–?Ũüø “;Öŧ<õ›VEÂČ ëŪŊv6j<<ŪĸĔG(îŌÍŧlY#&ŲģĨؚUc ”č%›ū.=pžŠŅ3~âļė$Ņũ’Öß@„ĸF4ĢģËęLHLʎËAÎ ÆžŪ3[ŋÚvšƒ%įÍ@_Č;ęŋÜüU}Ķ }an2ĨĒŠŽdįþãL`úˆqĄ5;ö–Ô55V,˜8<Ó!„Ŋ&UԆÃŧZHT\˜kŨĄŠĖ؁ŠÂŧD.8ŠnØKĸð—hĒP‚F^qåĩųW^{ÃU—,žlÚŌ/ĶNļf°åÍGįŋ·ũDúåӟžkr(Ņŋ^ņōŌ·W{ƒė<ĸژëÎO^[ðʧÉN~dÖé‘Ļ dBSŧWÎ{ęWpŌÏ=1*=ŠđÛ?zkᛟÕėé3fM]ņÔsíÔJË+ž|äÎ §Õw#ĄŠŌđô/ũ[ä.ýęģ­'ï*JįœĢ‰›…āœ3.ļŒZĩĸSð;~ĒL‚éšæåHc’2ģúmïr{N–îÚxĻ}Ōļa6lÜĪ„^<,ÞĒkBZBĪĄ·‡ĮČrxŨŽ- é—^”­œ8z,Ô1hP‚åLų7õĄQđaūY8:bœÁÁĩ iĐÎ0‹āü\`”Ō~Û@ Îôûūũß|kô„ņ#ōӂˆöõꏛ"ōG RŨoÚJ‰oČ­>]SÚtŪūyËŠČø;ĩ_ŊÚX;°p`|ˆ5,˜D8BBŧRģēûEÚ8ū^EīîŲߐ4ė’xdÝΒÓ H A߈ÐôÝŠ {đüāo #„ Ļ{Ühx5°æ.ŧŠĨĐéãWĸüveÐüy3—Í_øjræĖQ]ýöĨ‚g_š!#ÂĘ>yþžÅ{æ.ŧkŅCs_čũ·W"UԎō­wÝûâļĪW}ķpÞēW^~xĸۏÎ|Ĩâ‘yũ§aJ”chLøîÔþ7þl‚Ócˆ XÔķĢ;JĘB^þbųēWŪ[5uÂĖ Čį(ū\_ÔĘ/d’Q üÏŧýWĩ |ĨũĨgãĖSQvļĢĄæī FSc +JtØ!8­ēÓë"ŽÐÖšÆJŅ7/§… ˆJ‘Á}™Hã3’ėĄ'SsóĢCÁāž—™ucˆsîũBÂ_|å5ŽÝŧönüĻķųŌˆڏœr‡evÖ5°ŪĶæÆ3MÁ”˜ô–ÚšŽ6jí8ÝĖ<^­đ­ĩųdË–sá0+ŠÐvOŋð0wzVNB8a\ø‚ÖŌZ^VÛޜĻrÝ#i(=ژ4Ė)ū X4ýHU-c ü"H93LHÐЁjގš’õ+=ž‹ūÜļģ­Ývüā1ÏøžŽĪ°}ŦVįÜð‹_†{_oãąēũŦ'*kķv•īÏ+FDBôō=öT4%ÞÕ\^ąm{õąŠcÛ>ü|ę-Ëoŋn‚čō€Ē5ŌqĶßøqƒƒÜ]šÎĨ|ŨÆĩ]6Ïé-.uՇ_~sŨ-C)Ø=‘`(„Ŋw~ĢVQDYÕéėRhŠˆ€ÜÕ\wŠ5ī Ä֎ÔjģĮÄõ‹đĖá šĮwí Á<ŧVxÜë>,+D­B„ā)ntyt°ûĶč>œ\ÂđDėû31ĮŸ^†jˆ/š|uVĘöŦöV' ĢŠ%"›`ŸrÀ˜ØČÖŧ[r:ãB/Mʍ ށƅ €\0ƒ1_ŽS_·‰•šũ—ðÚb°ąüĄŽKõ7û]ƒ‹Č·KčKŌģD­ĒũÅ^ŠZ.ĪūcīŠ=ĨĮ―ąÎX{-·FÄ$Ķe ČúÍčėüPOžýįMk>^rï]{ĸq˜…ö‹ŠJ‰K0ĸé;sŽLg‘sƒņČðˆÔøĪôA7ŋ3--ŨĄŽ`šĮ02đp{Û F4ƒ[cūęžuÔ~žfMJÞ%wóĖŽŪũĸņåžžņđ`&.}?0ŋQË“QKAúß#ļŅRwŽô›?ĸĮg۝đCģ“ēöwŧšÛŧ„JôÎÎN$Īû Aájsé`EoKc§ŦūķÚ+ĻÂĩÚã7}ūrßĐADũ“k.+ũļŽ:äōę@ü”(…ķ†[ķė(;VQY[§D;ÎÔĄY! § bã^·Ûc C7”ČäŒ(gKEZ‚ļæjņ*ŲŲéý›U›wýfïžoŠĐ5˜īœüæČáf ūBÎÝ\_^Õ:|ė%ŗ]|qņe“†šĘ+ë]ãūđģa„ĸB˜·―tÛŠ|ðÚģógĖųóÕwÝ]<<ŋ`ĘäS'i4"Ėęępwđ[ËWšÓ™—Ū -ęÅŋš2Á8PŲi‰ķŦ gÚóz<^‘Y0aDʙÃUMŅÎȖĶVCqL˜úģ{~ÉïüáĘC'ےērÝ ›ŨŪÞër3B€RĨĒdíĮåņO.Y8cúũ?4wÎä+þôϏÐ4ÃWŲŊöï…$ŦZ ÄedĨÔ6Š<@†Mļ|`Nšðø…—‹―ĨĮ֠𐕛A•~éy6[8ĒuøÄ ÚþŠŠúāQ#óŠ;].Ŋ킱Ãv–Õī†&―(VŒ@TŌrrl+Øėc‡įŠŪĻmMƊ·ÁO[ËÕbélŪÝæXÃŪ(æ?Åŧ}{ŲþPBG&:ôWíB„ŒđžØēmGŲūÅjˋÉJîÁÅB)=ręh9‰L Šŋ`L^y}ECzĶ#(AčóFå$:… áɃ rt•ģ˜ŒlKx(GkVĸ3äþ ĩ"ÉwEę†ÃŸŪ,S,Ö{þôæĨcrMšnöÜæßûÛËHÃŪđ5s`ŠĩaŨį+7éaWOxJķӑû낐g_{ïÐF1jęd6pÄĪ+ôŽxküĀÅÏ,yæo,_ū]Íg>#žøšYO7<ĸéŠũKCRnÉ+,}íE‡>}sã ėīl;EÎm·ßô@^? h€Üzéô'Þ-q“„É—MŠ #A$ûâąöëĸ^Õ*ĢV"&ŋ3tŌ†fĪā#83ų&͖ŒÁeFB@ŒgKL8ӆü,c(@„!ļd@Áĩ9„€o!‚1†#&N@f0 Šr įBüMdšûßËaB`xLƕ?ÏäŒE%‚1ƒQ[äEES€Âđ!ČР4 ÖĻŅ—\…‚ŠtĸÏlIFĶäŒâ[abØĻĒáĪ{i!4:­xR†aBøšĄ„N.†IcĻāĮ‘…7ļĀūQĨ}üLAČč_=9é >šŨ­ë†tÕėŨBđáõ0įíŋÎ)·—˜;nęŧ—܈ PŪuļõâĶi^Ŋ3{ė^ˆ@änGGõ—.š ‘(ÔðļuᜱäÝ{ŅlQũŽįOvïęŌ‘2-ēĸĪEO{<ÚŋÉ3[q…ũå)^óBˆŋ‚ž*}f.[l6[yųÉāā īīÔïĩÓ ĨôäɓQQQAAAįėcßî]ŽÎœ9æï/5 !æ> æ6%Ý+ķg]Õ=‡iđ Bzzšŋþ+ŠēaÆüüüˆˆÆØv[õݕü}„b>3â;ý―í >_ýõāÁƒýĸ―øyCUÕãĮO bJJ’ŪēŠý…ˆvŧ―――Ýâs.oÅÂ3ï(―ßoE1 =7…2 Ãår™§Ģ—ž#Ēđ™ŽđKnnnppp@N°t]7ũŧ0Ïfũ~r!@ČĻíŪ8įþŽųo^iþJƒČČČ^ö7@D3^‡9ë2kÛĸþ@~øE1ÓÓ<―ôSaÖžĮŽÛđs'įI’"ãĀ8 Âų…R°(D!@ˆŒZI Dˆ›ŧD}ks Žp~ R!.L Sė6b’Q+I‚âõzŦŠŠÚÚÚ Ã8ũ{ßc1_ÎĻî8ÚÐÕЁóŠã#Ô!)‘éŅVŧ•"ĢV’‚ĒēēŌbąŒ3&<<üÜïm}}ýáÇUU‹‹BüKtPÞä=ZÛî·Έ ķYΈ­îōÚĶýUm!6g°ƒX‚2j%)čšÞÚÚZTTdģŲ·ĨLš˜˜höųĉ ĸĩ@ CUÍ:ĩ701”úO*bĒ”’îˆC!"|„R‚>ð#!íšT6îāIŠUDĩį?Iâ>}ÉYái;~ēÚËHXDŋø„č` ŋÐÛŲŲåöpjq8gƒ‡·lr% +H„>p:ĨĨĨ=ÎŪ †^C„„E†ĻaAzåik8Q}IPtŋؘ˜…ĀũÁŧÚ:,aáV…ˆ€#<”c‹Ũ@ŽôXL’$!DïÅ! 'w,~pÞGÛĢ#ާOũžü—{/ˆ=-ږ?þāšCMvKgtöĨ͙žÕÏÞkû|ÝLJķþęõĪGöĨHėK-)z9†ú–Uï<ûÄK§ ØęåŠý؇ï_’bë―UBˆ§ĢĨ˰:vÂjžļãÁ Ïž~iFâVÕ  ·—ĪĀ.oĄg―§žšņÚí17ū·jnĸ(Øŋm3Ī8į !(8H…ĻĒrÏÖ=_EOúÝý#ųm·Þĸ—‹nËCDJ}o@ Bp!€P‹…§*i*˜š$„ô’wBˆģfąāBðëBTTKãÕÓ§Þ;xæō/æ^ŊxJwîKé~įE!\ß œ!Q(AEQKžYļÄQīâū)TD^=ýöD§Âđâû RŠ  „ DBšP(åŒU|ã=ŒúvP(dÔJRBƘŸåQĩîāïÖ;ĸúÚžAɆÁ ŠŊĖāˆ'|ņÂӋKNiņycžĸŧĄą!\ PP…P5=+{Ôļäܜt5XíŽ?ō›ßýäþ:#qÐÄß͟;,üýũO”QÚzxíĶúœyKžŋ6Ãĩ|õĮŦj6OÛģîĄgæė[û™·ĸ8ĨlÅĒÕu™PĸÎĘuĶÜģdÞôð–]/Ü2óĐû2ėÚ?Ÿ™Õ8úŅ{ÆÅnúāOK—üĢÆ‘þĀ‚EŨ Oā‚COQ˅@ĩ’˜„ŋŧššq1‰á†ŨĢsā‚Q,ފNšųÁ‹–=rëížēþĩYaŠ U” ïū~Į‡Ŧlãŧô―íäŋ]œž,―þŠVޔw{ĖãwÞ^=xڛģ§RÛŽ^NÂO>?ãéŪ)Ŋå隁þŦÚ>-2BôĩČYG§gÐÐaÁDÓu`0‹Õsü73įG^5įË –üö–iūņÕ[·Õ—mĸû7lþŦŊöéþŋ~ōåĩ]SœŸÕxáåsf_—Ōĩm˖čÛYFGí‡xnüŊįþqéėYũ>ĩýæ[Šiý֒’[™‚W•íŊĀđ{Á‹Þ{?rëüž0öÓ§Ē•žúF…ðeÔJRVĩšŪkš=Ą Ũ5Î Ķy5ƒ2E5Þ|r>uJŋ§ÜņĸâēhgĖÝ7M^}į–-îA‘„Ū sáp&ŒĖĐ^đæoŸî˜sqÜŠËũ•5ÕVwMЛO5n+ ýėŊrãíz †Šë―Gnģ§_õî[3ÄëÕD/ Œąģ.Ôę†á§B™Átáö˜CÖĶq$– ĨæĀķ#yöϋĒǜ3nšâó™_WtÜčâ|ęoŧi܈uœ_Mį–čī(k\j|,ŅŽ †ĄkzS|áŊŸ}|F lwŧŧô  4HpÝėƒ”Rķwã‡íuĩœ3tuĐg:ĩˆ`Áą‡ŠVӐsŽēЕ΀ŒÚ^ŠZnŠm­Ŧþ`ÓþGŪĪÔïÛŅ5֖cqŧęë[”Áą§ëŠ;,V+\A„‰s>xâ„i7ŠZõũŋ~š1ąōøÎÖøĮÞöÖCU@Āj Q]•Õ5Ɛ<Ķŧ1„<þڛÛķþõÏoZ0ý:Ŧðp ä?^@€î!õÜShjBüæe6ü?ŋ:?NĖÝŅÂCĢ­mõ§ÛÕŅ ĩ՝AV  Ý­ëšÁU…ā†Ą5ķuqB)ˆ€ÂĪĩa/ÓÜđāF—g_S§Hl:ļ§Ī#þ*tÄĨXÂ[ïœŧpPTUŽQÖóę!Ðß…óœ$Iˆ"ĶĸÅËgykÁŽû}úÅ%/Ū;XŦ=aČåÅÎW^|üđg{dųŽÜ[nH·ŦŧuM[óöKÞũĮ•WOá°`ó‰ý+?z·âhÝî ›OÓŽ™3Gūûôœđ‹ž^žtŲąFy<áCnz~þý^›ņØËŨˆE!ðÓ@]XFNūõÎAÍÓoþøs/žðÜâßÎ\pLɛRąėŲ…Ï?ģpîŦ%Cn›šB ·›ášĮĢ3ÁH|nöĄŋūžė\œĒŨ-@(îÝWˆ óx.ÐæĖHąw―°čŅ<ąŧą^čzÆESĮ ÓßXōúę5―·âó6N(ôNVĩ’pČwĀĄ]qũēÔüĩÛUtļáæ‡ŒĪcðŽđÏį­ûžēÁuëÜgŠ ‡(‚#!€ÂK"fĸ~iåЍáSWN5rhOįĶf4ïýŦí­‚L™ņBD֚ōš›35&,xŌ]‹/ˆŠHΞïÕ7‡ŽópðÓ#ĸ]íóaÜPYó_xŋxýÚý5ÍÄÖŊpō„ÜÄļ1ó–ö_ģŪĶąsÚüįŠĮ Ö<Æõ>Nr˜Į3čú‡g“Ūŧģ‹įüáĨ|Šą3?ݏFØo|úaDļPbï}ō™˜8‹’ąôųūØ}"å–_ÞA[ĩ˜(=4rŲēåŸķĄĶËHÉLU =îFæ{EFíĸ$IBÁ4égC&"P…2M3ļ6Į•Ũ݌đĶëš!ÛĻÂâB•g†ĶéJxĘ57ÝN€pƆŋPŨ4ŽtŌ”ĐE„ĒĶyéðI”ë^·žb…ŽØ`—;âhCg]yóŠBD|ļ:45ē_˜ĒP‚ī€ IįÜ0 D2s­UUÝ}ýÝ]Uk­Ė| ÝYx.ėęIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-settings-network.png0100777000000000000000000002063713761647206021742 0ustar00‰PNG  IHDR|iĻ"cÐPLTEßßßķķķqqqYYY‰‰‰ĸĸĸðððņōōœœœđđđĖÍŅQQQÚÛݖ––žžžīīīķķķēēēqqq™™™‹‹‹āāāóó󑑑   ÎÎÎeeeËËËūĀÆĢĢĢýýüŧŧŧŅŅŅ­­­ĒĨŦoooØŲÜÞÞÞūūūĶĶĶ]^^ŊŊŊââⓓ“ėíïŨŨŨÓÓÓÚÚÚÄÄÄÕÕÕõõõÁÂÂŠŠŠėėėĻĻĻÜÜÜįįįÉÉÉĮĮĮTTTåäåíðņ``attséééĀĀĀŅØÝĨĻŊlmmäðôÍÕÚÆÔÖāæëvĢÅúúúĸóÜ:™ÆƒÎâ\ÔôØÞãÕÜāĮ§óúüæéíߘ‡úĸĸíĸĸŪŅāõĸĸ]V‚ĪŊÍÖįïōÔÏę͚‚™ÁÚîų_j”Œy€ĘæņĐĐ―ŌšŽvvwĸúîÅŨįŊĮŲýîÎÜ̚­Đļ\K­A1͔‰XW]>ąÛ~QD·ŨæþøåõïãC:=ŸžĻPMvßĸþĸčžÅšļæÐī|{€ÐÝéēīŋÜÄŪwƒŽlZUžD/Yg̨ɟМ•ÐtY306ÃÍāėãÕŲŲÉÏÄđpŠŊÍŧĻšĻ—lnCUq\C]Ŧ€ZtHBČX?Æā·ūĘčØÁ|”˜MUˆąœ‚ĪĶ~Wh|”vh”jUæũþäÞÖĒÂЎē˃œŊ—™ŽŊžĪ•žÍ„yc\rŧ–q:CjG=Y85R~`QÐ`MFJJÉA)ęúíîäđŊ퐄†„ÝŒ{Ѝp…pjydfžn^ĨcSZ?Ez‚Ąkx‡ÚqõōŨĀÉÔI`ƒdNHŒ·ÛÏÅ×ķūŨŨļ·ģϟ“ÅîþŋßðąŋŨņëŌąļŅõâĮŨÍĜĶūŪ›ēM€­ōϙåŧ†Ĩ€{―ĮĨũÚĄššt‹qzTX^9/áóÛēËŋHg˜˜Óõū―ôŠÍóÕÔęg}ĶÂ|rʛc~ūôŪÎh˜ļLuvˆqœhE|NŸĻĪŅUˆ–?ŋ|CT Xþˆ…œvģbĶ`–`î@ž`đxå˗·óĪ@ŲēiB’$ŧ―žŦ`0Tá18(’Xė;â äd fÂŽ˜SÎ#îÎ[īŦhH Æ7ŽÖĻíÎĖƋŊĪū ”M™Ų••/ïR†,Ęŋb˜Ž•Ч‡,T„UŒ•+PQFVjVēdiyZ^ÞžX™YFĢҠ˘9C^mÚīÉDig 8å2gΠÕĶM–šý>Y \ŠąŠ°lƒ§įĨ‚t†A!g’uրvž&ƒ‡ė(TPŨ)~<6ũaō2vÁBæž%=ųƒQz"ÏCųū, ŽŸčs~<= íQ?/ę?ņ‡€?Ô_ ŋx~HČräøŒų}>_:ė;ī|ÉĨ]/…Ų‘›`)ĸ}ž`üĻO‡žÚŦO=$ė)>8 >™}Äg_ÃņáęCTŸŽŋŽß―%ŋ˜ž‚"Ž>čS~Ô§Ã/ë|ŦōWũ.Ŧžđ<Ėčá ūåž­ķũOœ)o’rþ{[EėĄvƒ I’5wž…ļ]ĸ[·îÜđ}ēī]ŦqąĄįðōÅFū!Ū4ü °ļe} § ‡ŌSy„ĮÉWÁĮҧú"ø*ģújþōðŦN?Įwŧ  qqÆrMA^Ÿ ū{ũ˜ð>ŅvGõęyrÜ?[ΚøÎ2?[ÛC‹6ž›/ó{‹iŒŋâ+^ŨO_X|áÃï‘õíÄ> ―ŌžŌŦá#"Á'útí‹sĘĩúČŊréĨW^‚ïŨ؊@y9=þ\pŪýŪ{xëDĘĪ+j˜·.hųA%ūŪÂÉʕ+Ũ›:p‹†ãž;'íŒiÜzôŪ…Ģ'-rķߟ_Žŋ‰ë3|;Ø#<.U{:ö"ø*ĢŊŪįðb-f_ ›‡ ?ęóčîŅAĄúî6đīüzkœ?/ÜöūCGÖ`ÖÖāÎĐӕē ęļ~2ļ#oį5%ū~ڃ^šÓðYō|ðwŒeKæðŌ,ÓÆ]{ŽóđiíŦôé“ĨUeįą\ŽL…úd<ĢÏũĄyŅ·ĘĢ=ā“}ņ@Šøx0T?ŠôÝãn“Eün[ââüZðyĸjâŽ-NũÐgũQ|ïS†2}ģÛ/ŸegøĶņƒî=ЌyÎņ Ũ&ôxŧhŨęÜŦïdîÞžO'ó#_Rĩwð€^Å>Dņy Dœ}#ÕI%>Õ?Č6Ž}Їūwú5:~ąīüķ‚qâæ°ũ;ƒ“?…ĩ#YēŦ ÉüïŲíÁĸÞnŸĨŸzįž/OõJ·_ū40|ŦsÜÜļ‹FŒqäíĄŅOŠføÍGÏÛóúQĄIÍ=þjV2ųBBzčĸFðQ?úâŅ­OņÅÄW~\ý*ïđÜ~[ęðĮ6Äí˜:ÐŌ];ßw€Ķð:ėÚՁ}Į~?ƒî…ėüTųO|ž}ûîī‘wOÆņÉϔ|ˊeŲUvīŒŋgô.†ïœÛžĘ˜ĩ“›,ūóĨlęŦŠ>ô…áÓí­ŠOÁĮ38û*ãÏ"ŧGčĢŋe‹ÞëõfWæõÚvÝÛ §íøŪ:•;ßÚōÓĮÛ·oW­žÉĖð_ŪXf΍yŦ+>3í:pdå„ė[ ūv*šoî·XŊvČ[*ÜõŅíačSs{ņ#„ˆ_™aœcōVKEß_Bf?š>Ų=ĘáįþĢ1[ĶðúLjįƒęDČmfQā; öûôņåËÛÍ /3ÃK͌=Ķ“1uŦĘczL;ÝcZûý}؅6ÓéņĐ·7/˜ŽĮ4ņbG’ÔėqŲG{`Gyü(Ŋ7UßjŅSFqĐ@}5þˆ›_Ðs|IĘÛ&GŽŠ!å0_›Ļ3m2īvXAŧĀįkŧˆūf•…c_ÞđŽ“ŅÃôņ=Æîģ4ãūðÅÆ—$ōÂw=Ā+čĐž@ĮÉG|ĒOðĢë+Ž…á“ŲGō™ðÓÝ#’LųŋĨa™$IākX­!‡ŲįŊhÞâ€O€Ÿ|<~‡yOr —_ęāÔĢ=ĨGû,Ę‹Ž §“úQßjáÚW{ŦEõņãújËĮ_íe$0œ&<ų#4ÄgéseÉUĖV,—-•îpEnÜôúˆöļëAžŒ=ØAz\øņĢ-ˆęÓSâ.Ų…gP_ą|ēåC†øuˆ/Âg%°ÃĄO@0OãĩašˆÉŋ)ų§˜ =ę5‚OÕŊđ_ý`ŽB|:üĒ0~Ôį!>ęŦŊ€DX/yĪ>;:,ÕĪ˜ģ‘@D%ÕcČHĒ„duG– ũÓė,ûDŌĀ·“ÅúĢL2ū)M’XīēÖþ·Ãĸ—Šáĸ(ū%†ĸGC|g ?j1üĐēĶø9 |gé’Äú!|†āgÏôy“Äúeø‰ŋŊęËž?œ-ÉĸÛŊÁũþáē'ųûEøIīÂĸóÆúAüŪKÛÆð/~ïkj_R—ÝĘZŦi}%~õ”øB°ÛaÉÞ/ iAÍQ•óÉ·C‹áŦâŊØ~įԐëà 7>™ðüT·ģ―N7ękxķņðøŒþzÖFü|PßÝ5o”/ŽĒãNŌHūú`úØÎgø:]üg m>lŲ1—IÍ/6:čÖ°‹“Ï{4ŊyĸæõęËøŲ‹B}{6Ú4ņÄôĩëĮ]qpýÔékW/Ū:iýÍgž|ļ9nũę…ã·ŊxÞpčîՋø/Đ GbøęøŨ/Ėn°vDũ5Sk5­=éŲæ―ËZ™iõÞz5æļĪįø% ūĖ:ðnîĀņe.ŊŠWkÕ ąĘĖ^―ð•ą­g|ĻքIŠlÛ2ņųŽUWæė?ÞŽ$áŦâũÚīöĀö‡|į­}ĸ@•/ėÛHQĀņĸ^?4Œ ú)œGÔíķۆ­]QŲĨ+Ļ jģ@·:ŽŠŽkJŋ”&̚s[TÛ2+'Ēsþ`IS*Ese?XVĶeDŽŌ~õGïfzģ,Aū/·qƒýõáņāÞ{wÅŲŽóĩéĻVk[ 6ĸÄß' Ķgįš‹›/FÎ,k·'ë;ÍMÍķÚ9ū^—ĒŊč1ž%ėâ™ÕĩSœËd\K~č9ŸÃÏté―—Ė™‡;_3štëëJë%ũ-ÄW•kŌ⋂AáróӋF‘ˆą's#?WË―ÞF…Qázl{zž"ÂtČaQ‰ļþ@ø ?JL2]‚a%Fc4 h‰Þƒß?ņ‰`‡ RÄåæ Wûƒ[Ĩo0žxØičr8Ģw_w°î&‡Sčp2ŽÁ|†5Ž\ þPēö ûĨ°§Õ"„ÏáO >ÞŊã["ðA…ð‡Œ?Nú·áû&ŒķĮëīƒÅĒÝōŲØoðQa+á:„ĸ?…ðÂĸŸ /FøĄ!üh„æøøqqĪâü^ü8„ēˆ?Ÿ4 —TØðá;Y áëĸ!ðLŒ!ˆ˜‰KŨÞuJl †ëŏŠâ㏍ÃgåÔ/ĮĢĶÃXĀ}’;ī€FüĻĻņ ųMąßuH.âðđ~ˆÏ4čēĶŊ]X˜ōîlqUƒNĨŊKgœžį{øęŊð‰PøQïĸļĶ;‡ņÓŽŊīՖįŋ h6YW°ÏķŸxŲvýęYۇÍmþû]ëęŊņ—ôĮįtýÚ]‚GũâßĐ--ĨćNM HŒÃg6Š·k3ŽË°€ÕŦËÂą'õu›ĘWm`ęÎÔ㠂øÎÃ4ERðĒAŸxG7aīĩMųŽ/ˆÄôRxŪ‰žŽŪíGÝEhøhyßHā‹’’~˜ã㠓’þČ_*EøáŽ/•~Į"ü°ĮĮ'8|’DøaŽ/–’„âã“ŋ§ãq<žĻ°á‹ ūŒ$Å||‰€Äq* éĸ|:*ZKD ‚ú­EėĨ“ā{ؚ,ð­ÖfÂ+#Z‚čƒO|Į§(>ūŒÆF$GL į\:;ŸœïËØqДp[ïvĶ„[­óóķ™6*ÁžIy3T§oėŦĖOØXđãæę)ąĘÓŨ”āN^éÖÖ–Ō­U õ“ę›b™fdfä'”nÝ?Ģ$ŒĘúāSԀørql/FØáO~€Þf_7ĖŌ>ŽxßbËŦŊv?ۘV– ē―NđÝ|O_VR{AqÄTŨ\°āĩN—ęč* AíØšðÐ(,—Љ/ĻÂ7(•R„ᘸJĨá'$&ū\­ĶņÕj{L|ÄŨãaņ1ĄB!Ä*.øSä8Ū§ņq9ß"Ņ6nŽUZ@]xí Š*›ßD/lЅoPĐh|•Љ‰ĩę&MÔ&`“3`Á)ËÜfäü'ŪfL2O+-/ËÉT|RĨ2Lųß`Â;Ĩ7IŨ™ô4ōŽÖ/{æ”ĻGi %jsˆŒ5n†øYĒŪ‘Kðҁá˜^a°y 6€ðQÂÜė‘—āð] Į 5p|8iÃHüæ|uÛĢėaƒāÎQ6ę'$Å՞šøzŽÆŨ阸"ęF–TŠ–Hhü6™ŋlúvīã@ŲÚ!į^lĶŪÞ/î˜{â[‹zåŪ9īoõó­ÓOŽģiŲąm[_=Úä•Į:.\2―Wæä}Cū~ģtāø _Ï·Ũö ũ­žđŧãđóc–Ɇ;Ũ^<60ũlRüĻ…/•’ūTŠgāũWuę!':Æßņņ@·ņ囧ÏZļöęÜėB ĸ`îŨũ›)üõÖ­6đwÝQūnÍvøĨ7oáCV[‹ÎO;^ļÉuūø|hžëÞx îÁ&į>ŧ[―ó~öõÓ>'ÅEæšøĪ@ŠŊ)Ĩ„GŠÕUkû―ĖKã 3CGįS7Ī þîÃkŨ/Î.„ø“Æų‹>ĀW eßÛ4įČūóöā—ėŦÔClÖIë§žČQ…ôEņ―ņSÆMû\ũdϜLï,Ė,ūŸ―þ‹$#>ņ‰pøŠÍĪÔmÄžOŽsĮęÞ;—Æ?4ĪwîÆã‹öPøE§Û>īČqfĸÂýïg>\}Íŋõ. x|cÚŅ-“NOþĸüéÆĒN?Ų ņÜųeŅ§w=‡Ú1)9ņå4ū@ĀÄŌÖj’Ā[ U~ČüĪ/mƒē"Ã_Á[™ķ!LKŲPē[‹öžÉËý܎[^ϧõ5eâYÞ/GïĢūd·æų+4Js0mëÝüËĐJōė–•i9yö lƒ>Š\iö(“âŪn-|ų|’‰‘ýSSû RÖ+ŋī―] L–ģö$ųËukâŅâËåätyYžņŸ=„ÏĨ˜øô.sL|ú ·ĐJk’ 7;JDˉĩĶZ~ó–Ý>ģxâ·éŲĨKŸ^ šöėÝ^†ðãŋE‡& ŋ=ÂO@L|-ÄoðãŋUÂOPLüV?AąãwFøņ‰ß“ÂïC|‹^ʑô`íϰ$Ÿė/•s"•VXKĮŲÓÉĨ$#áw%ū6äDÂô:ðM<ö4ļøG"! üÔØáŦ„gÁ‡5ՅqxŲĄįv‚>·ĢNę…ÏŒ]Ŧ]p}—ÏvęņKVĖņýŒũŋĖ/æôĐæ_áK~”SüČéÅš™ï˜óųŋŪ>—Šß áŨÂįR?ú>—BøŅ‡ðŋģwĮ(ŽQEc)Õ6B‘Ā ƒÂ^ĄũŋĒĶ݉Ëŋ~QŅ ũ.ádRõœŋ?ðŋ?ðŋ?ðŋ?ðŋ?ðŋ?ðŋ?ðŋ?ðŋ?ðŋ?ð_^ĸüjā;UÅĸÁŊūSāKËņïā7ß)ðĩåøøē"þū͈?‚ß |§ üüVā;õ‚ĸw\– ø’"þuŋøN―âÏÓūψNwð%EüÛ>ā‹Šø'øĀwŠĀ?~ņðü|Mĸĸv\ÁÏSāøŠJüu›ÁņWð5åø ŨŦïTĸą,ā ø·ŸUÐ ü$ þ ~% þ~-þå?I€ŋŸ7ð+IððŦ)ðïĮ~-þļ Ð *ņoë:?ņ7ðkIðŨíøI ü/ðøøē"þö‹ŋ‚_ |§Āï|§ĀŨ–ãāˊøøĀwę ĸ ūΈ?ïā·ß)ðÅåø;øĀw |m9þ ~+ð*ņÏņ_Q‰_VŽÏŪĪŋøN•øøĀw |mųÓŽā ‹øwð5EüüVā;Uâ/ā7ß)ðÕåøðóĀw üþĀwŠĀžøwðëïøęō‘ē'þ~5ðŠâž―P |§Þ‡)ÁÏßĐWüüfā;UĶž€/)þX_Rž4ū°xc |U9>ïj**ņgð•ÅUPðeÅUPðEEü|Yq|Ių<ße?Iŋƒ/(l#‚/+âÏā‹Šø+ø’rüā')ðOðEüøy|vē’øøÕĀwЊ?_ |§ĀWŨÆ€_|§ĀWŨþ―ð`]P8F_YĶdý?|§Jü |]ŸŽ<ðŋ?ð*ðð[ïT‰€ß|§ÞðŊāįïT9Ï~+ð*ņwðïøýïøßíÝOHÛPĀņęiš-ĶR5CPŠLįŸtëœë ŽÃ­ā?ØÖJCă°Cœ ^ĶuŅš?(CŨ ę†ÔĐxô &XÁvŲ†zņЃ0d ŧÎk^›ĶöuĩŽö}9…žäKō;äō’K>>ƒâGƒâ§’ð͈%ņ/ §F{BüėKČĐ)VŠņ5`ü %rŠ01>ÄG’ÅĸÄ'PüØ øĐ$íã['ĄMô`-NA+0ĄøGzööAÛßęÝf1Xæ4‹â Ú;vjĄítīc<ĩ%W -?ŽŊSĨ{üV%īÖĢøļY ïfh|CzĮŋ MŒĖm3b 7ŸBņĨ^ëõ^wïcwŋ3jü{Æ.―ūŲŪ)PkĄø`|ĢT7ųnú·Ï9åq#ã›Am#cęį­æ0M3HŸJïø ũėۃmōųķ<ŽH6Žãģũ‡]–Ív­|ų9ōg`Ï?;āyģ44° ÅãwÚ$ü>ŊÍÖ62ŨÕh·EŌŒoĐļFžĮĄþÅđ­™ŅVĸ[ÏâĖV‹ĩÄĒø@|ŧ„{Ũnoâļąžf{$b|Āŋ=a2 -xôÜŊîúķÅŪÕ>zrģĨÎ焯ÏJëøNŦÔÔðÚüԘÏ;>üՁ3ŋâhjz\Žé+]=Œŋé)_ {§ZęBΊ P|0ūÔ8Įí~›l/üņ$züĘ ũęélŲJĸr―kųå{neýį™ĸTW BņÁøuЎãgÂËFņÅøĢõÐFƒņKŪĸc|<­ãvė?„ķß1ˆņ ŪZŠa•TŌ(þ‡ũAžŒgĒ)­1ĢøGŒ q0bÖ3ÄĮųøũÓ5þYŌPüXĄøĐ$ŋŠ H?‰Ā Ŧ(ĸ$(~*ãS(~ēéēPü$ãŦƒņË)]"]čHRˆOŠĐËZUĖ4 Š$5•ʐÅ`0ðKÉ^œ”ĢI$Ï.+4Ĩjĩ–S\ԗâEąb†æå‹rÂčA99ų4Cĸ/D—EÞŋJNdų2čÄaâ%…ËPC) įÜ­Ļú_ ‰c}\–pGĖ™Ög@Շk_T–ĄPœã˜"` Č;>įäaS&ðKĶ‹ŒāˆVB&’ðÔQÅ9īDŲy…"S‘1w'I2Ū+C‘ų/ë ĩ†E~îIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-settings-repositories.png0100777000000000000000000002702413761647206022775 0ustar00‰PNG  IHDR|iĻ"cÐýPLTEÁÁÁėėėyyyĸĸĸðððôôõíííÔįĸüüüõũųŲÚÝöööķķ횚›ŽŽŽōóõåņþ°°°ģģģĖÍϝœqqqšššââãŌÓÔęôĸŋÁÆÝėĸ’’’žžž•••ļļļ‹‹‹Đ­ī—˜˜ČČËPPPää厎ŽÕÕÖŅÐÐęęëÝÞáÚÚÚeeeĢĢĢĢĶŽ·šūžžŸĮĮĮïïïŦÆįĢÂčŋŋŋnnnĀÁÂRSS\\\Ą  §ĻĻŨŨŨÎÎŌÃÃÃĨĪĶčččĘĘËųúúėóöÝÝÝ```éņõŅâëāįëŧØãuuuÝÍ·ũĸĸvĢÅÂÅČãîðÅØäĮÜčĖÝįŲÕÆÐĮžhqœŌïũÂáøÆŦÓž˜>ą*ÃIDATxÚė™hQĮÝ8’H’ZjšĪÕībŠĐ[kM8pTˆ"‚qÜ{Õ=ęÞuïũĻļGŁ‚WÅEÁßŧ—ŧwÉw—ģ*"š_ĩūäōĐųÝŋĸ{―æËŸ?_õqÉ”r%?õ&ÚÉųƕ#æóHÖ%ÅaRS……@ETYĶ9)ņ #Á͈%$ ļD’’œ~L”H3V&sIIfØ$d$ ^˜H‰%ļFBžNJ°ŽRķHDĖūKTč{#^—\ ū|Éz—)RЉĮžĩā7i’ĀĶÍЁGÏcĐAIüĪĪĪ8Žˆˆ­VDó”t‹Ūltt ž”Ð6ÄÆd$&FáHIĄĸbPƒbŅS áĪ ÐũgHīÔbɈ_>þpUž[„ņ78§!Üë\AæĐlW0ų$' „z€`Āæfžš˜Č@û1Ô>’OĮaöĐ~äúgö™~ņ=Rų€É XSýōAïÝ[wýŒ=šųtW€ČŸÅE&EËWÎz’rŅ5û•VĀ>rÕ!ÕcųZ”|Ņa|dp)ĖPĸŌč#ûüH„ƒØĮúm~ĸzø…Óoö ?֒Ęņx õšųĩ{ų-"\`ÕšnAŒU·ÖwÉpðÖŽ8œŊ €&ŦAcÓĖ|“‚mڂŒxRÚ Ÿ„?/îõT― ë9ųČ>ŠūLą9d^öôf_/~ŠžŨŋýō―ņą<ūÚ֘ÚYN7!}ÁhĘN^þúĘĢĘŠĩŽ<ÚIĖųŧ@>W7_rŅVyÆ―ûũsŧŨ3E›IčA<―âā‹ý4ü‚{TõļėqÕ3ņĖ―BōˆŽ}˜aŲ—/ | ûذ~î‘ïvņd=}šUËîį‚Ņ;ĨŽ·ÖŪ]úÆDéSRų@óAsįN;XDįÕ@ėÝÆôÕöÔdŨuÏûËdéßԈö“@ū|Ų°z@Ąp(L>*ýÅĢeÅÃÆdækß ? ë—m~$‡ÆF)›U'֗Æ/ûܞļ…pĖϖšĨ‹xũ;KåkŠw?xðāց^ŊŲđOïųTûĪ;qíđ=ŧy‚ëČéûą‰Īx˜zzÔ8ŠągŅWŊ ąã•‚}ÜúðÁæØ–‡f_!üėŌKå+ëŨÄ6L‹Ķø 5}^ēˆ‰™’ģe:ÏTJGGéōî]þGôČÄRų†GũîĩĸļļęđėJNü'ĄdŌ''<ĸîąþÝĖĻ>5™ŽŨ'Íw(å •ïōËĮęqęCšwæŲŅ XäģŊPûšāAĐ}‡šõî‰m˜Mņú|>ĸ2HþŪ„:z/{C°å[Ýŧ·ļ[É2đē+‘ÂÏÜįíâéYwÖØ)/†YüîÄíŲuWĖÍŽn—qĻš}·(ßĪ{=J}ČÂaō™FĻž}Qūš}ŠhŸĘ—/óŧ'@~ŠÏÚī]iAū4ø7īÚ]û-Úë9ĘÉxĸu›ŌE‡ä~˜káŊķ{úöūxļáá•w‹=9/= ?Ãģ?{åîļ­―M8Zú đĸ™Øcų2›vĩoĩčšVËÉû0Bå+„Ÿm;‘}@”ŋÃæ X|>Ŋ99gbNÎūãá|‚5@ŸÎéØųĐ­ŋlÏÓ―Ëœî ĄvŒIÆņ§ēšÂUÖCä7!ōģ=·ģîæzfÔL?zÄhäw›|ð5ĻëUĖ#ņØ>“ˆ“/ŧßD­ĒĘ*‚ę§(ûĮú™·Ũ`­ĖäÛý&NÜ21ËwqŌäsõŋ~ĘÍÍR;ĘN:ĸ‚―îØGûWTË6æ ŧŌj‡ĘQÎ~)ãP5{Æa·ĐpÍŦđĮōĨõģÏ4ēaöņ·Zl* xč†3”}ōgÛN~â?Q§ŦŒđį­Ņ”úüōõSÜųzWýoŸ?|Č-S2ËNvų‡RÓļô”ˆm\zÂĢtGå>]Á…6Ę39ba†+ÂE[‡ė4QáPũĖūĒz&•·ZøiŒŲn_9ûčŒQûĖŋō•WíÓð›LŅ Ŧ3ë@GŽNIt2ųf›~č™ËŲrfUŨÁÝŌúœ éi)ĮÏsņÂFSꞚ§(íëąyėõG^wē/sŌðcö‘~Ē^j7?–1ųH$/@7”(õĀï0ŊýžØ— â)üõâTĘĮ͚~CõcųðzĀ˜$/–ý͊nq·õJæą}@ĨxÐn_ĩöņ#ōRûXŋ^9üä ú4ųÓŊ|ˆwC#ņōŅ9˜X=šu‰ÔŦļÏSï`‘Ę?XQž#í3ý•ægōÕēŊ$ߔhúyÐY1kBcČz„ ĄTՆ4lYT2Ą.Ė $:Eųn6ĖÅbåK óG)–ĸĢ„åĸK„åĸy°|ļ3–ĸGĀōđ°|UÂōĸ%~ƒü ō…þWDųšŸ–W)ęW04-ôŋâ—_.P~Jy !ķāŊ04,ŸÓh$ōãĒJü8Đaų?-ßl–‘ßīpÉ&.,ĸ7Ë/ųãEXþï–_Ļ 0 ―e•‹eߥUĪôū>P\sĒüÚĩÛÝ9ØnŅķ—į/ë,ާ5ËW•_XzāpýųŦČrøãfE$ô^7P\KäŲ8ŊkŊþS,Óz§”ĩī†E·Úm-{<›ú―]=J—Uß3yϙæ“t–ý3-Ó‡å+ÉŊÂË?uúÄü ÏŅq'7ŋ{ø4ûÕšg}ĩŨéŲ”ÓcŸ^îũxˆŒü7.ß3Ų—9{ðÍ#Oy:þԕõVŋūø|ĸî3û]<·ýÎú+™­2}VËÆ°|ųQjKO=o˜yņô„Ėš—GœžvjûŽ&Ũ·/ØoØŅģž;2ZÔĒ%ĩģáíĀ‘û7ī[qaY዆mđþÎĒ“Ý·ŊžŋŒœ—ŪV~ýRŧvÞ,šs0œüBĨŒōōKŨÖt:ģ`G§]Éöą ?nåÓ §žÛĮlZ;{ė•FG74Đã§Đ$ųßŲ7ũ˜ĶŪ0€ĸqĐk­+֎ nš••A3Æ&…m(KQķ ‘–HĨ%XZËĢķ…ī•ˆERyĩ J—”yÉÛ ŅčĖ&Š…A2ÅÄāŋûnÁÖōÚ| ëCóÝsŋsÎ폓ÓÛ{B@QGe~‚Ā"ŸĮĄĪNbŸŸÕæĨV6þŽčŨŌĨŧF°‚ý2ų„EþrōĮOŨŽo˄P|ų–þl“j&'A8@fŒÚ59ÍąTþ%Qlk™<šVæÜՑ•™#ƒJIĩ6ūđU–“ã/ųZiđĩZĐŽīČ_nŲŲïč—=žī6īW74·fĐĒÔãķ犧S7‡ƒnK1FÜ@þ '˜‹æŋņaOîþÐD~Q.s1ؘ•ĸūųy9Šđ’šįĀļ„hĀKOjņŠwØëõ`ģ―€äCözŲS(8låRHbxƒņĪ―Ĩ<'Ęö0c+xžlļā@Cf ^@rī·ŽũĨÛã){}y›)Ð šM;ÕįáūL„É<_&ÏWÃ™Š™‚†ņķ^öĻTw\s!€!žÓF‡)<ļMN›qwüÕ!&Ũ1ˆT )§™pj+Wp$?w!Øļōß7#ŸûC=ÍO“M% ŧēõóōÝ™ėœŠĨeũuS ŧĐŲ’@–MŧũvEÄÚę‚člęŪKÝiCs­`bRƒjģ[ƒ"&;gÐljNÜš^YžÕEUąsjzššÚĄ[Ý`WíŠĒá|MId6ė…]`ŲļÃ=ųīė{Ų\Ž(ž fSmīlBÓÜ5yïVWc―НöõfrųTsņ8ė^Úī?fÔŌ&ŅēëuuTō=Ų|°åï4ʧ˜“ŸöüũØDVĮvVtįÉpųžü]͙>yÓÅJ=­@”_\^UÖ8(ĐMÖ$mĄĘąÖĨ^Vï%o•7FæTĨu+ŸÎ ^ĢHsŠEŨneēƒóŌFûåųšė$—ûIĮ―`Óō$Œ‹&WĢōÃå•ŌĘŦ§ÉJuOZđ_QnžĒv‚h•z>:Oj8ÏúŽdđ ÎÂō5ruđbv°XųīŋSÔ?lÄegų†ŠÐŠûŽūHÐ8a”Ÿz +ísdöËÏYņoV‰ÐRÍ 1ČkŠXÚ vōā―ØÖîú"ų ÔčžØVB›ÝxŊĪ•Ð‹đ†ÔKČkĮœüfä‹―#Äq2Ņ―‰ĮļpėAśë%ā qĮ^Š7_,já]%:{Ý)$ ÄXū8ÍØJÔ-ų[ķÄØĮņãˆįļGķŠĒ˜aW·†SØâH@ŧbĢxBōķ-1Þ īžáãÍĨx§ Ãyq)^žŦÐQĒhÏü-paÛv—ÂX1gá ka†ĩāá1†ŧ$hŲ 3ä[ūd―lLåŧÎÉwĩČɘʷuuĨXäŋ2ĖËwĩČ7ËŦïa‘ožŨ&ŸēÛ‹ƒn"ĸāĒ|[ų;NãWg“ųę/1øõąi}Éoŧņfäŧđåŧđ™‘ĸē:óÕx,ē>0ëK~ã0+ß>Ģü}ų&žlų”9ųNû,ōĸƛ!ßúÉ·^_ōĮK“ÏHÚÎÍÚc"ĸ— D—ī}Í>ąšFũމUö '“Uï˜&pŲđ‘ČdųNsō)fäcWąB°Øēā­aą‰ØĨ`čX,ük"–žŽÖÖ$o.ņgۘÏëŅd,–Ë >[iš·Öš(JĸÔ.*ËîŽoWļī(Y„\<Ã.IGš‹;šË#$―ÃOĸü0ÃŪŋ3d>Y ŦũfØ] ļšÓŪŨÍ)‡ą‚ÜÔcõgė> áĨ{ūw —Öë…Û˜•ïâ‚ĘßïâB9ļœ|úōeĐ|Đę[Ÿ"UÆĢsP―D>[âyŒmóÅÍĐæĖÛÍ­jýQAz~ĮČīŠDĸĻä~åqõÃ%ō}Kę―Š9=ĩ…Î …gŒðĄFY`Č,SžÛÝ728>RwĢDĸ—ü1rĮá”Ņ+ękMúþÆcN™ÄóT%ËÉýĢn\}Ąē9Søũäúœ|úk,+Ęw_V>ĘgūTrVÐ4Š7Îä/1 ōuœ\ąp:īxøÔ?‹AYŅ:rQðŊógeųŸ|bN>fUčßá0~‰’ŽKÉ9wŲJrŦTã6Á‹ĩLI–æ‘süíäŪĐųąž0ó…ĄäĖ…~ĀįŸėÜyL’aðķ7ŽÖ•õÖčJ°kĨåĨĪĨÎȌ`CiĮĶ•–VF­ËđÖōŠV†•Ņ1;f–.sÍR鰚ÍjŲeYvýŅŋýÞÍę}!ĒbÏwoæó{<ïöƒ—Įũåƒąŋ!°!­ŋõAîķėp“e―Đ*?nj_ëYYĄ—Ļd]ÍōÚú Eāã þķ )Ųó‚ŸWģ1;ĶŌSŽįŨĀá›·at‡ÐáûŒJāϚåã~/!ÄņhŽP„‡ôˆÂCH|üôÅEá_>‡#ÆqĶ8„AnB\ ė)騠å>Sâp/LãKÎ)$6xx8ŅĖ‹ÂÅ!]ÍP‚#Ŋވ‚Ð=L8ÔáĻ“‡[]gfpÝ īøģH|-þÎ/øte“Ūjg›7UĪÛjėđ―0j§[ÄþNâ zS‹NāÃ<ŋÓĖøn”ļPjŦąįÂŅųœî‘I4øĄøļ·w(?˜ųËôÄ{Ō•}Ŕ’óØnöeþoĄÅũöŲÄ(@ų[ĄÃy{ã6ņEė#õCq6åīøC|Á!|ĘšTĘEq6ëhðņ!øĒ_âûEq:ĢéðĮ'ņĮ·/bw⋠[Ž“ Š^vN—ŋ°ĻĻ1zÜš]§døô"?ĒÎåq=hĢÃøøø>>ķņ‡ģ‡ô™MāsŸwōršáĘ―su€?ãÆÍúÔ''S`˜Îã―kČŪ/{V˜^|Đ_`úųÚįđÆóå~§wÜhŽŠŋ|ĨÐR_ŲþZûP“ŲïJÔyøb+ūĀ6>sŽYņĩ€õuCó1Ëéē…eĮ>–jŸœÔ>4īĀðUŧåoŽ3ZXĢ&;ųbæýŲé ~ģ1Ž:hÖÅ7ŧ”užG…_Jā CCmãũŸiýşøë5íõÚ',hĻJSŸÄ4XņYŽŧŠÝGTŧYauÆ0C‹æ€,'S6ĪšðÉš·ÄŠ_ÖÂbą ÎōĻ8‹?SĖîÄŊÔóŦĖųšüvÐ>­Tí6} lüU í$þ‚ęžĀĻ:=ĸĶĸƒ úZÝy~^Ûés+-OŦõüķVĸINߒu–G…_$ZņÅôøÖ/ ėĀgÍWŦážŊV›óeÄRø%Đ,_m†š”ÅZ VÏ7‰.ĐZMė•Aį|5QOfI‰xÄbŠ=|‘Č~Wõ 3xØģÚY|!Ž3Ÿéþ?ĮRžîōģ‰|ĸ5>|c)ŠģM‡/ØÃGų—WŽ1ŋá þw醸ōËĮš:ėOÂ.đ"ˆėeÝOÆ<#6ðí―áR—ebšļåž"NÁ§}Ãõ™ũd9ŠŋаvÏĢ{Ģ‚Vų+?{]ˆ‚JÐ3nDaė‰š ōóŲû:,ëÎė‘áĖ\ų…-Įs&–]á*eēÖé"&ŋą„Ë/HĄóöįd˜íV"Ô1ũŽk5§3`ЃøĘ‚ėUËîūđþþã­ũ7O~jÐ–šŒ›ëŌKTjFLŽŠõSÛ KäûĻHloƒ.N{;%ŠéR ėÝ1_“]bŲB\ŪfŽÓúÉk[+ÛöĶ–&]ÉÉ\\ĩ!sïÐā ˜8qfP~°aýÅ_SĄŸ—œ%ï%ķÖÔÝ ou†4ė} ė:’Ī‚Šē)m”àa_ģdÂmļz<Ĩ%åܒˆe1ũ‹Ô‹cßA}ËņÞÅp9ßĢÔR˜-;bP‘sïÐáŸ2%ā7ņ•MF€íÄĸĪËJ-mjSÔĀŪ”sûŊ>öB•É#{âō˘ēĐ}MRÍÆ\øęžD“‘ÄßŊJŽÛÚJâÃlÔ1ũŽüáŽâËïpąļˊŒŧ_’ũ[kj Ē%*WÉï =RПŨjhÄãkØ ) ÅõĪ@EoSąbŦlŸ"/M~':>C”ĒЛa#f[ uĖ―ãūý<‚įyWhÏ áĶ ÅUø ō2]$Âĸ ü~Îá왑ÔbĒā‡bÏ^ =ū‰ßðŅōBWū;ÅÎËÎ`ĮðÄKā_$åe†É&ũâpëÂ;˜0ĪOb4ûŧiÝōÖŲïåՁ?ŽŸúö gïô > ïõå;ý0Ė‘·ZķüÚÚŪïïÝôŲý{þ->P·ýT|īžö—ņĨŊėhø”ÔŠđ{Ë*VHb‰á‡7Í5šy_TÉû/ó·þ^mm) [ În˃æZsVĨ"]ū,þ ņQKĄ{_ûļŽqĸåžë›+î{RjäĻßĀP+Ãâž“Ú1ŒļÁßTu—ĶÃS―äfXJvĮ0+žĀÏ3“ÍM&ÜŦË]œYb9ÄþķČpĄĩRGŽðddlīÂÜ6ŽŊŽØÅĐÂVÕ=;’ũxb}R:8ē$–ZņcđÖáī{Ĩ0ī.ŊYũ&t,ŊųėĖÕu.Ŋ%v,ŊUgNŋķzgŪû.,ÛÁï3j”#ø˜ÉrÂdėŸ?sWŧ't-a‹•l]ZQõŽvá“C“q{e›u Ž6Yb iÐŽđîœb$ðKãīiō'I|SUčúÄāũ]^û øĘ$Iė’Žģn-‘įJjVųAiFōüÔPë0aՊˆSC#ˆá]ÖŲWĢüČ/~aÃðvŌÉõĄĘƒîžÜ/Ų:7âZˆ)3\žŧ5Yų™Ø6JēåPĮÜ5tøƒÁw>h…§{ākÜũõžÛã{zūãq%þH„O‰+ðûGøÔļp?„O‰ëðû!|J\„?áĸ„ïNAøŽĮ•øÃÐßp)qþ0„O‰ŦðG |J\‡?áSâ*ü1ŸWáO3b§ÄUøc>%.Ÿ‰ð)qå3ŋÂĸ.ߝbïláĸ„ïNAøŽĮĩø}þũAøî„ïD\qЉð)q~_„OÉ?ĮÞąžÐŨ áSâ*|/„O‰ ð―>Mū;Å~§áŧSláĢģjū;Å>ú„KËðŅÚÎWöîĮAŠĒðˆĨD#*ó#ŠYÂėiÓ―dŠÜâęœ%|2lŨŽø+óü’ ĸøIņØüĪXí܊u~LWoļ|ÉR1XËüņĀO üņĀOŠyþxā'ÅKÖ―/Īô ŸÍ5ð“ĸN<ós<ð“šZį?~6ðKŪŲø§ĀOJáÏāËĀO üņĀO üņ<øðU&üĮ~͂ŋ/?)‰€ŊēāOĮūȃŋ‚ŊráÏāŨ,øŊū‚/?Đøø5~_äÁoāŦ,øÏÖ'ðküŋgkā‹Žøü:R2āïāŦLøû üš Ÿģ”k6|ķÕløü([ģáģ9ĒfÃį°ĢøI]ā/[AOŸÔ~ëā—Løsãô’ŋĸÅô<|ÛÛ/øoŸ”ÄoāŦžø;øïŸ”/3á7ðEā'þx.ü üøI?žŋƒŊ?)ðĮ?)ßÁYð'ðeNüüöî·m ĀðBW'ĐC­Ø*ðÝÓXün}oŠP“bŸúŠė3 ÔhüųWŋŨs†ÕüO ĐÄZų ^bóډĸî>7/PĶOjVC ĩũĨūČįķ ãŽ>ĨD ūJVģĐø ~ÍĀâŨ ĐōQy„už1ņWŸ:6?}ĸóÖâ·ŠL‘šįģöyiRŽn=â?ėįSņåãĄĩø›t+qÚÞĮģÍ·å^âÄųÂ#þŨ>ˆý_Uygņ›=ßá$ó8ŌYĩÃ)Ž=âW?ķŒMÅ7 VĘâW]oxģŌ1/p:ņËvøÂ?Ā·ú?‹7HŧĒŊ;npjŽņƒaüüū:ĐJâ"Ėī^”āŊ‰øN2zđĩƀęŋõĶðäž :Œĸņ3u­ōáĐ ™ëkGXSŨëÆ‰ŸœãSrÎF$|”Üø‚ðrã üßėÝYˆaĀņ‡oÆ,5q·ŌBÝT6-)wĐĖÚĩ"‹;fš‰,§”p6֘mŦĄēhd c‰ęĄčĒÂȊÚí°":ąûĄōĄ ŠĒĻ ›zí›ėĪĐ7%Ė?ŧģó}ÂOũÛUÁ)MÂĮFŽā—*áÃóéīøęú/! R1ņĩ?ãŧFįžŸ)-PÚP%(ŨŽ(Œ? ũ–Ęã&yAl,øÚėŅĢ@ÁyBïŨËā§ĪXÐ Ę4ƒü_‰Ē2 Ä_•ņŒüfpīB ZÅyŋ^Ūā âŦ!―L6räWüHÜØî‰+SˆūՒ”‚ķ6$hķNÓāÔ_‹QFzï –dŒÆ06Þk…Ež4Ë5ąFŽQôÐދ:œ}ą=KNŸsÓĮÁÝē$Ģ0†Ģ 7 4SÆœAŧ#;Ķ6ģA&€ïÆGQHĸþāD°‘ŅÚ:2ģ@ĀáÁęXyÃXjĶkxžÄ™åšÆuÎ. y0ĩãštžøT ‚ģ)CŊšlŠũŠ:U°Y…ŨyšrmWŅqŪ+6"aK·géíjŊƒ38œ—ÐDpĮ,åXÞøĩðaĸ>Đ&eiģŦÅû ?ãę֔Btm˜.5+Ā>%ĨXUjV3Eb4AÂ―Ļzƒ€Ū-Žļš1œũN"Õ &6ĨSYˆŋ$5kICq JšØq–›W)&‡ÛSD0DĐ&‚r,|ĸ?ĀN@UũūČÕc˜~€šĐĢ9üA ą žJđ!ūj!ÖÎã7'îvœSeR0.Îá&ŌDéČč ―kÂÄ5 â›Ļ°z,NâķހIđ(wäNz(Į„ðõBøžžT*åņAīF>a6!tå/xáuŊąu;.ģŽ‰áÎ*ÛöŲx :îŒ|0Đn đßcxYĮ€!ïÃ(ŠúĖ 6O(-Ÿm‰‘ąÛöh‹4ÚŌ\#DÓ5m|ž!p\Ý"Å"åų7W_/€ï1bD=Ž—üūæÔ,ðSLø;ūUœ8ËŲm ,Ë_ú5ð§ĪBÛĪŋŲ#Ë3aüŠĘk;UðËĐ ~þUðËĐ ~•‘ˆ‘æÆŽ,`°đdöË@“ÕŠ;"ôNÖ·Ģĸ āŨú†kDįëøĪf“øąÃ}€­Ū?ļڍ€Ē%ŦröS^Ã0‰X|_ĢL|’Á9ü>™øjÝđ{}ļR&>ÍPīú+ŅN$é§|7‡ŊĉŠOÖ'‡ï“ĄdĘáwCŧTŋE:‘Ōa) þHß_Ā_ˆPqņ•Hgú=ū^$>~\‰ÆúŒųðív{Œå$vqíÜ1žþ-üX"< ža%Må‰ïŪ§=ĘÎā‡0EßîŠ š !HeĐņCóý{VoØŅ_ōC/Ÿí™đ/·MļiŦĮōg_†ĩƇpŽ9Ļö<ņ‰‚qcšt}ÆšŸÅŅ"“bĮGÅ41Bw|T>ø9pxŧ$?zÍ  ĨÆ_?ũ^4ĩáœvvsN2Mb)5ÕŌÚū\‘―9įšz͜øÛ9ÃÂtĪÉÆžÆęķ$;nZŋųˆƇ)‡Ē"ý&1ƒ|ÔŠ#čüðˆĮTîīĩ­đÞq-ž! ĢŲ6&Cô!ŠZōÆGp›ŧĶž} ORO‰ņFߜäšķ]é~äGOlxxŧõ釉ęi“Þ>‘íąĄuÍÐ-·>é~ðÜõĢ/:vm;ąąuþšŊŽ<š°ėÐĢ]wÕšŋ‚mHēa,‚`5ôvˎ63žéŦŨ “â&U5)ÆNˆ“éä­ū}bþøpų2>`SÉþĨ_vÖjâ§On|ˆoV§bwܘļ­a Cį―ėDûM`číhL>‰€øŠ`ŽßĪĶŽLŒâWqøÜ46€IŒ‹GF•ŸĄ­;įöž„o|?sÁ˓ŊÖķ&N=·Z!Ŋuį‘3ÓgģmXw7{ęĘþóg7Ž―{ny79đh)yŧõzĮĶģÝþ ~(D—8“ŽĒîAÜčlÏŲÁ$ĨĻģUņøžN‘cũĄLtþˎ2Ę*đ=hž—ĸ˜ßŋšä?Úķįþ%lÆáéCŪ™Íߌoó/‡|ëFŋĸėÎMg^ž|0ßï?ąxE2>Ãŋ|ŲiĸÖÖ_áËÅā+øûnį?…á?!ÏĸóUæ JĶīKļ•ŸJ"Qæ‡ÏOÂïÎßķ‘ ĨÆíŪ7 ŊķhŠ-–z<ná_ɝԛܖúúj ÜCãæ·YÜĶO?wŨŧŦá·ÆõüʓŽ?ā[:‘đ—x|™Žī//ČÏøŪB/,&ūģķ3øjđh|MuĢDlý5ĶÏøæþĒ7š\€OâSKDWëkE 1֘]…7Â8@_û|āԈÏ,ˍUš5âër5j ĻąZđŠUđĀ/ð+ïd•  þ?P_DÅÅŨVðSŋœŠālïþBšˆŽŊ˜{ˆ]âyž>Üþxī™›ÃXD‰4œ&2›iAųRųbž‘ųr!ōO/õĒ=ôgb"éSâ&öĒ"A$ŅK=HЃ{ëÎÓÛoí·??™—lŋÏÃ`ėî~ŋûŽûą‡LsðøF?)?›ĪŒ_ˆ˜R0ū9>ūãvpōcâ[Ôø˜&püC@ŠoÆņӃãg?}8~ĶųÃMČÂ~―‚ĪXd.'ŽŋŨ~+rYdKĐo?ÏŧQj>ŸÍéøĄ'W}uče”-/Ya‹ų?ܜŽŋ~Ųú^ür=š< ĮÏL|wj]Ý1p|0~DŸÕ*tU>í8]oˆņŌj]lũ@ų1ņYĸ_­‹ß–Úü™Qâ·Înžzí…íÏéq| ū/ÎÛđnŸïŠ(nũ4ø`Ôø<Ļók˜į‹ûæƒ=3íóÁŋæ‚=CāāĢÁzä&p|5þ†7N‹(x―3ģķ-/ԆúkĮhž#HŊ-S'ķG„WķŠïĸü8"íUö€l8~ōøÓÝ^ïÐââfÅJŠøN@ãtØélé­ģ;ø§>I[Įo3Ģ―—Į Œï7ķžúûųĶ(L. ~5~q5čދUōÍÅþĮórüå%ątæÆ Y)mŊƒņ‰\ b’ãš G'Æ?7Á>Æ/‹ŅËq w‡đwUkã}k_žqýä0'šÞ—”ĀøtÎĮoF_‚ÎߔÛņĐņ=%'‘9XŨ­Pä:ēHĻY/sąyP9ĘˆOär|^ļķBđ^æd Á 8þ.Cý>ėåãmû`Ðãø‡ŽŊ90>…ãkĸ,Ëâø)āøŲĮŨ<~ Áq|™p|mÁã°E˜ĶĖF%>IU$mI—@ĶE:ÐBÓ&$īĂ0ÄÁ°Hč8Ķ 0ÖR)Å·ÖËēæTÔc˜Įģ‚Īũ #ŸLPi#$ōhŌ(ϘLRn{‘…ĖÅt:ÎîĒŌŽoV Äę#ĖP‰ĸ?ëŦ—RōCãģ ä/Āeįtš#G9ÆNËËN:aĒõĶ ’”O†=ątbƌ_›Ô†rã2Čęō„ĒĀĖUHņušĀđ Lc\›”þ/؀ũÍŧŪ#IENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-target-directory-page.png0100777000000000000000000005752113761647206022617 0ustar00‰PNG  IHDRÎGæąm_IDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšžĶĄ0üëôE>ŒŊ~mmŨĩl™‚ œY$B‚X  : Pl8YeĨ[ŋX1þâ%ņGxĪæhÎ.ļð―8yrúžÏ9}ōžWĮ0LÓlÜUģŲŦešÕĨEmzōú㇟ĩęyŨÎfūdfŠŌ°,Ā4ØbYVĨRQUž‰ÝÞÞÞÜ܀ŊårŌ ÝÐōōâÛbēڒžëå{.w<ņ͐Ūk ÐųÃŅu°‚vØE öƒS þŠïŦāˆ@tÁe ĸÞđp°‰ļė€ģÓˆó.Î^0xæÓ™k5LËnÔŦ)§ÆŌó·åkĨÂč`x˜bY‘ÏÏLũøý|dęĩĒ[PÄvė͗OŧÃXl,#BdbŠXW3 öðq?ĮĮú{ĢkZËU§Đ‘úy!>Šæ‹šï;đT$)ø—šHËû§ūgŽdcŋu2ĩ°yļ-ĄNšð4ÕӉmŨNö–1ðŽ?.Õkōlbl}įüŌ1ĪgĢ8Eâ-Ė]4=eo=Ép;5ÛUø‘áĨ­’åØA Á'f,―wîĀ&fvOmïŽģž]ŠČyf”ˆ AM–UĮ6ÎgđÁ‚ßÚ/fäå“ãÔ`§ļīqR=ā(šlķJïĈ°ę~ŧRåMķŊ+Âr,ËlTLM~…‘Ųšú7ĀŨÕY§hgÂ―øJáäęĘýž6ŨŨ3ÄÅ9šTK/冚ŧY1óUwĨô“ÐÎ ąh8"æ=ßYMttôÅã<îZؐ=ÏnOf{~óÃęócšƒĖ <Ļöt^Ðų‚"č°ĸbÖz^Ģh‚hþÓ\ūÓwĘí‹QņŠˆđ|ˆHTPPbŒŲdĢÓŋ§{š{zOŠŽŊ§ÖbÝYcžYČP[õúÕë·ĩäā ČÏÍŋŊЍ?xnô‡Á[f ĨÐHĪ”P”B°oįžÞšyöāū~õ2ƒÓ€i­ ÉyJ įóųl6;??*`ŨcŒ“˜Â‡‹ŨïîýĸfũéŅíãŲ Œo=ÉXErNŅåž$€Qda”Ģļ†'Ŋ\YÅģŠóÄĐ?kzŒY•ąv ú Wo7õä8Ëü|/äSðü?Ōäœ|hGӆļ(I Ą­ėĻtÁ ­sJÉÎXšū$šAŅÆæ-ĐŽG`b;ĸlïž:-]—‡’BûĐVŽÎZ-O%­LŠá…ēąKđsķ ⭂Ð.ĄVb°ŌļZ4ōBęspRĀ}KiąŧmX@§ 釅wŠĘFQ6•ĄģüåÁ[_ ZõXßG,Åôī|5SÅūïŠWrÄŅA"áCÄĨĄB9KŠäcîšN+réSMSÕīÖĮ˜úޒ=ä6ąóZ6óųGWŅ.â% jŅķÁíS#Ô+āCέUÆw‹ÏCŒQđĸïöÎã“ÎÕvCųæýáÕÝļ?„Į]\ē?ž$ †w› |œņžØ”óïkm/0ãY*“\ōûBp‘åM_x^ŅÍTSäá؁+úģ…ŧ5X Š1GŨ—‚wðÚžÃbސĩ‹—u€ČA—sÆĸēáõą/ω-$| /ũ UĀ ð7€ŋ"'ĐKlLKƒ(óDâgŲĢ<ŽšŽ“9Y0ÄĖ`~r0ZEōqŪlôâ”„eð)–ĜԝúÃ#6úÃķc‚  rĨc—h%­Œ5ĸ؟FŨBŽ+%/îėíόąāĻʋŧŨũž―?ģÆ*ĩT}Ču *dŧ6Ļá_=…a@€Ó>ŠY äĮēĒŽI0)!Ixēoˆf9‚Ū@ JR,ĸŽ’–†r]ac 3Š0šļb#Óh(€RtØúŽ,čģzÄ ŽĘ(§–:GÖT€N jīāÉĩĸn6ķ QŠO Õï’lŽĸŸLXäsÁð<ÏäðÓ4á‡âņxīÁ˜Þ8ʼnSL Ē7Ĩč.ŒĀõėrˆŦ)ģ‘@=Ó°ī{tN īĪE_ËÚĘlĖ•ÂĄĮĨØ!=>QNóą&šc{| Z>/ëņņëäŠýJ6HOó‘ĸï|›ž8æÛ_üzŧßOđĀ"Ÿ^äCÐðA="‚%|2ßâðiWø­Uō雕ĩæŲĻBrÆ{“pĻ?ĨĐú~ČÜ=ÜÝĸüNęl>*šJËgŋß[iã"|ïýToâãąĮgÂä3/ü}!öø`§ųäžĸžwx%Ÿ‹qŨëõf―ņÃ?ކÍĢm7[ŽøÕjĩÖÛív܎Ôã­GŲ;R(”ؒ,ŠĢUŒYÄ4SLāãŪ1 1Æ@<•ķd2ĒÅÐČHïˇ[đË;ĻŨ–đWÏ <^Ïo„õø˜ÅäcKåĢ")ó& |Ę݆Ąð áðÁú|ðþ•GbnÅq‘OFÉg7Ž4ÞÜ|7…ϰABYäcKøPïÎØsøŽ^āC ‹åƒÕÉõýĪ“O č­?‡ą­/|víûÉŌ–˜7ãļú"ŸŅũ&“Ÿ ŽÄTôáƒþJ>rŒ;žÞŨóAĖeüXũڕŠ|PNó1nųp<bø8Ã?ãƒŋøüdWOv}}ĸĢ“áØ7ē–}zīĖ!Ūeõíą­Ŋ"žųm%W=}ŦŽH{ėōōē·īË|°>ŸJŊōQü>ߛî>í(ģ-•wäƒ=ãƒŋ‰qø ž^ĨĮįŠÔüg|ˆ—†ĖÂûqøŧōÁ>’ö›―ŧ€ŊâXĸþĖėî‘ļ 4āîÜĩE‹•â$ļkqw—`Å)ŪEŠCˆ’Ï9‘#ŦóîɁ”[ÚÞĘíýsßηôÃîģ3ģģËáĮ°„ēĸĐr_(IŅûCïõwƒ4ŠĒ(ęoFĢöŊĢ(ŠĒQKQEĢ–Ē(ŠF-EQEĢ–Ē(ŠF-EQ…úGB˜Õéī˜åtz=ĮâßÛa†a0BĸĩÉēœFŊŨąøįgd9­ƒ―þyĢ( Ÿ1 a†ãØ?jČ~ Æ(+ņEðÚe'ožB Š{qsÛę5·BSŒ~{@ûŸ™›f4Ģŋ’qą,ËåbYĢ_n–g·ÎlXŧýYĒųã[ˆzóØō ÁÏße ŒĒhÔRƒČ•­Ģ+WnyäfĢeᏐ$$ø˜Áož-Ÿ2séé{„cĒo]œ2mjðĢļ_]%į}ôrÎ Sûæę’†æï{ĄÕsþ Ė鎹ũŧĩŪSąbyĸR%KĐĘL;ę į>mŦÅüöMš2áyRöĮdüôâÆ“–>Š0`–ŠĒQKý9Ųi ‘‘ĄĐ™Ų€NŦŨë8†aœ]\9įŪ|uŽ.*'G­†Uw‰)ųðâI‹ŽÞGŦ]YĩsN ö}8Ú2K’‘,#„"˒Ä* Që7ÖØ3 “~}ÚøĀCwÂ9―RdGŊŠMš6(SŌM‘[öjtÎ9õZ„ÞÏIŦSiY–ģMÖŲéįO'"ĒųMDx\"_ītđ2ĨK—ö-áĨÁ2„Y}Îå8;;h>Ļ$KĒdý)|uęt:Ėpē(`åýI5Z―‹ĘŲQûþtHĢÕéíÓprvÔqð)ŠĒQK!ŒcÄgÞ8ķy}ðøČ‡sFÓ―ûä# FjkZøîESztíÚ-pĘÁs!Ā’Ë7Í^ķsã֝vŋL–2ބėX<{PĩÅč]§ïš}Ÿ‡?=°íÚFKzēcņ,{ãÝgîYL1ŧWŊÚžïĀÞ=;öšl$ČÉģxĢĶĩĘr’Ä éÅÕā}šuíÚkÚĶŲbÔųZSŽėÜķ}ũÉįĄũĮęÕ{āč[aĐ,ĮĀŋ"ų”ü"øû gŋW_b·kÔþĒ@ø”°Õó'víÚĩĸāųWŸÅcŽCđī?&V2Žl™Ũ­[Ũ[ÄĶ™pNaäŒëGVwW{œ~*$YƒēŪÚūeûwĄ/n9pōîŽA@Q4jĐ_K\1ãúņõ“GõhŌŠÏÆ}ęŧãVLģ>‰h5vf§n‹Ö‡Dŋ}ú݁3oIX~}ót:éõ•MÛv=LĖ~žvÕâmûïeFÞŧķkėāá <Ņé9ø%Œß]ūbņÖjãŧWwūčÐSŅðúČõgzåÄþ—F—ōâdāļŲ{oÄë9áČĘqíû>ņô˚iCYõΊXŰiÓŌņcvęÔcũĄcvmœē`q‚ō€+DÎČJKWģ%`2".toÕiÖâMO#žŲŋôŦŽ―v]ŠD,›ÛžeųýSŋ6qþ‰3į7/[°áČcæˆqíĪ―†Íŋ~õåíýk‡öhs>ÂĻã,7ŊŸ0~XÛN}ķí=rëv,ÐĪý-Z 1€XŅU›O―|ųpåâ.Q‘'^'K’1ęÄó(ŦGĐásÖÞ~ēaF/,iúÍ]Úķ(”ë2õÆÅ“ÝËŧU5û‡›·.í;·qZGkFxø‡fĖaŸ’đvОnÝī5žÚÁjx~ýžķdÛ%Óz@)+˜•xidQ!ĀYboÍ^°Įä\vßõnßžŲŋy‰ˆāŲŒá,ČOHÍNƒŊ]>P……ˆ˜wé&é_OŠXŽÄ„ïęÝđKũžÝGOݜ͑+į\LŪÓsņƒ;OŽn§Íx}[vŊrônXč­ã=ęļ( ‹ž_?°ĸīQßųÂË[ĶķQâ#ķœÁ,Ģĩ=ī– 7ûúØå+ëÆÖ“™Āo (ĩ”,A‘Ž —ö-SްÞŲ‘óWŌ-BĶũïÔđŨð­7ĒY†ÅĀ1ößS#Īîî ëÓūmëŅˎ0ŋþecdˆŋ;aĻ­ņ˜ĮÕÆjâtā4ŽZ[a”eHŠ• tEŋJÅóę=}ÖĻŦx“Ą$ēėZ°Ä°ņSJɟ#€ĀĮQĀÕĩT‹f-›7iP§īždE‡ZY'ï†í›8qļ\Ĩ…Ažu+![@€ėš—žô6;Ãâ]Ļn•âyY§Â•*VP"&ƒŅh$^öeûéŧŊd$―NķEŧ"ą…ĮÝžRiŋĒų‘Bā7QZŠ€“#ĢH’$ĒØ+ ›7pÕîËĮwķ-ėvóÂĄĐsŋ―oҰ23yÎ‘ËŠ˜4uúĄËĄGϝ6Ļ…Z·Ĩï/Ķ-ĢAájãÃWÃū3oęĀfđ‰Ēä$§Ói>îŠ̘yIF à E4‰\î!ɂ,É ü2YŊ€aAãĮŽŨŊGKE!H–kbz6ËéÔņ đi†ˆĖj#ā8„w‰ÛųˆÚ€q­0dÜÔ%k‚/^ūēyb$Å6mFŠ ÉēĒĀŊ (ĩ!ð(“Ü=$Īŋ>pú!đq‹'ÓIŒģdó  AÔą‹GŊþø&&..!ÕÃģē·ŧÛŨ!RJrt’ŅBÉðžB€`ĖX2cRóxV)äĶóú™­qJtb†E§qÔÜđ|ņ‡›OŒžO[EqöōŦX…ÝđŋåÄų;ŨΞpMÁ^åýō(„ØW­ēmh")ðkˆ"ðVŦUāÕĸdäT―‰?oïíšÞÍĻQUũÎn;}#Ē|ÝNýë—yxlCß!#^€dQÂĒÎŦĘîë:ú*‹ŋųĒyĮ^į_*S6ėé^ÃG’A” yī°ÖŅMü“‡Ī„HĒ$ÉZ„Ûū(ā–Ģ—ÎŅ>þĮåm›5žô`ÎCũMęė‚lŧnw=Ctޕ&š/+qyÐā•—“;7+āĀãZļÆüÕŦ;ԃEãúķhÕšu—n›NŋNĢUQ ‚ĸc•öĢb"žß―û(:6)=-9üÅãŧ!aIĐé†ÔΧOÞø8>E-Į?ŋwįęĨsߟ9wûÞã„ƒŅn0RâĢn^đ|ņōaqĐ)ąá?\ūpéęíĻ· /o]9wþęë7ïRbŸÞ―ō*:͐žþāîݰ7ïԞIo_į4þ1úíŧЛjãkjcc†1.âų•KŊÝļĢž4ņíëŧũūŒŽWO”‘™ũęéÛ?5záÎãg†ĖLƒ!==5ņÉ㇇&ĶÚķÃžÜ―ō"1%-=í[9îņƒ{žDĪĪĸT633RÞ>žsýÜđs—Ūß‹KÉĖČ0ĪĨDū~qũî“8Û†ĖԄG7ۜ=áéë˜ø7/ïÞ}ö6>Y­ggc#^\đtþÜŲóŨnþø*&>ݐōøÞƒĮą‰)†ô4ŠĒŊ›Ą~YšÁ˜‘aīg‘AÝ6ėuĢQÝ6æ”ÓÕMĩ]njĨŦ=sŌ?lŦÕ~ßĖVUûŲÛŦ‰ĶmgĖmlČml?ŧ―‘ÚÕÞ>ũ]îų?Úĩž{(—mķšá“ēÁV·3äžÂ{r:ÚØ§˜[ϝŧ*C―œœūöąÔ3ŠĒQKQEĢ–Ē(ŠF-EQEĢ–Ē(ŠF-EQÅÂg‰ēŋ,›øŽP…H’,Š"ü,PŸeÎfdd„……3 @ðđ (ŠČēR͌ŋ““Ģ$IĸÛQKaŒÓŌ nnŪÞޅEÏEQ Þyc0\\œþXÕR!5jóäņ”e>EqŦæŽ}ôĸIÔRäø‡nZ8vÏUNŦÏŋãĖcĀ,ü&ޔ•žeÆKoVLu=FÐrþĪŅjl›9eëeNƒö/œōݍp”ýxúļ•ÏĢyûoTŦãƒiãV―xĢVhÔRĸua>9"A[ļĸˆáÍĘXæ ›ô4ËęUđDbX–SąïŨy˜ąíj4Üû/f8 §b0ķÅr9؟}–Õqė Y{Xąķ!Ւ:RÎČöĄTšCaÛPöą%•ĻŅļq ?”ð§ÏōÖžzAP—Jē$Û{چ}?ËXßî˜?ę\H‚ZĀž$Ÿŧ–ÃęđlW`ŋZ–ý0CôŅēYÉļBšÏ]―|ŲššÞz‰`MÎdXÛÆÁŽČËáœāemŨŪŅé͆ œ;āûKˑ{]*æý0°ķf9·ƒąÍؙäɧqĀĖŠÞwg>ÜAŒ}W=fŋo˜aļˇĄ‰ĒļŪ\ą€qĘę=É"“xįÔÆģ 5ęVÕ``ØÜ üáÖäÎÐ6€­bÃĐŧ+ũr>ĖßÞČþCĨði…Ļ•BPÜI"S­m§}€(ķĐjrÏþ~2ķöØöyyvņÄđ{u}ž&š”ðäD…0ïŊ\“;außÞïg'†ĩó~XÛ?ĩlЌõGA§š°eņÞËá4æĪģûfÖŽUsÄĖ}‘Õ áĖæ‘ÍÚu z•Ė3RęU—-ŸØýËo"­$üZp‡–ĩírþEǚ1`CįųÕļŅėUÏ^Û―}{õŽšWðadóåí [4ĻßžÍĶsĄĀj3ÃoŽØ°;ÞĒaģ"f.Ýô8‘7――ģlųĒ9Óúõ­™Ó`ˆáĖņgoРېaé‚VŦœYþíĒđsĮ5ĻS­EŸý7ã5:bŊŒĩUúîŋ‡@Eí͐„į^ŋ50óęæ‘>M7hØpöŽ“<‘w-Û0  aĢþ§Ĩi2ŸÎ\ū{ĸæđí,O6ÆD<7Z%L„+Á Ú4iX? `ËŲGĀq–„'KĮL]·tPӆ5ŧÏ>ĐØs1(ëĀ·#ũßIÔéČéÕ3'mšĖhu‘?O\wÁŸ’mF9ĄetüđĢëjÕĐÓiÐ˧ĐV5ĮÃŪŽiÓŽaãķ+Î>% ‡hÔRĖąÆðggÎZ4m‹Rļ‰Ÿ—!„EĘÕ= ^2lŲŋĢLüÉËÏöo°ãČņą-cVÎÂĘíā5ũ%N?ūŠ—N’dÄđæ‘ođzÓjŒŲyðŧŦ.dJĶ#ÛÏdfËzW‡ØÛ—Nžt]0ģßýÝÛŊ=M =·yjpæÄ­{ۖH\ūņ ąnØō„í2&Č%ö‡Av· \5·cŲo§Žx‘Ķؗz’(äóo9ĻMÍq―ŧ­ó1 ‘–Č!ßoš㛙›ŨOn·aðˆāąrVüĨ'OŌ%ŒÅĪŧŨî§g1%î_ŋæŒRcÐĀŪY燒,ãúýŲŋ‘ž8xøĘC„ļø'Ũ‚Đ3wéāRüŒž“ãåݓŦjĨŪZ)iQ+o„ũhX n^yŸšvmĀÐÉN-nÞēđkĢęēÅä_­Íū̇{”ŋŋ|öiŅ―x§Š…K–m?+°W.ûÖĩ“Ņ&6æÚÆŊü0lŲö“ŋZ=sėŅ{)”yvۆ2ĘO žýýú1ŽÃd Ýšĸš"ÆlX°üāö=)ēt=xUzŸĖ§įÏ>ųõP"Ā:@øÍóWŽ‹—-q{{|äŌ#ēõÍč‘ÓšLÜ1ĸË=óæÝxÆ|Ūk[Ļĸ} ƑQ/Î]ÆŪĨ[ė\Ü·Pæ H–2CŪO‹ô 5!þ%įqŌK|ܜĀք8AzkđÆ―ÛŸüvÉðīၓ'įO {ųãgsāC}hļķ~ŠQM0PdâQĶzû*ûWýŠŨˆ žū’Ir,YqÐĖEõ ČŲë―é|7+9kËŽHH3fŧĶŋ‹đ.Xū^8ĐAŲ‚Ē#AÎÓSVëVƧXEKąRe+ëÖ}wĸ%ʝI‰I{0iTȋðØBfA@j/—üEóįóņö+ëëíšåĖ-ƒïĩ+ļhĘöĐŋýȅ§›b„kNŧÝ~P·jþū5'Ürk=ÉLųÁlˆ:4úŅóˆļ"&‰HYRþšsfLk]+/oE]˞7Ė đr(Q­ÝŦ77Ū~“õV·c=ãV§Óž…ãj0O ä?˜‘™žôîŅÚ @ÃÛg^ ëZ,<ä/;sōäŪåݞŧqpÝėÓĐoBR‹Ŧ· y8 /ęúMŋĸŒŧ—iüýė‰ó/G9jAVxIPŒ‰VGĮŽœâŽqkÝoÜė…ŦÝR­€Fmņ.Ņ ‹@!‹’d%ÁĒx”oØÁÝŌ―Ũč'i­ʃ$åþƒ"‚˜"Tx8é‰Ēd%„ÅsĒč[ĩíčIÓũŸ=;ķK-$‹ðĄ›Ž(Š$ƒJÏš*&ÅŲïâLŽŪˆØæ@p’!ɐïbĒēģĖģžũ­ÞnLÐôgÏvŪē4Î:ŒY&öEÉŦJÛJ–K#g/-ÕbņĻ^ėaģ4ÞĨj”v‘ŲÍQĮ)jA‘1ƒFâ úÕ4vōęmOčæĪX8k‰íäęa·ū_õ5ãö[ß/­Z@'ÉJî?ÁŠ+Pޜ§gŲbîēZDH –”ä$‹íXķ)ÓŽaĩDQD‚°2’ĢŌ…$FËnZ$ųÃ8XˉfN\í8tøĻÞy5„@2žš–,HEž\u!ž KŠZ)ęåĶNāBNï ˜“R2Mˆa…ßÚ5uíá#†wŠYW@ģy9‰08§ÁîyófÅ&H [Óē39― œeŧ ‰DųhMG”%k–ŌÝí1"ļmïņÝŠxÎÐ'ŦVËr.XV€ĀϐŸïéEÞ*@lL‚Ā ―“æž›w8uöžKŨŨ7/—W–ešŠĨþ.ŠČ3Ģaą,ZeĖEē˜L2rčŲoëØß_ņ+î"éóUŦï+JÆļčÐōõ—Đawn=%/%:ŧ[$Ö]ŊsĘ_ŠeÏÖówũÏŊp&S…fjø{$3 J―|ā^~pÔ88kuˆaŒ1‘'O}WÓqŨŅŨ-&/ZŌĢoQŊ3›ũæí_‡·>dŧũYŋöĖņÃQL73Ûm\oÂ[DæE$‰ķ)ƒg]–u]R{ĖøRųYŲ*ŲSãâåį›įôÁ-eÜō"BķÉŽĻuBēģ,ؚ<íqläŽóĨóvČ,P―uóĘ%Č`C,fApˁNŽ^=c‘cqëó3&—9MKË įL&AŌļ·Ŧ]­ĸæU^æįŪœ y­ōlŲ1pņéóĨōúč3 ÕîÔžcÎA†\DVœüš4pŲķ3ĩ|“råâ[ĪOœ]Ŧb+/b%1;Û$*€°b6ņŲ Ũū^—BŦ&=~­~­ĐY%/ޔÍŦ-ŠŨiÝŠüŪĢGsM+$™œūčÜēX=!đk=)++˔sdĪ­[ŊÝę‘kĶ/ÐûZï―Í,?žF%'!+úÉ―uKæXÂN„ÄeX ēĻÞų§”$€0ƒHjRėýû·#Œi7ÎŋíRÍSË-\―"ÄGÚš·ÖWåóéîģœúĮ‡žuB­ôޘ―e5›E[~If“hQ|[·ïäŧmŌØą―šø[JÖv7‰†·aOŪž―‘”,†DĪŦPU\·jãĶkÝę;ðõÎĒZízÂũKf,Óļ§=8šRxM‹ œõ2Ÿm›QŽælIɝ%qð,ZđR‘uŨ]*—ŠČ™ËĮDíØī* ņf3z? "ÉĀl–%…@.ÆÉúúėŠÕ.15Klþîm‹‘‹û·h_ââwĮ hY“…†Ý;—-čBĄŦÚĸžļ‹C›QkŽŪ ,ႝŠŨ ØÛۑ("î0qՎwÝkæeŅ*“V5}Qvj‰AÛ tb•å–5ýPVj‰Žje€^KwÓđū$’ŅQߟq-ķpÃáĄ-ËY­Š·wūōŋY9',äË5ëįŒë eeĐÝkųĖņ$Ý é õ;§J~œ·B‡Ýëš‹éēGĨ―;W·(Šg<+Œ›3ՋÁąPïĀđUžXQ" "DBšf_-Ū|`ĪÜ2Ï †ØÛ6ŋ™úūbýYûĐ­|îđԁr&(ŠÍY-ËęaIąėîÝūaĸUfųýđ„ũ“ėŨe+ýtEÖÜ+R$uĀ\֏įœ{aŠ,Ųįö~žžðūN”ÜåŸrî€"Š~iJÖ3ykî%Ŧ›öû&‰žýÔđįķŠYõĄąŠĸŲ-úķ–ŌGUéãYŲðä#o?ŧb;/~8Åûîæé_ĩž―ũ’CM|BL3ūj5gߍ[AķFݐ ‘sNĮtđŸJΝ“rï§m,ųÃ4D!į,ŠðņŠ•\ŪÝjŸ^îåüÍDQ }ųâEhVVfځÔĸúĖhĩÚČČh―^Wīh‘ÏïŲRDcXhœwŲrnQȟ#þÅãg\ĸ’^N !@ýį!†‘Ģ^žDž>…óđ!ŋTĄþ–eÃÃ#!… { ‚ø{€@!ôû‹ðöïÁũŠÕ*đē:gUj_MđŠ5Jøûr–"ēŒ‹•­PÔžŠŸV(úŽ–úƒï@­žHāߨa~)GQbC<OÁHzqïÞëknģO#Y0ÆÜđũÄú—_ü!Ŧ'JąÝcōËŠF-õûqZmėõýã—íÏĸ†9+Ãhâ?}[Fü…Sŋ]ĸRÚwŪnä8ü+IËdD_45h0ŠĒþQKÉĒäYĒjûÆÕī A Ê8ŠÅȞŒš,ƒĪ\ß=eîšïÕtÆ―o§á°šĢ6tr q- …0u°œãþðj%ĩË2:―3B%0 (ęĩf°Ųø.*6žÕ’S{—-_9oD@í€Î;o―Ucō]čđnštœ<\Iŧ7méîmË'vŋ95=aų” ķėt+<“e1bOĒ€bûNūuheįuzOžobVxũxæ€: t^ļî‚Līþ1(Šþ c&+6äÔ=ÜũŦ֙oŸmXuzČŠUĢ<mÜēG­Ŋƒ·ŪĀeÛoÖ $;;ķ-ã}ųbĘāķŲRŦi>k5[ĩŽ~Ãí-ü1šôGÁƒŸYžĮxhTāÔ]7ö \ÚØÝ_oÞÖčäī@Þėĸ,EWĩB.3ŲßjÐī /[UŊîïę$ņČ1 qëgßï?sEī XĮ%+UpÉSļž_AWwįwŅũƒÆ|ûc”‘â$`ÐĮIËBČåC†ļļuÓw\Ę6†%ĨeÅ_ĩ膎üēī_Ų3:8’ûÞ|ŠĒþ!QK°‘iĩHeICAbŦ·|lÏš’ō“‰ģįĶHYĘ”TāæŅĨKÝüzäðFĨ+fX@ÆPB°ģGGϊĮ›ŋbÅņcóðiəB$&:R’‹Áh‘ PõˆZúģ•'ęoŽ‚―b犜œyý܁ģw_ÉZG­ÎÃØ·ŒĘÓĢũÝËĘ2šSbC_ ŋýöų݈„LYģU ž9ÛbĘ·ęW,_ÜwŪū~yïÆũĖ.ޭ˝6sú·‹ Ÿĩ79`―>ŧĒFĀ€'FĪÁ@QÔĸïÏjé;ŠķôFŽ$WmÓŨō{Å9h5yōā_=ó*ßy]‡ÎDT_–0ø…%;ö˜ļÐņTX ūũŦ;ŊĖY|@Ũņ%Ä"ĒėðÅĻyļĪ#S þá]ëŽŋ—R°hIBœG.[ëđĸhŠŲ}ųúIÉĒģ,j+·Z4ŧL!Ą [Šúĸ>m|ð(ém\ķ$Éü/ ƒ| 9UДŊĪŊ;Zęũây^ŦÕVŪ\YQøPô—󘘋Åōņō•aPttƙKoœ xVię­Õ0„ÃįKą/fāE“~öę[Ģ’~îēLhÔRŋ‹N§óņņ!„üM‹ÛČđĸúâ…Ū`YŦŨÖōqđ°`ø•Ę37öŦ ŋ[fbtl–Ķī_!  åø$ķ^"ž €ýøŊ- \ÆÛûĐN•:”:·,(ØĄôøo:3ˆ@!Y1˜eQ$YV–%ēĪ(ģDdbX ŠŽËqķeQma†Ãåô’üąĻU) ˆ2Ļ“ĮDĄ_WKýIÖôÐā0ĻUÚŲjɌJ~'ĪH‚ ƒĖ›’“S­ØņfCbbĒ1Û D‰9q`āŠCo’Óx‰(Ē59)11)— `WÖĮMƒÕ ÖĮUÃ(Ÿšœ””’f’ˆšũüÖŅ™s—EĨdŠ{5:öïÓķ&›ŒôÔÄÄä,ģ*" ‚H@1$'§gšėÓL‰į[t6cîŌ5KįDüxrėČÝꁆCflæ’ĀKēd6͚yÉÖÚdLLJē*`GDkJ’:|2/ŠOŨ.īæh\Jš(ÛŊËĻ^—Á$€ęÃ8™éiYYYŲž 9QīšEøK(DdÂÛ2 Žō/}A Ø1ŋđ€nå|Ëd[sZÄņƒ[.X:gęϧIbRčĐ-AMįiüÝą3fÉxrÉŌŸ&Č,ÜÝ3âØũWxÆ!öÖķSWï§'<Ü2ý‹ųÃÚî;ýHd4VSâųMcækūûðÉL Ŧ'úĢßx x‰ČðûŅU-õņŠ#öÎiĶzį2:ȆcY†ÅņŨ7=įŦ$|ëz™Î7ÍŠ„›0eSDĶĨBį +Ô;{ëDȑÔÉqO†ŪÚėþd˰•ßaŦŲ/`ÂĶoŧ!2›œ KÂŪ|7vöFcfvÞ#ũÍl}bíŠ !ÖØū…ŋûnŌÛkßÝC5ĮömôüŌķoflÓ1œÎĩÞę“Jé2Ö-[—åzíLœÆ}ÉŪc-―Ė8åņðö*TLývrýģŽ3v?N"žÛzÓwhŲBåŊŪķ;ĢĒúÍÜ\ß5rŌ”UIIe[œ7ĄŊģéå Đ߇$éœôÓWŊ=uũړG7&Æ=šēysþČsĶ­y#™dWŋ‰–īŦ›įĘš!{"ŲÄW‰Mę=[ðâÆÉnŒpxÞäŨų{LV Ļ?üû˜$)D”üʒM–AÆ8=äâ‰åŨŪžÖwęŅT‘Þ†ZnÐuę4jDÓk,+Û{^€7xí#^ZØríîŋē>ĨŪ=üZã\ŊU―;ĮÎ0M|Ÿß™Ž-ûÅāH^°>Ø>ųvrĨ~úœ:üŒgŲõŠ‹’„Ē€ ƒ-i ZęOþæN<}čjŧ}1yĪŽøŽo°qÃŲĀÎ―{Îy>n(:ŧāZxĩówVâFĮ5Ŧp™Ņ,[4:ŋ‹6ƒiwáę(KČŌm6ūœÞÍ !øˆĪ@þrMï‘}oũðiûí}ū2š{æ[ ^Ņ*z‡ãõ­'7Ĩ—ë4‰sK~vã‘ÁÉxjÓ―Øø·ŽaQIÕJʂ˜ûE2`ÛĘÝøe €,!“•8™>ŦĨþÔOÓËsąåø‚Č`*ŲfčČNĩ ûyQ^āĄfŨÅ-Ü­yËۃgŒëÛXïĐwðÔ{ļ9h@‰‹ļ1yÐX“žYþä4DN ;?}Åþ7`WgŽÅ.ŽZÆÝÕņÃScČHˆŽ4y—)[k eˀĩ›Ã ŲĪž%†YĒ€K ïb ēLþuÚĶÔč†ņ-ālÐįÔÖ·ė>°uŲ‚rúãwĄo^Ëßķŧ$EąĩģBžĨUčÚÛÛM9ój'O'=“šĄó_ÞŊ.ƒØęÍÛ ­3 2 Öąe·u}óļõnZü…ï| =‘\z7)ęÔï†rü,ŧ‘x…p1á_,[Ý**š MjôéYØ1úÐþåk"Z7@([Tį|RfF–Ž–dš"}ĐvîiO;UëšÉ7vÂņ• Öíã”ŨÓ!oũŽcËŋ>·äėŽéŪS!―N_še™†ÕĘvžĒs+’mąV‰Õé0RdŦ 8Ç ŋD! dÛ%ÐU-õg$üxQĐ_ēh'ø2ČzDŅLlŧČ―ÖęŊĢŪÎoŅeRãNũ<”™*@ÖËA3ošŲFžÐmŦ?Á —{kÆÐ)—Ümåv}Čė=<AČīˆl!Hãę‘O“šmäÁMûüņ+WŊĘÎZĀQ‹$ɜ=be™•9=rížqŪ%ŋŪZđ*‘ũ)  •%ۘŒCÞbų }īqLN™_Ž9ûðŠŠčAąð@@LˆL4œģŦ)ėú“„zÍ}ÃïJVwĮœņĩē6lËý–ôŌ=•™sb*…ČäŽÅ,F˜ôIÚ2zėĀŽÜŨD――tĮĢpŊüΌlåu,ļh$Įę]ō]{óĀÚR^æ;ũ}ûīĖë^ÂŊ4óü>ņĐ^ÉÓĢ‘åā:ßŌ­žÝ…7wNūIÎŅEŦE.Î>ĩŧw8~üxē_G’mõvó4žÚđčŧV‹•Ë›|bvgݗ‡[ÕdÍîĪûróÚūĒĻĀÏYF’Ž -"ôY-õ§ X/ÜHlRĒ•‡TD‘^y^ą—° °ô$xô‚óF=SķYób:ЗŦ™~}PïÂŌy#ëaŨMpÕčēĢÖÎû~D-ÅœČ“%^ôîÅ˔)šqÞ  ūc“bfmŧēŪiy&{mũ/§mÛ7“•E"ʅ+7vqzŸVÛ :Å%fN[3CÏfʒVĘY$#IDDÄa&uÍÔŨķåÍĘN(XöëAó/ĘķĐĘ"/HķöŽkĐŦĮΚŲíÎ>Žhę˜6hÅÂĮCF7k}+/'4―ąg@‹„ysú Í^ģrö·ã†ŒœŲåŲ.ŸČČÔĄc—zģ`ĩZíãĻōWoŅēÔüŪMūŽå Ed―–8ëa€E>y€ąxÓíō†Y%đZßyū5ŧBjËÞý Ō9qxUé=e݃Ŧß Mëņëʖ)„TîĩÉ- Ģt9öüzVyŸZŜȗÏ+)úÉS­gĮ΅yÔzZŊ‚į^― Sƒ›‡6g­öCXoė wŊÖy*įëĐŨǜžŽYôéÛ!Ē„ˆ–Ðgĩԟy€ "ŸkĩŊ„ÁÆÕ·ÕĐCUŠđÛhėîŠķôå\K/ ޝĮ+mG‰ĩ‚Ū|ĩęžZ€"G.ėKóyœūöøgq…|<ĶZ’xŨþՖWĩIáÆ–ŨĀ.ŪųĮŽÝS'$ÜĨ65VĖ›ŊdÕ;ũ…ūąļąLĀŨSŠ!gÄšīē"Ų[)ŲRĄĨ+ų{ƒb0gcWhÜj-ÆīŽcVíŸÆ‹ēÆŲģBå Î ĻZMÚYÏÁû㠕Ģa[―ë<L`4ŪEËpËįŧ~ûáGÏ_KŒĢĨ<î_ļT2!CqeŲBýÆíŪXãe\ķģw𹕋@›Éŧ:ú@RŠĀ|5Ļe Pý‹―€ČpÐ" F˜ąĸĪ…čTūe‘ŠmÕ:Qd‘·($_ífeAP š+ŨĄde… Ī*pņoPļŽ&Č_žag‰7Ë )Vą‰_Õ„ EēH’ €ýëu.ÓBDīˆ2nTī’Ä›dES­cO"Ļø°Ą OūØË6ŽC$ ĀņY-JKKę3ĢÕj##Ģõz]ŅĒEdYþíŋƓ’’Ų AÓŧ§§Î^mðÕč‚: >•úātŋ‰įĶė\\ĮĮĻ?"44cėëë›ûšNŧkį™(ð(ZąCc„#øĖ)ˆ2QdĀq/_įˎ<ĻÕ*ĀïÆēlxx!ĪpaoAĸqŦZščPE_ Bũo*EÔ§KŨŲzĻū§›îŊß šĪ•$ĐB…bQ—Cēãž}‹hõ cøĖ) Č@^yõFŒ]Đ~9éĸąwũ~úüáøļëâ2Æ)ú.GŽH)vî—ïÞ<~þâ‘ÔrՅ͛››‡‡‡:ˍ*ŠĒišøÃt:ŲûōõŦ'?/."ĮĪ˜N§ģõĩņd|―đ‘Zc· rŽQQ”eƒ”/ áā ĀmåĘGĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jG_‘~  OS™s^‘Ô’sŪŠj>Ÿ·mýEQUgeygRKŨuÛÛũNNūœGŸmÛíî>ėš<øÔRŨõÖÖ݃ƒýœĢW€”ĒiÚšŪãZæ7 €˜ ĩR €ÔH-ĀĘĮĸ ĨH1H9Gîĸ€.įĶĶ―ĖÖ°ŒF1)R‘"%ЅU”s^Eu›įßŧŊįÍâGŨæ–õq<ØïlåZúEjaEĪ”–ËåééébąĻëšĸ_;›ÍvþcįÜÃĒŠú=ūÖūĖ Ã0Ã0Üfžkˆ—LĄ)ĖšûR ÔýlԐ›ķøČZ oņíþâ’ĪY]ý5­ŪĨ/9ûúŽÏžÛŌ$ķĨ—$­ĖqIZvïžQ ņ3kzÅ˜ļöäúBWu” Ąk@!lĀ2 FČYvS݄72M'(JdÕĘČt@hĄâQŪōú‰ÝU†ÛWDë$ ŽC„)―{íDöúŒËĨ‚ąũÐĨ)ËûĻ1Ą€!N+…uí>dXpŊžaœgĐúåí·Þ,ŦUyGeåĶöëėUuû\ʂÔ+uķN=ûoy CayT—·zÉFŊ‘‰‰ĢŸ’$ü§U ĻËûΊÜvÝīüöK1zÚÚå“ jŒ<‚GžŌ™`tįŌ‘ÍëŨæUJA#–§$ũ7Á=ïŽÉg˜ú›GOUõ\‘ĩi\xcîá/•Ÿžq騒ĖĪ+GŋqtÆæïM?\ŲT}zðXQoe­˜Ĩ­ŧļtՙ„uóÂ5Âg.Ļų·•o 8uāýÍYŸ•ëÃĶĶ`ÂwŠÅM‘ąŽZ™Ž iĒĨ›VŦUčĪ•v—& Ë;ŠÎ]ÁÅ$Ø2IŒgė6 u`ČB|wӜõGmí- mđŦmSČ@(!Ä­j)Ff‹=Ē_D‘P !^aŋóvBŠũčĪÏrg-š2cņĮ?ėšV•~ÏĸĒ”mÛšmŋóŦïĮ­Ũ§kÍ3/%%Ž7Đ­įΜņŽÂÍŸŋŧņđ7’ßۜļ`îšó“§Ä1Ug/_žŠ!ļ$?ŊĪēĸōÕėÔéûö{ŸM™ģ,{čŨë|Yw{ƒ€ŌT•UÛ‘‘ŧZQAî`X, IHpƒXNúdm:?Ęŋ ÔfLûËŋûüfOzųðĖ3uķoˆ!戈1Ņ‚ęYvðČ}}!éųĀC{sŊäŨV”Y‡‹ĩ5Ĩ5įō=7žÞËĻąˆ>€ ”mÜ·lš&lôî] čpĪ•!ôČ V”΁Œģ‘ØėΒE ˜B^Ŗ_;W.'ūëãc˜3iäņ„ĸ)2OlÄ8~ŅęIÞ>vŌð=DĖûvVû(CPļE”$QkŅolH›ãîôÕhm6ŦĻ Ģ"X%‰uôówŸ?ŽŽx/iīJ–ĘÐûAįA0uÓÕ ÅSđŦ•‘鐊mĨŦĨk|ę+ËœĘ[6f€JÅV]đ`öŠėîĮÛŦŠęØūũ*ËĖžBÁL óãcÜwÄ𓇔ÚģóëïüXoL[5mŨ’BáĐæ‹ËĘĨČÞHī(Éãđq“ÎîüûŪ!ĐģÆ+ˆĸt€šKrŋb™P“ņtÎɓĸųę˜>,A6söôUXŠî=äzøVW”YT % ,mĒ(H˜ã(!X’„š+† ƒ Ĩ€'"äü!ē;`#”Rėœeĩ_Đĩ Úë—.›ĢĐ>0„ŨÖÏL^áĢcX…Ü§#ōg~=Æ™v/bâŨíųÜQŧRĖ[đ~K֖cŨËŊИ"_Š3|ļ%mcæęeđzMųk˜†#īŲT„#ĸØšxþė/‹-cbžÖóôAAÞÁ/vÝŠüéäé{LŨ„„AŧŨ'%§ŊÏØœsŧFDvŧ6rŌĶ”ųŨķÏYýÁō,üW$~ÐËSgF<˜5uVÚÆėė‹Roģ―GÅér6ŽÚ”đ*yÛåČiņ!j(Ųl.)Bˆŧ]DAcŊî7v~ó鍘Ą›Kų„ĩ™EL]#į|LĻŌĒąf§ŊL]ļæ§š*"ŠáÏÆGõ?ÎÚqøČûöo°u9ĘY­ŒLþ hŠFÎÎ ísô܍"ģ L^š1øđ‘z,HÞÔûØņâęÆĐəqŅ‘,ÁB@‰ęßŲ\\Z- šî•CE‡áÔĪZąĖŸ+Ģædëš)ŽŽSBýžŊū6ÅU!ÅĒ(b{=;`I”ąOt0@‚„€J?vü”g―ūą/`ÁN4Ý_0‡ ĻøžóŠ3s@,Á˜B–"AÄï2vúL@(„Äa(nėÕlÛ? t.##ó#ÂŋĢĢĢ Bč ϔ!„<ϗ6á<īáw†”5ā3·kíC{ú9Ãdul^ú·W(xŽīuqEį Íų C{úėĪT+ ĄrW+#ÓþqšK§ÓåįįwéŌEĢŅ<áAÆļēēēĻĻ(44ÔÍË1 īJ&DÏßŊ­ŋRôā~ĢVĐä(íčC‹PR]gôRzą(•™ËēNÉž?^’Ī'åۖƒOOO“ÉôõjîMÕ Ð5ĀĢŅĶŧUmĐ,ŽuéŦ]ÁBbÔrýB―ý―X–Tdd:cI’(ĨíâoĮq À@˜ÖZpeĢXoÃö…ŠgŒ:.PËĸģ―;ķa„Â0HÞĖėÂFô á7ԉ‰â ,…Â֝äūæYü—ž—Ú;ÁŒ8fzésĖ[ÞÄ^kÎbfįųÍtŅūi<АZĪ@jˆmÛ""-@ęŲZëCmVtvŒQkM9įRJk­ũūĸ ―ũÖZ)%įüiž ö,ßXIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-tutorial-files.png0100777000000000000000000000623313761647206021352 0ustar00‰PNG  IHDRą_đÖPLTEJ29K?CIFPIN[KSiQSpYPl_JadGXqLQ€TPˆXP_Q‘hS‘l[‰nc}monq€erbu•b| dƒŠg‹ēm’đv™š~œĩŠžĻ“žœ™œœœœ  ĻĪ § ›§–Ĩ’ĶŽyЍoēŽjŧ–eÂĄ\ÆĐWČ­PĖģPзUÓšVÔ―[ŨŋZÚÁYÛÃ_ÜÅeÜĮkÝĮqÝËxáÏzäԁäԆâ҈áʍÝđÕū“Éš›ÂšĻģđžŊﯰđČŊšÉŪšÉŽšÉĨŧ˚žÏ•ūԑĀܒÅä‘Įč˜ÍęŸÓęĨŨîŠØîģŲíŧÛėžØã―ÖŲÂÕÎĮŨÅÎŨÁØÖđÞÖēßÖŦâØĪåŲæŲ™éܖėߕîá”ïâ–ðä™ōįôęŸõė öíĒöîĪũîĻöíŦøîŊøðēøņīøņ·øóŧũņūóðÁïíÃîėÅėęÆėįĮėäÉëâÉæāĖäßÍâÝĖßÝÏÝÜÓÚÚØŲÛÛŨÜÞÔÝãÐßįŅÞįÔāčÚâčßäįåææææįįįįįįįææįåææåååæææææåæææææææææįččęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęëëëííííííííííííėėėëėėėėėíîîîîîîïïïïïïïîïïïîïðíðņðņņōņņōņņōōņōōōōōōōōōōōņōņņōņðōņîóðæóðáôðÞõðŲõïÕõðŌũņÓųôÕúõÕúöÕûųÖûûÚûúßúųåúøčųũëũöîõõōôõóôõôôõõôõõõööõöööũũõööõööõööõööõööõööõööõööũũũøøũøøũøøũøøũųųøųųųúúúûûûûûûûûûûûûûûûúüûųüüũüüðúüėųüčøüâöüßôüæöüðųüøûüûüûüüúüûøüûũüûöûúõûûöûûũüûûüüûüüûüüûüüüüüüüüüüüüüüü;|Á pHYsÄÄ•+ AIDATxÚíš_LZYĮ/ pTŠNĨōŊVEž\[ÄN7*š`QЊōGhýŌZĸT'jhgēéÆÎƒ}ņ͘8ŧóÐØdÍ$[ŠZ[!úЗ>ī„dgŨ.ÕīՙdÂËÞ{iwĶ;NģKQïMü搛_Î>^ũ|ïđ_ įĖ™3ŸF,pôÉÔMâhvf8:;óäiĒZęr:ŧu0ütŸ„OÍ?JX]CíöxlþGû$Œøöã„Õå^ŲV–ŧÜօĮûĪ8ņzÂršÝkŠ2G'ž€•ß~ģþÞŅRŠ;ĪŨ“Ē8ņ|Ârļ{r•Í bĨ™nϗ†ĸčëį“Ąo0âŊo'ŽŽžŪ‹…rĩ‚°Rdœ;öųā1ĀohIãÖÞæekhsŦ.‚õ·“Ąų8ņ­„eïrvČ!Ļ­ ++ČÕfšŅLYÍL(Ĩ‰Å71uÃZ1ŊŽŋ• ÝÆˆg—Õaƒ KKĖeX‰Ė īŅL ―9Å8ÃŪfÕ\fÖhHÕÖÏ$C·0âŲé„eąÁЉ‚’mV"ļ­āYMŠ Ô·’ôCŒ*VM?3‹“UA3†édh#žN| ‚aH…įT`år2Ų™ÚĀĒTÉ@ðJ\-Č\äoHޚ75}=a•—)(qIŲõýŅTœx"aœRækĖæÖ‘‰ýŅM”xzęOņÃ##cû'ŒxýžÛ4J[Ÿ&Œ°kEėãyýúGTŊ#ą=V$9đ ó‚ ķŲlÖ~ĒßŋðāžĨÝãqY BŧÁ―bUYÝݖ]ŧßĖ?þö9þˆ-JØŲŅū[ï튜Z/âå .OŧēÃðÚ.―ŦŽ:Ü͊egWOyĄJ­VõĄåO6)ó+‰lXaĨ‚ €\-6 pČÜę-žßëpZ• ĨōĘ Z9‚XŽæmĢ™][J#Ŧn•Ĩ“f~É⇨f‡KO””–ĄåS‹äGRMāŲ0N,ŪIņCž[Ôōˆ…ŦÁˆŨ$™_Ŋ·Ņ^ĸÏÄԌ&~ˆ—\xĒĻĪ8g(þ[ãsųdjtE]ázEgĒģCĐÚüœã2eiJŽZúÐ(fõũx!ÞYhUj–ü~ßģßē­!‘xQÜ\ÝöO‡ÄÄ!Þ ,//ß[\\ÅmÎũÚՎN§Ģ8þØī–ŧ=. ąüąĨįünnóÍðÕ-<?h“ÃNûnÄÛēĖMüđÍļ?ķĐÕ hųęoœûîÉôÍõØģĐÉ;ēˇģ|“s‘73SYÜ™œûōÚ:Xbg—*TŠĄrĖmØ4RŠą™MĘxXRtēLĩAJJņšA I0ÄĄÐš˜”Ėč#þØĶ((UžõĮv†Ģ[ƒÔs`=2+ČČōŽá:IÖ]ķ  ‘rČĩ폭6Ô—”6ʼnu!éqf·…EˆôĮ.Z%ģF\”ōĐMĢ“ĢlþÁžãE5 !Þ­(ë-15Ö áIĻ^_xU–)ÉÐP>!Õ§% Ė`ķ°I›Įŧv°þ‚âþļ">+8žœŠGWōē?}đ”—clnô ―9BŊ_˜ĮČ k?É1 sĸy Ä~HQ\pĒXĄ(ũĮ‰uŧú)üe3Xów|8ĄÅķ“#áwÕZ^ý’ĩqč݉ņNžÜ‹Čír]~FâH§§ŨŧzÝÖQÎq§{%Ī„{ݖ5âŧƒŠ2g—úĸ ä}`―æũ–ØévݗŦėvČĸŋŋg…aøíÎ_näŪr É'vļš.*`5wöŊ†…ÂĻ_˜ÛøhÄ$üýˆðôËØvģ7ķÔčÓæ6ĩ•đÆØĒP‚ÚÜ3›ÃÚÓ/bþJ­ðęšķēaPˆtú…BFíHÃӑ†įW„B-q5éÄoà íPÜnĪōrŊÉxbZƒ”"đ"°æûm™ v\PÁĨ7Јø9‡ÄV‹šÝNŪ@ËûŽš &ĩZƒŸĪ~ÆĀņå·áyFüú‰ę+H)éŅßQM X?bHĐ@à % /ā‰84Ð./Ð õ ,>%ŠŠė„ÃOö$ÃyčÝKüchmm y…vˆâ6ïŸïķĐ;ö~Ē/wz áÞ+Qfę6-*ŦËI,Œ„{í–_ũ*Ģ8$~ëmjØũŦūīČ{Eėėꆐp/]Žß€p> ūlf’xl€jd“Ļ/qæÝ°ð‚B ÅÝæ*+c€$ļ$)bš9Į­â„ įžųc\ŒļMå;â:Žé8<áé~Ðx‘‘ÃĀq/Čģ~I\+Ģ6ũšST- gėÕņðBQF.ኌ8›*î-..[ Čõ8:Đjņ…B;‚šÍũ‰ĸ }Īɰá†xtIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-tutorial-introduction-page.png0100777000000000000000000005213513761647206023705 0ustar00‰PNG  IHDRÎ&ëņp_T$IDATxėÖQ ‚1FŅob“Œ=ÂJĸômu a+h &œSâÞü(aJĩ'9ēÖ=IÏ6(mÔ0åsŧ^ēŌóõ67›9å€p€p€pįĮ—ó’Ŧ:óýï†Î=ӓ4Ģ‘†‘„2J !°Áƒ `Āäd Ö[^ۋkĐÚũ^―ÚįÚ}ö:Ŋ―^ōÆXˆ` ™Œ˜$Y`„ĨĨ šÔáæ{>Ĩ[ÕuŠoĩģŪýŠšnßŊOüßïœ/Ûsū#ššščîîĶąą•„hšV“_ŸˆęŠmĐ<ĩ݈Ûf†ōzĻõ]ķÞi·ĘĮAÏßø‚øĪá•ûKâŊ^u\J―Ošü.Þq8Vó ĸúϓčũĸúí֓•˜ú?þIŸdüĢûŋ:üĮÆÆčééahhģĄĄA*ÍD"AĐTŠž –ÚąRĪØâ6ĩ\­>Ģ{ųĐ/õM5OSô Ã0ŪŊÃôî†c™ÖīË/ņڞû9*—ËĸLĸę|u]Wæĸ=jGÁō“"ĸ‡‚ĮaãÝ$þQ―xüãŋŨÅ_ýŪÖQûŪAH~= âžð‘āŅĸWüãųþĸŋԑ“&MBŪŲ͛7‹t:M@4ÐęÍMCŦjīš p0–ę)Öz`QŲwDēĒ Œ*âÐņWžZ>ķ,+CA  h˜ “ÐũuņäŋúMÃ4eMÓ1M]ķaœŧéDøĻýFÏ!ĪŌ$ Ņ5―^˜:wþf"!Ÿ5<Ũž·ŠýPûáÉŋZ>šÔwuŲØõŊh>zük?ÞųˆÃ_Ŋå,|øGžĸčū.þu”nÔG þQųü%ör ›ūïŦ…ĢžŲ·kk{”oū?<„‘ÏÓfΒåãĀ-‹lذÁÁAđų†!sĻģfÍbüøņ5ÃTííÛÅÓŊŽāݝĪ䌑Nd˜Ō6›3O8Đ“fĒĄÉ6#@ŠBœUQÓE‚ ‡:ų‰~?ÔÜÞĩsNwÓ,T Aā…˜IzΆ*b”^Ý2u[MĨ§zaj(ˆÅ_5H$ð­!vl`üī#iHtœÁķöđL™ÞERPðŊ5ŸZsRËEŋGžz‘ĩ-ÝÔyũđ§ŲŲ6ģį·ÓûÞŒķ ī哈?膎øAˆæÛlÛ;@Cû i3.œ…đjâāYÃl(ŅÖ1žŒ "Æ#‰ęVá/P A TBÆ:^y'Ïý~#Ÿ:c þûϰūŋ“3N? -ĩ<ÖØP˜ŪCÏÆ?ąqĮ^Ėd#3įĖĢĢ)EXĩEĪ&:Bþ&jüÔ M֕E.%ÆOIKDüXüã##ņø+mÔą!ûjžšÆ"ŠĮŋūüŦ8FŨĸęqŦÆŽŠÄÓâņöƒÆŋšMu‡‹ŋM@ Ŋ ēęį?Ģ­o—Ÿ}-Į-ĶôÞûžýŧ'xîßįīo~‹ŪŲsð<7jL*Į d^n͚5är9N<ņDZ[[ebõð0kŨŪåØcĨĢĢÕĘÖÐęį'þƒ 0ÆU—]ÄíóŲʓŊŊāÎ?âÚsŋÎÔ#fаæƒQ…HĩTĨĻZ! ÐŅžb°BŠrܰëUĐ8wî`ãķ·9}ņyHßDžĮÍS“‚ŋ"H1 ByÞęoJ™š› pPø 4pFxéŅÃ>æZn8giQâ{o§§ãLþazA•Ą ÂQ…\)ō’DU߇ę1‡!č:ZTFÓЉ,MyQ5~Ųžn°ãõUŽ9j"į.Čó›ûîfō%ËY3[‘UÂ4ũ+CĀCt ölÛBÉleÆäņˆą<ýā#ĖXz='Îi" 5 D?„5 uƒŨ ƒą­ïpũĘwđäšk˜ÝŽr§hîûŸüDs ÜQ6nîeÂĖyLŸPv š&ö?? §<ČËÏ=ό“Î"Üþ2Ïŋqų$ūwŨãė8åhwŽbÝfƒŊņhð}ėō0ƒCE„™a\{+IŦ„åB6›FÃ%‡Bcx–/ö(6iZ››Ð"eč;ŒPqōMm45Ī!ð°J„ŪQ!H50Ū­ íÏüēĶAex˜ Ý@[kÉ Ų˜Ē€Š“äâŊÞLēĄ7ßfp`ĮÉ7·QČ&ØŨ?ĀhÉ"•-ÐÜ܀éōęïî`“8š/^yų \pÝW0Ó9遊ĀĶŋo74)īĩҘ6ņËvI˜‚Ą‘2ŲB …\É­Ü| kQīCšËÐh…tCB6ƒŪAqϟ‘b#•Ĩĩ­•ŅݛøåCOsÞۙ;Ą-°#ÐL Í­4dd2ĐĀīDŽT.…ïhø ũíeĖŅiliĨ)›ÄsJT\0…Íū Œk)2446­y ģð9n―år‚‘+ą5,/Ä.{wũáÚÛ[Ië>·’‡­#øÛ/œHG[3ļe|=M6Āw*T|ƒ†\·4FĻ›ØÅal‘Īĩĩ”!Óĸ0 Ģk$Óõ‹‡-ĸUҜØüŊš_ŊáĩFûOd$ŞëPÃĒ*ŊšT%V/Ýãû~ėþŅ_3þ2õ(™ŠõîfSdzvā‹hé ÂsŅFGXIōÂû›°‹EēÍÍÅĄģģŨuåwÃ0ÃPÞ···ģeË,˒ ī(BAïČfšŽĮ Ó―Û!i$ņC’]ĒkFŧßėĄbUČgU™Ļ GNåŦ–}ÝXšj•Ô#MŨÐ GÞø>"FRãP(2fĒ z~ĩōņáĒš‡QĒ~™ˆÍÔÅ_=ĄT4Ž\|2 VŋƊe“-ndņ—Óݘ ļ{3ÝõKöčI)+Sæ-åē 3ðÖjyßāšË—č[Į,ŸëŋzÞ{/ņĀ3oā8“įĖĨž…áÚh†ÉĀæWųÕëĄÅĻĮ—nü 3Z\~wĮŋģÕŨI–+l…ģ/đŽóNjâ‰;Îß %ųK.ųKN™„rŠbŒ•ũÞÁøsnäīIÏwį/ÜÂĘÛūĮï'ÃĨœFCĶĄš6ïūūŠWþļD#`$ð—@HŲÅũ=D(€§\ÄJhl{ý1~ņGžë ) nĐHšcĮχ]ķpý ’ôD†Ó/š™ĮūÅ/o€G–g9ýČBkŒįž“DÐØŌ…æš`jIp,Sũ 5„&į ZMG>{ô GΙOAũmžHÚHQī˜:IĶÆéURCĀ)OCŨÁ!‘“ŊxUhãój">*??5ų'@@]ücú9ÅLŌCÃrÐ ™c[ũöfN˜5‰ÄÐvÆöīäL‚þĮq*Ã머c"‰ŪƒôÐĶTąHkrąĶcc<―ōŽcŪäÏϏĸųG„ ?Ē čÛĩŦĢ›mķ’Ht2ą ņ!>äïĄü!˟ųÉ ŅĪóŽÐöžMĮu …&ôÁwxoũĶķšTĘ›Ũ>ÉĶr·~ëVýäóž|î>šŪ3ŠãûčAˆB’Ëdîéaį`™‰ú^voïĢå˜,Ą°Ð5!ēcļ€BŪQĐ8ߓ9G]—ó!`j>år [ũИ):>§]ugnäĸüÓ}ž9§tØ^€ãzXå­<üĖūðÍ[9&ņ?šãy4Ąá{‘€Ð04HæiÄdâI—põéÓ ]‹Ņ’ÍČ hūFđXS@īĶ4Ųģ‹álqįqæ‰Ý,{kˆ “ŧÉ4õs֕7püĪœJ‰ēã1XÔ]ŸœéJCÓõ\Æú>`ýĶ^ČÍÛŋBŠŧ{ķšę݁–4hΙļžO(P)VþÕT„*›ęZR"SąëĪÚģ‹?KėáÄzû:6u>ŠIüխޏÕČą'^ât„],þÕĘõØMŨuÕ!|Ÿ–yóą-Ö ÐíøÐĻø!;ĮŠ tN íÓ'â AčyčŅ@hiiaßū}ėØąCþ+QĄPÞæÎ;fÜļqĩ lcJĮlÜ=eķžÕ‹69E[‹`ī8Âæí―čĢmĖî^ )luq@“•ņ@ zouĸFęã&5Ēz}q1újaŒ 9ŦüŊčt\ÍvŦïUüŦŒŊúø{ū'ó™.&GŸ°”mũ/ã?o lsäqį3·-‹eMD{é îđgų„M"1‰Āód?žëa!…fšyÓ'ēōõåü˖f]Öŋü ]­g’ÓŊ=þkúÖ·°oŊÏé—_MÚąI†!ŊüöAúŨ·1ļŨ•üŽo„žïcÐ}˧YŌ·åũÝEGĢAnęg8Ąë(oŽâ§?ü>É0ĮލëŲØ3‡î9ĮņڃÏrïÝ-\tV'šžÁó&Ï;“·þ†‡îü&>fÃ<ۜ3ŋw= iĪ@čI‰§øŌc%ē”…^·íúh|Ï#L€Ðč ũūË}ŋļģ!Ý9]M„ĶÉäF›ewßÃŲK?ËąSRjsÞ9K™4ģ›_\ÎíZČIô\ˆĖï!=Ŋ>ÁîZGihĮœqSō!ķ ’ÎSũ™jVåŋ:ēŅĄČœB‰;ÅĐė?uÏ/Ļ'âĸGULę ŨšŊœEÆ:ņûOÍ}åPņũ<ï/‰ÖņøG΋ķzõjQmuD?ĶIÚ4qzvPŲŲ‹_*Ą§Ód;'<Į0ð̉VݧR)y‚Öē,Ų^ÄËår ÕšĐþžÎ$Ų;ē•þŅØ^‰Ī™Ķ5ßÅøæičĄ)7 .>û·qq‰ņˆ§ZCÕĘG­ĸ­5ß8āō뀓ÛoæĖų—°uïFîxë&Ōyģî?ýðøŦųÕÂRņWįĨū·VS•puu((z~ú.ہá@.ŸÆó=ÛEū0ŸL‘MjŒŒ–Ðiō)J#cé,žþė;öą=fr­ûËRÚíßݧ2{(ĢŪÉöŸ;ežæyÞ­ŪNåã5w ÉÓkzO­5ÎąĐQuæįŋïÝŲfŲųXČ?—Ã|—û•'z§Ûj‹ÆÅöoŧïķuųÝÎåÐößčžļ6§gó4;<ŪŅåuÃöq§ýũ<óóĮ0ÂåŋÆßô‹ų''';P˜]ßü`Ž?·Î~Íē9ē|œ WÞ)åØÁ …“åÕäؚÆ+ũ›ŸŋžÝqēfóⷛrņëŦÂzįÃwķåíĮŠ7ēîvœß~ô]nøÚĄ-“ü―ZŸsøĮ4ÆÛĀ ü­Ŋâ§ęĨÉ_ý9ÏþY˜0Šķģ>Y“UÏĐš|åĒz7VØá%ÖóæEđļĒó]E[ņ?ü™üSYĸĄ`;+ōyВ§Û"ĸ憌XOthƒü;Aý―SZr;p`“GųĄÉIŽÁþĄžYß)eĢÔÅå+âîƒï Qþ!šęsų·ÖėAųƒų+ŨãïúiX‡_ŊÖsÚŋņ™“sęôeþ:øÛg,æŋaŒ• ėJdŦ; ųņÁT)‰8îsž'IïĶâ-lÎÔ@:ōáJØÝĶQũwE(~'M|ˆc‡ĢėąąSųč4mĖ}čBVĪ·ŒōˆÓœrŅÞ؁WSč,é()þf;tÛ3āĄ[&Ý øÃÛreþܗž "ŋYüˆÖlˆ‹ü­ŨČ_ų.ĸ8[Aˆü‘ÕĘEyÉ7ōį?ōŽuí5xq$ūđūæŽXŒ ·˰Ŧ—ĩ}žÅÜþ§øËFþØL›']ōþĸ(Ÿų“öQNd”ž*ņæmū„ÐþIŊ,é‘Ĩ\č5mõõ*ïÚéýÝ /ŊÄk[%?í7ŸČe”?ŅWW*‹ÍMvœäG:ė„7úĶų9XfđķÏaÍÓĀKųÏ=ëWþČÜĩĸr?üÓÔóAü}æiŧÁīÄa—ü­įĖ?zpÚ:‡ŋmĩÅßįÛ}ð—ĩü Ú §ĖŸgęæėė,đäísþP.ž^P Yā{mÜë[AĶļteŋ„ÜĐÎ TÔօÏŌp~~žë§Ë?ŨSö,Ã―œŋml)tæāĻm:JÖ;ŋý·cÕÓāïũŨΟXĩŽ#;˜f`vŧ›g[Ęc’ŋý~[ÏĸüģGÕģ-ÍJÍkĸ;þýmíßðŊâĸ'{ũ%E•>lüđ·Šš{†˜†œģÁE@2kŽ@ɊJTI% ’3DÉ"Š"HP@EPEI2Ā09uĻp?čðœ]ũÛ]ýęwNė·šęĶ:óz+č;wÆõĸoÁôyüÜņųeŋå•Ï.·ĸ]Ūð\ŋ_ŋŊņqđ\.—ÎÄõD,ų|ņŊ^Æï‹ËårđDJJŠÂårđ\.ŨŋEârđ\.—ëϗ8].—Ëår§Ëårđ\nâtđ\.—ËMœ.WÞCÔĨ~\šáÁĄ‰žįkšDðŋ•ũĖY!ļ–Ëå&N— ĐéÛ"5å>˜Kŧæ‘ZP9>īPB⍌Ē`Á‚DG'$%tždētÖ8^yõ5~ FaH/’Ŋ€Äëóáó" u""#ðz=^_Þ65!øÏ)LÓ ZۉÏMdû–iĖ_―o2~ú–Iģß ―ō=Ô.‹ã(4ÝCĻ‚áē DFäKĶÃAd„) nx‰ ĸáķāóy1 QŅ14ŨÎÞÃï،.xąŒ(|ARũ„·g:ވá:Dú<ų—‡ËŨ/nĢ@ÔĨåáõQ Į&üpĮÁ‘ļĐ^Cš7ĐOÉhËQ€ĀðøˆŽ.Hx݈pŋ#ÂýŽŒŽÆkč—ĘóbûšÉ#_bôīuˆč(ΐ.s=-ĸނÚåâ(4#ŋųōú-Ü/‘x=šnÓHt)pđÜÄéúÓBâO9ɞœ Åk4`ÞØ‰ž1íMÞ_3‰ú•Ģą•DųÓXņzZ·nÍSÏ â`Râ§=3öuÞ|{ óf―É7ĮS1s’ųpŅ$&/ßBŽ-ŅĖdÖ,^ĀÜųkH jØį0{âtVū·…ÏޛOÛ6mxķĸNd›hšä?åX"Jߐ~]ŅI,ž9•}‰Y|8ĢëKóúÐ.”ŒÔ†ÆĐý›Üïąp{ŒÍ‘”š&Á ēsÕlÆÍ]ĘĐī >`ß§kycÂ<R,ôāyV-œÏ›‹ÞcÏŪyŪ{{ķÍž*é )H:ú óÆ åÉG[ÓúąūžõņŨø….?·…IcĶóŲž―,›2ˆ6mcÜÂɕRÓ8ģo“Ķ/`ĸ‘C,ô\xųÄ7wT—Î7 āØPšA#îjQ4l%ЄŞŅĩããī}Ž #§Ŋâl–Efâ~fŽÁãmÚÐĶc7Vî8„- Ī™ÁĘi;eoΝĀĪyïq*-@ŅĒhŅ %E Eá8š!9ņõĮžŌ§Mļß―ū€ŸŌĖpŋŲ9‰,Ÿ:ŽåwņÓwŸŅũBÝ^ĮþD?RJ\Ū?Uâtđ”Rx — Hœ“ŧ7ņxįųpŨ!,ĢŅQØiĮyýåNô숭`ÕÂé<Ôa(ĮÓÓØĩk')~lÞ_0‹ïOĪcgž`å„Á šš‰tKbØéĖž9–W_Ïņ,•q˜c†ðl·<Ųo$ïŋ·†y“Gqß ó8“ë WR ŋhýęOš&øGVÐææöOÓĩa Éûķņڀįxa~·ÝۋĩËĄkŠ„mģhŨæ &ŋĩ-û2sÄËīmû8ĸWúŲ2gÆÏ'ážIĪaēcËr }‘―‰9N:ģgMāųūOōhÛ§xkÍGœLp%74ā‹ņ˜°pŧ3ōåæ7yîĐŒ[đŸ‘GŋßĖāáhÛęM\š5ŦyĩßÓtŸþšĮKJÂFF zžûîmÅ đKyũÂōýÚ1ōmØB㠁Ūåōþļáô~y ß%…ˆ~VLėÍÃúētåûlúds'māÔÏŲ$|―–Isß%ņÜ96Ū]JvíYąãSøō‡Ã8üi'X°h‰Y ߎįđþ}ØðíQž‘^v,―ÐOubęōílŲý5Ó.ôIÛöØ{ÆB3ϰhÄHzu|„{ëÎâuïēxęŦt―‚\ .ŨŸéYĩ.—ēˆ(z3sĮöㅁÓŲ―b Ž‹výÆ0īwk’vŋÏä%ŸQąÝ(6MęČš7^Ēûč9ŽŲӋ~]z2oŲūOaî†ÍÜQ1‚ÔŸķ#Īm*$€˜ķ…iQŠðũ`ȏUšþ“Ōžāa^čü ŸŽœÆW}Úð@õ8lĨ’Pæ)ÖŊĸËtļLˆHnžĨ!åŠGĄ‡+īČrt|a0tzžĩïžMLÍ;yþĨ‡ˆī-‚) ž=oû ^]ö/ÝS‘ų] įŠmĖ™úÍf=Žn„pB\ŠŦƒíq” Ų!BJpëCO3 ûc-—ïüŪÂBĢc؇ĄÃW‹{ÓęĨĩüļóü]ę‚[YėoÉĖÃČxg(ÝßXÆ7oÏäDũ;ðč^Ė Cņę2eboB;gŅĨßĖ™ŧ‘ūO܊@G€a™8&čhdĸŒaŊ-# sįÏæáFeH:—JčPúv~ÕŸąyŲÚ=?C'OĒZÞÏ —{ącĸK;ąņà Ũžo[ØĘFI óėũ˘ŧš’"ymõGômÏīōšOXšrC;ĮkÚä<ôėhzÕUtoߍýkwqöĩ'Ļ%PŠßŨâoąä›_ĸÜętt§ëÏÍV[ŋĖÚęÍXšd#gŪ`҈^8Qq<“L.pjûbmõ?Ÿü€Ŋ~LÆļ5ĄišGG!ÂßÉ{áĩ@“W_ykáú–·ÐꞆ”2‹ÓīÕÍ|2kiđ~ų‰™|€‰ý‘ęŅ€Ā!ÝĮÐóčTšvČ!?ӆÝK·‡W0ėÍ]tč;˜[Ëø؊œĖ4Î? Z=ŨĐHHEŅė‰û+ū$9ók2ýíR@ūũęB^s1TĄŌ•čųŌjĩð›VūĪ š õį/;`'Î͐rö  ]sũgŸ Aõ*˜ZQfÅ:N‡~&7č p°žEčúTWîŪ]™ģē95ãß`į œÏĩŊ‘ ‘ũÉL=Ëiîhý-]N6EŠF Øŧ}+ã§/åėŲTrē3€Ô Ð5/BhHéC3 îėŒŌ’’ÁیÆ7•'(―īčxŽû–Ó) dJâXEZfN&gO'Aūä)HĄpė –mĢy„f@z/ĖŧۏðhŋQžŌåï€Bhz8 å Ã#dĪ †ķAļ iāõ Ұ­~ˆˆ§€7žüŸ’R +5‹`HâõEāõx1ÓÕĐ7›Ž*ÚũËāîP†&JŲ€BH‰/ÂŽå€ca;ÐPB#ōbŋe§ …” ôhčķƒe98Ž—˝qšþ”WÕîgŅGĐPĐ2Ĩ‹iüt2_Ī—RŠSŠ$ėĸãÉÍĻWĨ(I'“Q ŨĮx‰Q’Žô4Ö/[Mé6·cD Eyāû/Yđh6_­›ËþãéĐTšËtC’x4-Û>ĢpâGlÜü=ĒčíÜPš0ŽâjšøR‘ĨōfBB(ĮųošwplË2Q€ē •Žū uåÏXī`)ōŽŠŽ_―Iĩšw!ŅĒc í$/[ĘÖs˜ž|ŌqÍömGâšóąô3œ<“J‘ø{(ããÐáý€IRŌ1’2üŧ·~ĖĩbØ―č-NœģĻpĮ”.(9†@ó'ąõ­ÅÔ/r7ß/_ÎÞóPąýM”Œ40óúP`Đ+u*Xž ÕKÁįK—1ĐL)ÚÝ{=gÎYT-i‘‘â§ĖÅ(QHąÓdGũ#é~)-,;DîųïųāƒÏļí–ëōŽ8–ELŲęÔĻT‘]‰›YļāėæEX―z5āå†ëPȰ1\;&.—›8]ÂŦj­ĖéŨ·;AŅxIRrĸޞ!ï v•xޚ›Ė€g‡ō|ĮÍ(ENF6§}7üÞãŧ'2e@üū•LčڜûjÅÚ}ËyųđŊhüČ”/}’Ô`]ĻðŒPrîāA^zļ5iþs8EŠ0zö0j–ð…ÞÕT8öĸ)oĄJŲØū"<Þs8§S^dúk―ygXfIÚŋ4‘z܆Ątnoó o}2šcûr]ËĮļûö›ųpã4]Ót‰'Ō#ÃÉ*?Į Q tmÚßw+#Žå‰{wpĮ―-ĻíYÁĖc㗭)ačė|į:―ŋSŲYTjô(ĢĮdŨÐIĘ ]X^2ņ‘äfYÜ9`Ÿ?;„čâeÉę<ģd-­M(Q:"<•oíÄÂu 9v.•)ˆ.R‚ŠåJrëØY4ëv[‹ĶjÕēœ;҇Ôl‹J#q"cč3jwt>éDPąj1Œj―ØĩŦ#ņ%Jaæ(UĸvFĖŽEûcûMUĻUŠ”%Rw0 ]Įī]ŧDÅRŌÂRe™°ø†Ģ))p6.ũEÖ.—ļöĘžÃ‘ĐIDÞĄŌðŒ.ïJSMĘKŦ8yį<Ĩy1qyđ’ĪZNÅOR­ųƒ|ļvÅD6–ÞŠĸ)ĩplÛB)Ū"äĨú…Ŧķïcļ= .Í(RĘžíhZxÎÅuČsíö…Ę ‚ éðáĒ—yīŨž™ķŠŅîAXAP Ûqš—ï–öĒÉģŦļė^}ļ99Áp=GåŦŧD]ęĐiHĀvōη†c‚0*Ü>ĪDáķæŠ Ŋ—WįžH4MæóĨē/8yý&Ðt '܎Ëû“ Ërpý~Ü6ŊåŊ~qКÏSŲÔmģ›8ĸ'\.!13OēnÃĕŪ@̆ ð(Å_ƒpöÄw|šëÕ4ĢF™b ōßfĢ‘~r7w'rCýĶÔ([čĸ$ņļÜÄĐĶjlcâ|%H œaïųĩŋyâtÕš\ĘÁSĻ<;_‡cYø~‚ŋ GA‰Š7ÓđzB?!Ë&?Ĩlb+4 óõzxyÐt—ë7ÕĒĖ3Ô+u7^=’üš—{œ·žÂyĸîĄZ—Ëårđ3N€xoešÝ4éRŌžÖáäoxûā‹ņįžqJ~Ëårđ\JAbzö―M ”ËŠmģi7îF–oÍeUãëāØĘ}V­Ëårđ\ķé°þ›ŲôÝŠũūšÔ%ŲþL.;“v+hŧ·Ģüĩđ #üâgũYĒ.— Í#‰ˆ6ˆ4bc#ˆ‰.ÆÝõÛpŲÞwb[Š_âóųøŋ X–išnâüõļI3##ƒC‡Ž iü5đ\.!ĀðHĒã=DÆDGĄkI‹.Āéó'Xýõëė+Ā/Ųĩkŋ―ð­WTŊ~QQ°,ËMœĸ{.)%))iÄÄĒtéR8ŽÃŸ˜ËåÚÍŋ$ĪĀðiŌ ÓąÖ덚’4G/ŠˆXÝü’jÕŠð[Ó4ãĮO––~ž;ãüÕļ„áÄ_Ûķųksđ\‘za:Öž’4ũÝÍĖõƒ°#R‰‰@ũH~IáÂqüÖ C'MĮqÜsœŋ>—R*ïãrđ.s“Ķ?˜ËÉsGx QgŒH‰î•HÝôKũrþŸü-q•WŪ›8].—Ëõ›(yC^ŌˆðFroÃĮÉ/1;ĪÜÂ―å/Ėårđ\ĘQ˜AÅ/ą‚J)ũv”ŋ6—Ëår9|{bŸėXƒ?ÓD)š@ÓB žtbKøˆ*ėé&Îŋ8—Ëåri†ÄĨ_J”Ũ2žĐKũ.—ËårIM­Ģ8ķú§ŋ1|ÚÅÝÄérđ\.ũšG†?ŋũ⠗ËårđÜÄérđ\.—KĮårđ\. Ë-]Yðųü_ŧ 7qþ9ļ\.—Ŧë-Ý—{ĻÖårđ\.7qš~ĸ„ųŋpõWÁ?#ĪDJņ‡~ŦŒĸeåõ™āũHH™W·ĸAĸgíB /í?‚ßÂÕc$þÉ~þ?ĮKíüiļ‰Óåēm›Ü? `‡ƒ\úôûąÅ?8œ<°›ý IHMō[BĒý–+Ά&ĘōÝŪ]> ĮþÍBQVˆėė\2/†m’“ãĮáwFYßĸĮ3‘üđáąüûĪvĨÏĀ!›‹i+þšŪaú38yâ‰IĐ,õŊĮYJþ[ķĀåíŨ!.Ą}Đ E0Ũi™øõŋûŸ3#‰Ý_ĸ@fP!tnâtđ4]'åðô}…„ ð!6/ÍóÓŨ<öiÆ=?‘ïÎæ"… ?)B|ēhãfÄcˆßx†l…rIKËB)þ=üŲiddÂë‹@oū؏Ų?Īc’‡Ð ė”úu}–Ÿ'á5$†īŲ6w$Ŋ/ÚNHó"ŋ]å°nÎ+ŽØpJfzĸžl>š‹ŨóoķW@Nz2ĐY’xĢįģl:œŽņ6Tj‡ķ2č‰ķ<К-ũ6šÅ["tkË3Erzķü§ ÆĐ/Ũðüˆ9œhxe6ģ‡õaȒí y™ßóÚK3øæó ž:šĮ@þcŲžŦËV–IDĐęÔ+Á„Q9îũvøcF-ZKÃŋ7"FÚHÍļf]qН—ū„ë'.Įup―5ų3­Kmņ„ûS Ðt]ŨÃË<ë,ÄŋŽGĮ"Ēt…hö`kŠņaÚ ‘Ŋu]"„@Ũž˜ŊWē|ōpoþÝk`SˆmÛPŦDlšĶãđÔV=_ûÂc{ą.áqį2‰Į°yoÂ8>5ëōþGY4mŠÄ ĐåsáŅ9ôå{žąð}‚^/2\Į+c+4=Ŋ\yiŸŌ Oļýš&ļĖA§X‰Xö}ē'ē1ÓNģņ“ĩĖ[þ]pbĮ[ŽÏQūR-îŋģ)q€ŨÝÐŊjŸvĨÃu$ß8†Ŋ]ęˋm" xã5” øĢs§Ëå8Q%ËSŦf4?$|Gęđã;xõãNeårā‹CÔĐ]“ēq_ŋ7žŧ[6ãÎzēãH:š&A)P‚äýéÕþAš4kĘã]į“ix8ĩo=Z7ĨYÓÆô5›ó!‰ŨČåĄC™:ôíK™C;x}Õ§Ú2yĸpîŠKČžųcûŌĻi3š4ęÁúÝĮŅ ‡·. ĸžOŅž26ŅŊýpN‡žœØą„A“æŌŧKkžð>Ķ’áūM;þ[ÝMģ& yhØBRM JfÅøþž1e$Þؘw?Íw‰YčvËĮŋt!>‚V—ãg2Ņt ”B(@ų9~d?Đđ&š&8ŧįÚ>pgxžšöYAZōFũđŸf͚ðčSIH qîĀFÞœģ˜ ĢÓĩŨÛ ›{vq*ÝD—!ķ.ú›Ðļ~;ĶŊØ †—ôïŨ3xâOEÓõč2|Đķ@p™MĀ‘œõhāĪî―sSĩrčÚē”ûïhNóûZģé`VöO,5„Ų &ņÐ#8››ÆôSŲôí<^/?ŽÍøe[Ð―Š'Žeˈ<ßĪ!7ßҁwķĸœ·Ï8–MlÅĻXč~:JŌÏ ĪËÅp‰“ïĒI“›ð™É>öķäÃ7Įqį=íxōÉÞtiݎą‹6p,éGÓfÍhÚž ė9‹ŨÐ9°i>ƒß˜ĮÓĄÃŽ­˜đįũd[š5iʓŊ-æhúÅdΟ†›8]î”ÓÏ-Ũ]Įá#‡ųúûBĨïĪel|ũŧN§z›8ģs1―|@ũĐoŅĄūÉȁŊ‘!#Ņ 4ތ}<}WW 5eΛ xĐo3|ĐßŅųÉĄxoĀâ…ÓHþr=ÆnĀÖ$ ŸūĮĒĩ_sįóĢĻþýï9•Š å6ã†/ߍ“u'{áæÓ˜Ų·>^MBj)@)…Œ*Lëo ~óÛyfČj— 0ōņŽė8WyKp§g7]ڎâīĨĄ PŽ·Hyþ^­,··{Ч{w"6ĐGxåę9€ÕNĶžąÜŒ}ôė2–˜ķS™2 _~™Y:†$ Į$ē\cú―؂ĩÏÝÆīSå™þėýāøpB?fl;Ãä‹Ü%ŽáOwāûtûŠ/?ĸ)$þޟYwp#ŲŽ 7qS‡OĶč O0ę‰&čBĶlLËӃ'óöô!hëfņŲą,žšÍž ģ™óM.ƒĮŅžð>^?“sAøöãŲĖýÆ Į›ÅíåÕq39ozÐĪXđėútGēĀ<―‹nwu§HÎĖ[0Ÿįšĸ 'āаý0V-›‹–°Š·7ėĪPųš4Ž]ƒÛoį{5ÂëdóŲĶ9pø~ų8úOZMŋņģ˜6ǎķcųÞdn"+Į fÕ^1Ē;‡Wãģ3ÐĨLÛË―ÏtäĶóïŌ°q[oøŠ\42máĐþKļį…) ŋï:FŋōG‚Ei|Ũý4ŠÝŒ!CĒļĮÏöŸr,9))‡ũōéĄS!IÜŧ·Wާáð tŊdHŧ—ų)ËB†Į߁ȒīŽX˜―ągĸOÔūŊõË'rðûl<Cݚ5ąÎáĢ/ūâ\ĀÃÍMïb˘!īkYžukŨ` ‰Íu7ßÃŌ5+i[k7G|„ĐédßÍԑ3ĻPŋĢ[ßČŠ#X—U‘)ófsw­Â(å nâtđĶ2ĻqKÎ~ĩ‡ũ·}MTģéQ?†wV―ÉĄŒnšņzN'&p ýóöeþšÏņûBB’œÄ(]–>ƒûRĢbęÔūŽäo·Y‡žÝFđĘuØáïĸhÉh}‘<=â Z5ûeãâļŋĮ`z>؂ĩĒ1’S8ųÃv’ŽfõĪĄ œžs?d‘œc" „ôQĒRqŠW*Í 5Ŋ̈}ŽO‚ņôۑŠeŦðø3ϰ>áp’….E8qj‘…)_=úÂzŨQĢjžX„ VĄó°ņī―Ģ5ŦW 7x–”ÄĢ|™y–=s^ečÔwÉĖĘ%-ÛžęŊAˇ:ŅžRyéݙjņ>„sŽmý@Ņ{žĢ^ÕōīhӝŋÅåēußY Ŋ.=yŒhšD(°?ĩėÃĀįĪZŅ‚ ‚Þß~ū—pDWķ…SļC^z™VMņhÛv$>ĮéÔl(r1þ^ˆ·~ž§/ÄÏdųę핒H!I9đŸ#UŊĢgö\_Đ"5kT!&6ŽÄĩ‹0hĮÓB„BūÅ(],–r+s}•ēč(DøðޟŊ>ú‚ėšļŋ^MęÜŅ™võK°jÓ„Ė$ķn[fLJóÛîĒ^|a‚ÁÂl3DÉzģüÝõŒmW!=Ûņėž-œJHā§c?ēlęŦžķðö'œ 3ĻQņBđ%K”Īæ ņčĄG]>þW—d:ū8žG[6ĒëĀgˆ/ą‡Ŋgå%lKųhrW]>ÚĖGßįú;{ŅĐķÁœ%ģÉ-SŽZUËŠ(!ÐĨFÉj7QÞwšYģįŅæĩôowQdĪâå^ƒų`O!ë~ĀT!þÖúôž‡RF{>ĸ–‡ŸčʍúļÕýũQ9Æ"`^đēũÎMœ.—c9ĐZ—‚é_°dÍVšÜY‡š·ÖaÛĒÅ>W€›*Ä )_.Ï―ĖÄYKX8cąÂí8葐Ë™ó™ ū˜"–A†ßDiĐIX> KĶLĀ"č\ü.…Ŋ@hˆŽCzËņčS―"[ bKVĄ}Ũ>ž6ëMv~0ž›ŠzČÍ bŲ CHló’ģ2Áôs`ïyB9°€`(@ å<ĶUŽâ1ūž~ĩ-‡ō·īÄųņÖnÛGÝz5ĐuËõlœŧˆ˜beĻZ\Įq šNî™ýôėÝŧQ_ÆũkOĪæ°s1§­ĪmÏīšåV„ô`݃@ĄĪ“ĖĪŌϟ'' ÐØĄēēģqdnâtđ”m!cËs{YŒĨ~ĩ‚Ŋþ7"…Ë>BanŽĸ·yēY―r{ŋÝÍöŊv’ãčØ!þÃV \:•ˆfB·nLž>)SW"Ŧ6ãÖZÉ :ŠđģĮ3hŅ!ęuŋ°=L‚9ؘ–(ޜl! „Ž2‚Š^Ũ”æ- ąö­ũØā[ķlÜÂų€€0GAl™Ō[ņSįŊ"ŅĻ@Ũ†70{ä`f˟Ã+ÃįQ·^jÓ Ų P(ĨQž| ķž6ž%ï  $Ü,üA3"+'HáĘÍčTķ(Ė]ĘÞûŲū}#§s@ĸØo&9™Ųäm„ē QŒ6=nį܊áL˜3‡‘ƒ‘\ĨŊ‡·@)R·ÎbäðQôą˜”ô,āXDq5!4ÓáäOGøâ‹/Ųv4™›w’fëX)'˜3x$óæMaėŽÅīhu/•‹Fâ?wėB|óóÅ+ÆøýÁ(đŲ„,‹ÂU›ðx!Őgú0eú4æ.ü€Ķ‘šô3_õ9GÓÏóåŽ Ë0)Y2Žõ+–°üƒ]˜Rbgg’ëũqŨS­(~ä-†ŒÂ΁/°)OŨ–Õ0CŲ,Ĩ'<ÖķâŨcģiþ †ĮÂEģXķ3›z·7äĶĶũpg4Öžŧ–―{ŋáýOvq6ËĪp|Qūýb#3æ~H†KĩrY―`:Ã_ė˛[wŌ$ ˆ5tĶN™ÄÄY čĸŌ Ũ˜KúpԕýÜ[Š-Š›xU1Š–4(}}]ô€—Š•SP€m…Č ‘vK'>ĮēOLJ{ü,xc<Ŧ?Û‹ß J=ÉĄ―[Ø·óGÎÜÅþSQB†ĮzdnmY‡U ^âÕQŊ2ô ÎtðÐ8øáDžč1œÄ@ÞEpLnâtđBĶ6#'2gÆ *úLŒR·ēę7yĐW,3DÁjxýÃų4ŋÞCŌų "# bhÍÛžHï֕1­"ô_ũ6C{7 Ïv ÆÁW ŊO™Ë}ĩ “”bÓóĩéĖh[ÓôÐiÐ(Z\iúh7d4=nŦ‚iš4j?ŒQO5ÂĒ“.Žûô…xŌé3hąDęaV(DŅfâĖžÄNnČÃŊOcB‡:d$ĨPũąąLŸŌ‰hĮĖ[Į6MtĮˆAͰ2ÓPÞ8Ú<7ŠûŊÆī$-;ŋ€gZ e^^ŋ˜ŧ\ÏųÓg‘žh yŽ"rlTdi:žü*wŨ-cŲ8Vˆ›ÆÔq―ąSRˆĐyógūA؈åšugüÐG1|Ĩy}æ"æMCIIđFÝōtƒp’T\Ķ@ĄÛ˜E<ŌŽ0z|=VΛHÃĒērLžÅŠscĢŠø3‚ÜöÔkôkß͟ƒ^ŽĩU!ũbž{8ķäÎöýyāÖb˜"†ķύĪ^)Ķ·ƒ7,ĢëýUÉÍĘ%"š$ū8ŒaPqž:q.ín­@FŪÍÃÏŋJŸ‡ë““žAȉĨÛ°Ņ4(ePėæŪ˜;‘ŌZ.Ąļ˜:w-*xˆŽú#û?Bīî`Đ8ž|u4·–+˜7óģlĘÕŦâøOIÜũÜ(fôđ#Ķ<#§/Ģm̊$%ĨS)4Š4~„Ą}ZcdĨōņÂĀ1ĻwæĖęC•X‰Ō •vbōðþāW<2uß++›ęïÅĀŪu0M wuÃĻîâÓ ņXĸ…Ž˜ÜƒēQÅjÝGũ'ÚkØ8Jņës‰””.Ũĩž^/G#"ÂGųōå°m›ĸ_šŨ‡.Á@%4|^e…ZRũæ;ô Á@ žŽ†I h#4ŊĄå_Žyōb—ķĀëóâ˜AL›ð Û$`Ú螋u° M„Ķã5t.3ƒlÅBâózŪ,#\g.3Cl‡üōÕQ…Ïŧyž^” ÏJ‹mđXvĀĖûÝĩe_S~8a†,įrÏ‹$,<ƒ ÏŽĨ†Ïc_(€pŸ^,Óâi†C(@ &ýD߇šð·77ÐđJĄP+õÏ?Ōzo~t% ā(n#NˆĐÂ}m_ü―̐š‘ïjaÓÁ04ōˆ âH.‡`Āēoáņ’„)Į"ēšŊÁ@…ļŠĖË Ÿ Ūé_yÕþríļ†ûĖðâÉß/ŽéghûGŅîz™!í`™áCžäđŠl‡@ „^ÞÕĨq—„‚A4ïÕuDŲC6^Ŋ'…ĮØÁĀļ2ŽyۅŦÛĻīðéƒðöÅ?áŌu#G~D)EŲēĨ …L7qš~ûÄéúsPv„ï~ ķR-J2ōfqĘšĸþā…xÍžø_‡@ÓlŽ8ˆ*\†rE Rār§ûv—Ë%4/5ęތrėŦ’ĢÐ/ÆëæÅĸZķ-)_ãpœĸĮÎâ6 aýW)kĪĶÁÍ9 rĸCD=çÐņNYAI@e`ų=ÉÄĀŌ’ýȌ3Dáþþ[øųûýû9?†ƒ@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8áááááá„„„„„„NNNNNN@8@8@8@8@8@8€—Ā­ĩß`ËũXU­NĻŠLӔÞ{–e`‹‡CĶéžãņu―pÂ#įó{n·ŊÜïߨēeđ\>2F­N˜į9§Ó[ŪŨÏT`ÓZK%ó<ĸï;―ũ `Š„„„„vĮ: €ÕŒ–ýĐJJ8øaïÞcĪ*Ï8ŽŸsæķÃÞ/ėYtUÐRPīķĐĒUĐ4­Öx‰ĩoŠh-ĒĩbžŽDŅ6þĄĶ‰ņZ/­ĒĻT-ZÓ*ĨЖSĘÂ"ŧ ËÎîĖžËûūm§ûŸėfŅāÝį“<ÉädæóüõË;oæ<Â:Gl(–sŒžI_ðD48•RJ Cd]}–ö\LwÞb#F& e ęË|JÓC? NĨ”Rņ@hnڞcËŪ>zCa$p8âhŽHpLs%‡ÕĶ(M "œJ)ĨöC€ūķvöģeĮ>ŠĘK™ÜRII:…͈ÃÍ―đ<[wtēq[7Ųt %UBŌœ§RJĐÏČ–m]!^2à øę˜Qxâ†7’Ëóð„"įÖZœã PoÅƒc0?‘ĪcÓjæĖļ–Ésââvņį?l )ËĀ:cūï#€ąvāg]Áš'>ž8|?ÁúÖÅ,ŊšÆ“Ũ…g+9gŌĐņ1Ƃâlq-ÏóqÎâ ļNņĩÄÄ9,ā{&ŽÁóņ=°Öâ„ýóFŠYg58•RJ G1@â8Æ1!!yÖūþáÔ+ļë–KĐÉ⒱œöýC‹ĄøŅŊ°âžŧØļ3bĖĪÓļeáĶ4 Oül ›=―•·ÚâÖåũq^K­~—ÛÞfÖkøIë|6žúýGž‚ŋųI–ŪÞÉáīóøoÖ0áŽkX~ëĘũü‘›ŊcîÝŨŅRðŦÖëéøæm\sJ=o=ósV,–ķŠÃļaŅR.8Ū c œæóžËjp*Ĩ”rÖa­28‰Éõ˜tė*J„ ąĒ8IŠð?žŧĘģįóėŠo°üÆ™ĖšéQ~ũË+hßüOü-fáÃsäƒ?âąßäžÛÏeúÄ#čøúw™?ïšē}žŧnĩWÆīävðÜýËøÖe x`Å<ŪŋönÞŧt&Ó―vÞYŋžËc‹ĩ†m›7ēmBLá/ōÃEϰôЧĐ|g!Wĸt%'ĸúnjý!úpÅāt€Óā<0J)Ĩį›aŅX'xqDZō… ņãã„dƧmÓŧīEc™wþ4ŠŦkļú’ïņÚÜßóIîbzŒaƍ·sÉ)_cÍÚޔ€Ð$Đ=4KuЁqõH°‹E!AØIãÔËļũŽŦĐã#&—–“ÏũfĀó2XïŨĮÃóbþôÛᨷs˟…ôEôîĮîހŠ‹qƒï8ƒĀaŒŅGî(Ĩ”Rg-Ö ƒbßc\S#oŊZËÚœÏ9ðmL>·3Š–To7íŸî#1Ą–];ķӛI‘Æ9ð%$†‘!‘pXkˆĒ€Žî>ŒxxÆâũ"‰ŅH\ ?Č[‡sk"ú čėĩŒéü ŽÏŅxķĢŠĄ™dų^f/XĖĪę ėĄĢ§ĀÉGÕ1ū.‰ˆĮðĸãösÝņ%:ðïÞÞۚcóŽîĸô?šãI“M Vđ§”Rę3”§=šŦ’ėî܈OšØÝSN:39ĮūހmŧöÐX–ĒĄĖ'áąĸÞ58•RJ9 ›‚#ęKčÉW°eW/;·vÂHá‹Ĩą<Áąã*]æã{‚CƒS)ĨÔ žP“õ˜2Ū‚úŠöæ Æ0bd’^qgCyrøģ8õŒS)Ĩ”u[0Öá#†įAŌ|„áҧRJ)O AI€ãßíÝą ƒ1 …AĄýįņžÂ•Ā xđû Īŋ[âëÞģĀĸ^π`9„„„„Č―wdf|t+o3įœqÎOøÍne73ŨZ1ƈŠúxÆšUu[ŲÍ|‰’ Ô9†íIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-tutorial-license-check.png0100777000000000000000000011451413761647206022747 0ustar00‰PNG  IHDRÎGæąm™IDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ Ų_Ÿýį Âĸ/} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?ؐ§ó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įÆō/fŦ>6ŽĢŠÏĖîí}Úw>;vė‹]'ņWįĢNQ Ĩ* īI!*ĄŌ’‚*·ąĒ(óA\*"þ*BŠ„Zņ! ĪP"’šŠR+Ō€‚Bl“ΉėæÜģßųūvgfw–9Ŋō4ÝX%*ņģ4šũæÍ›ßüÞóĐúņVMúU­T DļÕLĸķū|#l„ú‚˜ĸ'üHÜ>?ęįÜņ DĻTž# sf˜Ĩ€Y6Žr˜ÓÆH0Î-NĐôBĀ„P<Ũu]ŧ 9ÅbrīmûfČ įXg Mĩzk›hŅ-„jęâF1NĨƒÜÂį 'jVŪëĘŅģʑ1æ…õ’‘ð{Į›ĮĪËĒ+ݟ˜[iyóø+éĒ‹0!ČļC4~éí“Ŋþ•õ ėÛ·ĸĀúU-z8đņņ­ûķ­IūwîėŪ_ýāęEí=îčÝÆT˜EaÚĸrüä;ÖSŋĩũévîčŸGļãޘĖĨÖlÜÝύŒ\›`ÜãT’čb‚„#ĸÄDz6õ‘MÏîíŊʎ\›˜žļza*īþËÛwôn‰ãĀݟŲÐÖŌÖŧëĐŧZ“mwú™Ý{úŸØ4sõo“.™*‘t—)ÐŲ+ŋúí‰ú{·ėęĸbîâ[gĮg áåĖdûš-Ï>ņĐÚ ÃäPsņýoþxėg?øöó/üüJVä.ŋqôĩᇟÜūõ‘îó§~ŸÖęÖķ·uÞóp_ßWššU2%!6·^pŠ~ĘÅēUÝņôÎÁ};zýØðDYÃ.HWՏ7ÓžúQ…Ą*d㍊›ŠX”•§pˆsģzŠš4 0AÍJHłdĒVČ&rýoĶÛįGšÝ>?„R û―åP*ÅŠâZcn]Š;ŧðŌÜÔlŨÔR‹Īå™jŌápXŠ2‰ČöZ]]]UUF€\FØ„ëÖÄęv &RÝĐOÅR Ģ ÉHu5Ṋēũe)“s:ŊËĻBQĀËGšÁCJĀš_·š78Č8°ÝĮoŪr y!2|zÁ}z~ní˜āOþüĻ)qÛąŠųhÛGïYÞđėūûãĒd™åsïėiuĖž­ŊYĻåË&nP#2Ē:ŅtÆ(ģx]gÏēa&gķÃįēĘ\;ĸōũŋũÂK‡gLĪcGžĀtcIGŧÎhSgŧ,MÎRŪÛš: ›5vīĢ89k!L\Qq–ō@›É•E+ęÃļX,Ę Kđą?yųŧÏĸdhZ3*šĄĻA„°L“Ų&ržIëÚZŦƒÔDŅ‹ëËīh[<ī°m͊%ØqŒH%—›ũå•V‹°—1il銞;[ãÁĻn›Vý’5›zĒGüC/ū:U°„ƒt fQZ9ýÚúé‰3H Øs\™5ķįĒ!$hĐ`ðÕÓŊüčĨã$ڐ0c…PÊĩËȎYĄÜ{PþäæūŧŸ4&ÎþæŨĮŪū›fþOŋxņ—§FŦ“‹0c’5Í@Ôīå“F•øØĀ’𛄗,_'QĒôŠ\1ššÄq1Æn…WLlAâņ™ū˜Î2VÎÎäFÎŧPŠ~mŨķĩĐ$"•I4ÄÄ,•É{}Αp$;6öîtĐ<û^úZ&Č`ŧēYSÎ’é Üær‘ķʁHĮvĐTī8GĻŌē Ô^ũØÖoėz4?|æėč d;w(ãfvôð‡>öøöÞÍD‰†]ls!“–ÔÉĪå·kÄŠ‘Þ}ßöxnð™eu†-ķqĐP–üĀkĖL\ÏĖÄR+š·ÅĖÎ4ĩķ„Đõ_ęÝ?øõÁ=.0\.ßb*[b™ØL0Îō™Ëį.ŒĢŠT …ôXÖĪÓãĸĆVÕ·…ÐŒ †Ðøû$įӏ„ŠūS ūTĻu„‚ÏßW)jbÐFĀyޟĒūŦĐjø”?/?^æóōãY?<~ 7ôÆŋHģšžĶĄ0üëôE>ŒŊ~mmŨĩl™‚ œY$B‚X  : Pl8YeĨ[ŋX1þâ%ņGxĪæhÎ.ļð―8yrúžÏ9}ōžWĮ0LÓlÜUģŲŦešÕĨEmzōú㇟ĩęyŨÎfūdfŠŌ°,Ā4ØbYVĨRQUž‰ÝÞÞÞÜ܀ŊårŌ ÝÐōōâÛbēڒžëå{.w<ņ͐Ūk ÐųÃŅu°‚vØE öƒS þŠïŦāˆ@tÁe ĸÞđp°‰ļė€ģÓˆó.Î^0xæÓ™k5LËnÔŦ)§ÆŌó·åkĨÂč`x˜bY‘ÏÏLũøý|dęĩĒ[PÄvė͗OŧÃXl,#BdbŠXW3 öðq?ĮĮú{ĢkZËU§Đ‘úy!>Šæ‹šï;đT$)ø—šHËû§ūgŽdcŋu2ĩ°yļ-ĄNšð4ÕӉmŨNö–1ðŽ?.Õkōlbl}įüŌ1ĪgĢ8Eâ-Ė]4=eo=Ép;5ÛUø‘áĨ­’åØA Á'f,―wîĀ&fvOmïŽģž]ŠČyf”ˆ AM–UĮ6ÎgđÁ‚ßÚ/fäå“ãÔ`§ļīqR=ā(šlķJïĈ°ę~ŧRåMķŊ+Âr,ËlTLM~…‘Ųšú7ĀŨÕY§hgÂ―øJáäęĘýž6ŨŨ3ÄÅ9šTK/冚ŧY1óUwĨô“ÐÎ ąh8"æ=ßYMttôÅã<îZؐ=ÏnOf{~óÃęócšƒĖ <Ļöt^Ðų‚"č°ĸbÖęYĪ‚čýÓKŒŒ.4 /å< 4ļ―uúûŦúc#şã›m(–đeŲÐ ššŠŨÕŊÞVGÛōzð~­øŊôÁzDDÎĖΔR@ÑR‚QŽŅ~š^<ŋyôðöŲSýþ]1ŧÓZw$û9g|ðŲlķÛ-* ‚ęzgÆåøíû‡7ŸŸžüøāõõã/›·.šāC§ądŋ"Ë)Ž@7œˆ ë>‚+|ŨƑ}<čq>ņŪ>+>0ÆėÓXuŅÂUw+}P{đ>ũ­ŊGô‘Ķ”ĒßÕ1>ŌÜēBÛ0Í ÕIŅ ­K›Z+ÎØSmđŸŅŅÆ–Š”TÛ "qqïüōęÆiéR™ZŽþįđūõZš[‰Z™žXĘRĘ%9ë# Vhʈ5ŠV·―˜k‰N ĻïĻ5ŲõqO%PĪNspŒÚ”wĪlnSēüãAÛÐRËķZ Ãŋ`jаˆĐĻÖī0p­DÄņ„ĶÁBđ@- TRJZéXZÍQŒãÂÆÛ@”kĩ]žŪ6”‚–ã0üp š ")ā qÞĮ`tȕėðąo• iþ5‘6ōōþųÅŦŊÉåÓÔPüðüðčœŸŽG/pŽĖ ÀáŲæ‚0ÞÎxlØþýZÁĖxĶĘEŽÜ/!™ÞÝû…õD}øh.uWØéúŽķãóD}ÎÐۈĄčķóaĀÕÖðöÏΰNó ŽKu #áĢ\)ĸēáųØo€§ Ĩ{Īāð.<îAŠĄ2ĀþóûēÛM"ŠÂ(o­Voô ŠrĄ>€ü õĒcĐC[ĖÅŽöó· 6q‡ėėģĸYs [ūFí–ķRē›#6bš#2]YŒ;'9:’%Ÿč”Įģ—‚ģn’5RUŪ”nčšOFėåėLX+6ïž{ĩíÆ+f„‹ayɇüãĩÞtWjģz{öōÓė’―Öx7ŦwŊÏ>Ï[ūÞøžŧ ûa#ŒÁåŠ|Ņâㅏ”sÚÞl]ž[æ~aRžŽd1ӅÝĕÐá†0…#UäëŲÍQîĸŽn]ƒ_ÕôÁčBĖØ-æÄĢmˆą› ŸŅC~ũũá}däøõg]˜AĖ5íxW>}Œ_―xóeyŧ- ―ũ­ÄiCîOЌŋ?ÚåŲŠūÏjÂÃÂúģOĐc(å{I4Į„UųŒøóƒ”šm[4ŋLqŪV+ ī Ąĩc;ÉzԆt: Áp<ģlâhŌ,ÄПnHĘ=Ú§4”$ĪDī―™™˜•ÂĄIēMúøÄs˜9ņÛķFÍg/ą>>ūŽÚŸÉÄï„ÛŦŋoþhåĀ{ŋšþuĮoÔëËËÖqų8ú(ŒŠÞN°„Oú›>õ ũŲōé3͉”­ ’ŧĢ›„Cų( •ũ‡ČÍÝÍívMčd>z=5þã4ÓÂĢ|Ð{ïO a8}|ZD>WG>_8ûø ‡ųdOχō5M3›Íæģđ/Žčéd:ïd1_pDO&“ŲtķX,šÅ.m>žeģ$„‡4 KÅc+ z0D7Ctāå֘N§Ø ŅdZ’Î8M&BZâpg^lå,wÐ_64ÍđjF )t=ßŌĮ‡Ļ"KJ>zäC!inr„OąJ>8ÃĮÐ>hGÉĮ#6[q‡„ðY6 …ߚyÁg:Į…gėðÁ ߇NÛSøLöðÁÉ:僔Ëû“dD>I ķ|Úb4ŋāģŽïO†Ö|PĀžhšÉŨ{>Þ7™ôņIÒ†uøāČ#œåƒ` §ņQS;œÎ,ã˄ܟÐ.ųā‘žÃ|―|8žÆ§|2A?âƒ}x2ŅüD8ö QÓÞw’>ØešGu}ŽóK'šþu&ŦÞ*#R9??ïZĮų ý|Jz%Ï‡ãSóAÂ§neīæĢį ų ø ÚÃųÄœ‡‡ÆÓĮ'ģņüg|° ™#ũĮæOĘyN>Čč7;ul AМû/•ėSņbĶ„ výÕĖ,ô҇WÔ < ŽĀjŽŦ°ZŦāūŧIš;û õa{įÕĩŋý]Î93ŧ‰&–D-1É5đIԄó,Qcą$ąĒ‰―""Jl`C "ˆÅBSQPzTÞË4ę0sĘ{ΌÃkōËZ7ũ]ŋ›˜Üýųƒĩũæ[ž}fÎ3{‘xašĶ„Ķ9<ŦŽĐ()ŊįxáϖFŅĒļŋšéC€@0BŽ–€ĄpûĪóȑãCã+°Œ2ØF­U§\'[Ï}™ÓÁ)]„ŨÕ]<č6ÃÞ~ÁēÝåM4…~­ °™ņQų:q\Wšüó™ lNCƒÏęomoïār;*ØũØų0…6UįøïÛs=1ïîĨ3nΊÕĘ0—|ųð\{ûŲ #RJEC„1hŧwéðLQøÜ•W3kąļĪ―âwÚĸÂã§9k—Ï›ųý’°ûĨšúž―+gĖtØ™]ƒ…–ō€ý›ėÅjk=ŽÕQqmÕ!Þ{ÎG'įÆŊž5cáęÝYUZškšxÄsŨĄ3§Oîó:VĄÖŠŲ€@ VKø5a―*:Ā}åŪk*ŽĒu•.óŋ›ïž)(<úÖ­ÐŦŪ4cyîĩÓū[z"*)ö~ėĮE[Å0ōŌ'q.î›fOāīmØĨKŪk—Þ/ĩ0Óû­Xæ°vĮ•ŒÜŌ[7/ŸŋÚ -ĸÉá‹wČÉÍŧxf—ʍęŲ_žm!§­―čšŊÍt9žķîþýs5-Ōų·.^īx˞ w\óŲãžØiýNßĨ7•åvu[4}ԜUŧŊ]OĻŦS‡x9ÍtrÏɍšīxÎō›yufTËĨC[ūsÜû(-ėī㎉‘ų*ĢŋuōčęUK'Oþæt°øĻAŋ%ģ?܌ƒWBö/Û ÐcN‘đîûïŨmũώK<æķx‰Cą–Âíĩ;<œæMŸdŋčLØå@o·ï=B5ĩ‰ō9īŠŌÓþ7KÔ,ąÚ߄@Ž– ˆyæX`&Ão]ŽLā^ąšøāQyInčĐ­―ĩ…û<ýŠ4fkG>―åŨ­ĨėNtPđ"9•ŋ―,;!čði•ėËĻž„ĀĢΠŠčø•LHaËĩëųķģbîDÎėĮ4+›_ē2<ú’ÍP‹úø”:=ĸ ĀįĖ>Ģ6&”'nĸŠnrúÝŽJ™ 3zķUÛ,Þð~o\_à vŲāôz7jˆđ ûĮžfÁē< ˆÕ~!@#ēRÓăąßŊ;ž++Ð=zõÂmšJ―pš@%Sæm.@I}S­š Žo_.Ý<ÍúýW{ô0@8–éõÃŽ)˜UDlŸ7aÚL· ),@•…ÅĐqß=ŲëR65%õ,Á3MĩGú† )įþ‰MîûÛyÔäDĮ§éŦ(mõžl5kD/ÚēWŋūŒĪÕôížqæøáCÞ ôęzŒÚ+2WĖûfđĮéEuŠú†j%€ÜÝåÓ§ŽØĻ .ŋŪBgĐŪýė8―?dÐkƒô Ûˆ­‹g8°GũÎč0ÔV—ĩŠ*óO3~ڑļbЊkĻi0âõ\ÏOėW.œõÎ[oũ{―;`k[XžÂ21Df˜†áƒ/<Š‘™››ąC„đÖ‡€”,ŽĒĩžđ #Šæ(Ėē ;6{Åôwŧ ÓæÝ†vƒéœ0Ðé9–į  čYkIŅú挐Ô\K đæiT@ēÐó•îfŠ á›l’*sĘzbmMM5ßáf’ΗhÄéYŽ‚cžïÜkðĒÕ[_·0Eué3åGpbýÎ#~Xĩī—Ņr™E·þXϊ‰HĖāx―$\ōzŪc9Žįi" ōĒļūC>_ŋqÅCŠ‘ũ{―o{[>@'Sœø[žį IeĒB"$7“ãV'Î äTK^ Öä{ŨC‚ϝųųb‰Š Bx įčo îFƒėS[ö^ËĘLŋŊļŋüÞÐÞ U‘ž‘Į›Y`}sqeU‹žSDDƒ’~ōĸėÏūĘkáQ%üKģŨ:[č ÔÍš·Æ~Ó€ōōúĒ2}—.fõĨ•ŠFÁä™ršOIˆ~\vžXøøIIBdäü Ŋ5eû_ÎT y{H7 žFîvÛëåôÕĒ =Ā†Æ‚8Đ//Hcūsï!oũĢÕ%đO+ĖšvŌ77äWĐ^4xÄŧÝøōžĮÅõ]ŧpŠúōĩ!'åˆY&OäxŽ7T”J íœė―ą#š`Pĸ$Ŧķ‘ïÖEŪŪŽT4hE―,,֔("v‡ē,§Ũ4ä\ŋ[ÛσĒ<X-—LQ|hëwßÎY°`ÁüđßÞ)P@ŽXúŋC_õ•ŨÁ­ï0UîKėĮOš<ĮqG^cŸö\3ËúŅ9wŧqãÆOœķÔÅKĨÃH˜1– đ%%N9„0§rsķŸ4ÁnâėȇSŊ^öÅāîÃĶút&ŦXí0Éîóņ_͚9ĄPØhÎ|cōĻųĻ…“ÞéÍJžÍÉzą›8M8ĸ―]­fîÝéÜŧĄbĸ֟8ŧŊ>Nr:ˆ!ĶÐÞ°%NÞ럁'fū';īaĄÝįvūœy(ôžEŋQžøŌ ï^3Ïnü„‰ßĖ8v-G i9Ïë9=oØŦ€9%—S!BĀY V?bĒÓaïmƒäĐÓ'Œ?aúĮûO52™Œa+p‚Áę9VØî” ë:lėũ_Ž­-ŽY0máėZDcðĮ@ (/0ĨOs“ž'9đīĒē 7#)ëqmCƒBĐnR7<ÉLŒ‘ūčófRZnUBÓØŽĻ*Jđ{7#'·ūAYYV &?-­RŠTÕeOӒ’•TĐuYwcoF„GÄÞ―_ZÕ Q+JUSģ:?7ãÖÍψ7ï&Ī–Ö(”J…„RQ_ó$;%įi™RZ‘ ÖU‹SÓ TÕ wb#ŪD܎‹ņę@Ïũ§Ķ•ŠU5eŲIIYųÅĒbcRcSSUanÜ훑7bï&ä•6ˆ}5å…yą1ŅQ‘Qwâ<)ĐPŠŠē2’SӋŦęDĩųb•Œ‡âU uy9IÉy5õŌEhÖ(ŸäĪތŽŒŠŠ‰ON/ŦĐS6Ôä%'ĨįæŨ4(•õ5đYĐIɏkëÅXumųÓŧą11· Ë û"ČãfJ•ZóKDS‰‹j•)B)ÍLÃaX”~ЌQbŪJĐ|–aŦĪ)ēã·ĶķFĪëFT*ąĪŠcÚQPÝØÜ\“9vðËžōö°W€ČKCWš‡*››Å ÆBŋŪ#bl­RþöĒQĄZm”`ܕ84)ïĻĻėČ3KuþÏ`ĨĐąYąZÂ_ĨJQ}ĸbðąc>ÞÞ>Gųžŧ“^ŦŌρX-áeSk[ŧ‰ķæF99Äj X-@ Ŧ%ÂšĶ)  /–åôz=ų‡đŸÕh4ū؁ðĒ pĸæ›Ã,--X–%VûŨ!ĪPĻšvíŌ·ožį@x1Ā—””ŠT*ņAôäTûwB(ZmϞ=8ŽáŀĶ)Ņg bĩ€@ žðüŋļ%Éãf<Ų‹@ ˆÕX-@ Ŧ%bĩ@ VK Äj @Ž–@ ˆÕąZ@ Ŧ%@Æ BūŠ2JúMÁĸ†FąĸY "Ø1øw/ÚĸŨž|.›%~yU Äjĸ†@ĀslKSĢFÓØŌĶĢhšmRĪ%Ķ*ī‚ðÏīYĄ―8/­Ž^ zÞ1EQ#MeņƒœV€ŋĢ­ŠÏ‡æŨ·SÏųĐX§Ą '1§T@Ø8āĂŋkkiã„oSl[CJRZĢ zmk;û_äcóÝŨŌÜÔĶŒŋ„j[›uŽá'ė8WŦ%Ð SūÄŅaå*g‡ų‡Ēē5ŧ7ļĶkƒáŸčī jđxb{h|6Ēi`€įtj•RÏ 4ÍTßYuėj‹ð/ï$ĢØčc;Öļ|˜uŊHŲŽžË hĶāīįĘãŨu - N\oþ>ymõŲÛW·bæwßĻPĖRäî\ģĄR/ˏ<ää~Kĸ;ūw EÝ lÖþÆŦŒu—žV­r=Ŧ…BTciÜæ5Î*ŽÆð&īĻTÍíÄj ĸq DíuOŦeý,_6îÍķíK7d7i{ũ‡(@ˆ)ŠĄž–Ķ Cc FšĄE0BÆRm€úåĨ<Š’ę@SEm,JáŽhŒ1Q”Ž?:C ˆŦböQƎĩ;ēÛhĐHwĄW7†FRYQq'”Đ=„ÏÝåžæa­ræöƒû=|1ž+'U2j6t 芰qÐadÚM‰ ÆÆúâHŠlQ1ú~ņíī^rƒĒ1FÜ#ę~^‰Ī͘b!ÜIšs}G~6Ëv˜ĀōíŒÅĄi*ķÆ^ÃõÆâīáŠSÆĘÏ^#Æ üē—ņÂKI‘˜)C<‚ĸŊļTþŠŽQ cR"ĩ‘0mSœI wT6]1ƒB ,…J+H&ƒA^ŪÁũōÅð<ŊG]íÆ}p3ØëôƒJ†iōwņĻėýÉ[}Ė9ŅR ã6;ŪĪ( Ģ_îTŌÖņÎĔ4`Œ1⟠#Cðģ7-‚XļŨåBb‘˜@Žö€<Ųķwŋ7ŽF}žpÞÂAĻĐąM/ð’ãpíʐÝk>ĩĩ™ēîHI `æģÕĘÆöãOfŧ]LÓtIâ•đcĮŠ>Ũ#kixēuÖT[ëϖy_oGīɝqkUæ‰}=Üį,ÞŠĪpŌŃ6Öķ_|ŧ$ĢšE&ʼna_ŽģĩķŧÔ7Je2ĪOÝigkõõ—ÛsŦšFŦåtũbüO]Ø?l>ËëÕÁŦ­ŽmĮÍvžšV+Eð€˛ĒZeIšŧãd[›9?n+Ðī͆žŲëĮËd‰ëķėŪÔ2šŠLŊ́ĩʂÔīFŽ*Š tņÚåžpÔGïŧå)ęŠ―][ŲØŽ\ŋrË*ō6L™ŽAlĨ3|&5Tä')j1ÆÚōĖíËūƒ?Ÿ°­\G)‹îoøjĒ­ĩÝŪ°T’5%ōō<ęí6zô‡Ë·Ss h­ótœkõé§3–W·34j9å1ŅÖÖjþÖĖšvŒ€ŒQŌekņrŒ™ž/(EÚl‰ôwûčkĮUËŨ/Y“XÁ5å†ŧė;âđuÅØĩG+›u·NyL°ĩĩYčšUßNaÜ\x݂m­'ø9 1ēGa‡<―ïr™3ęŸãýŪÞ>ĩgíčþávė) [oø{ˆoŒÎ;ō5˜ŲÛū.‡ü|fÛ}l―āvbÜē9Ó>üðƒŸï12þ†·ËđĪ*CeFųļ&ËdtNÄ™éŸØŠoļÐôĒēÔë~'ƒ<\Ö/]ŠcDaÄj ĸIMĐ r"ĒBvm9ÁũĸlposŅ|)ČĮzüĢ:|úÍĘó―Ēöf}:4lÕøŌŪ—Ú°þė†i, >{fŌ‡oŅššc›+ޚptuuØÞÐûeM=ûĢk›2&ðčEåÐV,Vß rÜuoۉ3ó°›·ht,ę<ÐýHĀa§ …>đ’;į~\6Įýø†ï*žB͇ }Ïæ7æŧï°~ŦáĖð°lĘÖýĮĸēûDYkKĖą>‡Ÿ :þŠúķïĨӆ'1Ãþ#FZa5qĨÃäa1Gķy5z?ã<š_7Ý)ĨN‡ņ_d(9[ŧ~ŚDųįþgOõiš?gÕ Āīފŧ\Ü MŠ:éu0<ŊēþIb\Þ#……YÛ­Ļ›MžĄm)ƌđ_Ý Š+LHIi€°þК=õ_ošč7j@ŊƒFŽ~gØÄĐӝøëEaÄj ĸI0B…EđQ·bZ†ÛųŽíoŽ9ķ1+6LQ˜ģnÅÚØlZSPÁB3ķ―bûĘuÁąĸ—·€"Ųú@Û{f"ww‡āDqdqX`qY<BЂmŨāîēøÂâî‚B€ļËdŽ―_ũdÂåî·ûÞûî―ėýæĸ#3%įœ:]=sĻŠžóϧ˜Ü*Ü ;š:~AZĐJ2ßÜŧõâÂÞĐsķžÎÂ+ĘŠ9Š - AH}[ŽKžŲØ%ïÉóÜĒ·Ŧæ$n<}ëeæ'5›Â;WÏųéȕr‘pĖëė7@ËØÞ1MŧõęÚ;’ÐhD" 'SĸF&Ĩ%}zþ˜–ÜŊUX+ScĨŠŠ<―,§ęíĨäIģ.?ÉRjĻÚŊ ĮƒĶķŪŪŪNÞAîķčýOåÝÕ,ÐĢûðÉN™Ïó*FZĘēŸ―Ŧ0;l—Ŧïô1―ÁGŊPLQzëĘ­Œ—U―Ā7wŊ^~Í-&ÎUĘōšs_–Ũ„öH^4u@LlĮa˜Ę[įóėš$4ņņ‰í7ķąLÂþÁđ ŒJyEÖMŽĩ`f˜·gãðFLáËÜĖŽ‡'ķ$.ؗŸI–W*)‚īlÓkóŌ„ķ-#ímØr…ŌĶqŦö’ÜÔÄÉÛIØôËGŠō?ý4yōþ›Ī"ģ@Đ–É ,5"–Íœđųä[ [ŽåĐĮŌ‰€Q›5ï12ÆÅâx€ŦķlÚmڄ&ŊŪĐĖû8ō䃷蚷ÅĘę7kĘģŊLXļ-ŋTQ­ĒY‚ ý>ií°øČķ<LJŪXųCۘĶæ2Ð<žø4ŋčEJâ”cO2_―úH2 ÎĄUęæU]bÚGzzjÔÔÞÉÆĖÍÓÛĮËæ9ā˃žcĖž#§ŒlÛĒ}߁ÂaxqņāŌqüw­ų†Q2žäqK,Ú'YŽ@ā4-Ģ0ÄÓDeĨJ°ö`ÄÖɧ‰Ŧ\†Ã,Čmí˜Ōr% @ _YUÎIĨ0ĮjÉg @—gŋLWaúí ȅ?€cXBPĄ…bXP҆åP `”Ųđ€‘0*ÞmڒÓG–›ÞØ5tÅIA…,@†ģZþåāh’ŨÐą4A1,Ï1Zĩše҇‚ÕũÎ]}ôėáåûÞ1ÍTį|}ëņ7å™éũïž8•ķõĖĢ·Z1—JŒm}; ėōāÂŊw§ßŧq1ŦĻĻûøō,ĢVĐŽxĻIŨ^á&Ï]Ëxöčäĩt-ÓZâÃÛ·ž―đóúÓąŧŊýĮ€đÏæ.žžļtïĨ—Ī?Ŧå9ÞØÖ,ÉÝīlÅûjŠgIĨZÉžZĐUaV]c{“W.üvãŅÓŨŸ|Čį?8yŠĪIŠáAËΑîß°|ӎ3S0Ëø(/+ŠÐhJ ÝĪFĨÖČė;ƚn]·pˎM‰?ĸfÕ§·ŧĨel'ũĒ뒐AҁmâĄü<ۍl`’Ķiĩšŋ߀ІäąDĻkhĀfÐԞå§į:=qÉ^ óåZ‰c(―ŊRkyÐøfaû'ųyÝúÔ%ÛŠĖ‚âzÞS  1Áa݇ŲË2=s;#ýÖÍ[éĪˆÄ1$[STðþŅýŦ/”Ų/;ũūóø!Ū…œ2eLōšŠ’Däĩ‚dy€ãøĶ=†ÛJޜ:{'#ý捛YĮf[6ŧĩ}Ï̌—wŊŸËŪa8J˜‚žaUÝõōŒJEjžËøaÞĖƒîžxxûô­W jj(’E(šf„ {{ó_ė>yųEé‹c-ŋŧüIƒ~îĶļ]@“VžčĮO…ĶÞ]gö0Qđ­·ˆŦĨÔĖÎÛ/ØÅÁ1""Ę TįV…ÅY0Ž“āĖý‚›w71· ņkÜy`{WSœ‡ĨŪžūÂīÉÍ―… Ļ“„%Ūžþž^înÛ412ũųŪýÝ{/ㆌ°FY–Ŋ=̐šzųy ZæNÞū^îŽVÁÛļųE*™™Kpãāö11ūÆLvA1„Ų„øZ[Z8ŧyûļÚK0ĖÁÃ/4ÔÏãrģēĘ)4nėÄnĄļđgũĻВœė %eãāįïgņXÔÔ),ÐŦžļ&°[ŸŪąy^Ōž}\\ŧXs3Û›žđ{3ĪûÁÎ.ŪÞūūîâ’ÜØÆ·{dãâœũJZ°ãëíßÞĮQų1§ÄL‚CŲŲŲ{ų…ļژ#+?_k‘ļxøxÛ[đÅķnVžĸĄF˛šų4ōöpuó ôu0ÂaK;§€ +3ŊFÁ&œ–†åÁĄ^>ķ~f˜ĸb?aáéíįä`s,dėØ1Šeuþ)é7.al”' Ë[‡øhŦ•A=ÐÅĮŨÏNļuúr[W?ĸ;SL*Þ*w[T*ũņóũrģõljĒ-G―bĶŽęŨÔÏÏÍÎT“Ÿũ>ŋÄ.ĶįŒ!1ħQ°”QsĻe€ŋ+ôŊ?Ž… ĻēēRôYŪÛ>þuTðíAĨR=žņî]EQÚŋ’fyŽ%ęŠ)îõ(]áø:0BĮĮ jz°4YŦÉŲō•AÔgĢĄ%ękœNMKĮmG‚ÕuŅdŸ?'˜zŧ ýĨWg‡øŸ)ĄÎą Iņu ô—ÅčÆÐ] C‰„(FŠãsBg} MŅŲŨķõę=qÓęųQ­BĒgîŅ2úąŋÐbôZZąE’øĒĘP‚8]ŨNÖķtýUęoÍrĸÐŌðJëĄxsvhĸ‘+W­îÚ{NžBCRŽ^å+;ĸāMÔÎ#6ŨkÕ^‹NŸfčŠíĨëEJĸÁõ“ų%(†kø!Īôō|}Ģ~ŽÞđúՁ­kĄąT7û…ūķ‹āLŊ^R?uĸÐ4ýúõ›WŊ^+•5ĸo €ßpÏÎþ(•JÜÜ\Y– øw„čŠÜ;ũ–k,―BĒZKAžĸžīåO=ĘúT*ĩóŽˆhf%…đĸ„_†gVÖ{žį]\œ(Š6œÕð/…žāŋ uđû<‡šŧīëÖg舥ņþį8 }EōðŨþ9oøxZ6‹‰2bDï.m,ĨÐ7gusō§2šÄ4p ð=”~ðÁĩŋŅ9ŠęÉÃĮeÄ_ʁujßŌuAĸŽ`i‚ éúļÆÐ4EQš'BœĨĮ/Ÿ=ĘŊT~ŽŽ§%öO‚āg"ˆēw_åqøŲ Š þˆZAÜËëžúf~@ AĸĀ?r”úųƒĮÅJöļé0Čæ<ŧđgë–kyB­ĸG‚ĨVT*ĩ<6hä••å ‚AˆŪÉZš0=̊Gĸ4†‚ĄŪV( ðÛXĩRZeĩBõuœÂpüųū%3֟"8ø/›ƒ1°&uþ”ģÞ@Šk@ÁęĖéSWÜÉTĒô‡ŠSU­ EąĖ­?OÝy‘ z7ŌũĪ$m:Kó0ðw€ZUĨTQ Ö'#°•yëĶMŧ\LýŅ €\‘umdܰ+W/g|*āCĻý[Á@ƒ€Ē˜ˆ:öF0jXEá†U=‰ëjåaĮá;gwn;ûP(õœ/8ģņ§Ī+Ų58 F„âPPŠKl‡kmĒ:›ušnĨĖ›}%—`āW2:N1߆jIÄzmŠ;‚ †ÅBQƒøŦ―6,Čé ŠõôõYĸ8Ž ‚ãï·­™°õƒJj'ĮDa†fœÃ:tj„€üg%ŽÎ‰vrˆÎŠ$0âÆuŋfcÛ^]ÛyXHXŽĢ>ĀŅĖ+ „Bšė”„)Ũ2˅FȞ·‘c(ΧĐÜp ï\ƒAážŨ˜ūĢžBAĻÕģRčÝCÄ*ĻŧđXÝė5üĻ|ĶhĻĨz€āZfLī†4īŒĄuĒY§SÐųŲÉ)ŠņzÎāĀÂē‚%‚4Rũk8BđŠ(KŅ$.íč‰i―Z NÔv‰ƒę„aX7ouõІPkĀ0Š)rÓũîÕfāØ5ĨGØĖ+{â:DGFĩO^ú;„ÂOÎoėßĩeTTÔn øðÄúĻČĻļïĮéH  ôÓû–Ĩ,InÕ"ĶûöŦĘÞßŲū4uõŠ…ƒGïŽÅo †AŊ.íÝąįpōøI3—üĘ$(Ģđwx~ŨØVņÓķåkA boZÕ32šõĪ‡…š:ĒL“ûdõ‰c{’&Lš0·”āï^õ(3óQ‘V°yïāĒĨVMŌíÄíŨŨOĶ-M;8Ļ_ũ˜Ū}Ýz˜:ĪG‹ČŽKO=F04ĸÉņqâĒĢc·\ĸ€~þĘA ]}ø—ĪØ6‘QíÚ_þĻF4E—% ĩöƒÆŸK/ÃpüÝŲMŦ6lZ•2ūUóˆåŧï35[Ï>ūréļĢ2Ë*/lšÕĒįČÏ Ū)ÍÎÎ+Â$ėÅuŋŽZģzþ˜ÖÍ:<ōļÅðʏ’{ÅEEv\þëcÁqšļi|ŧȈþ}ŋ/TՓ<€bģęI^VČ+?qÁÁjZ ƒÁ˃k'·ï?0ePŸÅÅŦƒ*ÞŪ]:ŠU‹Ļ_ö>aXQ’õĄ DЊ·wzWĩpÛqŌgũÃT‘}û‡îĒ"Zũ[z šQž˜ķļ]›Čþ&LNū›U0e‡ÖÎZĩ*ĐßQŸ( ëúþŪĒcŧõŧ’YŠáuáģ1ßũ(,Vþú@1ĒäÅĘĐsÖ,Û.ĶõÐU§ŪYŌ!Ēõwƒ7–20‘—ķĶtŠŽŽ―čUƒ"ėõ-ó7ėÚ=fH|ó–―.žĻQž>ŋúøÉ]“†ÏZķŧŠŪãʁ ”#îœ\ÛŠKτ·eĮ”yG čŧæl: zŧzŲžĒįįF$,yWJkJžÐM`zč3hM~ ‰qęÓûVŊßžĐkŸ~+n)?ޞß!*&nõ… FACĻ5ā? žĨtüŽÔ}iSĐGëŧ[üéÞņ‘f7ïŸī%mÕĀ^%éšNØl7oûæuSbžōn·äڜÍ;EƒŧUŽČyūwÏŋğ’â―HČA\ÚÄDÆDv™>%ʈgyžgÎ!ļu _ÞC1|õĮũ)&ÎJ’ÜH;^]õüÐØG§íāų.aö‘žE·ĘÃmÜÛúļt0rôđęô=c~đ46mïxĖ„ŲŧH+z|vųķSF'F;æ=8―ráÆØ>“z5âÆõï÷ý~Dũs;6•ęËÆŋc{î?ēĢS€m]>ĢÜo+§&JŸūrãÆ•Đ!NČÞĪWėUĪnÞ9ą)•Øsâ“rZ]ühåŌåO%1Ƀ\ũ-Úô‘3ðņlÛiLr‚Ģ'ũÛėÐ0̜Ý.TöęĘŲ§oy)zqsýšÖ]īüļãče–(ž6yfuŦĄ;W<ąbÉĨŒ’·ŋïžĩ!oÔŌīÉ}}Ŧō äs2?DÝļpģļœéē―ë—m{aēhΠû;·]~RęÄņõōņ·öðcōũąþ0=úõčĢ3:ï^ī%†Ę^ nžGQāܒÅû°MŧvęÐЧāXē7oíî•Ó‰cîä‘yũķŽZ}}âę- \O=úäS53ũŽß’Žôœ(ýxmäī}ņÓŨĖíäđxöÚ7yŸ–NžŽ7ģ=uōïsĶ_ĘŌā@Íų›ž1!ģĶ{0wxĘ5>qÆĪŌß·Ÿ~U•skÛÔíO–îÝŨĮäN‚Ã<‚||dÞÏûBû$ô.üå§#ï°>Ž†MŌ·― fx‹‚(‹ēÎdcį/m \ŋjgYEÁlj3Œ[ßšt܅äÄß Íšũncį1ih?k&7eüÎ?nûÎī čLōē5öņöŅkn:í‡íØq3ą‰ÛSzïYžčæŧ øïžķEþæāPniôێuYóßW)4dõŧ맊Ķ1ã~ˆģ†FNÏëbŨ}ŅqršQāōŠôœÂwkįÏОÍxmdŽaiMŏ›?8Ū-íļîx§— §‡c>ïčïRšü"4·wqī”û{đÚ)Kr0 YK~é`WqÛå!>ýĘ‘Šžž sĶ’Ĩęjua9ĮąˆÔÂ=Ā4ĮË?ČŨýÔĄ#ųųë™M•ķ BŒ;ēļ ‹R‡DqD•ÄۍNÕŊݙĘkám҇ũË8[|óΑEvëu~õŠĐÓ?%Λä Zšm/WtéôːūkãZŅ €ōÅŋåģÝŒnä;OþåHßįyUįßgRÚĖ~Ô― céi+uóĩ°Ŋp ô3HÍ―Ųsķäeåãmô‹Ķ(4Ósōâ)ÝÛßÉÚŭ+Íy‘›ųVĢÚ1ý–ũ†Ļ,-{‘ý6°Wž‘RĀŠŲū{u$õžP„‚°hÓkÉēiMáklŽTŠ”<ÖR:˜;øÚ:đšúļŲ}АAý6OëĢž],“üVMˆáZ †ũî6-ĐlÔô™î.Ëqâö„åRjûæUŊ+‰O (…é‡§ÏøEŒüŪY̐vož…á žĶxŧ Ÿ’gõ 2}qôBö§ũ‡Ũ/””dŋĻö/øôęÁÕ …jSá%õÓÜâ‚üRڋąhžuËî™É)ļe\ΧIĻ•*-§‹|*E0žÛŧ}û6žĪ PeEŲ‡gÏnæ*Ï_đ|5W ÐZ=—‚VM‘ŸILėƒ;}xûėé§/_Ý―~5ŧ‚ ~vųČËĶ%.đō8ugĩuÐhiFLtfHĨĢ>ījRËęxŽÃÍžĻs·^š]ČņĪāĄØĮąjEëÕ4†ŌŨöí>|ų‰šAÍpĐnãĖëþÁ4Aįæ|xøøÉÍũĨGŪÜóî2Ŧ9=ôĮ)‰•Øŧ;Xð ĢU+I]üōnŨÁŋâԙso^eœŋúHc0bløíóGžfdÞ―~û]ą†xJļ•žŽĸA)8,ŽĒĄÕZï1Ü y}îŌÃ7ŊîÜŧŸAƒ0­UŠk§ˆĶ•"Ŋdã`q!eų…§ïõOāŠĖôuģ—íÜąjÅîãšwöh>xDã›įŽ>y™yįúŽ% r*ĩļ –ŧ4ØÍ|ũâäŧ7Ĩl9ëaŽF+ō!ðrŨðŽ]=Ŋœ<ņúõíŦWóŠ5 ø‹WÏÃ2TĐx+ũïGÆTLĢöíšôjCW+ĀŲ= ļqxï˜ĶFŠŌr-oëØ8$ĪmTDuŅĮŠBæčāœuįb5oäa#ƒíÂ’Ķ wĄķžÞVEJCž1ݗœãąĀ° VQŲųųy:ŧxúú{ËØÜÞÝÏÏŨÁҧ{tĒ$§ Rcnãč„ōzŠŋæ––6jŲĐOtĻķ$§°Rcaëāį`néāíäd.ãHnåāébkd$·ö pwķĀĨrŋ wOWŪæCvvĐĖ=rJÂ`;)ĖÕÅ,;ߍ}Ę ōhØ$ qXD\‡nČûė!Žærgw‘B‚JÜžýƒC|Œ%ļ―§w ‹[`·6A…ģĘĪĩƒŋŋ·―™•Ģ_―č&üB Ü .ÍÍLj0đ―§‹ č6båîïęlZV^Úéûá―ÚĒ ÔŠ“5ĒÉ+,å1Sßā@g[wuÂÝ„Ĩ#:IÉēž"eHlïņßw“@œ™‡Ŋ›•)Jóēč˜Dý>ŋÄlƒû™É€þc0p 8(šŦĢ5_HĒ!MĢÕþqUq`ŲĪÄĩ'õÝ4ĐKާë(>ƒbjÛBKÖģ†XŠĻ·ųĩQ§F|%ÃčéDˆ=U—ŒÏÖįķ bâ[ßūbTÁŅäÓ#č} ĪūPŊ^/Ž{§Šĸ­PK_{U'I“„8bõÁŨžŨÝ.ęK^^Šoaę}cĐ/tëæ°ö­"įýVoÞôClDTlRŽŠĄ)’kĀQ@Ru–ūœ^wãjŦd­+éŧDR…Ïēz—ę'–gës,C|žqô†Ī_O nrļ:qúKa‚­ŧ}ĸ@gA‹.ý9 |› sşēk`s'kã€ŋ 9Fųô֝wđeļ•[Tl™ļķ4ð­ÁžeA[7_'ŦŋgĸzŽĸĸ7cðÏõDĐŋ<Čĸb^ŋŪðįþŧĀCˆ‰@Ū8tÔðþ=Ē­ŋÁ8k€!ÔĖāZ*eq/Ŋ!ĸâĐϑ$ņŋ•Ï1Ī–bDgęRéy–|õøņûrÖUĸ ƒJQöčYĶ‚äĸJPĢI‚æ8ā/Hþ[ƒ˜™ðōéãüjj 4þSZąĀģīļĸwþgÉ0õÄß 0„ZJ]YYŀŽĘYŋ`áåôJ ƒþ”8R~\·`á•įUĻ(üĸ Œ―ŧļa‚‹<†j…REŠK\måķÄЛ_)PôkûœJQĨÖŌ0†Š_ݛąxÓ ø§$ 0Ŋ=ąnáŪ 9ý“ŦėW•+Iüęē1ĻjýŒÉWß+PĪZ(\_ CāŨīÃÁ^ýüČč);+HþÛ`€!Ô Ķ―ã"tĐîšów? kJ—įŠœŠÂ}K"N†!“/―ŽÄp<óĖÆ5›ķŪZøcŦŅŋė@ð7†Pk(†Œ­?Ï\qmĖüëŨĖ qĶÖOzĐXūqįķNîÏœZĖāeÏûyöB›Ž? h#ßģ6ĩīiŲą[S·ĀYszŧU=đv!Ŋ€‚ļĘ {WŪ―Å˚3LsĸĀđÛy0XóúÁÂ‚ø—ŸnÜ/Ę™ŠgŨ~Ë+Ī!ŪęüÞëîpģį UÝ=pņaAöÝ“&ė5}Mō0ßë{ž.P€ĩ+Ya+ó.:VÃĻݐžé‘‚rí―kĮŪVÚÂåŨ~;ĸVbãëåÜū߈c›K@ĒâÝĐCŨâĮ$ú‘ŨŨŽž (Ļ˅°ömįį?>ņŧvĄ˜-ļwéðhöŽ!voŋōĪðݕIŧJ&ŽßÕÕ§lÅÆC5 ŪįäčwÎŋ|Scėƒģk|Ó{|ǧęęþã”6káÜía3ŨÚīĘÍũlÓđ™—[ßaƒãǜh ũãáZž=ĩýJ&7 æD0 ßīߜCû6rŊïĸý‘—§_€ĩGŋ13· "Kî_8óBč―3Æ­> ųyóöą!5“ŋ›üǚUÞ_ūxÉsĢķÓûŲíZ°å̊… ĄÖ€ŋ đ,SóčӋĶ?NéŨŪy@H'Yåï7&{ú|?rĪđōÓãũe4‚Å [š8ĪGûčöŪ4IA˜§ŧđeã09BKļwóuĐsšDÅúxšWŠŠu+fk7Ėú'Wĩ-,Ą•x·XŸ:§sTŒ \]Sþú]&ŲiH·°fÝzõÃjÔ Ęs ÞĒ• õâŌ­ËŊ‰^‘žwŪ^r?+nDWœĒA‘ĻÏÂ#ÐÔÁ' Äß Zî5ė§ÔA]Ú7 tWió)žãdÖÎÆÎūĄžĄ1mŅ}ÓōY#cmųКŠũEŲEEϷ͝qðũGŠ-AāôÕ0@3œ…ĸœå‹vičŠP—ļKũÎAį$Í9þ”‡;//G đH#W[s ‚Vŋ=š°xýÍ* þÕړįx#K›ō ‡æ-X–[Mg&Ð8ŧšúz9‰9Æ0kĘ/°―SF7ôî=zŠ•í‹įy Žâ‚û'l™Ņ·uó6F’Šj- ęü `€!Ô!R Ŋ(ŦĒ8@PŒ“1ĪÐĢ­ŪŪQ#2ĘÐÄČJhĄ†Ö-Íhš&YÅJÝ*`Œã8ČBÃÁ ,ķą AĨŪŽP@bÐĐf#…)J'ŒāPSVXĶĪ9™o2> ĻĪV’cyGŋ° ;hÁ éĶ͜ÚŅiãÂĐwjÚũ ’iЁĪĐjˆ1Į!ÔL†‰Ü 4 ԁgTZRĐU8Ã&ŒÎPœČ0€@4eįþÃø„åëwýŠBuēĨ[‹@ĮWEemÛ6j▟ýÎįûnvļ Wk)a<[Û+KWļräaRĢԐ 4IĐīzū(ˆÄXŽ0'.{øĐ”į9‘a@t•ŨĻI7mŲÓ9ũåđsũģÞf<Î|Ģå>?Ģ)ŽĪYARd Ēe5 ęė+ķ―Ŋ"d0n„a(ą0CwĶm|–UĀņpYaQfú“ëyŠ“įÏå+h@˜A™­Qąž#Ë+J^e<ýX]þāÎÅ"ÖĖۑúíðŽóŨ ARĐIJb=8&âúÎ5ŦvėMž―XfÕĩĩŧIhôœ œČÉH%Ï͎ŧĒJžÜoB­5ĶoÜĻ„Ĩä0 Aū6ÖR4ÚšįčGO7ĩB,ƒšnÚģ{nW_ŠĒÝZš;ĶCÓ­†ĶÎOjĨ­(ãq‹>Æû›Ð ÜvhrԘķ:ē)<€˜ MŲ2ĶŊ}eĨÂČĩéđC݌Zâ˜ļxnû@kģĀØ­§–†;‘yųe2\ŠÂ€žƒ’tØ―•-͛öī°đ“„fvӇu FcWkiNviÔÜe+û5Ēhģ ËS㞍Ë*ÔŅcÖ-šÞē†ēN]đqZkŧjĩɈy)m|ÎÂ0{óÎÓÎĶ$ŒæĶĶõoęXəÎ\ļķĢŋ}YQĩĐoŊEÓzâ ßnzĘÎy=ÉĒËf·ZčˆÐÞq&ũ‰…YÚÔ§óâÔDWœs ë:y`;#āĸrðߑ˜kHĖ1 éJ,CŅ,Xĸ3R†"ŽGq ÐÉB†!I<áļļ=§)ÁPŽ&i–`M,áŒg(ŠáGęŨ‡,C0œĮXšdxŊ–H0āƟÝ^>o5ÖĄĢōũOĻ€m;w{[ņLĢ„â E ū hAÅ1˜#„Q…@Ī&ĀpœŨ1 ÁgVčꀠ8ƒCÓĻ€ļZW1 ÕįYP|ýĖā8ČQ$Íã\|įxL"8š xŅshŠ`9 ÖĮŌ4+ÚĸØđ{Ũb0ãï›\r7‚Pč CÁÍĄÐĩôcí?Þ­Ý:8t„ÎvҐFĪNķÉCíó›ÄIÞāsDå[ ÁzŋQ’ŪkëHģ:ïŒTED·CŨ6šÛ1›ÖëföŪvŸÐúÎi^o‚Zß:S§Ąõ#Ûå3ĀsI-ĸpbŠ&Ŋ?ß^ž_ß?üāōöáþęĒÛw ĩ (%k;ļū{šy4õuŠ‘Î§H-PRŠ) ŽÅā/Ķ@j€ÔĐpŠj­•ãH)•RH-w6„°\.sÎŌcĖx‡/g1ãF!j+/-­øXY[[W]õąŽīŽŪĐ­8!æYA3ø{ZßĪÝtübT› |°\ØŌ.þ§ßā$Z”šÓD5E힉 |~$,O―ĸ°ĪĸŧÍo)Þ• þįUūMČ~_þ*áÝ9ņóîۓË;Ā?Ļ‘x?Ŧ”ø;Ŧ‡ÁS4ō›áfúLÐUV”WŠÕÕŽKļ|)é-þqõöÕÁĄë\g9lžŌ$ÃĀ–}Ä>`ýĄŸwü8gþî›Éĸx…āRîãKĮ‹D―’"$É/fž—eÃąĩY͘ŪÔęü› īhïÁ{ķ~5č‹yž!ûî[ãkÛĮšfj +%|”Ý…€Ï øoïžzÚ ï5ËíÚ[p0™ļƒÏïPÁÚ ’Ā`Œ qDØŅĄėüŠī!+lÍĶÜ*žRƒēw°Ž*ĐĮB‰Œ ô}îîûēj·™îķë';­3F#ĨbĻ äS―†˜Ffė>Lh –mÜč7 tR+ĪüvūHŽęŒ#eüą‚čĄōÂ4ōÁ§~`™˜ęXĶTw=ÆTríC þ2``@'%"HŪéîA­ā·· DJCt#Jm Ą‘R}Šâ ĻĄĶØĒ„TۖIíÔĘ`]! kð΃PF:[ŸænbŪgĘTHDBųïO(Ī"ęLÁÝ―*™ļÏŦāŪîÆXėĒļöY15”@ÂäXą™fā”r ĩ†R9Š= SÕsĨã:yøŽ˜2Čī{ʂŧ7Ž{ž[.WĢLK–…Đ>Ķ–Q ’  Ū–PSVĸaĘŠ–ĶOðþÃ{–_=•W%LI]^™tÃ%~‡P~ĸC!А‹E čŅÖÚÐwüĖCïtyûz\‹Gaļó|’ÔBĄ8I2!ó&&ðEŠŪéә&}ú4ĀķYĩsĸ$k&ÐBÄB*ÍĐӕZÏ…­olmmÝÏÚĘÄĖĻ• Õķ03fĒíå­uAþģ&M=rã=€ĸ&nՊEnNëũ\—|*@höĢ%%ŋÜšėRBĩĻ"qà gw—ENËCëÕ8Ōôfuðæ]›ÃĖķ]ū™§VĪÄĮd―L Xu/ŦQT‘°^žÐeÅæz5‰I?ōwrũ\ąåį6ųî͓Ä9§ü—ÄóŕŲwRr īTž ðœiįėęþWŲ{›q@hŦÆËäŧwßÖ€ݏtģģuņp[·ųž`/ô·wķst?ôø@YôÏÁAÁA›ÖĖ>aýŪĮ(Ŋžø.vrũp;|ýĐ ŋ|ër7gŧÕŧŦÅøGMO#JŠÚëîūhÖny•J4·‡9{z͟iũËÓ:ļ!yþʰ ĐķH}x|Ânïcy]áÎ GW§€õGkDŠžĖ‘ŧgÂ7ÞČÔĶŊŽYįđ-1ŋĐðîi;WO·…>A‡ëÚ€īþē}mV €ęþ/;nžhė]ōY,2?ýę/įģĶÝČŠp c–z{đ:- ?õPB^ģýJ/wĮï]ÖĪÕĻāŸ^°v™·įâe ŌüĻݎöÞŪ›n=|Íbq@/ÜĒį.ÎönžŪövßÔĩ*›_G]‰Éąáā=Ų}~V|⋮ˆ U’ŠXķōCüÆÍóĶ·ųįDiŲŦ°ĩnŽËCN5J5―kalݰÍā/ū>ÄÆD·ŸÞūÄÁÍÍŲuÍë1 āŽ+{]}ÜÛz_Œ-&xĸü„ßšmK<}‚nįõîÆŌĘzā—CfOŠUĒķŠs;7är1@JĒ"·ßËãą 8 eû­sĄÎ įĖrËŪj  I@íˆ}pĩRŒá*Á/{,ēwsņÞõkĄŪÔę|f8Nhá Á@?|”:Ŋ?smĮũ/<ĄĒð[ĀėSiņQž„ČgÅm ëGwũņc~ØzðĘōyƒŲ}ŋ=tãENZ4§*!§BBšâļį2ëŲ’ŸÚÔ&ĶUhėįÏ3pú™[Ũ—ÍĖķüöįYT0ûc\nĩB^wëisĕ'OÎï·Ō‡ÆOąuš9vŨŊŅ.ßY+ÍU­" l9&–œž‘vûČK6øŊ1ŊœÛˆÁm9˃ONZq2=3óōi/FKnčîGþŨŸĸšëĮûÖŠĶjˆyQ0ÆsŨÓģþoîßĐCðœŦŨ28SïÄeė ôā$&rGCBjü|(ĸâý<ðhtšT.hc~đýÔ{ī(:6úâeÛ^fgEx)nž|@úÃũí駞–žíÄųێöÎl[ŸĮōNI‰5Đ}õü :AėißĘūwŦL„~Č|ZaAïÏų°6üō†ČĮ™‰“ĐŧÏ?U’īÖæ B€ [ŠÅŽWÅgÐ$džjÉĶswŽŽü!3.^$ãn Ü;ŌĸhԃÓ'"ž|ŅØVk]ÉĘI  =ÛÉ­,Ō ™{3e_EÆšņáŨӒböëĮÁ ô€…åÛWïøa͉Ė™aöðî―—4~\í2Ó}ĸĐP7Ô=ü”isĶ ļ-ōú&§1 +)kęw0ú„GƍŧmjŲ‘­!e}ӒŸ1ËîÝLzß+mƒŅøó:įv|åķ|Æ0ƒė‡?G•šŸšâōâõĮĩĨIŽ&†]LšypÁ­Cŧy@;jrS+6ėŋĩzčÁféý––ūrĨŨĄó7.ýƂÖÐP.D€PASĩDH:­CŠÃîÆ$…Îcė?rMĒĄNĶnŠ-•ĒŒēįûFËÏF§fĪĮėwĐÛAįß G™ó—op˜8ļŠŲšÉR"˜īŨHoĶ5Ë ô™LÐCÏȜÍ12íÓGÍāŨÖE†­j2åÔËpÐ.Óïž5ØÅ†3ĩÉąčË6Ð71ëÃbŅÄíĩ§ÂV5›éŨ) UíŧÚãYčŧÉ?ú?Ė134ēb›™ģ @B!ƒ&æUUū, ZdŪÏÔĮŸ :FG%\ņÐÁΞÓ9 Ā1f6ČڛNŪũab,D>#ĶÂĮ;-Y?{”ēp€ūÁ[đ Zļ9ÄaÕO[GŊĮ‚ŲÔ―úPÏsųðHÔĘY<úģLÓlčOŦýG [Xôi%`’ îĐĢŪĮÔ0T|ˆ!EĄ>+ü/{ø°l YNĸþĖdË §á†ėk΋Ģy ðCãß;9Ýy|5.#™•’>óûÃĨęŅģæOąĪ0ÕvrÖÛ52›E§ģ!,]Õ6zˆšcėūvóÄá™eÃL1ĩJÐVQĸá\ØÛ‹šZ‡ŪŅ *itäþī6ˆß$·ckOjhâäŋb@ýڒVtČøŲĢLŲĀtúÂI/ä0čÉ[*x†‹'|ĮĪ1fÛ.ŒH~Þ("MMÍõHc―OÅÎȜcldhlÂĒT‰Ov_ą|úpŅkŽ~ +jī&õ‡Â›-\|‚øĐ&+—eĄÓ-›ˆĩĢBTm_Ūv-‘ ySü\”2~ĪéČJg ģĖĶB@éøXįĀy“^H °5nŦËēđó§ąeeLMë\(†>Dƒ†ę[ õu·ûŌL˜<ýĖu‘Æ@*˜Eƒ ’_ōý@S@Žîwĩ:ĸ$č@úEa’ĪÓ =+Ėņ9“ōĒžęĨÓ7žÆ;ĮֆÖÏÛ|ûâŲņ}ĻÚČĶÓp’Ð'Pm7J‚ IÆ5$Ī ^ÖhŧEljȍŅ7čL΋[ۓĸšŲLc_,W}zƒ‘‘å—ýĮf IPÃöΞWƒd™ôeqųųŋĩkÄQS›ál“Ą§oeūLŠ(‹ĐOĨ ôiÖÎNC͎Ä`Ģģoå―đēfZĞų|Æ_M·hmtLJAqĖžÕÓqT^W^(Ó―d@Ã0P CĐJØøþöū™Ÿ\ß4įGb0ąpÉØö‡ËVÄ/ōô3Óį˜#ؘicSJŠ 7šŒĸ=cČphāOlÜp;xyLÔ'Ü\P!ŅŽŅ\^bĀē`3ĨFh4 ï]nI!ݐ~‘Iƒ0ˆjŠ1ƒih>ØĘoóŅÄy55y>“­Ē#|OyuÆ~ļ‰Ļëܒ$Ŧ€ķ Aōöę*‰*ē^0˜ŽOģÍ,åŠíĩĨå@ßŌԘ…`‰ã ‚PžY‰kIöŽ*Ä`ũE°qģ6DĮ§•VŽ]8 |B8kÔäYóėŠ†7Õ†€6h„Ýųąų…Žot0ävŸ˜õú]zlĪ  8p&ø#Į͘·!tƒŧÝt3&„Ģ8ĩP( RÔįŋĐ(fŅŅT2~ŦÐŌÔdffdĀĶũūZH’5lęŨuÜW\P0ՕZÏŒ„P’†ÓȞŧZFņÎïe ㈞õ‘[ŦĢV{ûúyyšg֊Āï €ĀôΝkØĶ~{óPÐķ}b}üöđˆb1‹Āšß†IC`’Ā˜ýÆÎ(ũļ~ŋqęžąų7Ļāý}üþ•é9Vyŧíž,7óÝ0sŽÍĻ~$ÄÛ9·EC#qFC7ļ%üÅé Ýü ļŠOõ†ā (ÞՀ„e=óؒéŨVÍuũôXģņ 9töķņ'—zûųy{ûjĶ1FÐŪŋÚK%Ï4™‘û=\―Üz1uúô!}Œ7í ßEyûøúxųÝJ(Cԕ›ž–―jTƒOH1œė,t'Mú þ­ņũ~úŪEü.éIf Óâk[ûáÅŽQNvS0Øš=Âüýyoj]ï―,―Ė^=Ví;ï§ąæĀtĪ}øâ1!Ūö~^örMB<Œô ûZ˜íýÉÁ9üL•Äœø"ŠáÚŽAŠoþÕþSkNųøųyø­OĻŽb+,šé·îāk9ëÁÅãïÛ4?ýīÕŲúĮŊ</rw۟]-#q:čĄßoÜŪ―.7·ļų.õ 9īiŲà ƒ@/ÉWsŋ59ŧ%ðøÅ2‡Œė\UXC*Yæ;vF°^õĪĶėáō0ŋšŨaLœĻŒXë>Ū/2ÔÝuÆ·sÝÂfAđ+ž|||<#%ũŸāyĀýë=Ë<üü|ÖïØ' ƒĶÃ8ø#\{atc˜ô37Ņß`įūëRƒž/Aā€N—sk­ð_âëžïÁËāMþf†éa8ņûKg=wÏīĐ_ī`1uė~P þĢĸóč(Šâ⒩ŠjAÔ‰*[<ŊĻψė S75Ô (ŲIÔTQϗQ ĩˆ[ZތZ-•Ŋbc’RŌÛä0ų;B]Q^/Ó`TS#k}‘œ‘ûžŨPžóę5_&ųXÕŌų ÆýX&PhÖ'ÅĨ—KPe{æïÁđoxî›ĖÄØøÄŠ:ēS{KUJR\ģՈyÕMmĐU_˜›”] Tad7œÏmŽm‘SĐðđ چ–ž4?#66þõŧmō„Š8;íų쨌ĖJ‚TīÖV7·áTZʎē’ZAŠËŌâ“3ļb5ŲIPS’ŸVÕāŠĶþS/•(?Mƒ›Ŧ˄*œjķ7Ö4ķĘĻÎę?žLHLŪá6dfW6 Đ0™W\Ũ‚’Ý$-ï“âbSęÛ%d/hã‹iãFÝĸ ŧĀĒžôĘ؄Â:qũmõ)‰qYĨu\nOĪ!{åŅÖÜĀjsV yMžŪEĐ(Ė§f“žË•Â$*/ČNKĖzßÔT—žÛĶP·|,õŽž\Иš“žUÁãĩ4ĩJČ?@Š^gRŦ[PÖ5˜ •ÛØ*%ĸHŅZ•–˜”_Ø!oŊĐiéÐNGÞ^ZRŨ5‚°đ ).&1)ĨQ ë5aUUYANVffv^ƒ {Á5â*ę≋O,ŦoéMü6;9.6.ũ·"˜ĘģĢųcÃIčhĐé<Ÿy5ɉq/+šđum˜ÄÔ5%ųyŊâããó>Tv„ōÚÄÔSŠÆęrą†Ð-hLKˆML/n”ĸŠÂÂB>ŸŊŅhÔ EŅōōŠēērđ\&üW@Ô'øĢÃfģkkë9―Aƒâ8þŨ›(ŠD"ę7nÐų4ĒęĻĢŲއÍiā3 sl:Tfóčþø?DįýûũÔ&ŠÆÆÆ―ģƒÁĻŪŪĄbūür‚ š—ÅþœŽŽ^ŸaëŸÍØõ;î3uuVGWj?ČŽ%ÐŅŅ―,öĸ{ēŽ–vą ôPŠ:څr|nhkSĢX…ƒĸãÔÂÆœīĄĔēf!øgtttĨV'ûÔæýą@œ;§~🎃ÏKZ•`;Ũ.âl:øÐV[VÉýŨ ĨJĖ+ŊiFĻ+Lūõ$åÉUŊŲKŸe·‚?ĨĢĢ+ĩ:ˆŠU Ģ ĮwNþŽßӁ˅@,C @QIĄŒėz G1āˆZ(#xOWj™ C SÁ]1$"§ŽVĻPðrĒ/–Ô”'$?âi@7 bĐŅ 8ĄÁS $2mũ$&D øSÚJõ…ŪÄHm0õŽýũ .îčŦŅžžQjRUũąBõOhäB‘LÕĩ_ÁíȈϨW"Кė9@ĢRcxũ#Vwm  …’ŪéãE9Ņ'Ŋ>j)Nõūuåė•Ëvý?Īåƒ?ĨĢĢ+ĩ:‹ÁĶA GeÎóļĖ"€ÖŠ7Þģlœû…æs%åOO{û.v˜įrėÎ+€úŒË~Á;ũŊ›=cÂōWeW<ßāįéæéš3*@Ó^ģ/ÄÅÁÕŅÃoK_zÓTŸŠi Ýn]–ýĒĻPPé­#ÓæŲŊ]ëŧÄÉ-ĐR4―^ž)hÅŠ…ëÖvHîÛėåč6Ë}Ųãũ|@{^ĖĘe \C"îČQ iČ[ē9,tËÛy>›\>î―`þTߐ"1Nõ|ïčօN.nKŨĶvîþshĮšĩŦCV͟:Ýųtr•ļ1'öqK'ÖoVũäw-pYȑ$œjbu˖§VķæÞ;áäčdïāt#Ģ E[Ÿœ>õäŲ%KÏīcc:*jĻiĮGûčččJ­Îß!āóZ„R*žt ”7h}RZFÚÝã#4Ŋ—…]žąåéģÏNė|/@Á͊Nīšŋ2þáɖØËĨrPžp0ģjčõļÔãķL yraoŠÆ6)%~vŋúËģpðIyü3žŊ]ÄūݎÞ6žĶJc.žO•D'Ķ]=đOÝ^*PÃĄz—f4nyĘåāí™}ũđGRO;ØyIŠBƒ·°mI‹ŧRũôXB•’N* b28ݓãŊ7%yĨz9ųųþË\ÁĮØË[ĢÅw“S8žðŨ4H[+ Ë$K"âNÛÄ%§ þÁaöũ~KÖ]<éĶšp؏I{|ĪJ>^―ðPbc-Čûé`FāéG·B]"ÏÉ,=VŊqœí~ũ~Č@Cˆ–n ZûUЉÚŽŽî:ņfÛÞm:ĶčĻ.Ïk[rÍūŊĄzŌ6I•’ĸdo@"Đ@9érÄâuÁnÓHyÉķ ƒÉ‡įf­õ^PáģaĸFŸo[4ōæ7ũ<’…ž6û)―ÞËDˆSr2J?Ð/žþåmĢ://ĄþP@{Wh9wĪĩLøÆÚ†F’€ë· šcÎđų™’fÞ&ÏňŒa`< ÅÄÕļFs-|ņ}ĻYaČĶŅĐ`ƒ‰vAkįôÃŦM,įm^7ČBmĨoĪOĮZZåÜŨkÝåuĩä7?d(>Ũ‡ÚåÄæÝcģvˆIÓãčģMŒM @áK͟ûõiōkAjÎ\ũCÆhģœ[~6,@OŅ!gL a@ßÔČĀ€nnbČ č•b^Þ?=ðOéččJ­D@ôÞû 8É1ûÂfīQvI‘ßė HˆeÃė°ãFāüþ$†ĻĒ‚mmBQTĐ킠[Ėļ_]“vĀnÉÖųķ }HhÄĪĨwÎmčk!ôāWdÅĸÖ~ðð7ý9cGn, ŋ•RĩØĘÜ@\TÝŌNkûīūi H=&‹öåˆoŽžšyvœĩ #lēÕ…FŲŋrē•,ƒ…Uc€dF4ĄZ(LP)2L͍ŽGL>ó܈~ˆÓÓö ŅfŽtP4DĐÁ@oĖ!+t\ái:i杅3ŒšŸö4<ėČ5ŨI_`„­Į,PŠj”īĖxDÎī4::š_ čüÕU%ÚčėââāāļýBIÃ! Ĩql~ ߖ{!l‘‹ŧĢoX%{Æé5‹î†ŧøøŊ ŲôQ ˜4}ļŦ<‘ AlĻð^ˆŦ‡ÏÞģ‰ĢįĖķ61s_ą}`Í-_ßĨ~ū^73 HÐK~*ģZā°`þ<[{Ŋ>?Ü?eãšŌī dÕŠˆKiCĻū AlîÞBaŒÃ&ŸiŠ 7oĸĨÞ·Ý•é:ącsÉĨ@ŋĨþū~Þ/đƒĶ‡hŅĩ'áÚIƒÕ*%ų­ûęĨ_óýĻ<|――=D Ģ0čŒ :7C˜8mlėĨ}ũÞRƒOūs\=T,=ÃmĒžÕw[}lŽ„,õ_šÄmSdĐ2rlmþŊÞ~ûy”f%ŋ-G ðOéččîjuf…\{īļ]Đ­9Iĸ1Ã-†}GBŒá“øë â†v͉ÍWÖ}Íw°0·ŠYila=ˆØģCoŽc˜&Ģ~ū}ģŊ1DØ­YßŋI鍛2ՂĀČЧŸÞÍ{[BŒQßĨõö9KwN°an ·č)éc`ģrۙY­z4ųæũĐú ”>`Öís“újc:xęb^Þŧ5ÞÏækĢ}ƒĢƏ+Š38†ßXÐYô9·ÏMąÔ ūvëЗ–lę °Ŧũôū0ƒ Ų[Ýžš›ŊDéFŅðÝ5īŒ[rč$fDĢV`ŎÛĢmՌ~Lð A`ĸ{ũ"Gpü73;7›·É0&æ4  A=ÐEÄDDRX؈Ērf“ĘJÁB0"D,$âæš`@ QQ+ËKOÐ`!‚‚5 rBØÛĸ‚™5ē~>žzšûōöũïŪÜđkßþ;Šˆhu|âĨko;uöü…öüŽnޛ߷<<úÕ·Éæ46Ý~ïŌzŊ•Fƒ` o ā „s§—‡·í^8ûåĐ/ķßĸÞóƒ­E—ÔéŨŸ|ęÍŅņWÏxŲ°åú#/>3ú.ß|hÏuŧ’ļôŪÞûØō]Å’ķæ·_SŊøÏčnÝÖ ˜ņc1Đ@jĪАZĐ@jĪ@jZĐ@jĪĀ#ŠĀpååc+Ãhþ`Ð?H-ðugïđuKSŸ’ZĪ@jZАZāÏ\Õ―iïÎCõšåЇŋėÔy―kũRüäĖųÏOŽ^IŌ$ĀŪšēáņ_:[+Ũcē^H-4å‘=GoÞqwüJ9Đ&ã2@jĄuU?ŒˆoÎ}ýÁGïÄÏŠĻŠĐ…fLÆåûŸ,ŋûákOŸxô‡ ß8ƒÆ%i’fÉĐōȊ$@jĄqY+ŲØËëČVåÔR‹ØÕnhg›zEŧÛrŧkŠĪÔ6ËÓ4KĪ@jĪø;o}úÂÏÝxß37<ûöÃ1 H-˜Øílãåyg.ßÐɌn§Ãe/pëk.Ŋk[UŅʓV‘Hmó°Ŧ―,ŦW€€Ô ĀĸՁþāØĘ°ĐOR üÞ °^R ĩH-€Ô ĩR ĩH-€ÔÎ<АZĐ@jĪ@jZĐ@jĪ@jðs)Ër2™ÄEDRûW(Šbmmmuu5þ)`<įy.ĩŒŠŠ:Îââb\4°ą­ŠJjĸ%~ûŽÅĪАZĐĀ ~lï>ĀĢŠōþŸs6)“ÞC$„Pc @Ī ‚îbÁÅąŪšļ.ŦbE\ Ũ‚,‹eÕÝYŠ R BHï―MĶÝrÎųßdķðĸ.žo`ŸGĮ“3ŋ™sïãó|Ÿ3gî=ƒû >žĀŽ\.„ŒąÝnommmhhhiiąŲlŪþĸÓčŋøģQ ŪĒÉŽ,ËåååyyyEEEgΜ9uęÔņãĮ‹‹‹%IšTĒNÄø %-ūČģkĸ(`4āQ 9ëp8īÕæģÉÉÉ7ÜpÃôéÓ§L™’’’ĒålnnŪ6―í7mą(H_|ąŊÃŪšJˆ ęD‘`ü·ķNkkeĪ·%­S{ zûīNąŊ€` ÁDkœ›ŽbQo-§Ö|•í ĒN }ókĄïÝþVĢØÚū}ö­&[ã·?9$üËXŪ—h――„ÞWüýåļũþ—ˆZˆÚ’’―^Ÿžž(‚kÝĀßß_ŧgŨËËK›Ûö·h‹‰ ĻMū—Ûieihci^öąã­VU/ mĩ%û~ČiąqZO9x$Ŋ†‰Ī&?ïhÞEäžöģŅŲûó,6V~tũęeŦÏķKDCmžðÂį{ ­N{muMAîĄÓe-‚(Z[Ëũ8ÖeW{ã’#ĔæžV2ø™Ü :ÜŌ;֑V;'rw^NvqUX{CSqAîÉâ2.ķŪÆÃŲ]’ˆ•â‡r‹&ˆZðŋģDÛÕÕÕŅŅ‘ Š"ĸgc­ŋ§§§đđđ7‚/€#Bzĸu…6WKóv}øîŠÏ֗Ÿ|vésï}ôeu{ŨÁŊ·<ŋėÍ/ŋ)Ž8ąwóšÕkVŊÛômmíá ‹_ÛðᚕËŋĘĐ.;ķu뎾â$ŠÔÚ| {ÏŨ_čän%{|úŧW^|ýãēĶú7Vmxý[+ķæ9v&š{góS5•§Ž>ģôŲõ}UÛÚķoÏWkÖŪ_·þĩ §ãƒ'[ĸŅ;O>ûæ‰SMߎxbՇûjš{J vūüÖÆw^&§ūG ļ\q‚ īĩĩųøøxzz*Š‚þŅhÔĶ·uuuáááýîĩȑ ĢNÕmpĒ1ēW<ÜØļ`ëÛ7Ģ͜_9ōø{š‹ķūôā6æ3aļđąĐ:g=°lņČÆņKÜvcæâs'Į!§Ó;/cÆāĨÄČGĢŊ›ījņ„Ŋ·ĸ5ĸðŪÍ{ š?­īĩIĄČ C.I6ËÁCđ!wĸåÍ9ĻãäÃ[Öû„ÜhV­-݇û°§V>šýŲöķĶŽ ĸ@cw w§û6ŋÝ#ŒMónmėtˆQޜSÆ9Ē\ŅÕŦÕęîîN)ÕĒVûóßģXKamVÛïr-cvUfZƒˆÝåßŊúŽôáÉąĮëĨÁą~JÃĄėÜĀp?Sx@ĀĄß^a ˆJądfM*@­E9‡›Ē‚žtJՙĒē&K‚Ŋ‘#nënĖ=T=\ņð™Qæá3$<>|HjVt盨·žÁđ"IŒq•Ąā€i_öĄ\ĸp?ÏĻ”ņÝšäcâ‡ų°ŋðP7B‘BõĒ.á§?ÍúýĶŋėØ?6>#Pš~sâ Óáėï=Ââã#‚9cčŠĒÖ$Ir:ŠŠ^pÚŦ=Ŧ=Ē âŒ‰sŒ4đÎĻwČČéæ―Û#HŧšpĮôŧKĸ°áÍĖEkîšmæō•_l) šë‰‡jV}·kejh2VOîØhNYð󛇑ē#=ōókã'Ą*Iđi܇ßÎ>iR’Ņy%Ä 4î™K7þiĮŋ!1!AD>Æd4_?\ĖLIïn}góûk'.zuážYËWþuO}‹ŌŨM‰°>zø7ģxrϖ\Kėíã&g J>óōĶ­›ŠÍÇæį æ„ϰ+ĩ@ÔƘ··wuu5Ĩc|ÁŊŋ:;;ĩ5­ōBIŦŠÆˆ§~#Kã {Į>―á}Ũ3ēŽÄ=žrūÖRe…G――é­W‘åa+ßB} ·~øåįf ņfT–UôЋkz å%Nŋoí Ūõƅa§ÂŌÓCUân~dÂ- Ķ:e•s$―'͟ŦJ꾉XR؂_ŪZ€§ēÂ"ÞÞ8­w,I2žėTĮŽOãœ%%­ŸƒÓ ÔĀeŊýV+PeiäĢÏpŠJŠ‚Āp{{;ŒÁ`(/Ŋts3FGGQJ/9ĨĩZ­ûũïŨūþ þ—‰­(ŠÚĸâ“'OĶĨĨOÛ˅Р%ĒŽ`ĀQKKË8į‘‘áēŽĀŽöŋkVŦ-ÅÆÄĔ––F___­Įuí!Äfģi·3DFFšÍæËūƒ8õq€Ļý/IÛļļ8UUĩŧī+ īðÕBķĄĄĄĐĐIû3>>þĘl†ĀāŋįšZ BbbâčŅĢcÚrÁîÝŧOœ8!IRRRŌ°aÃ.ÏïÓ`V 0ÆÚZmHHúü€Ļ—Å՟ŠĀˆZ€1EĒŨ ƒ =jíËđ!,Ē‚{zäƒŲõ›þpjí;Į7þūhĸþÚķ6ŧ `t øß·ĮÚËð:ĩ‹ ƂöīŦæ Ē`„ΜiûōÏgË[œ‘ÃÃ2n“QÓ­|ýmYAAËEŊĘ˜+Ęø?F[sAI—SÅčĮrm2KÐ :―ˆĸþžz(ÚTÛØŅážp”bŌÝtĶŲęloíīŲ•+·@ÔA ••{Ũ%†§NJŒð7ļ{„™ĮLˆ2.n_nCII›Vƒ.ˆčDGÅK/~ÕhQ\1ĨÓõzÑ7Þ9ÕląÁįĘŅ`ėe BXïjëuHē4Օ˂Áõ&DüÛ3ø|Û ;_/ėęÔũū 1]ôąöÚâVŠôe7í.ŽéÔéÕïūÚSPÜc0ôŽĐuŧÞ #Ũ@šōïÞØYÞpęxQ}ģõÜļzŒņų#Ũj\CčŒˆpþåBo·ÖÐÅQ Æ6›žį`UĀāČāčā.ŧjqp‹“i]6Õä–4hïĄÚöv;!ļŸ_Īqœč”eĪ5 Ķŧ6ŋ:ĸîŧ6T2―ŧ{[Ųū…·Þ?ŅoK;T‘`QŊk,8ļþ·OÍžcŅGŠõ:ëo)ĐãGŽįm)klÍmrĖūu܈D_Ue?&ĻN‡TĐdĪ –{ęZ+DŊ °ŠqY'$%ņõ‘†M]ņ WņKïĻlé8ÛÔzĶððT“QPŠ€ĻýÁ˜ČNĐM&ĩ6\c%§ÎVvtī!Aīww•”ŨôāšÔ*ŧÍĶÕöĩDīó‰3Rųä–{|}°Óœ2mXŠ%·/^ûeæÝ·šS•õ§RĶáT<þž°ž·gß>ŸŽN“W[ttÝvČ\ÖXō]n~sE~éÉZ43ËgÉM7ýė?'ŒM7ŨoXøó›ūiXpßÔōĶ‚ēÜNĪũ,ÚúúÝũÞũŲĐŪԉ#ÍïūüR“ƒĖũeįûëūĖÁ"Ąœ1•ĐČüģ‡î *É-ičē9ĐëK0íQ§=ļsC`Čě3WüėŽđ ß5œg°”œ*lķI#•2Ę8&bUÁ=&ĢKðK\tĮdgŅņŌ6™ĩ}nÓŧ'ÚėRvaîœsO/=uZ%•‹’4rB“Îę.’9ïžYfosX [āÝŊ$w9=JUĘÜĒ–ŋųŠCgōņ4A3hP öðH_š<Í!jë%ÆÞÄįJüėĮ‹nėҟˆƒ>yé{ĢęÄ3&Âĸ•ÕËŧzß_{ïį:―€ųŽŽĐ}ÉŊ’ÍþAū>1ŋ^‘XŨŒ<ýÝ|u‹o‰3y!•qôï€ýjaŋZQŠ*>üĶ øš‰ž&Q ^ÜZ_q64:Î.š•ÛíÎڃ{’9zôPĨŸÉĸļ§8ÆŪīåœi=Øõecė_J]ĸÅ}x­áŠ~W•!Þ đޑ3­æ\ÓÕÉ1AÖúĢĨΑÃcô‚Ŧ@ƒØđČÄ ū7ü§1{_Ų[ü‡„\ĮåqÆþiŽŋ3BäÜĢŠp ĀeØŊöŒZˆZW0ýņë}ÕÔ+þúTƒ^Ô::$Ј3ĪPV’“āhū}Þ―^?݈U…rtÍĩŦįH„I㓞mU9°ģÓŨy›'TKÝÉ\c{eÖÄ$ƒÁ8@'mœ)?g€ŊÅc, ÐX8Žææf‹Åâããƒ~4Üŧ^;€$I:qâDVV–Á`@W‰ĘĘĘēēēÔÔTUUŅ?#„twwk'ņ#Ũ"\§ųLą/û !ÄjĩÖÕÕiĮíl  }~LÎ2GWÉéÂü‚ĒŠę‡ÂÐÅp§ĩ§―ĨĨĨ­SųqkŠÅöĐėB?ŽŲlÖōĻŋUUĩÓ]&ÁŽžîmŲŌÚÝmĨati˜ôūõbvŦUĶ_îiŧ퀠Š*ŽÕ^ƒŽ!\ü$ŒqSeΊ'žÝ]Ōíï­oŪQ^ĸáĢ3’įŪf]ëV<ą―ĻÍSgõ2íÉ%Æz^ôýéΕOžëĢ/c|~Ė4‘ũđdĶŋņ&W–œøaï!›Î$Šv›ę–uÛÏRt*ŋÄ4Vęér0ÉÓŦ-ÛŋÞ;õÖQÁz•ÁŊ0ühĀôķŋ„áΚWæßr8`þį۞ė‡ōģũĄH_•RcÎ(eœAˆqĶ#"ˆÔqðØ~ĸÉO/KïYļøÃáĐ+Œ§ŠĘ9'ĪïELŦ"ˆ1Šĩ0ŅéT·(!ZDŨbŒ/’wŒąKf1íƒ.D…Žš3ßþy§ĸ˜iģS‡Ĩ§đĩÓӀÆ9cĄóŦ ŪFoŦŊOЉ‡g·f ÃÜcdÆõ&OŽĻ―/9_ūØôĸÖsūqą@‡Ļ―ĀûôũĄ•ąĄpũ–FóÆžMŠðVš:u.SĘyeÁî7WŊĘŦ‘BĮ?õÂÓ)Aî”qDČ˜ ˆ1qCŌ&D$ÄĮˆnĒĩņĖŊ~õëâÚ6ĢOúëë–ĨD{5žÍ~áąe':ėáņ#Ũū·–0ĝڑŋüÉßzÍ|üņ›†ký'QŦé§ ÅYWuĘ4235Å۝0dė •·ŨœÞŧĸ˜MUõ>™ãĢýPÎŪÝMLTÛę›%ÔŽéÃ}…ĨUݕŸuŨMĖLĐ:Uė†ëþpĶĮÏh/)o0E&OŸrŧĩüŊ{+ŌĶe•c;·;Ģ32ã}Îæ:|ĒJFnĢ'LNŠō―HÚB jŊM°>ý=iģŲ|ƒ…™§C͈2а sVüúŅgÅɏüqíÄw–.\ôë ß}ð˜—ČīzÄ„=[>šũãâjÄåÓFË]•ũĸfUL{þ֙ÜzgâĒ€ũ/ŠMūï“Įo#ŧ'wR,`ZųÚ/VįXf}•(KýŪņþ˜‹jų9ýÉĮ(ÕĩķyČĖßŅSwöļ’x]f†ßūCíc†sKgWĢÄ{uķv;˜Ģ!ĸûœ’‘ÓæļU:øýĻŧf{b~ņƒ‡Ļ―˜ÕĘē,Iš"PYĒŠĒJNI!Š *Ÿžž’ŽšmV`Y=dÅO§û›šóÆŋÞ ŽÃžäƒ)Ķ"“)eūæ°Ôąņĩ[·oþ&gÉ ÁÛ>[wât[}­mĒÜÖZӚ}ÚãņWïJņīĘ~ˆK\°|ūôϘ›ķlzȝN‰ĄþĢö’ßđ&éý, `„(Ģ\é-`SΑ Ã-Íí]îÓfĮyûš’ã"Š•·8SÎĢGgĪ‹ÍŊĘŊUTFôžnĢÞ'Č닔ާTeē‡ßā&^ōŽ•ÉēLE„°Ļ=Į#LŦKŦ%ŦĩäČ~ėīPÕ­[b:ÆÐ…]ģ?ãDíEfĩQOŋ Î†Ú?þŋtî(ĢQh<‘Óã7Þ0$@g·46vÉAÍ ĩ=:―ž0Ę0ÃLC)Mž4ņūiÕÛ>ÝøÍũaUĨG:CVžxÏĶ'ŦFz―‡ŧhĐŠ­SF$Šēa…)n™·,č:ļņw›Ō–=8OÏaü?\@ļøÜ#BÜMÞ͇ÏÖ%Š ņ!ˆ:ív.čuÄŲÕãŒôóīÚí2ÖégËŠBÃqÆī†ėtRŽÎĸ> wļŠR•"ŽzËĻŠÚ,6ęįhhēĘ>{zđ SRjzχ!ė&PĘ/įn]åœģ€Á7Ž{,}ÓēĮ~ųüęĩŊŊÝYX‡tzÏÐ3͚7Ž]ņÛ5˗ŪËIøųí1ž"ãŪy#—%iûïß}bņCŪēΝ<ÆWĮÛËō·þiKEICîž}Í$î‘GÆnY―䙕ŦW―ņÎŲVYu8L#î|í…ÅübųúO%Ž0šB(Ō… 52Čūí›mrŽÍ9ļã›ŋ6"ó8ӑėƒ9Ų?|_Ô?Ę_‡ĻĒ0ÚëLU•rŽ―͞ķŠã‡ KėTëTxïđ2EV9ŌðÞzÆDŊ7$ÛũÝö‡Z{ŽLĨAq‰Áf’{ðXYųŲ‚b+Gøŋí >õƒ ƙ―5lGvQE-xjUjf’ĖÝ{æĩĝŧК, ŸY35c„Ā(Į―ŅãÄޏ?ũFUM“ĪōWfߗ66‰uG#óíŠņŲ/æŊg ÏúśÞqÛË: æĻ/·ÉŽíįûËũ?I)lpPî:Ž~ö?ŲL€3ŠĨáøé·DŨÔīY똘†&G†ûûŊŸjŪŪéēJĐã§ÄD+*1.“đ›ĐB#RŌLܝĐjHâļižÁ6†īÔŸ9ÉÄÝÜFNōä"bĖÕã#0CPV֔šÖ.wĸc™‚==UĢûÔi3+Šęl5ų1‚+'U%I“įŒ˜Ä9BD Š$)TAßŲóh]˜SI–ŲđjŌ2Ķfˆ!DUE’dÁyó‹0ÂTUSF“%‰r2yÖmY―ŅĖ%ÉIFM&TvÚ刍DN§“_Ū$ę'mĢ)6!)†qŒ ƈŠ*―'$õžæTĨŒ‘°(ÄĐÖōóE\ëÃzŊØĄZ c”{DEkuÜíT•rlŒˆŽfTe ų† 2‡ĸíú/ÄĻFôðMH2sŽ\cqtiŨԍđĀđGÍČČÐëõŠŠĒË\X§ÓÕôŅ6mčïÆ\ŧÝŪmIãšēâęúxA‘$ĐĐĐ)22ōڙÕīäōöö>}útllާ§įO"JiCCCEEETTcė‚ql4ŧšš:;;M&“ WWÔj9ÛÚÚęîî~­Íj€…ZŦÕZ^^ÞÞÞŪ(ĘÃk@íÜęááĄmŲĨMú.ĢÚđ6áœ_úŒŌŲ ‚  ŊŊŊ(ŠĩŨ(ĨZÎ^ŧŧ ‚ Å!ä’gt~Ú{Õ­!hŪŲY-0――Z0īð?ãĒ jĒD-@Ô õõõ„ā Ī/f:dąX mŊ䎰ZĖĒ%K–žũÞ{ųųųmmmí— -TĩhÕV‹ŲĸtéA6I_GqIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-tutorial-select-components.png0100777000000000000000000011137513761647206023716 0ustar00‰PNG  IHDRÎGæąm’ÄIDATxė’ÍŪÚ@ …QĨ,‘xxĸ-â"]ĩĒ *`Hf2“Û-EÖ5qïQ°U‹ ĨRÏšĸäƒÁl6Ëó<ÆøýRŧÝNū˜Ō…ú §Ö~ŋŨ)[äGžÞiŽjwøŦ|Īó?Ÿ~ԃðb“7Ēþ'ßČGģúÝPéŋ'[įƒó“ó‰1æy>N? ‡ÃņxœeŲ7GŽ,ž‹Ôétâˆ!øIð Vtf!ŅM7Į&,aÖ:zUqčžŅüņ|―ŌŋČGī5Ūbîí|ô#ŪrœÉ~›~ HBŨ߃Ýŧ'ĪŊũãCzr>Y–M&“Ņh4pÎĨ”bŒMÓÄVt­ë:‘šģRŦš :v' ,Κ7Ņ ī0åĒ{BĒŅŦv>Ēā#ēDHōQ)ąĪÍG˜Ålx<øm>0ũæM]Ë6œŊ É*ŅßVwī>Üþĸúņ› ˆ―GÃóœ| ų°Á97ðޗeY]*ÔõÖđeąøüōē˜ÏŨŦUœ”ō­čJg.Īëvŧ].—EQPÜl6œí S(ES_‹Oó_Šųz―Ē•8K6Ąîh~Ą‰xĮnÂ/Jīšs Đ2šjq†S/ ē8ž5)üšÖąiRôæã+^%Ķčt=Ï%ïãC-SŠ!h>Ō)þ?žŒXþÞʗÕųé_žÃ'ĪæõÛYŊĖ\ðUýþ?ð -GÁ‡d|5JzóÁ#,d5ðÏōĄØ›Į|ČĢų đā \+Š,ĄŸÔTíOTéũßé‡ĶÍ~ŅdŧXÖÆÆUtݕyãMQWŠ ŒÚ î͐bA^”Yƒ@Ũ­Úd^™a˜™;sïÜũũ{gÜĪMÓĶÉ~h›mŌ6ésįą'·Ü­ýī'ááy~Ï9ŋsžß=gŠU† fŊ^đvĪ~ā­ëÞëęĖŽŊa7§q·īītûöíąąąņņņP(”Ëå0!„@E2?<>ÐÔôøųC~Tåģ@<ąn^Tą3Z!ÐŽVąŲųMӄ‡æÄȆ ú8°ķũÕë ÜîøV§>€Āýi GxÕ°āU%žGķԚZœáoĶhîÔ§úēšš[Í―ŽšųdēČŦûéƒĘī~š­“&gŌiV1ėyąáĪN} —ÞĘJZđâМAk0Žĸ ~KEå3“Ss”þ5žŸ ­WvŠŧzØ^6čƒČō‰ĩPh~aņŨF­b7{ĢV­ÉģG§Č{wZũøâxēqęƒ ũÐĮn@čœ/ ŲOŸýį ÂĸO} NH ›ŨéUíŦÄbCYÞ@ŸšŪk53 CŊ•ˍžm―ûŽôËÏ~·3îM=9yėFýátø™ÕŽŠŠý;Zišžžž^XX ( ņrũøņcôƒŧ――mÔ óĢÕЍ‘í―ÞÚ=Ö&ïq;D‚[îŸuđ>:IŪ›†‰=ą3ʂV;büÛā vƒ 2Ļƒx…}ĩðĀ6€; JÂķK;Ųɉ0(^ņ}õŅ SĢ“Aß{ýwžh•ęNYūäëøÅĻÁ‡™5ƒXؘ8Ĩ­6 â@ė„QŒá 0ū+WËӝžņðowøŦž–é5Ēbūb†ēQ ZHM=Äą_ßHŽz™h°ŧka•|uģØ^ uBaĻĢKkËîsÁ0ЕM ‡Ũ˜xBŧ*•Â_}E+˜ÞBpUˆ†ËĸÆuŠ1ĘïlLzÏxg^ž|ÔÄSd‘‹ņKąf9·2qúäņÞŦCūÆÃWf#;9BŲ(˜ÚŠŽDķÐÎ:ƒxČ?e·Đįė0 _ßŲ?ŧú ôqöf@·ûÎŨŪđĀąØ˜ó…mŨdÁ į|aÜ9_ĀöÕ!E‘eY­Ú#hqxxâûßûãĮĸyoōï sĸ˜Ÿú˧Ũū<øÖÝŪ.į•švF†~Xgffhš†xI’}?xðĐ<ĘģZúS˜ûf%šsŨ;^?0brl€ŽWÄĶžÆ ðā Š Kīp‹_―K;§ý Bœßßva*lę*™ÏrĒŽ"7‰ÏĪ’ņxœ(ąˆĩ˜ßŽÅb[ŲĒ€žÅĢ—Nų.~’*rˆ*YkŠÂmĨފI^BGIā(’ä˜âææfķŠyĨ†Ū“ÏšÏ „‹š.ó%šå™b*•"JŒR{]Č&ãąt&+*j6ķäjn[ÚČqžĀ3d*™HlĶ)VDÎŊz›=1Ū™ ī>7*hV2ŧ™@°"š$Yd)šeKD"C𒂘uS ~Ðčūýõ~_5$V°^jĻbŅĶs‚ĒĶöðęų†ūŅX*ˋ2O“4+ ’EŽ.–8―Ķ–Íg67·ēž„ôýúĮ9h·oÐ?Ȱŋó֞Î>öųēƒÎÄ9_ÎØýį ÛwDQ Ņ?žZ&Ëũš·þðÏͧūíõĸírāÛūÎŋšÏh?>4sø2›•dûãûũïŊŽŽAÓ4Įq à …h4:==M’$ĶÁ"ĨKĢžūåsLĸē2üXųB―yŸýøÚzģĸæ‰B‘D ˜qN<ÏÕ:=áĘ~D/‡2œ$Į>ö({ˆ=)F *øÞĀ€Ā𭓠’-887{č󈎙Rþē§!04rĨÏssiÃ(—™Ėƀ§Åãó5·ī ,óš‘x8Þsí%™\rŅ}îz†U’îøýž––ÆāČŊ›ˆKVÔÔÓŧíū_ÓoßZž34ōf—ŨįũwŧšŽüīi,Ó „xžŊæ[ĄˆRVï_vũM†M­xĢÛ3ý,§ņ…‰ŸN7·û―·–ŨĻlü“KÞvĸ\N Û˧ęÕĸäXopŽĘŪßčï[z^PļÜÔĀŖw[[ģïÂHŽUŠąGíŪž@OScƒË;ÉrĻąŅÃQ_Ïú{‡ÂEĩ{tąÓÛÓÛãú°ĄÉ;+ˆlöy—ÛÓęņũõf8ff°ëGuu§[ûŋ\O?šđámït7čšU’u&·â9ëēæÆlĀ˜Ũ+JtqĘï>ëksŽ‚ž:áiïėëðķ'7IQAß]ÕWï\8rŽãWáĪŽš"+õųíën·ÏÕØz}â‰Hg~ÖzüPÝɞ ƒ‚ė ÎG ][đÚ>RMq~ĀŨÚÕÓŲŅvōčŅāøNR$G‡@7îÝ?ö@įæ_ĖV{lĮŸ™ÝÛ{Úw>û°cĀ/‚yÄĪĒMĨĄM j)JiUĨĄĪUäŠÁ<ŠÓĻĻĸīĻŠ6Š*EŠõĄķ”ī)*PĒH‰JhEDą] `ĻÎ9ÛøÎũڝ™ÝŲÎyŧɝ…ĻÚHýYZÍÎũ˜oóû>ŸĶĘ$•šŽT5t dĻôÓíûŦō Ð_óĸ„‰;į‡8sāœ;„ōwEBAÎ ģā3‹†U rÚōGđÅ)•žBAEĢQ]Ũĩ[ëH$"ŸķmßJYã뎥ĐV`ÍgÍ!šĢPM]Ô!ÆĐt!\bnĄVåšŪ|zVųdŒyi―b$ˆóųžŽ°ûÓŅWūĸÂφĶ5Ģ4Ļ DË4™í`Ē!ŨɚīŪ­ĩÚOM^°ļūHóķÅ ÛÖŽX‚Į•jđõ―ž4jōcLYšŠįîVÄļ?ŽÛĶUŋdÍĶžðąŸ~ïðKŊMå,á ]ÂY”GΞþãÇ~ō,Ō|ķÃWVíđl Zș>|íĖŦ?yų 7Ä ÄX.аjíōrb–(ũ.?―đïāž§Œ‰sŋûíņk龍™ýËŊ^úõéŅęø"˘dM35-FđĀćQ)?6°$FF“ā’å+Ģ„ûj͟ģ<―ÍĢØ“Ú_0ČTžzVU?žA<Ð#pĻŠĀēþRũ+e›•I NϙÝBe_ĪģZôßóĢžÍõŅņC<ģlrï“äiĄ•ŦĮ"1ģąwtáŪnÜÞe7/E}Ý+õ@@ýą&‹Årđ\ )0MSŽ`MÓTē$Zâ]lJømÜ_[Žę"(dĨhĒŠ ÍK‚ð0ČĘ^Ëþ§ys FĪRI”ƒÞūįþžÕ{ŠŨ\Ə„—ģēė)Ô ëJéCfp“yʒȐĸˆųfĖ Ąk6Ĩ°Vô]üĮ{YjgRŨģ7xXwl‡ZŒӗĸ9œu9!ČEˆ+_4-ʄ„‹°“=yė ģ{ãîþ­-ą°p°dŧ(u#i2::4ęó5&ĒXŌ—š1Q ôŠÜ1ššcÄq1Æn‰WLlAĒŅ™ū”L3VLÏdFÎŋXcũöĩ‰8"ĨI4ÄÄ,•Å{sÎĄ`(=6öþtĄ8ûAōz*ÉdŧrXSÎ’å Üæ2ŽH[é@ĪcŧPČ[œ#TŲ9jŊ{bÛ·v?ž>{nô&ē‹;”q3=zäÏCŸØēĢwóCaĒaÛ\ČĒ%uēhųî‘jĪw?ðĨŸ|vYa „m\Č%?p37ÆS3‘ÄŠGîo1Ó3M­-ÁXbýWz ~spï㠗Ëŧ˜JXI&6ŒģlęĘų‹ã(€JHD.9–6éôøŋ°ĄÕ„uÆmĄôOÃmôþŠä*õ#ĄęGEŲ)jÔ>BÁŽį_Ö)ja0FĀyޟĒeŸĶŠPĶüyųņ*Ÿ—ÏúŅņĩĄ7ĸ͜ĩõĪDáþđöÁÖzAÅÛîē°ŧ,‹ĨA+*†ÔVkąąXQŦbĢŽĒ`Q‚"Ë^`ö"Øô˜˜>šþˆNŲfj†Ī}čKÏÃäËŲïœ9ûå;OĢŠšĶU›QŦÕā 4­°ī(OŽßlü^,|ũõXôstŠZ*U€|HC%€|>/I|ŧŧŧŧ――…_sđĒ!&Š*'ÅÅw™`Ą·nöJ_‰“ą·ĐHY.Á>ŋ8ŠOXŽŠP,ėž} âĢŋhÅû ØĮŪē ía0}0€ũ'ÁFÉûj`x—-ÖaLČü‹>•‹Y–Œî\˜ Š―Z.„(’fYrˆĖ§ĖzCÎ͆ûƒ4ĮqĪÃ5sĄ™'æÝoJ @MtCß|ņŽÓIxG‚^Ęá LdĘR”%=éåoo·gíPŪ›Ō$=ôðqŊāũõ9<ɌÜh‰;?l\Éa†Z>8oXęJĖûģë -líÆ)G;Ãđ†îj'vOŠgéeūãÆËEq:0ēūwyeĻņįcÃ$í" Æ?WĐYĨôzåũŠš) CƒK[Y`čķ á'v$’ū4 āSûįšÕä,ïfób’Ķ|~žĒĮs’ĄŦ—Ó|%ldbWé‚Ģt{xiãŽpČÓLNŦg߇ÝþUóËĩ$nr=nŽį8v#ŊÉâ+Â+Jŋýu]æIšņ Žģ›\I]_›ŸÖæzšxÏ0ác (ŲÄ@g'Žž*æQ<ōÔ1@r~ŊĮé'­†ąjkëņųÂŲą°!Z–ÞęĖVĸ €ų™ ÆŋúGÓÛ/dx­%­û‚íj‚†AIŽ Û/LĸJÄÁôAäJ3*• dC IœČ@Mï_ŸÎÎæ_Ę;Û?(ĩz)bĘ?―†ŠęJJ ĘkBĒĄƒ –]`2ųNœÄQø9žŲHÖhGw.FûÅ~~ëĐ6ÕZœĖ3â—Rðz:‡ÃņxDDPݜmĀÄĄ’>{ûúÃóïžūš}öņðÆ'C4ķHņĮ+ē’Âs†Ž ąá#xZÃ$ēÅ —Ž{}.øĀģĨq1Åø ·ÓíõAqœ•ú2ü―>xþGŸŲÖZb į:6$ZļĖJûÂĻŽHN^Sđ3Wo]Lđq=Æ ÆšÚšĩĮq†H]?ūšyĸśŲįÚđĪðcÜ~ fķąpMFÛēZTÚQ.5{šD§A4ʒ›­_ƒÖ^*­&?+Ļï‰9`wCZĀS+i}‰Þ‚ũr&å ũėäĮƒķ‘ĐõXk„å_1A*Ūbjj-Ŋ ÆRŽfžN§ï~ETÄ%4š&BŠÖÄԈĀ^Ÿj Nۘ—ŸˆŒož\]ŋü”―Õ!wnîûģ]Ýýþ ŌZJíõ=H9>^ïĐÏ#Ė6a)†Á?pwpí Ïū,ĀŠyÍâē` $|”Ŧĩâ_6\ûpï(=Š GNárRŒĘĸø7üĄï_îËn7Đ- ĢžĩįToô ŠrĄ>€ümz.š-=Ļä8`Ο+,6ė`ÓgČĖ\óŸą”ĩ[Ú:HÉn>ŒØ ŽČ8tđgzf1rėœäčH:”|ĒSÏQ>ΚIÖHú §ŅšOFåėLX*6ðŪĩíĘ+f„‹ayɇüãĩ\íŊÔjņöęŸO“[>VôZâ]-Þ―ūúFPÎi―Yŧø~^’âe%‹™.ė&Ū„7„)Đ"_ÏnŽâŸÕÍÚ5ņUMŒ}ˆŧŜXbī 16`S"áã32Ÿ\Úo·Ðāč##ĮŊ?čÂb.iĮŧōéƒ`øïŦ7_æ0ÐyÐJœv0tâþĪĘhĸûĢ­Nsýõ}V›>֟…xJC)ßKĒ9þ!|ĻęÉgĀ˜ĪÄÐmÛĒųeŠsąXX M­ƒäØIÆÐĢ6ĪÓY†ã™eG“f!†þtCRîŅ>ĨĄ$!%ęĪÍĖÄŽ]|ÐH’mŌÅ'žÓ|ˉßķ]|4j>G‰uņņídÕîL&~#ÜÞ-øļ}øŋ•ïýîþû#ŋQïoo[Įõäãčģ|0*>x8Á>éorøÔ#0Üggȧ[Ė<Č)[$wG7 ‡ōQ*ï‘Íãfŧ^š˜EO͇ĸ8Íīð,ôņûSAčÏĮcŸ‘ÏݙÏÎ.>Či>ŲÓãïóa‡ž|MÓL&“édę‹#z<Oũ2›Î8ĒGĢŅd<™ÍfÍl—6Ïž™ÂC†%‰âą†N=Ē›!:ðr kŒĮcl„†h2-Igœ&“@!-qļ3/ķr–;č/šæ\5#Кžïéâc‘%%=ōĄ479Ã§Ø %œácčīĢäã›­8öáCBøĖ›†Â››ĸšiÁg<ҧėðÁ ߇NÛKøŒŽðÁÉ:僔Ëû“dD>I ķ|Úb4ŋā3ŊïO†Ö|PĀžišŅWų4Þ7™tņIÒ†uøāïÉCÎáƒ` —ņQS۟Î,ã˄ܟÐ.ųā‘žÓ|Ģ|8^Ƨ|2AðA><ÉĮ'‡č_~"ŧ…Ļiïũ’>ØešGu}ŽóK'šþu&ŦžÞ*#RđūūîZįų Ý|Jz%/‡ãsóA]§neīæĢįų |íþ|b‡ÎÓCãéâ“Ųxþ2>Øg‡†Ė™ûcóg僞$dðã';uoƒ` DAðÞaũß'Î@Ÿ>‰™6ØĩũūĒ>üD]ū €ũW €ÕX-€Õ`ĩV @—ô]ROôyŪĩæH}Vú!I―č:0zœrcï<ĀĒļÖĮ}Μ™YPT b#Qc‰%Ņ$6"æFėÄ†Ēą››kÆXŅØąGą!ˆbAQ0Š (v‘fCïÂē…-ģ3ĸ3lāæ&đíųĸî}4ũžęãΜï|įûfå}†e™SČeJĩŽ―ũŧ:DČ$ŋvþtčÉĻ­€þ +B‘ŋëXQ”N­”ÉŠËęïžo$ˆj ŋ‚ ïv،‘ŸõwqsqîŨsÐÔÛ9Z–Aŋą Bž*(pëúŧJtQā_E0õzĢ™ĸ­fr’Ģ}žû}ÞßŲýË!ƒ|Úģ§ĮĨûeˆaĀŧƒ &ĢAl@ Š%ü>ŠŌ|føÅgÕö>~‚į[6Ģ œPŊB‰uýöBķ6tÃĶ‘3Lˆ,R1 ‰5`Ģ’Y+ĐeS"ЕDʘ3î_ð[ēäa™ÁÚęo*aŅŦ{ã&Ï Ëqčé2uÖÜŊ=úthÃr‚NĻũ°ÔšIýęķ MYR3õ_ЈķąÅCM$ ‚]_Ģ­Ä)‚c†­ąežkēnZ_™Kƒz(šĩ–JąõC6Ö~†f$ķõŅR óË`ý,ĩb ģ’ĘŌâķ­õ―&o"eaýBVâeÁ A@ ÕÓBŠN^œĒ38öx|ĮÞ†þxi߀›˜JĻSFîYėååõį%ëē*õQPŒÁ) &YÔþ“žžfÍH-Ö`!BІ&íÍģē3§ˆļ]žû,hįžðČČÐã!Ņ7ÓĖ Ó`iÚPy2xKĐŌwáŠûŊŦÓëï^ ;™ũbÕĒŲ“§~wųaĄą:{ũēI“§û\ÍĻ héeQa!Ą'cR’o-œ5é›o}_UŌX·ˆzՕ-“pÆó"_ļ„Þ—ĪåhÁP}&hÕqĨo"âS ĸ5Ýō·‚B]‘}―mK+€$}―|Ū=ʔĐī5ZMuaæęiŪvķŌfÝšÚJĨmúÍM)Qę*ž čÕÚķm—ģ5U/}Įtif+íÜĨŦcÕÉÍ;)OŪ.}ąnî—ķ MKŽ›7kÚáĢĨįŽúÛÛJÍÚO[(ŦŦSĘETuö­pg€&#ïæTkÕøīˆRĨŌh4ųi—žņÍi“ΟX3LóÖv\LŨŨ•,sé)‘HZ;6ąĩÂ9m›·jûū“}ŋķīō§7mi’s/'‰Äú―ũZ7ĩfÄu?ûĒR]œđzšŧTjåāÐĨ‹“ÔĶđãðMgŦkę†Ė·ķbíš;ķni/úu đžYgŌ=žļĩ[Ë&ö-[ĩkå`mįļâÄ―]íýc‘JØæöm,Áīôó“·ēĘ2ãÝ>°†X·pė?}CZ^qðÂ~R†nÖg`ώÍŋöۓ+ŊU)äÂĸúÃ^•BēĶŧĢ€ķi1ÃĸhūLõäÂVkzNÝZQUzdÍT<ī9úđū2ÕĒÚk9š”ˆ…―=&æTŠOŽü€ÖÁŅéO.o· Å‡ž éÅJyEvvūZ–·Åg8žūũzĶZY-o@­Qe\ î åš8ŧBŪPüēž7G}ŋ€ŋ:DQ[óčˆsīë9į•Šl­óGē}―'=ŧ3õ}l[ëÏėyōčĮ)Î-tŧ•ĢĻ)Kþž{+deûÍōŲ™ũæô°ĮyüÃnÜ9ŧ·Ón„_–LWœÓÁ•ķí~&MþėÔ2–­ū<=ųȆ‰€‡Ēå%) Gu…<ČÏđØąûá§Ŧ+ ÆG!‹iÛwšŸ|xýž0(Jc4ÝÜïÝÚ|wøŽZĨŠ.{1ŋqZw8ĶčMuĨŽJV-'Ķ%‡―Ā, ŊUŅ—/l˜ï%Ô*Nn^īáDÂEu-%ũÃ'ŽļýÔ –œ[Ýø$…@iN‚ 0õÞīņĢw_Ė ē°ŠļēZĶ`ėü)}:Úó€måØÂŠĄËâ) Kãyŋú9>%ĻkM€ J0JĘ ĐËgӔĪŦ›ûûmmī5K<ēkã5Ũįó.ÞïdÍzø;åÓNÚīķ‚Ņ’„7óMÚtšą`r§N―†Ï–7ĐkUōĘZ\ØČ,ÕēÓ'ƒœŒĩ†ē*-‚ĮūįąÐÏkXŊ6NíņtDÁĩĒēĻ@°ïîļ:ĻLmŽ­K–i ˜9‰Ãėū‡öjÓ^ †Ö_ $þiDZÚbЈņ6 xÛō9ã&L>•ĖDOĀČgĩĻý†ŽÝēm6†ėŸōõ…{]šfãĄĢ§ð.N=ŧ›8Þ"IQIī +ēMį^~þëũŒĀŧ ÍüęcĄ>@Q‰ĩÄZIŽX†ŪO.ˆŠe$–iT^ąyëķÝ:#áeÔå{ŊDj…'ā? Åóoæ ÍYIhĀÕr&ā­,?yĢ @cfOEœbûüÉÛ‚Ģž&§?ūŸžïĘÓōÞC&J@eÔđÐ[wn_Š>UPntę9ūk ƀ•*ˆōĖž™“D( Õ(e ąW&^ˆŒJl›^ŧÐņCG[p6âėåGI·Ŋ^NĖ+fíŧtvjjÆóąnM8ïÏ`m7kóQßOÁ˜‘Y„Ø Ŋ,))ÐqĒ€lķ,ß4›ú:ððØųėųúZÍã+1*ÖiŌ<ŋ‰}!§WŦt&@ Ւ'8MîēĨߍ3jäȑ›‚ŊtüÓ7ëgxôāyú؎5—Ï?løðņ“§]I-Eâ8^ZJ‘Ųáãņa>ēŠð;ŌcĻĮXwŠŧ}11<Čŋ—Ýóĩó―G5isøsÓĄÃ'ôu°ÞïįģiŸH( ˆž؎™îļáŧvTY€ïīá#Féđhåî< ?ØËũĀŌ)éGýōÛĩ‘}<íß=Óņī™įĖņtĀ™Ė@JKĨ4DĪi ØXŽĒeRĘĖ_âéųíõB;ïĩ[†ömĸŅ€ąak>Ę―2sīĮؙūM{Ž :ļŨÅIĒ7šo23‚x%Äžž—īšēpËŌÉîŅWz 6|Ąy+OĐLÄ2į9žj 1›L]]ƏüŽeAvð4ĸe5Æø#þ̆ õõäsI֓,sûĪĀ™Áĸ6ōAQ]YōäáļØž5Üõ[w_VĻÕj…RĨQŦr3’ÄMsî?z\PōFY]™‘žš’úŠB&W(”šUÎËī[ qąņ7ï=HÉ+zĢPĐÕ*eöģĮ7Ä]<eūŪ’+”ŠęėīĮxëâĮO3d ĨüŊT+ð"ōŠ—éoÆ]Á›Û]‰―ņčizI…LĨÖĻÉïÆÅãÂæ–VkÕ*…Ē:?3=9%5ŋŽJ)—åd&%Ĩ=/Ŋ’+åU9YIIŊ*åMiōgÝš9u?u#ínÛũ“Ëd •R!WŠÔJeVĘĢxŧŲ›·^äkj4 đĒĒč§Ī§Ïē ĘqLiaÞýþ§ÂRđŨĨĐ*+xpũöõļë wĪĶįâu*Š^ãāž’7ŋV)‹ēŸ%Üļyũé \OÁëĖ;·o^ŧ›ø Đ·Ļ[&Č…ę—(į•* jŒR!ž·+~ *4fk<ũ7aJåï-ŽãÕŠ_`IĢĀį-ā, %)ëC-GJœŋĄĨx T*ĩš’']ÛZ1ãō4ĩXÏb°âwÚT*W6VŽ_[ÚlčMē4'üã`\€%­ÂRŒeĶeõ?ĒZÛąŠ0ōLXXÄųÜ7ĒöĒZá?ēŪNŊŊŦû]ÏDĩ@ Š%ĒZ@ Ðā­„Ā0 M#AoBĀqf“ÉþÞRÕÏŠÕęėė„( x[ ‚ŲĖwïÞÍÖֆã8ĒÚwŠĒäreģfvíÚĩåyž„Paa‘RĐlÚÔöpWK€bÕķlio6›Áہ@`{ÖrôQ-Ahžž0äŋ›y „·Wĩ@TK ĒZ@ Š%ĒZ@ ÕQ-@ ˆj Ļ–@ ˆj @TK€ X(Š‚āŋGýzĸŋ ZĘoˆų?øįaIBáDĩ„wx3§ÓjÔjŪÎH3 §•?{’"Ũ úûBQ°8#%ĩPņO—ƒBÁß|"J1Đ˓ž<ŨsxgÁíÁ·Ņ%ðw ƒĄ&>8ƒūÎ`ĸ–·üģ17=ĐļRļÚô'É5fGTKxũ`Xķ"õÚ_æÍ]šlņÜYsÄeŠsŌvŽÚŠ,‚ā?D,ý `õ†Ų,MgĻ‘Ë&ÂÆÉjÔrmĪcE‚ïŌÐęZqøDā5*…Þ`†oY‚Āá þŊ…AČsĨRÙðwŽ„M û~õ‘x3 þéZJg0ýšwHŅžâbāÚË·dL]E Ŋß­JCSDĩ„w)CUn…ÄiöÂ_uŊÛ4UĶVïč› P€Ņ4ƒĄi ZnŧÄC–e,7—B Ë`EYR‰ÃúW’Æy,4īZō0īåF†uH(A(œcIˆÅE 2â7oŲ_ËJոŌî_9~"ö§ tl*ÖJãĖ…Ā/þŠĒ†Ė– ī4Ú )ŠÆāþņ „ĄYASKb-æïN§ëcÕx0–-‡tÃõĪð,2xéĘ땾D‚Ä„ŒXžĨ‘ ݘ_žÔxĻąA\ ‚ÐÓÐ;ú›ŪC[Åuid)H<)K††w­ą0ķū0 ĻeKVÆËą°zËÖ<{°x[X>'aqŠņ}·īfAāLæúíԁĒŊĮÏUQČŌĒļjb,=ĸ‚•H ØŧBAlŅŪ9eK$ØŋZˆ3ÕÞI°ãÛč2ā‹93įtĒīš:“ĀC@Qfƒ"r‡ŊŧÛā1~A…:ĀR\ôĄõ.ƒÝūä}ævÃ0…Obf ‚ýø„b%šęŨë―=Ý\ŋ\pðЁb(,:zÅŲÍË\ÝÝĮN“ĨF,âîÝ;n°ÛĀoüž”éâ_/āü§ŅģÝ]]‡y…?.§ôŠ ûüœ]\ŧz_đ›ąccØÅpOÏ-YrŽ]IUeÝ Øģoũũ3F*ĄbĩWBw u0m]ĖĒō’.Ítsuî‘TL!Ôøý0ԔEîö8ČÅÕåÛøôjČiŽoš=d°ÛW#ĮÞÎŪd$LiJüÎM;VMtvąïĘ―K‡;t]uāŪ‘a˟ÅoÛļyËĪqû^þČ%ļÁcßÏÂӇŽ—øš O/IūūsËî}& üÂ}ÛĨT3-aĄņúQŸĄnnĢ&ŪČŪ2 “üÂîUĮCŒáöÕhŸŸŠųÂäó?œ‹ ˜8zÏé{\­|ïü.îî^s”D7HSĩ?môš“ĄÂ"ŽŦJ XēķHO>ž;v›ëĀUûNŦxÕdmô ĘӘišŋ}tYȃ"ŽBܰ„RïY°å|bVŲ•]s7đ­$yq‡ũEÞ{“ópšį07įIÛ"T ęޜÛĩęø‰ýž.Ãū^–§ō’Î8ģ}Âč}ũˆ„ÐXs3>ôâņcūžcĢSeęǧþs‡ŧđđÎZą5Wmlð;ĪĨ,SZ)‘˜cũlßŧϚYû ûsLĶ _Žô›GG{ļšyL‰ÉĻVÞ[ŋ/bËōYs6GŠe §ÃŲ<―7åË9„ë‹]þ]ķ,Q-bhUÎóØļȀuĮx§/;;ZcųԐO<ĩm{‚ōØŲÐîeįVïčÔÍ54*zŲ°Ē6\ŠCĶÓŦķ<ë;įėé“#ûõ`ŒU‡·­-í11˜―7,hÓęVÖĻėiÄž=7æ‹XÜ5oųÚĩQĒg%žōų\Ÿ€ūë‚-éŋ{m@ąŪî֑€ïƒŸ.:īšw7§~CGõïØkÃÆ‰í›RļBžėÚõäîú'ũŅ+– ēĶlĩÉį/?Ņ­ÚáWruïíŨJõ|Îâ]΂ƒ|úîX―=OeΆ’Ðæ“+o:šî·3čāþ―;2ŨŽų§6 8ūčëîó|6%éymÉĐĢĮīÝžýž? ˜3ýĒēũ†™#"ÂN>}ĢįÔőĄ§áˆoķ-đbåÕGŊŊ‡m:œŅbGHø‚1]į-ڔRĒ7kKN9zųOs‰;{&WËgÅYsFíwėô˜.U{ƒÏëý4öāŪĻ‚iūŦ:ë#.ĶĩîåėŅĢũÚÍ<ú%FnŽũ ßģfYÄņĒkxÔž] îÕîįÍĪD‹*oî đ?åÛímžķ…xŧYāh’%Ü―§6 ÁüŅf™†Â= díėđû›”ų!įĒķ&čĖš Įcktœ`å°ðûƒ§~Xiˆ:ô XgE›ĸxpwtņŽ•+Û+nœđ”Ņöã/†öpšâŋÉÓ―'m'ÆŠG·>ýûũûó–­ŪïŨ,úÎ7ŧՄ“§Ž7Ŋš5cEˆ–ƒßRT>OļžQ!*MŧsčāŲŽÞ“í^ŧte›·ïé4r~øņįö›ũ:čÖÞÃk‰ïtw`ĶÎũ?wfwŦōČ˜\ eĀĒZĒĻžü—q·ty„…ŊpēF€fN“‘-Ï{îįģ"1“Qį”rPĘJ7-õ;›Xj䊕ffČī1ė…] 6)ÓS5•ŲYïg^?ĩtÝŅW9đLÅC 'įÍB‹î}Į|jwĀwņÁ{Å6R˜‘Đ,->°zņ‰5ęWå €4‹Ę^ÞŊ*,Úŧ~݁;UŊjTŠęԒWÎĸ―óŠÚþþÚûī™ôÞB IHč-Ðŧô*]šôÞ{‘.MéUA@TTô"MTP)Ō{' é™ĖĖi{ïwfB‘ûęûÓũ§ũzŊįóĖsÖÞŦœÉó|9œ9ģÖ°QmS*Į”O(ZēTT°Ŋ_bÅr=ZĀ™ޓį6―øï{ø‹/#bjī’n~õå§ß˜‚jÖŪ`ē}ķ}î˜Uŧî"db@5 ‚f,œÝūQZų؈|kķUÂYXĨRaūā*Z&(ūBŸqþVaðÞKEĮMÐNûöÛ;EĢ_ZzaĀ…”v™ļxPģzÕ*‡˜%Uãý:·nzpã’É‹7æÞėQ:!>8ēLl‰@/_ũïūØ9jäĘŸŌ ­Z.PŒ~éđCj þóÐT­\ZŦÉSÖ˟1Žb /B(CXtóŠ)SoüĪiëÞYŋnq·œó{FÍ{ŧ^ŊŨŧĨÕx—ÜgÜĮŸŽŦĨ]ę=}Ģ{HáĩZô˜!fĮĻŽœË·1-ũöOį ŠĀÕôÐ*Ŋ$~:töĘ„æ‹†tfýÍōˆ._đ„štXŊĮRÃŅý{Æú#į1€™Ü8šŠé:‡x`Z‘MķĐ Ã3(Õr e•€Ųۏ·ÛóōŽP˜ũÄÎs"‡ž ø― @4BEFU"v4ũĢ­Kž1kýîB*iZŪÂŽ`ĸæ™GĒaĢ^ŊQ*qáū9ëðķæé!ĩĸYPMa6Mä1ŅdU'ŒęvŦ• ·īn―QþwŽ~öôá“ß_ŨAÓóÞđüõĮŊd_=wōÄOûŨmøäûkvũ5›<‚Ë5íÖüÔį}ûÃđ‘žvE™WūY·|û―\ŧŧčæÎs‰Íz— z°ûÝC/|óåņנּtŲZdĩųĮĶĶĨy}ļcĸO—Î;x8xķŽŨúÉÖ%ãg.^ąxå‰+™>þ!Y/ŪYýaķōTBpþ_|īkįģvāmēæTSĶX‹E ŠKŦ›ęþÁöštîčÁ/ģŠ―ĨØįĩÆ-oX8aöŌĨóWš+7čÔæøĮKŪÝ8uúœ*’Ŧ•ŲŪĘ2uĐŊÝjĢĖĐtEšŽ2äe2ø`ũŒđk–O›}ßTĄY―ΆíšýhÉb§ûĒÜŠëT‰diē;ÝŅŽvŧB­”Ž‘wÏðÁąsgN~wņēbÅjQt4EģŠ:oōōâÔmóū—ųčü—›ķ}ō°@õÜÍ"Å0Æŧ7kŨôėĐ;mÚķ äY‰Ú+•ū3ię‚õŦfĖŲũ8yā+ޞaĄ^öUKæOë7öÓŦŨcÏ| õŒiėq7—$ÖOHHj˜s3=ĐbÓwGvrïöõoOþúfæžcß劎ڋœ…ŌdÕŠRÁÍĮ“Ú·Î]tęNBØõ2Ŋ°ðüŊŽ­\øvĶgb“TóĘeģ7l^3féŅŊv*íÁŅgiuÅfs=ėElVU՞ZT"hŲÛßŲ~ôėm]tww3‹Ē{đø’?|ūmĮžïđ°āá­3'Ýŧpïėņï>ąiS4 Œ: #ŒģÝûē_‹æß=R%Ãßn„ `ðƒįųžž|Aā}||þĮ™qŒ1ÁÝ7štLа@ ÎÍXp +WĘALåĶÕJß―sËŠā°ĻļĘ5jVŒĘzbŦÝģOÝļÁ+ļ„7đqįXĶÚøA‚<Ýã*ÕŪāĮn=|L°g\bb·ÄC#ĒgßŧûČÆöÚ'ĨīāÕĶ^uõÉýô|ŧpđøØ0_ĸð˜Øøð°& R―í™ũŸäIQ åK—HĻ\7%<+#—ðž‰*”)W.ĶT`V†-ķRye8ītŒ/'ÛusB•*eK•Š-ÄcQ26ūœ—g@ӆõîecʖņ4ŧyÅÆ•/ã!`Æā? Œqnn.x{ŧþûø›A999ðÃ@’Ī[·î˜ÍĶččŋe89æE‘EQŲģg%‘Ũ™0$‡Ā‘e]2Ič…Fë ņœP]Uu ›$~nq8AļbģŠĻ”ËP‰)ēÂI&žjēFĮK.\ Ņ$áâôšŠ$=]øYĩÎČ*E^QƐĢNŠ)aĸW@xÆË‘uf2Iā‚hŽDÔų™ð Č*rūÁŠ,;L&g"íÄûŦ6†7vŠqĶ@ŋāîúHÁU€ŠČ”/šøâ”Œ*Š&JQ2ŅdÂT“U Ï!Šk:`‘ú‰9jx~Ū<Č[§ī;íÝ~ÉÔ!’*3Ž…â ŒĸyÉÄ#į1š3<ƒLŠ,3Ũđļ™+ĐË1ĒjDEĒĘ:u~DˆjŠę°HvĶ>ýį§ŽŦ2qäņCN4 ˆČŠæ8Įâæ™Eņ‰đþR˜\§L4ž{z4U刊:ĸúŪÂĀYžæČKĸ#/ƒnÜļÉ‹ŠŠPU͐Úŋ‡Ôþ~ B…Ų2 qÉR‘# þĨ0ŠÜ8Á=2ķD°—N(ümĪ–‡ŋŒ1Ŋ€(Ÿ@ ”0øWƒ°W­ĢÄÐŲĸr Đ50`ĖĐēĸ.ŅáŊ‡ņ‚!ĩ†ÔRk````H­ņ‚Bˆã8ø`@aŒÁŋCj U%3ý‘Č3``ð_ UGÁĄá’$jkH­ÁŋU.zį?}Ÿá+`ö[gfT‡ĸ 4ŠŠ‡ä ëęíÚ_ų7ũŦĀc`”1Ā3į›_Lƒb”ē—ðo„1gI†Ôþđ˜D<"ŊČáfÂ Ð/čBĀXîõCķŽáĩ^Üĸ!Ø5\Ýã‘óoýƒ€ĻŠÎ°$ōŋeØ"0ú :Jĩ;—.på"ļ ?^(W1Ė‹'”=ĮĀ(ArÓo=(b˖°b?]Ó(EÁŋĖáŒŦåēĄĖÚ?Æ1"b]@ô…‘Zd§ŠÆāĮ)ķ;Ų?n―ÂP1Âė7ĶÐã9„ü[ #F~ņâQÄsÛįŋŊTžŅŊ…ôĸý‡īZ h2‹ûy,„xšĸþŠI|ĘÚņmŅŠŅcël<ÐßO$*qyé–Ŧ yxy —ŽėÚzÞ}ÉĒ 8‹%üÁmŸ\ũ>š§7(”ÁŋÄ â…Õsæúĩ;2Ŧ+ĶĐÚ%ˆÝߞ“oŽ)Āqðœü|ËīŲ[™NB+wãD7F üšÎØË:ëåÁ§†óŠ9 û3Ԗü Qĸ.u"ĀE/\QÙkŪ#rļĘéšF(ÃÏ!Æt]bûtÍØžļAÃ;ÖR…ŒcTŨu„―|ņ‹b~ÏNaLsŌWŽŸ[iÎęķž‘Yāy&: ‰­Ņ(L4Î! ŽL„þ\Į`L‰#Ė9Ē8ÞQ ÎjŅ u͝ÄĀ˜Ë•90gr „QgNïâ%äŽ 3æ*ļpÍaÄÆâЖāĘC‡―þd ŧ\ĘGoÝ.!­IĐšJÕNsūR—šųāt^þýČȊ>~eƒ_‚a“éÍþŧGėąe`Äŧƒ#v _Ëmbį€ŌūHĢžxq2óčá_B`æĸĒŨõČÄđņØ$‘ÏW,^ązÅī~ĩk6ø‘sØ"wņØæ6MSSuýð\ķåþWS—nŸ7ĶOŸYïäÜÞŧCjŠsØâ­líŨ†-bŒŊ|ģsÅŧÎkßō­Oð‚d{|yýä6I)͖ļX°gß―~ãåđ‡'ûwk™–ÖpԖÓ/î' ĖėékĶ q$ĩbŊÓOÐūũ„Sũu“IßŋvÚÜũ/H‚uŨãęĶĶÖę4äĀåtÆqyĐÎĶ՝}Â$fQā/ˆCøá™c+—o m7ŧĢĮ• {!5köüEá ^ÛžaARĪÉÍŋd“˜ˆ†í†ŽîQŌĐßøwÞYœūé―n‚I€_‚RZĶJÃøČΓfķL‰s„ÓGŽf•č:ūMÂïėž'Cæ '~žŒúdĮŠûîŨūģ}HjĪŠ‡ĩÝsÆžs―ÄöoZķ―ąðƒk%jĶ&åœÝkÎūí –žŠA­2L‘CŠķßõþ;]؅Žšwĸ‡ÃkŨŋ_ĩïœĪ‚ĢÝŧäRFķũ8{ãgĄ{ßÚąûģäŲ {†eMė:õĄØĐį‚ ß>tēÔfĖúY­·Î™óõ\ŽÃ†ÔüĐ ÄĻĶiyV2}ĘīĄþpþŌãlËšu óó‡ éI‰úkūTUėËķ+cßU5=Ë:ggæðO>xH(E ŠøŊėš •oˆ,ʗũ~ģWčōÎÉĄH&ÏsĢ6ĐþĢzÏę2"IÝømCVô [Ü> œŌtæî!Ž|f)cB‘ĄîýÓžk'ĖzÅ/žgÅrL ‹.á>ŦkĻcے>A ÂƒÜæŋę8 ŅĖÓ 3“‡0Ē…_Ú>Kz†-jå•TĘ}ÎŦĄËŧ4ðÃîîÎĨ>)~Kz„.ëäŸä‰tų˜Fĩs&ĸŠoY3ēiĻYmĸ‰õ}'w]Þ#ĻS4GudžØÉ™b@‚I"außĖ·Àå=Cg6ô öĀMjųUOð™Ü)ĪoA#ðRŌiüĒa­ÕĻf–•óéÐĒņ‘í+§/ۜGx“WdLÅōÁQ1ņĨ‚―ü<ør߄1ŦzœoUs(ãüŒy†DFĮ{”)_%*ĀĮb/ŠŲqЌAk'Uô#ŪĐ:cÐÔHi–{öā˜ŅÓŊ挟Ü%™ß|zæÞÍCãÆĖüúæýËn€2úÝu5ÝũvčwðõđëDyPdærOš:óĢŧ™"σó,XŨĐËš7ĐWĘß'ĨÛø)]›VŠ >IW,ŒuēŽcƒ”3†xø~{æÂqˆãđĖ›ß?žvûëŦ'-ųäŅe[Vž!'†Ôü‰ DU]-"ļCįÎE…+—.zgĮ;'nÕŪ}‰ IyV;ÁŊ Č, ‰CBî2 ˆgL7IíŦzDI\‹̓„ra^Ë;ûy[ÔčR>“øFðÏÚ"ĻYÉwHӀ@4ÜąQČ ŠĒ=[)ë―ž“··ߥQðĀį–ÎÞ~&0̌ōĨĖéN 3û™ĶĩéPN …Š™‡Č`i|·ÔVX@§MK2{đq­RĮ5ó‰’ ĨfВîA ^ĻFyßÁÕM^îÜ+)#›xEˆRÅov;/wapËā ‚-[­UŲyG/‘CUc<û5H DK{hė!y[·Ŧ ëT7˜óqį{5 RĮ#ÂĖwkÐtÅÖéšgû†Q'ŋk„béFžÉÔX§ÕĻ1“w~}tŀ$BYÆÕŸÎ<ķyųÞ―uó&pÜÅýS&Î>ÝĶũ€V‰á :}ttMĄ” L8?†]0œĐU Čđđ„”ōeŒÉÍ á ;õ;eÚ?ŽŪnT>@W•"Ŧ0fH­ÁŸfQõ;…(&ĩ}·ŨÝüéÜÞõŦÃÃk·é}˂re#ö;ĩI@V―óhÄGŲgōqB _#Ņ3œ+ō-īT”āŽ({žÝū’?`CúGqûjĶí{žLĸ8kÁy^Ĩ}û•25ŊōÂãk‘ũžSģo.8Zx“ @ÕY|”[b0ZģåņĪyĢÞ/Pž„“IgO|?kÅakj’‡/4F|œÞcWöĐ–y.ŦãšĖƒŨ47O :"ŧwgôؐūú;Ŧg)ī`)5Žßž;ˑtų‰"ĸßæÞX'};·ÃÛé{/ۑ™‹ ’ËŠYÔ$Pęfj*pN…Qoy4ú“œŧŠPΝđnĩŲåU‡sķ]%ĩņƒŪa‹ęÓa‹ōóa‹TÐrvîÚyâŌ#äæi%‘w‰+yö‹ïėûŅnÍ+ĖļåÜņŧįïž;qęŰEp[Ô(0ŦÕĘý71æóždÜ=ņŦE:ø}z!’­ŠŠŸŽ]V‘SĘmŨ5―đtÕæm'­MîXÁ+Žr­6ïčjZ–:ōá+ŨŊŸ<~ö|†Ęad<`ð§@8ÝÛ Lšu핗•þÕ_ô08ļD”BĀ$0F ‚ßF hWėDG<‡@ĀNJþ _œž{ P}`Gŧ Ä!ú PËēĢH$ŠtF“5ŠQðāÄEsZé›9D0"Š/i‹‘8„€Ųa@ĐËN˜Š3ʘŽS€™~1—Ãn˜ÝyĻk0ƜQ0%ŨlD&LŅ™N™Ā!ŧĘ&;ScržPaķŠ‘âØĀayČÉĄēõ3{3ŪÝŅX DŠÔ+2Ąœ€œ§Ė‡ģ$økĄkZlŦáÃõ]cŊ Ž‡':,q ä·ÐïsWÄ$ũiÓЍ@õ†Ý'JŸ<ēvï9Kũ<EÜÆï}įėɇEvŪUÏąÔß_įáÕģ‚BM§ÅmÔą)dāĒõŸ|ņMvž%ĶNŧþqœĪiļlÝŊUāuÏ:mûĮ f >aėĖię_ãíeíÃ%U#Žxē}ĩNSŨ†U?tōōėãį!ÛXûđK_igÂSÞ~;þķÍÓrڛËÞŋ˜­Ÿþf‹k—ēóõv#§j‘å4 ZŒ˜RÍ;VÓīō-G/Ūl*3Öījīœõļd› “:55-ūÍĻŨqI•yÏ|ã­:{?øņî]“[I #ũ° ÃúúEzņŒ1Cj þ#Ŋx‚Ū2žwæ“kx™ ,-īf‘ŅnՂäēt@āŅՇöĮŋýá[›·úáíšÍkp OOÖ­ķįŦ™Y$‰ļ8–Dä|ã*€jLč[ÏGlÝHzÞÉlåōcčÚÐû!Ï·­ä.æ[ēō*öâ8ä&ĒGđę™ûz•(nÏųB!@ôá IÄ@N6#Ð5Æ<Ý:ÆļYï*€áŊ%$ŽJÓŪa‹ŋ‚ˆŪhzXÕb‹ÞŽmfmŸ[$æø>ĢG:ô_ü0_r hšĘEĨUU ’›ķÓUY§ \ ĨSÆTŽK4•â˜)Š*„Æ5‹âTYF15Â1“ĩt…*7,Î$kžĄëļRZ›*im\ĩ:BDv‹‡ĢNPÕĶ]ЁĢHÚēϐ–āĪajŠc Äĩ.™ØĪMEæ<Ŋ ļĶ8(*@bÕfÝĮĩŊ):!‘5š—į*ų7ï;ĪyqRU!(ūk‡Ä?sXĪ!ĩžd)ē Š%<Ėcā°§ãĨpžr2mųO2™ėļcð8Ãö―Ū+Ū @ŧ|{Í^ ŅčŲkVk=w3Ė'hx ŋąą›aýöķŒąK·Ž>đóČ^Ļn>áÓ"  IQՙïæÜ|Ēo9áûĖ2ãݜlđtĢð|YŸ>i>EeQ‘ĀĄœ'ķyûģĨzuĐgĘ-ī}ömÞĖ]Ųã{ KzᘃÖB,žšj}lJŲđ[EĪ€rŪ?ēóŠN;ŽÄÃÔ쉙äYĶ~\ø(‡ŽúäÉĀz>Z˜ėVëôrē5v󱝗u„áa†üčēE]ņá“Á }ĩ .ŌéÁ,åUĸæ†RĪ‚†Ļ#Ũ―Bú0[~ïī\―’OÃyí_ėQeNTYþ'‹ėīž€ęšŽkā‚čÚKAˆ ŋāâDS•g>Š+ŽKO‰ËĶ[\§Á/ÁԗYjWäį üœg•8_dCF='Ėå‚ĢeEÆĀ…Ū<Į(y9ŽŦÂ?™ŋËÄ\cb.BHĩå/Ýw}Ũ•0OÁ#š[ÁĨŌ^Á&Œá9”BVŽ|7Ï\ā]ņ&øĘ­Ū3$ äPYsūĮŪĮĪ€Įvnx$!°čŒãÐó<ŠÆ‰GیLĨ(ÐESņ/Xa‡x=ËN ä'@ŽĖ81Ũ UcŒ+.ƒņ<âąŦ›0Ļ:S ‹ŠôØ>dH킁%ĪČb)*ēÚíēÝf-ēŲ5óæåģŨ3@P ŠŦŠFā? W{ô›z‡ęŠŠS“[—ÎÝĖ,Ērîđ/Øu„ Đ500øßÁ‹búõŦSF7y°~݇;aüøy+w~đrņ譇4„Á…(‰gķΙīîs0üGaģXmęĸ$—HÄï7MŸēų˜ Žđãũ~sþ0iÄēKũTĖaCj þWMũ‹ˆė;äõÁ―:ú°lŊ2Í^6ĪG‡Æþ‘ŠŸ‡ p‚ģÉ uDVmÐ8)C˜%Éd2 <?!^ ’čjŅâĄߛVdŧ{jáĪ9~å[ëœ0ĒsËó~•GlqdãŌû6lđsrŲôašŽïßâíy#^)žĸÍÆsõ™ũÖü‘mNąĸûōũŋõæÁŒR̆öÉú`則ęí/ŨÜüãœÍ[šĢÃĢæė‰žþ`ó[{Îu;-æŌŧëŋžé_ēBZŲð&=wn›fƄ1†xO-ĸĖšũūbúý·f.ÚđqG6%_î\šî–æãÎÝĀČxŪö_ƒfŨŧŽ]?ŪsÁŨæm‡óe@{cЊŌŪEĐɛ'MÏí7v\ \˜ņÍÞã}^{ŊSZ]§<―;ĸÕ#vԊĐč?äÓýŊ~y!+'Õ:L™ņzûëG3cŦtž=åuvý{7|EĻDŦÞjÂĪŨ[2KÅS‡ŋļuó‰í›ã nŸTäā>{?=ųíåš­™_…óĶ“/~ą{›ÆÔģ‡vį>P损w—zÜģA*óũÆęÖU<%š_&:įSēLž'ŽŦPūLļ,ë €Q>ĐQ—ó|}ā’Ôļaœ–sø›#‡Î—™ķ8>gxqÆÃ^ĸB ˜þÞn@AÓd`.6:ĖĐÐfĀÞ76ö}2dԊ‹đ:Æņ&Ï`·Žü,ÍuYȇÍāIDl–ü|döč‚ŲdJœ jš.0a"]ģedįó&ÉËŨÏú8ËibJū­‹žsUŨeãÜ<ƒ}CŦ >bþŠå;Þ~MRd ƒI *ĄĖˆ]U ŽäđR1 ąĩĘðßvöî+}&tŽė5o`ï‚ZÍ=ąÎ€!ĩ2ŠŠ(„‚ ]ĩYŠėÅÝđ‹ŠTqNjÐ%A=úO]‡jbcT,`ž[`“žÝ?Ü6oüÂÕŦW­ûî–đįД[§――cûsæÅÕŠWÆĮnŨ‹ Up@tK‘Í\W‹Ž@óÕCó—mÚķtŅ'hB―Šá•wÔî˜ģzˊ…söf„§6Ū Č6Åą™0į EG5ÚõņB—žļüāÎŲ3įŪę;j-nIŪڋė‚_:Є“_ywcųšUJ:'5īų:.ĨiĻÝðÉļt4xģ‰cû” )e†Ôü1P,UMn‚tUq]†WoíšM` ĐÐđ+VeUoVÂe‰oÖ.ąYą&ŦŠaT'\íÖŊÖn]žĒ( $5ëYÛĩÓ5†Į§Dsš,ëÞáņĒą,+žOtãöeˆŪŦrŪŋį+=8™kÞÄVo4đF#—ŋ.kšÉ·dĢve•P“_jóMՃ+ΌۘNĻ,kĐí;đ΀UhØĮâV~äčDF‰ŠjėŲāúČĔ’™"+Ũųĩ§ !Q5[”r`•æí@ŨTmZEhŠōĮ\Ø­Á~ĩđđđOž<ĐXą"üWsþüų   ??ŋŋZŋZ„PރKw }Š$F0B~ĩÆ―Zƒ?ƘoTBĩ„?Vgü ėĀøZĖĀĀā?F)Ąþ8ˆĶę„ý~9EŋdįėY7ϞŋE Đ5000ø™6Šûæ[yėūIĀŋý&†*Y,ō/h/dŸ{ÄČÝv†‘!ĩĸĸ Wŋ‚í aė48-‚À%Éĩ."WwþY[‘Į?kbāÜã\Ü$:ŸîđŸåzŲĩÁu(8\…NpRžŦ8QąE2I‡áâD/"H"Ïáđ(_!­UÍ2ūWÏ—ŊĀagUŽĻÏē8“:pŪðĒtiÍâQŧO:Lșse0‡å°; tãFA@OOĘQ4gHíoÆĀĀalÍØđpLÝÔīf}Æ~y­€łûįįlV755åĩ…—óĻ’wsZώ)Đi]Ę ÜŨ›į―wō‘( WŽmžņîiQŊÛū`Ã{̇öLŪ]gÉgsŊė>yÅ=pïŦ}ãG~ΉN‘Bœ`|vöPG …š=FĖŋcČŧĩtÍúÍ[Ö$§$w2ũrŪ&‰äóKÞ\žd\jJ­W|t6K’ĻÃēüđŊÕéöÁŅ'{iú ŪŽݧŪđ[ČĢ‚K3_úމ{ežöíãFîēō|ޓÛ9…2OķMđaãânMë6·ņÜũŸôj“R·ÁÔ3OT‘GßėYé8ĢšÉŨväÝ|ûƒ]ŧæNÜ{Ä­ĪÜĸvBßšiu_ŲüŲ@ĀxréÓ) V?ē0A’ŪY7kÝ?t†Ôþ 6 úŽą—ŋc]°ęíĨӇī+ãîļŊoŧŸ8o؊9=ĐßÜ펙ŋ|՘þ==ąvíôcō1æ2o|ųÍ71Æų7O.™ē, ķÓØ~ÍWÏþmķ}|ýöcũÁķeíü{Ņþˆ14…Ôč9ôþ„9ÛǚÔðÆÚųc{ß-žrrïĶ-Ūô?öÎč0þ&'—ļûņ܏.`žđų”^đuįĪŽ–Õ“ŨgŧŨ)UĒNãV}† âïï:üqĩioÍi―iÆļS™”Į@)čĸåŪMûÏ=â蓕‹ÞU%/‘CÆsĩŋ„AÍ:ð@ï4PR…ļ:ácV}þÚĮŽÜ<ƒæï•\5˜°ÜüâāwhħcSŠøhÅXE{"{rXŠÕZŽŸ:ž+Š|úČ·rKNčV}ÜîJ–9pĄÔĶU5uUF™G`HöÖóōōŌ-D– P™úÔ]šfrĢŸčž†]6?ē-ĒŽó”åݚÕÕõg_?sŋČŽÓī}ÛĨÉw>û’‹ZĩļOlˆÐ{XŊũÆî|hÓdøâ[ũšķkÜąÏꃃ›•%ÄĘaė…(#a#ŽjV>g_Ph•Qģ_móø-áÐ―LŅË,=GyrĮĶHėY&Á7Œ‹ĐVĨžvįĀ9™!­žqȞ‘™“]HĒĒšęYģ[“€ũÖl—Ôø7WEŒþ­ĨÖĀ`݉ĩëOރ?‚uŽ3þ›Á"ÉÍÎĩ "į(2sũöáÝė™…Ąˆéˆy$įZ ü€é”1J( ōÃĮ—˜đ0L˜Ä€höĖė|_AHjÕÃwåĀķ}ĪĘígÅûK„čXĩ­ģ&­}ūxtovóĒ„8 ļ3ŠSx’‘Ĩb_HF AJ~>!%―$2Q0ĀöĖ'…*„IJQ6%"ρ–ûðÆåĮ’›ß™ŧwŠ4ðæ_Ėv&Ā  é @įƒóf-ó›“g6ļ4!Ÿ―'ð ézžŽrzš‘˜ŌĶOó_ÉÍ?&J(ļŘ]^íŅ{c›đƒ•o5,.ԃ*ōßZj :ûJmŋ?*ÔģÔRBÅ î)5ĮoX-Χ{ÛėÓĪYÝũšïšŽÖPxtôí·įf§Ä―ĩóF―ūýÜyóüī•+CđôŦûÖøŨčZ!@úÄjĨŠ”Ša•;Äū1cĶŌ:öĀ–=ĩ“&„ģôųczÝ-1ôöڄ.]úXîąn\;MķĘNa͚ĩH' €ŠEEēFĒY­ tÕR”ýĀ’{ëâ‰Ë7ģŋųōnBđĻsÃ6lĐŅđaÍA‰qŧÞų8aTS―čŠ9:އ1ŦM̚æSĄE·RóĶ^+ÜŠÓeãkąß†S5ÔtōÂM›åßūæYåõŧfļyMž·zįĀF…ĖdæÝžŧMÚ0ŦOcû“ĮĖėéavk9qŅëÕ}Yt“Í;vNnW‰J8YНŋöPq‹ÛąvEÅ@8)ļTé”Ū-k”a„€Šj\ŧ)óÆ·,›i1Ï\ēķeyßk OKŠ ŧ{7Ģĸ„Ĩó{Ī…ēÃōÞi1Đa•Ú6‰ Ð4Ýčð›100`TGĶZ­û'·/ÐUUw[õÖ œhŠL§CŊ!ðėyW3ą cE,Đņ°šå%§îŧzkåWĩYũI“\Á°*ÍÛĢg―°{XŧÛ=ŊÍ7ĶwÏxÝáĐkáöĐ Š,û5ėäęõ:vÖUY§^õštcŪþ )]*PMViæýj6' @Wč;xϊŽĒĀfÝÆ5'š#…gåN%@Q)ËŧļæhÞ+Ãzx#Mfð{0ĪÖĀĀ€QE–_6ļūģzÁˇNõ‚į „+6Ÿ6ĩŽĒЌÐb‘<š-[[-NW5øôįū#Ŋ*3FŦŠŒ1ĪĐĻûØŲ(ĻĪė2 õgå1ŠË?OÏ^:cŋž_~ú†:ßžžä<å—y–―œ‚ĻÎģGXÉ3ÖÄŨŠr‰þïĮZ„PqG‚_·üōfÆĻOTbuÄ^ôdLpII Ģ„P§ eė%žIūÕjøSJžea„â2•ŠĨN—ŋŒr^ÉuĢ(!ĖøĩØïÆĀĀ€Q]ÓdŧÝņR5RüãVDõœėl‹Uæ9ÁÏAķ‚œœ+s,đÖ0Bēĩ ;;OgøĐ‰1B vĸŌųëEĢ_ÍMB/­:š1ø Âų]:kH­A”gĩú‘ƒŊĪÐðw aĘð~_:ļ_ŊŧNP,0ųŅĶ9Ŋ7jõJãķ―7wsžÁņôˇoĩnŅļIëKwœ$ˆĮŸsõ“aÝZ·jÞrÔÜÍų:BÏEY ŸN5ëë{"ĩų€j-*’ÁZƒĸ>ōÚ§â”ŊXĸZŒ2øŧ‚fZÎwũĨ6švëÕŦqŌ’ČŽ,đúGöÁįĸ˜Ø&dú˜i7 (FÅÚ)ĘwNœú‹?þlIĮ-ģĮ}qŦPÔÓĮŽ'$O:øųFvnŅô/I".S„)˜ĀŲų@â0ž ü3Õ$Išööē‘ï~ÛLâxÉä@z֊MNþđáBž(™œH=íÆðžo‚Āá—[.ˆOĢĄâ&ČÕýāE‹gŅU’Ŧ:Œžz9‹3ņ†ÔüŌüAF‰*ŊÖ.Y§ŨŦĩÕĮnYï?ĸĻ|ß~Ã*unXë‡=G­øÅE,‡qÎĩ îÞ49ĨÛ—3.ė_4kíG‡ūÚŧtų–O6}š{įüƒ{ ŧ‘Nîë•ZŊnĮaŊåōǘ{ãŧqm[ÕŊ—ķ`Û§*įA—2R{î–Y}ÓŌę―ŌĐŨŲ‡Qâo}ýņĘ7ßZ5­MJ―–k]N@a―āúŠYcū―mqČĶõáéYK7ÞËĩ}·oiŦii ŋũÕUNŌ/·ā#UiÁííoN=ŸÅÔ˟VLšąx`ŸníķŲF†Ôþ^ ú$ŽĐŅ~%Œhþū0Äų„(Ÿ ęÛúŌÍ·ģ,\p šųýÉl…>š|'ŧ ðæýŽâ‹G`É)ōŠ-R]§,@Þý K^Ķ@M&L‰ŪD'`ÛcųŲÝWīžO?=ßylÏZōŒáà LŌÞ5ŦOg3.ï‡%o|˜˜X+:"Đ~ģž#ûæ~uäōzģVŽŊ]0iÜōBDöϚõ_uÅÛoĩIŪšÎ˜3ΈåũWO^sÎ{ÞĘÕ­*ˆ=†Íŧ™Gä'WW―ąøNx‡Á JėÚúî] Å1“ŧ_þíï6~ø5CėËũßđô@{rfĮŦ3ĸŅsöĘiÏ7ôÓģy֌KŸ?íp`ráwßŧkeXyēoõŠëAņC&Ö€1Cj”°‹ū€ĮŲũŽ|ĸ À1øÛˆ~•ŨoyoųĪ~YÛįõŸ―ŦHڎW‰žzĩu·ێûčÔßŨ?uā‰ēB\ۚ1B€`—ęš €ūLAÞ­Gū1ŽUÃ.ƒŧgdÛJvh›ģcÃũ_mŲb)Ýú•jŅ‘åü"ĘÅÔŪïļĪMŋūgåœ Ÿgeœ{ü؊ŠķnųãūéóÖßģa3Škó~óå™îŊ ĐSĄ|ïūý"ï\üņFf‘ŠÔéļiAhĩ†ŊÕ1Ï[š'Ūß>\=áüÅŦV~ŋfęŌõûMė*™Wĩ 4ŧ^ū˘ “ŧŨOĐgģrm,(ŌïÐÞ-‹WÉą=*­š]ņKíīmú˜īŠ‘ßŋÔZ~`ÛÔę{ŋÞ 2(<Ï]9ōž”6ļkĢęõŧŋ^/+īļģ—'Ģā]šE­ļ7gÏúčÔu*ŠĀyņ…§Į éúuv‡ã{{a2—\ûũŨ/'véØąAÕ&ŊõŪ^Ģī"ËÄ&Ôëžuڈš•ĢJũč ŧ>ûú։ƒTąK― —]y’~~ãÜđO]ĖÉģ(‚ŋ†Ôč,ĀĮQÐ4™ÉdϞ2ęŪųj‡6Ąū!ƒ_ģÄ9U•(ĀDŽ3Z~^‘Ē‚įðÐãÞlÓ8žĐ™c†õˆõŪ7tĐúžÕf)î6 ŠßĪßvŲóĖ•‡%ŌílŠÆþvî/ī­*āøđ'ũ&đYãÖīŪķkíTÔ ·unEA‡T u­õO]‡ĘÖļáøįAúėƒ0|ĩhû$„ |îAÐLņŋ‚Ã*lāDNÆhïŋsŽw‰ÉÔ˧\Páû!”ü)·Ą_~œœœ7oFö?rCŸŦUŪšņþŲÆĩĒPjŊūķþodĻ+‚Ōí,ÎyįŦŊŋĩ6 Žsr=Õûvö–V†ĄfŠýũPJ+ũ\#īįŲþŧ–įnvËļĻŧK˜0ŌåĄTý`Ģ…[™ØŧmĒ5ûĄ6ĒNGfhËčėÖQŅ`"Ϗ6Œ>$UāEݏíęŌ1 ŲŦ&'ŠQāųÆŸÞ'„úã+ļFG"36U:6AŽÛQūøŨ•Rđ5Ã;Ŋūh­ĘÃÕĩ›ãûžB‡ŠīiōéáÉÆEü šûÁÝ: ‚ˆÔþ7ˆ|/úëAšųL‹ŠBQWŅíÚNZ ĩ@jĪH-€ÔĐR ĩð?ĸb.˟x}áÄžHžĘĖLĨFjĸâÎî)$sĐãóíĐe@j€ÔАZ ĩģ{6^9ą―øx|‹ï$ŧŲ âžn]SÍØ9ŅtGyúož;ŧžČT›čÍ\ÛęlËŲž;ËûŒaĄc`Œ8óÛÉc_žéKo―?·ë… ‡Þ›uŨũkeHm@…úč§sOÎÝûöG/K[^X>/ę~:w:ōĐMĪŌŌÍ;Ú=Ũ=ā–Ũ–ŠÛĶDÝį‹ЈĐ:fYÂIË|oš0čŸØþRĄ$„øņėĐßīĪEj–īœlаēŊķųÅū|ąŅŲįíuóŽíXlöJ 6Õ>šþāęŪ‹ýōû_9:ŦÜ_ŧWđvZ2Õ& ]ö—NĸüÝø­ŧ§n{ĶzӁÕ+ŪcŠM ænnt6æfrc#ÓĒéĖ…“ŋ,-ZS-tĀhúFüƒČŨÆĶZčˆÖâģSĮÞýāČōųÐ!SVĘķ2+ėîþlWOFHR I92Ûe·ïër2RڒĩZč”LYnÞķW+Óþ’“MÅ?I-tÄē„–M]āc1 ĩĀėĐĖ,ŸOęRĪö2`ĶR‹oüX@ø;ļĄ 0<'úŅÚqfŧØ}ņūŊ’?&€ÔH-R ĩH-€ÔH-R ĩR €ÔH-R ĩþŦåįœsöÞq;ŧH-_)ĨĖ9ĮÁÕÖZĩÖ@jy_fķÖzïÁl3Ó:H-FKĀĩ€ÔH-R ĩR €ÔH-R ĩæōīw'ÐQųŋĀUũvw–ÎŌé„ė{YØY k4. ĢÎ(Ž>ĮqAQd\F@tqGGÔ7dA} „Ű&$d…ėĪŧï―Uõ{ũuô7sč€ ĸGzęsΜ“ĄoßSÕ7ũ[ŋŠkŠ{ â0ô ŒūüônB(Ĩūn&á#ĢV 4^ŊũÂܚDQ”°°0ŦÕÚM !Œ1—Ëev‡sÞãFŧ   ŧÝnöÎĶĄĄĄššÚždˆ;ÏÅÆÆ&%%Y,–Ā頌ZYϚÁÔÜÜît: !æf€mmmæH)?8įMMMcÞĨ=Ūžíšę/b!õõõĐĐĐŅŅŅYؚCHeeeYYYïÞ―)Ĩ2jĨa͘™ģæ}û3LŲĄ&~ö―ûĨäįË6›ÍŽøjjj4M3‹ū3ū…būŠëzrrēŠŠˆøĢ{@ ð3éę§@8kƒƒƒŧ.‡ĩÝ f=kælZZ(ģûæ/äöíÛÍąĮü!@ [ųXLVĩ^ŊŨœ·ž5gņ;þC AĶU;°kρf·AHũgc§jŠ[: BÏū튈VÃ0Ā?ÆtŋČÄBp.žéEwK}íĐV ΆœÓ1`žïtŦ—ĢūķšÕÚy“žæåčæĖ„–––øøx8DaBøŅ°ūēŽŠą~&Ļu”;Ņi―ģåXyĩÆ æĻ#„Ð4-pĘvĩ"Bš‰'ŠÃ›VŋýÎÛïŋũũwÞ}oÕÆÝ§Ûž„øũ·Päå{ū\öÅĶ’’=͞ģĪ'sóŲę'\ ^Į8‡Lčjdũ9û9ļ{ũę^]úęŌ?ýųģžĻ’/iëŽ[ŧöPÝBÁ―^í?Ģ  8šųģŨ7ˆPąíÚŊœĒĪíëĩŦöŨuŌsŋþųlÓjķöĩ?þvęī™3ĶO™|ßĒ7?kh3ššũCð·æNcÅ.8f^ƒé…ę§šwŅŧߝ[wĖļ뉒 Þūcõģ—ņœÛÂ@"$Îđĸŧ—5KģšNuqvlÓéšĢ›WŦhøÍMW„ŦˆŠ*7C§ËŦÓģĮÝ81ß0 $TĄgŒ#€ĒŠČĸį‚s†„"M_­Û•?fBĶéL!ÝDĖYkDä>þƌ†ßn(9=ôōĒXlj"ΧÂl%DpƄ(RļP,JĀŨ”*ŠŠ_ÁØqšvݞŠcGÆĢfˆïÛE„ũÔö{ļëúægæ&Fā‚D ŒuUÓ\`7âÐ3ÆāˈŠbÅŪ•åö›~5:đxÍōŨŧíëÃŊŋũÔ aŠ DÎĻŠ ]gĸïĸĐ"TŊ›C čĸsĒ* |Ŋü›7>ø6þ\ œģï‘(ŠRŧéýį_z5l›tãÐDnŧÕÁlÞ^ašÅ@‚ųų(ū_ 82jea끁‰#9Ĉl‘ŸõÁŋv>9hHZXéŽõ%ĮN…Åõ3æbãÄöu.O݆‘04Úó› ë}ÉðÁŠŧdãN[ÖÐū‰A‡wojēf ËąJôâ [KöŦlðŒ7:;ÉBœ{IëŊ#ÂĸI4ĢĢÓęLHLʎËAÎ ÆžŪӛŋŲrŠ%į+˜ūs oŊûzã7uí˜ÖÄÅđɔŠĘŌâûŽ1éCF‡VoßS\ÛØPÕwØļÁ™!|5ĐĒÖÚŲLĒâÂ\;VfÆöUÞuBä‚ č‚Ýīĸ'‰!Š%hhÁUW_Ÿõõ7]sŲž+&/þjŌØëú[Þ~|Î{ާ_9åé{&„}ëēWŋŧŌdė…7FĶXw|öÆÜŨ>OūxÂcÓïJDM œÜĩ|ö3Ŋđ‚“}âĐáéQĖÝöÉ;óÞþüˆfOŸ:}Ōēgžĸd‡VRVþôcwg8­ū„ŠJĮâŋ~Ú{TĄŧä›/6Ÿļ§0sŽ&nB‚sÎļā2jeÔþWÁïų‰Z0 Ķkš—#IĘĖęĩ­Óí9QēsýÁķņĢí_·~ƒzé xGˆJŽ i ‘†Þß'Ëá]ĩš8ĪWzaķrüČŅPGŋ~ –ÓeßօF Ë óÍÂŅã ŪIHKu†YįāįĢ”þôaF8Ósė{?|ûcĮ ÉO "Ú֕Ÿ6Fäé§Ūݰ>:&.”_—[Ö}ūŠ.īũˆ\}ãĶ‘ņw9jķŪX_Û· o|ˆ5,˜D8BB;Sģē{EÚ8ūVEīėÞWŸ4čē>xx͎âS—ôI A_ÐôýŠ ŧN~ō7†…@Ô=n4žXóFˆ]ŅÜØøéëy·"hÎėiKæĖ{=9sÚðÎG~ĸō°į^ū)#ÂJ?{áūŧg-žĩsþ#ģ^ėõũđW#UÔöēÍũÜĸŌčĐĨW~1oö’Ũ^}tßŧO{­üąŲĶaJ”c`LøŪÔÞ7ĸbŽÓcˆ XÔÖ#ۋKC]úRŲ’›—ŊY1iėī Čį(ū‹\_Ôî2ÉĻ•üĖŧýWĩ |ĨũĨgãĖS^z ļĢūú” FcC5 +LtØ!8­wēÓë"ŽÐ–Ú†vJŅ7/§… ˆJ‘Á}™Hã3’ėĄ'RsóĢCÁāž›™õ9ÆįÜï*„%<ūčęëŧvîYĸIMÓåW ī>éËėĻ­gM §ƒ)1éÍ5Õí­ÔÚ~ЉyžZSkKӉj—-ĸւAV TĄmž^áaîôޜ„pÂļð­ĨĨŽīĶ­)QåšGR_rĪ!iS|°hú™ŠZÆøE.rf˜ ĄÕžíĩÅk—{<—|―~Gk›íØĢž1yYIa{WŽĖđéWŋũūųÁúĢídÏ7ëWToî,n›]„ˆ„čeŧũï.oL>īģĐŽ|ËķŠĢåG·|üåĪۖÞyÃXŅéE8|ĻãtŊ1Ģûđ;uJųÎõŦË;mžSÕZ\ꊏŋþöžÛR.°k"ÁP_ëüF­Ē(ˆēŠ ,ŌŲ'ĪÐđŦĐödKč°[RŦÍŨ+6æ {„ƒčß―ƒóė\ųņ1Ŋsð Žĩ‚ @Ī ļŅéŅÁî›Ēûpfp!įB!ð\Ÿ‰ų?FøtÓUkD|á„kģRķ-[ą§*aU-ŽØûěúÄÄFķėįØu†Ð(§3.ôōĪÜøļā}ˆ`\ĻĀ3óÅ:õ5›XĐ{_éqŊ-ĘNęąT}ŧÏÕŋ|·$ū$=KÔ !Îq\ėĶŠāB€@ę;F+ß]rĖëŒĩŨpkDLbZVŸŽßČÎÏÅņÔŧŲ°ęÓEũßģgÁŸYhŊĻĻ”ļ”>sž―+1ĮĘt&97 HOJïwë{“ÓrĘJĶ{ ƒ!3 ··Í`D3ļ…ų€°öšOW­JÉŧŽüĀ.’™Õųá?ŋޝ7F ĖÄĒïæ7jÍŨdÔRþûn4Ũ-ŲŋĮÆ/ĸųÅ6gîĀė䄮ū―ÝŪĶķNĄ―ĢĢ éz‚DPļZ]:XŅÛÜÐáŠŦĐō Šp­æØ _.ß{ē]Ņõäš $ÄĘ=ŪÚž:įĨÐZ|ÓĶíĨGË+jj•h§Ã™:0+ĪþT―AlÜëv{ @a膙œål.ŊDKŨ\Í^%;;ÝĄŧbãŪ#ßîŲýmĩ“æß>ÔäÄWČđ›ęĘ*[šŽčēÂK/-šbü@W}YE‹ `Ü7w6 ð?æm+ŲēbŲG―ņܜĐ3ĸrí=ũ Î6qÂÉG5fuĩŧ;Ý-e+?ßáĖÎKWŒúfõŌß\`ėŊč°DÛÕúÓ­€y=ŊČ6vHĘéC•ŅÎČæÆCqŒô‹eaŅ[~úņōƒ'Z“ērÝõWŊÜãr3B€RĨžxõ§eņO/š7uĘÝ>2kæ„ūË^ųW―GhšáŦl WûϏB’U­„â2ēRjOVœ ƒÆ^Ų7'ÝFx|Ÿ‚+Ş’ĢŠQMČĘÍ JŊô<›-Ņ:xÜXm_yy]ððĄyU.—ŨvŅĻA;JŦ[B“G]ŦFF *i996‡löQƒsV•Ũī$eÅÛāüÖ2DĩX:šjö> Ö°ŦІĮF‡9ĮLônÛVšŊ”Ðþ‘‰Î„>―Uŧ!#Ŋ,ēlŲ^š·XąÚōbē’{_tĐPJŸÃŪÏFø"c8dÜXdØgXaÎ0DÁđ?e™Ūöws˜“qõ/39ãDQ‰`Ė`ÔyIáD @pn2°  ƒƒ5jÄeŨ ā„*]ĸ1[RŸĄ)9C€øÖA˜4žp0éZF@N+Ÿa†ūf(aŠ„a@ŌH*ļÆqhÁXÁ .ð§o”C)E?S2â7Oŋ‹‚æuëš!]3cîu€„Pnx―Ė|ũ„sJ„Įíe掞ôþe7#(”kín―hęĢ„išŨëĖõ§ŨĮ!PđÛãŅQýõÃóoA$ 5æï/5 !íííæ> æ6%]+ķg]Õ―ŧiđ Bzzšŋö+ŠēnÝšüüüˆˆÆØV}Ģ’ŋ‚@<‡ÏŒøD?oû)ĻÏÖ­[ûũïïĸïÅ{ UU;Žˆ))Išnü—Vĩ"Úíöķķ6‹Ï…ž cĖQšoE1 퉛B†árđĖËŅMËŅÜLĮ܍%777888 'XšŪ›û]˜WÓÜïBîė%NÔvÕGæ~QœsĮüOÞiþJƒČČČnö7@D3^‡9ë2kÛóޑóÐGEQĖô4/G7íB˜5ïŅĢGwėØÁ9Ôå,ós0·õ2gZ2j‡d͘Y(išvÁÞš„ģ‘fΞËĶP]ŧŌôÄ[TQģ”Ģ”žĩyyyf7rėWUՌZßū―EF­D)5đ !ėíwîĄlõéū/=š›]ûœ9Î€ŸoÉĻ•ä/·ėËų%;(Q$I’dÔJ’$ÉĻ•$I’dÔJ’$ÉĻ•$I’Q+I’$ÉĻ•$I’Q+I’$Q$I’dÔJ’$ÉĻ•$I’dÔJ’$ÉĻ•$I’Q+I’$ÉMų\€$I~GŠŒÚ€ˆmmmMMMœ ļ0H’Ī(J[›Ën•Q„QQŽ#GŽđ\íp!‘$‰s‘œœ$ĘĻíņ ȌŒļä’aˆpA‘$‰`Œĸāï‚k:Ï$I’$h’$I’dÔJ’$ÉĻ•$I’dÔJ’$ÉĻ•$I x*H’$ýĸ@č‘åŸ0\ø$IˆŒã€= Ĩ`QˆB€ĩ’ˆ106 086uŠšvÖęĄg R!.L Sė6b’Q+I‚âõz+++[[[ Ãļð[Æ$būœÝ_Õ~ĪūģC=Šã#Ô)‘éŅVŧ•"ĢV’‚ĒĒĒÂbąŒ92<<üÂom]]ÝĄC‡TU‹‹Bü[tPÖč=RÓæ·ũψ ķYz ĖvwYMãūĘÖ›3ØA, Aĩ’t]oii),,īŲl=a)“&&&šm>~üxBBÂD-hŨDe“N-ACûÄõM Ĩþ“Š˜(ĨĪ+âP?Ą” üL@›fG„ý§ÚyR„jUQFmÏ'IÜį\rVxZĻō2Ņ+>!:ØBÁ/ôvttš=œZN‡…ĀŲāĄM\Iƒ†ĨGÂ9p:%%%gœ] ―† Š QÂ(tËÓZžę4’ č^ą11 ‚wķķ[­ …ŸGx(ĮfŊåc1I Bˆî‹BęOl_ððėŊŽīEGXO4î{õŊũ_ŲÏ|īh]úäÃŦ6Ú-ŅŲ—?2sJV/{·įįkæ?ēų7oþ3=ō\ŠÄsĐ%E7ĮB@ßīâ―įžzų$[―\QǟøøÃËRlݟ•âioî4ŽN‡°ę§îzxėÂ7/ÏAüŲŠZ!äÖāM’å-œAïÉgnū~[ĖÍޘÕ; ömŲ)ÆđB ÎREĄŠĻÜģyũ7ŅãĸðāP~Įíþĩï°ų·ŽâŒ!"Ĩū7   !ļ@ĻÅ‚S•4L]'$„t“wBˆģfąāBð3օĻĻ–†ý+§LšŋĸīĨ_ÍšQņÔ—ėØ›Ōõ.Î*ŠBļū"8CĒP‚ŠĒ/œ·ČQļ끉TD^;åÎD§Âđâû RŠ  „ DBš~P(åŒU|ýgč!õí (PČϕ΄>Œ1?ËĢjíŊÞŊsþíŲý’# ƒ+šV0ƒ#žØĸՋÏ.(>ĐÅįztÎƆp@ABQÔôŽėáĢ“ssŌÕ`ĩĢîðï~ũÐĄŠÆ Č‘‹–ΘVwt˜ésũ6ŧ“r―ôĘKT€P,Žyߏ<vՌŨô5 þĢĢ ÆØŦn•ļŨ­ýT/ļãé?Üę á,8yÜÕi‚ģcŧW-~öé}ĩFbŋq˜3kPųĮŸ*ĨīåÐę u9ģ―p}†kéĘOWToœž{Í# gî]ý…·ũhĨtŲü•ĩ™PũÞō5}&Þ·hö”ð杏ÎÛ4í™2ėÚŋNoņø}Ģc7|ôĘâEĸŽvĪ?4wþ ƒļāpĶĻåB ‚ŒZI LÂĮߋŽļ˜ŒÄpÃëŅ9pÁ(oųCũÏVĮOûčĨąKŧý·^[ûÆô0U‚*Ęšũßžë­C•ķŅO\~‘Þzâîß/HOßxÕGËoÉŧ3æÉŧïŽę?ųí“ĻĮmG/' á'^˜úėvŨÄ7 ótÍ@ĸUí9-2Bœ1j‘ģöOŋƒ"‚‰ĶëÁ`ŦįØïĶ͉žfæ?— [ôûÛ&?üÖ7ïÜQWšíßē9ŊŋÞûåĸöŲŨŨ?q]Q~VÃÅWΜqCBHį–M›Ēïdí5ĸéų1ŋõįÅ3ĶßĸĖķ[o+Ēu›‹‹ogB^YšŊēóþėÞđÍĸāÃČÍsĶ>öâĻϟ‰VÎÔ6(„Ŋw(Ģ6IēŠÕu]Ó48Šp]ãĖ`šW3(STãí§įóÁ“&ö:~ŌĸäŊۈvÆÜ{˄•wo:ÞėîI8áŠÐ9gâ°Ą9UËWýýóí3/[ąléÞŌÆšŠÎązcÃɆ-ĨĄ3žûMnž―CÔPq}ðØöôkÞgš“x―ščf1vօZÝ0üœ„Pf0]ļ=f—u…i‰%HĐÞŋĨÚHžņËÂĻ(įÔ[ŪúrÚÖōö›]œOúý·ŒēfókĒéܝeK%ÚÄ0tMoŒ/øísONcýíánw§” Ū›mP€RĘöŽĸļ­ķæÏ3'“NĢĢ6õt‡,8žĄŠÕ4äœĢŽj%) Ģķ›ŠÛĢb[jŦ>Ú°ïąk)u{··GēeĮXÜŪššfĨėĐÚŠv‹ÕJDaâœũ7vō­Ã+WüãoŸŊOŽ8ķĢ%þÉywžóH%°ZCCTWEUĩ1 énA ađþÖÖÍûË;ÃįNđÁ*<ųŅ ÐÕĨ3Ÿ€)45!~ã’uëþŨ/Ŋ͏Ss·7óÐhkGkÝĐ6ĩOt}MUGÕh (DwëšfpUE!ļah ­œPĘ" 0éDíE˜ĮË4·@D.ļŅéŲÛØ!ė.nŋq)–ð–ŧgÍëAk”…yu„€h‚ˆB'ILjé}éŌé#ߙ;ýĮŸ}iŅKkTƒÅjOpe‘óĩ—ž|~á-ݞ{ÛMévU`Wb ŪiŦÞ}ųáïýīĒãÚņCl:ūoų'ï—ĐÝĩnã)š5mÚÐũŸ9kþģ /9Ú 3'|Ā-/ĖypĸSŸxõą(Îԅeč„ÛïîŨ4åö)O>ĸâ‹Ï/øýīđG•ž‰EKž›ũÂÂyģ^/pĮĪ”bļÝĖā@Ũ< FâsģþíÕ%ï}ââ―nBq·ëūBT˜Įs6gFŠ―óÅųÏ}čĐ] uBŨ3.™4rþÖĒ7WŪúäƒe_ķrBĄ{ēŠ•Ī€Cū~%čŠ{—ĪæŊÞr°žÝ ·>š`ؘ~:OŸõBޚ/+ę]·ÏZXT0@ ^1㏋+NÖk ŸđzōðĄýD[874ą Ų^{pOdâÔ#ēV•Õ6ۜĐ1aÁãïYpQTDræŊŋ=ð@­‡#€ŸųmęđÆ Õ‘5įÅ‹ÖŪÞWÝDl― &ŒÍMŒ9{qïUkŠ:&ÏyūhdÍcÜøð“$!‡y<ýn|tIāš;ŧhæŸ^Îw ;mÁÂč^4Â~óģ’ …{ĸÓ câ,FHÆâ^üjŨņ”Û~}mŅbĒôÐČ%K–~ųÅšęN#%3=T!@€œq72ß+2jĸ+I Æhŋņŋ0€*”išÁ °9ŪūáVD Č5]Ð؆Ļ834MWÂSŪŧåN„36pðÅšĶqĪã'N*$5ÍK§\ũšõäc3ŨëEĸzŽã‡Býž ĄÎņ“n/ĨDh^ IÔ/}"r]Ũ9#đ—Œnč‹Ï/HĶ ‚ŨÝð[Âėotáe\ó{öe āÕ ö‹.5ĸÅË$ũāBÁ9™ĶsÙrݝwƒ@B„ŨĢ!œ!P)ų.m(ŌÔÔ0I’4MÛđsgAAÕjeŒ]ākʄ‹ÅrŌĮÜīá?LTĩōMG] .ÏϜs1™ģm@šNýïĸ‚pūt{rB C‡meíĨ5­Ģrz]”d ą!ĸ0W’€™\ĨĨĨ™™™vŧý_čāœŨÖ֖——§ĶĶžááBļĶ8,§[ö–7v…Ûl*"ô°­CŦŽoŽ쯅)*Dđ€ IAQ3dËĘĘķmÛfÆ…ģ­ŋ…‚ÐÐPsĢ™ĸÜÖËBސėrGĐïĻ-k ÐĢ(DćŦS#{…) %($)pÎ Ã@Ä16ĻŠJ)?ĮÆ^ëŌ[ܜsčY‚,4>B ·|ŋ5ļŒZI ,„€ųĀp=ō o(Q9?Å$I’äŨ8Ēï?PÓy&I’$A“$I’$ĢV’$IF­$I’$ĢV’$IF­$IRĀĢ555”R8$I’$J}1ŧuëV—Ë%Óö|$I掰fĖÂĖ™3_yå•}ûö5666I’$I?3TÍh5֌Ųĸ Š0ī†îe›IENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-update-finished.png0100777000000000000000000022263413761647206021465 0ustar00‰PNG  IHDRÎbðZŊr%cIDATxėX SYFݚ_―ĩ•­ÚšĖDŨGAh@ūð5Ļ›߈Qš†núýāádēIvvy‹đ =PëdSŧ~UÞęūýsūþ<ũT–X,vqq!Ëō?ŧĮĮÍWsēyfėš[=€'ŨƒÖoߟgÐúėÏģ?__ŒV°0f-įįįÕjõÇ?wŧŧ;lí]–ë^Ï7€gžýyöįŲĻÆŽE„ŧ&4 ībû&而§EēÐ>FÆÖ'Ī5)ÔŠĮĀŨŨóMûóėĀ\Ïsĸüßû`Ėö―xņâóįÏĸú5zzz>}ú_Â0’§}}}°Z~ Äĸōå 0ų刂ýÞÞ^ØifBBŽ2ÃŨĩņVƒopPNX[!žéALS` °Ē°üæĩZøxõvŊ€•îĖKoߟzáö1Š·ŊŊ·Į,ÜKO__Duã,PÕÜx•^(üPÚų›þ@ķūÞ>Č€į`þ1þ€Ë}îŽûšũ^}/lÂbâV·Ŧþ=HÕSôĀܟ?â|Ąý'ũ…ĸoøëwß}gĐ=>qŅ āy>‘HÄbąH$F‹ÅbÁ”|ttäfBs Ÿžž6“išŪŨëÍĻĒë:ÚiũâīɃ`ÂG„VUØūđ<›ySÂïûSÕhō†*–ĩęý,BĐp›+ŠÕĶL—…\ūĪčŋ•§^o4ę­þŸÂ3yš5‚ÚųņŠ|{u sr‘ÔÚ]ýþQÐĪ驔ÏfŌéôõõU:K*Z‹KƒĢk čMŅĐÞbvķ4E$ģ7éL&}}•!é{amû§ÖĻëïOöO3―YC ·}Ūģ…|‰Ŧ]ö ÛþÁŸ/@įįËü\ā%Za.ûŋįā ýąčÐ4MĮqņxüýûũ‚ C–åL&ÃҘķĀlæW* ÃïūÍd˜Ą…Be|–e126 CfDÆō7ßbœf vLʰ=픠ĩÝ>&Ą5]›ų‹Ę‡&^ 8g)N…™ŨĻVžöÛ|IƒĢ}‡ĢĨéĩ†”O+NF0öGp%UčôM^ÕŠōŪA…]ó;‚‚U[ÞšV•™ĩïāāørhrÓeĨ^UÉĖuž•aÚL˜^upųĶg§ü3o6JžfīĨQ8ĀĢÉĖMž2rĨÕp 7]ëz“?ðĻÞÐũf=sŅ(‘õĮМî+ŲũŽŨÃnĸĖė”/ļąËˆU$BPĪĄõŪĄŪÏļ"ÉûWj# ?l l!ÍËzýį†ú.č í]@TóR‚bŸēL0āĩš?_æ4sBįįë[öĮĒ( ƀ_pácSUÕFū*ę°B7ĪR)øT‘$Й 2LRõPÖd2ų›äƒƒČlp(?šÅōŠöŅŠČˆÐ†ƒ€øŠÕÂüÁb[oģY‰æfÁ&ēÍüEá6ßĸų/ƒņËbĩŅāÉģ‘þ:d](Đ5EŽä)2Gæ+‚3L‘ļ\Ū()Š, ž •Eå+ĒG>ģģ9æ_ÏPENTdĢH’Ī ―"ēeŠČ**„ ÜCT.GAŌÓýæč]ĸũ#'7,Ė,ąrŋėŸZݗx:huãW'‚aš°7gS„7EKš,?üëeŪÂBVš/”Ō‰ĖOsÖÉđ·ÃCÐLåēųbYQuMU$ð%šHsĒČqÏÃ;Z|0Cā*üýNąÂIHȈÐöŠ"Ōy2—Ëąžo6°t<á%äóý0eÓ'„o隖TI%‰cNRô‚B‰gK…,”$Ek4”Ė{WĒIUŨ9ĖP ‰,T*œéDŽ―/H `UWÎâëžÅtžƒSÁĻÃA=U‘čĪ ŊĀl…[ˆ•eą@QÅ2§`ĸ}Ó~îĪÐÖ?čÚĪš@ÍÜI?7G™C,Š™Ó*øÛũmZāf"ŽÆ><Ą#ĄYEšM‚U„RĐīŧŧ ß°߄ĖēŽüƒž··ŨŽ įEiąXTCë> iMˆ‰o}„ŨꒉņąŠíTĩŌÚū‘‰?"ŧézųō•wý@ŦĐg‘·ĢVį|IÕ/w7·›°[}Ám^­ dÂX+‰j>óû|3SÞąŨCÞ`„Ŧ”ÂAįß^ūžô“”ÚÛ$<bb šNîVw―FEý>ĸĖÔäØČwnŧ"ĐFgUv{ÕãX;”U äĀxšŒ.X=óįĮ‘áû‡GĄXR’ïÉÐzLF­/IqÏ ‚ĻˆĖŧ)‡ovÞíē ŲbgE™NŒþð}ĸP`9VaŠŅ•Y'át:ˆÄ LÍý͙Iß4ážÜLfũWƒ.'°O üÝš°žPëĘޛ Û1á|í=8#ÞÎ,Å3UMJDގÂđČĀ ―JD<„Ëép@~FP Wa3Ũ§„wé"ÜWTiÅ3·qŽUu‘ÍÍMđ“·dtuÞãv ÚWã™Z]ؘũū‰žë*ģ<=K抍úåV0ÚS4ų$ō„mÜ:ĩq˰ų%ĮðÃĢ._ˆ–ÅČ"P.aúo-X'ĄÓ;ĩz[ævv*077;aąŧOnËpP[ûÖvýcÞÞôų˜ 0ÉÐáųj-ņŸûëWðĮbŒ<Đ 0ø`üŅ Dã‡؇ĄGíČ0UËå2"ÃÅ’VIØ#tÝ9°(,!šÅ^ģó*ømg€ríbÂÚú×ŨîųPČndÉŦÕO8v{ƒEIeé"/ŦÅÔöhŋõē$óŲ}§}‘æUō422䌧ŠåĖĄ}ОbÄl|Ë9ŧUâDI–˜b†MņĒÆŊX){°EÜZ͞„‡‡Wt9}hē_ԜüðšÄ„WžKą3QVUōbŨ:æŋ" +:-jŠlĻ–)ၑWãNËã fT™]ē9æ"å ŧ=mũÐngÚæ_ؒt-_LØĢ­y›'ȈĘÞĒÝØ$iAŨĨðǟ˜^#Y‰<ýilp,Ub#‹þ ßrŪĖÉŠõĖDÓ5―īÛ–öQ|x·ßøðęîy™špūķE“YžĘŠZÎ$ƒƒ6Âíšô§čRzgÄ6™åī›ƒ7ãŪUV–J4i–üöāŽĒKóūå3Uǃ>W†x­– ÍđĢ‚Ėē Jd"2î^ūeĨŦãwþå0-ĻU]XzWvÏó—ņáQÏé-[ÓųÏîY;âéŒß:0ģãDæMĀķ=ģšęðģsåOqWļ§go@bÕ‚Hāˆ(’íēTr)N*:\qĨ*GURąō·åð/ų1Ū”uX€ˆD ’ĨΌVŽ@Āė1ģBH„cŲ™žŲ‡^mË‹PąŠæSŅn―þú―Ŋŋíî]ąSfŧšmĪݜ/‡đ4Ë9!;_ŒïP‹ÅYÚ]úCØk$>`-Ā4Müē úGUUlBl4úrŲëõBg+úŠĒ˜Ŋ ÉRJŦĘoŠ"mØâ(‹`įØ,”JC˜“°Ē!2€ųƒ >YAhô‡éĄUdþPœ"ĪZg`‚QSö:Ú\Œ>^5ö9Ø*ęÄÅÜ܍ëŨ'&S5*ėŲBQL0*FkïĀ@wüũú{@ Õ+ígŽÚbnvčÚįækŠÄ'Ti™PĻjíë}k ŧCõĻŸ€ŠĻƄU[+`Ę.Ŋ­(AoĀį‘’*ķōMÃĄļl9øþ/}ôáųÁūpĨ\ūķūÁ·Úƒ^O@J(d)Ō/)aUkåråå?ÆoMĨ–ÃaÅŽŠïØ@ĪÝ Ŧ–9ōpČßŲ}ļuŋēžVĐZ"Ōwt_Ї_ōKÓĻÓžŨōtúÓ+7kKŦk卍bėáØDīæmũ{UČcnę2ž]GAØO.üøH§?>zÄ[Ōē™xōyïÉūōr":~ýúČã⠟ßÛBQ@ °ë܃rŠ"…T@W!692t}üëĪðyU (ŠGUðá|I7JëUd‹Ï”Á##k‹KeĢ,‚Ý'Ž·-čZU؎û[Û?ÐaûÚŨ8_ Ų~Ķ>–dk‹ŧÉØ2 Č!0œÏUü/þ öÞIeĻRKK ürAJéiüRÕ[GĢ#H†ã4%C)…BۑaËŌåB’XËž {U0Ž (yMĢlĮæŅ %ӛî "#Øņ`ۂö éACH ›;cwLCķõwã3)5rŽÕc E­­?NÍžŧxéėÉ ēĐFJ‰OĐHŦ†; S˜ÂŠŽüŦl*æúâƒéđã?ļtņĖÉ DŠÄE€DÅ4ʕ \`АčŠ][ú;ŧ“1ýŲŠęõlžXœ™K…:#0*åŌƚąéŪÔá ü~ŋGÚđTāz‡”u–RŋũUQ5ŨA™WúÚį.þėōå/{GĩŠ ÁК@5 låÅËRÕX*,”J­^RU|€QÅ.Zõķũýō·ŋ9đßø*šūP°Ĩ―į{g~ņŦ__þøÃĢ]ĄZ­áuą…A?Ļ20pž{îþXŠÔvŠŋ3?ó`&U9ĸӟŸęíŽT+Pču”Ōō‹ĩõĨ'‰Â3SņŽ?ŨĢQ}ðý.œ9!Ābag/UІ―r D)°._(d.­Žn˜•ÕÂÓĨ@Wށ0e |ĻÂL|MA˜óþqøÜĀŪģÆMÕtąīA44ãÐôFP!;_p—ąóÅ&™€úIÁÁˆüī’ĻdA8†VŨuxō"ðī,þŠ6‰ ”F­`Y#đP(Ā}ÚÕÕ%Ĩd:ȰUą:ķT…Ðô†ĨˆÃÛ KÂėEe7/Ļ%ĶÇbæ)Ieģķ‚­‚­―CPPÅüÁRŠeöž:}þN6ʆi”j9Мū32ņu.ĻŲč\Ix„€ë 2ÔŊW€%Īô@ÎķHÄģĶO,TB‡Ú‚ÓÃw%,Ĩö8:·l 7"@w\Ԋjū’Q1Äáþ·?ðß― ―•+<{úmŸ”zÂécŅÔĒaZ&š&ĨX_ž76<<2<4rũÉō†bę…QXŊ*@ĻzúBrtäŸûúÞ}§Û3>ô—ÏŪ|61ųhÀĘ^āBiČįSÕâėäčČįĢũR='΄á†ī­ąčĄĻ/scöþÄĩkÉgæ`§Ĩã―ģß/NÝŋzõĘÕŦ·2OW^™ R­åĖ―Û lhčæW‹+FΧ?(ĘÝĮCÂl?Ø Žßūq#ųĒ\ZLFÓK^U‘ŠĐðąīŦðøþčũ7LË'­@Kļ+â01úå̌đ^˜œÉÛ:kO“ûëKĨšķū}‡Ž―Û'Ģwn^ŧvã‰Ō~îTŊ°!… 6˜ŠĒH[―î;EÓH; MGŲýBĢŧ9_gÚHÏ7=_$•ðøƒÎęČårÐæóyėfffāixÆ ˜šš‚8\ļų:€}"9@2<Ë—)đC4œ"SføN ‡(3FĐ(ĩ”,N vH<… )!?LõiĖFc‡ĄÆT$ŒÄ4ņ§XÐģšž+á yĀB1ŸÓģY=|-ÅR™Ž–N'“)˜“ÍčöD]Ũ`†Í€ˆ††h™ųx,ŪŠy=Ÿ‹§2Z6•J$R9ģaMSČkY―‡?čÄėā|lnzúŅ—cCüÝïĸðÉ'7ĸþ(ÁDl>“Í“íųžžIÛ_åßDJÓrķø|˜9MÓēvXm&‘ŒÍĶ ûdĄŒÁģŪsétÖ^5ČÖ튋‹ųĄOĸôį‘ŧ‰D<žĖž€?,ĪÖ+ŪĖĪc3ģņų4ˆāžNÁc―ąØžV'ÓîŅāqD2‘H$“i]·%kZfÓã"äIÅæ 8•LĖgmĩzÝBð+sæÓķïš―FĻ NÂS™T2–Ė%›JÎÎÆ€‹ĩCŧâ°°˜ĶŠvu°ĩčõĖÐa[·)š9ėhÎŦå|ūØųĒ8;_ėž;œ/&@‘=õ‡īíÞ!û m|a…O?@ ŋÓEDĶ>f„KFÁDšķō!ˆ™‰ –™ÎšNė7ķ[5ģTÛņ…Ø,ę° ›H-“Jz(BA§lΧđ?yÜÅxÓÁlĖ?ĻŋņچöĶ Á­.QÁĶz`ÜũE-yo|üáLëĸúXÐÆvþ ’ÍĒthŪūąáŦ#wÂ―EuæIC6ęÓ1 ÂęÚ([Ģ?6ð?[ũ'fcA2{Q”†›Éũóũ›HAŠ3Íį‹Áa“ģŋRia|‡!Z séÝųÃ+î?z­$‚Q@Aâ4]40˜=üý'Å/ĒóK[CÄXߚÆŊ,)|‹Ŧ+™ĸj”B-Ëfð†ĩ $__]ú*'ŋBŪF8°ųŽž4$ÐĮóüjÂÏPû7ÄY2yO"O?d؈Ŋ'}c:xP?ãąk‚3%ęÏžēōÂÖ­›O^,mäÉ:(x Q+•*’$JSoۏc{(\ÉýW[ža …šåD$ĄūsâøÏ{Ž&žkč?ÚJFyjû„ŅCGŽŸdj:Âdˆíɐ„}„[FĢŪW`ø-‰Ī‰ĒĮ!“з·Ņ—_aęÝßãFžˆüĒy^­R(Tę?=Ė mŨÚąĶĢwÜy-&‰ĸœAĄŠ}öÓčÕĢɔ).GJóĸM–ΆnÛ~ôQ~MĢĸ,‚ĢŽŊĮ!Ä\(PąÛ~†ĐÕĒEj õ ÁAĄ+ģnڌ4ķÜĘ"‚ áíýK7ŋōīBŠ#eĘ2Mís75.ä˜ņĶIđÔR ąäüąí;w\Ūf‚3ĻýLAäÜ91ßjþĩgÅGOýŅe…ÃŒ)&― õ5–b‰TĶŦŦŦĢ#Ĩšæ'$)‘D""R,ÕŅՕŅ$šÉð·ŽčãЇĒÅbüƒĪ…Κļ/ŌŽ6@2,`YBU-sÜKW&#ˆųŠ€üõņ]n[ũ_QKup―öF–6ķÓIBáė)ÆØOX8î"SÍcĸ‹ [&Ķ(J,–ÐŋF1’@Ųą'VšŪúĶV,hŽ C(’é`jŌYŦŸH‚9aVŌßÁ$€2|›ŦÃÚÃE|ŧ ]æÍü‡Ī<ág§ų;Crī”fjۜÜībõ‘ žĒØb!e}aqqƒÎĢ'ŒƒÉÔīgg= ‘X8K’$%Ój%b™šw^›VˆHÅfĒĶ}8)“i―$išxÁí°+hRë ™„@ڈˆiĐŪÐð“EŌĘ 2Škkc=Šk+m !FZũëâh6oÍią–nĸŧuķēΰļēÎh°é„ cĮ˜ŽnüĨTL ĘPdDāāūˆĀJ6ąQä'"ŽåīŽĨ’Ķkü™|îJBqþ‹ÜĖ\–ĒJó=I’·mÝî‹>#llm†toÃóžpéԂ0g(ĻJaUĩĒą‘ …ō)ˉˆŌ–à eR<Ô°đbžŒ†Eŧ „Ï[ũÚsëҜF‰ó‘Ā ĸ5ŪŪî§/\ 9ŧŌŪĢæ•ï_ÜķÚÂÂböž ŅO IÓ@™žû@`^nōÁՋ­ŽœBß**ōv-ýÎÚÎ!ø~.ĒiĻω―ėy,0.+1ÂŲÂÂĘvMlęûĶÓ:ÎgZž&kKÓݗĖÃĖWlô­PCŠ­ŧsÁËãx`ĀŲ;œ)(oĪZĩî3lаnmDũ:ųîŅÝ{ēōoûíąīēÚá]Į‘:!.5æÄ+ËNĢnGûxîŧ‘\Bür0$+2ïîܰũęĸ‡ũE§k·ÓØ (‹ö8}oeóýŲĻt@R†đšũįÜ›[X,t^Ÿõ^…ÔōôW‘ĩýD(Ûqôöþ~ŧÝõņũ\CqÕ7{?L+Oŧ°s_Ø%Ŋû―ČŊÂüšũéBüc íęŦŨÂCCCŊ]š8kDMMþEï>gC“Þtœk3{ĄsFq•gî?}ŲĮŨũĻïÅw5ƊęŨIŦæZ˜[,ũļV̆" UūyæĩswDRzԅ?xž|_—}ÎÃ7ōezŌÆ™8"Ģģ‘pD—GûŸ8q*8=9Öqņü5g’ôûö1rxŊ6އoˆ9>ķ%öĸķýþU " 2‘^km-,fÎwJČŪD$ÁŊˆâYš]ÏÞÁáááØ”+ė˜üŧŧķí ‰KU e*3}Žėŧ›YVœ™xdįĖÜŌaŲđ;Đ,l‰–XÕÓĻs[ũÎ(Ŧ§iþiTБ―û_ÕR$,JO8ēÁmîiër1&™!huåKŸ‡ÃÂÏûôŋrOĐƒ‡ŒÚĮ@9H ķņîÅýöÖÖs^đŨĀ (ÏŨæ=vüLĀõäĈv–ó~Ę)k$?­ÁÃtéŲū{_MÃÝgLIÖýŠĖ7™õōÆīÔå}'›toŨNŋã°#db1ÅÕGû>xÄÓÓ넷·Ũąc§ýŊÕ°DqÚ―ÃëēÃ#ÜÎ58.•E™œ‡‘îĮï=M:ķnöÞĀŽ–5ŋXå8w†―ô#…š#ŸĄöoxyÐP’v=·šî1lГyRŲÐØØPß@ˆtôôujóĒėÍŽv9_T]zïöĐy6ģ=#ē(xœđkۊÉĸ˜å}õÆÍ›į–Íš4tüôÓ7nßÚîqðM ĪyyÂußM+f™-\ų(áfĪįēÞĖkl>5Q‘íbgq22ŪžŽ$Č{―ÓÎ@y}unAÓXyãōĒzŪî]Ę~·uaÏxšxũ$nŨŪöfß:{øÞ―ysÏæõû"^ęƈΰý–óŨ^ŧŸ—q~Ëōĩ›vßĘŽ ™ŨĻĶ(%­ŠĮŸéq1‘ ‚I)+ó·-ą;ró֍K?mØõŽPÁWåėtŧÞ+"Ģž,ęēŸÍüõ ‚ŋ~‹ģ’Þ0ÉŌÜjŽąR^W§āMl,Ŋ[WšQP\ôķ ­†EŠãCnĶigõŊIYžŸúüyrj2.ÎpĐË||Ŋ]ĩtæ—ë1qŨýķx],­UĶÞÃlØWŪ„―“3i!öÓæ„f•gdíqÚäuĄž”ÖūN=ī{ŨR[ģĨ›O&&ā*čŠĖ„@ũ5 'Û,JHÂquœyþI™„VÄøž\ŋfųtÛÅ!7âr^–?―rfÍj·Ôr‘˜Hðs™·lsôŦÚúúWq ·ŦÕĐŪöÝēČiĮđ'eïÞ™ýk|n9"‰ßŽÍ@Óø:ãEZō‹Ô—/Ŧ4—{Úūlį𜠕DJ? õōØsL-&̃Ï…q,“v=ÐÍņ;ĸĮĨ-OÐĪÄøísũÎ-nIŅ‹kÁÛvėŒĘŪ‰ļüĒîWRe™‰.K]BÕWäÜN~‹{eÅ_ŠIF”"lŨ–ÕۏgWģ"MõÉÍKū[é‘ðžĪŠ n·ËÜÉkNVģPũÞĸÓ ŧEŦĒãâ/ŸóÚzęŌõ§qÁģŽnûІ](͇‡OŠJržcŠhô,ĨīžŽ,+éžé΁Ý:Hž'†šmüé~N)•ąqáįýýϟóÛíūiýÆõ‡ýCˆŋŋgßé;‰ȒÔûÎKW†=)ÆĮĄôį·Üũnœeiģ? &ŋĪĒĶ8yí,kï€ð§í;”ZP'Ljŋ#Ô~&B5zz2šeđOĨFyĐÏ{$TŽœĩ7!þqļïĶ6ęœ-~ŨJë!3ÁІM[q=.rú CEcã éKĢb"§vuĩĩJ5  ÅŠ ĖŨHz7{‚aivÆåЧžˆ‚Mî‰ĖŽžįîy+ŦŋōĒĒ{9õĘē0ÏCÕ*ýM>I‰Oķ~ĸ-§Q·ĖïrŽšŨd—-‹GÐzëņŦ›Ė šå1qD§ņģ"cÜVý*·ômEęÃČSĄÏ{Ïږv;bŧãīē§gĒ“K›wĮˆ` ss Œŧ ԗr,/LW€ L†  ŊŠjŠÃÖÉ& šþý8CĨBZĀóó;LGâ=åČE0€2œ†ĢÄģÝöލōĀËwï`[Gũ―ƒZƒĄßïxpóō#öōžÝÏËøe;žĢSÂėŒ—"žå•ÔŌÚRcFŦŽąlØYÂp$ŊŅ:gSüóĮŦgŨ|(ōŋð@C’ u1ĀvEäݘÃ+F!Ĩ‡–æąpÍ۔dđĖøvķïĨ‡·ŊøIđēžXŸÛzĶ n‡Þ:·ŨQþúFă4–ƒŋ~B@ŦËs—ÛN4døļIvO •]ûŒúŅēģâĐP6”œ―õ”ëūhä—Ö.ŧâ$<ģ}îŨdŪĄR~Å (ÂĘ `q<āąb<Ŧ!ĶzœHļ{;Č;|ũōQŠŠÜ‚ĖŨ†Úí\m›9î=ëÂEŽV’ Yކč}NĖ~Ÿ(ÁvĄïĮDGčĨ›íŋ#ôEđˆD ŦæÅ:ßo8|'üT Óo+Tė§ĖŊQ‹F˜™ččUėĢį3D§Ø[˜TūČÍÎK”ĻÖˆžrācbFAīÝy<0ųŋkū›;ë#–ëj>Įđģ™8•pįV wφ*ËģßäžÓ ’‡ļÛmð$ŋk1ÛĶŋŠ ĘŽ·hĮ‹ÜŨQgķPxþ-Ąö3ą āBĄŅh8á/fØX”Ŧ$ÄÆY|-ClC'tāņÃŌ:,}Ýķ:ęe4HGŨ ƒákÖõëŅsX‚į?qā4 ĮŒ-ó&v24ķ35 ŪáUsČKó…}J„§ŧĨÃÕGeĨūĐĻ# pچP„ Į7ÍHÐÄQ ļf‹ÖŲ›ŒõÖðĩj…ž(ƒí˜ ėOÓt§vÄĸ,Ņ„ %ÜؐüĮ ĐŨežÓęá}zˆuShU5•*ōoû˘nģ/0·O~SÝ ĩxM`˜<„ĸ8…žąū‘W‚"üHøûߛ)t qęHDąJA5D ]ëØŽ„ M vŽēqw6VDÓší U ũ jaĮ_IAHÜýûŲólÆéá~•™1WÃē=ŠWgCĘy 4Ie4ĐVj„ï–Îčd<Č|†ņ1™ŪÔĻī ˆP3BrįWTýAE‹Dˆ!9BpÝd{Wģ^ØK-ëŅUZôšÃ ĻViȑžV€qHHNÉëÕĖ[·―˜ä8^°”æX,"ŪÅfŸë7mUtĘ?ƒOõ=}ņdvŊŊFŲ ”ņ<Ðï3Îmã2C)'$vô;<û+C8Žę›:mâ—"üSĢlPhø#ŋ6îŨöÞ­=kŠ ‹ûNĸĮčĩŊbvšïļĸþ› š˜ŦžcYę7i6, ›ĶâH’TÕUŨh BĨzwoÅÚm…\ÏSÎÔÞ^ëļũ)ASAžÔ@BšfZÞgØR!WōE"NĄndCáöŅ0Žā^†ûgOĻŽ}Ž:ëMÉ*â)ũý{e7BžóļÛpģþFíĶūđ1"HE~âZ‡UY… .û}vüd&fØĘžëËÝķW‰øœ?WéúãÁtŽjó+\d•PWŸ6ÔŦT4ßWWá•›óyWûũ#žĄ;˜ļ9MŨaÞïÚðӎC~qĮß ö–Ï’:‡O45Đ^‡ķ­_ūbۑ`QčwFjŧÖÅß ‰MĘVÄjuhĄ3ÏB°‡ąĄ>HōôENŠQdgĨf”Ę›ŸûsœĶë虋Gũ-IÞžeËÍO„]ÚėķōitŠóœŅƒ:ōŽPĖ0ïB‚.ŋ,ŽŅ"ß- aqrĖÉS>^^8Ŋâ™ô4iÁãŸĀr Čūq1:ķJŲz‚å`äx·øĶžNSũ>91ŧZ.ėķØ–ŪĀDR ðqïéøčk§ƒŸÉ0ąĶĢaÕ-åų>d°ĻĶ+z69"8.­b„å’ųŧ Ž‘Ŧ[ؙ*NOOz–ÞČŠ rŌž―.ãlđb°ļgCEDā)ŋSÞØ–SÁąĨĩJ―Ū}LGũ§ÕĩņũsfNûf@]ĨžąVčΚĪú}|ėy“–[ÕČ7›Eéīë@ÁĨow7Ũ“ŅÏxJŠQ_ųŪžZĐŊŨĘßĨ$§ y•ũ›ŪCËąĄWcĪ*XČ} l›/úönâÃÂNE܊‰žz=%č ÔŦ ËōÍîÅö3āũ„ÝŨfœÍWBl$Ã|ņE‡ū=ŋč!ÁŠuę:Ų°5dš‡$uŲAŨÕĄ/ßĩëÛŋw{*äLĀĩčx\ķŠVe ŨÔĪ$§ ÎTmz„Ëbökē[ĸQ4\ ð<ęyÜuÝÆįoÅâĸ†Pû™8žüvŲÁÓ{Ũtâ_ÚøĢ­íĖ™?o=PT ŋqÜ}xÞú,; sįƒWšØŊ Úho@^(ÝtļrŲ<@SÝzČØô&ęânŦï–%QÎÛũ:OėĶÔ ĐЉgy4ŌjÕ)w—ō‡KæYY[Û,Yv ĢHŪc8x‘ýīڒÄu‹E%— Ę°†XB"‚$1SĒ™đ˜$ôIÚ`ĄĮéefĢ„^ðËcÍíĖdœæ·g^Džūd\?―`Ï-ŪkÏÖ ą‚XІ,:õ=3Āũ i}šĨs­Žm,úáAN"`3\CI· ë™?9eoke=Ûá|\iÛîFgw1 •ál;ûvē·…įŊ§ą~š §% 7ęŽģĢ“ģ@Ëw\M!) CÄ$”ļU;ÜĮ‚Õïjbõ‰Hu{ųŠ5Þ2æÎ‡n\œÏgŪĨĨĩíOŠM‰D][îøaJÜYkŧyĄ)e–ŽîÛmMT”B­ĨðĢ&H‚ à eĮ_\8ŨÖÂÜ|ßåĒņÖ+íˌ[·r1ÐÏžCųņNVVģƒïe@Dīļˆ!e$­Đ.<žÉeĐãrÁ” ~ŊŠTjØjņŦNú$ÕŪ·ŲäodŽBŋĮð)“Ų7asæŊŠ0Ѓ$îōéĮïT‚ąÏ˜•tĖ7ķý:ëD>čuSe1m*NÕvĀÔE–#ßfÏēr+ӝaBiŪx{ÝËĻ4ýÖnzŋ.I—Ž:oØöž•īBˆ.jXƒžã‚ΟHdŧ/ī·žïRŨzč‘sgĶõÕŨ°įIŠė(& ĒÅ­ô§­- ũï3bē>Į ëŅQ·u‡Ū]ū€ļqþÝ~Ė|U*­‘DOX ‚Ī'Å%W°·„­Ŋ.Šo―=úøÃũŊ-ž~éĢî„"œÚžĘžĄdŊÔŪ„d/pÎģā+_ūĸöëŊ―õIĮËðÄđTYĘPÚZrÁ@Ë^Ëåp›iā4üė―'7xeģ=?Ø_ĘäNĨ:)į’árpjŒåäJZé€\#éHÆN-”ĪOéŦ|ˆĘK$§%@~Ĩ–$·x§[•Ŧå#-đú·ŽŊÚ5úú*›ÛaJá?•BîŊ•ĘåK—.]Đüø‹RŽpf.ũ‹ß!ïė#žĨ―ÚO•ïøIaãŪaÍúŠ]SÜAG‡{p&o?ŽVðΞWŧģð―ƒĢÃýüOvÎfWēåĻÂąVDî:}[\Kā ōÉožˆ'Cˆ·ņÆb`‰y8ĩ3~ϊ8Į-5FmĪæöþj’•Ęđk·īīîĘČóĸ^g/.Đ―ļļļļĪöââââÂäŦäĒŠäkåââĀïáķXU―žž˜YõĪDð>~P"3™Ŋ=ølAOÎāÓx|Zî―U•·i)RĮŅ—Ąj%’îúÝwJϚŧ0[Û·T čąIU*(îA5å‡Ęįįvû`ËF\ÖZTúvUkŧŠįy_ķr)‚Þ1ŨZ•đ[7ãpwíŌF„š™j;ÐPÓãļEA[K@ĐĖé2žŸGHR™-ĶëAļ§Ž[Õ―7û!Š*ÛËí%3=âv{!áūM ĪĐEŽcœõyžĮqP"áÞ9šwĩl äĄÚß}ü`ōX%Jþãgá,€ŋûþûï#B...ūĖėãĮ™)×K­Ššifķ›ģĖōØKˆũĸ7ũóeõ‚ˆhõGUféŌl”š•ûu“<ŽãQa”å!Ģ•õTsSûÞ@ߎ+ÔV‹ŽŒ]uߕ“<―aH*˜%RYRf+#Ĩ „ķÜgĪŽø†—ČZK:­Œc™ĩ3ĪÆGfĢÔmmŦ€įņTíĖČCėū’‘ņœÚē1éĮZY•™―ãģļ_ݝDV9ófŦþíuû ČgÔ;rqqņuPÍïóÏÍT–{H‹E•xøŌEåđwUR­ģT5[UoōdkM†[YĮqdÖXQ*ÃC*Uæ8ÖŅ:•]ÄÜ―ĪJjLe‰Ōú0j‹ÔsdÖ˜#pïgU —ŲļK Ļú8wŠJöO‹H)Qrä~-{VK_f™ Yõŋš ÄL3‚ 4î^"T…22ܝĪwßՙNIīwu?˜.)éW;‘y·€ĘÅÅÅ“ĸ[6™lG ÚbĄ­œÜî•nv§Õn/RDŽõroŊ,š°Ýņ€Úæ7@Že=Î9ŧŸge>ĪgNųčtUüÜ%ĩÞ2Y-)į>I ߛd/fVķÃîN†fÍA„­Ęyŋ“T2ŸT zÆĻģ@ÎóTR  wīŸLw§Š4۝Āęt‚„”˜Ūh–ČØnú$#ö>ßÍ2Éįī~nJ ~ EārĩßĒŦ-U’s\ūŌmwMZf„ŧ=רּ `ķhV%•ĩ–‰ 3ïÍU’…"ĩÆÍ &6Õu @VäRËļ”ęķ­š6ŲöģŊ'"3*ERÛw'­Č˜g†™õdŪuë`wÏdTF%ۏŋŠBjDj›íņæ% éūÓYxKTüXk*—HÓ5ąĀ3…FddĻ2+û8qĐŠÔžO#Û;SÖŽĘIlyÆÕfpqņ-J-ZnFÝĖė9~P-pĪÞZŋž3ĘĩVzøöépĘxBÓýZĒf%•‘F]šÜ·ïáövũ"’ų0řąŽĢDĶ5õX‡”ā―ã53 Ēķ@lw#9í2#øÖŅiof)Q’Þ‹Aīa…<Sí^ā]™c][ēu†*R9ÎT*I”ˆ{ĒTáĐýĀĐä­ÛÎû―DԘïŨ4€:wÛm2SÎsWĪ‚"U™J•‹‹o+Ŧ•”l5ŒŒŠ;9ÍĄĢŋ%ržgV$U›DVŲ–Ėi}õȂÜá-|x Üs6hkëaĮHä(uŸŠeDx†á! ’Ïqfž _zDŽĩ"2+ÕÔTû‘ŌLĄÚâX7‚ŧ#W5ÛUõnÞ]RT‰ņÚ=™þ$Âį‚CũHĀč ypîíáëX%îžBDƒāˡý,āŲ"ūŧ2UMÍÃÍtË#öđĄ|Prqņ reĩ[ĮÞNÅ2Ð}ωV…W‰’jæ"%m$ŧÏãaũބØZ%ég(u­ĩŧˆuŽ――ŠŽã <;l-ІïČXÚķ1ČN~O%MMŠüÜýÞH–ŠVũųâ xļ@L—*Ý―j:ŠLŌĶA"Ĩ–™·„k‰Ōϝ%Š”ŠÖ퉉#%MutŽôoÍš—+3‚Ę[ûYĄH˜­đgA(ˆū)§Pn?3ŦOāÖųtņųv―!rqņíqeĩĮ\Ę āAk™ĮšWe’ÚžsƒėXĀ+‹UB€dūݎUky’J^nZFÓLĨãRīaŪŅVH{X?}gĮéÏyŠÄÓŦó„šDĒDDdĶ@HļŧHeēf%ßyûŲ}Ž >úÂnFÞn7ÄđK„ýÜ;]ųėčĖđ”ÏÏŧŧĮƒhŽu€ˆt(E‘ŲŽx­cZ2LŸyŧXL @•ĐđÏQ›âËÕ~›\\Y­ûžžĪđŸgVĻZ2BÔL Yēցū"%[fķZJ•iy]šãY­*Ôė9ōxs—%oũįÞ17z™yØēĩî}Ųa”š"8.W5ķĢ f dôOāî$ÚÎjFĪåūf̉‰ã­ÏÓ§5] Ŋũ{dP)"án4ŧÎÖÞđđ ë+ķįđ1ýg"A`-ĢĒŠė―A˜ĀŅ oĖå]ŠŧßÏWĮíķÝ=&k^Ó,œU‹‹o+ŦĘuŽ>ôŋƒ8ÖŅ:TĻjŒŸm•óó,[eÎ}zøEũ{-ģðDe>m HfØē’ĘLŽã–Yįū+pÜ^üôĖ ĨwũU[Ô2&îlý2Óé…ĻĖéũjw,Š&"ÞÁmËŊTõĩŠ| Š€øŽ€ÛÛ~šL$]Ĩ:î\ •' €™vÐ\ķЊpé Áû—>ā3EyĶī™ÎâŽČ\ Sī"8Yme)đŪ?âõmrqeĩJJÉ4!Đjī9Ž*UËĘ Ž…8ģĖÁyžÕá#ÞÛû_Žî›dQ–­ŨóĄšve—’Š„°$ĐšÔķŸĢģķ,ũΌ‚ž·-Õw]Î `bâšŋ#1­R8Ž#2æÝÎĩfTÉ}ųwîū3ŽŠczŨģE)J7jÄl‰“€ŠíÚ5“Ļ1‰Æ *é Ē!Š 1QPąž XŪØ+6z‘~€SvýΞįӛįđ7_üóåōKÏģËĖė―ŨžģÞõŪaÉęŌ·nÞžuû~IEƒLð7/Ķ?*oĶ(ESSÓĪ—þí ākĘ.Ķ]ŽÐ)ôÞW‰ŨV—W””””UT6jNÅūý+MŸÛÛûދúĶچf”wĨĸ‹$ü†”Ļ­ĖHÏŽåIúÏāÍē„6ĸÁãā=Ūl`XŪA!ą ųÆÝ ͚WåĨƑ)**ĻŽmúãĨLg―՟"6ÔÖčåO^‡$mC}EiiIiqQaYĢ}}ĸ þ”ĶތôįĩüŸĪN„rsIŨTUß$ĸŋ<-YÐWŨ42œęękšp"HŊĐmÐ4ŨÔÕ$å/rӕĖß k5€ķoĻ\Áy0@>‡UAāątS“ØĀ‡iāS bB!ÔØĒĄ4Uá’ =čģAĨS2Ã2ÃōXڅËj1M,C ØzČķAM’E|C|;˜qņ+ ũ!am.S‰oŨjÉțĶW7(§‡:ˆČðöXÄ $Žâņ‹/īØÚŌŠĄhĪĀ2ū,ÔŲÖOAŒŲj”ņƒ<CTˆ„kā7s2Žô!:§”·gYE{2!v†ŨTŸ5Kæ-ønæĘžFCJtČÅĮÕ*•n—ïŌÔ{åĖk1ēƒx™ŧ=*úū†`Þüāšxz%iÆŨsCÖŊ_ĩÔûÛï—ïË|(“ôÛÅۄķūŠŽĶQ!ÞęÃ`8UaFĒßö“‚ÖT•–ÕūqA’kƊŦ›ŠĪø†§ÛB֖ę(čõiœÐXēü›YÞþK?ĸõáËđÍ*‚ķžĒĘðÞ1û05nžũÂĩQaĄ~;Ïܒ”Įz™on9ë-Kj,ÛūfiæKĮŌf–åHÍOÖ|óýʈĻĻŋuįrKHŠúŨgˆš―a·Š›éĸ68EÔŋ*ĐŽoĶXŪîË5ԟ}„­ŦûFÝ*hä8æŌO‘óĮ7(4K6î øíęĸ[s īe&iVĐÛråQ)EÓ{Ļ…`ŽÆ\ (ŪZŧa­ā Ep Æ/œčĮ|(6ôBY ppAFå­ką…ëĪqĨÎVI"Ķ#Tč.€ŒØå—q ŋ7˜$xĄÕ›œÂq"â0\Ī‚}Ū€Ã(”°‚CÞ`Āô68§ąQ·)‡†mÃP›\ŠIAäŦ@ēĀl·gą‰.Ĩƒū‚ 9ĀwËŠč‘fŠálôEā6 dĸŦŸ&ŦRe^š ōÃđŅF7ũsįBWÏč`N™Ņ ‡FT=þûŪķ’ō;t+(ā° :2m ”~ÄĐ;SėVZpĸđ@/\åčënSæ3crÚÓZú%A9 ‰æ ÓRņōĶ’8ėä+ėÏÔBKdßĩįô5ž aUD)ēˆ_Œ7ŋv=ôÜežšŽ…Â%v„Œ$Õ}‡7i''m ĸéŨA›Â/–Ū‹ X™þĪŽm •šcX 2n,IÐD(Ŋ·Q‰ŋF,ݔPsðlzúų'8ųM_y!ŋA›w}IøžÜŲt,IPšŌû—>+WŽ›=ķEČÐcðĀ#I†c5wŪ,ßsOƒÎ"Qßdč&.TÄã9[þ ^ Ø|“Å’ÖĻÛú݂>Žœ )$HÔEIÆgĢÓAV^ë:‡ŋ‘{ÕÞ}âŠÕkŨŪŌÃN‘äÖ’8Ų‹^1 8 ’Æ6,ËŌoøn˜þo~ 4ËHû6%däOnÛc˜ÏŽæd + %Ųô&`vÆũ}JmėŠ .]Î+$ĪšãéSíyĄ!„ōëĮ.jÝúõ›7kēk{ēÝðČ_[ŲIpu”\6ą$xīGČóz‰ 9õ{ iíþ›C­,Ë ąWāÃ@’~Œ’`LjßÃĘ ą…+ J-Ð D ~I}pl‹ĢŅ—XøƒŠ^$/3 W1™ >Ø4€Ą"Јå8ZÆ/ ū,A€­ †ĻS–1ðo€ĒTĀVœÅÂ&2ŽĄÍFąûĻ)ĻVQ0„ :Ģš°%nũöĻđ‹hhúޅä؟ 3zøũ?ūl”ðm‚‰ėóûg9rü”ļß3œáíŊį8ūøÚü/ÂÔJš’ž+ũ—ÜÏ<œē+6bޒ„fšĨH’ãˆKû6§œ<ždŲÎ#ũ( sŠđîðĶYcGģd[ĨŽbåæq!“ĮŒ<Ã'óYC ļQ,Y•ŧ-óŅŽčˆ‘}ė(ÆæÓ ĩžï–Ķf\þ=óÐoÉÉĄSĶūZĖâĢĄmÚwėÚÝøįÖõ;Í‹Ž aA8{eüŦzýå‹Éi‡ÐYGoWČåXí5zėČþņe:‚jxą.r]xP°įīEŨJŠŪ^âŧbÆPÏũ',ú=WĢĶŦã—- ZūpōÐĀۏ*rŪĨk$Eû"jÕ·cĮýtÍÁ&…ĶĪÚÛC‡óų|ĸÛ%ī)tqKgŨwŧwïö^ŊÞfåŨ――žëYĩšš›ē;&&õIÎŊóĶ=ÜcŽl•ˆ^5u]]›sdþúĪFEEÖÞY1yŅåA_|=Ä{ԘŅ#žfŪxXŦ+―{îpâ‰Ø Ą‹ýOŨ”?:~;‡'(JŠ;šÃß}ØĻaÓcöĸ.Ō\uÎqŸ°bŨúôáŨÛŠŠ‚Ŋ‘īt™ÔÃęæ'šĘ‚Ęæ:3ó†ė‚æĒK)”ûāîTíņkYŊDĒđðÆĒEÓūš;ßĮûÛq—fÖW>Ęøfō„ŅÃ<§ĸ\ËģJsŅÞu BOĸfYI}mbØWǍœ6=2ŋTƒ?Ÿĸ§ °7Ū”ÅņĶņG@”ĄRąœ,Ãā―ˆÄ. sŦB€Ąhėß*ËĶH426t•°ĄÞL ‡ŌÅBŊ†ÉË+°pmū/ÄūÞģĐÕjPļøuÁ  f%MÁ&Æ_\ ĘĀw‡9Â&ÜGô`(ÖÃbĖ•D7oÁqÐÜ<^ āâ^ĨÁ1ÃK$†xï[„EŽãQIąíÜԄŅ'LÛ°v’yuö‚eÛšÏŲzúd2óôÄō g% 0Hš•Ŧr–øïŧ%ņ`ČØ]k7=Ūã†|9ąîJØšŧÖGnV{zôq4kŽČÏzøŌšËĀáŸô›4iFDč85<2APúNøjhÏîó|—ÍïJņR}Qq!ëą16Æ)7ųR‘ūâÆþ€ýũ7Ÿ<íßïUpøUQ8"x™Q ėÛQBS°@X:čáú2ŋ­§û`OŸ;FõueĨ•C`rÏ[æĸėO+š3‡dÖŋ·wŧĸóÔ#ũjú bīÞå·ü”fô‰S‰ú[ ûÏf”’{&éėunĮ†õî˜YéŲ5dčÁýs­_/ߎĢé72nUąë–õr‘îÝū\Š#+ïžÝ›ņr{ō™ƒŦ'XrÔ­ŅAIe?Ÿ:9ķéNČÆĢZ™Ä­Âĩ9iŋćŊ^ģû”ÔŪģ\ådÖ3™Ŋ9•rFėŌÍÞąóōØ3§DĪïš^Ļ!Ж€^l|ōðN!ē€ŊUüë•Á@ąVŸųƟ?{ČĶ4íDfķ―ÛāáûL™ö]ļĸĨænöÕ4Gßø92ęHĢIŧūügô”{õŒĄęܞ­wšŧėŲR™ķëZAĖMēĻpîãÝ*î?Ęŧ}§Sĸąs&ž›yûÞđó•Cö┩Ükũęj ÎýB~Øąœ+Ï+iķrī5§Ûv^—|<>”ýýĀÍRšîĪËÐļ­Ž .<·å7‹˜ĪAóðĩ5õŋ @ DhX Ō8,„ŪĨ 0ÄI' xŠĪeØ mQûnņ‚€ũ/°–IšÂč†M  ā€pĀ)#Æb“0žW8ŋpøM‡P‘ÏYńārÕRC“ZPį āŽņ D”ÃQ3Ž@ŨĄČøŌļô€&ҌEA:‡h Ŋ .čÂá'>O<Š,;h<|$ÏC8‹þ5sXoÐBŒ˜Ú ä īŸĀF9oĩ!ZƒüzŪũMƍQ1üã[Ų„Û·3Įđ;9wčdo­ēTë‹oޜ9ŋÍÜõá‹H<ŊüûT ųBlnY ĐāNN]ŨĐ#úvu~oÄŽtû5ãūL4ZôēmKāGý>úÐޙ–›^ÜËŊŽČ Y8{Óą‹%åUzANFQ™Û89ķsttéŌÁūüÎ%]ŧOæMüĻc·_ /ŧU!3PÃM>ČŠ/-û%dąwÄYMĄRŨĻoÓŲ#6zõfïÔRģå^,ī˒$-,mímÛ:8đtęāD LØd;'ÛķšļÚŲīƒYũ>ūÞõqsíĒĒ)1ũÂ)Méģ•ģūŲžŠ‘J›d˜ŽÓ‘%‰G=.Z”k +Û66.öí;ŲtęäęЖÃó+^tëäæþą‡ĮĀ>Ö ߎuðü|[؂{ũģ·#5z―•“]ûŽ6:wąĄĩ7šŠēĖųfq΋jIĶ I#đ ZŧmĨGŸNæ4Đ·ī™9 gßŊýĶ5ō—‹5Šlm;78ú“^Õ,Ģ")N‘í{ýãÓ>VógL?ŸKRâÝK_•įŽž=+áV~ié+Ãke/Š,wėųþGžzw2.kū˜>ðæŊiyŲé˅Đ^}mãņ•ßûnNĻįi^xm EĒWĮC4ĻŨY3.{ûšy‹WįŨð’DĻĖÚÓđÃ;ï8ØõĢbiCvæ]ąĸŽĄ=:ô4íˏíOf<$iÃāŲ[7ų øhÐÖķĻ-aĨ+w8…Ŧ8ŋóĖm[ŨQ_z ŦH؟\äôqÏũhäķ`ĖÚtusū°cýŠONčegÁčKã7,™õó ’5̉įŲwú†­\ęéæøīļčĢĐũpîį5Ĩïy―5 T_ĻU8Pūc„$!•>HˆHä{€ŋē‚ËOåŠH Ø!Rā‹H‘ÛWHTOĸÁ2)Ž0•hAųEbáΆHƒN°˜a$ ļp’:€Ŧ,hþeš€°ëĨ@ ‹áÝh ÝB1Ą6dŋ*œÍSAԉAã8|kąņÎÐĶ·HĖˆˆ@vbH ŒŪˆîˆí 7ĄbąlÂ@ƒ JļžB2m™ƒíq Œ§$„AōÕz äþE |ã_GZVÝ―ĢËÉãgŪÖqƐžĨīšZ-ĸÚwˆē˜ī•ucÅҝą!z/hy ·9sŋxvjŲĄ+Ï9Ž#ߔúĐX‚aÉĒ[Đ?fÕLïafÆYé_æ4?~TgįbO+A[ÓH-hŅðŅæjGŨáŅۏf\ĘJōkŊ"Z1JŌxƒ(ŅaíôŽRYZŅ` ˜ĮŽÚš[Ŋ,Öv.Œ…ëüč}‰nßÚōū―9!ÖĶ9ĸŪëûu•åYų-݁Ãĩzže†z-K#ˆÆ%™ ąq%…ĖäDT‡­Ð kŨĄ[ĮO6ÄíI9učė1KãïĀūģ6ßģ2K9/0*5§Š{v3õQ~·žï2”X]ŲĻÞøŠe^ķéÕÏËkēŨĻ!ö–Œ,*–K„,d‰€YY0ž…ÛÆ`čéþõæ]ŋ\ļ™ĩlrEÔī9-Éx1'ÉJMĢ– ˆŠg…ŽYïvĪ +Ī —Yieð8ëî?ė=09éŸÓOlۛ9ũpŒŲyæfö…Ÿ·!áČփ{ 4éģÏFyö7c9ũQ#Ŧž%/ w˜ÐÓē,ô{ßÏï#–ļYšą4‡æŋV€ :š"ž=yÞØh07ü} n›6EęhŊ"X‚@ &^T(Ž’AϓæŽUV͕tĖ CĀ*ĸQëOžë3Վ$ĨƒÚwóœ4Þî— [’%îޙRmЧïM|ŅõrÎĨßš-ũyP­'eAgā%…zŨÕ%-eï΄4ECxŠČ„ų;ÚžpûÁPēV'Cũ :­AûŒŸÛËņųÖö$'í=˜|A3ߊ(p]ÂÖųšem―2tëæČ9s— ýŨ,ųÜĢ―‹‹!ũjLphnĨþĩ”pĸÜ?ĸ 5kV­;Ũ$Š:­;Ąču’^PÚtčŽÏ―š)(üQu›ÅÓf6§ÜþSÂūŸķ^|ð’$Y―V §ØTšĶPߍŅk·fŽþfV;†īZ ƒ§"Û,tÃó ŦŨý˜qó‘ÚÁՆģģxÁÕĻØøĪý{·ÏŌ›„W(;mHý%6 (Āo•ßŪģyízŒleļr\:uˆ"0vvŊĶN>]hĻ9wúh―@ÆĶȒ…}ÏķNŪņũL|Y^K’Ž­ƒmuþ„ÄħMõ—Ï}Z/švu>ĩ/nßɛ­ÖëD―ýtÉŨÎ/“—Ū^ž4Ŋ}ÏyžïRÛ$ĀË&GÄ4āÅÆĮŸöåŽÔý]-:õīzđõhŨ)Ôuz…déŌk‰Ŧ‚Õ;ŲdŒŒyX%óŲYŋî?–v―āUÂ?/Öč ãh )”P<.ïũ_ŋeŦväŠ5;šķmĀ6” íQžëZ tœÛũžþðųŒŧ|ËŠÖdzļų{Å7úO_|ÓQŊØfšĮÔ*tGņ-šģųûÕ͚æë( Q2ôuáv:.ąĄĖV7Š?œÎĪr]VęËģgcoû ü§ūųdū@rđūÚ1‰|ļĄ•ŧîŲ@õģÃī[ktŽķ’(jiŠ7Ėí– ĀũÐ;—ūEϐîG›―I Ü7X†EaîcĪčø“ÅQųÏyÉʎŸļ–ūS–ŨĒāâöxĸâõŦËōâåoŋĸņë//ĸúÅĮŠPš^ Ķ|7įZŨKGÕ4Û°ƒ“Iâm–Ã|7û@7óƒHËŪCããŲÂ~ģz+i­8ŽuÐ&q9-a dęüįÚ;]ZZ}túäŲéuIÛqN[ܞÃ[aáÛHŠrëóWīÐ}xöüÐVŠš?ŸN™‹#ŠV…HßđÞ?ÅxŅîÐA ­Ųj·š}ŒÚp˜|úðfĐRĖŽn@vÓI&?ŧ̊Ud‡IšûŪ Œ`”Y%[ŋĸՓûËŧÛNöoø°ĘjîãG_:@löÃýƒjˆž Ēü kŠYŒoo^Ŋę(}þíwĐÁÓæąe(Íđƒ"ðlýŸNe ―étšy― _Ė'‡c(3ŦÄI`PåAq<ŋ• ĐŪB―íĮŲŅlŪIWípōÍ UR]ŒƒĪð-SĻPĀJ&iO ØĢ“_?šCpK’ëqƒŲ{(MÓŦ<ė.ïûýõô>Ģîž}fFiīŒ„Œ$„’ˆcÂą’!Įņ9‚mqlCã;†„ˆY >Š@h ĢYzFĢéYzÖÞŧšzĐŠĸ{ßũޛŊïýŦU§{Z#r<>>ĐïQOņÕ_Ë_qÎSũŧïģÜzéæ)ü{-..ĀPNþJôĮãĮÃÚwĸúOüøŋþ>‘s6°å”R"2 ‰ÔSŋž\L5šo›Ï­ŪyfŨuų7Š[ÍyĒk­ΌÚJ "ÏīÍq–f2°æšĒėŲWbę6™jó­Åŋũýėŧ?úҟþ™ŋsæŒkž}đņôÓûĶŨ]wíŨYNNœšœlžDŪýŽĪÉÔjßÔōÚĨÜđ*ĀĪąœS+―M&‹ŊÄđË •ūTóKōĮZĐ §ýĻÁWŸâÜŨšô}ĩuŠóI—ÍĪô8Mr:ļë2ÆĪÖÎj+MâËkéSGÖŨ†þMâæ?ĄīŌäinģ^ódĒu& ņōį Y…uð ™­œ<öÅ?ýÝ?øôņĸė'~ô—oĀZzQĨŪKsH)šý|X&Ó,ĩ4nŌÆWAę&ņéRKU˜tÜjĢÎ^úký‘ũþėĸųÝ·ïSWÆ<h<z0H™ ōīËÎĶ­”æaó9ĮKÐÖû#ė&B˜CęŽ įIfëgåÜW™ú·F(}IóßÉŲ'e€€j?SōĸŨØÚ#eþˆi+ &úū€óˆfŪ.þKkÂn:‘~&kˆ_;õģ>>j­ÔĶ€4éÜŪÏļ†Zz äŊQE‘AúŠĐëīÄũÄÉĪCD3eąģh-Uôß[9ų“O>efŨ\sU)õßÕ·"ĸōĸÅĶM›ˆÖæY Ŋ*ŠīœsŠRÁ œ|›xɍ'†Š sýĪÆüÐ,9J-͆q#oū•G™óŽW@Ū­_cäÄLcēf"P51Íū&įÎ{t˜ ŽÝÂðĶDRîDÚ\Ą•së{3 4€<óKšŪóÜGAĩĀ\íĀQ”kĘ9ĮN€‘˜#ŪWæI4*–Ē2~Ėgw8ĀIE= 2Ïr$g–S§Nũ‡?ō3įg_j_}ŒˆÍûüpÂ^ĩ'ŲóO―ļõęëķOĮ˜ĄWĸARíÅwĩÁ`s‹jė')†gÁŧ^âX)ø+!aõxï8[š•>žIjŌTRÎ>IUi7ėqĈÚĪô%lWæ[FHūC@Ā”3S25UŸš•RkkAëĶî"cjΐXMęÜ[Á~8ŌĪ į$­Ã~Q5WsYh$æ―bč[[)­ēŊ{įB1D°đķ&”đfkA3!óĻ3 ;ĢJL1”艓C§yãŊü50"ÔÖnÆy5ŸĶŨÝúÚ#Ï“―0šoS.Ĩ"‚ïak‘zNĻT[Ë9wđsmĨ”‚$C8Ĩ2 Ōó=% ð21õ–<"ÝĒD­6ņō˜Ē―YhfĐ­ŪŠ #1p_* 0'iž°–8õ}o`žõĒj]ÎÅŊSĘ ÖĪVĐq5[]E_ûv]Ũüä*eŊuĻBœđ‰˜‰[8–!)ēqį’Žė*ąâDĖ(áHŽ—í“ēÉZlŪ]#QMŒ;ösŧÖå\ĶĘb3–D” FlØüŊþˆ‘jĀåŪ Č óQÔĪ‘·zŧLėg]cāRÜĩ„īI—c@5öŠóHŸĨ”ú~F@yš°{ÏžĻ“ ߁šĒ­Õ)†9B^ĀehØ<: ÖÎS8ßϗĪU―ðÜ1·ušïvķ:[Å7ÆäŲ1ąƒHuđ-­Ŋņ•š‰ÏĘävåCˆ#D@1bãaĪÚä\ÖŠæĖ‘/3w z§ÚÜíîq0Ās]}l%æ:?“&Įlv€"gĪ­[·~Ũ‡?zįo–Šr1…>^ė]‡ųcxîĢųī”ŌSO=õ‹ĸãÏ<ðbęräø* šÂ* ĄHkLjØq')Ĩøđ}ĒÏâÞbęĶšF ČŦÉj•Éīģ~5 :qƒš·ĒÄéYīÅÞƒÜÆ#FlDŒTë9ߑ}%*h0_𩠈ŌŨ‰"S-…æ-ß-&MCXK_ôLœüė^›FD€ÜúšÛ†#ļGyøCúP)åÕVi,,,|Ë·~ÛoýæoHmĩ5&ō’ˆ6—?$j.ýâhE‹-Šx ĢkđšŠäĔ’ĖÕČ9EŲYžĻ윘ĒųŅc|SŪ­3ĻZ8)úÏ0ŌHFŒØxĐÖ(ŠTĀæ<å§RĘSm-TĒ(ŌČï™ žþË ļÕӊܧJéÕ#ĩØ)W˜šŧũún|ÃÞðS?õSW]uÕÍ7ßÜZ{ĩŲöũūó‰Ŋ<~ßį> \~ŠĶĄ^(ĩ†Q*ÄjáyS@ßÄĘ$O<ļ Јŧnþsâ~6‹SCôė( J‘ãåšÞÎķ~ĒĶŲE ójßĩĻ씨 <#Fl@Œ „”boāƒÉ9‚ˆӐ^yb!r"u˜aÎĐßð&ŽžÁˆĀcfŸ )ĨyzáķíÛ/ŋâō›nū9įüËŋüËĸøĮŊžōĘW[Û4<éũ}ė?9zäčģÏ<Ūį%ΜSõ8…Äóŧû°HQdĘt“‰Ļ ;Zq“XJˆ$1ü2EĀypŪyŋyDJƒÁŋÛ<Á… ~Ļâ"„1bÄ<ģų īļ–ð‚Åđ‰ýļ9%!ÂđĀÓĻ&ôz!L}ßŊ…YļSÖŊ[mގƒ—^öšaK‹Ũ^{í'>ņ‰ŸüɟÜđs§™―Z"Įm·ÝķyóæmÛ·ëžIsÍ,„pø\ 9"ĩÚl2@é §0āúրbĢâ“/ "ÖÐHD@măuswYJs0:@―>Ąë&‘ï5Îī#FŠuúÔÐrG—“Ee sŸU_ ĮŽ*óÅÅ<ëôÚĐjhøÃJŦĒs“ØøRv‡į­ĩķ°“į:Ē"y”š_ÁÚ<•&•ūDŸBv“ŪĮõē/v+;|øÕs=fęŧlëKaBïÃ& į {ïūL0bÄFÄ8Պä”Ĩ ˜<]_™x-?‡VRžÏ† ÆÞGũāI§Ī”ģ:\ŽJf6liO:uré,"ŌðÕÓĨãZøáŽ;Ž: 6@sîæý4œÔū˜éĪ›ˆį|Gņ81•ZL4u]mÕĀR"fēģPæD ˆĻÞĒžŧΙ―šúĒVŒ0uÄϟ ûœ!"E†úˆ#6Ē…ÁÏū€P ]ļslÍ)+^§Ņ–˜KkÁhļÖâ…SSQN$ÂúÕåAß:PÞm·Ý>ðėþýûŸþųP’―zT-dCzK?[]>sڗĪŲ5jÕ=pėUë&“8ýs ĻĐ6a·ņFB3Ŋ•kÖíåŲĖJßĮ’ŨwÖĨ‰ú•UD ĶÄŲCČ,$ÍĖ ‘Đ8bĈ š@PõØÃU.3šJĢíĩÖæ:%lĩĐ4öhŦ‘2Ĩ8@Äļ;m.—Jސ;/ŧėō+Ŋļöšk;6Píd2!"xupŪ|ûŽíG’ÖšnR[CBÎ9Ïf=ŪÔšÓ,F™ ˜LĶąīú2Ÿ[s"ÆŌũLˆ(ĩļ‡"j+ ÍĪ!!'NœJ)˜ŧ,M q"7È#՚ybb§Vp“˜3ũķfSŦ"ČāĶXSī(SëŌ ûū XŽxCŅh71ŋÏŊ}í­Ûķn6§ûöíÞęÚWuĪGÆÔššžŒˆĨ/þāLžeCÉĮRQ!Wρ™ ā≙v^EaĢ,―ĐGt%bęg=0äÔE™˜‰ņ$‰Ģó„šŌ 1 ĩ€ZôĨ­)€‹5 FŒąņ, fČÄ5šg˜đHŊb]ĘÔĒ€šóDD[qŪRĀ― @PkÅω…8a·HYôpĘ]ũÚ[_7XÅ>48ļ†ģ)"zUĩĖÜ1GķŽ8Ý#ąW…Ïe[„PkÓÎs#ÃŒ„­4dĖy^ˆkc2óÞhY'ÄŪ›ŧË Oē75€G2’‰4‘Îŋ°ũž1æŽó.ČÁ<ĸlĈϐ7‘ė/N!áĒŽyîxõÕðV§T[ Ř•ūĪ”€ Ŧ—VĨÄĩUBTQM§ ƒœVUNŸ>}āĻó‚W!ą ąÁÖ-›—Ï,›i7 4Qsž *pšš8 XŦ~w@ kmˆčŽM įžāV―h2{ ŧA$FÖâ͒LHÔ\7›s"_btŲ=ÁĨS"B‘f0bĈ ļ@hî[USßĪĖčAY”8…]KRYâД yØŒ“—ŌģŊ2Ŋ―áúÁķššzōäÉaWv‰WqŠulŲēåøącÖuˆ+[=ßīEÅlœþđ_Ö –J.ČBÂRzŸÐ\Ãŧ‚Å6w:ņī‡pÁÖū5NŲ•p‚Dg™]LZuũ‚KßĀ%J\[!ôž›#6"FÂĶÄɋ 9 ’aE÷šRfšĄĖ"Fi˜giĄ šÍđĖ}‚Ģūï iÐlÛķMDöîÝ á/Ÿâ  4Re€Čĸ<ŅąCŌö_Þë’,pŸR"n2 %Ôóŋ,æY1%/@‹8 ŒjŸČē‰>J5X˜NEĩ5É9Â―jĪŲ‚ZíKâ6Āãx˜:æáÐüŧĩŠ@‘hc0bÄÆÃHĩÁ⹁)ÍËļÐ9Øt0qˆm0þI- Ā”üŪđ@r[ŠĻzŽ8ĮĄĸ–m[ũėđ<įÜũýÃ?|ĄöĀĖĻ€―”zŌfS[ØM[ķ 6°å”ŲNģ5pēō·cÞZ+8sŋš*­å܉TÐyRWm%ōbšø7ĖŲ%ŒŽŒ€fþ )EŽÅ2Ũūs‰‡Ęxƌđl8Ú'UĀw؀Ķkđh­Ũ9hōxF"vĘFwĩ#F@+­Ë™sĀZ !ĶInĨĻG_‡C4ę+K: 4ÎQfƒ):nûYΉÐ^ģkÏîžģÖúÜsÏ †ðþ‚Ãy pßÂŌâtņÏ.ymwóSūŒĨCāЧY—‰OŸd<Åī”āë ēšömHØkŪÂgqņXâÜ4 x‰J_ˆ8wÉTųÖFîxãI*}oæ‡{Ö/#Šuī&Ïî20ąČ^ëĀÞû$>ôÆî_Â>·Š#į„číŋ›rÖeõ^#FŠõ ŽīVƒE―“Æržį°0€ap랃Ô4ŒX"RJM‰)e_2`t8îÚ―û†nĩÏ<óĖđí9"`ßæÃÏn>hŠŧoÝtë―[ž―tæ3,›ílpρ šzÝļ5Č'2―0ŗ2œ"Ž„ī7X6ŠÔŠ\zÍĨGðˆ@ô, ãž—)Ž_:4Qčc‚}))‘gĮĻŠŪ)‡)ÃÅÂ,LJŠ1s‹‡63ðøE/žSvŠö|péÂĶÜ* 3l@Œ1RmôZĻjBÃï{Č$ŌĀeÏrŲ°Õfņ9đŦĨ;G–ķÅFąĖúĄĻ9RŽ9âj§$kf úL^Þŋép2Č[óÕwmɀ*āpLj_Í{ÃĄmîËuÅR|*Ņ™'1•v§§“äÕYYÆČĻ`M[JÜu š7N"ÎûÁŒ™K_8Buš y|œEĻ,@U%bš{Ќå.Įëi]îЙ0`"n­ŠhbĖ9KmŠÆLvnįëCīÁFÈ#Õ:tXd F^Œį æ™Ų|€S 5Ŧ­ēĢĩjĶ:é&Ņq‹fVfģÁ$vĮoFÚŲl6Pm(^#Ÿ%TŦû7`Ŧ°íĩ ŧķōŽÂ+Áüs”HŨVÛÅķ7ļÆÝ`$åČâ3;ÞžÐNNāô‡ Ïēˆõļīeōķā”j‹CåœĢĮɞU|:‹-19ņ 9NōÄ@=ÂĒĪ'†wfrAō\ÔëĐáqð(͆°!1bÄØ-fĶ`v.ÎĘĮY–ĩĨ.˜ˆ™jîR­UÕr—™8z "ôŦ/=RŒ†óí;v^~ųåf6ðėŅĢGĢ ŒˆÂæpW1ÍÐČPŊžnZþ?Á™ÁĄķÝšŲÝķ 4AkgTũÉĘÞūÜWgeŅæÉ ‚D‘ –\ËÍļq”WJ!ŨiD(ļˆˆą–đ?­–ę3;ÅPý !ó?W"e…ˆ#Æc1‘°QU8Ä~V#q‹Ŝæ^BŨœŠqʄóHÖäaÅũžÝdzóÍ·,lZPÕ!/qyyy°˜YLĩhpkōóLF3øw445Āăū ó†Ŧ™næåû+0ķR}’ÐO=:2ų:ĖcŅ ŒĶ†ū… Ķs‘ūŅ݋>ž{Z"ÖI`ėÏ šsĘđ3'k#FŒøĸ/.&štQņđ53“øŌԙĒ8™\œÐĒØĶ5ABt‚nLœSį%äjljSîō­·Ý6X áÁ ?蹎™É„ÛÔ,VÅ Ŋ ëĮŊ66üEaþeqĄ€\\ƒRM­”ŒįRÁ|‡ĒŠ]—Eü@ĖŧxK)Ķ6™L‰Č_Ŧ"PS }ņ<†Ņ,Ö/†ā_—5Tbfē† ˆ#FŠĨ”T›ļ•C?ÛMōœ§Ā˜“ĐÖR―†ÁϔD<Į+Kk>šÂšæßâ 7-\rË-Ŋ9ëĮ)%t„cÂėë―võ+ΠïÏĖĪ7“Ēýē,Wkð˜j)EÄ܎KqLŨM'€Ë՜sDôÆĘĩķJa P_'ŽGŊƒLāUÁ&ĘĖĩTĶÄĖHPĘ<čËL<ęW'ÓЁŧę6 FŒĐVˆæŪã”J­ęŠĸųXGMšKũÁ l@ōÕcéûĩ nRQül·N]yÕUW\qŰ7˜ÍfÃ`›R:7Йãë‰mE'ņ—žY<öâ–ŧ6}āCŧūĸcWþāGŪøØ_šėý;ÓöU}!áåa>~2yōCœõ™Š'é$.}蓼Hέņģa+<Ā"큙TīĨœ)q­ūdH‰ÂëÆ1ût&)'opiĶÂi Ē†ÄąX°ģ€ˆS3t‡•‰ĖËĂР_ĸ†;‡^Ŋ!ũ`čķi­åœŨi ū$†ƒ‡gÏ>īōö[ūũ§îųūŧŪđÖáų•§?süO>qäũ—Ģ3˰Šf†bŌĄ—įaõEQ—Āœ€æ2,ˆN0ōQ—°ÔÂȈām=3RH}ų M˜3€Õ&h.Bč?€ōë!>IEÍ―Ā4Š―6&FŒSmDe—ÕUM9{ÆkUĩŪ›šAmÜŸ j dbĖTk5ĩŪëRbÓĶĶ䂰ÖDMwėÜą{ũž8ĸyōÉ'ŨīëŨ”_ÄxôPĸāŋ9ųßŋëø­ïþÉõ<ļfӍßwõ_ųë7ĸíË'{ŠÕcðĄ/ëũÞöïüŋĸŨ;ãķÍw-į­m‰8xVÕ‡t· 3́Š1ģv!ųïĖZ­hČîēĩđ֌DŨ*Ų ý“ýW(Éķö_ģð:›šĪ”‰Đ•‚°á0bÄHĩv/ðfōR%11‘ĻƔc]óėÄXÅŠ'.šŠ"xށŠqb"Üūãē[^ûÚÁ!6h†21f&ĮšuíŨļēūŨ‡?}ä[Þô=?üŽïž2ÁNŪÎ/Ÿ‚5ÜūõMĸÕõĸÝVÞ1i6[|réûnzŨ5›Ūšá’[/í.SÓóķ &ŪåúŠ—AĄë:'_IL`ÖZ›Ŧĩb'ë \mq>!^*} cBb’æí þc$ÂœēŠšŠŋ`SŅ ę1bœjEЊĒ)ī:ũ†™ZóÓöNC>EDĩÕÖZJ‰LĀ(ZMÍ`ũîÝ7Ýt“ˆD-nWƒjþÓāÅЉéĐO\!ŨüĘô_^ Öðøé‡~äáúĀ?þΟøíŸ]iwïxįw}ĮŠÎqéTĐ+›ođîvøšrƒJ#Ũī&1wq)Õcw°ïR7ÔÚ"Ųևw@ĸėäü‹ņęÄ$\uŠ óŲ–K)ĩ6 Î)GšíØ-ķ1bĪZvӎ(ę^$fPôN FåąŽ*âŒŦŠD ™)4ŧ2ŨLoŧývfÚŦ˜ˆÐ` čxŲ5]‘žœÝóĶũ\ŧãrXÃR]ü‡ûþ°>:―åØ/üņ/ýęg~GĖĀņÁ=ūbšËHūüôŅ=;ö\~Ų•ā“fí<ÂEP1ÔV›‹(:/sgOTm)'vŸB?+6/!7M>ęĮ_pGœsI˜2\fS‰uœGØx‚hÁ†Ãˆ#Õz  h“)‡œ@ĒĶÐûÍ\áä”]îÂþofþQĐĩŪéOUDķíØ~ĮŊ4^Ąô ?.­čåó‰`éHÉtÉ-7― ÖaïĐūtęÁKø’Í—nÞ}ĮÎŋųĮĸėāō8vOöž9―ĸé}ŦßüšũýÐ;ūëš-—c[Þķ-m5ųę<ëÂīŠôĩ€ bŋÚĮ<•ėÄ>"-šL ĖBĶó,’ĐÍ_Ql{ŧ.‰ 22QĘÉ+#…ŽĨ ÂFÈ#Õ"˜Íģ šŪ“&ĩßPāˆ9e5óųƒg}žÍÎY–rJ)›CU_ģkŨ ôšÍfC9îââbJé<ž·x-?1–Cý|ÉĮnđÖásĮþxoRģÄļóŌ ,ūxxé08yóĘ OÜGŋø­?ũ·ūëŋ―$u⸁Ŧĸ‹_|ý?ųđ;~õÆÍŊ;ąh6ŋŧïšČ:ð,„N6žj6/'o­†y7äˆQgŌ‘RÎÞŨā†ĩ֚9JĐhā·‘éåJ2dUwën8Œ1Š―ÂÂ,fhāvÛūr—"“ží†(Α,žÕ‘™X―蛉‡ŽØëŊŋąĩöĀėßŋ‘!X8H§ë:2č Őy ?^/ë6ßļn{``û ^›H°uī.[>kØķ}7O.Ų”ŽÃÎnŨðķįq>†‘ö J‘ēFL„›RÕŲę*§4ÉSg…îŧ…ČüVw+ !2†y,åÃq8}kĐjŠ91ĒÅ7ÁųōÁTÆžÚ ŠĢŪÖóe’ ·ĸûĩËø!RTˆ(čēï %fô…ƒĄĩ@ĻÁÜû°kũžg9m”›CqĄŠĻÐYš0NNÍtiđíūþ6X‡^gÕ*ÆXJS O?ð~˜ãÆKwÝxõö_{øo―þî·ïđGV›čķnŦŠ€Ã%ŋ˜ŧŪų>ĨZ+DžlU!ǜŠÏRΘxicļ(‘Šw wÝ Þwé/3ü ą… >‹>ė9§Ä°!1bÄØ˜›ÜúŊ€S›đnŸsŪĨ! Š·ķ˜ )™ëĨ|æ(‰ōš™ūΜ9žtōd„ ާÚZkßũ‘ĐhUNä3𠈰H ―j/w^u ŽC“ūęZÆĒeĶ'Ã^·sŨoÞōãĸûýïþŅ·øo€ã7^üGŸ_üėÖnûR;4åé|Š(ĩiN‰˜D4ķČåŒĖ,ĩĐÕ°x@-ļZkk`Ķ}ߘˆxŽ@1ÛJ Ëē†Ūc-%ÎϜ™5؈1b Qôƒ#Č^1 óŽ™ĪŪNJzƒFóÞ-öyÖĢ:W0qé !ŠČÉK;.ŧlļ GĮđ큈īÖæü{Ūũü|ybUĻúúmŧašU59LáĨ•S°†)ošæ)˜,Ž#ē3ķxĪ=·Ī‡2fB‚u˜a[/Ģôæ4ƒÔu"Ē čÃoll=,ûūģÉtbŠĨoČKC$ĸΰBΜ(ą6ECœWðV3ȉ4iŠj°1bÄ î)Ø9esm,31&ϟĨœ’Û]ĒGÍķ9{ŅŽŊn[7éZÏ €ÚÚââŅ=W\QKY/í ŨC\Ėčbgt MlĮĶͰ Ķ`ëTąˆĮ[%Čó’É50pÆnBXƒ­ý<Ým –hU‹ŠMr'ZՉ󎙉iė=Ŋ+ŌúRÉ „#8SŦ4DDôčp#ö~H0š7Š™z­C—2l@Œ1îj}Å ‘Ņ%b]—Jé)Æ@*ʞDŦb Š@„Ļ~Ú>Y˜dî|;ĐÞÛHÃrāĖé3ĩÖ8Ę_ÏķëAä“ǁĸ U€ų[5ļ$OŨWŽŦЀázJFh­Ā:2|=6^äӗžxėa-Ô&]`1rz·˜Ļ7;P­-QÂäŧbÕØ€ĸžÄhæŌ·Ļ,ËYÍ<:=i“ĶÍ â“[ŦÃEŠEA`bĈҘKLķĶúJ‰jk>8!‹īȓõ Ŋ1Ž}mĩķá<\EįyW­ĶœÎœ9―ššrž7,ؖþú?@1˜ĸsķDX)ý9žŊĶ—ûđá•q>ýęž! Í,âš ŅsÁąÕĶM9%A1ÐPž‰jī7"@?ëÅ4Í;cWËæJ]rõZ+ĩyåĨŠú>Á’—ģ™Ó|5,M`ãaĈQW‹‘cDÅbHMqJОĮÛÔ<5\c,õ–o ŧÔlĩWčûY)å|o˜ƒĖä‚(fÍŽYí­Îīö*3•f`vjå ˜‰á|“Õ&bX15Žm„Ņb+l@Ÿ[WW{r+œŠQ—šh\O9uÓΈ™čž9ÍæŠÄ‹Į}ã`R)Ė#zÃĪ:ųjÛGN^ĩ&ÍZ‹jH†ˆ#ÆÆ\ģÄ){X-x:ļ/ ˆ<*0’ÍLŠ0sNđø66ųIڕW]͔Nž<1›­ĩ+gÎlÝšm―E!č8tĐF„ ž[gŠÎ‡Ę&UĖðéc‡Ž‰€FĮ #âšxoĩKóÂđÉŨŽUĐ`†á5Hœ@bj61Øéw:]ļíõŊ_Yö§ÄéJ-ŌĒ}üė Ē·ĩižPûÝdöNÉõģpiáŊ+ĨaîrŦÍ<óŽËY Z­HļqÅ^#FŒđŪ™í,灉Ïđ<€ĻUogHî­RIÄ蹁āP5iíÞü–äĢĮáųį^|ņEU+ĩ‰āę GTíĒÃ ą˜ŊfA`ķ""@ qĩ|xpåķÖ..†Î›K'Ô˃ÁQȊŧÓÎŽJR5FPŊ1;þüūþ4đŒ*c‡Ó„iJÁL뚭—ÆŦ­;sdeõ4T(ģ2[^ö–huĩŪÎÔX=Ā@PKmUezÉĶmC@‚[ݚīZk)Ĩ ð°a0?uréÉ}û}äĄâs.īZbt%ĪVkáCÂ%đˈž… Þ‚ã•ĩT°h”Ā˜ĢaĈSW­ÚŪ~­ĶšĩÕļ)i"Ę)ô§ÂœÐ,ūĸÂó_þĘWžynĸ‰Ó'éôĐRŅ`yĩ‘1( ŲĶŧÄËG^xþČÁ;væœÜū•·ä-6·9ĖŠÝ|é­ĩÁŅfmĸąýG–ĄŅęōĘáĮNŽžZMõÔéá―ÖģÂüŲēJą U5b_Ô` )ĨŪë`čØģgÏĘĘĘSO>ą}ûŽK6oî&†ÝÃtøÐ—^|ô‘GšI—˜{7æ2'3Wk°ĄßĻ ŸãIáœSQ„‡#FŠElĒ1Ϛ •šÜ™Y+ÍĀō$ĢĄœË^AÅRdf‡ÎĸäГ=ķũÎ7ūq0ã†[aāĐØÕēĢëΒÕM7Þtûm·3s)ý‘3KŸ=ēïOŸ|ðéGþlą?ū"ýQZ€>đīōéý{?0}ËjNūGÎŊŧäŽÏŸøâ%Ėb°ēŠ”Ķ;ķöĨœ^>ģš<ÛėųS'—aÖNŸ>upņčRfK*GϜ>~fuĘÖĄŪaõˆƒž§sAĖeÁéAļDī{ũŪoųĀ§Žœ39† ýþĘŊ„kĄ/=!§ ‹Šī–rN“Ηđ R—Ýē‰˜âŽ}Š&† ˆ#ÆĐ6œþq†ÓuųÖįŲyĄgfCkMšxœ+·ŌÐIĘT[ßÔÚģO=uüøąĄüB!mÄđÖZÁáŪ|éæ-?pĮ{~ėÝĸņsK‡þāËŋûį‡úÜsũ[9eÝ.ÐR]ųô3}ãÕ·Sâ.wÓ<―sû[ņÅ_Ā"vâŒčÂέ [—WVO--:ųÄą§—Î,§­ŧŪžėŠ”ÓfÞī)OßuÅÛŊđtÏ4-LĻ˜2rGymŋM_ŋÐMšÜåt9gf2UÕš­ĩâüÄáŧï Ÿō‰Į'“NEŅíšjÚjãDņâD”™įÖŠŠ0&Šņ' !ģG.Œ1bãíjÜ8e™“šÕZČÉWÕ\øEÉÍļfĀ) Snëļ3€Ō*3u<=vėčÞ―{Ŋđæšyá:Äŧį=2°ä0ÎjõåWüț~hĨ­ė_zîũýÝß|ô_œšŠķŲóÏė=üÆũSÎÝĪ›ÜīéÖwėļũs'?Ŧ|čąã?ôķïŲĩ°} ũ#KĮ_:qāSŋ -ýĢŋōģžņ­ÄO.ßŧíŧT$,`îęōîŊÞf‘zÓũý0}GNž]ݰNÞ`qŽ7œû=ōČÃģŲ €IÓŪKjÖDØ|īUD NĒM<Œ·&ĩīœ5—ĮÁˆ#6äŪVÁ Ë“ŌŠIKÞÜ­æwÁ™”Y!Æč#ˆ<ƒœģģ™ē;MgĨW‘§ŸÜwâÄâk^ó3[ϰë/ÖŋK@ÃwÖÏúŌ·&7lđþ'ÞņcˆÝÏîW·^1ýâ“}îŲ/ŋorWĘiÓtš-mĸÞ+ð+§ŸûÜÏūũÚoþąoúOgËËGO_:yęūƒũ=ūøĖ―WÞýáŨ―óôâ铭šCÕB a:ApŽŋfæ·Ï ʉ‹ˆļÚŌūōØĢ­4"까áS ŽÎ A]žaĩĒŋŌÄ\|ž%&؈1bt‹‚ŧøU”‰=üŧĻGvÍSTĖPÁž‘ASN€(Šžū˜kõėN/<ĸüÓO? xŽ‹ÖÚl6sšÓ•~EîđōîKŽKÛ3Ĩå?üÂŋ<žx|a­ŽžUÜķõMëÆ_ųŧø•_ĸá_Ü“#‹ĮN<ý‰įĸôðgĻâ_þ†ï‡ŠĨUp·#Åáú'ë‹ýxŲG˜y˜ïĸÂįO<éU@EđˆØMŧĮ Ąj8‰˜M%"žęž(&ƒ‡#ÆĐ6k@4%úÃXÄz —ƒ#ŊĀŲÍ4%mi’øøąĢ_ÞŧũÎ;ïŽéÁqáÞ`ýz!Þ˜t8î/ĨĻjßĘ[Ŋ~ËÝŧnĸÔólūnëýO|ņ>yŲßxïĮķmÞ2é&)Ĩ[/―æÖËŪ9yōäĄGO,―pôđßÞĸ;û—^xįĩo~ũõï^>9?‹[ïbq|.o뜷âžÏ‰Ņúųũ‰'žØ·ï tâ4„PžŠ{íÔ8'õ_%J)ÕÚįD[[õϰŽ3-ĩ l4Œ1v‹ĐĻ”ę)hĩÅÍēÞôæÔ“S2õ›ÄĶL”dÖjM]fäZ‹™>öØ#Č9]lW{!ĸSmkmÓtÓgŸýĖ?øė/m™lyßÍß4ąlŋqásOüŦŋų‰ĸåąįžrnkĐģŌޓgNZ<ü…?ĸŋ=ýžxz"ų›ŪĮÔĶĩ•óĻüBÅ5žĖ#Ž—pĨíũņĉãȄ~„M— ý ]ŨEĒ ‡Õš†IrNásK‰ 6FŒĐ6üVāól˜ÄR8 hŊ툛ķŊķã€Ō Ũö#s^9ģü•Į/řh Ŋx―īīÔuÝī[8š|tiyé7ÝŧđÛڊpĶÝ7mzzéSíŸĸäĸôŊþéKĮĩR†óī“§O?|āĄ_ÝũOö|\ŧeÏGîüÐ@Á€sržØLýŠo_ö]fÞ·oߗÛ?°ÖJˆæyčå óīi~{@ĨmBÄQÄ]ŨЂG3Áˆ#6 Ū6ŽđjŦäzҜ=tFđÔ9%ŸÉ bĩ*MÁeĀZOĖōō™øów}ã7îÚĩKUŨ/ .6ނĮkõĩûõoãåw6iŊÝ}Ëm;oüĖŌ1åÕĶ—^vɉӇĸîïĸršôōĸæíß~üԉƒĮĩ3°ĐßtĶ?iM~ðžïŋfûuļppÎ;Ŋ3Į…cėđOž=qâÄýũÝ·īx"q’ÖÔŽë"Ų6ŒđÉLkv!Bil„[Šï ž‘!œf €°ą0bÄ8՚Ĩœį‡ãŽÖÄžŽSōam~ÎĢjĶāí82 úšŦũ'§U!ÂCėßĸ žlŽb`ýGį%ĩĨäœ'iđ ?ōΐՙVmENŸnÜexðņŽ?~äØŅÃĮŽ”e}ëÂ=oČ·Þšų†o}׉čÂ]ðyģęŨ^,\ė ‡-íWūühĘQšÜ9Ą‡N ⷁ^)å(_H‰sĘ*.ē.wĩų~fĢaĈ‘j#‰*Ęš9%9 %?kĩJkÃãHLK)ô #tÆ`>Š43Ė]7äz=ôāƒĩV\r\LŠĄCˆÕD_ûŧŪĸ†ÛũÜ^ûjUW{›4č&öØ#~ĸ“8|čĀ‘Ã'NžÜf;_—ïøÁŧŋĸŌéÎ&íÂekāâ˄W^,„ðāK_šĸôé“á戛ŨĖRîē7ؘĻrĒĻó‰ęĩ1ðšh‹ŨY[]›î FŒąĄQĘqÝĩ6UëšlāŠQƒ”RQģDĖ™}(“”3#G1R“†Œ b*úôū'ÕŨë_ĸz‰1óBÂyũ}“r˜ ķL.ųĀï{āũãɂĒ-›ėÜĩð û?þ‡ŋö‘;ÞÝÏfCWĐuóæKūýmß į ^öâÂkpŽW\Ļ=xęЧßûh)%đÂ+FY220unuÕūŠJJY Đ‡Ž‡žŨQ<Ž–hĢsGŒ§Z―NÎģŪ™SOĨęr2IÄíĶ™Sė Š!%NĒĒĒDsƒ<øŌpÏÝÚüpėeũōoßũĖï2ð=7|ÚHiVĩĖŽÍlûkö|ðþüoáđŸ_zņÅS/]qåŪ[·ÅTþēŽ‰øÎę .üī ?DDg–—?ĸđÏ.?Θ8'51PpÍ,x]šf0§.åä Ę94 ÉĮT5%ŽU l4Œ1R­™%ǐjđ‘ kĐôeˆԃĻÚD„ãKšļÚÉOØÁ8ycđЙQJŦģþ‘N“b^þšĪ>ØN&“Čĩékų†îzýUŊ+ģšķ&ģ™ÔŠ“Ý,þóS_ü7‡ĸäūĨÏ\Ãå*ģę+:âíŨŊ@ ǧžÜũøĢ{ŒŲ5[Ķ€LŠM5ÖēIZäų&N\ëĢŦëŨG^$Ä'˜)Œ1b#&{5e͜’Ļ–Ō31‚GÉ Qi֞Ķ€k’ŌȐÐ;đ™UU4įdîtxęĐ}_ųĘWŪšęŠ"\ĮŨޙšŲ` ëšNÛ·lĸā›ÞĸĨ'•bHÐР"’„+TßsĮŧŋãžï„bžq.ķR8ëW ëiw0 áóŸ?räpĘIZk–šŪĩ hÓiWje$?WhJÉ;!ššåŪ3S-ÍÍX[8…mĢ)FŒ§ZBtpĐ("ŧĐĄ5įmv<‹ˆ)3"ÄRčýZIDE„)Ik~éþÁÖÅĖx1\0ÞF):ÎŽ,ŋĸŪoÚķiŧŠZ3hq!ĶM3ō_ýķ)}9^c]°ëŋĸ+ņU?þø#=j+ž1‘Ú<œsέ Å (ūáLĄā~Ė`ęa49åV[“FČ)ĨņXlĈ˜ė•æ9^ŠŒ ŲК)š~6BÁSN  ĩ’·y›ßköS ?ý§hBŒãõŪëVV—ŋüčĢCųÂķmÛm=Ŋ]LĪæ;ÍėvÞnÞuÝŽ5fó]FĪlKmũÜöĶۇõBéŨŧoŨĨxðeØŊaá%ĒAxðŸßŋtvÂĩ6fĘ.ÕÄð•ūŠiNÉÝ Ô`î['HHÜZCĶ„ÔęÆla1bĪZWk‰hFĘ5"%ŋųŅÜ$æķ(*ÔĻÏ…Hqeâ8^7…Ä$ŌņØ‘ĢƒęëÆ›nZÏ­~}Ņx„3ôąyéĸč·ĸåÏÞĸIœėė*w-‘••þGüŊnßžm8ķ""s\ČĄÚ"ĩ+ŪŨ3ė…ƒð  xäá/h­FH)sßũþó3@ PNŋ:é'wr˜™&ö4SBÄ!ë9#B•Ķ0bĈ ļ@0ģhÁZ‹AÁœģjˆí1ÅĀ‹H^MXkĨÉ"X°gmĩÕfjDØüh(R|ð“KKqŌuža,Þ―Pi;'YGĐýÛn{û›_óŽ…#Ýôô$­Ī4ĢzŠÛÞüođ7žXņ ŋ~Âú§ūpo°nKûŲaĪõüodϜē{ĀÎ%…Đi889uM$""3XdĢĐõģĒbH #FŒTKH*"ML-îß]ZÞ0ô§aõû_NÜDJéÍ4ĨԚ8)›+Šš{Ũ€Líđgũ?üðÛdōcÜwĮšiaÓûï}O-EÕÄīŠrâwžå­[7oiŌ^–[/vqáôŠŽóÞ%â!—ö҇.}Aw·=Œäŋ ĸŲÉģœg“ˆúl >õƒ9&Ó.6Ũi€Įā"á\Â!Ū#iėӟþģĄqrmĘ0PīŪËĩunM‰JiņÃŦŧÐWÛŠ–eŨԊpJņ›ÎŽ"ĩÖQ0bÄF QŅZrâĖĶ‘Úy2i­…Ė€ÖÜ\€äÉÓÉ4ØŌ'ÐØB(ylvk 2'S{āþûž{îđŪë.ŠĻ]ĸÖûßx·/åî7žņÎ;n7°ÄŽh?ü―?pŞ˛īŊ‘Z°þ"úÚĢîú f~ėąGúŌ`Úå,ęņ:‰9ĪĮ >Ņb­ž#ƒ.ß0 ISÄRjĨÄŅđ`œØÅs€0sGŒØ b/sŽ S 'ią+ČÉģŧ,§ ‹@LĩųæĀ4åTû6Œü Åësē˜ÖV=2 ķašÅ‹ãž]ŠŠæœÁýÁÛķnû–w―gaš€`{.{Íwūĸ[‡ôØ ïýĸN0Į…Ņ 넇LÅãŠÞi)Mãį§áņ& < Ą5Åø‚wėh|Į.'bv‚šĢ=AýzÃaĈŅÂ*š\žŅÜąÔfh>ēAm•‘ršĻ‰[f‰r*Ĩ@rk2wę~*3ČĐ Ŋāŋðųo~ĸûŊžōĘÉ~EGCPm\„Ŋa ÚßþĢß{î…įŋũ;?rųŪÝŠząõëú•Â+jÎûī”ŌģÏ>û…Ï}&'$4CĀDIABøˆ“Î3šÄûƒ‰EŠ"į,ĩŠƒY•FHk…˜âO6†(ŽąAuĩ–<čϒļô“ÔYƒ˜īÕFˆFf`~ –eĒ=7†Ô)·H`^ëČLĶĒ ĶÖånÖũûŸyú~ĸũÞ~ï;Ŋŧöڝ;wÆ66hîe··Hz=ݟūĸų/ūãĶ{oŋųÖĖéĢßöĄœR_ "^œ^Ũ=âj^ĸH\Ŋĸ*fĪcŸųôŸ>u U™ ĄķĒ 9ž―n .Ą5ŋĢDŒIĪ… }ᐜ‰ÃBL.ŪņĖ0bĈĩ@@lŪ< J)ąhŦ1{ŠEpmî:jRl2ÉMÜ.E”į՘ÕpVz@âĖDÜT\1Ö5QC]>sęw~ë7ĸÞĮĸö?øĨ_üä'?yčðáÖĪë:"—Ã9Ė)/ÎNüýÏüÂÉÕĨ~ãûÞý–·ßtÝ })ąx]ðāEö[;ė„{ũCīW5ņV`&$öâqėrœkĶ“nâą;ŪNlŌZŦfâzŊFLČ(V;ā\*Â8ՎąAžTv6ë‘ÐcÝ#‹”s§ĶnĸæāwÅĨ/ŪŌ*ÆÉOĩMšŌNŌjĐCuų Ï?ũŲOýŲÕŨ^sÏÛÞqŨ]o°°°Ž ûC&uõķŦ>þŸĪəS§ÞûŪŋt^VËyģęŨÖÄx{ÞsÅē"–Ÿúä'ũ?õdtYĒŦßÔĨoāņfD@ÄÚĪEo™SĻ˜Gũz^"•VL-O:ôŔr((˜ļËyNĩ#FŒ-  Ļ"Q%æ4ŨRâÜ%0kĨ"@ˆ–§€âĐŪësU‰~-iUDР˝ó,œ…{XaaÓ&f>―|ęˏîý?þŲ?ý…Ÿû{?óÓ?ýGø‡Cíc­u2™Ņ…,ŲĨî–ŨžķõŌŊŪūëíũ–RÎãŲõ$ûu*bšfGÎy:^rÉ%=öØÜ_ZE$”8Îr4‘CĨ51rįb!ĶÜeŅfĖŲÕoÅ|ũ­ÕuDÉ?Ą‰{C6 FŒk ÉTc_ÉČk!2dj.H`›ouSΊf.ŨđŽ=BÐĮC‹„Ö* ˜ũķ Ä9S‹åÔĩ֞ÝĸôĸÛOüŌßĸųŋõ3?ýŋþëƒÓaŲ]ķĖ|nPį! -..ūï―ïŦĩ^čAøzŅF“1ÆķֆEÁ†sðāÁ!üûÁüė§?}øāÄžoPŦZ@K)č?ŋFg0!Ïë<‘Ąú‹ō§ čdó—bBĖ „Á „ÐÐ7 0bĈ ļ@@õ$„00%5k­"Bâ\ĨÅVaž—ĻÆLkUCgg‘†Šb€Œn93Ӝ2 īڐp!įy H„|üØŅ#‡?ōЗþųoĸ_wÝ}ũÝo~Ë]wÝuà 7ۊ;\‡/éûþŠ+Ūļ°ĒŨ`|õĸĻęāē˜ú„cļ.Ĩœ:đ4đ5ņƒū‰ŠĒ#1·Ú8&DšO “IŨšVĐ17ųęI`)=äŪmŅÕH!Ä0ÕŪëÔADœĻ–m78ríˆ4DŅųq{ŽhŅY›S2uæ` Sƒš1ųŠ å4‰ūBôSĢÜM Õ\áŠ1 ûœkÄI[k}5„”Á@˜ũĨ°Í}?{ðþ/>þčĢōoĸõ­·ÝþMïyïPPķÝĄŠĨ”v‡ĸåģ8ģītęÄââĄCŽ;6LĐŸŪ ŅgNÓëðķ֚R &FljË!-ęË\ŽÆ]—pž€>Ū!R$5–Rž―†ÕæņđËĨ/óˆt$mB”˜[ĐH”SÂÚ*vybjæ%7ÄŽŅ“chčBļ#Fl@ īÖRÎäT‘­Å‰kĐÍ$îDÉ<Þk$ąšũĄx b7™Vi`–8Ģ4Y‰pÅÚbą j­6fėšI­―ˆĨœ3óÜüšģZCōÜ'ũ=ąĸЧ>õ§rý7Þýæ{ĄÂņÅáĮ=<íęĘėĖĸËÞŋæČŽô0à ))œýîc3ĀŽdnOŲ!‰ƒeõ7{(ót‰‚+ís~0• ^þ?ĸŊŸŸŸYä~îŸ;ŦŪkeĶ›ŸCĸxž§Ŧ?ŸĸCjg†Œē2†"wßåî”āÂØV››‘ŧ6‰ÝŲO’Ī‘œ,ZX„ŅũÞNw·Yŋ€tģŽM˜ČņėėŪĩ–qĘ$þ^žxĐVĨî2›Ã1yÄĄÅ9õáĩŪėŌY€ļOņÁÉHœo›_ėˈEcUW—91ŠÝ!kûōðxöđϑŪĩ„’ÁÜf#!ęĸýĸųþ?þoĸũS…`4VVwōHÐ27ĪYetwŽĩ>WÕvw3·ðg?þTLß"}YVw—G8―U­&ūq\h˜ ™E!Âģ›ĒÔk­{?&Ō0Œ’8cöM [’š}…j‰íî5ïæNaį`î^žxņį2ōījŽJ—‡ ―AŸÏu˜ģHĘ YŲ†WŨČfÝĢšē*|™g‚ģĩ€ŅĨēšHšYeâûĩÚ*G#圭jsĢ!|­ë2(HáÖ] >Ÿþų|š Āįßí­C#u°Ū&‡\Ï3Ð,ŒV•ŪuíË=ä+é: ]Ų#tQŧL ‘UEib$yx6NoMŦ9nšóp#t8ŠðˆŪ.õéþtÕLÐĪgVuŸŨoÜĖ‹RėásZk­ė+Œ–™#-‰—ņ{žS@æV „‡g5’ÜŽ[‡ŽĒT{ïɁUŦÔg­y2Zf&čūŪ+2ũÎ}îæ•™Ó‘~}š{‚tíĪ―īþýá”Įī4iÜUįņĖZóGÕų<aq˜šęģ&ΊÞę–!s·ZÄHø šÍښá}î}ˆÛŸ―\q‘ŽîũDŨę„!\Ũ:žws[??ĸč ŊÝŋYh™ÕUŊ[ėŋŋؘ‹–šĨĶûΜŨŸkõ{œ8ŦÛH ‡ÔÝ<[Čý܀™sųÚϞ&X·UÝ܉ ŧYØéŸOUĐÛNÎKÖÆŧgmHæVŠŪóáY f<äŪhs'A˜‘ēŠ`ļï#)5ũĩūzĐët—e>ęŠōIĐiÖĨRŅ€óÅü·ĘJIŨúļđÔnŨ5#,í_ĖöîĐė-c-IģG5ģû4G1ûðËÝIÛđ'ķ‘ÄĖã0ėú~ãÎL3‘•Ā7ŧŦÕæëzö“€"Vu˜Ęĩ'k”i<$Žŋ†/^Š=äRF;2RšyĚpUPîgfÏ·xuVŦé6ø9čŊ“ģōđ>Ũú͉›SŌ°ķđM#Î!GÏŠqƞŸˆīÉÛđI-jå&Ý a­‹g \ÝæÖŠ<Ģ·ŦķšÃãÐčiģEÝđ \ëTU‡ Ũ0Ū™yŽ―ũ1ū•ėßÛUUC2#Z•#7FŠ_ū$íýļųȍGíāöŦĢŸÂϘåĪąŌ™…å™xW\CÜïŪöÏáÅŧ@ÐŲ{JøŽu`usÕMڔ mļuD6:ĸz@ã―oŠVU‚Ķk+wI°Y ü đ›ŲŨ°{ĘqũųĄ‡ÛĪvđÅ4wí\ĖįŲfę†(U\kú"I[îßīw§Ýų`Ž;ĨŽ[O"­›OW„ũ!âîrũĄxs_Ũ5ánGo€ëúÔSá+Â'F’4R;Ÿ>–e3vĩ[˜CÂ0ĩEd&ÁŨČ3ðâÅßÄ[xĢŠ]ā|̇dd·ž{Sróg?{?ÓCēzW%0)‹_Ôģ€t6Ð%wvuųáŊ;+ÝLPî=‡þÕ5‡c‡ĩģŧA3·$‘ķwÍįT­›vĒĮ[C—ŋŠąšâj)kÛé^ė,ĐgiÛ ͎SvÂqÔûđqø‚N„yäŅrUËÂö~ūýęį~ĖÝÝ&ņÜe={ĸ}œF‚øRŠĶ’ nįųģŧðâÅÄŧ@Č.ŨueŦš Čþ• @[q}ηæýÜîŨšsy’ö“ĪķC=•ãgĩî6ÚÕĻCp„uĘĖfĢZ-šŊˆįđŧ:"@TĶŅjįĪĀāėŽĄjĢO=8ūōē‚ųrWũ žk]•Õ-ũ 9Š54Su 4ĸķ™YD\•’īÏįÚÏŪŪđ ðóŠŧkĶÔõÝHļ›M§ŊŧŠlÂėžó~žÂÆ>·'; /^ü=ž œÚšu\OlĢ Ę úL 0ÜųL*ÍUMŅÂuÐą–ē'Pq]+;ŧF#uÄķįŒ†įŲ@‡HH`‡ŊýĖáØ5æÝ9@#ŲYæafįÝJ‡Íŧƈcdø ; ‹†CŨDÐđóŲc,ĶŅž}ÐkIÝ%6ބ9yŧũÎŽk]+ӌ00Ö ŋpũĸæqs3ššŦōúįƒFv9ÍÝũÎęZÐŨQ†/^ü5 CwcÆEĢÏĩÛÜÕúÆ!ŦzfĮðÔhR]­äKMr}ŪŪTĘÏ4:•e$R]Yę2wšuˆk]ų4dWķz‚_ũąüš!3U2úįú ‘ÁHÓ~îü;d ÍĖrà ߙ„‘āа햇ŧEUæŨšĀšę:šˆ’`ÁˆĩŦŒXkŅyli Ā'wuÅWó;™Õęo\úģŦåūdWw­keV•1ŋi /^žø{- ĖîÜP―+í°ZWÍ(jnÏóTÕZWL·ęVĩ› Twƒū‚Dî92‚đ?{ūþŧÐÃāk-=ÝbĀää͖U7ÅŧĮä šĮĄō^ūd|jÏ;ļņŲ§é`]Ē*Ĩ2_û™Áxú­ŧŨOfWMýÁýüvRÏ1·ĘH˜›ĸœđ{]ԓ‰caģ}ĶīŪØ;[ąūå ­Ÿ’rwNkÃýlģCuŧ{p EcWŋSíċ·[ œ†–ú;vKįŽC·ú{ÚÎ{?ŲEû $ĖhŒY;č―“Ī›Įšvn<œ`>9įøŋ*Ww ŧËĖÜ­ģĶÎëðÔ$w›N’ūžŧTZŨG@VđŊÏõ™õáŲ3>—Ôø>ą1VÜũÓUĮâeYucĐÖþ søZiéV-ģĢ€UV—bAJPXtū&|’‡ËŽū⊕•Y ôZ‘]ĸY2 „Ņ=üjĸ^žS-ÏĸÓ5#ÉŠþvƒ“•9UÛņLQcļÔ'ŲAËŪIĨųŽkz_ Ų”x1Ó1Œ+€Q’åŨĖÆ0°ģIeäýÜäÄÄX“îēc1Ļ6Ôę9đbĮHfËŋ•æķž[Š:oðĮɔ;AŽR›ÍAėįîF>; ˆøgÎ‘—egDLžŸ‡ËJ3öáė"AĒ+I“ęģ>Õ=wŸā4ûmmč~§Úŋ‡ïT+€īįŲYitĐ{Žķ ę—gŦĪa8ðdØZ 4jĖĪYÝîáĮÖĩįâŽėRXāDؐ\+HJ-õ:)0Y B­’œoúÜû1sHŲ‰ą„IMØô,N˜@DØû^~žP ļų˜Įč:ŸoūŒĪ9Ś%õĻ DÓŽþÅÔ웯^qIČ3ģ·ęŲ·ÐjxxW‘“ų‹ęęŪIxĻî‰:›ÛŅ,Üũ~^ÃßŋũXĖÜb­aðļŪĩũÎÚËÝ3Ŧ•ŨuŨ;Ė#|ėR’bų”ÓØäjŦûâOgAxxxæūnhB°öâÖg?qRžpxę”|Z]ĩÝÃÍŦ "HĢ)kBö~h˜―Ásüs]“kZŽÕxšvŒ&`c-usšŧKæpîũTč??îäŌ’&Šåf;“īˆ‹vz+ģQąą,įn •ŨÞRøüĩ$âOĶÍžxņR­Z~đLڙāömï=rTŧ-*ĶLŽÏŪóAr?Ģ‘Z æLéHšó:6 Ėl&Ð)Įáļ@rč)ÕįÝō!lRģĘfāūũî.§Y•fŒãgĘŧŪyĪþoø­jįy}ænŦßžŪ3°7;‡ŊœÞũ]ÕÂ4› i ĒņÉIĻq@ßĒ ƒĐωðįŲ9ņļîÕõýEZLßåŧŦý‹xņÞX€ C‰ˆÏ—ė›)ģÂÛũæ4ŦŊ-u ū3|īF3·)Į=“r Óûï•į•Â›ûį‡4ã·ÆZ BĐÍmyHÎ=Œ'aŦ KŠýė#l―ēģ[kÜeYéūÜū}―îaôđũŠ8Ý·Û×ņ‚cN·Ęäœãļ›vÆUŠwZ`EÜũMÐÍ>[#[ę'ÍÃČėė,:#VU7:"ūķŌu]­Þ]„VÄĸԙo Ãŋ7nĶļųõYõݗ"ÜŧŌ,ˌîÝE#ŒÝ†ZŨŠŪtÆÄ ΜH'‰Ęt7ĸŋ"ąۖ>ŸËÍ22Dņŋ7á7ü{Œþ§!ü6w3oĐē$ģŊ4āXŦ|øČœ_áÛž“$ ëŧ Hã§"ÍÝfĩ‘~­îĘęaXÕm$ÝōyØđýQ_a] ĨÝI·))ņšþÝöZÐ#hĶÝ<ŋpTŪæ†Ö―óŠðë:Å=›æ ïûīáī]IáÝ­™Q§`\0ŌÍZēpĢ5ÔY˜ŠąKRW43XøˆȈBįó˜äĪAŌĖÍēŠúÝ!üIžxĻë”ã~ĶĘÅÝI<ũcÆu- 1ģ18x8i-°ßČŦÖéS(M€K„ÏiWT$í“Ūhî„}[ÁĐĖ4n&Á7QĘól3ũ4ė^ëĪ―īÉėØ ēöđÜr?tŨŪ4'œÏģKqdgqŸõŦ{˜ŲaÚ&‘•srĩÜÕŠ,4~?uýäCN·B’ `fY q}#lڈqb°1å Y5ë/^üE·Øžų“!0éŦëðĐyHÝ~ČNčsïðÃó<+VøĘ.üvŒK0\îþÜÏ4{ĪßÝG†AĻŠN€Ë΂ŲđuÂ8e6=•3–™SHģĢ +ũÐ1tģ)đāīđËĻkþŋ?ŋvv;\Ÿ{Ŋ€É^qų:ĖŪ6' c~ÓZŨD§ŧđ9G%6~°ņSÐ ēöSĨÏį°3iF·hîþ.þ ^žĮbģX‡ŋFaŊÓĩUhbbÂíÛK?+Ũl5 &FRŸ?“ą;wmŌÂãôôXwóŧĮ…ĪĐ~˜úœßֆĮ8's>k Sčën'(ŦÕíaîžÏ­Ã€îÉĖW,ÍĢtOĀŪÎ3đû$*„ûˆ.ZŠĩŠŦģÉï`ŽsÁYđfN„#―[f<ûYM嚇ĐU5ŸLŽ*ĄvUé:Ĩî• `Et5‰á‘õÅ^/^ž5ŽŋŅ<<Üŧú0ctũ˜ũOjxįNŸÆ,Q§ô{osŋŪ˜Hœ†Į‡NĢÏZ ÕkM1Ũ6šŧOOÁðWV#~~‘FŌÝšš@Ž Yî„`īįįÖ!k‡w•~ĨZýQuïĘV­;·Óļ>ŌÝX>œæąî&(Ԋ[Ċ ņaę/^žøc ōxXE#Zŧ’îa6/@‡ũxh|~n˜dŠēH:]ŋŠąåë5 ĪÛqĘb6§Yî0Ļ4ĩĖL@UÏĀûėœ pUgïWļJöíūÝĮâuöČķŪkčõ||Ķĩa™6ĨŒ)ô­Đ)ųŧ$au 7ŪëĢF·Ü\Æ|öŒĒïį6·ļÖū§Ā1*SŠðˈg?ã·ŽdîĀï]Âŧ”'ÁœÏ!eUƒxņâÅßĒÚÁŽ[āÄ0…šŊÏį0#…ĒĄŠRF<ÏfãúįĘ*4xūČ?ũ@[ĄÖ,s[åUÉóæŠ–:ÜÂWž*3_ÃģZ)[šNÆ%ĖBâÐýxĀĖÍėđošá Ŧ Ö-šÆ:1SįÞiÆËýįþ™PZAi§˜·v ĀĐųĐŽŲHČ―i[•ÕPLŊåY _Ũ5õšę‚(Ũt\Š<~Ülčs}W#°íîęsGgýöxÄkĖ}ņâ/Š―ŪC{Ąk]ꞾŊuˆĢŧÍ=xU5Áë0ãDbĸw’&īG<ũݒŧŌĄWéūoÎTIŦnĀ`–5Û ―īÎ ĐĐNˆ°9ô§āáŧ·Rū P·ø%â+Æ]n˜Óķkīņ OīBfš‡ļņ†^Wė{Ãčî0iŨlIVˆeŨýÜÍHĢÔ]e<õ$ŨššjfÞŲHėgGDޘu°q‚fÂąvŨ_{―xņZvíîĶhĨ:óĢÜMÝ"=ܜęVŦéö ģ|.į’ohKVyވZh’:ïfnŠÃ8rģÚÉ×öŊõ@0wûÕĨFļZ’&•Ķ%3Ï ÜŲ‚;Hķ:sąí3ÛũøöĒŧ›Y mÓ Á‰ãō°Šgïgy\ëęjP ŒØũ–ā˅Vqí‘âJÓ―ĶjîQ]„“ĖĘRûÉŧ™Œ1_áîÃėxē{: ˆŽ’ô7™öŋ7Ŋ–ĪĮ:F5ü:œUr3óÎŽ^înÖõ LČŽįŲ4rŧŌĩ.ŽzNÚ!ew·VkZgýÛÉHįŠÕÝîfîÝÚ{Óė„ķT·*Û"J2Z˜‡YK~ÜlĮ7üđŪîęj‚ëZįÄaĸ]yoÖáC™Y—ÆÏFCæĖÂVŽėæŦ=šEÄ!tĩŨguÕhÎŪāGę‹ˆĘ4Ðf;QigŋÜŠóĻnn6g\ŨŒÛ„Ü_cî‹RW;ĶRPĩ·™]Ũ•ŧHÚeėjŊĻŲáŲĘ)ķĄ›Õ„/ôė ōZĪĖQCÎÅ+ŒĖÚę63 {o7ûŠ ˆIŒ­.]ýÏ?Ũ đĨFĢžä 3BݍƒÏrĀšþ…đәŧ ļ>Ũ&”ŧ_ŸčŠjÅĩŒÖU@ų‘œnö5!ģß5ŦTUœ―AãûAÂÓŠÛXŨãÏýßωĮčąbÂüįđGŦVUY˜›ĸIĨŨ‹ïT+œjEôƒnõŽhÉį+°u†3ģĩ.óoTvŽÕ0―ÞÕ"VwũLÁÔēąĨnđ…YĻ;Ü v+G—j^YûI ÃYęŌŽdčn§MNnŽÉgHIS 9š`wîg0Ü=MĀV™] ‰ēįįķVcïvģuÞM­.GęįyâdØĒuQÝĀh!T;ĐSMV5þ…ĩū"0uŊðûlNÖšp&ý!ņ’š/^žøƒ5ŽÝS.ĢÕNĄÍđVÜ?ÁpëÖs?•iīîĸOjøsßđ ÄŦōš.Y9Vąę:ëNFxÍÉÕV] hōÆ<6lNœ‹ģšËÃÖå•ČÝ#üūÝĐjéŧ&ĶÝ4óˆ,˜j>{X;ũÐxķđ}ÂMgÏ4OJŲÞIāÞY-'ŊkW–ŧ ‰“öų\“P3J†Žė.`‚rölĨ!U•™ípėŸÕūxņķ0ĸ%þ5Dž9· (Vāø&Î ÄxĨĶÃĶēbÅõđTf$‘Y]ÓHæ#ŋ%­Ņ3šZUG„đ›Ų~žî4ãôîÐx}ÖT…Csq‘ãCîīpũ€Ð[ÚęîĐÃÚÝ5Û ĸŧoŨį"@Äå+§žŌŒ†ĖTπėU‡FÃĖ Dļ­ÏóˆŽ*;k֖Ūϒ0ÁŋģŠŪëŠðŪdæcœãyāĸüsfÎĐÅ!ņâŋŋHĩä9@Ŋ]ęð˜ú–ݏŧ˜ąÎŒ-UåĄïjībÅxX'{rdĖän#‰—ĪÎðuĮšĻŌTy,õk˚•Å2·úMq?OW9=wNZMÄw Léw}Ņĸïŧ››Ŧ{Hæ8s8;ÂēÏÃ`Ý2šã%“Ōu}þũó“Yæî‡úŦÚݍ–ŲCÖ5ÛYš™KĨ~Ýb/^üI]­š2KUýÜwnŅmÖŊB;™•ąz'Ë-žŸM2Ö"Ų­i&ŊŪ߯o>gÅĄĀ―3Ÿ=:9Ų+BSØZŸÏPj\Ëég'€Ų3Lø@Žxr Œąöó Eðô>ܕ―Ö2Zïâ7œĖ2‹6Ü4$ŒųÔÄ5Ę.Š~pÂnŒž_·ą…{Up·o mÉݧĖā”3†Ÿ?‡Ŧ›Ns"6ã|@°ŠÝúÃēÚ/Þ]튘ƒu@ëŠÎŠÓzāķ@ }˜($ŅIi]enFƒT’Z~šŠ)…[uĐ5MīUIčú\ršĀÍŦ[ýWķ›ŧđp œäsĢý ĐĖúķÜÜOۘŒŅl 3Û~ãŨϖ{m< NŌūá0Õtfï*Ą@ēŦqüļūVUĄ{]kšnĪ6·ÖĪĮT,§qēŧ‚^•ÓŅKXUÚé§Ļ]óŊ~%Š!zē~ņâÅßkaó/ņ]ŨPvÎ4'dm™ŲŠët…Õißũí“ĀMí{ëí]ÂÐĒg5 nNÚýóĀ:<dí Qü–ËšOfķÔt†Įý<$WļŽX•†ý#N?˜;-ÂFŌ }bėjŠ2ÕÞ-ü†Ð%·8Ų7›C<1­ŽWCÝrw?Ūģ)KÞ<}· ÄäuÍ'MeAg}qoq-uOwï”éôŋ€;Ŧ“Ī;ókq;í“Ä‹ïąØŲĻ6ŧĄÞũv;;ŲÖ·e€–•pûÍ1(sxø(aI]ŨRâŪ†ļO.âô3tí0ļðóó8üŠ‹$LkÚ3yp7 kŠvĨ‰@TĮÆHČh‡gģW„J] õ䑏ˆbjÔMƒđý&.MÏý$=•gāS8w„ xø™ĩ‹ÆO\8ė;šÚQķŅHRŋŠasýįsĩ憊ðÜYÝgaĒrĢðâŋŋ·Ŧ­Y§Í=+IšÍÔEÚ,Fc~jÁr čɟ5[s*Õՙk-|”"ĖŠŦō7bžk]_þjAxîgīīîAþsŊėýėŪšþų4ŧŧݗ™ïį9”Jqėģæ+ėJAaF4ÜãšŪîVË"ÜĢ[ãz˜Ģķ3ï†ĶÆ2›ÆŸōøÕĐęß}EįNƒe(w_WĖŊ9Aæĩ3W‹Z–ZĪųɟ4ũån°Ę2 {đ/^üÍ Paį&͗O€E̟]gN<ÕsßÕqÖŊŧÜ|âZy$ýáæũ}– €ßĒFØîŽfũý_ŋųÜÏtÃt*;}ų!ht·Ô3J·āáŨĩžŸgÅ&ðe\ UõÜOUšųģwV!ΚuđŧëiØČÎĪ,ĐKsļ—Y’<‚āýsÓ|Úsį1æžëôõ dîd0Õ5Đ:#™€ð9ķā–HŒ8âÏqí‹o^­āæÝ]•ÝŠ€đígíúįš2s#ØU4šđŅv}Y2։ģĘĖV™y·ēnaéÉmÆð2ïmÆĐr ‘ĀŸ<ŪŪŠj;AYŧî&ųųį3ĪėA’Õ9gþÝ]]Ôųa–Ģ]WdĨÐNóįl~ÝИJŠlw3˜ÓÝņ”iŒ–€^ņa›ĸ"žgŒ·imčQãæóÐlâÍ$M‹Äó<8·&xf[ƒ@čOÞžxņ.ˆĘęî 9EXÓ―8’Ð ü&€Íö™mŦ†g—đWA§ŊˆĘrĸw„Ðj3ŧÖ%Õ~îĩâZWf ßģþ“cÐuķ '„pMЈ9GRõ™Ww} P>[8YŽčŲ)ŧû} +–™Ũi= @eĐk Äō˜ÜūĨgĸæVY™{ęouXܗWWVæŋ;eA„ýWxÓSĐ;5æŲYƒ9g˜=ūŧæŸĄ'%RxņâOâ=kTuy,’“á2%ÞӜxŒđŒ6Qĸįú Ý˜ŲøĐĖéá~ĶNĢā7#FÂIØēĐ=xØ<Î9˜E,šgķ™…{e>{šŒDPësM1™y,€Ï~ô­VėLyÄ:ƒ°Ïˆ U•әøma4ĘąŲ8ŧ›™U—v??ÝÓðؒhü–›ÚīëZžČąYŠLÉMUō8―Rs˜fæ?ũS}ļ8"ŸÝ üMýÁ‹oáô+ÛÚ) ÜŦR€›ŧÅŪÄpđŦĖÍ=Š{~øų?Ÿ|žn˜Q';—yC3MwaežŨf^;ŅlÍÝĻÖ~sŪëÓ-áæ•)āĪÁrFP@*ĀŪåęRÉ ŋ%ūr‹‰$WË-ÜžTÝuˆ8ŦÛė{ZÉÂ'ZffŽîįŲ”ýóđvå$“ņ5ð·Þž+[0ÔÎC§.ĐĮ$ö[§ķŪÕÕÏū§ŋ―û[gyE,w /^žøsĮbáffjÁpÚ―-ó°ðgßFš}OØ!yD ÃAĪåģ˜ÐŊ؈fŨsĸLņxVvëã-egĶyîMũX‡ ;Ýýīä>'ZūâÉ)\˜Šð§ŠHë–2Ug}q jb·Î0þÝÔKݙĩsïˆKøM~™ÆÝ d͏ņݜÖoF—™ ĖfæĢdĻî”æžũļŪ‹$bÅŽģé$˜•æÞŌl‡§17;g@~ņâÏá{Íô›u ÎĖ+–ûū%ļÛļķÜíŠPWWKZ>óĢZZWo˜™õn1eÝ81ÕŠ–Ÿq5wĒ@āŲĪužģ56ڑū Éý<‚ ŽŊ1 Ũįӓ>+MŒluŌaķÔ ÃtņþÜŧēÃĒ{ĸþb*wúēo y+>—‡W·…/þvGÂ=” ˆhÏÞ;Ÿļđ·ĻąĨ=ģ2ū>ŌDÛÔĐÚý™ÚÝó1PÝ]Dļŋōƒ/þč" ßÏFũoëƒÝBU†›ŧ?ŧ úI ŨŠúóŋÛOwĄ„}?"âŠáqŌƒŦšÜŒīûpŦ‡“øųđÝlĶIāŲÏV‹r‚Ïs ļâÓ­îęÖšĒŠ+ÛÂĖŽþE'á%AP4óûį‡ÄņŨŠ*ģ70ģõχ`UG8eˆÝAë|fĩZđn‚Øĩ§ífË7D PÕzxÕ<ŋ…ņy2ĖĖ=ģ v·XĢ&Î*Áė%Û/þ"ÕÂûÞ'šÛ 5ūđ‘đŧÚŨTsŨļžž{“\ąÂu‚ĪMđ7ŒNv &ŌÖšĪ–DÐOķ·ZŸ>UUjŌ|…ÄĖM0ŪĩŸĮÃŅdëɇƠwwešûuōgKmÆó8åœMÅZëÄÞáN·Ę ĸĶ}SĘdfGÆ{›eÕÝ]„ŊðŠę.sƒ8ëWœ@ē―ˍÝŽ[āŽ5XOþn{wfŪkM‰ï 7sQ=Ąāîu"ŋ tšú͛yņâOޘųËhn„uŸq„ņūŸĘžØŠ<ūŊk–r§‡›ąfzÅ·CaÖū˜\ÍMꎞÍîp_Ũ Ö,š:kĸšđ˜ŽĸŲĖãė:[U―ŸTÉÜēę<ĢMl˜ZŸë22ũį[gcža]­nĶ­J_+"‹m?EWMąUŠšŪĩVėį@w_~?[ęÓ4ĄÎ&­ŠcĢXî`úu@ä“ÝpũÎäægÄNu/^žøk5ŽÄ˜ÁÂŽ§mÐ(Ā ­vũpï–Ļą!œ.#bXF‚›SČŠ‘ũOôâY{úó<3Ä•;€ÎÝ'öÚÏ3OqžUEĀÝ%t'Āð‘Á&Íâšež]í-ÕNîßÅŪGŒŨ $Í‘Ī›đUUwûŊÏâl! RwĮAU™MœļŦ šUukšœ„9!Ž,u{ļĮ?™Uįņčœðï)ķÉÜnŌhü_XWĩäî‹ŊŪö_asqDUfŒ€™‰Æ íæ‡ ŋĄāâ45ŧš {ïĘīS3é1á!@g€]ŨĘgŦåæëú*ąŠdWŸÉ9( ģVU— ļÖÎsAÄŽ_A™;ÉsMG,𓓓ûėY_œĮ{ĶĘlj&§ÜėÜš*›ī|ū ŧ[MˆųdWĮŠoVųLåŠÃҧdlŨ7úĀÐ=™đf‡}yŽČ įŧŦ}ņâoR­ŸBō§’ŨfĶ!­ģ{SiŽčŽCĐ3HÞû)šŦ{?ŧJkøë û|jW·,üxp{R=ė[Tî>Ý9&bĖcn6CņlHigó+|Ū‹N€G1öÍŲĶ#ý8ŋŽUhœ•kæNŠk5ŒÓõ{ŌËäNsfý ·øeNM@­ÔÞՕų_bäH.Ö9ŊÛ;iļŪõåīXąï‡w7ģŲHļŊ―ũýóļŲĩÖ~ķN…eXĖÞãŋ?‡WWëËóŲŠ6B§‹ÔįsiŌąÐÓ|“]vØ0Ŧ$EL1ĄĖf•]O†ŅƒKlŸëSs ĸMu)ƒÜđ%ĸEíė]ÝĐî5ō†]Žĩ(ė―‡Đ’A‚Ė8]"Vî‡fÁÐŲĪYØĖŠ›{ӈd]IÚu-ũģÝĖ'nž:)HsSC]æ$؅Ûœn1ÜøÜ‚V[Šk…4É žlÝĩk·™>ū2“†j…ĮŪŦ}ŠŲųÞüMžx§RķÖgĐzĘ `VÝb$OÎðøëģršĄÔŲ™ ZÖîÖ7qņÉî6ó.Vhî@4ŦŽCÐaîÝôĩgę<% ­dî+\jĐH›’.šđđyŒ–ë7ąĮðÖ;ģ īˆėęÖåãģęÉĸ–ĶüÆwî.Mtw}ĢĮÃܞ|HčŪĐÕņgc„™Ý?7LaÐĨŽ2ZvĄÚˆëóÉÚÕņŠ9ÄZ+Œĸ“/^žø{TKÃZŦŦuņóđ:+ũö0 U%|…ũ YøŒŧ Ā:qV- ûWRJĪJ’Ũį‚˜™*­S^Õ h< ŋŪ™uU·ėî“:Äg+Ë3 ’đIŠJŽ› A.ŽILĨɜÝ?û{ąņœķ}— ™ )"2›fãā8j6ÆîįyÂĸÅ7ƒÜč4>?ŽĘ2*ķUÕ'ß Ÿ―éūŪJ›ãÍåģũdĻ ØYîîïöāÏâÅĒļHĩzUrïCŧĀ!ļĘ&Ų‡† ‡†Æķ*›Æu…›U&ČÉoĻ0ó3ØBÓŧ•Ïdđ†ŧ·šŋŽS™•y]ãA6Ų7㘁WŒ]=ĩŨŲðŊyUķk—AY˜ ÉŲęęÓ"Áɟ5óV›ĄŦH|—$ī_[—­ŧ…ŪŌÔ:HŨÆü]͇­ŧf }Û<ŽŧIÆåģ BxĻ5―A óČuņâÅÄ+öšĄltþ}āf>R'ˆݚŨ vĶcyuJ=Õ/ÕųŸ#vj|Ģ ķoA°ęŨ”ETU6ĖÎgßhĶĐÝ]#Âp^Ý h[ņX3g‰<]č}(r< {į4þfĶ9ÁãaŦā>=’rsĐÏļj‡ĐJŸąīģÏĘĩĖé}ĪĮ:Đf0 mưčjŌfÜ―ôļÛčŨĩ u‹ ^žxņDĊˆĢ9mšųrŌĖm]aÆýėV_§äĶŦېUÝ9)ĻîÃzNŠ:ÍísúŠ~#ŧH4ÕŠšķąï(m<-2ęŪ8ýā]Y]f:hīĘŪ{w•@õáĘðS,6m`š=ōÞinÝU{ĀÖģŸëĢ2ÝéFũČ*@Få5ėėž357fSAðŠeîÏótéqųįh$rW—HÛõT•JcöŊ§Õ-M;ģJ$#Þ†/þ$ÕV–ŅFc@ģÉd‘zÄĸ•a'â:ŧ 3Ô§rņZŦēōؐuë2Üýéėîģ°ÜYYcŦUĸ îėV§ÜūëW“yŽF  čî'ŽVkđĪsëÛs!T7ßþóęIÞúŋnzr]hîvf·ŪXE˜@óčJ;R‡ģŦM#Ŋk ūl5pޙœ‰ØĮ…|–đaņdæ“îËģ ™…ŸüI#h$Ķ\rųęîŪ–ú-ū!Š/^üÍ]íŠĐų‚qŠmZm4YIĮTÕBËÃ#+Uíņå5šEļ # h­+kŦæžï NUéfnū+f€SÝ]fðū3›2Ä| Āu]ĨDĢĨÏĐ77Ōà >;ÏŪÃÁomøŸTÍÖÂ=ΚX ĖžoßĀߒ›Ą[^žxņ§Z@ûÞ ã §UVļû咞{ýŸĢ=€Ėx" ž§šŨŠų>^•ī‰Vičļ!ÕéáëZG[ą‚n­ęė— R›{ÄŋÔZÍö―%ørũhuWExĢŋõįīģN5§ ÚÏvr]1…=™ĩb‘hČaf^ÕOĶĪpŋũŽ\œR[}>KÔódU‘č*uKāoCåīĐOļŨ”ã6ÚhŨ|”™GUZ#ĖV6Ā ŽCĐSņđeˆĩt /^üEžÉ^s`x*iüÏIefīģßĪZRƒānÝ­ÃNîŪîSņ^5ŪËF*ŧπų2ððüfĀ-ÆþKڑš%nNb{Ŋĩü<Å#Ûʝ4„ Ŋ•+žē:‹îQęþféŪiÏ5ĢŲ·ÎÖÂ[Š;e8―ÕÝîf_ÅÅ,pm\ËĢ[ĮähcŅ"ÓļncK{6Œî!ĄU$ė{$+tßfķ–GxeķúPdW@ØŦj,gö_šđīܙŧHh•$óoCZÎcÅ‹§0b,'Ÿ> ĪyįŅN ö―ĮļŅՙoá͋Ԙ ĀdÝMs ŋ ÖÖՄ` Aõõ­‚ČÜSÎļsï―'Sædĩd„_Ũ•{•htž |ųI°Ųy&>ĩúžĻÃÎ-›Ïv‚ÓĨs6ŋĩ“fË€ÞÅ_qÂýÜāŽ†ŧš=Ïķ@6TĨýĨHkUVđŧY` #š+֙šgSč;VŪÉ ;ËŪŽŪÏÕį9_wïī‘ß'ÎæTNTwK8ebOŠÖį›\ÓhŌuĸUĸ‹ïŪöøz­Ø•&ÃŽ5Ŧ%pV™{ÓŅ-ž―Ãm­•ÏÓÕcóŊîÚIÍēRĢUݝâœãŊˆŊހNXŨt]Ũ—Ås{ö6Ó꘏Á ú)57r ŌÃb]uV§$9ý‡ÛÄuũœÝđ1ŸíæĮðķģ3čæÖUšbņØyiæē„Ŋ“Ņ%­kđG=Ųiîl•ÐŨuôøŧĄnÕN ‹ģ‡™UɰķŽĻŽxđöŋŋđŦ5·9&2Áø;͕q\]ŲUn1R­āŲovuë$8ˆĘMš$įqÓŠœŠÓ #ŅęZËÂgeģ Qæh€âІėÃSW,ųĪJtƒfÄŠqĪ­ĪēRh ģˆŽībUŦjŨ.7‡ÔÝnūbeķ Ž ķ6aŽ |>ĸˆšũķCÆĩïD/4QŧæoUé‡gĨX0sÃāĪĪŲÐú\Īw„/^üÅ‚ &Œ1’XšÓ,ïM3#í$ƒffU}H~öžģĖ9ŨōˆX wnĐ-VUŦḊíLMī‹Yí20܃~$eéWœˆÛœĀ„ÎÎĖiEĖÜcŦ5pÖÁæŪoÝà @eĮr;ïÆęĩâÛ؈+Nžb–:–Ēó+ü23Č2‹Ô {TíZæd~ü Ģr“§9ÛqNq:[3gUV7ݝÛÉĖDVO―9ŠĨnh­^žxņũĻķÕa^đ4wĢåģA"mģļgUŦÃ=ÖwāaŋVÍ@&JG™ŧŦĘ—_ʞ-ðŠøy~Ô °ŧņÍËŪ.ôt+”ÚĖÂLY‚Ėmv Męęvģð5^söÏixĪYK{?jœjČŲčĻrNąŽZ %%Š*77B] đŸ„hųú†=ŠÍ―[úВŠE3•žJî†ĶØg'#@ft·Ęl‰-Ë7ŲëoâÅŦ@0ššáÖÝ roŒ˜`äęu]““―âôŠ?33Ú>ĪlFÕ―Õ'{Ķc†ŸķÄÖ Ÿ…ĐÃĶÃiÂ!;RŌē·ū‘ æÖ%iļU-ĖÝŧŦs fÓŅ+fvß';&ށĘ$đŽĻķš@Κxį3VïFNqzũlWUĢčîqŒmR{8ČĘ"eÎ>ÕdvĪŧóg›ÛoØ#OŌ9~þ0"~[sdæ_§ƒÜ! /^žø“TÛ­ŠT•O4ŒúŠËÜj–W`DKnœÂ˜Vļ/€ÂCŌīęÆĩÔÝ sóÃģ“čð—Â}*ķL*MW››‡į“㔍ãÁ§ėÜl‚šÚĖAÜÏsx“Š{Þ BwŸ‹―šģōZO―9„8óėýŋŸÉÆíRVš…‡Đ%Ļ”aŸÜų5!Øļ9āΓ?{˜Ú­Ï;“\ūöÞhėîxæsĮëšÎ'Mƒ1ūÕzÅ^/^üÕ]­ÔĪŊP·šNbaÎļęjt7A’jMK.ĻÎyÅefg?ŦuŒ ‡ qļŽ‰ŲũĒ&ųÖėK|DDč8hûï4$šGĶņ?–ĪŲsÖÐ0a…_§oËÝ æNĩÂÂ8@ÝũwŸo‹XŨ―Ä!pž…ÃĶņZëyžŠš‹ŸgWŨɜEU Ĩ’Č]ŧŪkœļ“6Ý6óypß·ąbį“™6ԟõÞ݄/þ$Þ sW æ_/–šm‚ĀģFÅ%iĶTsWŦÔF€Úđ‡n4ŽÐĩŪĘ>WÚøqĨ†óÐîåq]Ÿéaô0˜ÚZs'•{‹ũ|ŋyÂ‡Ô Œsqfšđ™gfWÆ·ØfÃÎæ·Ŧš@\늝äÔr?#H0’įîmfÔ‹Áó<ßģþõYˆ‰Óõrg™óóđöYæž$ģkzpŊĩŒĄš4yių=ÔųĄ› Ę,âŋpWkĶl|téę.ëŠÉ+aÅŠü–†đ}bÝĘ|ÂC4áF|™ĸ=· ›ėŦ™aGUš,<<ŦHëŠãāzŌ)iŨXđHÚØŌ̟uš š­Š" ĄJ’č|ōĖ§›@ Lyˆ§ūŽ27WɌFâŋqŠÜÍéŲmNũ5ƒp‘]ęþĶ,>·#,ĄŽ=î2РĶāRM c“?ũsYÄ #ŦÔčp?dWf<Uîëģ vïsĮåÓ1~ČY Ámâļ4ý84+møø'ÚÜĖ#ģFÚĩÜzŨaGrĖY2 'I(ŧ>Ũgw‰Ó(góØŋÏlĒeč. "ģúÜ ĸ|>hí:Ĩa't&ï·ę9‡f š•OšÓݞįa†:‹đMļí‹/þÕNcnuįÄŊøĘ3šnŠBëŧÝ : Mšx„CĻ9Ž_žcECūđÝNšå“ß#ŽÁã‚õ{?„ÅÉBüĐێ$ËO'Ģ[ļ‡ūĐ`>udĖhī(ÖRWæÔ‘Euw&ĀļĒö†fôČÜøU>u­kWô­ Î"mHXæ ؕ‡Äg-P°s—ŽVŧŲ„;ėËû\ÆęamwË―Ã\$ęšĀɖōŽķ_žxņįŒđÝڙęŽĩŽ„Ë"ÎŪģÝ#ÂŅM‰ =ęQI9įQUӞKX’N–Ŧüðnué›E›jĻE;9^Fš ĘJ~Ó kžaąė<›Â Æî†īŪ0pĪpvŠ|ĖęĖnˆ)K™‘nwfĢW,6(Aøšā@7ŅÅó<";s&f>>qyŽ ó[îFSÂĖGøÕ‡Ī öŪ%hBsĶí1–Ŧą!3GFņâ/â{uðˆ.M‹Ēŧ=Ï­jŌ,˜™œĘXĒģIš­ņ}ř:Ÿc~%đŸFHÞUīo,ĀÔ3ķôðåaõ$I3Ė]ÝB wVgŸĒYæ.Đ~îYįâņ,ŒÆËjŨI{‰đéĪØœÅŪūÕķĩŅĒņÞϓÏëĀ0Q0äÞ&ŪĩĶÏFęÏõ[a^UŲEƒÓ8Gpf0tũīĻu įÖæ–įb˜Žđ7Ē;3Iđ9^žxņĐvv5)zP‚Ņ|-wÏgũĄ–`T‰°u­*ßBïį~†õƔÅĢ 0;d ^ŸgĨJđĄ2ũÞM]ŧĶūŽ„ėåŨR”3"Ö>™în‡—ĮõY‘—}žXëūŸR›Åk5IûÍŧ1Ø?ŸŒÁ=čÖ­ŠéīûŲÕ=ujeæ'söé,ŠÔ]FĢŲ>―•ëúš6šk­˜\چÜíÄëô ‰Œ―w·bÅH|[ ˆ/þ(^]mWƒ_?U•TmīŸķŪïq–ĘÍ}đŠŦJ‚‡ŸÍ#5)*gá˰VíÜS?ĐŧŠ*ü05íë.Ëiáî†u6­Qx؜V­Xv˜‘Ēû7 ķšf;ŅÝfūVėc7pÁûū[ Ō`Ģˆĩú<Įw}QŲÝþ›Stw;íđĶ_§gs’­îßbīĘ2Ú$@VÉëšÔš2wSŦ[Ë#ĖæŸā+5›čÛŋ[NþâśėĨnIŋ‘S™™fÖ}(°ëT$<{įĩŪŦ'[–ßÓöĐ}tóņđęDíDsÞQ„™›ŠiüV+v“\Ãģ•ëdŒįÎ1ŋ%ÖÝÝqE렁'M_ëZøũÅZq-AïųtôZXwU&„é^Ęc‰Ÿû§šÜÍĖ æįÏŲïŲBŒCŨĖæ/üęŌ†ŋÅš™ĩ3'"ŋÛÞĸŌš„ĢýUĶ}ņâ-'ïîS.{硫S ÔÏý?ŌÜÌ{—ŅŪõéĐ}qZøó<’V„Ī―'ŨĘ=û1ڊŦŠÔ°p7˝Ē<Ũķë aUĶ_‘]80·Ú9äE˚ØHŠeÁ|đô플Á5Ác4žŲ6Ũš&ŦaīīU]Ýã(ëÖâ ý<ÏtܕŅkß { ZáæTÉ`ĸ\]Ē[\ąũsrđÖũCå@K“i@@“Mū\R}3v}ï',ÂMÄáYN’YdU7š ÍĘ:áÎO‚ŠēVwGxĐ i\^•Ļ6‚Ɲįđ’ ™ĮGœ§#óŲ€`$ąïÛĖcEĐ8,"0Kw|―v2Úy6YØdKÎÄÝZ}žMfþ ^žxËÉiîüđԾₘÏCõųZ­Ę2€nÓĨ(‰>gbø|.‹P‹ŅR§ [þuũzĖiû›,žU]eîGģĨĶ>ĸŽÎꂹI”ÔUáD{yŊëRĩôíŠŲ'—ˍąÜ@uÓŽ”gĻ AĢĶ }ūËJ ŊFė|Ķ莥Žė.sΈMģˆĩ3iF’…įIļ{˜ŠØBËhĩũ“éæ rÂqÆÂĶĶ@ãĖŨ Ex·Î*ÃéūŸ$þ^žxÅ4FØþ1wį ~53f–ô%ãįÞiŒģ"ËZĮ]6Ų1;ģ;ėB°'Ē{ žŽēõԔéģbô}ŠtrWUųĐĸÎ]AîL vˆĖÎOû°›@Ð~ƒd|ĨĶyW·pļëÉ=û ™öģOķė§ĨĘŋHĄYՒâŸkĸ<!†“ކ‘@4ڝŨōû~fäw√Œ4ņ„˘Ó܈Ü%`]>óōH#v 4+HŲ†?ˆ/ÞĐķŠ'šķŧvΗôo•VŸ%)E4ų ČĖ'ØÕ$,|ô[ ,LYjL{~þöýÉɋdéŨïŸ//Ŋĸ\Hũ+Ā1܃‰^‡?žøįÃŨŦ/?ū3eše]=#þá4ū:;ŧsxpõųÜXqqá9” îąJ=Ea‚ęAm›#ãÅ8ėtPÔŲ öÄX6-…†0K:K "ķ,DÝøE–Nđ‡q !ÞI2ŌvÄŊ!qqNÓto­Âž‰ô˜8ŅØ-#įÜļڇ~ îŅ1*—98ūlkŽąÆ>š―(JDʆAzlD>û—―óþŠzþ–ė&›F‡: J  Ĩ Ą#"―ũ"*Eš1ˆ(Š"Fzï―#Uš„N)!Ih Īoėį9s|ßĸ!wåæîŲsîÝž;wÎĖkr\YŲÕÂjþądyįÎ]nÝž a+WŪâįĄp+TŽX­FõĖŽ,›§Īî“ÚUžd‰j5jdffâiōËlŲŲøŽõ6v:iF‹`.Sģ]ĶrbnNW -ĸÖÛĻð>ČmŦVŊQ-ŽzöŦ,Õ'xUĐJhíðzū~>„‹ģ5LaSgž)ģĖ2 ĩGģýÝZgEéĻ)‚]ˆSū|yœŧýûũūL~‰™šúp|5ujó-ŨŽ^IŠ~Ÿūý““_Ėųáû “§ä XývÅ °Žt™23==mč⁃‡ ũå„ËW.ŸųëĪÓK{Ø`ęØŽûrü‡-šOœ0ÞÛËņMÔĖøļ8B 5Þŋoßųs1>Ng€@Ũ?‰―zeë–-!åCþųį†(žhˁÍ-ÜRþ4)ĶX€y5›G@‡ƒŽ-ÐI‚fÓϔÕzČŦŊÜŲ pØ―đq6ýāÝCKãëƒQöĖėšīÅõ$a-~ÉôčÄ[Ģ †ÍFYvŽKĒvgŽGX%ŌßH.„€Ø“„e•{ȕf™eVaŪņmF4 4€Z(čåíãëëĮ‰ŒŒL‘ģ’Ís6hÐðîÝŧß};cÆ7__ū|™0n‘ĒE˔.―wũîïĒ"įÎų)%%H‡„/^°C‡ŽÅŠúúø”+âVšz\Ķ ,VÎŨŊWŊví:ļąo―õvbb"WUþ­·@įōåK_žHNOK ^ūtéË/ðRĩWÍÝps€\S§"ɆāĮČČĐC՟m՗ąes–’–f‡d@œW‘8ðžĖ…1!ƒéŊĢĄhN°†Q Wåíd“Ī4>VÍЀōLvp ˜ķË%i°)ð%rÂ{…ō–Y–ûĖōj Všĩļߓð,ņMrÔã˓ Ւ“āOĐ2eHĖŌ§eÝ­ũrĻ.—dt™UéŠč-ÞŪ”öŠÁh_?ŋŨĸ9sþáƒûŽbRb=0ÖUeBiô­-W­\qîüđĩ+WĶūL4dčč1c›·j5°oŸîÝš:ŽC§ÎÍ[ķ2°ĸąĢGļNŸeÓIŧã(ŋĀ ĻߊĨī^āŊ“ą^žL9ŊÃ4ŋŅæ „H#3í5ĨĖåĄ=Øđrq~™ÐdãĒæ)%øŧZXáÐĨ_i|VŠTÂ4‰Ā·ÍöÐō9jųĐnĩGŽŅTÔÏÄ2Ë,˅"Š6hB“ņÄpČ`(„‚§OŸa@Ϟ―Z·Ŋ[ŊuDDPPņŧqwK–,^;žF*Txpĸn,ČŦZĨJhÕ:áu ,ž=ˆS^ūüíŨđŋ͛ŧoÏŪ„ĸ5]™ \<þėé“' ïðĄCģg}·aÝÚkWŊ‡Üŋ?f䈓'OV ­J°Â••9mę/?Ïa捛ÔĐ_øČ1\‰xøĨB: ˜ŠÞ .šsšG†ÎĄø•|ž%Y™7j ƒĨzyY›ÐPSeí*ÚČËĪU˜” ÔŋČ*c‡fđ™š:BÆâcö–Â06ÍīxŨī“drqA4&Öáa™eđÐŽj1Ýēw›„xaęėĒŋęģzÕrō  žf݆ĶĪĪķnņáī)“F/ž·āwΐöôÛŊŋÜđskŅŅ8ž[vėzøðazzšŸŸß­7–/[ĘÉíŧödddĀ™ÝŧáŲĐŦ+Čsú8yšĸų§Ų?üøóÜyó *øÃŽï äÏ?hč°Į-Ztßū―p|Įž―ϟ=gÎøøøƒûöõęÓ·CĮŽąąWþ}ôÐÁŧ[K~™ÚëAÍ0]Ģ"ōŸ4āŅj/ÓĻÆTĮá―qi–.ŠąKˆA% þW0ĶYĩRÂŦū4o$ A Ąķ Ŧ3†žlnmā˜GWQ—_=h//UĒAZRbšRfĩËĨf™U-ĶīęÛSgS8HKMýþÛĻŽíÚFEFN™üU›–ÍÜŋöĖ™Ū:˜õÃũģZĩhvčÐA4[g}5jÄð_įþŌŊwÖÍ?X8}?óÛÖ-šáÕΟũk·ÎŊ^đ’ˆw>úŽį'Ýšuéäãô=|øP—Níūü|ÜʕËúũé―~Íę… æ>tÍęU#‡ýbėčMÖqžô…Ļo"ŧwí|úԉEŅ ÆŒy!&†)|GpnΔKHšŦŌóF* T(GÕ aŪ63ÓėZ9ÁI1.ÕøĪ €ŋęrûf€Đs›Þb&ÞĒģ‰)Žĩ,7Íxōč•\€ÅF 3î\ÛÃŅ2ËŽX­Å† %rÝēqĨþīö:}ōÄß§O‹Ú‹ë•'Poïļ;Ø-Þ Ô”>ŊiķeÓz`bZØĩnNFú…s1W.]":aĪķ@#˜üöí›ÄČÂîÅߍŧs;šé<ķyý:o§·Pïļ îÛwpĸ>uÚHŅ―pþü… įy‡€,­―ŋŒęŪ8’FïFuŧ!ĶÖVHEœ§ŧē%ĮK―NjU—Ýt™tK1ƒF!īųš9cۈiå 'Á-?F5œš2Oí+ŽQk·CķÁžÁ­ 0†Ý8S7b 60&wŠ(Zf™@ĀÅ3Âø\4ž1‰Ÿše$ššifÔ^pö`ŦxhŒĀ9åHóVĩ%æüsÆŪÆl6ý sĪ2D3īĪŲÞh/&Rų§õTÐõŋÁ`_ē|đ$RbUφÜX2›ŪæÉI-~•Âb}6Ũ|ŧƒÝ*•evĒŦŊpxM)-Ū·^šŲÎrëŠâÏ—Sx·Q{0QV'ZÍm3ž·‘Ļk"2H:ĩ+:QÚÕ.rđlšðşžL-á`&a†eŧēõ’åÂsmÃË,ģ0AŲęåāP[';8ÖgpÍUOŒ|žLÔąsÔ+d˜ ‚5vŸ0­sśc_ÍS1Ąp 9jëŧ ›þƒ‹å™DI­=wUM@Ĩŧ_q€v—`_CŪĶ­1ĘíЂ^ŠeƒĘ `2‚l§H'HGŌ2€6ÓøR›Ž[ģÆĖĶŅSÎrĩLÂëęĨŠz™iÎh7pd>(VÔ|0-G‚ \ÆkĶ!9įUqÁ„/ll”‘‡ËŠ?ų†Ë,ģ,7`‹1: 'Æāŋq^ĪĶĶāņK“·ÄpĘ  †I%qՕéœzý§ų _ÉūÂðaŸËĖ6·ļ^Ēö’ÃT° IГ%äØÍą[Mƒ2å—M:w)ŅČÁ^ŋēį‘Öķ&ˊ‚WÄ`ŒŠ€7—áĘæ@gŨėŦ<æþDŊËô”TĨCæŠJ•HÕāYk|VÝkõ\Õ]åëkéŌē4&ÔŠ4›F!­øēķšŪĶɂúķš/ĖK 5yĩĶ{9Ŋ þ Ũsgo1Ë,ģžZžNuÄLŊq`ÝY"ÃęaS1B|ØV­ÛLœhV PÁāāāIS§U 6rԘÏ>‘’X,ĻWß~‘QßEīmïįŸ—ĀÄfËČéï?pøˆ6íÚFī›:ý›?þ$8ļüĀ!Ã&OÞŠUĻ‹)úižS#̆ N%[zf:Ú4§L+W.ļë'Ÿ~üiO§Ó'īJĩ1ãūœ2-0‹­hŲĄrk“ÜX’Ī·‚JĄƒt>QH€ūÚU—óqUčL0i 4HÂgĨhxØbN‡·Æaī ßVĐ ßáēŅ@`ŋQ^~#|W…Ë,ģ,ũæŠdkp1jÜĶÛ,;ïïŋũ>îœgŊXž$oū\<žČQŸ}N•`þþþÓ§M­YģÖØÏÆ=rĪéôėÝwİ!ŨŊÅÎüaķŠŲÚûôé;û‡YqwâŠWg֐ō™™%K”þmA42Œ'Ož˜óëžýö čÛ gįģ@‚ŸvĸīPĄBŸ<ĄfĄĸ€<ČČĖ,ÔĀĀm?š~ãÚÜų ß{ĸýëŨŪõėŲŧ[ũîÚG”.YšZ‰ÆMÞŦ\đōŌ%K^4kņíwģîßŋ—––Î ãÆŽYŋv5ąZØJĈxIÛ4MžŌ}đWfũÏto„ū’h œe#ÔC–Ž" ļԌ4™ķo‘R‹Ž9`”ī)ŌĨ•ƒ‡vĻdb/OžlŨ‚x[îLöēĖ2ËŦu jy”Ö„$•.Ā‘# Š7Z,Ļ8õ`ũïßϛ//AL§—nð wíÜҰ^ 1į>éþ)ią“&~‰F"Š‹ÍšĩxšøļOŊO‡ 0qü.WVxzG$1ï/*rúāj‡Så[oㆠ“'Nøëøą-Z†UŊ ōĩAš+Gõ―G <#2RKģ\ýz}:į§wÍZĩÂë6€ģsųđMë–Sŋšˆ„nۈö@ŅHäķmÝjÖĖψöí}||æþ}‚ôĒ…‹rU3g}Ïs―/_ū$.’•‘IguÓP>Ož<þú›oęÕŊ?zԈ{ņņkŨoZ8zü˜㎈úĸßącûō%‹yÕ/ āÖÍė#1'\ƒ\͔”NHýú‡V ãŅžNŽhâîaĶŽ•xč勚6ýpØðąąW Čþņûï.—ŦNÝšmÚDÐoˆC:ÄŨ­WïžÝˆŌķoßŅBZŽXą^Ýŧ LßË(―E•ÜS5e™ĮÓvķÔŧpö,d5öģr!!õ4DČæĀþýDrÁ35Ãlv8røpƒ†ú|âŊŋ‚C‚/]ž„ī͒e+vlÛJČâÛĻåÂCĒ—Cqbņč96ås’Ķ›c\‰ÛŲn›°RýĘãoSýFīq]oŊoī g ·[ÍSÅŌTúæBÔZf™ŦĩI ÃĸddÝŠÃ"9éëëûũéSÆ >rø"[ä Üžq#+3ëúĩŦöï# E‰ä~=eĘÆ ëPōnßą“‡æ-Ž^ĩō\L Ûe(ˆĸ:ũįãĮŽ€ŠõkV=rļR•*+U‚Γ&Œ§ŸÂ‡Í[„Ũ˘˜ĀSđiž‹*ØĄ?ē"Te‰C\ūt‘'ņīôīÇþä-7oÝ=r6Á įøĘĨ‹IϟsI7n\Ï<Ą/_š…0ĸĸv:”.]&1ņ9ž‰,“€CKþU7Ŧ’1F†‚wnüĸ?i\T@IÚ—†kZē3L·ÅÞ0'ްvÏÍ1ã„ģMĢÏ`ä ļ+ÍWûŊBëÜr›Yf™åÕēŸĢ@RāÏþ?‘`2N;sæt`P1þ}xßŨĮoņŅ įĸæïïįôö!˜pëÖÍaC/^·ôþ―8ŧCø{.ælÞžyŸ>}’ž–ÎlPaÝšv.YēÔģgO}ýýķmÞ|`ßÞĀ  ôÔTHžk\ÂĪΧĢG Įôqú Öđc;žMĸ€>ėÔūŧVŽrėÐÁó1,T˜XpZJ*{tįÎÅtŒhëįëGŲ$…ŨģfÎXž(š72úƒĖ­I~0ĄR"TChĨ°Ü#ô$…@ýVOý4ĪķB’mMåą]΂K9ÐĘc ėŠČ­QQxŸĢ„ÔSæ$o4Á_SčŽÔ&Ų6ÝŠÕæRģĖ H―?åą GÍd! pėįï:=|Čq€_^0ä$oÖŨWÄ_Ëš·”Ė&&<âO'nô"n›•™ b`( bÛÞČn҈Á­%đ„Yņïݍƒ\°’5‰*›p0…q:€‡vlŌ6ÜKýMÞëéáðHOËHK‹g·Šž<Ŋ_gē žÚLk[''=™ü‚<:œģ:=%ČũŌH°FpÛ4p@éŠá8ŦRŋĄ…FšŨÔ­aĻķ)c°1“ ĸ mF#BCĶx—ûĘQ§ØÛá Ó1ūÃĢĖÕtÛ\h–YfĄÖ&ŋn#`ŌKAāĀ ÓcÐW·„,*āÂŦdL‰‹Į‡Ð†Fˆ_åĐ*ŋ8`– J1Ä`8EBœ@‰m†ĻeiÚÖ,G}FÕč2âđR ›ó_ŊļirLڀîŒÁ~Qãe€ĖcÓ6‹ÚîÜ4VāŒ~yšÂ}DÍ]ðð{9čŌË$\†ŅNThóŠŒ|87ÂRčī3‹N.S°Ļ›ŸÜh–Yf•0ĀQ}ē0FýG7n ŋdÔ.\4_þüyō PóĒSx*ō_*î…ßÉûØô1?ę2"Ųe+\~ÂĪ)í;t2ä‚ÏĸáRÏ< A-„Í1+ŪK GĪL“G @ē,ëBqÝhzĢÚ1ÄCJ7ˆ7Md@+K›Ā(oĩS”ƒĐŌ‹n…đxĘŠ ÃX!-3óÁ};`Ė—?_ïFö9’:yTqøķš–';ËÅFī-`ŠŽ93‹§Ï5kKsđLu…ïÚ ŨÄūEe\Ü­ųe@.4Ë,ģP‹‘ĻäéĨŅLīa.Ú1―ûũÛMŲėÁǎŸˆ^žŽÓĮŸāÖŠ ,ØÁYc0úģâ ŠŒīwef3ð *1z˘ķmÛâ< qĪ“ð2ĘÜr€B ėd\DFZ:ë{Ų―UËfÄa]™Y@YÁœ Ŋ‘ázŲā‚Y ž c܀7.ķv@āqßŧUƒ†ÆÛÔØýĢÆŨĶé―x "ŲĨ2ŧО\4BÃäŸõčŅËnįUql_ĐØÆÍÍâę-Kâ­Ķ(@U<`q]EŨQŪPûĒ;þ‹ĒؘÆNV­ĒWônøD•ÆfrĨYfĄVjóa+؀šu،CeʖĨšëôĐS$i͝;oðaīĒ!į?5-Ē€jÕŦóh4}}}j―îïP @úÛ~ßÏþqĘīŊœóKäŒo ,ÜĄKŨĨ+V~1a"ß;uYķbeŲ2åļTxįG/â;ũîĸ°EˌÔīÚuë™+ŲļeÛū"ŽQ―FÍfĸ4fÜļÍÛvŒ?‘˜5ũēnãfÆŽXģūråPÜXž|·æRGįĘãŨÄKē-ÅÜh–YĻåŨ<ĪKĒ’MzðKš•öĩ‘ð*ĪH~‘tãúĩ3gÎPËāíëėŅŦwĮN~œMÏÜïIũåb…‹iÖĒÅŪ];cbÎķþĻMŸūýĐw0҉ƕBĢf|‹kIE>ōĻŅcĻûëØŅJ•*―]ĄBū|ųšžũÞÍnžLMŅ=*Ķ6?qŌŪÛŋ76oū|‘ßΞ|ų‰š-Zķ lÔļ ō—.^?ņŦŠÕŠI·ÝËúôíũQÛū-Ļ==ö3fÛŧgŲļ­•)[ĶLpp­Z9{ýúĩ*ĄĄČ&„‡‡Fā˜ņˆ6ðÜžųũ[ĨJ(}'·nÚüÖÛ:uęŒýudTéēeĮŽuð‘ĢFwųļūmHHHŊ^}ýûûý("bÐā!+W,įJÞzëíŊĶL̆ g^š=ʖĒüzōŲæhŦ1KD1·šeÖķÁGðjâp“ė%mýb3Ō_R åeRōå͋.ƒ4lÐėÃfxÄĨJ—æa™‰.]š9}jôï @ĩŪė,™*;›§ėü îÜą#*2jęΉøÎõ6Úšy3ûKĩiÛĩ[wTW­\™üü9ĀĮŋf~ŠXĐ"ÁSęr™ĸŸëŨϟ;‡Ncų–­Z:yōqBBš5Ą^DDÄŧïÖæ(Õ%2+ę Û·wéÐnՊeK—,&8PŧNÝ={]ŋ~íÆõë9ß+WЌĻ7Þč―ũŦV =yâąTõŸ={6mōąŋÍ{øðî*ņŒÏ mDDŊøJ ",ÍÁņãĮÚķiÅ* 5fŅęÕŦ·iӆŦ )bģ‹Ķ˜EΆ­9y Q}†Č• ĩĖ2Ŧ0W‘JČRiĀ>ūHbë+°ÂžJÜ6þĄUŦâŊ]XÉy°HÄvÍŠUļ{”Ĩjũi­H€’C<8&`™MeLĩ+Š]’Þïã|ðð>zĩĩÃëīhŲōņãĮ/œÏĢŌRMĨÖÓúóĀþ ëÖ#ķ°vÍŠŌĨK·ïØđxņ+—/Ą*Þqņ\åӧϖ,ZLÓrŧķrxúė)Sųø:ņÅÁ-[ķjÜĪ åjņwãĐ@KKK̆ļ`áÂhė>úīeëցÅЄLIyÉMÃnžløČ]sûĒĖ`3đ\vĶZīhŅ•ØŦÞN'·öüųS6Åōå+@F„æ“―&þēmëVę’q]ųZr―rŲ<1ŧÖžÉf“-ģĖē\V˜K^­6—ÍĢA[‚īŨ–æ]šûSjūS“―ö۟t ]ēxŅýûņ%€đcGŽ(R,PģĩĪbđråjÖĻ…É H eT°•mæĐV-Žf°î=zrōö͛þýwëĶMs~™ËŧöėÞýāÞ=―fō ČĀøŦW.ŊYĩ2Ŋŋ?{mļœÄ’’’zũ鋔Á?ĸÜ$Úð(áQąĀb›6Ž‹ŋw/ĻxPbÂãråĘĘIO3EŽŧ{ŨNĪpũÚÕŦ'üË͞>sú―ũ›ōÞí[ķÔE'Ē]JJJܝÛxôZf’ä€ŧxōø1ŲŊ%`―á^üÝâ%J>}ō„ōbSĄË*ĐĐ/„ãĩØX„%)AÆ ČßŦoBÛ{vnŨ$7ūxķd/€]+€`™eđ0€ ÝĨŽ@šsŋÆčæ"u_9Á,Žĸ€Al‚……UŽ^8}ędą.˜w7.nöœ9[vîÜē}g˖đ23ņãH5ݰmûEīNXŧz•Öéz Mpüð‘ųŋýÖļq“―=æØŅcÛ·lĒ@āĪzpíσRSSí˜CōOWŊX~āĀBšÛwîÞī]XIĖôŌŋįΝdgNšvõę‹ĪĪđ?ýˆFâōUk؞Zŋikå*UÄg”nvøMÏH?°on,ÜßŋoŊŊĸã„Ä#þÉ:ũïÝŧw56=>þ.Xtxɏ]w !|Ðaļ{įÎÏs~Dwåęĩ[ķïZ―v=I &LÁÍJ™Ëĩ~íژ˜˜/ĮOØīmÛæ­Ûŧ~üIŲrÁã'L2lŲ oīhLŠä0ĻËŊe–åFģD…MōīOqxīÚŧÛÛÏYˆĐiüŌ86!ņbá(~9mņŅ{óũéģŸ! IÄāZė•ysŪT9ôČĄƒČ€å-ŋĭiĐ)^Nï‘ÓũïÝMŽT|\Üņ#‡ŦŋŸ‹Iģ]=â%O/O ĖQD‘”ôlØ þMšžōöÛîß;qü8Ý€įįcÆĖ*õ(!Át”9ļ‹ÞĢģ‰Y§OžļtémÚĪ_vÕ|ōÔtaWŪā_”Ö36ŊMë֝ /Į˜Ë[-Áā@Qn™eđÏŽ. €GKēë9Ō ,l…―@!ņqAR8ŦB_Ķ:Kæ(nXŋ”ĀJž<†{aR‡§Nœ Ī@jfzÆĩëąŌ"W„―ÝŸ9 5î)4ïÝo@‹æÍ+VŽôãßŦu"kŦ=ĖU4ĀN(vë֍ÐÉÓÖģNooĪÂ'&ðxOę+KS.qûöíļ;w>Ž„wíŊcŊÄ2đé§ðåÄɍ7Æó]·fÅœÅo}™úōÉÅ'\Į/^$Ø%tāãëC‰ÄÝ;qž‹Ëƒķ·oÝ​á<ÝŌn\ŧFhÅh~ģtėÕŦŽÂ qådqY;ķmaYÔ:Ęđ„5Dh†e4g™ËĢ€Xŋˆ[f™eđ/ÁtÛæē˜cvĩ4ËCĩ―ĩs‹ÍÓÛÛĐ[@’)ËyˆËpð?HĸĐS'ŊßļÎy°b°™ÅĖÆŊÛԚįnÍ/ŦRđ2%°“'M  ˜ŅldéqĀŌā^dÂEÚK]]LĘcmj,Álð‹cø ė8f—aSĐMæUš:ūxņbÔðĄkVŪīygY—ĩaž9ÆFj­ķ°”īވЗQĒáĸÐ\ûāĘŌRS§$†û T―ôše/§Ņ—á"9–”5îT$nM^U‰Ž=,ģ,7šÕœ\MËþw,2ŽĘ…Đ[ÕÞo·16LðgšĘqųÁĩ;røœŲ?°­f„Ė.ÔÚBg·ÐþkÍ,pÓ%&júôî]ŧ,˜ũŦKËąīFVüA|FƒQ°†MȘį·ŋfl+bfŠˆĩ_§:3~Ŋ’yębPŒX9nQbΌۑ‰1 ‰ýĮ܈xŋŋGÍŌžÞWHŠļÕД2Ōd‰ đ›`DÚ%iŊeûđ/ÛϰGBc\Ũ%ÅÞŧg DÄZŧš-æZ”š'âŪ@Ô9Ž\Câĩwû7k%‰'GØ3=ƒ>üĀ7ė™)áĨÐˌMx)Ŋ3=Tf>­ ŧ›Ũ9Z‘kW ÖZšĶkōN3O€ĐôLwGƊõt;3R]23𠔜ëžAéÔņ83‚qúDf*@TĖŒŦ*’Ąßō•ī2 8įrÍï`Ũ>ï“+#cšŧ'#BQU "DˌĒôh1ōĸ~ų† îFøþ!ƒUE" Õ9ĄPÆ“ŪÅĐC‚fD^ŨåņڋĪïåâĮņáÃgē—1ķBÓmāņWuiïÕS‡ūŋ&05ĄÏxbe(lũX!Ý·RCŠ/ƒ„}ŠsŊ\yÕ;CRœ;Š]kÍ4€O:cāé=Ã=mT@Ï~z[3s{6Īߕųøķd(ÖÞšZT(0óĪ%q_nŒi‚”Ā'ŽČŪ&i##Nh š=kî ĀL?ņq„ĘÃó=(@fļŪ FÄgäÃgcnu­\Į&Ó]ŨąýZŧšëtHā]EZ+O]ÝóϰŧŦî dßD%3W{&"B:Ũ‘k<Ũ`å&é›ï˜Ȍ•xæĘŪžqÞ­é3‚vï-҆Ēš[Ôoxë’ ėî6žŨší ÎđlŊĩũ~ÍLWIōøÔ)éNŦpfTRw‹mߋ `Øs]Ũ3įwf`XkũLUŊĩ`œ*ÑiûÓÕþH>|ēÚXÕ]S ffwßv[’NŨÔė―#Ēęx&#æOū ĢęĀQĄš!CŌĖ|Ŧ§ŦęHا€‘RũĘé~―g+ŧk0Z åĐS50Ÿ·ē@äJŨõ†ųÚŊsÝ6œĘPU=J É Į4šęT}?č›VČOR1ÕÃã9uÍL0 \]$#„BĨčjR(xųŠE`ėS%r8ėõZ‘öØP„‚ïũĨGūí2ðÚŋę”Į?°Ŧýðá“ÕēŅ0ˆq CÐą‚fũDĘĀŨû-‚;m'Ä\y―/ˆ#ÖđÞ6%ŊžAŅm’!éÜųl*$―Ŋc+Öō`Q™15KJfWa°s:ኈĩ‚Ðã\Oh§âšƒÝËpÏāIÄšvũ€ÄŠõ>oQU’2Bį\ä“R$ö^į:ä]LœۙYŪ3īâ{m)ŦNÏÐDļí`°Ïą"{Š?>Š%ĶGō+_]_$r…åĐøīŦό+­ĻSŒf\_—é;yĀ9§N?ų†āq{D(ã}]·s32Ï9$ÖkOW æĘéî1ȕŲÓmgjÆU_ķ3böąđ_Ŋé™Ĩ–ōôc­œʕ …ššbfž*žS‹ûgnvŊ• ŠÎÔņ-랞r.z_gĶĸíŨŪÆýīíÎ1f0œŠŠ(” ]ïw>ąBĻšh)Ā9'Ļ•ųūÓB‰ŸČ‡ŸÝb€īÞį I4 SĪpCi­íē§§ŋÓI+2pĮš]{ŋâŽ5oqŦ{@ ewŲ†TÕEņ>Ą ŠĘĖžŠn;ŨĐSÝI†ÔþõË@wyu+O(Ū?{h^įǘJ§Îģģ`f0 {Í4H†DžëāÉg1PüæķķIR‚ ;W:ïėĩĶë0°ũ>įôX’2úķđ2"â:§šALÏī )tšmߙL ?‘>YíZ~ĖēW(šĮÃP€n[Tä`)rÅĐ3ã―–R§/RkoÏû"5ƒČŽs0ž]ĶÆĀ!ÓÎČ:įų‘+ßŨŨīƒĒxÕ!4ęÉ|-ӍŲđŧjÆ0Ĩh·ŋ‘ÎmâĖžĨ7ĖsŸš·Ų;ĻĨ5ãžn Āï­hÓ+ģŦk*3RqŪÃ{w2Ā™kÝĸ EÂūŪũLï•$kîmĘë—ĀŪđϏĐ&œ+ôM|øðávĩíŪ.(Ķ}Ķl‹ęŪz_°CqūūšfDØîĐiũLŸ†™qÛðŽBšjô€†xęęïąŦŠOˆ˜îë:=ĩ2ĘeXĄˆ8Õķ)čØ2aW]‘Ė\Óãn€ŦgÚk…ĒęôĐ―WŨđšÜkÕ@ ŠpŲ0náwȈļú\ŨbᯠāĩwDž*{h‹O§ŒûŠ~ŸC)"žw3"bįŪsŠ!Fũt_ÓSĐč)“ũ9ôtw@ü4>|øžė5=ÖÃSŒg‘ZGFf䊩:ŨYđV&mûô™&MēĶĶ;33Ē{”ĖLBld,ÓîĄ"#ŧkfB™į:}:s5üŒØ3ÝՆénÝCbÐ4ïj0Œ_kũtU{:c™1BI°Šó7 B”1Æ<qU ĩÖ>§lˆ"Q·g§§gð#S0žžŪũx2lũĄ=}Ú@(<čc)3Â0>|øðÓ„PdŪsI1lW—2VîqW ßŨûIQÛ3€0zڃˆĻŪŠËö^{f|Z B§ŪЊČPžÏŧNg&ųí› sUõ^đ_Û6ČLŲøĐ`§Š§ KšiĀAŪ\UP)Ũû==Auß'DŽ―kJíđ‹'És•Ë+sܞąŒSõHpeޑqEäãtÛOÃÖZgj`­ĪqšLÓŧ{2%É3’R:įzŸ†Ï Aü8>|øŒ›éąm."\ÕĮŠŠ[’ sŠ`fB°a@öīK ĨÂļÖūęōXkĨTUBáš<óÚ{āӝŌÞŊ{ڀcp|Ø{Ųî>Kä9‡"kįõ>†#Ãöû\wĩ_ÆØ^ë š{āPęN{CĀÂõõ†ąr8už7^Ïõ.L@ŋ‡@vÁˆP ŠŽĀ{ÎõIąg朋`ÄšÞoSY}f,IĄŊũ{ef.ƒuΌ―^Ũ)ˆ;6Iũ>|ø‘]-Ĩ™‰Ėé>Ũą_ŧ{HDæZŦšj*2"8öØŧb˜nOߒŲÕRëÏ+Ĩ zšŠöÞcOOˆĪzšũeQ’Ķ:eą2ŠJðZ;Ÿã3{Ŋ{ņž„NžQ„€ë\Į#ĘݞɕÆ-hOFÚiįZ{?ųŽRëŠęebͧB‘Óm˜VæúÞ♊ęšņĘ€\Д„s]†ũëÕ3‘ĘH=͐müD>|øĖŦœ―‚øØ˜äãÖČY§žÜSÏ6ĸŒ˜Šš°Wž>“|íWu“°ä9ÆđwU5-*W>6Ä­§ûd’ņ4Ĩ”’|ŋߑŌÜåÝxžëęi1<0 €Īís]RäZŧ!DDÏũؗĮ­”"cėŪ’ôZŧŧ)Fnwï\É'$!3“äéÀ3Ņݙ9]6"ģęRFBķ=CJDWļ^ŲShĻEР93øĸāðáÇĸðÆöŽj ^ŨõïĸŦŧŨĘŋŠ`K1=ÕÝ·ĐĒŧŧš’BöģfWjĖ0ôŨŨ€ˆ pþþ=“Ĩ§ßįxšËSWD†ō}wĶĒÖZ_ï/ˆ;ēoąöUûĩŋækš3ŸR#’āp’qČžéŠ―öŨ{šāĘøĮ?þņä‘ņ á/w7îĸƒŋÎ?ï‚TätW·Īļôôݙ9·ÓĮũĒÝRĪŪũû™Ë3Mτôä$U-b­Õ3uk­þó2óWŒw.ƒûįûųĮÂĸƒíŋĸýĸú”dwãÇĸ5ˆČųäŨŊ_ĸ9Š=UĸíŋĸsŪŨëOERÔ9IĄĻ)Š€Qu"‚ āņŒ―rõī kn>―aO$1ãïÏįoYæ]JhP/Nl+Þ{wC―TŦÕï—æ?eLEŊÅyņĢy]ŪÜ?·}Þĸ+q=Gôf_ŊÄß(%z6ožŽ3SEH~=ąUŪŨj[ޖĨÐ0ÕÔMsļĐ69`MBʀ‡_Ēø?p@ŠR- "ÕHĩ@АjžĸJ9žČfi‡j{r€âËý~ŸįđN\ōT[XŊŨkĩڝõöú8ëõZĮËÎéŅŪ­VŦÓé\ŠÛ-ÅķSŦÕ*„ =CR5v€R―Ýn§ąÝív5Ū\ÚÎįóņxĖēL+Û*øÛ$u:‹EŧݍFŠđwéņÞÏf3=ØúýūY*Đ_-—K=TÆãqĢŅøßP§ÓЂėõz:R˜ ”ŸŌn·[ $ýSd%ēØęL{ØYí–fûĻĶÚęĻøJŦgÃmš|m6›Âd2q ûbïĘ̚šŌø}/1B$ėûĶ€ÅasCTP§hĩĩh[ĩS§ÖŽZŨÖĩTGÛŠĩb[ĮĨgščT[­ÛÚĩHąî" ī ‚ēHØē'o―oî#mϜ#I1p°Ok14^*.Žlę‹ *dpÆĻaūrÛícļVŸ9Û5&ŌߝeļûaëøĻm3äÔÜÚļfyĩŅkÕ–8kõēé ‰―f1Œ4ęMPĪōŲï(ĘŽŨSĀSá!œý(þ~ž°ÓimøvĮ’O/›Ã―\{:ÕÓ&ŋī`NīJΟâ<Su^jtBhû™X]ÉŨGZ\Ģ'åfúĘ šĩ*Ī,Ë`ŋĸ­ŊVåÄēKĢ–EĶŽ§,>Ŋ žœ‰õęō–ĸĩÂ?Æ1ŽH$ÖÚĖ<ÐŦƒĀö~GüĒø”æÚų†‘k–ŒsŊ3wĐjČ žiĐčī?·ĩlïđÆÅݚvž“ĸÍÕ:Ũ„ŨVü='%āęMEj)Ųvĩ°ļþ™,›™NĩT}ĸjá5sĘÄEyËĶũôœíZ "!Š āĸ1€Ā„‹BĶô’14?H !8ádwIqą^ų؟ģ#+Ï]˜=mīTÄ7xÁÅÛjĘū­Õ5‘AđŅþŅ L>L)ųųČᛠC|åŠŌc:E|VfžˆeÜp9ŒctĨĮŪķYüsbƒ!Ãrý[āöÂÆ1BĮÛ Ô^pÛ(ųĈĪŪĘãóŨþ{áŪ#ýüõŨĸ{ðÍģ_îiũLŲŧ{fĒ(·Ü”čvIÂæĩs|$pČȧūZžþ‡õcvl:>åÄB}cŲĮųŨŨm}7wJėYŪJ]'_ĩ:W)fiց N_ĸ€5å E$ā …NČz2UõuEÝ­Ķ}‹Žīfė=øvÍĄ5KfžQą_Ũz1į9ëwŽÚ·vÓgģgÄï_ē°(döáCió§Í;˜4xþ„Á6?čJĩ&H­ý‚5zēuŊŠa_―r,opŒūvų‚Y/7vvK2ēâžUĘĪAáM?ÝT›‡‡Ép8Ž·ūÄÍ3(ČÛPßXY{wô YŨŋT˜šLī c1Õu=ŌˌĪ0І`0œnšrâŽü~Ũüy·į,Ïó öëÖčé'1uĩ6•mßsĀÐŌI{4ë(ÆĖÉO/]ôŌX1CúúøjÜÃ#BEīžäœžķY ėļ0œĨI†/ĢEó%ąiHĩ§šÂ.—™ëž ũõ˜ýō›‡įU6ë7ü…5[æåī^“H*ī­?ëš;îX0ĸŧęÆî4#A‘$Ëē{[Ú BTˉÝäĪVÓØÐæŸė:Ũī·j˜ĀDzKéM@ģÅBū$2iaœĘāð”ī͝úĘŠZ_“öĶÎ+35ĩÖØÆL$’ļÂ`02PÎ24Ā9ȉUAQ˜Ķąžō†WZŽĀþDĩČĀnT‹@2ŽęɗÖF{vݖaãÂc΁Qųۊ”pOąDæëKŸ8ī?đ苭ëŨ­J8z2f ÓÆ‰ÄuįömøgÁ;ïxį‹ŪÏęøĖ~‘XI3!A-Åņ^\ŋ†›‘ƒĻēp\ aωÏ6ĩ0Aéƒü$ÚnßéÆDbcOĢÅ$r–æR1bGfŽqsĨĻøŒgWÎ!āâéãk­gã˜ęƒLö @Pa(õŽÉęWvödaÉųŦeŨ[ÔZ\„KޑQW/œŋxþLqe‹<:ŲßUÄ+øēæ_ËN;^Ũn  8BŨÕxŦĶUK·76Yå°ĮTŨ/•Ÿ9Wzöâ]-iZðXÖĻ”žëEŗĄ9fģEŊ‡ĐÓ>7ZŋxÉô ŽÉCī‡,))þâûŸŧMækg|räTŦžVxûKq76ŸÜĩ― ģ‡Âô͗Jū.ŋpŧ―úōõj5b“‘âøAd\åãwý|ŅîhYėŧ€ 9uôÓ­[ÞÉ[ųb~nÁÆõąģģĮšŋmįŽÕëvE ž™âN&“…äõ™ƒAļÎ|jË7‡Žž()úþËōæN sBŠjĘýÛS[\;|’"ðV[‡Æ`b†Īö ņ…ļkĘČ ÞMM=‘”>.2<ð·§ÜĮân‘Ūģ í čĄ!!þáËđ7‘@ÆOfą°YŊnðIþá\MGâ”7ÖædxēDüÓŦ–ā!C(ĶmË7øplĖō7öŒ8VZÖÄÞ Yï‡`@‚Bd DA‘që­xÏą YÜE>0.ðš~@ũwkL:0üëctĐįāD%Ú ác^ÔLdL:ą,B#pČ24T…DúXsø'Ë9䍋Ũļœ,†"štņ‰ž:=Ž",,üĖ /Ģ3qŽĩ3ü•„QČH“$É2#wî2éÅŅ8Æ2 ž<ŒĶ)Ž‹d ‚‡đx=žû†AŌBÂþePá8nÏML›:1q8nÝĒH‚ĒÔ(ÃI’ÆÏJžĀ!A18 -IÓRŋ؜I8"FQxė° #8€á4iĄYĮģ…ŠđôwbnKKKpp°X,ķæH=â8ŽãƒAŦՆ††ö91·ĩĩĩĢĢ#99ŲF簃öï•kë†uÛšyï›{ą3uĩ^ŊŋråJFFFŸsFcyy9:Š,‘ Ö͜ðÃÆ‰6xÚ ŠšÚJÆųĻV€8ŽĢUfPĒT*Ņú&þã;ģŲŽŅh<<<úÔĄBĄhhhļyófXXšp =čtšššībVŸÐôČårde]Uį!R­ŪŪFT1 ëŨr3 iý4, „°Ou{XŽ­ä$CžžžvîŊÕjuss3ŠY–ĩíŅCsA"‘øųųEDD Iĩu""___ŊŅh†qڅþSEŨ*Īģ}PuBj`ã^ûQ”Zī_$ņGe # 7æšpļ,Ó 'r­þÓÞœhƒþ‹°ÁfÄsŽc ÛÄüKïU\>!ųŨĢJ-ØŽļų%äÂ+|6k_Ūĸ[ АZĐ@jĪ€gfvũývwfžŠ:įĻíįvũœSUODdfwŋ|Šŧ33"þFģ|jũËIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-updating-components.png0100777000000000000000000042421513761647206022411 0ustar00‰PNG  IHDRÎb88% AiCCPICC ProfileH –wTSŲ‡Ï―7―Ð" %ôz Ō;HQ‰I€P†„&vDF)VdTĀG‡"cE ƒ‚bŨ ōPÆÁQDEå݌k ï­5óޚýĮYßŲį·ŨŲgï}ŨšPü‚ÂtX€4ĄXîëÁ\ËÄũXĀáffGøDÔü―=™™ĻHÆģöî.€dŧÛ,ŋP&sÖĸ‘"7C$ EÕ6<~&å”SģÅ2ĸĘô•)2†12Ą ĒŽ"ãÄŊlö§æ+ŧɘ—&äĄYΞ4žŒŧPޚ%á̌Ą\˜%āgĢ|e―TIšåũ(ÓÓøœL0™_Ėį&Ąl‰2Eî‰ō”Ä9žr‹ų9hžxĶg䊉IbĶŨ˜iåčČfúņģSųb1+”ÃMáˆxLÏôī Ž0€Ŋo–E%Ym™h‘í­ííYÖæhųŋŲß~Sý=ČzûUņ&ėϞAŒžYßlėŽ/―ö$Z›ģū•Uīm@åáŽOï ōīޜó†l^’Äâ ' ‹ėėlsŸk.+č7ûŸ‚oĘŋ†9ũ™ËîûV;Ķ?#I3eEåͧĶKDĖĖ —ÏdýũĸãĀ9iÍÉÃ,œŸĀņ…čUQč” „‰hŧ…<X.d „Õá6'~khu_}…9PļIČo=C#$n?z}ë[1 Čūžh­‘Ŋs2zþįú \ŠnáLA"Sæö dr%Ē,Ģ߄lÁt  4.0,` €3pÞ „€H–.Hi@ēA>Ø A1ØvƒjpԁzÐN‚6p\WĀ p €G@ †ÁK0ށi‚ðĒAАĪ™BÖZyCAP8ÅC‰’@ųÐ&Ļ*ƒŠĄCP=ô#tš]ƒú Ð 4ý}„˜Óa Øķ€Ų°;GÂËāDxœĀÛáJļ>·Âáð,…_“@ČŅFXņDBX$!k‘"ĪĐEšĪđH‘q䇥a˜Æã‡YŒábVaÖbJ0՘c˜VLæ6f3ų‚ĨbÕąĶX'Ž?v 6›-ÄV``[°—ąØaė;ĮĀâp~ļ\2n5Ū·ŨŒŧ€ëà á&ņxž*Þï‚Ásðb|!ū ߏÆŋ' Zk‚!– $l$Tįý„Â4QĻOt"†yÄ\b)ąŽØAžI&N“I†$R$)™īTIj"]&=&―!“É:dGrY@^OŪ$Ÿ _%’?P”(&OJEBŲN9Jđ@y@yCĨR ĻnÔXИšZO―D}J}/G“3—ó—ãÉ­“Ŧ‘k•ë—{%O”Ũ—w—_.Ÿ'_!JþĶüļQÁ@ÁSĢ°VĄFáīÂ=…IEšĒ•bˆbšb‰bƒâ5ÅQ%ž’’·OĐ@é°Ō%Ĩ!BÓĨyŌļīMī:ÚeÚ0G7ĪûӓéÅôč―ô e%e[å(åååģĘRÂ0`ø3RĨŒ“ŒŧŒó4æđÏãÏÛ6Ŋi^ĸž)•ų*n*|•"•f••ŠLUoÕ՝ŠmŠOÔ0j&jajŲjûÕ.ŦÏ§ÏwžÏ_4ĸäü‡ę°š‰zļújõÃę=ꓚūU—4Æ5šnšÉšåšį4ĮīhZ ĩZåZįĩ^0•™îĖTf%ģ‹9Ą­Ūí§-Ņ>ĪÝŦ=­cĻģXgĢNģÎ]’.[7A·\·SwBOK/X/_ŊQïĄ>QŸ­ŸĪŋGŋ[ĘĀÐ Ú`‹A›ÁĻĄŠĄŋažaĢác#Š‘ŦŅ*ĢZĢ;Æ8cķqŠņ>ã[&°‰I’IÉMSØÔÞT`šÏīÏ kæh&4Ŧ5ŧĮǰÜYYŽFÖ 9Ã<Č|Ģy›ų+ =‹X‹Ý_,í,S-ë,Y)YXmīę°úÃÚĚk]c}Į†jãcģÎĶÝæĩ­Đ-ßvŋí};š]°ÝŧNŧÏöö"û&û1=‡x‡―ũØtv(ŧ„}ÕëčáļÎņŒã'{'ąÓI§ßYÎ)Î ÎĢ ðÔ-rŅqáļr‘.d.Œ_xpĄÔUەãZëúĖMŨįvÄmÄÝØ=Ųýļû+K‘G‹Į”§“įÏ ^ˆ—ŊW‘WŊ·’ũbïjï§>:>‰>>ūvūŦ}/øaýývúÝóŨðįúŨûO8Ž č ĪFV> 2 uÃÁÁŧ‚/Ō_$\ÔBüCv…< 5 ]ús.,4Ž&ėyļUx~xw-bEDCÄŧHČŌČG‹KwFÉGÅEÕGME{E—EK—X,YģäFŒZŒ Ķ={$vrĐũŌÝK‡ãėâ ãî.3\–ģėÚrĩåĐËÏې_ÁYq*ßĸ‰ÂĐåLŪô_đwåŨ“ŧ‡û’įÆ+įņ]øeü‘—„ē„ŅD—Ä]‰cIŪIIãOAĩāuē_ōäД”Ģ)3ĐŅĐÍi„īøīÓB%aа+]3='―/Ã4Ģ0CšĘiÕîUĒ@Ņ‘L(sYfŧ˜ŽþLõHŒ$›%ƒY ģjēÞgGeŸĘQĖæôäšänËÉóÉû~5f5wugūvþ†üÁ5îk­…ÖŪ\ÛđNw]Ášáõūëm mHŲðËFˍeßnŠÞÔQ Q°ū`hģïæÆBđBQá―-Î[lÅllíÝfģ­jۗ"^ŅõbËâŠâO%ܒëßY}WųÝĖö„í―ĨöĨûwāvwÜÝéšóX™bY^ŲÐŪā]­åĖōĒō·ŧWėūVa[q`idī2Ļē―JŊjGÕ§ęĪꁏšæ―ę{·íÚĮÛŨŋßmӍÅ>žČũPk­AmÅaÜáŽÃÏëĒęšŋg_DíHņ‘ÏG…GĨĮuÕ;ÔŨ7Ļ7”6’ÆąãqĮoýāõC{ŦéP3Ģđø8!9ņâĮøïž <ŲyŠ}Šé'ýŸöķÐZŠZĄÖÜ։ķĪ6i{L{ßé€ÓÎ-?›ĸ|ôŒö™šģĘgKϑΜ›9Ÿw~ōBƅņ‹‰‡:Wt>šīäŌŪ°ŪÞˁ—Ŋ^ņđrĐÛ―ûüU—ŦgŪ9];}}―í†ýÖŧž–_ė~iéĩïm―épģý–ã­Žū}įú]û/Þöš}åŽĸ‹úî.ū{ĸ^Ü=é}ÞýŅĐ^?Ėz8ýhýcėãĒ' O*žŠ?­ýÕøŨfĐ―ôė Ũ`Ïģˆg†ļC/ĸ•ųŊOÃÏĐÏ+FīFęG­GόųŒÝząôÅðˌ—Óã…ŋ)þķũ•ŅŦŸ~wû―gbÉÄðkŅë™?JÞĻū9úÖömįdčäÓwiïͧŠÞŦū?öýĄûcôĮ‘éėOøO•Ÿ?w| üōx&mfæßũ„óû2:Y~@IDATxė]€EÖþvf6Ã.,9Á€ųĖs=ã™=ã™ģžžáĖ9ž ÅH1’EP$į]6‡ ;ĸũUσf\ŌwįiĖvuÕŦũ^―ŪŪŊ^UuwƐ!C’Mš4AĮŽQPP€ôL&‘‘‘‘ž ĨoLð—mˆWzšņõ—K—ĢžúúúõJ§]ŨđÉĩãščŌӍ>ýht–nį{\WđõĨo oŋ╞Ķsđ†äĪ—kˆf}iVގëĢõį}úŅh,ÝÎ7öļŪrëKßÞ~;6Ä+=Mį þr#gC4 ɑ š?ū.~FģĄcCåM^CyÆ/=o}éFŧ>ū–į?Z9ņV°~:Ģؐýuí=Y@„Ũ<”äucšŪ@}Ē™l ‘PŊoÜÉ4ūĶs(æ,Hą(ó™hú›.Ēk(ˆÎoĸ ^Û0/],žøđŅ*Ãø{ņ2Đs&Û?’õˆÅbHÔŊ čĒ—.VΓĢ6åīeûbûŊ)·šÎ§ŸÕÅōĖvnzųé,nyŠŦŸ^éĄH͌Œ8íltþrf+grWóĒŽšOÕâëUGÚ N9b§4?/' •&~úéÕõSðÓ*/ý|ĩLGíŅ›^aՃíÆęaüLŽx­Žâeü-ÝhtnqŦŋÉöÓĶ—·r’íÛđņÐđ?Īëb|EcōÓåúyųó,nüýt–fu­ņWž_ŪōŌÏÓyã›~ī|ãeš™\Ë·rvî§7ýLķņ­~ –æ/§tË7ãĄs°rJóĮM†õĸĘ·4ņR―~ ĘģļÎE#,ːĮĐ#^MȂĨK—âëwßÅlj/-AļQ#4íÖŧu4ÚvïūCņð‡ŠŠ L›6 +WŪtĀf'Īiáî,ŨšukWÖ_iSNĮe+–`ÄØAø~ŅwĻŽ+GNf.š4ïŽCö< [tęænÞoN 2‚ņ2ýuôĒø*͂›\+oų~ž–ĶĢņOûÏMķņ4YĒąāŨEiĒ1:;­ĸhō­žhÓCC4–æ§ĩītŌÛ‚Ū››^:Zščüķ2ž:jā•ŽbɜŸP—ÕíÛĩBėÜ*•K`iušīGÁÆl%~Ąúš ĖYVí[#‹c$“íō­Î<†P)€XKķC$Ū-[ŽU!īkÝ!jâāÝþz+îÎ3ī‰J|?}2,ŦFf“VčĩÝ6(ĘÉ xð&"_‰ĐW†yĩXž`*ĢâC(ŧ1švîĖķ+ik:mgņ°ÔĮ L^ÝDĨ |ŋ-ŌíïQytF/ŽîĄ$JÎCmnKīoֈzŪĖŠÆ‚Ó›'VÎd*=^[‰… Ē*Ęv Ė+â}ŨYa•ĸe{O773Ŋ?ý5EÛ`í Ŧ`ú‰ÎBš.:ŨYzŲ9Ģ+æÍG4·Z·h,Ģþ‚ņĩšøy[žŌ,nĮô~Aé–'=L7ĨYÛ6>~Š‹ÖĘęčVÖøųóŒÖʛýÆĘoĸđŅø&Ģ!zKkˆ^iĶ‹ŅŲ1>=ÝÎýG•ą:ųuRýTĨŲŅâ*c<”æ/'Z„‹Æ‚Ņčheýųé<ýåDgīV~Síūøâ‹oS!ýÄÄâÍŅO<†‚ŸfĒïĄcĸsÎÂ6íÚ"úÝ|ųémą Zīäh<ššŒ”‘wĐEÔ/ŋüŌ­›îēË.Øi§Ðķm[TUUaƌhÜļ1réĩ*Hž ãäó†YJÐ|uČSĻČ^ŒŽ8ĮrzvïŒK&cĖØOÐąeW4iÜtĩLÓW<Īŋ~ÆÏņLĨYšŽ&WGKŨđŸ‡ęÕŅôsK7~–ož”ï§ņĮÆTūŋž:—―ÆėßŅøë•Ūōüų*c:éhņtŅ)ÍhüųÉú þûxeÂrlŋÓÎ(Ę ˜JðÜcaČļÅØí€ÝŅkDÞJ’ðZ·ä[<úô—čđkO}’+ŨmŧkÁAÕŋ1sþ*4)lL0S9ÞXԓhvø\“X4n8žģ;õÚ™ė”―:xmĀęcķá-dÍ2žôėøáwhÔŠ1&ūû6>ĸa!ZmąZæÕã§éÓQ–Q€Ķųaį Éþė P1^yėLZ\ŽÅsĀË+ąÕÖ=Ð(‹mĮé”jëîz%°øį™X\žDģ&yĐk(Ýdoï^\ËöšPĐúËkwüx§í§Ë čg„ęņųsá“šŽØ} Þ'’M[)$žwïNR?^?ņqu)Ÿ;=ōf-+ÃĒ9ßc^e[uí‚<ÄN͈7öŪ}pv!ĮĻ7_ÁžŒVØaŦöt%3Õ>XD6Wûð‡mĒôĘ⅘ĩ° ‘‰aÐKÏbVžÛtnÅę{ú‰ÎŧūŌÃŧÎî:2}cÛŋ_ÕE?édíÖņcšŅđú’ŋĸÜĘøË+?ÆŌ,]GãiåuītÅÕŪŽŽę%ÝėÜĘč\qKũŸ[šÕÉĘ+ÝâVÎú+oų&Įx)_y~=untëģ:oãcåuīļҚ<íg4V“­ô†h,MGŅX°:YyýõZŸýÅ'b Ų%@ņ™Ģ?Fîī)8’ ŲŽ 1ęįĖŅļmwÝ ‰!Ã0cð`4ãBĐĶáÔĻe4Mi)Ė!­xlŧíķЎ])ՈÞj=PWW‡üŅĨkąUÁ*§éŊ'ÁRü„Ó=íÛķ@Ž~9åįãāÂ}0 úŒųv(ÚķhÏÔ+Ŧō’­`Æp'ū?ʗ U_Ģũ‘ļĻÏ譌Ž v.ōütĘ7ūFo6ÕQACq“ãųGôFk2Œ‡É­ņWyš•‘ý-nåuo+ëÏũÓXšäXšédiâá—m<íĻ<+Ŧ2 °H$ŠĨÓgáĮđËÐđy'”Îų3gĸ„úf]~uu)–Ŋ,)ŅĪysäŌûhū.ūĒ;šærMĄŠĩlóĄx%J*âhÜīE…đXðåįx~z įŸī?Ú6o†Žd V—"ž Ģi ōáekąÃ~ļdû0r(uÕՈ2/#ZŽâō )Ŧ1AYzŦí…BqüðÕ|öõ \pŨ]؛ĀSÛ{gÜuå}øpčVčx\O }é $>§ïÚ yy9ÎĸrõŽÖ!\Ô'Ÿķ-Ę@#ĄĪļNKWrÆ&ÉGģĒ&ˆDWaܐgņCrœvĘŅhÓ4IÎŽ,]VŒŒœ4o֔ _ÏeŽj°ĄĄ’Ņdv  Ä(1ZVŠšp6š·h†:ŪÕå•H4kyĖä rÏ3.ÂN™P§iðDJVĢ:–@Aģ–hœ›LzĨ+—-E9―ãæ­Z!Ÿ.―BīŊY}īYvÁÏ=ݛōūNÄPūj%Jęsáī7ëVÍ„Ų8Ð(CqY=ė|ę]Äå{ēōËiv$ã([U†ĖÜ<ädsIĻēQd!:Ԗ— xU9ĄL5Ga~ĶMøĢ~áøCû sŦF8ļßŲHryÆÝģŽĮō+QMĒIģVhÚ8 qęYQG'%+‹Ę-DģÂ|Î,ŽiÃjéíßÚЎþ6í,ĸØ― <‹ÛŅĘØđĘŽŊýûóW]ĪĘ§ņV0­ékyÖĸč\Áx™–f|Ä#=Í%ĪþĻžhÄŨčt4~éüՏ)ÏŌuÔđõĸ~ÆÛÏËęcķīĢĘ)?“á?­ŅˆÞx_Ĩųƒå+msØ_õ˜0)ǟcÎcÍũÓ°S~6rįÏE”ÓŪÚ@ĪĩPÞīÛįfá“Ų3QËôžĶMW§ĘŠGYYÚīiãÖ)KKKČHŽÖ-[īhŸ~úÉ-°Z…ĖIŽ ”ýˆ=Z`eÝrÔ.ŪCV„7§ū*9ÖnëVXŠŲĄ4ĘkLũ.˜äšAӍ,Þjéé*Ģī†Ę)Ïlat–&^ĘS#1ýýž­œUÎllō”'>J· 4Ģ5yĒĩz˜<Ņûõ/?›K·ēĘģ <Ĩ+(n2oϜŸ‡•óëaü\ý 9MОIÆÏøûöj‰™Ófģ3mŽ,zpô™1ë‹á' hÚ0|>gņRÍ-ŪAÏ=ŽÁ9§îˆqï―†Ŋæ,%āâ ~'!cÆŧøūíá8gßøzÄŧxï›h™_îˆū;méß Į QSĖH §Í.8ý΃Ð4›íT·?ۙ›ųfĘĘY&fæeaÂOcZÎøsŋ=Ŋ\„_zŧs:ŠĮĮ”e%\^ĐBŊū§âŒÞ[ ^ũy…âŦðÎ+ŊĄÃÞGĒũš`öčŨ0ēš.=i/Lþl$ÆNË} å(Üæ0œŲ·+ĶŽýsJ3ņNpîÅGâÛw_ByŨCpÜÞ[bü°—1dŌ 8•ÞļŽ;ítäŧĸŦ™/į@ >'üé|ėŌŅë“ÔžÕ– tÞP°öjyjÓ֞íčOKÛ}ĒtýŒŸäZš?]Ŋ‚ŌÄßî7[wņhåí~6―DÓP9+o2L§t>*Ŋ |ĢI?úuPyãaeTÞŌũ‡_ģýĨ§ę°ĐöW™Õ§Ë*SU‰ŽųyČÓEÖČW2NāLDŅ&/MĘŠĢũ( Ĩ.ļĸbšETyfæiQUÓī:Šņøī ŊM#ôNZķm†Ũ”™ōÐč Ðk óži‹BŽĖŦ䆒:þ8Ú_ÓÎ~aņS ŧð:7C9ylī:úãĘWPš?Ū4ŋ,nG?ĢÕQAy ÆÏߘLŽņq„Đ?J“þþ›EY ņSšÕSųÆWvķ†aōEŦ`|,.YĒ―•w„Đ?–§Ģd‰Î‚?Ïä+ÏMÃåķÁ}·Âž)1ũῘ6g!:á(Løf›T]wëƒkûķDÅĖÁļũĄ1˜·Š7šdÔ QA:&Y1,YV‡/ŧ―B3pσƒą°ū7zõÜ““!œ/ðĢ/S0ŪëÓeÓáūG?Ã‚Ōƒ‘CþÕnÝQk”qĮįäËĸ‚m0 ũ<4óKũÅV…™īģęCYYôŠ#Ļå ”ĀNpáō@ĪbW‰š– Tbō7ӑđÅaļâŒ―Ýīi]ÉO:čct9ô\Ņ-Œ‡xãč†ķk‡=ÔŊžũlýĒIxûËéÍeâ ÃOGŊ}vÃā?ĮÜūŧ!1å,Ŧ낭:ĩÁ–MOÅĄ­ōņÅģcčėđĻÝŋģЊ›Áh9ōŦ‹W ĩœÃóv%Ņęč5öØûėvx#ޘ2’äŪØũˆQ1#ŒģN; Eeψs5#Žå?|…·ŋĐĀY—\=šfâÕ{ïÂĀápé!m[9y;õÃM—܋™?ÎCŊv…”ïÍ~Ī·ŧV܂âÖ)î§3-}cÚŋÝ':Z9íūÛ}+: ~zKóóą4Ek|šŨ•§`ōÔÛĀßdoG˜úcôĶ‹ŅĪËH?7}Dŋ9ėoōĨ–ÅÅÛä*Ýî—Ŋ:˜ÞvT9ŦŸŽ Ę·`rtī`åuŒhęÔOäÉ(§];Ô-ã=К-’\ˁn"2–/C<ī Ž`“T@k$ąTį.†R*//ÏņÔQ;i5%ŦF)YRRé:ĘĻ*c iÃDQĢVȌUĄiŨ‘2‹n„ZŪ“­Š• ĶdžSw-(#L~kĶ LâŌ‰ž•fév4øó,ÍôĻoȐŠĢĸ&ĨY9“'žþ t+k:ZÝíheUΟ&z5x‡h·z§ËSūãkGã­|\ųV7ÓŅhtTū~ĘS9+ŦĢéaåīæ–ä8ą Í·ę…úđS1üÃO)°öéØūĒwŦÁ“>ÁĮrŠ•ŧĻģ @ ÅØiššqgjŽ:ŽæÛĸ=Û ķļŲyžþl‹šBŒäd!Ęv•ŠÅŽIcĖĪEČŠ/GŒ>ęŲÞĻcn°ŊŸÝ=> ˆäĢiIöïŽja‚%ŨJW•Õē]sÝUK™(_ą…ŲÜč“ÁiH ĻâĻĐb9ÚAAŧÎÃÍ·Âɧž-›Ņ†äW]Á uų­Ņsũ]Ņ(Éfn&§iŲî9…‹üLBđëžš ÕŽc5ŨVßïĸĒÜÐĐóv%Č?”‡^Ûoæyq>c]ƒjÎĪuč֍'w%wėäįXÎl-›Y§mz€ŦĨžE9Ø ÝÃܔUU›ĢO;Þ‰Û―úŽ^MŠÝ.ų™_|ˆ%ßēþđP˜vģAšĖlķ§Ú:ätØĮũ;]ščZӀõÛcÛÜÏ0eĘ$TMX„mö? ™Åsņņð‘˜U–DtŲävßŅŦ›[Ôá ïoŽ„ÝŒT,ģŨ79}+Ģ™!ŽžžM―LĄC‡n§ËēeËp*ۊZð ™DĮĒn˜ŋr<ēŧfD›qCB!Ũ·ŠØņÕ –^G;NŅ‡]ÝHTNAuP0]<~k<"ËsDüc@G+ĢļęÓP09Ē1Y:ęg]4ÆŨOoéFŊsÅe‹ÛŅđ~:øY3[K?Ĩëg6T Š+Oå­Ž[YĢĩĢ••QžxøƒŸNévnt:·Ÿ8šģKŒŠ“Mąkŧ<8lö9öE*8ðâ͟Š>æ ė{ÎíØ):j˜óâ4ûāŠģĪļĄĻŽÓzÜåĘÎÝíHĨZ5\ŋŦĒWО‹ŸŽÃü;ÔLÂ}O §\OsVÉÕCā!˜–ģm†^ԏDލÏQ8Ũ ;tÜÃG~…é=:Ą'=—Ęe?cėŨߥĻÃ~hÄ5Æh] ĒËKÝŠŦ§ėŊÝÉmÎk'ĻFđ KÜį;PĘN(ŠkģÝĻšyááhīŒë dgæĄEA;œtîUÝŠ*+PUąŠ”\+­V―éŠŅƒR{Yšx Ękķ@õŽQQÕ][äaé’Ü [Så#4Ž ģ^‰hę›vĮÕÝ#žžïŒ]Îڑkŧ­Ņ~ßĢŅïĀ^\[­BY)õ =Ī›6ûđšD ˜Dk ôlYüîÂĐéŨßïXÓmpĶÜG>‹ąßEq̓Ũc΀‡1„zē+ã%gÛĪü$í W`ÉōU([<ãg-Bēóķ(_ü=FŒüĮ\w3šTMÄ#ô8c,‹ÕĢ’čYĮõâú,o`NŦrJŋEÉąŽĪmļĻ;mÎbtŲÄxŪ‘‡iŊÔÔž)—ĸÝ`^;Ÿ7Ôþ­Š•X;VûŨςŌÅĮŌ­7tŸX9ŅϜûų+ŪtãiyFŋūþĮøéhzĐžÝŊ–n5‰xÏB ”Č߁”:åP=•(Úuî‚ėQoá7ÞÄĄ‡í­9•ĸŅ?ĀwäÃ9GŒõvkÃΛ^ˆžRíekð:Vzeⓠ8$âäN/N^îÜLt7ąžóúËø†ü*–ÏGiĪ. ĸĖd9šnÓđÞ6<ŋö$xЃÓ pÅ\ zýy°ąd3ôî―ą™Ûu4ÆëĖ =Ü â<:vÛß üĢ)N>ū7]úžĸû-TfĢ°Ã–č{Ā^Χ=8pÐîYmīÉãtðŽą#ðŌēéĻ\^^―C3ÚKqí†ģ?šĒ”ĩÜĩĐÂØ0ŸëĶĩŦâØgߞČhÜG{ÞØw}1ˆ3YØýÐCÐĢ}ëBģą\’Ũŋ~É$|ðúrօšĢ?æ īíÔ MCĢhũݐE{ķëķšN§îý; ēĢÜ5#'wĶŨČ:ÓSŽ åsGlG §œ—gĩBGBđ‘5i‹.[4ÂĸxÔmōŠUŽÄ°ÏŋĮŅÝ8]üÉ{xãÕ œpōá\#æóÜž&Íšn‡Ã{MÁčÏc‰ItÄIûwãlÁÏT˜›ŧðQ.éĻ ēön0ÉiyMŦ [{T›WHoÖníŋĄvï 6P֏Ĩ·•ąûĖdŽ‹t2]EŦŸÝ[VÖęáįĄ2ŠŊŅčč§ģššžĶ“Î-ÍdûóLŲğnqÓÏÎu4Y7ū:*˜Žét–ŪþPņĸ–ýMõ[—ýþcƌqĩ‘]x+Ė)ËþĒ|6­záÄ8 ÓÃĖkÓđŧðĶāKUÔЇ‚øhŠV`ПëðHŊ4íŪXŧÆMچŒ˜Ã]wËĘ~æ4ŸGãĻ9+’‹fÛĢUÓۜŌáú(§u낸yøÓÍĘ7íÂ8&)>JSHÏó7.GĒQÜ_oãŦ4“į§1ųĘ· biĒ39ŠÛ œŪŋōLOãaiâåOSšŌDŊŸxúå)_ÁŸĶļ~ō ý:(.Ę3ųV֎Vo;*ÝÓ?Œ|n2‹s]šŪ>“;f3éÅTĄĶžŧ+đóR€–ÅéÖZN†ģs‘Ã.·Š†ņĖ°Ûą]SÁĒŲ9ČĘΠVã1Ņ‹0â|Î3ÉA6;âzeÜD–ËéؚūՃųŪ‹Ö02#|‘BĐāNŅ,N·fs—jwf*N―ĻK”Ālö—7ŦGĨb|ųF§_—ĸ4Ÿ~ý=ŨýBØbŨƒŅ{·îôî8'XęÎáO6QđN3{íÚë ãô&s]ÝcŽ_Ųųáīl ëÎÉ's:ĩ†3īCn~§iųĒōÍÍæô3=ŋLūôƒóšô$ëøō0F |ĩvÃáŧlIo=ųŲIŊ^ī[v(ÆĶQŠC^đ9ԋ`YĮq §akkŦÝŪŨžĖzzĐä•ߘ`å€īšvÍå#ÆAðšķâó”yÜmÕË'TGnSŨqm)ÞĒŊ Í#ÜI›ÅČÕô°óđĒŽ;mđߐŨ$ĒŠ8•šä@ ‡ÓņīpĘŧ7%8 _Eú\^óšj^ŦÜ|dpPUMYŲžÎÚM\ĐtÚ33'w5ņ’”ƒ„FÜ'‘āõŊŦW]sy ŦÝrX>’Qįôq—†ĘŦ/RÐõõ·u—Č?–Ķķj4*cũ’Ō­ýŦŒÎýAåíū°2vīþTų v4YvO)Ïâ:ZyŅ+ny&ێ*§ļÝŦ~>&Ëht.> ~þÆKiĶŊÚ°â–gzč<‡ø™Î&Ó_N|Ä_ų–įųĮŌ”nõ0~Jģt“Ŧr~*ŊŸŋŒÕÏęĢ|“ĨļhTÆō,îįĢßĪéV„ÜŊJŠN? S9 QpŒy.īēšz‹^Œ ļ•ÓA<ēø†"•ÍÍËõÖG9âŪâZžõ:&\dņI7ļøIÓQqĨ―ëĻ <ņQūĘ(˜NVŦŸōüžŽ.Öā”o:‰Îø_å+(OÁŸŸNŊsĢóëgt*kōM?ĢŨđŋž_–ĨKgãeķp*øå‰—Éąžtû‹OšLŦģÕŅdˆ‡âÆWž4Óģ—t!xĨŧĻh'Ō閗ĮĻD빔N‹mÄóõ†™l‚§<< ­4M*Ŋƒaœ+ëĐ-xŨÆíˆuÞ5‘ŪaęĶĮ#ŅÚëÔÉģÛĒ-ƒðž?–O%y~û[]eg?u@”œRĐžZĸ ˆä-Õ ļI {Ėģ“§·ģl*}ØĸL7qnTÚyëŽdŪõXÚ"eCÉ3û{Ũiuĩ e˜Ũ6ųv$îFÕõ7―%/,o‘6ģ:_é―ĶJžR7ģØ^âĐû˜WÄa]+Ԉ§l`ŨÔņaý#NVŠ2Q3XaĶÖ)žįU·ĩ‚xé…Ė“ҖsŨIr\=”Čļ‚ĩ-wÂ?žm―<ÕO?Õßß=Ž―„Ēr–.^:ŨOmV<<{züDgžýīŠ+ÝßþuîŨÉdčheýžüi*gzKK[62=ĢÔŋ,%ųåûó·|ĸŅĩgß5~ŌC!―œt°<˗LŦŨÛþ~—-uTP}LO—āO1bÃôÖéT aŧ Šž(OĖtTš~Š+˜AtnÂĖĻVVGĨ™B*g4ŨŅxš •“—ŠsËWÚš<#“#ZãŊ‹Ū < Fg4J7ÝėčOģz§ŨŅøŲŅd_ŧątŪ`vÓQiúÉÖĒoŧxfãgrMã#žé4V7;J†ėĨĢņQ9›]·4ō§ō­+ßn ĩŋøHĶ‚ÕYqšâú™–ŊĢébõ6ýÓéWÓŠĪę"yĶŊé`åLņO·ŋŌ”ïdfæp™ĮY—rî ÕËž<Ëũë*YâĩZŦM"PˆŊÕĮhÄĮâv4ģ‹^؈+ý@ŽŠŽu2LgŦ‡ŲĮęgžėÜ_'ãë·‰ŌŽŒŽéįĶ“ąûĢkį]'ĩ ПÆô2ۘLÓ[,WS9kũ–ozϜâÆOųÆËhL†xš: iÓíïŌSēÞT\|õKoĸŌą!û+ÍÏÃŊƒâĶģņõëou0―ėÜøųyųó,Ū|“aī*kö2ۘLģŊhĸgí/ųúIĶÉO JW0yĶ›?]ųv.ýŽNÆ{cí/Ķ‹ņīsņWūņWšô5:ZíÜŌLoGô–WØÆņ,ŦQŸŌœÁyģ+Ð4ŦĒ SCTšĢó7bŽ CQŠēvĮņ${…GãcĘē xŠ{6gg•2&Ï3RüÅCšHɋqL|ô_į*ĢgCe,Pyéc7“Ž’+ÝüÆ1>z―Ÿøøoņ•ģēNwĘv2ГÛāBŲēƒ@FųîU”gH2ExðÛßnDˉFÜ*oõ2Ûš:1_é’Ĩ)mgęx(8;ÐkŌą!ûˆ šVWģ•éïdûíOđ ēŋl$[ëÚÏ_Ø_|X]cåm’ýYÎė"û˛Søįė_ŽŌ•,ėŪõÚö7Ĩ§Ųß؜úJV„ÓžJŨOvV]-l’ýyŠ9ãBFŦ[ēÅŨĩēv Ŋ™Ū—ģ?óD#Ý\ûIÉ6›JŋýMĩýŽŽø*HŽâV?ĩ)É1Z-(.~’ĩ!ûKÎjŧEƒí_ŒÅžĪîž'_W/&™ë—Lŋ†ėŊvî䉝úTû_ĨKïôúŽÕþžį(ú_؟z)Ýo§8þ”ŋÚþŽÕÁî?ē_KģŸŌ7ÆþŌUž6Ęþ)Z]GÕßéÄk*ÛYŸ—ĘŲdû›mtīþGšÉ mŲŲú–ó·9“Aķ^ûßTûŦcŲÕöOÅ­ 4dõå‘å˗ŧJļŠĪūŧð)Ž’Ŧ‰1ĶþīôxX#­*,•ģž†Ō”ŨPyņōįĐŽdš|žh•'>ë *cåM—uŅ‹—ÉSđM VÆŊ·ÉöóōëäOũĮý4ÆÃoKó—Qš•ó뒞ĶóßŧýŨUŲÓo;›­ÍþvŪ<ØÜöoŧv·öŪNË߉ųõðĮýåM?ËO?ߘöŸ^Æôō§+nũ‘âéa}íÏøéheíø[·ŋęĐë*Āģ6˜n;G“ę›ėÚúf·_‹ýMĸt―ŨuĸĨ· Ŧ›øXž‹ĸ‹í?ƒë†ŋl™Ķmp ,X °@`ĀÖē@D›}‚X °@`Ā lœžEŽĢ Ļ ,X °ĀïÞpþî›@`€Ā Ø Āđ)Ö h ,Xāwo8ũM 0@`Ā lŠāÜkī ,ðŧ·@œŋû& °@`Ā6ÅÞKI7ĨD@ûûĩœv-įƒÖz yÃó“P|a9Ÿ5v=w/EĸXOïuÏxoīžĸĨ üf,įoæRþ;+Ēuó{•ü Eq)ŋÉŊÕ4âË―õVĶuČågķÂŅø`āpŽĻËÅ~GƒŪ|•Ũ: ރ’‰‚zë_Wīn°f~Xo‚âkËKVðküØ3ŋæÓ˜ ČâgÍþąëŅčWœ%[I= n~ÅjŠøķ@0Uû?|ņþSЇųЧ™ÃžÁûôÂÎ{í‹―vßÝþÐĢfUðk$ÞK­ÓuÉp֗áЧîÅíũ?ˆ…Õzi:ÕÆ' †ĩüøt­ūÝP ‡æĮē§}ö.<~GôÚåØĸƒ°įŪÛĒ{·ðög‹ø‰2ï]ĩ ĸ-ĨéûuüZ]ÔûĻÁoĐnA] üZ,xœŋ–+ņkՃX·ė\z΍˜’ÕûŸō'ėS‚ ÓâČáËæųZLz„üÖ*ŋčke>„ïFž‚ÏšK+2°Ëa§â°―·ãwdĮaÂä2~LšÆ};SßĖ”ž™üÞX’/ŪĢž1ūä›ā7?ģųy*}\<zŠt^ųÝÐ~ŦČÉåũ=CIŌWŧ+ŧúr šoėå‹Ĩ“äIzzxúîĨ>†ím’ÅïCfó“gŠLīŪu1ïeé!~Zéî{ķüŽh6?óŧ›î{š^ņ0?­—““íøÆXķ–_eQ°ēąĻ>Á敍G™O›„ųŌ…ŸĀŊ ÅV§ÜŽ‹ũï€JņÔõáw7ģøÝOW/ę8ĪÎÁŸĀ›l87ŲdŋŊZ/Ž)YˆIĩ1īŲn7^{þE”EZâŒKŪAï; ™āWp*—á<ƒ7GMC2·‡Ÿz>úī?Ô ,™4o~6Þû~Ļøî=ô5=vë‡Ŧ/; đïŒpÓ?{/<5‹8 ß98ëØ? ‹6\g.ĶŽ) ÂeįõCãp •UuŪL(§1špŽxųŽaļæ‚ 1ôûšlĩǟū‚aC‡āÚGáÚã[áģ—žĮc_ÏFã&ŌŠ‹ËðņĮÑWŽšUXZLÏwI3ėöþmhW_Šį_xãgŪ@ã‚Ķˆ +J*ņņÔex}Ā‹Ø·p îšö<>hÚķÞM2ŋÄĩŽũ.{Ū?Ĩ?~‚ûþú,ŋĀ]€&ē°Šx)† Ÿ†nŧn3úl…oއ?]tj·vuųôŌŅXT;;sw”ĖúũÞņ<îŋ§ E\ŲĢ í–ŊĢoŧŘũó·kų·ƒņZŦ6Ø}Ũt/Aų…(úÃūčT1ŸNž†ūŒ‚ Ýßî―ÔėßgrÕéß§PĀųWfN§æīÜ Ïýý:ėÐĄS=‹=WÜó U&ðãøņäĀŊŅų˜ë1qøüíŌĢąrr ŋ€kšk€3ÄoØ}?â)<>ršî}Þþ ūl/Ėĸr&M_€ïŋýũĸ…ÝŽĨg43ŋŸŠaï_ŠC=Wüég”›_Bũd„|SÁō$ëęŠPLõ悿yˆų>WÏĐãúxF―ö ޛPcŪ~ģŋų#Ÿļ9‹ņô]áĮšō9uŊĄĮĄgcÔ'Cqz—ŪŦÆŅýäë1tøÛ8}ï(ûf"ëw•âõœ.æŪŧð|5ö#\ØŦ*ŋ…o&NÆÄ/ãĐ·ÆĄ]Ÿ+0jâWöîëh›_q/ރģ*9ĩœËiÚz6ýžzcŋõdNįÎÔųsQĩd:žúæ”ÅpŨ›cčóŨĢmv%†>;ĄmšÍéázīęx8ž~sŧđęĢ”ųãL4îv þïōĢÐ*8íÎ70ü‘+Ð!§?ŒŸĖ)į68ûã­QSņÔÕ§Ą0éM_ĸĘZ[ N`ĸ Āų?q™þŧJj:vcŊÄŧï―ƒŧŊ<™‰ ļï/ļõ…‘XšŠúūÎü1/â˜#Áß^Éģ LœŧĘ{t%Ĩš<ÃÅô 5U9gü§8åčūļũ­IĖ]‰ų+`YI1jxvô'aێ…\+ ĢĻY!ēč-fp-OA<øMë_­]jëOrU%ǜzôá5Uáęc"ŠÅ?ýLŠFØģWO† Þû }Û|TUƒE%Z?äĄ Zãļ3.Äö]:ĒcWc“îļîŒãąm§NhÕŠˆåĒnúY čȍÚtÆ)į‹Žšãā3e*wôV­ÂŠU+œMŽîģŠÂI4íž-ökßąš–ŪŽäZj=bY-ÐûÏWâčšĢUÛķbéUeĨXđp1õNâþKúá”kÅâ ŪĮ&`EŋSI1žÕgÞ|9ŽÚoMYï1!2ᔷŪÐIn˜ į6ãŽæ?Ēóqũ5gã°ÃæåsÚ)žÖõq  Ø( SĩeĶß9=ļ―ą;íƒŦ·Ų]Úįáä+ŸÁė9óPĮõN…Ö;‰Ûþr"§ĸâôĻ2ŅļÕÜH3?e8ÏóŒdrĢ;ôö=vÂ_ïū^^n”iŲū-Ķ}øąĢ]:Ŋ‰Œläįčą  å5*D2ģ‘“‰*ß&šz‚zģķŅĢGfLˆ7GžŒkO܋zðq ‚f}ŽÎmŽŅnSBĒ–žėĘb|픋īNÅ Íļ!nxâþ  “ˆŨÅéá%xN]ļyÉĢtäŒ3…"ÜlTšdĄKŒÂCÞmĩļŽÆ=“ɍ /ŋ7 ·Ø ۄ1qšˆåĒãÛĢs3p:p<ūą#vïÞófĖ@fžˆô3ô’ˆ˜―8 ]ðærî› ‹°Ïv1ÖlcoīéŌÜO„Á=GÛgbŋ티pEŽėÓ…|nTaČkŊaëŒ#°MÏ.Ü(ã=ÓYOīiįpĖ9g`ÐÕ\ûŧüTT-ļ}wŲ‚ ·3&}‡&;†>yCĮĀWŸÆ–ųGcáW/âį%1t;úDt/ĘÄPĢ6ĘhMwuā–amš%t Ĩ˜ėb.[*Š—ãÃw"Ųđ Ŋŋó ÛÛwÛ]ë—Ģ=ņn`ĸþ8h‡ÖhģlÆüīyíGÎ_$~”Į)WŸ4‚sMÚõäšäÞøÝ'øâ쉨ūh?„ã3ąx§v;lévûšēn7ðjMSîóå27ábėsŊ`č~…Øđ}Æyuí·EŸ?^ˆŸ' ÆŦßÖp·­7Iįœ,°a ĀđaýŪ)īŦķūr.nūá NæĒyģVWĢÛáįâö?õÅvÜûÚ?Á ވ›/:ų…PUV‰sŸþĮōŅ‘$―Žpļ ō" 4ßæžüÜJÜðČcļåō“ļđ%å•5ļāÁqïyĮãÕ§WāŠKïÄ_Ŋ:dĒlŦģ0Ģũ8äˆ~ØŦĸH|øĖ-XēðgžųĘh❞/ŪMÖ&óļkõF<ËĮ>‚‡o>ÏäRvތSĶMpëkGāļŊēKŦqŲߟà ÞG"ÁýŪÁ=MCõČf=‡KONhVŊįlg#/$_þáĢ%H ‡/SPq 9^VŒįŊšŊDǘŧjÏšånēK{4Æ1xåЕļōÏwâÂ>G^Ē]w?Ü|7ölŸ)|„…;€lqâۘč +čq˜8§pOūä.ŽŽŧw?FūTHķ 9ÂčCđū+BóJé[Ų=ß=ÛîûõÃ1ŧ†ŋúÎŋģƒļc^ŧUŽfMļiU!ΞęZļc[Ūýā)s!°ĀĶZ Ģļļ˜wp ŽËœLÔbņ…(-/̧GĢ&ÍÐŪcg4ÏÏ"x% ŒœŠ\š‹W”qc7Ú<[ĩhÅ)Ņ ŽXQŒx2 Í[4qӔN‹–,]‚%+VrÚ4ŒFų…hŅĒY dņ\Ū9Vp#(hŲm›šg(ĸ’*ä7n†öí[r píf›Ą3Ü ŧbų",[ūÜU›™WĀuŌæhÝĒđ›âÍHÖaÁÜyXUå ōÐūcG4É qj6ę•+9}›D!éóđ`ZΝŪõ9hŅŽYV=~SQAëv-‘]ý=öï}8~Ūi‰gúŋƒ.‘b$ē ÐĨS{dsMSkÂ|ĐV.úKVVpQ&Zĩã:iQ>â|04VS†åœÆÍ+(BwÕÖV•cåŠ 4nÚ ssæ3ŪņšrĖ_°ĩu|”;ƒ ›ĢyóFܙė•- mAN&jŦŨ.ĒŦK–`þâUܝÜÚ4CŽr%–./æw y›ĒSę) mÐk]W;Ō 0 Āi–Žëą=-ÚŸĶųŦũWŨî<_ĖcĢ (;Ī7 0ÔûvšŪ‹VtFŊļ\?įų1ķĶ˚4GâĸCýÜ&ŋžâ’ŌEúŧüTũūÝTŒ2õZ?;7―íý·IŪ=F*§c·=œX[|ðÅDėے/8pS―^MĨĩęâ·WJÓKÏđę·–>Đ4ãĩÚSvõĩðleš/“kįÁ1°@`Mģ@œ›fŊ€úũnNé†âûÅWÜœƒ]ö܇ÏiŪ ˜ŋwõ,ð[·@œŋõ+Ôïß`_×ívÕÖÕÖzŊü7H X,ðëī@°9čŨy]­~Õā†$ū„! ü>-ā-@ý>ëÔ:°@`Ā lēs“Möû*°ÖsŋŊŠĩ ,Xā7jûðÄ?[―õ§:M}b)ÂũŒšÍĸځČ]}îD[(í\Ō=FīûR J[O•ĩtERaõđVY)9.ÛäH ~=”frÖ”0þVÔō—;gųÕų#ŦēôpŧŒąŋŽ•óëЭĨųË*MÁéHÞkåų䊯Ŋ§§ĒR― [ˆ‰ãc‰þĢ/_É<•ĻX<Îįk]ýüÔYYYžþú˜?5ˆ,XāÏęëô&°?ņŊ„õgnn.^|á9Lúî;ŨyFøÎP―ĐEÛėüÎb8ĖïōĻNUia>(Ūíûúđ-öė―õnmņÏäģlq–ÕëÓ"|æ.ƒ7ĸư0ßĀĒ>9ĖĘU™y…MW–ŧɐGĢ|o(­ pWūĘÚ(ÂŌM'―‘EAzyž―sékįâĢļĘJ/―\-BūzU› ­<“ŦļĘJ='—Ĩ …ôø„eó§Î *'ūŠŋlĄG"ôP―ôŠįĢ™|휂ôK8[éûŒkÛUõU•?ģģÄw^ĄŒHūēĢÞĢęN]’lĻĸJņtņä*QÏ`†ų%‘JėÅw·þņÔÓųMI―yÖ ͒’|ĸý,Ŋū– ,ð?hõ}ÛnۍŲwĸóŊ›\/pŠS:y2F ŠüFųvöėļž™úø.ú @ݛKRq=X-/%ÆÎ^v6ßš"Q/āĖĘâ+S'hļgĖxĪ:ruþÞûAõ.Sņæ;Fų1f ,4==„bŌWÏĻI–€/‹'Vžžā’ŽĖw&–HgfIņUp )ū„ûl§Ģ<1ž ģøáâļ -Ð#(ŠV &{(íųĀxj0āÞ,ãÞĖ"`ũzîQð%PMĄ™{RuŽŦŦkÖŨŦŸėę|ïŦ`TÝ%Wö+.]DëâQę#zÕÏŪ‘€TÕËÖš&€ekʕ=*+*PTT”’―8ÅsÕŠ2ūāž%:vlO9zUO ,ðŋgaԜ9?Ģīī ……ĸRÖ œâaĮ›—ĮWå;°8…HĶúˆ{į™BPEu؇zuÞ,§OK)Mųęˆ #§ëėŲ™ĮxÉûä)iéáąL8”ë@KŦ/ØGÖ *'/ӁÁLü^Ø(ßC:Đ§—įņ Tb)Г7å†įj vƒ‚I„uTČ pôĘ ‘Æ·”ĪN0*ãt8%HŊĐmÉHŠŪŌSÞc=e Ĩ§@_ā%øË“Îā‹Ís8ĀÐB ĻÁ†#byágHRw•hĘU]ďļëdyÓŦ™žþ,ãę+9Ō%“^ŠMūT€)ŦĐĐv Ąüúzo-U„NĘé%āĪō ʓžZãĀ øÜī)AkM< T\žũœÚtC}Ī·6ŌļACĘFn zŠ—―֝ę%ē“ę&ūléįĄÖOeK.˜'ðĩā XĘĖР‚6UšĘ ųęäM“Xe=ÞÞæŽåŝ'ĐoFŌ;&‘ĘÉÞTķw͔žÁχ!°@`Ā6l5―ózh5-ĻŨÛÕJ! %8UŦž^ÞĄóˆ˜/ÐR\yBkĖŨš ‚“+Ōk7“ž$TŧX―õOÏkãÔĐó4åáz3ÉÎK%Čę|ŌeuĮOū’į6ÎpJSxÜš utÓÂŪ^ĐiQzl›Õ@O0ŨÔr6ilŌĘŦÔšŪWߔ§-€u`åM#;O›ë…â%håMßP„ yŽŽŸ<šuvÓąü” <ļ5O–€ÉŠþŒŦēЛú%­M:o–õŌtm$âMÁš ų HÅKvu<Ũ›ūÕ@ÁÛžä Øīŧę$ýĪ—ZĸĪWŠÎœ`ÉĀĘ{R§Opb‹:Ðô@Q"7ā0ßyOt}9HĘĢ#_ÉWy ēuVD&§#5í*NŌcx ` ō ĒnÚS ,ōEž*HyÄ8ņV·ŽI]86Å)Q=žZ?Ļhģ·ã”^XʓtÝ;AO;DšQ„Ā\­‡ę(ÝĨŊd;–į Ū<:7uJ=l]SįóĖŌŠŋį=ԃ#Ü(OÁ·Žü'āũĶgšÞtĩęŊÁ„x T”'[erŠÚ}O’ÓĢē‹ó–ɃÄĖ—MĐj}—:“ÞŲ™r%Ë (žŅ‡“)•5xQđ0?Đ)`– ôqæ(=mŲA6§:nšZmŒ’ąĪĢä!°@`Ā6lÏ Z;Zí"UĮŦĐOPĒWŊĖþYšĶÕMË#rk…ĖrӓĖ3`0/LīóՃģƒW܁$;r’óĮĐ\Ę@É[rD‘Gå<7ō0dqÚRýūlÞKäi9ŊSžÉK^Ūže9€ ‚RīÎÛtdžWBkĒMušŨĨ]ŧPÕA3ŽĒu@Oäj’óðfä)=õ1dŲ@ā%Ā•Ũ-%ÜT6cžįL`cžՑ=ĻĨ›&6Ý`ƒšŧē4†dóŋۀĨAE6r™Xžĩ@v„Ïҏę(}ģ8-î@’ZļŲʒ^ oÁĪžgÕGƒ·ąKzžåņKũ ,X °Āú-°aādoŦ7ÉãÓŨåÕá ąvQį9@•wäMIjũĻCUvþïá~‚ËĘģØož)UyqQN7ØęØÅW€”ÉĩF·* $°ŅOušČCóÖũč‘Ęë$p9ÏRrHzÏfÆčiI'=ĸ(ŽsŠUž|(äÕņ<“į/į•ąn6HjiŠTā§|jÅ:œ ķÎsÖ97đ5X„äÅ:j€Ą|Mđ’ĀÉeķã#=4M,–·,ÏRÓÓ瓸ŠtÕđĀR;šėnãyæpP )cåi@ A‚―Ü!DOÖyÖīģø õļ‰Ā:“ú‹VŠäɖĘpžýúÛJX °@`Āī€œuy îŲDuޚf$P8Pq ã=ú Â îpuS’?7Kð“‡æMđz^š:wį‘‘ĐžT—xš—°œĶUrģ8ŧČMEđŽ;I€ĢŽ^<ä%:Ô)ųÉK‹RŪZ;`qz|äĢ2 šįMz "J: 4ôš:Ïc­ũÖy™ÜŦē.°Ō-Iޚ"v?‚ĩ“Kýt’aø" qāåžp={IÞZÓt^,‘ĘŨ@ÃóøX·vęĶ6ŌčœTZ:8ŧ2.^n Đimrž=ÐÔ c5˜ËÛĨš&õ8Þ ÄÛt$]ÍCVWEÐĘîĐëėiē™þRĻžbÕ]urvSšÅ7“˜ÍÁF 7°9˜ý‚‡ė°Á[íĨ‚„Ā뷀î%ofmýtAîæķĀïfuæÞ# Đ95+/IžŽz_yGžĮįíZÕÔ :GíĶÕī uÚōÉ=â"P kŠ—īZ{s,‚ÏÖüô*8‚@Ïóp= °ļ<<€tqk*Ïļ‰Ôó bœb–NÚž#žX p Ũ2ГĨúh-ؚšũÖ"ķž3Šrē”­ú‰ĐĀ^vĀ ― Ø{EšIoņ—}4ņŪ‘w―\įÎN\yēŧdIūyøŠŋĀcsvëzkÔŌ‰âÂK. 7\‹óÎ<wžõV͙‚'þvĶ–ÓVüũíȍ`_=~îĸt6uÚð-!u}bÕĨXžh Ē”økĒf\UšKŠ+ÁŽ+ķü3ÜrË(á`aõeĸïWü?§A2Ž•ËĢēF›ôü–úÏаđ$%“1Ž\ĘšÔŪ]7PŒVaɒ•ŊČ6—äĢYētnšéV,Žb•nVŲ9^‡ÅK–qĀÆū(=3ęō{dĩÁ^BŪ@ĮóhžŒõð€„/â(ŨīŦŠ:d†ōÔĐŧũĐō܍Ėčý 4mĘVāĀK@’ĄĘóh=/KīBå PĨ—ÛņĘ2J“‡'9Úð"Ðð@ĮËðk Uz*.―ĖcQN§€Žž$—ˆG^Þô­)NtāÄNUr]<T)Q‚õōĶ”={8€UČ[Ö›&ö€^>žt`ĒŦŋtũÓž]Æ;™ž9uÔth ÜĒ’Đšˆž~ Lóͧy]XNĨôðHýólåyÖķJ­]é)~LPtóÖ§E›NØeŧ^8áčŅ13ŽvâõÜAMÅP[ąÏÞügôé{―äL[CV8†·đŌûíu žų`& ™˜9ē?N:t}ÆSƒŋvS_9oŪ>ņ(ô9č`üéžŨPYŊuiŊ ęhę+–āéë.}ûâĪģÎĮŒRNßĢ<};Ž?ļöęũgŒüa;ڝ& Nsg60qÔË8ģũA8čÐãð؈éi7wé"<{ӅØkĸqpïÓ1čÓo0āÁŧ1pč@œpü˜YâMų땇Ëf|ŒW~O=ú7œsɛX•‘Į6īŒi·ĢÏÞ{āø+îÆĒm&&Œ|gHY‡‡'FÍ |iãyą%?ā™ÎĮžûˆƒļ#&Ŋ@Žj)þ~íqëÐûÐÃðö·sh,,øznüËuļåĘãąÏ‡âÖßÅ ũ]„}öÜß= U|ÓÔĒo†āšËĸ‚Ž?{ĸao\þðpT%ē-_€ûŪþ#&σ;ïŒĸaōœĸÕ ÜtÕ ļãúã°ũ^ûáÆWÆĒŽ|"ą xāô9Ī?æL˜Wpžýïļũ>ð7}ØØŋũؘš0†ų߯sCFá‘SÅýo|ŽZÚōķģOÅž.§žwÕq ,PÉāõŦ™›Ž8Ŋ}―Ō=]đhn:ĸĖŊIbŌG/áôcöCŸÞûāÂÛĮÂZķũŠĐļö’û1ŦLÏRŨcÄĢáņ1?ģ,/fvļũž{^1›Ï†n?W>ø6BüāüôũĀ}Ŋ}ŒE3?ÙĮCØG]ĸ4VoFÍž|ëEļũþŧpäĄûá >įcú’8~þv žō>åX<øÆXŪ€ðzéÞĐŦÄčŅý1ōõþļéø1čŧX8uŪ8―ú°Íž|Ņu˜°Ī’íÓî3:īïä7îÆ=ýG#I,<ÜõjéLx/Ūŧų&\yų)Ø{į=qÃcï Ęýņ“pį…ĄũÁGãōë^Aiû&–­œ;7^t$ŊĮ8úĖ+ņÃĘŒýÞ<Wu*î}ã;dĒo=xčÓ'^x#&-Ņ@fƒ`Í18ú,°aŦąQĻ3Vg.`s4-ŊGģ€Hy^gïmĀÉ⅝~ÚÁé:ovōnĪãĀóŽT^@ |y‹Zs_•s É^Ð/ŽīĐīžW‚ĀIÕ<<Ņ‹—hy`ūFĪžũh€*ŅÉ­é§sïK/’āĨËËĖá%:KSTõ€+]ú ؔ/đЇdĻ*Ūzé'ā­éé "”ŋ6čģûv Yt Úel ŠQŊÕQSŨōœü Þ”ē§—óšgēŽUNkLēôŌđWϖžŠNĮl3þ ņžÅÓūÆëo>ĸŧúIäö8 ÝZį;;„3ýōÝxōÛ ˆ}jFâÖ‡ĒžÓĶÛîy,Þ9 ·\Žįï}•Ą(ÞžóaütĀĨøāƒũŅoŋ‘YģÏÞsŠö9ïöĸ+ĒcžÅ;_Ėe'â šÂÜŅ―düH<4` .{z ^}øntlÆü/_ÆĩύĮõ>Āí{–ãæ[^ŧ3Z€XæĪV~‡KŊ{‡Üũ ^―í0<{įý˜[^‰Ï܃Į-Áߟoū~öčĩ%ö;ĶöÞzg<ôčŲčRč œę‰ūE]v&ø‚#?wÝz‡ōP9a0ū^Ø―øęÆ―ˆOgsŪšx".đþöÐkxõæūxúöû1{=Ew øMŨH/Üpžøp%üĮxĢĸØcë yæžŧĻž{gîš°7nļúNŒûąÉÚe6x(íũÜ{qo<{ÍUø2ũPÎØ=Š'ž} ™˜öÅ[xýëZ\s߃ØŦŅTžųÁīÛé ĩC'œ}ßøÓ1ŧcáØũņäīnxá^ß[Ņ”ƒ%ũø―ŦP“.ØŠÕJ<ųŌ+H°Í~õŌ Ø­JGãœËŸÁΗ>‹ũß|5ûãš?A2^Šo'‡jNĘ;\2û{ĖXQÅ~‰FÔh(ģ[4™ŠÁŸ…šģð:üÉÆ ,ZŠ·ûÁ2YČjŌ·<Úïŋx7ō*ū\PMÛ'0éóxc|7<ðvŽLÄ[ƒ&ĄÃΊKgœsĸã8í°œįĖÍi <ėØkOėĩßÞøËOâāŪåøËĨ·ĄžŨÅø`ðÛØ>2 \ýJcŪ'rWXƒŨē…“ņõüĨ`ū­ėLŸ°€ņŠ–NÁŦƒGǰïõžNgāó'čąOþïŒ*?ožũ Þ2uŦ؎Ô;fâøkžÅČ_G“ÃðîØ°ãŧ`ûÖ=pņÍũãĒĢzá‹gĸŠ[ß-ÅËž‡,þ7?ðô C6ÝNošBV4éuôžwč6ŅPž€Aā!ÏRāĄ݁;z€^ĸ&FiyŠËSuŨŒ ÆdzAJņ10r A)ŲU§hīŲE€% r •ybŌSÏ|zðCRéĄĮFÜũ3=@1°VĢÏæc%^ր“Ķ2’vš74mĻ—Ķ+Í=úBÏM: „ĖtÓŅšaH'U_―PÝMąŌ^ĒÕMĢúļ)Z1§ķōŌÎä§ =Zo€ĒĐXŲJ<ūŠ·^ö [ œ]XNĢHé%đ ŌO<:W\`ė€_ųč7ÔgsÕmފ…˜üýhqșxåå+Ð6GuTŧ*ĮôÏ?DÉėoqÞiįāÉžķËVÃ'ŽX43íŲa  §VšČÆQ—žŽÆoށ~݆ÉËkQą|6fOøß|g^|ĶüÔ5åUœÄōlWώīeŊ}púþ­qÏy§âĸÞO‡&‰)cÞGųĒ9øë…§ãÁũV!ķ°eēĸ…ģÂøöū°ĘbųþĪũÞ i@č― ((*‚X@ŧQ@@Ei"E*vŸúŽX°Ą>T°! H“’^ĸįĖ— ā{üÔŋ/Ŧ—Üû•-ģŧsffggwþžŲÛwâé)ŨcÄô·‘ģŲ ų9YX™ą]FŽ@–õhjNE|d4ĢŒīšIðãøē^d_zû‡!.61q HŽ‹€gE6üZ ĀsnFûVíŅ6*–ýQŽmŦY֎X@­{Čw‘ģĨ9E;j‚Æ@i–fíÄĐŨÄé-ę"đ^:"žŠņÍgßáü‹‡ĒIB$N?{šėĊĩÛq€cĄÝy—áú‹{!•å7ĪrÛČ Ņže*b^03ļþŠĒ•žq96Éī-ģą@Ïž’I?ŅLš·VϊNjƒęŦ’PÉŲÓ*­Mvį]™ßYCū_åėdOŸœļqįģpÓļņˆ ÔØ'Ūj%!Ėa1éˆmØ<:AlŊ—oö.cg?‡;,„ũۓpóÛÔšŲ-úĮ‡=āÕéqÅmóąâáūŠĻ‹n―oÄø!āQî2årÄPį^āÍ?s͖Ã*؝ …Šb‚JˉÝŲfëĩŌ{%ÔZØŦįXî{ý lþæM đōVžØĶ%FvŠĨ`+aŧ Ņ šãŽ6`ø€óáÞü2<Ö4yŧęĒ|įJdāýlŲšåĄ)ðâDĖ/üû”ã@Ņ*,ų*ū§°UIkÕŅÍû Mq/ 'ž˜|ĮÛhÜz,Îđf:Î6­óņþ—ĄžëØ{~ n=&Q-éPPįœõæ\'1mŲEmáäæäãrHû]UëNĮĄ=Ī­ÆHT|ōs°}' X?ŧķmFĮŋ—#`đÞ)/.EĄæ0uŋ•+—"ĮģĨ•Íi ÏĖ.?…ŲČÎ/Azļ2ĘöbݎLŽÖJŽüþää–  O_3ĸô<ŊÞuf]q1G­öĖWĒļt;Š*4·―î‹:MšbÖ}ã)ĀPhįôg_íÏØŠBŊ0D‡JĻM'B‡ŦįI™ĩ‡ÓÝÝÏŋmĢ tiZķAÚϰīA2,Į,(æåhšbîĖKI@āÁ‘aQn˜—€TCÝÅüĨ™iâ (īfĪžMÓĒf%î+ ÉŅžø_tĀHė˜õ`^­• Ô„A N`"āÖûŌŌôĒã+ įģV/ŪiJ āOŪ/Y9ųMKcŲjĮAA€`Ĩö9뉎†'āJĻ86™i―Í7ÐúĻÂN.!ÓÞN˗u–ĐQBƒåÍũTķčZAĶkBï“gYđÞl Ō֊Ŧ@SýRŠ8!lMVīāGm”ĀŊ&°°VlžuÖRõÞÉNÜbSV@š3cyŧ*9–Š ĐIúĄûĨWá™ŅsqĸCHŠ@Xr7œÛ6EÛņáŦÁ{ÉÏČ^ã…Å.‡Į‹°žcpĸÎ4χ čtôFęĮðxÉx” óĀKqjģx‹SŽqģó§Ïðøü’Čņī0?4ę8 -Ÿ‡9ÓæâÔVQŨ„ PÁ­3ųĐÏuŪ>ÏãĐÜ‡Ý―š#?ÓÃnŋ}{_„Ũ†MÁHÏÝHóũÂЃŊDZ\2r2žÆÓŸÆ„.@Īc1 8†ļ„x|øøSxˆÏkęĒ|…ˆZQŦ*,@);"šwåúŲ XĀēvõl†žL\rÓ0Ī:ëÔåî!ļæü‹0zŌŒô؉ŌŊįeÃp搋pÝŽûqsÅOØŋō Ûy8­Mr?(ēýŧÂðJŌū”ąw9˜šą/ØįÁ~~øčõĮpMËõđ>˜Õ gwk‡ēÐþļöŪûpkŲČúi1ÜšũĮĐ­ë ó”sþ8ŲpšZe1™r§3.Eú|šoïyų#īá)8Ŋs]”æSĻ`Мß:žĄ€ĩ<}Bä‰'&߆šó&"1kžü5Bƒi M@\ˆŋͧ Šþ8óÜģqũóģ0aJšr+Ō~ Ûø9ns3šŨ-ĮŦïįĄÏýâ†ô7Ü;m"ånÆŨ{ķá4Ōø`bÛËRŅ―[ž~ņZvŦ‡ī―āķû;œŌĶ'"ؗÁ!áXúÕ{XP€Ŋ6ïCųŧŸrýÛÕ'ŊrķĨŠ­ Qþn\›Ÿ„Ī9pJjīÍEÍҐÄT|{/fMš‰SŊÆĀūąxčžIØĩž>zãīūv2Ō(ĀHĻSŌ\ ‹Ŧ‹oŸx‹~Ä·ĸþ ĄíėžO€'ū3S―iŠÝĩ{R:`@ũöHýą †Î› ĸ_cÕēϰ%Cå{!"&{ūüÏūõėuïŋ„ÁÝo@˔Jžôð]ɞˆūcFâýŅ7ãÎđĄhŸāœðö˜6ž^žųb,IÅ5ÝK(x9uģJÔþsL xLœ8qęąî Ā>úðClX·~ūŒū#ĒŒĪ‰3&Š‹IiŽĘ|)íÎ~pō HĒN”J“ž#f­ûÓęȰŒ.åYÝFõūÖôô]ږ§Hō%ļčžþ*/Ý7—uÔ  (šŌhõ] $ĀÕ;ˆ°Fž& ÓVðëžižlÞQýTķĀĮŅÉØøŸi›Um–&lĀmZ­<€ÜlWUŲ%”,•t" /°ŦÞ>tP>šÆĸ-ä  ž§zlïiû‰k‹Œ4gw‚đy5ēĖī]Õ^iÄĒĢŪ T%üĻ/YAûmôP{ĻęC^oŌīNë~:îæ):dgÓ<ÅgCCC­íjÉ$ŅÃ7,M›4Ebtˆ§8…§_(ę7k‹ÔÄx$Ķ6CŸŪ­P˜Ÿ ŸĀHÔoЍZīA‡f Ų'ūč~ÅU4ų5Bpdę'#'ŋ1­NŘËÏE(MS švBĮzČ-,FXT4mÚĄN˜BÕQ'ۀqz‹ÉļÏ―v8.l›HÍ+ýzvåšcJļö˜Zŋ ęĨD"&đ š7j€ČPš*O?ÉÁn((wĢIŪ!ÖKD|ÃfčŅŦ)%‚OTš5m„”š ļŪU%!š1ý5˜**ÜWŊŌĒé‚Í[ĢMó†HK c?{ ĩqK4jŠ2áž=z )°’ZĻŧ•ÕĪącöĩ|ļ^šÐĶN?ģ ĻĖ <>•å6@ӖЊn ýQ ÔütLq!ꐙ{‡Ä Iģ͈ hÚĩm‰z‰ð GËvmŅ:―öŪý ›ũUāĖ3Ú#4Ū FÞpĮø#.­%Z3ÏBŌ8đŘ2â$øŅ.$MŦōôf>7C™tH| zöi7Žï`4hØÉņņHmØõS“ĐYy"6­ŨŲR“ EÃö]R†Č„šHŠ Ĩ q•‘8ÄôlmŽĸčĀû‚ ?âËuĄ5þJ$>•ÞQčŲ―|ËĐV{Įbðˆë1ŽS2Ÿ@œJģp jÚPpšîēAhÚ "Š-Õķ‰Naŋö@›uā–‚3Î8]š6Ÿ§šv< A•ˆJïJgžÞAZJ 6mÅķ$Y[âę5GËjKu茈ā2D%Ð\Čģ~šËÁ‰hu Į OķAömbāŠ―ÐãâŦ0þüNīL˜(cMÕüiÜÍCā^WóŧķAj|6-þ'Ö$ž‚ū­’˜Ü#oŽ”`Ôoß퓂iŒˆÂÐŦ†cāy‘FíÚĢ~Ũk#ęáŠa—!•Úidý–čqJGq)*(4Í:u§·’< á‡MPŸK ‰ÍÐēe .?Ļ-ß$^š•E SHH0yߥūø―­vËĖĖž5āæņãðáû‹lMMĀ@$ ĻT…hcEĒŽiæ.G[tĖģĘTAÄÜ pČČM[ģ&·ķõOæiÁP‘‡Ķú­ä€ĩVšüĪ Āt2ajOÕq00_^0į‚ģŸ7Pa~kĄwUš˜ÚâxðRŦ#[XUēN*Gm’†Ŧē øXV%P'ŽŒtʈ\óĨ9 ōU[€Oï[{ų]kššgfR–mā-ÁÁ&Ė•ōڕyŠŠ―dĶĩ °•7éėlÁqh.­T4V0šĶÍgôūōķčHj ÛŠzđī_—9V•Q ĨųGíŨ5đķļāL~'ōōōô„%™ž7nü~~ūHIIķšđîČ_i˜Þė2óžŪzAÚ·€ļŒĻšYņx(@IÚh1%{/–Ë%+ŽĮj ģtĨŧLķN&j§\ôÕ?2—;oӈÆHSÚÂâJōJõövĖüŌšŠ)žčŪ;i'mÝIž^DAŒkâ4ĢJ[RĩïĮíU4ë[]ɀаŅ)‹ÞÁ„<8n\Ï*›ëmĖĢ’å–”Đ’Nų|‡uŪ`]ÍšqŒē\ųĻĮĶárBėFØĨI§ ËļŪĒdBï ŒÍžŠũȕ„zį`pû*ðŦ*ĮŠõ*ĩĩS1g’–ï–k0ōy˜‹˜ŧĢĨžĨŦýd€ĶYģ\ULÁ4)ÔÕI o{čXcŅUī3­”M&eŅCT,Æ@H‚Œîð;dfELė1Ã"ą\ ˆÂ"Gˆ0"œÄ*9xnøaImÖaâŪdĖįˆņ+ĶsÄ%>NÍŲõ’ë/\Bs䱒1Ũ͎LžŠøĐžĘÅDŦ.ĻŽÅÜā~d*#=<7Ū ĩŪęFžŽS-ĒƒmvÞqå}Žē\ũ™ņČr%ė(åáIã‹r‡“øýP‘:ĐĮgéúal :ŠP‹9ÖlØ\;jž WžĒËÁėn°g1‡%ŅÕčŪ$Ÿ—߁ŠčČ]Š―œt§]zΎM7ýPņdôGyŊ\BČáÝy07Ũ- ëę}sxÝ($T―TqBmq• ŋGÐðˆrŠ?éú~ä8Ņuwũr45ũWŅÜNĄĻZ/IŽ^wē'‘.GĢ čaī9ē­zđŒý~D7VeZûįXĻ8ŀĨĨ‰íŠi‹éÚzĄ™/‰ ž'yUĀĄ…x€Lš. Р'F%ÍË@†($&_ÄN5 #@)Ē­Ã$™–R;P øôŒĪ\Ó•?%X‹i­MIšĘOŠ‹i^,Įc†þcM•dÉgU?“:YgG;æ čøWe&aŦ™5…"AFƒ\ԜOJð+―Ģäīß1Ët­šIÂT=ļHI”r‚R= pI—GŦīI™TÕVŨ< ĨKĢ”^+:› ™yéš ~3Ŋō7û€°~“TŲ$ Eœß;˜eĻ‚”ŋčĻþ’v[›þÞИ ‹EP8Aý~4ĸZívĢTMüšo:ëũ-‰G†ŨĐK§5Yķ4ëkÓ_5§ØĐ˜đT|;#’œ5KIĒUŽ371_ij2Ą (’ $1}‚ÐMŋ"N`šÉėm‚  ČøåKEÖīZŸÞU=TŌĶx_ĀĢõԒ yĮ:āRIIĩŒn„ÓÔ;ÅRĮ-/A„ĸ„dŪ•„-ĀF2Ŧ,kYÂ:ę·LĒēÓétiÓ#xË1pf{ €ųžĩOĶ$ķSĮŒ ‹ÎM`,“œL[ΘhæUþÖ5`’GĶ]ŧ„XŌU-—@!m°hB€ŅJu­Cf:iĒĖ[ĀČ­Hi]ę*Ŧe&G™nÕŠ˜äÔCkÅ2_ŨĶŋ;4v\Ü_·­4CJ(ýN&hĸ·ĸŊÞôSōŽĀD@'ÓŽVÏO[j1ü-ŽPhĶŋ@F Y Z€gĶOjķ.'P!HĘ#ÅąíSËÓ$aō(ÕwGģĪĮž-īËôĒsR ũ. $‘Đ!ĒĖŊŌÅô͉`Ã2G!iSČ ĩýEÚģ@HÏčžTÚÖÁĩU^W›džx›ƒ Ë8ĐLiÛ|ŲĀļˆÛaēöí1 XĀ(MŌ Ð@ jŠŽl—þ0 k—LÆzÝYO˜+Lšā& ÖĄÛŒĪŒôĒčïI3ļĩSBŒ2ĩū”HU_ĩĐX€Ëû Þ ö€&ŸrķŲÖ ųœ@UZĶöËŠO”—Šé˜ß%ÔĶZ ÔR –ĩω5§€J S&WljOJķîHģ6ɈũJ cÎFNŅ2í u9ŪWT™]HĖ]Î/ĘGëtzWĖ[åņ_į·P‡Zgpp0ÎxZīh î>"ˆ/)‡#āhŨ”‡@UOŧžŊþ\õïz֕V6lĀýũރ];·ØfŽ·í5 ˆ:‡@ÎB(`XÜIþöf,I3嚿čhĐVïI–)P•C”·ŊcęĩûüGŨä0UJ­Ö‡ũTŪkOŦœą° dÜU=Í҉Wūvlۏjī:jĒĨŦÍĩk)PKZ ÔR€žôøDpžg…+ō„īĩ3qo&i˜Ō„ŌhĪ]J•‰QޞĶÕpíÍĨ‰:ZŠĢácí=J>/ā<čd#fNæŪ@ Ę[ïó6jĖūŒžąýûũ?Nmþøe*õãžļÞįôÁK/>ĮøŠMŌž.mW '­€Jū&`^j›œŠĪuK Ðo%=o=…i’3­õJëķ(EBŧīrg•žšM>jļžnÎ[ÜŠ~éŨķî°|fH-WæZ§ŋī>jöŊ>Ó§6ÕR –ĩĻĨ@ÍĻ8‡;kSž 4 æĨJf,ÐÓGæE™YĩÞ'‡1o1}ÓXųĒLf‚%Dd ØĘÅ\áíd.ÔZ#s#P8+æĖC°ĀĶĶÕEóæÍ1eĘ$&&Ē~ýúV^ÍMüŋ{BāŲđKWüēv ūYš”íӚ­ęK3(éĄï*,ž Ŧa9K—aë·lŸĨĩp3 ËĮ‡ëĩĪåAZ‘nŌ‹éEę*NpŅ‘Ņŧ–āHϊ–Šd$ĪPóÔšī9ÁSZĶāÚtĪá:ïVuïI!˜ōg1ĩЖ Hø>™ãû/ŅĻÚJüiĻ8eÞs1󮀎š‰k―Ï0đĢmý ŲÕPĮÄ*..ïR™ ÍlH0•ÖŠý`ĶY‘YËtĻwĨíðI{ßŅžĮ­)ŠŽn Ž‹C=‚ĨÖQ|ðA˜9 vĸOĢ VÝđ{ũėÅæMŲčE'k/AT*ģÖJ]fRĮąĮ Þ öŦÍڏĻÉ-u #eÔØm}“} Ió4-•ý gDWˆĘÜ,M_Ĩ„Ū…úÏ抛ã‰[åhÅēt_æsëӓDH93î[^1·ÔČrp’ō­ÍĶ–ŋ—’ݞȇÕɇáîþ*‡§ĸÞvÔ>ĸŨĒ@Ā)íE ZŒÚdbÎú-†\BmP !/V1ui@ōh2q1r§Áō€u™.ÍÔû)åÕŠ< p‚ŋëEý6ÏYz„ę~Dd”­mj$''cŅĒEļýöÛn@ņG“TíÐčÓļqc@CŽÍ.Z9€ähéjƒ@SĀįČ―rĒi›&YýöĄ3’6ŦKŦtĖĶ8x™đZųš†J‡ågŌIŅJõ0,ŊkCū4^=/MR}ĄßVÞWĶkМÞÜā­ëzödĄ›ú;·°‚AĀK°G= wěâΞâ ū ūxdŌ“‡Ýį\“%ïhIЂƗ0{īg\ũõŪņ>wôœ~›ŧņ\–ŦũN$™RÃÜĩ\ô{ß=‘üĸ~ĶFāԉôęDrc" ķ\°ÛĖtĻßĶ-j―ŒĀ§>Ņ ’iVā§#Į\`Ģ0vŪ­zFs2"hh=T`cžŧdĩÚÞĄ}’ĶÆ F,ÐüõŨ_ąuëVëDõŸ‘Ô”þ*ðyqQ!ōyL“LkķJrčÉaĮYkäšĢÖ0Í Č1đÃ8189ī‡4tįρ&óVÛDWŅÍZŠ Zū[*P”öČgUūâĢꞄõĒy36Ĩ|1O !y ˜Ĩ]ÚPūĢže9Ð~V‰-FG>wīIúŸÐWë›ųŒÍšËps­˜―QJĖ’Mí;ĩ8Äø]zœĮŠnmÍ,ÄڍÅČãļÔøÜ!ÐA>œ‡âŦՒb+W–æcWf6=ˆ° 4Ï]Iüē(o?rä1‹Ņ Edxc;{ē]ÏýöŊš2|ûų'ψkÆ`þŅāŋ}îЕU˜›…ĒJ_|āœ[Ģ2ū9ZÕã^zō …w<’‡ÞþûŦ8…„ QIŽ9Ō4õ[ڒ [Č6€@C@!P• RÛVAÛ~Ajš8\2]ŠcLóâ_—™Paũl―T@ m‰s#œĶYŅ”œ”Œ}ûöp*îŦãÏHjƒĀF@Š=ŧÍ,­õB›<ŠĨņ‰VEŒ3)p2ā#E;‰cÓ^Z ĀŅĮĮũāz§ÚĪüM’@GŠz’ciŌÔX‹šŽķĻ―īOMpŅ_tW€Wč? 3ē ģŊįW&uúÉNĘQĄ kS-N&dq’oDLˉ d‡Į‰œĨ™xúņûņč“ïÁ7&[·âÂÆaü•ƒčVŒ―ŧvÃ78ūÎĐBÖ&ÎEŸŠ,Ė›1_ŽËEˆ7C6ï‹ãŪ@B –Ęž}…įgMÁëēPq`/’Ïš ũÞr1b|e rjĶl|sæ>‹wŋŲ‡kf>†―ꒇhž+Qa ëåÏÍÁī·V#Úß™ųÞ8õŠ›pÃ9ÍáQ `įŦĸ+[‰…sïDeŸÉhS?ÎxDõ'ĸŪēžąäþĐxÞ­Lč…·øŪ[ŋ;Ð*-;vg#„þ%ūTvþWS-—™Pš‘˜°$$~5f­í%r rÖâĪiĨ!Q“2̰–WeBÔšž˜ĩōōæ‰ bö™ž­―Š’ŠėT>'PUČ8ý'0nР!B(Yi-qÝšuöW $pųĢ?.°č[œW‚Wa~ū Z—Tƒeęņæ7€åĀR@{–ī“đFfV]ÚĨ&•ŽI“ĐÖN^āĘ\Ëß8MĢīR%wŪ‡hËôËLôŽhŠúXŲķNé8.i/ĐčĻzĐÞÖIEu2šņg[Œ3đcޘĸÓ*Ëmioöfåðd†ĸÞ<üZŲĢd.!Ģ:ŠŪåņÚKd;.0·ŽCÝ·Ïމ›nþ.šú―·oL„·F_gÞûn…û0{Ä8žĩ%Ÿs°Zfšw•Xą/ý‡ÞˆÉÓĶá†!=F_? Ša–”ûĄßäŲxũÏðö‚Û°âĢũðÓæ&ʍüÁ;-;uCĢä8Z‹ÜQ°ãgTĪuÁ­“'ĢGļoüLl. oēBA\ÁÄWtƊ„m3Ó3đpųĶŋ|nĸӉ5Z&RŠ>ží‡ø1OMipæ%ļŽW+=aï(KÖJÜ:|$ŊÞÉŦՉaYýÏüSpj-€ !MŌ€ĪâbžåUڒEža'HsŅaËŌķĪ…ÚþBv€žs'’ð_æĸŌ4™ģå+Ā• ]Ķ“:äq+—ŪÖ14äyŒŒ”m‘zäx# øģ>šl“/ĩ^…ū3ŦzVĘ ü@āģu\Āl i#ÁAu–@ DßM+·ÎÉŦõN Ķ•kÎč>'Ķč$æ,!ÂĨŋæūZ/ÍyO[ ë˜Ė-TæZ•%OfþqĀÏëq™z•ŽNl‹Ę0§!ŧzōþq1•Ģ.ÎýųsŒ―īúžįöÁËgc·ŽþՒ2Ũ{Õ.üjũþŠúBģģĘĻžœ|Š_ŅwG@Ŧ~ÕņtŪ~EC‘ĖŪāvmÝi7”—å_^„&_ßú;ļ@IDAT‰ūWÍGČ^īŊūþ–oĘ?<ŽßęĮ›q“žTý%VJĘŋös|hˆFš#JÖå•;0đo,\ĩï1ŦūiIBIq˜™ČŊXÉ#ËxķjÝæíÐŪI}ÐqŨæ™S&_Āžš?ž“ŸĪh?„pūjđ’ÆX@bW ščīJįŲĮ.EÓõ€ë/ˎåŲMšīÂ―z!ÚĢŧŨ|Œ)“ÆcÔčÁ>aO―ÉÃËũނ3Î: ƒŪ―?ėÔQäœë+ߞŅįwE›Ó.ĀcooĒĢTþ1~>\‘a'8ýðÂ-˜öÂbļQßņÓ'øtÅzūËå8ūïå^ŒÏ?zŊ―ũ6Æ ŧģ_úŽÂ;­‡Ūšýý=ΈĄĩaŸÚ˜=ŋ ,œm%ōNÓácĒ?ZK3#đ$ųķiZ’€Ī•šVā/ ČĖ•&!i[ĩ'ūŪr,Ę AAōĢÁ}ŸV{7•ၰsįNSÎŸ‘œuD ŽįlpP Ũ7óŅzûęā\šg(DˆņŦŌ0OcZj–.Į fbÕڄ…īs§Ã‚™đŲ~i /M“r‹%A™Áų[æ[[gķWewž–­3dÎåoõ‘9 ™ĐŨ1-+x―fīV­|ČP$ƒáõ“›H'ķMAæŲ 3iÝqõuØŅå6,zv°HžsW&ļþģcÕŨxmņ2„ÕIĮy}zÁ}ķm߁ý{Öa5§Ïčy–/^„|†ŒÕå;Vcˁ ė[ó~qoŠ‹{uīmÛV-Á/GX’ōé ·ýŧ°}Į.ČZ‡ïđÆÕđŨyh„=ëūÅëï}‰ĪÎgĄw›Tl[ũ+ Ë ðÓ§ŸĄ"đ1úöŽéŊÆÐ{Ű-í\QējT­Į;/-ÆóWœ‰kÚT"ŧ ŅԜs·ý€·ßû72˓Ðg`/$āûĩ\Ó*ބ/~ĖFïūÝąsÉŦ؄šč{NODúU`íŌÏðÁō_Ðđß%\4ä“ÛŊÜ4ï5]§ŧ{)Ũ3đŪ^€M+Ö ĖŦßü9B[wF·-Q”ų ömÝĖđ˜~tbh~‘ŋŌĐ­m‹ļU a:ãģMĮÎxúų­ðŋdÎkŠ63Á€6uĻŲđ„‚Ē[:Ķæâ§fâó—c0øĶÐĢe:Ï=īî('Áœõ_ᕷß‚{F‹Q/ mÃT?ķL•Ŧäņ†e:ĶŽĶę˜ÓßÔ؃įšî\ö)þųōNž5ų]$w―u<öãŨ^GÜÕģņā%gāŧųS0íÍ|,|ï-žųyļýÞ7ņރÛmÝøë>Ė|ô9œųĘ?póõ·ĄßĐģ°jõHâĄčâŅ9Û7á'·Lûžõë·XîžÆ:ˆHTxhtnÛē5šÅ6ÆÅSïÅÅݛpɈsÂîþoýSp:Ŋæ FÚI3Žā!ąŌBå1+‚:'†ÐäČÁAyƒZ[.dF$Ā’ŅÛš%B^ĄŽyV–m_f_‡čmޗËn€+ÓmrZŠE *äI$999ķÆi Ŧ,þ„$Ā4-,((™\sXI3ÖāąuG6ÞęČ :ũQIĶjĮĄJßøïi{Ž/æ%MRŅ“œ-#:H/ÛãÉōôÝ QĪ―ĪmišĒœ}DS―Ŧ3@yŅ„ģvOsjÃ:ƒOŽYŌ_M+etާĘ7‡#Ąą>'9I30­˜|îĶŊðoŸ6xü†syÆb>:ó@|r ēWūŒ3^Gûn=°ëÍųøyO%Fœæ‡™W E`Ŧāŋũ+Ėžĸ/œ{V[lþrē“ßÂYÛāŠđß`ðāAøéÃ[ą|Ũ]ļŊÛŒšö:twōYģŨŨuņĖĮĸtžoĨę<É}ņwČîčĀ)­’cÝŦ‹æLÁ“_—MÅ#·>… đ‘đäižņCÚ h|lïČ/ ˜āi4ËŅ ųEų\ŨôCxlbęú".1 ą>\.Š2“p–ļ‡áÆÛįbDA6>ū{û|6ž{mZGR‰`>æČųę•ŒN="1,sžūïÕįķL侓pÉå0Î_%S0œoöï‘ĸh–nĘØŠŸ7† ËÍĸĀ€AgĒlųğ~æŽļ BŠņþgŦą{Į^Üxé%Øŧr#Ę}öJäCų€1wĒW+^üåļûĢXą―€Ž˜YLeųˆĸV*å…KĩU‰ãœs!8&ĄŅąˆ­SŅ‘äcUīp=ö?ō·Fā4  #`īý"Ž1v‚‚1k‡! Å(ĩ'Pu‚ŧ3zƒ™+1PĮđEÎ2bFŌ܁Œī5GĒG(@f]yӆ„„`Ž\đŌō?pŠ LĩēÔčhLJIՈpįƒƒŋO0đ@Óī]ķĮÏÏŋüžŌGŲŧL~Š·œĪĪņÉd-P•0ĄķēÅ5MiŸZc°í(Ôšy‹ucÅøŋRI—DSUWóʏfj™y%ThW`'“ļÖPÕ'zH[_ÔW*PeZ?°Yô]™É‰ČĘ  Ę ēĒŦĘ;YI8ŽvhmšŒß‹ČX*LŊÁ2įālցĮ.bų{Ÿ#ąþi9üj·õ@Ÿ9KÐ+ąĒ“aāč Ļ\ú,ÖïØ€ącŪĮ;î?`Åî<2ļ|Ôéw#ŪÖÛrpíÃŦņeŅj$5莑Ũ]ÂÖîčóĀ—č•Бņ1hÔtx,―ļkŋýËWg8‹ą)?ũæÂ7/―ŊˆQãNEÞØ'‘Q€õÛĄERúØPšKïBvĩԜĪõ€Söވ+g―„‹ÛÅI bįD Â?ōë„áÃmûĻ…ĒíqýUŨĄnÆģXæÕC‡AlÁäïØo7žĩÛōq*Įéšý{ą}_äėHĮÏÚt hîÉŅMņM“JzÂjN”ōlßýėĮū̆cÔÕMðÅgÏēóáĀó}}ũs.ÃJ%Þ7m“ęāŪŨÞĮNCjĻ/Jē6áõ·ß@t‹›ánƒËCnžæĨ˜Hu° eĖߏqīŅųün(\øēũģN°­_7úÅĒUë:hÕ"Í{Ëށs›GaӆÝŒŽFD0C•r6zp^›• •Eąø°yĐÃ6ڜ9Į] Аâ7›96é@Ļģƒ•B"|‘ÔĪ+îyāfĄČĮćĸ'DNvŽ=“―i= Kë#5*‡ÁŊĀ.:]•åfāß_lCYÛCæŨęxÏūK1hžƒ>8 {úaé/ëÚIÁ)ŦČÝ*ļíŪ’Bšox}4OŠĀóóî‚ƍØŊūÃӎ ëßýgĀĐ.“‡•ÖĮbjrˆ‘IÃS)žGmZÅ–Ļ$†n jërUÎ<”ŽL3#S—deÏ*š õ‚ÎÞļČ#,Šæ€æ-Z°ŽRlŲēÅ ™2œIĢĖŽóۏ,ß,d{! 7ę7õ…G$ëCĐLmð(āD"hVäHð“Þr ·ûŲĶl^Ï&Ļ”:õæãjæÁ$sh1Ėv%Ō’•ĩšÛOÖ0Ó32i;^ŽōŽĨĮ<*ėūš'š9ÛmôÝÃG‚8Á9ņÍDËJŠ:|Ú<äøŪ&§ķęčū؃C;§Ûĸ)š1ņdíë•W ŠúH“”ÖŠhëF@Ņ= 0ĘӂNäó]‰’'9ą™Önyû•{'bĘôļ}öœûF|(Í7šw†4šLÏïýÜĐÍ]~Û]H XķD$]E7 īxyųbõOâ’Ĩ`ca۟}*ÚÅ5ÆŧKĮáž^ï[>WLū ÞkāĄh†”ÚÔ?P§í íý5Æ_{ǃ―0ōŪ9tæpĢ™•ϰ<ũ–K°KNm(ũ§0tÂãxvĘæ0Qŋ)ĀG1‚ęīÃ?n‹ąó– Œžâ1IŅXũÅ|<ŸL'ĻUxkåeô`tÆ5߄ ―Ïj ŌÃg^x–Ū™áW]ƒ˜Ä$Œžu&š…ÓyĐVã<æ(ý\IßõSŸÎõ‹ČMRÛļņˆâô)Á[ß‚Å9­‘ÚąŸëÕßü­ PT·~ę_xũݏđÍ#ūÜGéžđs§sL]:Ãï{ŋü~ĖĸāLáütũ Ī€‹ž…č{Ådôî}BĻ&uÄÝSR҈&[øD/[ģ1h9í&Đ~(+ރŲOˆ?Èj™Į3(uĩĮļĐ](ܓ߇Ysœ slPÓn9x nŦŒ6ARŨĨ”„7ë)cšpÞÐE­3īŅŲxxA],úėk cž<#•–)wôŧųnt(ĖeLíH3gõėhNHc'?€ĸþ\B9nē=cÍĒåiļÍ-†>0dĘ}@L}3MOšũ,þfw;čÜßƒÔø ]ĸÎÜ233ŲrÄMcoĀŧ "ž­“bî­bĘķ^F†k`'Д9VŨųŒ4G:”Ī7d+Ō4Éžĩæ)ÐTd"3#ōŲՕ:œŌwÝ}%ĐB,^žïžóŽå§{.ĐSßÅ ČĀæĀ]ĶųF5ôGÃ.!Ô.X&ïÄ‚ąYk˜=ŋR‹  Š)|@ëXŌB―ē)ló…Ûö\š09ØÜĘ~ū˜›úģ ėoÃë6HÃÚĩ+ééKįĢķęŊ1I€ø>”™Ū9ĄĨáĐÎúm`%40š‰• [NDŠ$ ÖN8ļ1O9céYĄXķm+Ą XënÎvyÄĘ⠐Ķ$P§š Cí_ÖÕ/Ūģ:Õo‚ĻS ŸŒbЅcúŒ™Č˓ž“ī_vãÆ_Í,’ÂÉÍrŽ—Dōý…åørcūݔöqčŅ<–Ūïl7+äéåŽûķcëŽ,Tzú",2ąŅÁ4íĩkžAáHJŒD%Ĩjíõ Fŋ3Þm@} hÂ7ÞŽi{ûa^ïT‘)ĨƇZĩJđGnˎlxY>Q˧ð·ų„Ō֔‡­Ûv Ô͛ëV ð"ãŽpũâúą;ō đÖLĮ…gËÍދ―^HŽ 3MW(.ĘC™GC·‘KS(ĘĢs˜O įFIŨöÂ'ˆĖŽŽ*^Ądž|>Пã‰w>Ü KE%Ë ðũAAn&ķïÚ O?YWb ,kÓą) °”“ „鈈ŋšäų9īK°*ôƒ˜/…åÜübö'} 3ņŅÏ9øĨ ­Sļ.XŨßÉō…jÅÉēĢyĄyYĘõÍ +?Į3/}…î—^ƒž-ępii„[Į8ĸ&ō+YÅÄĩ4_Í˞™Ë§ĀGKVœŨœßZēQ€>ÅđZF~įðQÍą æYĘ<ĨÁúPā>˜Č ŠĻUVOît2ôt#ïÔûUIïy™sĄcŅÐeņ mõģÄōŠĻāčī%OÖWõÝägĄ―Ķ ūâÍšoTýhĄq'/ōdôݓ^üDikŧ懅͊ ™ÍŦŅÂ)í/ûŊ”ˆõë7X;“’ þÓĘVëĨĢg!9]khrޑSŠ:ÞB 2CvŽœT\ŪßŌdÔ].S 4/ŠÃžggČŦSÏ pdú•‰AwÍ,Ė^-!ÓlŌĪ ;˜•`žgÏcÚķGfĪëędūˆM^ųøÕ?ƒLāĢQ§UMZCĩâýÃÁËņÆwœKVŽöJq{ $jeÜߔâė‘ĪÅđÔ~óHĒj{i ĘĶwėķՋ đ„û7ĩdĻÄÚKó-žåžÍüfú-AĀI•Hí’†īRi‘FÞWŅTŨ $5‰” _úmÎ<ėB~9_đč#Ú+§Ö;Ę8ЙģģÎJÐÔ:Ŧ'ëĻÉ­3C ÁöŲZmœüUGĢĐCš“ōŊšGý+†AÛųÁ<ÃbRél‘fĨ;I‡Fü(YŋúÂĮ?H?h” YõÕ;’“ÜŅuÛáīøúĻŨ(ÝŽ―Ãw―(17æ§Ķ|āŠú°uÞå"VU õvîëg$ĢĮDōŊ+]ó&cæ}eōBļŊŋsŸ^Ŋa„s™ĸęëB{ÔŪ·ŒUO…Į°ūÎFþęeĖĪöËo( ĀTŠN/nï°ß\käŧ)&ŋú„Ī dį6”Ó ŧĶ$aīˆKîÞĻŨōLĖlÓË,=Úûx8„Uå&å―#“ŲĒbĒYõ(ÏĻ‚:&ЕĻ\ø+í˜lį°d@|ÄE9ęS=•“ïšjTýšœÛŠø92 Ð]Ų–UŦ9MáGyüČŨĸÖŋkNĩ^Ė[ā ā34M“ YŒZ ŲŅ<íIԚiR|V !U^ÛLô]­ÃL;TėVŠģūæ€a ’Ē5mÚÜīM9—8ÅØ-?ÖEÉ#āŨĀžN‹ýŌĀæ7ČéMXx‰ĖžŊ ˜WÍ/MŋēPæĘĖ’$Aē|>äNŊâ=tkGSKĨ°l*0ŧ9ž2 LY4Įf`ó9<™4DmĮĩöS2ī-7Īa%LB‰kŧŠč(š čôē"IóTÅL!íD'™ŋĨ­k­Ô]ŽN|VįxĘ\.Ú2kë#ŅUýĶ>PÚú(Ŋ‰øZ·3šģĸ$ޘįŸĪä&XÍŠLiäŦVŅ頊Ķ5ŋuč õ·RuYuæÔÓÐ?Ī?üīōĪÖŲōŊýįoE·á0äŊđ]U™n4Íxō`gÚ`uōHB ―áˆY' XŒĀjÚÁŽŨŨJŠö§yCßéÂîW.u•ĢÃĖŋÔ>ó8X֕Ģ`%5ØoˆčB\æSDģĢFĶflŊ*5D 0}—" 3S+Û'€S{•dōhÚ}ŌAÞīĒŪéđRšLLļ`ÉĢ{Ō$]ZŽýV^ė *O!Xjũd&•ŽÆMwķj‡ÂôŅ‘m.ýÝÕūPKR`GŲv”o=šŪU<j}đ't3cĘnaH9w $&'rËE͛.{YĩįĸÂ_%t“―šĶ\3f‘ĮÐäúåĮoâ“e›ŅęīģÐģ3ũ-síŠæwMwj ?~ôōŌ:âÔzĄīĀý7đŧœ?ëNĀiXČlÅė„f‚dŊˆŲÉäJh‘IRĀ(æ.PŽZ'Āj]ĀŲ—HíĸÉöÎK–—˜ķöŠ1*0:ĸ˜)Ž~ýtøŅė"æūkŨ.ŪÁq?·bˆųëšĮ2ēÝļ~§ïüļsýˇ@ĀGþoó—ÉaÎ4Â6Ղõā=Ŋ ŽÚ:t<Šïüåp–ÉÄĘ$gąÖBdâvE5­‚ Æ6JĸSüŨĖĀH Ē•iÛĒ%û@Ĩę·Ž“‰V}$:›™˜ũĩvŽwD[™ķĨ•Šī–*R ŲCš—NZR}Õoŋ7Đ=K–,ĄVÎ;ï<{ŋ7Úįk)āĒ€Æ!ŋëįoĸ hJö2V탘ĸä;ðˆŽ ģOĒëĩÆýÏ?ŒĨ&ĸöÅŋāNôRnýÚy  1ŅáķözžZjÍ4—{ĐŊūáqīęÝ)Z3fÁ·þc^*ŋß7 +Ū|§77Ü8^=þŧW#pŠ9ÛqXÔVŌ…rVQŌ Óģs *‰ëÄįüHj™dÜ ­—ĘŪ/MH€*ģˆōŌŠ ‹Đ7äáÐ 0 mSĩZērŠ@ÓevdĒŠÞeþ‚Tõų‰€§pDIo hT·ĸ*UUÃþčiŦīā īV&D(†2ŨŠžŽģKg…õąuH‚†ĖŠjŊh-*Š­+óōP`x―sDđ–Ė5HŠ/dVEkí­ĩČDĒ;SĪųë}þcųë―?*ÉáËŽûČ2UíÛ·ãįŸķãäĶwäSĩŋk)pē(@AŨÛß<1ã&ū†‰Oŋ‘ý[ wÏfŽ]·abđÔQZČõtĘĮeþĩĀņ6wxŠH~―äýāĮ|ŧš?Č3ŝy­ų[Jkítœ·īN‰—r~——Ōņ&2OŪŦûPðŨ2æĪæn­-ōVðĄũ―æŧs­N? ÖÁ<+x―Ró™ÚaQ1éh$_‡]+žÃõwŊÄĖgæ"ÛīĪØh]REžïÅü&NûŽmŋ <å<Å}Ÿ\þ‘TËŨ‹ŊŸ fä3*‹u—(ĄĢ‘ ÅÓ]IžžœÄZåŽÄj!0•Žul—’֏uOG>Žōēķ’6eĪMđ›—9S9í'ílΈNr€ïŦV”ŦČ?õoĀĐý…ZáÔöi2Ņ–pۈy q;ŠEžPļŽ“kýMĨ Õ@Q€§wųčDO>"ÆŊw]Éß/éé ėš<čžzχ|úNš›yÖ^úĸ(OzLæqpäspøSÖþūRšLK9―đ+ßŦjāïČö7Š tlŦLŽōšĩČJŽŋ7&kĒXP B )aCŧÚŦÁĒõQ—p!ārs ’ðÁQÉŦ}ģŽŸqŧLš|Væa‹LÄ<ÄJJé­ú™RÔĸôä†ŋŋ?t(yõĪ~•Y~͚5fĒmÖŽ™õ{õgŽũ=/{„âfw?ħĪōī gžïÝŦ,ÎÅĶ-;đ6ŪPЁˆŽEŊ3kz·öþ_•ČÍÜÍū§—;·ÅŨĄCŽÍĐļīÍŌ=xô―/Ðrø}a'xЏ!2Ąš1G9=ĪŋXļũ?ôö0BýӇbōÍŨ#Õo7æ ŸŽŒ8?Žųü lˆ>S%áå'āį­ðŨįĒcž}ŨøðOYų%ÖŪaTŽŲũ`øyąä]Ü>ó!ŽÝÏ―Ë Ú>yÂíčŌØoß}#––&aãwcõÚRÜ4įi\Aïņ­K^Įmũφ­8}čÜ2ĒöóĶūūĐî™xýýPįŒŦņÔĖĄxhþËø`Ņ*ü: ũ>0-=–ā–ɏc=ƒ}tđr&Ķ éBĀĨzÓVdŪĮė'bõŨŲļō ļuÎlä.{ũĖ{{éŦŅøĖŦpۄk‘ä―ũ^7;―xHýqļûĨÛŅ<Åßx˜Ž[ÛWŒI7ÎĪũr’šķÅóî5‡Í 1ŸĘ}X0} ^øb%öû$`ÂôŲÖ% /Ü< ?įmü ŸmŦ‡[ïŧC:%ãĀÚ%˜qÛõø<#-Óę Ð+Ó‡:<}FĘŅ_!ąUĮObČbîB~i‹2ĐRø0Æ-ð’vdZ&ŋÛi„Ī™ e “*ķ’īoQÉ XÎu=‡Ėđ.MŒë§ ‰‰ˆ7óŽƒt€ĩ$Žį§ÞwI+ŋwŦ$먔…}ۃÐĘĸ,ôūC.Į ø!čŲ áôļ,Ž(ēšŦŽãĨšØēh`Þē”ðäkÛFÔ^ŌQī“&iT@(ڈŌĀuM híą Ž2ƒ ,Ā΁QáŠ4~'EnŌžLóž•dĮ2UŽyÚŽd9æÉLŠLęĖ‹å ŽUŪĘø#’ Ká<–HÂBõ€S.t?™{ÛäŠbĐ ÛÖüSƏĮ}?‚{ģÆ,gžågïÁūýÚĸ۔ģküĮTL9ó‡[ĮŒÃӟōŠß>zÂWJđW.cũ b'üJíƒĸ ļÝįóÍÃ―?‰đģ&áŽG_æ6ĒėA {ō0…ÛkÛ*ÕöGЧÉ#ĩ„ÂdÁĶũ8ýtĸūú4ŠxïûĖf6}û ūÞä)>ˆf+ŸĮøGūƈŧžBߕxāÍïČ―°“A ^þj+.™2ũŒn†Į§LĀĘí0ýš1(Šw ·Ų―ŠþÁ?cԈŧąŋŌ>ÃãŊ~ãîÃMg{á‰ûßáZĸVLq;<Ï~o<=Ÿ<: KķSČ.ڇž|ŦËáÉĮ§"óĢGðų_\rzKĪ%ž‚Ų܅.õÃðņ‚ ø.Ŧ^]ôFŸÝŌxŪČ-o\ũÐ\yQwĪ6ļ7ß=1{Þe0ˆŅsŌģXøĘ“Čújnû·ųëŋþ?—Eáîn@ýxm)ä'0ï[‡iÃGĄ ý`žō曘=i,BxÛAYœN—­ûŽÂGŸ.˜˜ÝxmŅWdeîØģá{žģč'ô˜ð,nŽ—~°Œ:yæN‹Ŋóáå…ÏĄwJ–,þt.!{øËĪÄ2ĮĖĻúš*.fNĶfëtž(ÏLđ]{Pʧ‘:ŊĩNĮ‹ģŠņ“ķzWš†‘uӇĸ)QBĶ89šĻÄž›5oaچbÓîÞ―ÛÞsu­mšiRĻó;1ŧ2аųĮœ’~1ĶtŒVIõ“Ëւø2ó,Úó2ļîáEÂÁÄrĐãŲZ>QBÍÍ[ŦĪŠĢ%ÕÓžXĐiēĒĢ„·ÚĢÁC”ī6JøPJƒÔšĪ4C ýV81Ģ+Ÿ—–i,ũO8։ýâœx"3°cRø*þĶĀZy›kf3‰!P`ŠLUL€ýûĐzīFĸšÚí|ūþúkÚīicÂŅÆí°ō  aÆęĮÏÍđ{`įϘĮĀ ~=Gbō° îþ+f―ũÍ Ä―Ó‡āŦųáóz}p{ßfÎØ­Ęīē, ÏM›‚/*âÎŧ'#5Ä ;ķlDū_<ŸÐ§‘Jíœ@›#°h͚kÄUæ.Ģ9Į―ģoŪ›~þ7žŋcobšÚÔïķ=€g.Xþ6ØN :Nt(ÝĐMŋ“œĢ§œwš]‘€ōŒŊqÃļXŅŊ?zpÏæ %ÎÁw€ÛG4§4ŋ$ÄyÓBôÝĮoÁ=ĩ.ë،Bĩ;Fũï„ëŸ_‚üéÍQ‰ënŧm›æ "<_ zķi„_yãû=û™ įĶGŽšÚ6BnôEˆ|ävŽgĻÎUa 0į"œcŪïåCpßČųČ(dÉ^tóL\tjs|öS:*Ũ0Œãþ­X^œƒ€·bč %Ô–”ÏVd#šëåļÖž’ē-BÃxÝ qæĒNZüyægĮ‘ēl&.°WŋtkdÖ0pž‚B =2 IīôĨÅâûûކw―Þz:—ËH‹Ņ}Ûaâ›KP0)ûģâpõÍwĒM_–CÞÏũÅgrvŊÅ·Ã1õ‰ĄH‹ówŽj@ãéĒiŧóŧg0sî6ė]ŧƒáX'§ ūyuhŽE –@į~•įCAc Ō"̐vÃĖþä)ÛoB}ų=TpЧ:P ŨĨīþω/N pObÆÞīϋ€F™eŧ—GËŧ1m­sJŦWÖZ%_ĐJ1#:ϐņX:ÞãĩąÖjĸúõëM#Ņ 6 `9‡Rõï‡Ūí›L”{wᇏspũ€™ÞyØ9:Ø%ųŨÅ`~Z„īÁÝĶ`WņnOņ:Zïņãē}ĻįÝO]6Žīy˜·i6Vø‘&^Ū]TKŠčaklŋÏÆ2Ĩ… čDW1c5É<I[9đ P™GžW f{/:ŠĩVåíZķĩdŌÏÖCųŪģÎėŽŦJĶuš ÂWųŪ4~ģ$øÕî\Ï &ĻŽĸˆĪņĒōåøĨmȋúŧïū3Ū€TÖ=w"ióĘOą*Ļ)æ>!dˆmˆáŨĀ„'ŋÅŌï›âãUßá‡Ĩ0ccg y Cø9đæo]ÆĻ2Áļh܍HvöuĶĪ7·›y;VāŸ/ž‚ ŽóRŊ:}ÓUXýÚ#xųóup ŒÅ‘cŅ‘øúÁ‹ã­Ŋķļv4—ž‹wüßo/Ɣ[*qËôáðØð!îĒÓIIQ%Ââ[↉ÃWū/―øOjFnøigÎđtú7?-'Bĸĩg8Âcë ŽĻ;SÖ;"á'jŠåŦô @ŦÄüãųW1ėÜSО'č€ZėþýYINGųķUØMg›Č0OlÚžåauđƒ—ŽvzWûĨrŪ:įËR@!‹d”8KQū‡ûa˜ 2ũ0ÆŦ;"Bá•ģ?nĖA§č(dn]Í5Č`ãIÚ`\™B0fF áüôAxđÎļbŪ?·.ŊđÃ?ŒĮcofYî!ŒĄŽÝ ŒV$ĪâðŨPQŲVø ĀLĘĻf—ā…áƒãækoCë^E:}ö/þeTīĘ2gGBL―t”<ūŧó+TĘ%ŒÍŒ(ĪĢÖȋČ;‚Ëv‡‚j†zų…"Čk?~Ųī`|q­uVp—ƒ’ũ9ŊxéFL™ëį>ŋ_M‚EvV5ÞįŪ~A…OZ5Õn†ú +ÏÂŨ_Ū æAøę•7‘•íXâØp>ðŨH5§Vī§C• öbĘZ?Sˆ+šíŽŌjjGUZ–Ö-õۘĪ.Û,æ.€ðÖNvīķŊČT)@ ‹D:ĩM›6㔉Ë9ÄÅlUĶ’ý­únŽų73ōϊ/ö wëĄļĶó€ß€fã<qāÅ0R+5 nëS'`Öú)fšÕ€ô í-ký~ îw*’ümܔ/só‘Iĩ$Ė$­:N—“^·ð‡kœ2ϊžĒĨ.š)—4‘ °338Ÿ•“ī9ô(Ęoš°a§ŽPšDNŸ(?9$))āžTW•É۔ρyŲ66JzĶ™ˆ%ðüAI}ĐOûöíņŲgŸaŲēeķÞĐ3W;wîl@*OęMr‚ŠI`õ`glč―čf­TēÛKÃÐ6% %q}0|P„Šu@fÅPkaA”īĢ~S”âŪ_ķŧÂČū§"ûÛExtá6ÜrïØóޓxlþ{hró9HkÛÓÎŦU ïÆ?iŠęßcFß~ӑčÏ-l˧Î7Jš—ųŒdÝãÏ9ģæL†Įž3xbBz_; IÔī ’Š,”‰üƒ‚ƒøMT―vHöū sĶÎÁ˜Ë/ÆÎÏgãÓL†é[ŸÔĶÝÆ(CâMŪDÐJ띇’:^€.ÍFãÆëĮĢsB^]ę gõƒĢĘ™IŦ:Փņāäv{ã)ļ}Æhd/ëLūŨ^kģŠhM ‰HCÅþðâĢOaÕĶB|ēú ,ūĪ3<åTĩÉ[1xV†á+c0ę‚ 0éá0îŨWđy=LĻï( Õ þ“ŋŨœ’^īFf.æKĒÉ<Ŧ$&mG1’…í”í’I`čŌå=ŠÎ—fĨŧŽ'.ó"ów™xšģEEŒ?&&õęÕ3MSšˆ’Ģ•9Šōu}t0Áõ94t―zˆŽYž‰xž“8vö™JŦĨ5Ô§Ŋž_ūډ3zbÚųãč0äLšķa]qvt?<ŋó^óÃþ\F)DzJ“ƒ9ð—tWŌ§ĘīG‚žâôJËv҉ŦQgýWšžîËŽëAï< *rŌAßf2gØZ?vō"(VŸÏÆ<Ā6Î)ļˆNōpÖĢúSûn―xßÎK•p#dýƒ’@Sšĩœƒ:uę„ĸûß&,ĨĨĨAÝÓ3'–øĮĻzWĢ’lÅt‘óČãpgXʒ’Jô―ņQīóĻg^î ðßáōhœĖøĮ îBŊÞg›1ąßs?Ō?yŦãöĘĐOĄŨĐML{=gėĨhŅ<îėC€qÃysæ"åËũąbÆxLG‚?ĐųP<<ĢÜúQŠhŒc}Â)XķÏ=Ĩ? Ēš‘.YËw Ēîx\Õ­;Ēčdã@ĩ=žÕåxä7ø3ŠŒ[X#Ü?oÞýð3Žiw<4d:5ˆg}`üžGžäGAĢÚLã<-wũEŋëį!ĶŲĮø•ÎyūI<•%}ؖFzŠ1 žk‹uûÜ0dO4Úī~•^2õ~TDŨ3ÖCï`\\ÆČ%Ðķŧō&<Ųíė8ĀeŠ_ĄƒT5ZrųjÅŊ?ĸˆ{‡ĢČQKt<@et˜;&F§ØąöiЉ‹1 dm&žGíHā( I \ Zgû ŪbŽJ™r%đ4f˜=1ĸ°°0üōË/öþoMīöZ5=65UŦ―åØķūv8É<ĄĒzÚ_š…‡ŒŠUðMŊĀ} @|tFŸ6˜Zą3ŲΎˆOē!ŧb?ÏĀۋذDÄE&ĖF Uf›…‡OPÉuüüŦ_YijއbŅjBKK7­Ôėz„›ĸđ?VæWŅBƒE­ydöu„'ˆ„ €$Žčū4{ŅUĶXŊ@]‚‹úF―æœÅ*ĘėŦē%Čč•cĶ⃭úŋĸĒvŠŪ iVێZĩjÅzîA]sMÜͰģ^X„oVŅŠÐ”gsŅĻþÍûor­2ucüð+Aô@öo5XŋĻxxō°ë…o†–WtƒŸ†RĖ-%-™‹D”›‡™ -ôīž‚NI<ķЂ&·ĖŸß§yoÆß9‰kQŊâ…ÏÉpU:Įs!·h4xų0Ū­g.Ïv:{aŨFšŠLâÁæbtļsĶïÕĶĸ”šndę6l†šõcņÞ3/cÛÞĖ.™{SāJqžü+h‚ô K@Ŋ‹‡U ĸZĘaœV:,š…ÄãÂ!žŪ (īĘA’aOÐø”ŪŒĨ,'O4îr*;^1g+‘Р ’ÉĘDûczNGœßŋ‘Ŋð|fIâŲ­ÎŒNšJb--uÉÍŧp=ω]žÜ„ā-‹Ë$·<õī>ÍēáĐI4™ú§€ÎĐ|—‚&ëÓĪsU}čH“Ōū7ęu”`XÂéß —6ux“,Qķ4ædÃķōŽÐˆščÂȏÅʇ<܇<îĒKœöĘOÂøģ[ĩüUĻúĖ̜ÞC]Î<]9ŊÅīb0žYg ŪPĘút8ë|ķÕQ€Z6mĖyÅųĖÖģ<Åþä1~ąœu•äEKĶތ;Ö@Į|þáRœ7þIÄÐCžėę/“jN2_AĖWģâ2đŠéÉIÅ~“҉ųšĢ›e œÏ“—Ûž"ĩÔĨAˆ™ LmãRN?ēĮëZ(ÁēiÓfÄYŋĩEåˆĐ+%3a„uÝ>ün•p†ī=SýÝÞŋ§„šūđ™ųČī’ ŸûÂ―BáQ‰˜Ķe˜žø j{6Đ0ÅøÄĒg/<ēęiœÕ鉍thEˆWB<MšŽ`―ĪÕ)ilņ—ýŦu\˜öXĐmj>ÚęSĖ âZƒõ’éÚœ!Hoŧž L€QųŒ \”‹4@•Ķ#‡+‡F}Č.P”āĒļšŌŌÍ1ˆå›V[ČΚŦjþ›ÔoJjŦ’ڐžž9đÚë–\ÏڃĮų'ĐiOŒéģųÜ{ļĪo[:†žƒæß‡ĩÉþø~Ųjôŧ|üņŠ”ÚÉaíVĩĸü^ Tp;҇ÏrûDhŠwþ„UnÐŊ.Ĩl/žœ:ëë^äôäģ•—{ąøÜIāq0†íÁ{%.ĩ8ĐúwaÁ‘74~ÏđsÎ ä #|ķšUGŠ‚ÆŨ‘ĐLëšUЂ GĖt’ž'X–ÎÄõŠT―W4}š^%$ ä]{(™ˆkjïQēbýéë°TEqÃĢĩ• :øøÁžäKÍG݈Đ+Wc{fÎ:­( ýĨP“ĩ>>pšð uHđÅps-{œõ1mA!æz™cúÓĶŽö!ēáb†Z·ÔĀqīI‚†ÞåuӎĻ]鞘§3߉ĒIM[QäēuëV‹ãuÅPõžþ ĪTþ9f •™Åó4‹!é~óÜŌ}‹áïáoZÐÃyšûĩۑą?ã p*|U`A~ųÆŸÞqâ‚wāZįZô„ÂōB<ēåŽ=°’§Ļ;^c1Í4kMŅ@É|lƒ (\á E+%I‡by1+―ŦgõÝ]īėž4IŅFÂĨX}§!•ã°ō’0Ģgå―+į$YþˆĪvŦu ‹ör*đęĐïš§õMĩï„·Ģø„ Įe“ßd6íÎDAĐ?O7ĐÄŠwÂ{{ā‚ģG`rŌũ(fЈÃ[é†įŽÁÜfŦņýϛčāáŽĶ]ûü?öū0‹bûþĪũJBBĄũ. M‘&ˆ(ŠbCštô‰€`}?åŲPi6Ī Ezï ŌëĸœŲløˆ4ý+}øēmvvvvæžđwnAÍšå虅~Ã!<Ðę`Ą1üċØðëF:qBéÐō(]5ž ÂÎc)ˆjw3š$A.YɰhÚåõÃ^ö=7*u{ôE”ýņœĶ]\ï!Q· ‰xnz ŋpFk)Nĸ_-āÂ0s1ĩk 'î,ō+ĩÄ ÝëĢJi)øļĢĮ QXqÜûR.ƒöÓ9P5ņŨ7J‹Gį“&ņ–$­`Îwþ’ÞƔݟĨXŠ|eZpēĖR9ÔÍXsČ^ž[īH›žÂŅĪUâ ?!é”ô;Ū·tyādQG($îâ›ļ&Đ„ wĨu:É/­@TbD%ã]ˆũŲ@)ÕūŒîEž%ÎÕėKĀ }iUFGW0Ä\š•4@!"ŦdƒŦMðv.ŦÁ 7Њ‚‹&uûĖ3Ų‘§ˆ˜V`l&ÅfĪT.ü)ŦËËN%Kž ž€Ā0:ņá:įo›+Ø―$ôS t æ{YƒÍ >íģ#Č­žę.€’ļ•poĩ Û@ §<ŌZæū‰€s›5N‰P-[K―Ķ:qāÐ:o&š8€ĻÚŲÏJ:`9BPœļo^K„Ūē ˜ķčŨpĆģ2Ŋņ—þŅ7U„ 9AÐïbImxõĀi ĄļŽAST3ûųčÐĄ3ūYļˆbWWøøĒ>9ÆKĨPŪY·sX·ķōy1ÚɅkžh֒Šī)ŠjÐNÞJĘ^)[ öRļKÞxSá5ģà [TŊž+>úc-@­ÓŠ[ã7­ÉóŅ ą'óv'Ÿįn.úŽQũüTėÞļą)ų)ƒ†ļģVÎÅ$Ð7vĢ-rę˜#“NēĩÎJ,šAi jÄę―gN Cæ %`ķL Þþu šD7@Óð …WãÓĖpg<@!ž:rOrĄ°af]ƒwÉ7Ŋmž#­XÕ?›ŨÕVŠk*õ1‰ÁmŦÞ_5Ôû0“igqŪjsgŪ[ę™f­”JD [3kqĸ*Gũë9š čđKĩŧĘ·E+ŋkĶ}-’ÞŨŸą]åž]uŧXRÓÏļýcÉ ~ĄåÐýAėöâŧþQ-`‰Û/óJä4]ēðÆkÏböįkîËņPé.Ė6€ķŒv—)ûÖ``ĸ™čųütki<Đ]XĒôōąh֋Čhû8VĄD|T4`ÝÜIx/ģ^Ý ‰ąGáˆ’Q‹^XRņŅõßWN‹#§$bM*oŪ“ôÝĖĪĪ!šÍEemš@VbB…“!ų#.øīūFĘ/nÓÞĖ)PŠpĮÅĮ!‰NT†MPĩÕO )Ē/B/?§ÆÆĘ6‰n)Čóâs.B_%ÍĢ‘pšk—Ūô›/‘CuōlĘöYI+ņõä(žƒÝ qäŊ\ĩúaäŋ‡âūVCÐīû…Ũ?86ëÖŸ!)į$M],§æ*V°` hœå& cŲZÓUŌÂøŦ$ðíYķ…‰—I0W†šŒh_ū%&2kÅæXíĻ5Ë#Ę5íÄēÔæâ4ÍdƒœĨĘQûfÞ+Ž’XZž‡Ķ’ĪĪp=„m|­’€QĀ]œŠ[āzhW۞%“1ųÕ=˜ūė{tvÁþC‰ŒÛ šG™qģŸîųË=p{AĒ‹ŨÛ >,Ëŋ։4ßāXófðrxĻÔķ7D)ĒČÆŦ“Ÿ@VÓG0Žk3:YļxIÅgŊï R\>‰ĢÉÓzģ‰+1Ę<:gļ"Š Iœ-ĒL’Mb˜­Y–@ˆ@aė3IŽ…lŌŪåĶ0‰h-]žTYɉIFóVë[68 (õ“(R a+ĐēA•Bä+,Úėȝhj@tDÍ+X°cĢņÆũ:Ÿ(V! ČnæxÚŲó§đįIąš'EĻŌ~ó*0)ų ˆÏ9Œ#ŧļÎÉāÖЏm_i™~HĖŠĩH™‘ ĪÝQŪVBØēqUc \Ī!ëJŽQí  ˆ"Ôŧrbītųzjã<ÚB“!–ĐēÔNĘ+uĢ6Ļ1âLG *-­yÚbc­_˖JĮŨSJ>›‚CGO˜ ÁõTŊâšüÓZ€Mš‡[õŲ64ŋŧ+Ę'nÅēÕ /Ž? Å/f?oēj`DįķðJįdM <Ņ;IFô“TGɃãoÛÂ71ī{ 4jŅ3>ÝI“2zĪÚü~ØēG6.Á'óūÂĖ)ÏāŅąŸ “ ƒFšdî.þówi+§é%$š>q5Æî’„ߝķŽRŧŨZĨļ)—ö™PSڛÂČlŲxōŸŪ§â,Gœ ‰ĪŅ)Z-r-@IH8ňœ­tFˆ-ēģÅv:VēŪi­ð2‰óeÛGõð ïß*`ŊeMσ…öÄĨēpœÉ)šÂÁES]3?‡Į’gĢg!zü§BœØÉ.Yug-Q­˜vqÚ2đÕS@-îFÕûÛ\wŪđboj§Đí5Į˜IāŊĩdÛ9ŧÚ_Ï2­C›ŠjRbđÝSžRÃņŦ |†@U­/éîsįũ―^Rĩ=1ïFƒð"š„ŨK%‹ëņÏhéœs؛’†+ūĀ[ģ_ÆDšJþÄLœá˜?ūø=<đ( OÏø%č=ƒ.Ý8öĪQ›ÆI~ZZšųĨΧR)ĩūƒGqį‹â….Ĩ0cčؗN'ôG7ã§}'VíFīĄ‹đîw=„Iß 7ŌPéâôũj+ –ÆŲ·ÄÁˆËӏ;å ēÓŅOĒ.,ÛCWvDsō0žÆŲ˜Ž â‚<(ķps‘ĢÖÞ(ū$ņØHôšr.ÅZƒãĖM á˜, ī€ÔÞįΟÁ>eįO·YbemyNČLĶŌGÜbAēŸuâóÅGŦþįø?‡€_43“"õ*š§čąĘ—Ū€ÝD+6ĐÖ)Y>ë͉‚*ns{ôi^E`Æw“\›˜Ĩôöa*ËģÅŊzaĩīÄūŌā3đŪsb#š&5*[Ę[’ (ė˜^AĒ[íˆã5ë›qĩÆĩJGŽ$cÕÚĢÏĸÖņšūéFúzýŋæĢ_ύŋA@IDATß{Ļ di_Ŧš?į°8īē8|bÚā™7ƒßĐŊQũæáXģŧ=ÖʁãûĘaõĖÉørýwČߏĻO߆Įšixâ•o‘H k%ïĀvøāŦŅ8K:ŨuČDīŦC° 1y҃øõH:Â8þ}™ŨÛ'%|ቈRaÆ=Æ|qú{ĩĀ€ÓŌ5–ýC #Cz˙E‹ËgI"o*fVĪ­ÛIl˜žAîMěÄZwˆX›rx] !M\q?))į(ĒM3bJq\vēAT€i‹Eī_yBó#°°ĸ)UXyĖ–îĪ ė…lÐīĘVm.žãîũ&=‹ž é-4áč؊–"ąģ2Zœ5éĄF ÆōäCĄ7ÛČuWj)åÐ8X #ōf›d°-5ŲP{Ņ.' :–(XzTü3ϰZģ­vŨĪF *äÕwx–SųųuWiÚ^‹”””%K (ŠZßX‘í ZYIŊ-[váĢ?…fšĸníĸ‘zÚ― ŽÓSOõÂōĸH9—ŧ'åĖqlŲy€FÛîĻRģJøZfHÖ=y8ŸĸÁ&ĀúÅËÉĀŠŊŋGH6Ļî萜Jmņgā ?ßß/þŽōYJeR“q:A\ĮýF— y›WA,ČËūđÆĨ‹?ę• Æî<.ɐ,đR‹>Â͋ãÍw?ų2ZÄŅ4Ęéū^ô j·đĄŪų(Ųz^Ŧ{ŋH›IÎÎ GĮOE[$ąīōöï&íЈč’^HaF+kŌĐŨ!ũvâ\E# Šļl5‹/^_-pyā6"UŠųuíu9íkNČcīeE„‘ژœkdGą\ė‘ “° <ōĻōx,Â/Q9ØLŠįtėIQŽĀis˜ŽĀĐ{Œą?KXęYę}ŲôIëbϒ'rĩ:ÏʞMK1ŨAXܜLQ˜ã7„Õû"Āiđą;ĸņl€Ŧ=TŽ\V―§ļ―t:8ðōĢý ßßÍō}ĨņJŽWm%īÅĩæ=xŸ@՞`Ðd‘jKģŽÂzëR$R”3Å(Xw€*ōj˜jōĒķ—‚’ÞŌ*K5ĩū›ū™ę$ąėUŊEJHHAÜŲtÔŦ^†^u$E°ū›8ė,úÜýÆ;œ,ä Í žĻpõGÓąŸgãéZāüĢe\îūĪË0rôÓøõŒ7Ũ―ŽĒÓcĸÁØ;lûāäO ðāčxîģŨP7äR\s>xö)4|ąvāLÁŦC ÚØYč^‡NĀcÓVŠJXÞŋ/W­ĸŅkųøyŅ,ú7]†°Pdy”ÄØg_ĶįĮÉČĨš†ĶīũlŨŋ7ū4•"ÚøĮ2žULW4ĄŦđ(ŊŌĻI!7§Ģ˜3ýkÔjÖQÁrƒ„ðR–“ŦdŽ=:TwįX[ôŸYtÂÁx˜KŋD•Q=ČŦHß2xĢåc"ņâŧ3éïڙ.čZÁYkT^ŠŽÅįŊ·ļUĶÖ7ʼnššōV)þĻŌfr@04JC,BŠAJŲrëÁrÝŸŌÜÏ5Nž@Ũˆ}ų>šW?Ã92Ŋ&#:6íÎķŌzĻ€Z"r­qšQ.”ƒY u­ĖQTđĢKĄŨœĐSĶ™ũxĻoš§xáËųßaåŌĨč|GWÜÔü6zâ„ŽÄÉ4Į%ĸdeR“‘ýAn ]=KĀ=ÂWÍfūM–<Đðš'fšóé{OOėœÜļzxQ$~ūč J?831ídĩíųk@*挃ļʏ`ÕóÃ-õŽ;ŋŋύí‹%+Ŧb’™Ų8ÞëļïĖ€Ųė'tНGŧCOãóŲw Š ōüž§1yäĢĻ=l6îŠÎąäPIĮĒþ§ũsp81uÚõCĸŪÕĄˆ[ŅáŽÜĸå'ã1ĪN/ĖzŊ-ÝTđƒ:܄~RKۜ”Æ)ON~Ae"9fDtHé8fÏ'1Nč2f 3ëáƒ'PcÄ4ÜrScļ‘!Ļ}Ï3˜ÂņšnĢžGpƒõČógĸž°óÅï]Ũ-pEāTíEŽ q7Y!e,Ũ$ —ĢÎ$#b/â,ŪG‘9D”-1ĄÕâÂõ6Bũ=üŅ#‡qėØ1ÃĄ œžÚˆ" ĀŌL­ŲĐ<Ã―ņY†ĄdÂ$‘ŒZãôK+æKœ_Ŋ§+Óæ“ī›â:j>ŨU–@ʕAfÝĪjŪ,†šxŒĻt LŊ#LzoeJ&Åș$ĪÜgÅĖãŌHčü\ý‚l'ĩđlŠ€Qœã„[ïęÎ5Ît~éT$ĮE@Čd}äV0áĖiœãûęš:b5Eā;ĻݰÆTk‘Ž“Yã$ŠĨtdūŋƒÖŽÍÚ2+ĒũH™k$ÆzĩĀ_âZŠž'î]y4ļIÓI)œ;·mÃ6F ĶCíšuęáý·ßDýßũð@ėÝ~†o­o{å”ÏhŦ>œŽŅŊÁwņAó.poMũÂ~q[ū˜gĶ`=ų”ĻÖģfMBČÉ1bæDyd`Ņâ%ðŽG'ßŊ>‡ēiøxæX<3ũ'ÔĻZ žĐžčųė,tŠQǰ"y {°ø@2úŽhˆŦVÃ?Šj–ĩú üaúÄą8\ą#F°ðÃóūKqœrjjĸ0gūŲĸ+V§Įā•ÍBŨ&ôŅ9ïÄ ­ĢŦ^§_|ũFŌðq|w―ÂzïØ-  4{ū“'‚ËTD˜ïĨÛÛūĢč6—“ŅÐ mðpLkC4ķÎ;(`ų 2]·a͂1'ĒQ41åīåë7F%Žģ-yƒNftē# ŪPnØé“–ģ7ũ 2ļĩG4/Ó­ņ3[īŽâãë―.œüðâlD93VąWĢ­ÖßD eĮĐäNEžķeh/3ŠMÕ9­jŧ}ÛV4jÜÄ,ŪQ̆)įÔĐSˆ‹‹3îö홄š{ÄĮ#1)Ņ€†‚aK<šKtĖŌ`!mu&PĻ+§ĪŽĩČĀŽ*˒Ĩ˜v‚_ųjDmĀîes1häëüŅWļĢaýŠšâÔŠÏ ßÂ- ,†ýk!ŠûŸ@§Ö°|ũhÜ闆5ūŽcÃĖĸ›ƒąwũƚĢāũLýðgĖøũįôBô+zv{€ą Ó ËŌNڙ8NzēņÚko!2ë0ŽqBŸg_AĸķŅØōÞK˜sŽ:}Ä0cw†;âØģŦŅRģ ĒdÄŋ^Ē8žČ KņÂssþƒf/ ÆSƒŸC[Þĩe|Ï0čú­ũĄÍkKPyėÜŨķēéúlÅÉą\S&óÞy#Ö}„F=îBŋ{š@ĄYOĘĨ6ýĨ§Ī7Ũ+%…ŠŧX…ūXY€Ž.æũJe_ŋ~ZĀ9.^)ŲqŠĻå`Š,ÉPebãfTĒACž fRōP~­ŸiÍGÏ:,K;ŽaÃöíÝËāÕÁ&˜ąXūIuŽðböą€Aψ9z;víbpՃH<— gŠōīÖ)1ŠĪĩĐéå|­ÐóžĮ›õÝ)úL?Š#ņą &ÐXë~*ŨÏ͏ŊĀ™X]äe°Ë“ƒŒ)a-\aNFž>ˆxĩE’ —x‰ĮĪŧ’;>G1sÝm‰ã,üØSŲvYrh@[RiĩšqLPwLj7Û7­žé„‡‡õö}{wÓí#ģóœDīôģęéåi<îœ8~ŒĀšÅLTŒ e‰™ÕÖŌhÎw"ā›ï@N“ #ЧŊ‰8TrUFÉģ90įLåköWíÓq ĮiZ™ø–­…~ĮËOÆķūAƒŽ·ĒzËÛpŠ8•FÛRk råz<Ę@ĀÍoBïöu Ą6ïi·ī3―D}6ę~ž@0'8:‡m䔗 Ÿšwbæ+#đ֔‰ú ;撗‚›w"ąÜ=h^-’|bZDW‚snÜŽ 8ųĢÏĢcŅĸ†Hޜö ú?û:zÝ8ã§―löøüŲq˜ũËblŠŊĀēĮú㭍ûŲõ9ÉĢļįøw0ôæ’HĨ+Į‡žxŧŽōc―ņŊÞŊbįYŲëJJĀ€Å%J!ČÏQŅåā+O3Åé·-₯ãó›Ī#ƒÐŋĸHŨhŠ{ëXÁ$Ą)NÅ-ðgķĀ偓ÎWXœĶĖ`r-ÚÏ1bjnŌwĢC$YR[VÝՈЄ#NTG"Gí'ŸMÆöí[QŧNãbOįÄáÉ.JÄEɈYž€E ZąBETg„q—9L|JÖÄïÁē―›°Ë $dŌ$=y“”X2  3’“Ō°ęāVtðl„t‚…ĩf놩>5°.ņ'ÆčĪĻ’uKKįúŸ+Å= GĨāČįRS”Î#ä–Š zîÜYÄŌæ4)3…ĒZrNÔ>“’N' lēđrN vW&"ŒËn8v‚īMbÔ.3›ïĻsq@uVí;täÚÁ’?ÃUš{ þÚĖ™fbĒvĐ‹qOíK ļGcbBÔ7’(HrÕ§á,%Ķæ7’bóÓ‰kyîZ$ÐöpÍAIJ1ó8ĄĻJ‘}ŋaÃąnųRôxh |ýÝŦáā<$MļØÜý·ĩ ĪH<o%įĢZ‰ÏH›‚ŋ Lyd(ķßô8Þ~ †w―ÚŒüD,Ûɏây•—ÍI–“.Ï@?x'ïĀ‘S p=ĩ Ã‰-’wXY„xž%7i­k–āwĨÁ%ŋþ'SœšĪoÃGûĢMÛĶðcHĶOŋ„ö’ÍZ|ī=Žž<Šë“ļ;ũÐëLmDųQiŦp‚Åšqr“ĨZœ.ŲŌŦðāļ­yk'„–z qĮļīR'q'b9>9F4.‹Sq üI-pyāäC,ðēÖËīv)Ó€ ežbĀ$T"úFӖZįĪžĒû°PýĄČĄŦļ<ĘũíÛĮ5ÎÓðóģŨ‡X$ĐžãOÄ]"M‰í$@Pđ%|ýp_›0Ē՝8œt_îøŋÄmÆÚÃ?â4―ĸäŧ{Á‰ŽÛ“ē œķĢe™ę0ÞKž€j6Óą·Y,•hH˜SHp―‚éėݟ\dÎ&1xu2vŸÞĪ”Tļú3‚Kc8ō―|éMțe–]‰pŠąSôF5x7)RQņȝkĻAÎĻ–W“ÚĄŒ,ÃgJÁJ) Tým@Ô;ęý9―·~ōĪĪ<šįĮõë°wũNcß(ŪRœ―ļN[KWÜū•ČiŠë$Ņ—ŊŽDŌ&vbI DJŠŠģcûð—lDĀ<Ý8˜RXąįüßąGWÆ;ėĘoĶđ 9fæņrĩ­]M%j5ë‰îK0äþŒ^аJmҘþŽ3 Pđ 2*ŸŊ\€·ņŽdŸÅ’Ï>Ā ÝĐĻA;›ˆ‰B°§gļ ~—^hķø <Œq4Ų^4ŸQĀoĮäƒ!··ĮļბØĨ–-ތN§#ÄÍ!ÍÚXYģ#ðÜj4ŧĐ JHfčÉā֎…˜}rūT{wæ$œYu\ËėÐwJ:ģ/PĮ‡ÛūÂYO‚aC•؊ļ:mđ),ÁŽĒw4 jŽĩÉŦĐÓ႓THyø†ŧPŌ+Ðz|ŌO<•ąÔ€ËqŜū“ŅąBŠðėũÎEŊ€nf X/§ũ–ŽVÜ·þ‰ĖĖgLG­•j_ÞFXg üí­ŪéXÉqŦũÔą&$MEŲēåW*:aø@đʓ3 }­“ZŠ><&@æHÔÉfræ7“]­”ĩŒČĘhíRžMP)ī-02ø‹ĸ–ðG)Ú)î݁čę8‘`%ųę”vSī.Į,ų8ēû0ÜSbjŪĘUÕÆ§Lmž°äK|ûí:JœQĄZ4*G ÁėĘRqÃÓ^C™ĨëX†k–Ýąëp"žĒę⍗ę#ÜH?―1dÆÛðĐ7ĸpLó9ķí>öq{7ąé…qE—‰/#âŦ/ą16<ũš4Šđ0‹K˘3.§Ýéƒ3ÞEÏžt>pĩĶūƒ[oŽÆrr0|ÖÛðWęŽG_z•Wl€ŊÏåĘšðņĸSGœĻ–ŒŠˆS'ŅæA nw Ē‚(mČ EŋqÓ°âdŽq§8·ĀŸÕ—N>ED]„͝^mzZØ@šPYäEœ‹S„]Š3Qj_8 UD\œ•ņÔ#ˆ7Č―[EŒR:Úŋwj@ÂEm/ĩŊ—·Ŋː_ëŸrÓ&ąĨ€šž_4F7Á<î˜ķöuøSŊü§―äDí@[š†côĶ4Ā5―čÝcŨđÃXŧán.{ FīéCåŸTœb Īäģø1öGėL8€æ‘ Ð―ę8—pÉjū ~†óÖ>ĸi_ïŽd_ŨÖNö9ûØj'‹{. žö}ښoĀ›8€]Û·^`ęnHȝ_ĩîâþÏkÚęÛHđIÉrč.%h|C}GËÆS{!Wenú þĒ}ë:Xš|ū]ąL įI‚ŒÐhݰÂÂÏkē^é"ŪūeÐą[™ ŪÔ/°dņ .‹.=Ę^‹Ūlí– īcŦš B݆ÖÉ3[0xĀ‹ˆŽRĮwŊÄáZýКjXá―įw<Ņ Ëhpþą{ÎÞĻŨāJĀïŠĘo0ũ5ĩ6eļĒB―‚úðŒoɊļ―GÅ Ë/>:ß\šĐPŊ#įO™=WoTĐŨŒþaQš%íæâTÜN \8Åíī‘ËŠ8K[–qKĮkƑņxģNâķ ˆyڀ”ļ0ÃuT<\=ČąŠ˜ `]q”AŦũïßo€ÓC―ÚÅöísÚ:æŅģen"1ĻDŽi4ņ͘ķ1ÁÎ'ĸ]r†gą`ý"Ô 2Üē?ÅžRšĐæ_“*ĖÄ/ū‡ÐĄ\mÆÎÆŅ„ã\Ó<‡Ģ‰G°,n5œé*ëĄú―đF‘.AÓNV}HéUn$Ņ“B‡ zš^,ulŨßÞwĖŊē‹žĀjrð3ÅīgAƉ §sú6z_•įN[@‰ÁJŒĀšįļš&ÎWmĢļ›Š§>ŒÎKëŨ,LSŲ™ÄG—þęĪįVŊ^ UŦV0õ―ØóäČA‰ĄŊy ތņÏ ÃÎýąpoŨģ›ÕĢͧŋq HŽ8·ĀŸŲWNq"$ÐâFšó‰  ĻDÔHIƒđ^FP-ėšŌĮЉ·”VōI”Å…I!EڄU‰]ĐPD>g(ŪÝAqmíÚĩÆĻýr"°EšĶį+ŲŨīŊs牔FŠÖ™tØĪL#4(Y+PĖUÎ?ïþ //Á7ßC E?#Ū T)…*!QH&(L<…Fj9zę0>>ø ÅūGqcŲ†hÝ ĐÉį—ô\G€S}“ŽmāēójŦš:ž·ïąïW™ĘcƒĐ}ïîÝŧągÏn#–ų į"…Ķ>ZW66œlgĢ]Ë5XqšúFō'lM(tŽc™™5NÖŅ8ŠįZŸœ2Hž|-’ÞU“&Ģŧs-ø{žĄāĮ B]ýũÜTœũïÜęĒsŌÄ·é˜Î‰O8óžĖā“™ÜZváyĮ<ÅûV Hq‹Ttĸۇ> oĮm{!ēDUþӑLŪõŨ›ņúžw–ÁĘŨ+Žĩo7Āj=Ûæíz™Jüąëĩ[ÝV4Ŋ}N"Ų={ö`Mwôîz^'Rô1ßEã™āéLÐd~#ŲŲZļúF2žŨšēB’)iĒ Î,-_ģ>Ksm=CßņzIēŸôø Øē}/Ö/ž oËâõRŋâzüsZ@Q„âîĮīiӐåí‰ģ4krĒŽD`€+Ë5B­?āuŸ›Ðö†Šp§™“’LęÖŋĸÞÉh†YĢz0ä uþÏn[CĸėrĸPyŽKBÜ1äP/$4þÄ WL4Ïc[m|įüŸsGžóX[,˜ųÜï|u[žÂ”É♘Æ(Uƒ“{‹ŧb‘ŨI†Ë§ˆ4đ)ũHī'b-‘†•Ē"žš€H$›EÍV‰ú4+į"e n QW) Pü֊#5Zž$ėâzRÉímÚð ÝTĩDIF5°E™6(Ų€Ą6Ó9ûįxŽ}‰iŧēitSÔ)UÛhóVŦ„jÁ°:é'rntׇ!>t ‡ŋ˜W˜kÚgÎ&"–>ms8‰ôÎôĶ›―dãßöÆ―X'âNāēëĶį].Ų@Ļ ctQDŨųN|'Ðä΋ôžl>6 zŒĮėÎUXūX#%Iŧ,džžĮr-eyšjĨč*îĮƒÎĨMnŌ-\Ð( ît’ï"ïYôÎdø›üđð ­4_HÆôâ$―ø1 €Ū†š™Ė+{F%Ãåðj=ÍĖDÔüŊĩ5Ŋ:ƒŧ:˜e?ș?žD―šŪt2ö<`€Ó‘Ŧ4(øc 2ŽųtN€#ð0xäHī*ÛÅ|ôŋņ>ŽØū’n)>fYįôĄ).ĶzlÚđņ•›"žZīq§ã‘•š‡&^q(—þm=ÓÐĐV$Ðký,mÁÓ9ŧNŽĀĻjÛĮv>ģëęļĩũíëÚ*imsŨŽmlkMVÔVė”äâ­:°|3áŧsHŠ' 4ÕîšØč„| šfšJâwóM(N—D@Ē`_‹Ī°b_ĸpÁeKāĶ–1ŽŊĐ6MI%ŋŌsÏž)Ÿ1W8ÜŨËô“Ŧ­Ũ9ÚÛþšãōiNTkæ%ŪÂeiVZNI%qa{Ņö60$Œvž†Š>6+)ŧķQû›ëõåŠÔBŲ’þ…ŨŠwŪ‡ Ķ3”x†“ó ĒBé}Ė‹ZæWJ—^Þ(_‘ŌŪėÓTR D^éh”-mnÝOiN&ãÃ>ņøbŽøv Ú>ø^xŽ#ŽmúKēęĄAō8ēę<þÔ Äēĩžkëwžói5@bĢņxöä^L{úQ|ŧ).~Ĩ1tĘLt‹IÄÓcÆaéöSīŦ+‹Á/ÃÝmāŨųS1{=m·oĀö{qëāĮáđú|ši'ŠÜõÞzĒö˟‚™km…yv먅F}&bęðîðÍ<ũg=ƒđ_mĶ[Ëtīë7 cčˆÜckņėčŨáZ> +–í‚Wƒūø`Ú`ú΍Į;SžÁžķálXMž8y2n.—„ûN@Bī/vŪZƒ―7âí·§!&~1Þ\ķąbüއ1rčýrӔ< ïL€ė6S0īcÞ=küÛãõ§zbëWÓ0{geˆ›4\ ŊDģžlÖ,ÅÓukA] jkßZÜĖʘO"[•Ŧ”'Ĩ"Ę%úHečŊ͛6j‰*ýXčgkkÛ[SŌZ§:Ŧž§kâ@ëFŨGõðęœ4RŒIo5é ?æÁjđ{äcû–_ðóÞíä(OâD|Đ ŒŠn5ð@ƒÞ4^6œŦ]ūžaïkkĸt^É>vÜ=o_nŦwÍįÆ?Sņ)Ųp‡|ųLM6 ĮÎo`ĒžH㙝Pâ9@°EęzMJŒÂŌâJ•Ū ęn$ mk:ģ*õ&;ŽXđjeāJ?ŪΜĄģũÐũ°'gÕđxíõw(ZÎEģFm(rŋÚ°byØųó—ļũö^5áYŒ~ļô8ķŸ’―+}'œ4DõbŊĩõ‡·qįwaÔč‘ü­o·b)žÏ›―+?ÄðAcņüSÃŅýîøbë™ó—‹ũۃ`XąÅŊážûú`ÔĻáōø3\rĄOĮŦLWšükÜŽË,AICĀįå„M+ŨÃģÁ@ĖÛ‹gĸ›N4øáčl:OÎ-ßÍx ËÃnÁ‡ó`Pũķpɕî†Ήk~:æÏ‡OVÃôy_āÓ·§āĶrĀûã†aŲŲēølŅBž4Š<ĶĒwŦ$Öãô>|ņÞhÝkþõDWL3y­û`öīá8ēā=ĢËČĖø―XôËÐážņxûåąX5ũ,Ų’€}Ëæ`ÜûĮ1ųÃøhÖ8Öõ|ē’š#Ūøåŧ%8z;^{åylš‡OdaÏwŊaę’žņÕ ,žĸ9ô@vpÃ2ŽÞã†qģßGįėøũÚý(ISžÛk•EįQÏbø#]éÆZķƒK ‚RņéįK‘•ēsßø7–Îĸ 'É ŊøôßðŊZ‡6`ÓŅÓĶ=Ô*ĸ„tYāT‡ũ"P'‰īÄŦ<ɎFn’Äp8ŋŠã‘TS a‰cE”ÅąJ<Ŧu7õ&‹˜s“Įę[ĪëPōKãý{vÓû™v^„tŽý‹muN`#'ęü<™Wœ”ývĻݖŅS(*ĄžSýŅĶ2’J0ĖM>ˆįž‡öãô™ViQxzđĢó ·ēr‚Ą>š]ŸKí[íu>Ÿ}ŽüJvýírėëŽį•oßū}Øđu›™ž(ÞɀÛLíŽIˆ&-úNžlLƒ49Ō•’Þ=‡ ))€íkõí4ąŅHĒ\ĢøĨIÚŽĀz-’”šė°bO3bÉĪį^ÆéätãáÓųßbÕŌÐŪSīïØ)&ŽØ•kuîð:<~įÃðn6ß}û –.úĄ?ž‹þ}ßDßũûą#1hþ&+BÎÅåâDR&|ŦݍI“žÅΧFĄEå€ rč ŠE/žO—€ß,ý­KėÂÜÏvü&Oņ‰ĸf d›°bõÚÄĪgŸÃÄqCßôÏq‘•šƒ―‡ã…>­PĐbuŠ?S‘*“PŽ?ŠMģčŋú́}ŅxŨ'ļûŪ~Xļ-ŽŽbHV95f3ΝÄO 7 ÏÝĢyĨDFWDxp:ÖÐJwč‹ēAļáÖ{Q+0Ŧ·Å#ß-õï‹~ݚÓĐ c6yĢę†jĒQŽt—ÅRw$ n‰ûŧ5@Ģ–pWÃR 4p?-ýĩ;<„fŅ!ˆĐ3zŨ,-›öPÂÆč,ĩ`ė{Q§JE”+Įņ-Ë éČ6 ļëNžđ”"\šî"O\‘:ašTŦJN܇žÐxŌŧÂĘ{!8Ē J‘+'91ô'?ύÚÜ ß}K°ā?ŊĢô}―ŅīFūZ<ßïŊ‡þíĘSbI[dUü”. œúðâl\hFb&ÍJŒx–@GÐᖮ^(sã•Yž‚$C”§!dqHŲž..ÕŽÓņXDÛČþyģˆđÚ5–{wïÞepHŠöOí^\ėkÚÚŨž6pęœĖ^—Ŋ?ú(Íå:…ļÎŽ Îîø õÂÁØM˜―îcŽ?ž G’ŽáØŲ㈈,‰`Æĩ9n•c?ŦčūŽU/ûžãÖqßņ~ĮóŽûĘĢēR(>]·v ý˜ža'e;ē€đs›âhqôlCÞgė2Ų’nŪZGh]mb­#[ÚÎĖkʗFģÄØ–‰‘žiDėĶĪŋö„Ę9‘§Ûũė܁ĸžõ&>ĸr6oۋũßy‹~FÃpïCšŦ5ūāUĪÍŦŋÄš€xæÉtÜï ŸŌ51éÍņH:ø–ĸēoŊXŠŊŸÃ&"ÖbB KՄ.+Ũ~ô?[ŦZu„ųQ„Ar‚_`8"üč'øôq~‡\T*õ[p―ā–âƒkÞųĪ'ŲyŪˆ(ZUŦ"€Ë2,‰š9$vA_ö)’ ކ&Ė#a]WÎ\2Ĩ߆Ũ.ÄvóäËØt*‹īP=L†g"Ŧ—ÄŊûķ‚.ŒđžGÎ6Ûôíáqú„Î õäaŠsFĐpāĖޙÏPĘTÓųŅķP\Ûēe+c“iŊŧŲ€ãļUŲŽ`e_Óy§üßęYz‡LÖŋ~ųšĻYš*ÖïÝH 'ãuōÓņ81 wdäĮá—ģąŽ{žY·‡Ęũ0ānqs#…eÛĮÚ*™ũ.r^įŊ;Þc_sÜŠĮÁ›ÓžÃŠÄVXņf­kŅTÅÏļęPXą˜ũýûyÏ<4čq'úũî JYwʖŊd‡ [.—zŌé͌ŽĢt‚Čeđy4aËd@vNĪÍ~k –N4ŸŠRĄƒDh’ËGóįä„NũũĮûÃĶĢoę6”ĄbÎ-ũ @ß'zbðÓOãņŒĸË7šĨ Z”õÅfŽ‹ôũ€N,$‘*T)ý)g˜zļ1Ёå3ðä짐ēoŽ•î€võÂ8ųŧ! 'að˜<ø'nÅZ—†˜Ýūý-ÃČO–Ų hH-ôžõŧ=Œ˜OáŲ‰SQ5Â0hP 8ņšĐ?›M‘kĶ; ŸQ1ҘōܓøĻú$tn\ nô'šåÅøĒujW‡ëĻUĐ*œ’kryĝZÔáī]Š$ôęÆžJų\J“ä‹ō3Ōi^ģdŪþ}þļŒ3æéKUWžu/\HWoûāEM05’Y#įh…ģBÆĀ"ØFËNe–ā!­M€īą, üFäČÞ`š(‰ŧ”VˆĀ†€§Ð–2š|ETŽXŅÏh:ƒZs ĐFāéÛҁķĐĮĮndÅ:čÔĪ*|9þÂËUb„§ōĻR· ÏĮĀĘMÚcH_*ÛļįĀŋTu4Ū_ĄAÔf ŠD“&uJ/g^AĻMũŒåJ‡ãāÆOąÅĐ+j… Čúų(EūÎð Ј[Z4"ᐁ’QÂōûĩō܂P‡ũFq’čĘ@1ĩ› &Š‚Ã*ĒëÍÍ›˜öïĄĻR­ĒX~ÕšQđBŪpFDåĻ[ĩ<9x7”ŦÓĩŠ DhiD– &ôY­˜G‰Xiš•ÜÖģ5*s…ķíî@óz R―ē5Ņ V ”`xžčęuYF ü)ÅĐSŊ*—+AŽ}ýíųsÏßY) Āß0Iô EįÖŋ-‡ï$­&2âU’bģ^FÂlĀ‚\ĪÅň˜ëv‹ø}RRiƒŠŧˆjUSâ\ƒæšÏ•/#.OũJ$Ž5ŧMTˆiذ!üýýÍ―6 ˜ŌyŊ}lou^b_ŨVœŪQĮ.ȟ’–ŠvėŽ3ļž™p.ÎIÝÏ·Ō$LÕ63!7Ɂ·ögikPy,RĐÖslNØ:cýÕóó™ķ)ļŨzŽ•ïRįuUŨTÎNÚīnŲžÉj'žģxÄYRÔL.Zeėc9á0šķzGÞ'ĩn‰tôUĪę]2JV ŽŦo)ÜÐĶ4đUŌRĒB]jðrđŽũ”ŦK`įÄ_LlƒzA|oé`Ļ þ^éōĀÉ’Ųˆ…bBŠ5]Id9GÜ#Ŋ‹{īX›õO6ˆˆŧÖŨÄՐ.E éĻIIH Đ5PãŽŨÕp°Xķ‰i ïīcÛ6ÄĮĮsVČk„XJÚ:‚Ī}ÞūfįéY†æūžþ”/˜’å°þĖ)FIŅ{˜ ^HtËš4ŪVÕ)Ō•G$•eĘŨū’ã3Í þąŊŲĮŽyËÐuûØÞÚũč―ĪIŧᗟ‘DûMqâZ[Vû+Ē‹YÏdÄŠ| `™šˆsðkĒo"YÓđŊ*Ŧ\qŽzžöĨņŽc‰|]Ipô tíZ$õ Ŋ"aÅ:tŋ =ïđ §MČSÂŧōüްbåVlúĀ_Ļüð0tn ·Ä―xå­_1öãEĻFĶã\X6rfVz1XĄ„bÃâ9Xž-ęĸëą1ī^íV ™€—†ö@|ëxïŅÆØðåŦøtKÂ<ņÕŋĒĮˆ§ŠAóZt–Ŧ}†ÂŠ}9ËũeãôžUØÝ“ Š―8ôũ„#]#Ø8& IIūž33%ŪâūÃyuÖ\šČŌ‚TŅdĀēČIYŧLŌó oã87KdžRũķ ßÎËx<+Š:nqAŌ2Láó9Î ũ™KïĮ(ĪlŌ>;éÝėĪúdPóýb)z MÃBŲNųōH{í6XÛ)+Ë>kŸųûl/œœSˆ@[ĄÖÄÎKðÉ+„>Š~š&ïŌâÔ=–Ļå„\û.ä<Õz3sLÎS劐óvī8O‰p:þ”1MĐ@q­Ū+ĐLýėcĮsö5m•L™ė ZīÅĩæ^‚þÎaÍÏËđö ũlÆÍdļ0g:fį]ČJËБ)Ö 0Ę9v9Ž RėĖųĮņžžĨũīïÓą}ÝÞÚũ9nõ<9žßōëFžfg§öŊQĻbÛiÝÖžÛM)“ģ9}MFØ2…M^ôÞÁęŧHK\eŪūóó&%ĸĐmÔdŲRÐGļIaÅÂ}óļg;Å6įÊĨē ÞÔËņ`@ðÃŧ„Ŧzu5r @ũģQķÞ·Øu$)ng蕇%Sû#?v é9ŸFü€lŸĀ ÅŦlÐē•.eïAߛoA4cPķ…ūO―‚Ž`ëųŅõZĒaævĀ—ÁÓsûĢe“ŠWWŊâ\ŨĶ8ŪÃō&<áĒnyÃnn‹2&ŽXI xęe, ÄQÅ­û$Mo}BƠǘ—ŪøŊ|-ģėFZ&ō—&ŽEgŠuE·þé Āi‚Ed%·—ØO/&ŪGÜãyņŽ>ō߆ļKņ‡tXģ7#R$ čž|JXÄß Ī,߈ y]ņ$čØ!6mÚĀ5·ķ )ŧAU†’ Ē:ūØO\•ĘS>ýī–wCĩĶhÚ ŧöí7œš3Áž M$xĄœZ6jÎYž%îīAÎõ\ûž―Ŋ­ĘWûĻŽŨíc;ŊŽ“cŲZÛ\ŋná6%f•øÕĨ@Ŧ{Ė;ēý%JÔ­s6HÎS/S0)”v­ÄžšĻ°Œô@m..UeKđHĒ]uV)n]‹Ī°bļ>ļtų/ø~åruĨ ’ÆghpÚ4džkx‘ĩÆ r=pFÃVíaãę}Ï}˜ĸņgHĘņ`ð–ŨþöĒ7ðØ Q5ÚĒO"—h@S§iáÉ0*|ÜÉ_qšN[€klåëīįŊHý\ūRčĖäî?ÏEÉõ·;įwMĶįäx*Lz!ȗK=Óī,DęxI wâõäk°jŧ n騀tŊĸtUĀ)"­…rqˆJ…âO]yĶŅąLND A'‰ b,ÂÏ{õą.Ękė? 2J:—)Ņ.oæcļ•™E.:ˆ_ým žFĢ”y p€ĪîĩAčRį•GĀĪgØãM/!íšß„­;vPŨD@“TģFM pc)th—킎 wđ}Ýk_WėäXfŅsâ8€m|g­ŊŠÎÉßēIþLÛQŽjŋķZË03~Ÿ| ūCŠúyxš[Ē]ķŧļRÓœĩvjÛuú+·znĩj1ĻRĨüEÛHÏVë-iÃЏî<æÜZ|Ï?ŽrþŽ‹hĸõo Đaūx~Ýô,žŧ-\/5IĶE5ó―4NJnĨ&Ä"™&8á!2ãúm^kōžy˜ôbZvhDe%1hŨwš"eaķ íĩ/NÎr•gqr–Ų_ī€ā‰Rī y’ý&3ŪHĨ@Se‰Á(’C'ĄīÄŧ F-ð,ķoÝēÅh˜ŽĐüAã<ĩ í…[åĩÅĩö}Zģm\·<=čϘÏ6bLÖ'ĪD(ėyOĄHTeÛIûWú)ï•ōØe:æģï“ĮĢUŦVāČŅ#…ĀĄķRR7’r8xq‹zų ķ':6]UVŲ–‡ ­-[Ž ŽĩRq–Öą€Ôú†ŌžĩĖQô y·Šó—'ŧŽÖĪKýāŸqÏČWœŠ[āZĩ€IŌÆRRŸ4.úÏg’ˆåįd˜ó)ôŧ* 6KVĪS&/ĨˆČį‹–īŽ l°Ö>§ēœ§Óĩ%}ȊENtNï§Q—ÃgМó‰Ō Œ4óŒÂž·â](cB*ë)") )ilk\gqŌ/ó,é/Ļ\û|&Ÿ--™Ék&jįlÍþļÕD5!Ëŋ–,ËT ŲŌ2DÏŲėô"RØRRn•­-ŒRĩÎęę?%&ŸÅþCGÍÄæŋ_›âü“[@OƁ ˜Üï!tč|:ÜŲï.ÚÆ Þĩ~!îÕ í;uĶïŨĐØ™ƒSŧ—Ēïméአ:'i>õÍ+Ã0{ųaŌ9wl^ô†ÎZaœđo]<ý?p?Z7o‚G_]€ãÛĒã#O`;Md$UÚ>&ð)ry/‡+i­;Î\ƒ§í†.]:ĒË=ƒ°)Žv+‰{0nü8<>îiīi{3nę1ßėM€§g.>Ÿø†ˆ!”Ð5ly^ýd/ä™óÃyũķėƒŦâpæ—EčwGwÜv{GÜþČXŽÞ‘gšĘ›ÐĢĶ~ēžæmXõÖó4ücdÐŨïÖ>ÆŠý ôtÓû>‚'& Į―]Ûâ†ûÆãĢĸ›Þ=ÚĒqÃ~XīĸmZĨs§ĒíĄÛĩꀉoüˆ,†f|wų·X=ë íĸœËĮ‰•ĸÁC}nAįö]ðėß “tMīGčSÛŋĀ€ĄOaïÚČRJķþ̉=}íî-šu―ôÃ+ŨFHƗņ‘u\§,äB 8lp)ŽhjĶ"Į"ÖŌÕbķ8&‰ ģ9ÃčR…ԀމÔÁGÐ`­ÍşŠ7\§ĘļØ@sĨ­ŨÎ#@x `”ôĖzjßâ&ÚĶz™ú†‡„ĒkŧNÆŲđ}ŸÉ\ð§č9+]ęž}ÍÞ:æŨ9%ûœę—ÎYŦ4iOÆÆsŧÚÚüc›{Ø‚Ų Dšnž3é{°M gJóu<šŽž5Ó5=R3žŠz) Y3U‰”uŲgŦfĸýŋé4Ā4öÜÖg ĀŊÞįčŋæÅ5øÛĩĮ“ŧs:持oTÄĮ_-ÂÔ‘xaÐlÞ·ž}ĨĀĮ_|žîƒĻ܃xĶĸ`Ī5žŸ~õͰJļf#öāėĪíēfĄįâwâāždCûŌâöcņ‡ËŅþž§ðÎôqX=w֞ GÔÉŊņî’]\˜ĒŊØÞA`ŧęð%į§ņČÁ 'Ïôzü|ŋä?;ģ‹Ũ*Ž`.ķ―›ö—dô yháģOžô!Ļŀ„C[ðËî“č=wĶt‰ĀĖOâ0M^y~ýÎÓčĸÞ4tĻ#ï—ÚCąxŅįč° C})ĩq_ŋÚX8ĩfĖ™Bļ č4°}vįā螟ąë KóĀÆØ„įߚ‰Š›æbüŋwbÔŋÞG;ũÍxmÁŊĖã„č:·āŦï—cƈøü•ũïW·ÕŪDįũaÂī‰(ãž#MB`ũ70ĸÝaø~ö$Ž‹•ÃŌ9ōŅUqôįoņŲOĻxrs^_MĮ á!ݍë(]~“u{.QŸŪ­Y寘42ݐYŠ^G?Ģ„ÂNãF[Ãû^ģs‘?*ĢhģïužĨčyĮ<š&qõĄC‡°~íjū?…m({Lq€ōūĪЊ:$ÍwũÏÁCbp}ķŸ&"R’Vēŋ—Ū+Î Ė‚ôÍtM œÍëZƒķĖ‹ĪÁfq­z–&4æ!Ž•ĸ‹öNÂĘ5GG'ėVkŸūŨ/ۖáĢŋĀĀþũšüųŦÅ{Å-ð'·Įēč%Ų=ĮݍrôÃEÅŦņ@IDATÝãa”z·7V­Y…ŧ|1î_ũ <q䅇!yũbüīŨcg߇č0_Ōē ŌižÓwmqwuņå9kĒžÍ()õŧŒĀÝĻ\–^―ÎÅą„HŒļĸf<‚­ĮšŒeÝ>üitlPibk`už5ķ#čBōÖ>―ðŊĄï –f`õšCŋ›ÉųŽÁĢï­ĶĸÛŌ—sf‚müĖ’Ę .…þOL@˜“‰Ä=CÆ UhlĻâ†Ý§Î’Æ0fgüVŒî9žŲŧ‘Eš“†móa$•0”ĢÓŽ?âg†l ™3 ―Ý2‘”Í(VY―˧vŋ[h-úé-‹i3ŋBŧ,?õ­q­Ļ―gčӟüíĸ?Šŧ<Įi;ĩgIŒe+.E„ÞČšJqHüg6ó HõOļKĨ8 ^bGēĒM‰EĖ"Þ9”ũŦÏI)H +nIœ§ÖÝ؏/ŋ˜ÍTš9wîœá%šĩÁÐqŦ}ĮcŧmtN\gZNÖėį,Ķtivū*ĻXŪÂIčA>r‚n5žšÄÎB-ęāÜãØīíđ!-v+’Ï8!’īÁ;$köėãĻĢ~AĖŲÝAžgąį4^sÉȧl6Ũ3HÓōÏÃڍk‘G“+%'`jÚQr…ÄįsņØļį8žýÝQ›ņ<Ģ~‡ŽũžŽV} Øūš$+1^§{&Þ3 Ÿy4ÁœY3q#ÝI2TĮ―–^N!öTēÉđaãNdŅ―))ó1ɜ?ģg'é\%T(IįĒryĮ]=á™īŋėMäN‘ÍË„ÝP&ï]†ĨßæV |IŪv2? ÐÁN2iËcŅŅ<cJ&ČOeÓŪôØw2á<ôütŒëޙöŌ|Ių2qōč9ãŠÐŲÍ ĄyîčŌĸ%|ōÅ"Ž[ĸ%n,M $iūRFķ3:ũũÝŊâūqoĢŅh{ïičĒÉpüđĮÉÎB.ÅØō̉óTpdwy"Ęņ:Ž/#E #6Ī!Ž>Ē\ÁQ,óˆÐëz&‡ %Ią3øÔīXŽ–‡æ%Ā xóĐ]•šrŸĖûŦWŪ KĻęhÕš ŠVŦ† Ā x{{óynO `ĸė6ķ9D‰2ņŊÕ/ĢFd tlŲ!% xĨ$Þ {‹r‰*Į>goíēíkÚ―Ũ~ŪŨŪ—}^ĮP“vëVà 0Y{6‹ÃW{Wsl™ōļ“+7NóÉmJŠîÁ°\Rēė4-.Ý|3~MPÜÜ<Ė73 IÎÕŌŒæ„…ÕŽïrĒĒýkÅq*ŽXüđ ÔŊZšDHý@^žâė’˚ó6myVŽqkūÛïsĶūïëĐxpÚ<üŌŧčSĸw˜ēdŸÄóÏLÄóôä^ÖrKhģKmũ3$ÓSßUÅ'ģï`Ï=Ÿ’ŪÅøgŋ@ÎméQôZĨ$ĖĀ‹ÛLÍ)gÏŅíYLŸû>*‘ĻýóS>~bXąqģ–!ž$3x”ÄØg_F“rWņ4vÜCŅ·Į]öÞtŒNûqĄB―>hÛĪ9NũĶûÍįF#cKsäļ”ÃāÝ1zl[Œš2 g74§2WÜ;pÂ#ĒðüėįáīÚ +ÖĨ ā nÜĀ +gaÜĪ3HßOŋēŒüÓ n~%ÐýŽšX4'nŠo\đS–Ä$ÖÃå"qú‡ðęŽxėMOÁÎ%1ŽWOļĮmÆÛŊŽÂîïËaþ·Đč5š#Ÿ@r”:MüŨģtĸ þ°ĩ:C%Z0Č7,éĸĀ5œŅJnđģ&<Š„+`õ7ŦŅ―Įd„ĨïÃčŅ#āŲi*6ŒŽ‚>\2)NîOŸžœ€ ÔX/–eM°I›åϖejį’ãÎ ĀÍĨÜą`îË(ÉwÍ8Ï?ڂö ëcgŊxū†7ũ邱Û`ʔ1Č9ÔųTššuā$DÐkSŅ]Ž%<Ë5CŸĨ1rģ3M›Á]ÎXüõ”.œŽĐæ2r‹'Ū%ƒĀ'ÛAĄķ2…čO^mDx”Ę/­HšzSæÓښL,Ô%˜Ú€ķ‚J6åé*ÃՅ"F•Ãû<(ö•HW&ûũîálú0Ö@˔BãšĄnÝzĻWŊžžÔuŽt1`@‰ó• (į;L6e§ËŧđEkvkķc—Ą­ ‚öūŽí}ģSäãs•W`Īäx^Įš8ØŨÔF+—/ĮÁ}{ÍĪÄâNyu5““.XĮž?*2‰›g‡ČŠ+<›ō $õ\•ĐvķüÔŌ\…^;Īh寉Œ"Hč›ÉtEëĄ*Ũ؊ē\qøæÃĻ’a’—";ŽØ “_4}Ĩoĸtĩį/>ĸŦXFŸ—ÝÐĶémqtúš―tÕņúŒ°zÅ>øžûzŨ3qŅ ‰š)ųČHA‰œ7•ÔėBčq&™aZÜĐéįéS^”ŽðwŌôËÏNįŽÚ…ëāRķ·$Œ„_ XË4%ô+͜Ė:H`_wõåĪąJáyûQüČ WŽlzũôfĻ&‰ß™,ΜiÓų†ûą4Í$‚ÏsĒ_QO*hĪÓ]d>EÞŽ‹<Ã8ņÛŲ`O[ę<ÐĐ'Q'™!ôãôã§ïÂwžQú*p̰~ëlúGf8ŪNƒ0 kuà EýްbŲäN?ō>lØ?[ƒihŅē!cNýG―ˆĶMVbë‰Dx–ŽŒ ī{ø%”Ļš‚Q•ÎĀþd#éĮ6fôŋ0gŲZdWĀða!9‹q|)IcHj”k>čōîdÅZÞĶ-ĘúéÛs”šųáæ{Z ~e:õc_ī5ZģœŅiôsža-’Œ{/vĸĄ“ô܀ŽČ–ļģs'†4ËÂKÓïCÓš•x[:Ÿ—ƒÞäÎTFƒFŊāĶV óÜ―_E~H9Ž}ę”ÐßÕ}ÓĶĢÆĘĨØu’z“{ĢÍ U‘Ÿt݆―‰Ztĩ—G&fƛaÓÁrĢNļmĖëH.Mðt˜9o"ˆþĢģōÂ0öíũāV–įŲį{>öZŧ•‡K‰Ėzk~ڏčïCũAą8Įøžn?­‡ä\?Nö=Ņ}úLÄŽýÛĶĀÓ/ežĐwRï!žņ<•H9iÎËõ€WŒęį߅6ŽC\îu–.œ8ž$Ðņ&`rĀëŸÄģâ@EĀE˜s(Vĩ€P6ōM+WqŌâd^KuwŽō4Eč™ÁÍbĀšŪûD8LbÛĶŅËÛĒįRÏŌ%ßVėÛģËūĸ•*WAģæÍQŊ~}Fo5þi689ķ·@L[ĨÐĘHIĢ:69œM››860*ŋöÏq_Ũícm•”_?=ÓūŨņžō ÏĐmÖŪ]‹ ~6íĄwgIæýđąÚŽí E ģöÉŦjģfiDŽÖó$BŨ7Ō·P^%N>Ԇfm™UÔhÕĮŦCÖÃĩĀīÅæhÅá_Ž―Laōķ,ëa…Û·{7ķŽ_á‘ĻU§ū +V2"܄Ûģí4Ûō·šKUįÜÖåXzžF i„yK>ÆŪļûQ=Ė?Í{ ŪßCâ°Ë·ø ÏģŊadįęČ9sSÆÜ‹ų;ØB"püd&đ{áÄOaōž58sb/JVïĐ#nÆīņ#ņņz†;W }ŸŽŧހ[ūÃ;[+ĒIãH$ŌÉüˆ§ÞĪĘĻĒvŪō›jÆnšĮ&ū„ƒņ™ŠÖŊ͘„2^i˜CneWnotÃĻ·žÆá/Æcģk4ķ.ĸįēb0čáĶøŋũ?āšXfÎûéß>‰•ž}ð|ŋæČOÅħFㆇfâ–ęMŧĶoų cKāĨ—Á[3‡ĸ‘$sLq_†‡‹°]ý_íËsýŸ QŪÞÍĻP_ũð’f)„_Ū“'jĩé„Ú<ëÄɏėÓūŽa‹vhÄ1ŊÉŦŅxũŠ@—îwņXY3’é–TŠ’.ĘēhÝî6“WKUī AúĐ}Xđ0ÝĶގ Ũk1iúvŒ~~hî‡Ol#!ތųoū‰8Ęõb7ÏĮŋ—æĄZŲ@SrÏbĘãŊĢ|ŧ§ÐŠ3õĸäÆh!8šéĸ0šũxyî|ĪĸîþĖ Ö+‰`™īƒ, wĨqhÎQÉ~Ë!ÅonM“—cTįΟaX9žd{).Ŋö­ã1þņFÆŊlË1KPlūaxôݙčÖ Ō€IŅoĨōô\ŅO݋€úxæå‘ĻR†šõšĶ1ÏēúũŽžˆŧnŽlōĐþķ"§Ę[ i=Á€ïĩęŠû­ũŅąy7ĸĩ|Ū.gðÖKģžÖŧōmÍūmŦšKЖÞWįåWe‰ŪŠîÆlŽíeęËöS™jŋlŠ€M žkޗkÅš–㉗ĶĖD!!ÍtÓõ•.Ïq’t‰ÓÔGčTÚRöŅš%đžŨG%ý6"VimÚb\K…‡.-N% Ä„øßīcŠ%/gŦðXúšjx}dcÚÂōšŠƒ'ۉSŌ5š"{œ9} ņqqŒ(ēŸ}üÔmÐ 6Ē(·.ʗ/_ð\Ŧî(•Ąa€ÜíÏcƒĒķŲ€fÞΰL] ËZ`œHįėúéXį, ēÎĸ?öÎ@‹"ëÚg"aČ9g$#ŠTĖ‚Y1g‚9Į]Ũ„šš†5ŧęքiMˊ%#9§™aóŸįöž€ĻČ~߇?ŪS03ïÛ]]uŦšûž:·nÝZļ`AüŽČ]aÅZh‡\Ïéå…аMŽčG;ïx ðņ”eÂDãáNīđČ#@þŌĮü[ÍKę>Ę2“$1ŠÃė͚,>/2ßq b„ėŨ°s 2’čöß&ų%ōsēČ֗*Í:ëī ŊÔðËÏÓ7ĢÞÐ6ûíŊŽ―ũŨŸËw›68‹ÓËŊ?Ū•õ*čūG~ÐēŠģ4üų‘:ŦWo˜]ĪýNŋHGïÐUS—4U­îąŌ<ŧØÎHĮĻE­jjqČ!juĮ'fô~ž­tšF=kũՋŸMRéOkï“Ŋ[c’ýėå{ôBZýóī=ÃLý!þkĪŦŨ>CôLß4éõĮtĘÉįŦN—uLũšŅâ5Žj?ƒö„,øðžųŧ_Ŋ5)ĨyibÅЃ‰5hM&°Æ°sQSĩó{:Ä:ĮI>gWŪ§Ū†‰|0fþQ’Äk™ŌđĨ™•ÕĶmuėr™Ðœũ&Ø­Ú8Ŋu‘ GAëĪßeēžĘðŪDí:Ö/ë›ÍģN?-Đč3æXÐv)ūŲgŽ3đđšÏ[ĄÃžRŽ/æC=!.lĶ™X˜ ]6Œå’x8É`ä€@°€?$ņ0û<uų’Ž ꡜlÏŦ\įĖžĨđ/ÍÖÛoÔ:x{ē^aĘmÞžđjÖŽér2Â4Û AƒPdĪ üMýZ”›5ņ ež‹ˆ0ĮE‹úg‘Á0ų›įsŦ „IžåÏÅķÍ[6ËÏĩąÖŌ6`Æd=uōƒƒrĮþĶޗŽö§`â`åŅ™2Åfé;Ũú—Ï#QĮųŠD)ŸōčŨdø%€į'î‹ÏcΉÏf°Ü‹ß"ašĐYŽúÕ,Ŧį–ÚõčĐÓÎ>G~K•m+†Q~AdÝ8ÆųÕčëóĨ=uÎ9{{OCĮŸ=óTsõ^v2]d…’X248†žû+C9ZĄũĶĖĪë4ûkÖÐ.ó―ė ÚþÍæl1W―NĶ*-œéĢ=ĩzņ4}?­D;ĩŠ#Ŋzũ`ÅaĐ=•ógjėô%ęÓ2ÛsÖc|O(eÝī\ŨžâÐeû_ĢûiŦ!ûčē“ĩ.–zôMBqzJÓÎļ‰Ā<Â/Ûr"‚øhzz= Üo]}æņZXÚROޚh-ɛĒÛnžGûðīÚÕÞðkM]ĸuÉÏovÅ*ęļįvŒš^ æxMĨïûœfyލÛVŒ(Ã[zÍ·gvvÕŠfwÓâÜĨšģxY˜*Ó<ðī―J•žweœŠœäę›>Ö\ÕWTÍós%ëĄ_†ļߥo§ÎWƒVÔąUc+ÕB-[0KKópÜņýũÜz―F •ãũ?õä°+ÔŌyö.ÍōTpēĒSþâyšŋžPu?-w‰fŧ™ ęÔЊEóīxé2{”û™­]_ukT*Ó9ŋÃ;m―•XnŪŌoø ó]„ Ąā7”„%0F9ŒÂ2|cQÄ%0 Ÿ4ŽCėŲ҇‘ĮHōgŲ#”„9!ļŠp ̈́‰R–YĐŒ€:`FÅ•šã`đķĀæēąŸ|Žo―EŲ[oūđŧõéŦ.]šÄĶĖlĖL]0.ÂÝaJÅěëUK—øĖįΝ­… cóōœĮ›[Ã(ųKŸÐ?ē.G› D„iÄýØ%ŠÄĖmpG^F„$ýš0vĀüKæ0Ą†#P (0e㕜ó―4—:]€û#YЁ(Ëė ‚Ĩŧ|˜&õdÛģ–~§^ú‰‘,ýïŧæJ-e Ïŧļ›öÏۊU·?WFE7Æĸûīŋ9bĸõķģëF™ rC"/ŅŦÏžŽ6^ŠĢöï—ä\ÝS/>ÞKũ>ûž5PÓOĪØúȃ˜ĒôĘÚÝfÝ?_tŧ-ûL‹ŋŸ )sąœ`aÁ,f3U<æ•4ðĒcôÞŽz’öV;Ré;ïĢÃŧVÓĘv–Ë7[ÏlĻĢvÛVį]4DswhŊÞ­å…Û'rŽų­æ­ę镑ĸŌ]Ŧęj†MŠ/ýëÚĨãqĘ0hro’äeģ–˜―0ŋÛQÄō“ð(,[gģ]Ÿ~Z|Þp5&Ŋ­…Ž/C9ÃD”l‡āÃī‹†Â“6œˆ ļ ,,ô[Y’ä7:'ĖĖefp‹Ė`™žG.˜ÞĨ<ą,ü_<þ @`øýwö\õdüĻ·Ôēuk›q{…'îĒÅ‹īØŽqÁ‚yĘ7hæ{ļŌĶT€4~˖l:Ë܄7„5xŅvdKé0[ąF‡ OĖĩSdž­xvWķŎA~xvĢËóMė •S‰éĄÐ€! žÜFíxWÜãĐ}XR`+›ý2<8ŊZĨrč•d*Íš ŽuÚ_ ũ§‘ĀKdōíĪä ëyá§éW%Įá% 끹 åXꐙŋŧžBY&™Ŧ™õ%ógáĩéã0<ö§Ę‚AâDÐؘP€  ģĒóSƟXđV8ŅX.@ Ėļ98ū؅Æ2$Ę8ØŪ<€U­īGîļ/ūô\čX3ËĢ^ƒÛĢņ“3 ‡°æ|Č 8{9G 2ø8l–WhĶ󌖁:Mžá($ýF_…CĖĮ‘ģEņžļûŅϒë5{v;Y‚ģ·)}W#ũũĀXŨ HŌÏQ–čč'ũ…Ģîųū`.OØ%#hƒˊČN{ĢÚįú`Ĩþc9Ž8ø°‰S-oķũnÝc[ą‘üĀģģnBöšĩkh·^đ­˜Ág‹­ķ^·ˆø\§Í–žyLRjEgĨ:ÍÔ1uАÓmûūJ ë\^ÛyėÝ·njØĶ§ōÏš)ĮeuK•åõĶŧî3`Íi{éĸ$UŠÕTûôO@“ÍÛ&YjwŲjmÞô jŅaíũF-ÖēĮ:šŊi ö;vÛaíuþTÉKzúį™2íÉé―T·\Ŋõ^”ßvË^šRþ°>―øj+3,ë"æ–W{=ïũo?ŽæÖÕð#öēӘIAÞjÕëŌLYžGŦ­ü”žĻÆâ°ęð óέ.ÍÖN‡ŦĢšTŸW.Óę&§ëóëķôÔAĄÚvÝYo―ĸ Ž?ý5mŧýŅ:ëīlŧ@Û%‰ëK3jęĀvŅ'c>Ņ·“§ëģąïi—Ąįëó·ūó{kݗ7QÆr•uƒÃ NúũÓ:wŌšĸÛjzôęÝäņ{€q―•tņų7Đáá—ë•“·Õ­ ԙ= ũŸĒ%3ūÖČ šöþĮĩíßéĐ7>ÐŅ;ķ°Nē^3m·eG}|ĮíúlÆAÚĨā#=ôņr ;ĩĶžūý|}”ūŧž~ų4}óü :ÝS]ŋN fOԌj[„5ĪhÅRMøaŽ 2°hųųpœÎšýoÚŧ{ûčÛēæþîþ„ūþeĐχYđ&&ÔdĐ`ĘĢsqVāĄ€ €Œ0ū[A3õ“pŽķ2ä Įīķŋ`ꅙŪ0 ĀÐDaâiËŠ„PĪöLó9}2WŦÕĮņüį5Đ% G!3)ØåPm–S/By€sˉbrø| GūĮŌFĖÁ!ĢeāZǘ­V–0+úÆmu–dÖ Ŋ„‹úx-ýéį>Ķnė9]&ß4úÝŨHšh?L›‹ĩĻ1hðų"‡ģb°AðĖãž`B‰ŒôąËĖðâųU6ÐéáÁėO0xŧÖÐ/ zâĶÄŅMý+‘ƒÐ€€üš?CÆrÐÜÔũ žüčŋWYÅó4üîŧ4Į›]šõj=öákvé5ú`ZnDH+Zōnžæ>õ9ó mŨŨ1'[p Ÿĩ„wÕęL{uÅqëx·š-zWŸû˜ ėÖũ‚[õϧþĨ+Žņ\üM草ËÔšæŪļ0‚e4ßí õŽ1Y?pŸūųhĄ:ÐûU–$z›Œã~Ý­ jÛ\―ŨA'éļ΅šýÎgīÂ^âĻtĀü ŸhŽZ8fn_orQ_§ĩŊŌūt$#;č­īŪ:ėü?iĀÖÕj‹Zr,’DøOৈí°§öo•§įėĐ>ÂāÜ`§]ÕĢąôéĮ“t؇ŦiÍęÚcŸÕfÉ4ĸa‘_Ĩx§ĐO~S’VXípȉ:|ïÕ°ķ§ŽCŊiÃĀi qĄô°V˜ĪĖõųĐ °K)ŧ]įk3X0&įan-–Eø&”Yūá€E>”;ĀDWÜ9@›žn3,5Ŋæ@ Ėžâ:+Y> €k™WŠE>ŪOS€Ė20' óâLŧ˜QEØ%õ& ŋ–=ãĩĘúSX+õ˜Čň6†§1MāŸåOØt2ā`VØũ- Č:(Z†LŲļöúb @u= °ė Ž.$I?YŸ@õĩÜĖË=ŪG ĖäɜĨû€ëÐČũÃuS~âT„‡3ŒĀtǰÍ(-ķƒÖÄ)3âūnFb•‹ōßÖ~yŠŠ+ę˜ËĸЧîęˆA]”Są‚vÚkw5ö’#hӇOÞĄũ˜ýø―zØږ6ŋēM;6ÔⱟkIĄĄd&O^Ū-·éāĨīó4vėGō1.›ĶŨĮ}ŊÞ{ï§>œĪëŪÝ^_ýÔq~üŪ *§šķÛđ—ÚU_ĪųK―ö|―wđ™Ít|ßÖšë/Ã4ūö@õjdï5Áā-HYb)UÍ-:Đï>ûëˆ~ 4îđg5ÃŽUŠnŽÖ đ*­X Đ?,ˆ+ĶMüNKsŠŠš} Ðéķ RZ‘'Z3Ũk•âĨ/éĩtėÉûč[.֟žúP8HõŠWņžluMųvr”·lÞtÍōöjÕŠä8`Â,Í\8Õú._―þū— fĐĒûŅËæ5Ŋųô˜ýŨŽQčfükÃĶZw v~”.Ë(D|ŒœnfkÁ1…„rgÎĊĀïîð4ķš2hÂ,ĒCøZ&ŒÉ ĀĆĢ&n–)lËE0Ģä+tÁÔ 0ĀÜåÔ‹p„q@ŧĢ$€ vz˜+`M‚$809ŦŸ‹ĩ&ÖĀpþYËRa|!# éö„•iÖrø   nüÐ_ ø xó=Ø­ÁŌؓAD2‡ hãčDŋx\ā~ázŲKW,k,9ąp Ūpį‹ ÏŪ#XĐŊĨžļ>É?˜\âôC^Æ}öÚĩ™ˆÁįŠü96>N_o.)Ï΃/þ‹ū?IþûŠâ˜ÄåĐž6Iøý)ÉĻĪŪÝw°N°E-mĶîþē:õÚZMkų}-™Ŋü[­ķūN-Ŧ8(Á*+kþÖŧ­―Ÿlg°‹ÔYŸi\‹îšŧߖZðÅÝęč=žŨ{K‡ĩjĄ]ķéĻaį ŅÔí[čĢÞÕ.{^eg‡Úüë-úĀloޗïĻĪÕvÚa‹:Ö/hĪ$Ą­Š ó”ë9ĀmãMÍØOýķiĒÕv|ÚįĻ6ŧÞĻ‹–―§™ŸVƒĮh›öôM‡Ū~ýÃ:ï3Íyįmö8<ü)Ō°ķÅīÜšĨĸ>?§y-"õģĐJ•*2čT―ņęŦžũs0q”ŧ•3 œŽÓė Ķcēú V($Į +X*Ž4œ_˜[30`Ō@ųĢėCŅû;Įų 2”1§e™Ĩ27įē’”ˆíį>RČäs\€kG"L4Ø^xĶ2?č<|&@ aą8(ŠŲád t{aŠHB†|0Fœ™°æXĘĪ ‹ïîŪ`>€+q’bā PÁ\“z-°“ú“9ŅÄä^ŧČäå< ˜ģĩĖ”čōščwڟ F’Ĩ-€7rƒYÓ^ËÏ=cN–@ ÛÓsØuŨGāįŒpOž<ÕÞoÕĒEó(;uîįþ2 Xš_Ēũ&įéo~ŧģŨ5îĩu˟d6-ŲVlū·[?ŅŽOÆ―Ĩ'þõ°Ÿ~Œþzõųņž­ŸŊü{yllžōÉT―;ĩP[·ŪĨ[WVJčŊŸŧ VĻoŋ™ŪꍛĻaÍĘüįkÂãUĄe{ĩôwØ[$3FvByųÕ7ĩ2­švē·u‹Ú”įČS_7EMÚo­U= ēbŪÞõķæ.ÎWÝfÝĩÛŪ]U9­H“F―Đũ§;þlõFÚŪwo5Ŧ Y+bîÄŊUhÏïurâ}Eį/ŌWß.Ō]Ú*+w–ū™YŠ.š(wÖ·úzÂZūŠX5ķT·­:zi S=)y=X.^ĐwßyG3įŊTĢÝĩĢãÜĶ™iÎ?NŠÓ\MęÕВéßx]jĩkЧwJ_[:Sgo―ŊŠ=ĪŧmåĐë$ŊQýōÓ1?yķÓšđmÛʛžØkv™>{ŒfægĐįVÞÎ,ŊDÍZī°i{šúX3°ÏÐã„ÞŸ8qRšf͈ģkö?Ldœ(]æüč{ĀÅĻáýJŠRŽ,1ąH–‹ÅwÅlHâÚÄŠyÖlŅ  ÄäŠ9Ŋ/”~0Eē|ƒž1_`°B†0}˜Ĩ€Ã€ãēÃÔ鷁ë2}~MÜVs|I@ú0ýš^:-6}―w•:ôLâÄúï?~ij9ĻK][áŽô―aÅÖv/īžŽÞĪģvĩ[1O?ËhÂĐ ‘J>V’‘ĢÞ{ėį#Îå~ Ŧ—ëiÚĨB„ĻŲēŦa“Á{Ē·đĸ‹Yïžâ ―ëjØÁ]Ø%aĪĕíÚkŲq9ęE_ŅGiö2ßnũâXLčœJ [ĐĶAh(øwœRúäš`eí›ÅšÂlĸKLŠî+k@3(Ž4€BâžRfõMĮ ĸÅ1Pbm#Ņ ļ•Đ%aVt·8ÕMy.ÚwđT@eŸ˜M įæF1æRęáæ„ Õ2Ĩæ)9øPW2‡éŦ|Ó`ĢÔ_ŪDGÝð€zÔZĐ·ŸúŦÎđō)ÕhU_ ž/åûœ§aWé=įéæËy‹9j˜6Kõû]Ĩ^sŽŨSþzå96į(Õ'ÞVė’;GyCzķŦëmÅnŲļmÅ~ŌŽ$ÜįÚÃþSEkĪ>Pkæ“Ģsuc莂ēčOĐëøË&ókĄiÝ3k?'6•ŒGē.(ī‰7’Ë^ûŅ[oY7m(ĄG°`­ŸÖ­‡8ĩëĢŅy9­ũԍ·ï§6Õ­ÓSēXĢü\ß$õütųÓbë—―ū,ŋ—ïNë2ŧ3'#æ ĘP–ÁˆÛˆvĒ ĸģęFCĄßĘ|(h .ôáÞH(~ę ķéŽÍŠceŲHˆęŒŒXn^ēųīÏĀ(;ĖĶ1RÄÄjįë1“qÎN7 š$į§\X/ Ϝ-Įņî,ö(ĖĻåōƒiģ‚Ĩ%ó SlÔG~œŌ0þû8ĢJĖC°>bІŽwĨ]üŦ@Á•zô ÃįZ—`"7ĀL_E^*Îq,dĸĨ:§ PIũ%įaļŲÎÏzQFÖšū§ŋEb •l+ķZŨŧ>îĸ)§‰mŞ‹mÅÞԁ‡Ž]·ßĢ·ËiÜEĮ ė-ãŌ4þíGžÅÖ―:ó/ëĒ~ž‹ÉkžW:YĨíķÔu]ßÕ}ŊÔSŸŽVįŠģõí‡&”™šilĘs…6OĀķøá͚_š\_k€Äl ó!ŽāhRO€Ī- Ķ™D―i:ÔO€å ķkxʉ& āVČŪer/ãÁtÞ3· (ÂĪ‘3Ø#-ĶóXS(ĻĮĩ8Óāė“€Ûï|d§m=#Ā—Ūø]Ož0WŨíöŪ]?‰ë8`•°TĖӉ9Ö=ękÂóØf΄Y'Œ7*ĪđþĮo~č;ÚJĸ… ÖýE?ŽČA―ī‡c˜@“6:ŊG_đ_đ֝äóø7úӗoÂÄӃ“•·ÁŒ}HŸ~ðA=óÜóûõũzäûTŋq# tĖÚ\ïø°ąÛŠ­ōMŊžð/ÍsĄŸžüOĩÞ흷W§ð@nķå^šmH'}ōĀsZ⭟ŌKsíõøĩ2ŠĩP·ķÍc­Û&lnyŅŋQĀfō`ļ’ tÚb UŦČûļq‰ÁëcFę™ũūõÛÉûõ?MÖĨËõæ ÏkÂBû5üBQÆU}3ō―þņLŋ‹iŽI;K  aýŨýēzĨįQŸyMģmDž]ŋÛŦWč͗žÖũóaYÓôÐĘŚîãĸÖ“.Í5―ųëîPÄF‰B+g- É(Pð˜_ŒĘ; öî/~(€[F,e`õŋX—é'†Č<°ŸR3ĪPîŋ0“Ĩx Š ,0Kn`ĄŸūX{čsĩό…A­’ų â%'–9€ôCō›ĩÂ.+0‡ëķ0>āË1?b/qāIžq& %<åāT„#_—‘zÄ<ŽÏaJ včóĖ:/r08XË]­įåÂËÕm°1g‹ų:ú5%āēÝw\ KOÖĨĶÚH_Ų\íöRýƒŒ`i?ï/–X?ƒōŪ |@?šýŒF ãFnš_åSۊ3č5iÛVÜ}‡·ŧAófþPķ­X}-ÎĮRðkÆŽDN&&LøĘŨäjúœÞSņ /&_›šl·—įeÆŦ ~o\+]{b/xöp›ū|mĶōOŋãČŌÍëjŽc·^pôņþÐģĸŅķbž{SŸýŧn1FÅÖ žĮ?N âÖ?öã|‹õœÞzúąëŊŅØŲđ~ĸæŋgÞsä]Węú‡?ö VzéšsuÛĻžŸį=§4ĢĸÚ)måxÝ|ã?ôíĖÄ*~á@›•ķ\wÝrƒÞŸ0ÛÄ#)ė&Kū|RCÏ}Ōë6“ōĄ˜jë/]ûG9ūķgĄÅt1&―˜—4ŧ‰Č<ūŦ Ð%Ęv„Ģ 1 ‹Í6a@‰Յø`ĶZ°#ß\0Ā*ÆĖ ֊ /XœËÅïïþė‘€°x0•”ƒR€Ķsð€Q –ÃīËyŪ Į!&aF…ÍÂî`]6Ïe’Ÿ|ÄžMæN 0~Ē&ÍÚĖÄąp-ēÉ-`œ°R€'ŒŨĮ‹ "ÜdĀ+vÂð9&āÅÅɃDČčš @00ĖČėŌâÃeéA€Íž”·Ú놋門Ŋ“-ilī°fž°NĒú°4„üČĖZJĖ + a†ĪÁĩ””Eŋ„—Ŧ{0,)—ö˜ÔßéwŽ`nõPÕý €FûÜWĨ–9 .Ķ Āōƒy8.yRøH›(æM_‡Ā‘cÓýJķ+R=Į]Ŋä#ÚuïĄÓÏ9W} ĢOėđNoĢä­/sþƒmՖû—žUU[ũîĢ ĢoŌļeÎ …sõÐݏŠÎVûĐqÉ*åų6īėÚO7 ?KéËŋÔloŅTžþ zĀz'Ëۊučë}QŽÖĒēmÅfϘĒËVý<û[§ŲžÞýæâ‹OVß·ÕE7―†ÛžĶ8ū둇 PĸvŨqgÝį―b3ĩbĘh]zþ<ô ―äNå—,҃WŊÝöÝßËũÎֈyKŽžÖU­Ö7^æōęc7j@ï~8ø]ĸâ\ŋ֕~7ĮūņO―õÝ"‡ï[ĻûŊĒ}ĪýOŋIž1­ąŌ/yēšá‡žŌ€/Ũ?ä­iūé+įéïĶ―öÞ_G~ĩÆO]ėā Uĩäŧ‘šÔkHO|”Ξâ>͛þ™zûSÍþæyîĩšždĩ·VĖÖ]ŽË|ÕĄ}æëŪ?Ŧ}ûũŨ€CÏÔ'S—Zũ­ÛŽu:ėþqÃÎAtN€]ŌKĨ6cp€`bÞģ įŧMŽ ā3ČĂ}?Č(cĀG"ęM„ëģ–Cýģ.Û(=”6 0aq€&ąV œ Pa~° (üv ӊQ‘;ā‰&GĢ#r1/Éw"/€?ËŪØnGāŦe Éĸy”q^bNÁ/#OŪšžô\Šeƒ-&ŽO>N=ÎOÁžé7ŠösœŅĮRÎ;Áx].#=ÍÄIŠĖyĮ/1ĶÚ`ŌvZb>6–öXÆžļ,Ú(ļÆŌHÄžõáøÁėM›Ļ`ļ–{†œČ}įĖŅŋþÎđļ0)j“ýÆŅĄRV‘·óóRķ­Øöĩ[ĸūą­X·Î"ø\[ ûŧîÞöQxÅ?5uh?åÔkŊÛzNĩō_UŋÝn՘ŽÔnWč­ŨÞPãS†ëö}õåý—ëūwWčþ§^P•iOkâĮ_'#đē6§™häM|Iį_ûŠÎŧĸŸÚŧþ0ņ­*Û&nޔÏõ}ŋŧóūÐmÔeũŋĄ=[WSE{㔰ņšŨQϝ0RũÜ}•v?î6íÜĶ–uc2āģŠŅ˜gîÖ―ïŨÕ]O=ŠÚ“GčāãïąēþČ_â5øoŠÕ [të‘}ĨŊŊÓ7ŸUSýÓöōvg7ëÕąGĐClýíá/ĩįeĮéĢgoÓݟ6ÐãÏÜĢ17 ÖߥÎŨœėiēÝĒ6å=ü•―AāÐPū˜2æX'ã ģρ.ˈë€f˜ ­™QėücN/•Ũčá åï‚ý1X™0°•ÄûķŒi °+Ũ͓eÁJĢ^Ŧ|ÏBa•ÃÛabĩ|%0&I&fęá€/ZR.ļ| pÂø(ŒzcŨŨ&õxOLũ€ۍų^h˜MXËS\æžėˉcĶP",7ā€ĪȜ%åēAnâ) ĻY}8ųZōÂDųØ!ũķóŊ@ͅĨ.ôaČL^ƒ óĘĖĸ2H 7ļÎå Á­YöHßDJš,ųž‰~Ũðî( ŲVėŧqjÁķbRF*+lņŸÃ"iÆwÓb[ązõ7b[1ËYĩõŽšä/­UßŦW2ēÛëâĮ_ŅŊŋĐis—Ŧõįë‚ū}ÕзŦjm­ÃLÓėĨųęÔáB]Þ··ęæļŌōôûîOu4jã5đ+gŦíƒuÞnŧŠquŋ%õ4øÏ·kôŽ*š–› ÞĐĄ…ÞÚkëgiØĀīðÝϕ“3ŌsņÞÁáôŪ:ïF-[ūTó smâôÍÛh5Þõ ?õ/Ï(ÐŦĢūV~ûãĩ•·‡Ën}ķmð0#Ņ5UÁÚūýœ2[ũŅ€íÛĐff{ÖĢŪaĪį„~ĖąųTõzčŽ#öÐUƒÖëýŨå— UóĖjĘXôķÎ?ã Õis;bwoŋĘVsĨuEIūū=K[ī—ķmí Ŋ=hčēåëHÚOÃæÛf}Ņð“Č8Ži_ų+œŽú]tʁĩuˋ#ÕÛ2dÔÛFý―—ė;ũÍŅĒi랁GjŲüīÕ!ý­ß€ūYLŠĸāiƒĀIßKą"ĮLÚŨ7,ži­Ž |sÂ+Õ 9;†ÃŌŽÃð˜s4$ĮcŌlc(z”9 ȍaþÏÏC°ĐX‡č“”ss.˧ðr^ęÄîÏzÐ`l>ęÓn˜E ĀaböyÂĖáŪMĨ<°Č@ØpŅ`™+LĖģĖkĀõœ@IDATr&ĻB°JįĢ €(ÅÆŅīÎm§ĖøĖœIĖ Ņ~_ÂØ™ĸ Šû’sČĖ9ŋée,5·zļž0Šû4õîŦˆc>“Œë€Ņš$ú‹m ïŲᄉ3(!?99G šû2ŪNŠˆã›ęۊíåmÅÞýĐF―ũîOŠą(Šë˜}ķíŽzõ―š{#RfåZjÓ~žéUĩsŋþÚy―k+Öhæíŋš­wīüëïŋ2ÔĒk_ĸŽŨ‡ŌkÓekM.œĶÉÜV,^Uö(’qoQ Ŧ‚*ÎօžĢf‡ ŨÍ[géĀþWzíąõ™ JžAT‘ĢôˆÁZŽ-$ÞųÃrīäŦÏ4yŅRõō{šJ<Ó5ÖSá”ÉšđīĀ nŠū˜žTĨ]ÖÍã·<―ŠŽūЛhŸ0Np îčē­nØÕdĒQ °…îŧĸ)];ĒŊ.:<Ũ‰Æ€TN_Ĩ‰S§k1X=å Mĸa^ĒGŽž9í°X ‹W8XDAšö=ōýmß?ið5īĮ WĻE͊úØ{6oßÏïŊTë&2Ĩ^PļLSf:2P&ŠëØ―‰žr1ðôŦĀ ã"ĄÄ“ų2ņ“€7) ―ÏR‡XX뎘â"oB0?@˜\QÐPēį%s–Îėį&ašPtK^ę fIý€œËž`\@%õĶ&ąđ @^ö€"æņ(Â/ é’ĒNęIœ~|čü”Í5ĖSVŽņĻ‚i— &Āå3āž pØIœŒ,@ī°æ\˜I—zŌžfīųģo–š$#ðxeŌžcôKēs‰Íā– đ>bÍėé+Ÿãsô§óu[:Î%ÎóĖÓ2&r$ƒ€”žŅܓMœhۊĩoߊLæŸVH1ü-Oå=ðŋíðGø•BV;ŌÏŠē―!ņƒ l‘#ĩĻĐ―ÄéķÏėÔķlĶþý؛Úę§ÁïKéęlíqô~zú”Û5äėųʙôđū™ąĀoæÚg VĢîÔģå ‡‘ĒŪõęĨņ3Õļ[ōūągQĐēKÆéŠ›žUM[AōŠķaïŌ;7A–zívŠvk\Ē}.Њi·ihŋNaų*ņŪ;ôÞ_ŸöW 2GįÏŅ·ģōü>c-+K\™ wx—$ rPĐõ.ÚŋÍ*]>nĐnÞs[ŒeÚuïôôSįęŠËŪV—fv–ęŲO‡lŨ@ÃÎfĪ’!`ÛA1šY1Įį°4ĢøîÏáDSļ(ĸÄÉ&aĐāNDŦžXĻËsY€kŠ'ŧĪĖ,#ēPšn@8ķččpēąY7dφ ÄÄrđ\ ÉŌ–{v•–;1ÁbŪDiŋM°aÚN<‹Đ“~ĢáޜųāXÛÄęϔƒi•H Č}-ë=Óðž-cĩt^xŧmĖĩ"ŧĀ07JßÎ%ĀŦĨ,ŽŅôgŒG,+ũiđ―=ėH]?ü{ŪXóZlŠXĩk*(ĸPÞŋAüZŽZÞŋe?|Ŧ9Ŧkj‹f TēbķÆOZĐ-šmĄâyßęýÏ&*ۛD7ËÉÐÔ9ŌÖ―šjÎÂ\5kÞŌ,•AŠôÃ7ęƒņÞļŦSgU3c­áØķurÐ;IņßX1kēÞþč UlėøģÕ j›Đsóššã˜īų5ÛŠUõB―ũÞGšŧ(OķØR=ŧķVVár}3iĄ7of‡š ûė}-ŊÔ\=Ú6rÁnlõũÝč›ÉsÕ ŲVŠ–ģZu51^Š)ósÕžEKûXį-›­ ģJÕą]Ãä―Ÿĸ―Ķ-(T§Î―þÓp[ WĖųŌ{f~ŊÜâ4ĩîŌSšŨÖĮēÍiŌEM‹ũũĖ8ŅŦŋIŽZëfwüViӟc`šĐ‡ @a3šaȂ‡WĖĩaĶ€ir­ĸZŲ6m†s#!—“T‚đAÔhĒäyČļöČņ,_ƒã‹sĮĩNg”DĶ‚ú,Œ6ØĪå„ųĶķč4+€%ųl剷0á c€ Ŧ9˜—B@‘ųAĸ€R@ÏŽ0Wð*øĄ#oÂ]ŊóÎ\ÃtjŽËdĀũ%}’ĖKDÝHLÜKLÄxĖ2KÚÏč• \Į9Fš|gĻOđ=xÏbæÍŽþKæ,k€?UFŅī fÉZY–gˆqWg^: ōïÍ%-^ēL /UۖÍâYŲ\ä*—ãŋŊðYĻáĨQĩH…­YÕŦį6žķņ8­QgíÛĖ6`ŋ'žwíý"ûýĐ]]āwÔÝQdiŌy'ÖÅŲ‘ZoƎĐ„·ÕFmtāÁ[DYÁHK―žÍï^Ģv=ž ÄËŅVWÖ.ŧïãKxé“xģĨYUīe—ęဉã\Įž;cÎ 9“ē!ijß}'učIÞå ,j Î5Ëäī0ŲÕ;$eÛ}S―AûØW3ķwtaÅīįÔëŠ―ûÛlÅCī3–ūtčūÅIօ§ÚóGĸkÍûˉûî[ļ&  Z.ėvãM/­Ā“94=? eo–ShÓ‰Æü`€Š;Ę!­rY8ÁJĐ9;Ž™Ô1‡éü”Apb‚ðuáøÃwH$—S † aô I@ÓõøZ#†Gb€đŅ „Œ°[ķōađSÂāĢóĩĨķņĨ LĖŅp2G‹T›:-Y’oũý)ŠŨšžšïQßÏWY­n+1u?ûlœ.žņyUŊÓH§<,žŋ•iŲž úôŦ*­TS]{n­zëÆÝû…B ŋsîü~$üė9ÄY­úTƒ‰ŦuRÁâŲúzėx{-zÞ§SwĩnTsģÉĮĒüåš?wąÃûų·9―fúŠéýĸŦRqcĶ:M­ZĘņ nóIl+ķXsŽð;ėųïrTŋqcåüĮۊm>-*—dóîkˆŸ‘X‚â\Ž øPô* l„vÃÉ{ĨfUØ"s‰°-æI˜Äė˜?4ÛōƒŽĐ08+…Má ŦóÛėˆŋ€(ĸąē5{ōua~4[„þļáīä2Ā9°DáÁÄJ{(;_0âĖMLđĖĪ—&Kl0P6s‹”æZ_”[!öOŽņ4ōë6xE^Ë P’―Gcý§û†:Ē € ÛíuY,9!č}ƒ ŨđÚė5úNt8 Ý~ä‰Ae Îq,v?p―ܗpŠį’ūä6a<MĀßEþ&iɒ\-XąJ=Û5Ž„žžą™+郕+óô·ŧî7KNķËÎÜØ―2K4îƒįuÉyŨiaĨÚöx›§ÝúčšëþŽ.õsībálåzģáĩs~ŌÆŊG? 3ŪyNMš5TAFU <ũFŌģÎ:ųJ5iĖSšøŠg”UģHóÕQ—8č€-ŨÍ#ý ]õ‚ÚvmĨžysĩ4­–tNØ―“‡H›c*ÕŌsURąĶjĸ"ĀŊ—gųũšØÞ•G:ĪݞÝjlFb[ąŧž­Ø[ÞVŽÆĸr[ąÍĻYåĒlķ=°Aā†ƒ€DBs †ÛĪ‚0IZ‡âØĖt0‚RŠŋ†â9MÏ­’hBŪ ķåü"JÝûü@Î|z ÚČpē˜2ŨĪLð6([æ1ņŽr='2B,\ƒ‰4@ÖíÁq†Ïī!žr}žđ ”ŪM™㔇AéSrP6yWåáņ‹CŽO–Įýrrbú`s#“~už˜—eŨy‘?aégLÎūįŸĪß-“eæ<íyf:Čõ1Įˇ0ŧLœpē óŽÏuÛ`Û0Ü øÎ— „|Ó&æXSۊ ŧú/ÁęO<4ķ{ö™W5fÔ(õ?üPíēÝ~öðÍĩ0ëŽÏüŅ–OĢ‹8MĩŽđG_y ŌLÐŲ―ûęԓégęĩ ÎÖĢ―NŨĢGmíPd9ūĸЂJ4gY‘jlyžŪŧpWïęSĒšž0o―Ô|įĢôČۃԠjž.9r?=ōĖxįÎ?Ę5sš―2ģŦéï—_ĐŽĨ‹ôÆ?†éė#ũR―wŋÔíaĻĨZî ‚ĐzŠ~ RĐTđ˖yý`Đ*UЁūđĸ„ĩÄķĀ ËG:ï—/ÉðBybæTŦæF‰cĻŪTE·Đb° ČúÐK1ä"fĘ•!Y ĢØņ˜ pō1–~$sļ>ƒsxé@–⿇k™#d+š^Ú(XaÚĶ/Ü$˜32’Ųdäws°sY°Nū'y`ž †É’<æĖžƒáãP垰I1ĖŨ–“|á(ä6&ĶÞä„Wēë Od+‘lÏÖČLb^:%Þ} hbūīŽ_#Ó&úÅģƒéŸmÅĶOõBðũßWíMīeũžzäûÔ IcuÂiúîŦųn'}úëé‹ũ_ÔĮĩ·Ņ˜ ûË+Ītå―WhÏ3ÕĻOwŌ?Þ[oŋ9U|ŅW— ŋV*Ŋ-ģÔũ*Ũ‘`2ŠÕS‡:?ĮpÓTĨz]UöZŧģĶxũŒulöSSmšû°ŠÁŽY“&ŠæŸvŨÞĶŨÆôÖ°'?Ô—íΧnŋLW=öĄŠ—VŅ6ýOПÏ?RÕŌVčé;ŊÖ-ũūé…ôuÄÓĀ6fÝũ<ŊC.đIíŌ'ęėŦŸÔ€“ÏÖöŲ_éšá)·JšF―øžķė}ļķoąZô1ÕiÝGwüýŊj[iĨîŋa|kĶMüÍ5ėî[ĩsŧjqïŸ4fvE-üx”>ž―HįÝņīk5C7üýE­Ļ2A“g-ŨWė­‡ĸ2X―5KųÞ4þœ[þĐZLwž—īēęwš2įJÝnO=4â|Ō›ÁWęák/ŨÝŊĶRŋšŧv•.>iwiæŧúËíOĐÐ!ėÞüũjđ•Úßv–šx)ÅĶL8ņŽĖ-°U ‘Ã(Ūsƒ7eĨåeĸa{`ÃCA+{ˈą^Ќv‰y… ˜ÁĶ…`m·I–TPþHâd… 4‚!šiaŪ$o0*ŨūF™cMLˆ~É|M0@Ũ<ĖEÂč‚mZáÃķ Î';ģ DYÎK€#2·9ó•Č`Q^!Q8,wäeîŅ ãę$ųËw–Ōp,›yĘÄÄ Ģ5Ð[ŋ>ü–1ĐF˜ĖņōtaæĶŊ’a&Y_래ŦųLĀäa°âZÝ8Fašfp‚iØq{|āĢOč ØsQ@X ō_ÎÁQbNŨ‡9E>ęŠ{æ6Ēï,m§?6uōXģ­ØŅÞVŽiÛ-ôč=wÆķbógÍÔ!ĮžŠëi‰ÁĖwxĢÄÉ/(V“Æĩ>omöz]·Õž“›XÜÐáÍÚjŸ!—éOÃ.7ĨX'eĻeÓŠ‘ûĶ.9þ$ ŧëQ-YĮ€ą&Ģc~ūóâÃ:ëāþz|l[xĪŨüLâJzÕ'3čØ^õUÉKj&ūóļŪyėsÝþÏôŌģŨjÂ?.Ð?>ĨF?Ķģo{Sƒî~\ŊžüĒÛūĢŨ.ÐÄißj9M/]ĄéĶ*wĨï]ÉJ―þÚŦ_­Ŋh˜ūúnģā*zė‰ŋ)}ōX;Ý;ĖÜŊ›ßŠĪáOĸ[ƒũĻĻŧï{ŌQFģĩ|âGzöųtÐe7ëōĢŧëĩįžÕęúÛ脝:é€ãĸĪÛ/:D•<ŠÝņˆ+õĘČ7uņĄôÂóÏ+­á6:Þyö?Áy.<Äaá–hŌŨ•ŸŧZãGÞ­›Ÿž­kzI/Ī+íĄ.šHO}ū`M]xģ—§ōøŋė gŠĒdy…UąŸ?”Ï!€ ŨJ:Ė™dö‹Ujóšą(UϘ9Ė Įæų›[ ģĄ6ŨĒøÃŨ āCÎ1ęōXŊH^LŸœƒ9@đšl’ŽjØĮ2ÝŨ ,đÜbé‡ëYmÓf˜}Žzų pP>lģ!ĀKÜļēũ,gĒNŪ+cžÎ (Âǐu|í*{ÏŌΖ pĖ` É#é+ūÃbc āž;}ƂsȅĐ3sė<ã>F^ú7ØūågKړswÛč+ũAĄ8.‹~Ģ/Ė f7î_2?š0ëĖļMŅÁ–gS&žģ3ŨŲVlŦîÞVė<õ=ôāØV,§Ęū­ØíškÅĪņzæã™eĒëÅGîŌôšÕđa–r­ļįĖXöóÍĒßž|ĐåÎ―UŧYšæM%_ąfM›ĪŽC*t˜ēzÛĻûN{hûn õ駟é' i|ï4ņDú oGõ˜†}˜§#ûïdSoŽj,›ŪĪīUúô‹ųjÖŠ…ęŨŊ­ÅS?ÔĪĨɁo,:ÏÍó3l€_0î]M[:S™öōõcĻĘXaXōg'3éŠ=é/ņŪ1ĻóĖĨš·ícÆõ”ÞýhŽîļėUvðŋļéŽđrZåg­Ðm&—.ũþ‘‹âóÄWÔĢ–éĒüKgļģrJ<,˓[–'yû-‰{5ģ‹ôÝ7ã”ĀÓlÍsĸVŦ\#ÞÓĘ~ŨV—Éã1îMxÆ+äĻÝŪŧϚ·[<ŨĢ/ũÍŽi“5o#ķÛÔ╗ĸßÕØ1ņēEË~›ĻjLŽ˜ĪâMæaÁú™™ÆũÄ$ HHēVڀŸIVé@€ āðz‡ō‹îïxËēô%–kpÞ/ ĶRxĐ 6@ĪĖʐ1}úmu=°6jGįÅņ‡:‚ņšQ°Ë"Gę ‚N†—@€1ažü%?ĀÃ&ÛáýāåžnsâŌ7‰Ų—ŋč#ōŌF@§)Lžķá"Ų.ŦČʑĨ―š{ЋÁËe3· €Ãu9YvĐg[īÉųéƒpnr_S.RRvŠ6ûxA&|"eFNx*ām‚á’ĻXŽXFSTûEySęĶMī3'ŧP5+y0āy0ŠÜcĀ>:ðð}īÔÄâ wޜ‘gŲ:—øsŌĩØņ=>lŪŽ;í―Þđ2žKƋoŪÐ]oŋŽ•ÜO;ėĒŨōŪ9įéĘ3OTÕ5Í,Öč‡/Õ=#įĐ`þwšÓņÝq”ͰŋuóÐþšŨį^=zÖķzĸ‰?ëæ—§ŦfÖ }õÉb >\Þ2ôG‰g{ÜÛŊč°þ‡ŠbņrÍsŽ“ŊšG{4•Z ~ĢORĸýQÌÅZÖb'ÝjoÛ6Ųu4čÝĢuĀ^{iËĶ•ÕīÏ ]―oe.Ņ CöUÍZÅZīŠŪëa TqG"žýßK]ýÅD~Lō‹3ÕkŊÁęũĖŅ2ðĩlRIíúŠóŽÝßŨVŠUŒĨÂÏ'Oýķ―wŅ=W\­cgVПŽ3ë]þ.?õDĩīÃðįŸŋŪ'>Ø[―véŦ{įč6ý^ÞØïXĶV•ĪŦïūCÕiÄ šßŠŧzۊ[ŦÓvïŪīž]+§ý!Š ý~DśðŨj/qšï=6f‰–Íķ™{ÛtČ΍Ý)ÓuýЃ5ĐĮMÚiëV›P€ōĒĸh=°ÁXĩUŠTҐÓOŅË/―hsš―­ôRFĻ8kž`^VúėŸļ†rũ› ķ"P ŪÌ #ž0ÅÂXæųßXböâĨĘyæíļ.Ė …š^Ā8€ð4ƒâZLŧHpī S'Ÿ 2äMĀË:ĮĸøFYÁīü—(?ŒØ}™ŲŦÕų1o† Ų€xâQ;kžki+`G›`l!‡åÏ2HN0í 6͆S‘eĨÍth€ËšQt`ĚĩÛļˆH˜kQv–• ė CČ=Ûx-·/ôqú6Ý?8ĐPĖð&⃜čēšMÖiŪ7Đk™w‡?üˆß&VíbïņāŊŦFŧöjémÅ2Ä āKf|7]sūúZĮē›486&•ÚŅh”ūĸaūV,˜Ī‡ĸKõÛ4PŋC4čā]ôõĮïĻĻR}íÐŦgb"K5kÂ;zũó™ĘðÚÏ^ŧėŠf5īĶKSŋýJ…5ÚĐ]ãŠZ0í ųø[åĨŦY‡^ÞÛą…gœ–/œĄŊÆ{>Ō&ÕRīéŽn­ę­É”ŋxŠF―ó… = Újû]ÔžN2![°|ķÞó‰cƒĶŦi§mīUŦúš5ųk}6nēxÍh5[pę7lŠjZĶÉs–9fiKå(OßNįĩŠÍTŦrĐ&~;]Uę7TÃZ•U°tĒÞĸā[--(UŦNÝÔđms-üaЊ*6P“š•”į5Đ󗗩i‹ÆJũÜíGï}ĻÍÕŊ_[M;FßÏĖU‡­šjŲôņÞCëdę“w?ЂÂę·{sMžšĀėŧąjUņ†ÎģŋҘOlžMŦĒî―ÝwÕ=0\đPSæ­pųŽãj^>á8,sýę?š\^Ó/ĸ7J4}ÜhųbŪēŦÖÕŧîdžÕlZö`S&|ĢQ3s4uešš·ĻĐ[WVJžVá+OĻ€Dü_ÅŠÝ pæ8ÏtЁó%UŪh…pZïĮRŠŠ6+ÂBÁƒDŽd^ŌÚŊfBÔuP2—†â†™j„^@Ōzŋl&ʓđ8"Tœ7ÓʞxŠĨ„ïóR įPóAïøî—Ãe{ō#øŦÄŪëBM˜Ī/0Ėv~dƌ›€lr<æ]ŒÐäPč€`NQf€S0f ž0ŌŸ' û{Ō>ŪĮ, (ĮRË Ó$,åbĘÆüŒ9Yɋųh;`‡99)GĶdn4ËUpž Į&įež’ó°rÚ 'bP0\ÚëzÜü™0ú–%ƒÚkŠ—oSæ‘f)Ũ^“VzÉB*mŠ ïôᄠ“c[ąyósÔļWuëÔÐvÛtR]ĒM?ʰ‘_ōOŨ O?§%9ÝtĘQŧüč6ē˜ōlĸ=ðÚgÓ4zrķn]Ŧ8ĸ îįĸī ĸ—ĀđAS-:-QčþL“ųĀt―gM+âtGį0œÚӔđMƒ„QE Ó"ÁŊ`w>Kč˜Ģp@>œ!LŒ  ›0@LeŨ†YÐċč0!;$?ŊņœEhį{ĘėÉž`EƒH˜n]Ž ô4Ō(ŨrđÐ`ČLī­ŋ]>ĶP@POĀ˟#–zļ=ô‚lG@Šžūž―°GūS}ˆŽ0MÄLíT§,76ÎO_ōĒšĄ˜_)‹ör –î6‹%Ž'dN…<āpŧ‚ÝR“Ŋ‡yē'mc^3tī§Ė@ĸĸ‰į C‡6þiēü|Čōŋ“§r­æ:ü”ģ~ūøōĢĻؘmÅþPRÞØĸu û1LÁˆPûVxC ,Vîa.õņBæņĖū`“Á4ˀ žœ\ïĸĖđFއųŌ F=xĀĒ*ƒmųú0ƒÆ>†’(ƒĨ9Ę Œ-Ųo§™ĸáĖCŲ֞ó30FŲe ēÚsšv03D‚@S—)dLư:ØQŌ~æ öŪ&ĘÜ!Xãrhy™ŋ gËMÅiŪ pUēÄÄđðXKJےāIÛ"bRīÁ§UvH‰yZ—›€=ýÃuđÎG?R_˜Ė]?2Æýð=á|xÞÖÎà ƒíÞ |čó”#Wj.@̧~ÛĝĨîįšŋm;Ęk+ïōøĢõZ뗓õ “b€ ˜Ūᕉ‚.00\É2ė!k Ķe0MiŽÎ °%œ`gū$ūó‹ŠL–MX•RŨâübV ‡YÔēāŽå9Ë ĘSy”ũ@yl>=°Á9NÄL˜—Ās‹ĄžmREɇģOxn& :ŎŊdžS§ÖųQæ>  HĪĖ € JœēüŅÅú;ĸ|ŒscŽÛ„Z€0―’ˆÁZbđfĮ0I4}Θk@fį… ŧŒēËcŪ†‰Œ1((6úęM―õÆŧ:cČņöæÞ”Þ˜?ŠšüKy”ũ@ylTü*p&N$Þ;Ōû_f8ˆ:āVėĒ –d‘d›­Äđg5ŽÔÚ0Ā,€.aĐŽ—ī`€#ėV˜01X[r%Ž eJ^Ā IĀÐ8˜“īIÕĮ1“"úŽA Žz>ĢxðLĨ0€ĩËfŽ0@uY\{`ÚŦ5)+qœÁ3/ĸˆT‚ŨŦó'Ė ģ*ė•šģpŅ*’Á ž/WÁ$ čaÎĶ^Ā3I‰Ė ð›QRåä{VĖ2a·ÁØ,<€}ÎLËk€ŦÍū”˘A„ĸ‰(U~˜^c`ā<Ņ—îĀ?q*J™úĻ7€Ō€É9žzüŨGą2Đĸ/ĸÄķboMõR‘úęđg=ËG/:Y ķûôÓŊõėM#T―n#2ðPŸOõÝŊKątÎx}ōå •VŪĐ-·éĨúįŧ`Å"͞ŋÜũ'īlÕjÐX5s~üZŽZ4K_}>ÎۊĨŦMįjÓø§į‹ō–iÞÜEą­X‰įŌ+U­­ĶMęømųmŌŨ/?ŊéM{ißŪ › 7ŦZž­Øōä>z˜éũЂ4nǜ ŋUïoVQ.ĖoÐ?ÖëUˆBÌ#d=!kÃ3ÓJ.ŧ",Ã3ŒĒŽ™sôEÆ%+Aģ8ģ4+C‡ke*…ŦˆˆƒĮ§ŽÔg›$ s˜(t@pÆ\ úÁPØæZ@0'rJ?žg jÖý‘ētpEfžZ‘s+)Ėŧ°8ŨŚČt˂cSŽw4c…€aöĨÞ4ģAíĨžÄĮāŒ71`är#œwœ•>ˆĻ<– gŠēØŽ3Ã^Į˜ĨéĖ·ėĢÉĩ%[`&&U6aÎī‡'ä§ĸiÕÕØýj€Ķ}4>˜Ã2YŽÂ@ĀfĀA_b&GöðjĶ/]Ÿĸ$ƒËœ™æđÓ2KĮĐoS§Å‹Wjۊĩo ãŋ07Ė}^é]BŪŋņ6o^Ą~}ö·|ë‡ø%éŠôö wëžóT‹{)}ĘŨš‘^OŨÞsŋvmUS‹f|ŊÅéuÕķÉO*|þÆ]:õOOk‹v­•Ÿ^YĮœwģÛzÝĩĢŦ5ņƒgtݝŠQýUõeą†Þr§NëÝäGŒ}ý{é Úv§m”íå= šėŠsÏ9Ęë0”m“}ųô‘ëôŌî·ýaó―·čÂŋrėáúZ•][—ŧMÛĩ,öūÉļ?xÁNúÆúÔĶ=ĒÏ›6QØŽËÄÂlheœáļ­huX[€™―Ba„ą“J,ŌGđ'^œįžœ0ūL;ëõ(0M1-@ “)l31܎đQ˜aæRŽĀĨfRwõ>]õŦä9ėūzu䔟į‚đ3TXŧąÎŋüÕtŒÜīŽŠĘö.#đ~ŪrĘä–Ø’QčPv•Ė„V9r{ŪMö™•ŦŠz%îŧaķ8d8FîŌ%Z]ą†ŠWÎŌJoQVœæEûÕ―ŽÚĐÄÕ4?ƒŦV,SÁęlÕĻ‘ž +ĻIÅdڄ|+—,Va†côV#_’ W.Ũ $ĐP9G9•’ļļe§~įŠ4/Ŋ‚whđDCú{[1ŋ;m„đáwÞęrņĸĸõhó‹ 5ŠēFŅ&æ=œPėÜ@`‘FÄ:F›$ ,ĘP#üĀdÍ}#’?û6Āâė‚ētåĮ<Œ#pķT)€Âk7æí §QĻ—ÓÓ-`åŸÄņÅādýŧŒøļTPیŠI˜ŒŨ°á@ÏÚ`ąū.ĄPaÐā†ĐÖC@D@ƒ2™‘/qlĒŊĖâÂ\ËühĒ炉ŧ0pļÞĄJlYōēÓ ĮÃéĮĘ5քš^„MxÓ&ƒ‘h_Ï'áûøžŽ5kM͕Ō–-BôÉqŋæģĸ',œÏeyaôÜŨMqŲVlæôézþ‘č_Ï<§Ïūœ Gôķb͚čĻãOÕĘXڋðŋžÆŽyIŸÔÝV—€Cõ9Hzýöą­XÞLïĖņŲįzäƒw4úš‹uá…ŨjîzAfKÝß+VæŠ4§ķÚ·iŦ:9þ(ĨyïË:Š“]Žų?Lô~–%ęÜü§ĶZÖWŦ^M7PýFÕ nmMiÆÛũT―=ÉÏņ4]2øh‡œåÏ3õ—3NQĸû{ÉõĘ·XĐŧN;IgsšN;bu=`ĻîðŊ:îˆ=ÕģãĄz8‚–—ę­ŋÖIįœ­ĢŽíŊšî aĸxƒ€|ˆ„˜īÞ.]ĢþuģîđŊöØï`]ũÜXũļ4cĖģļũ~ęßĸ ŧïYånú1’kýíRЧ–/ÏUZĩújŨšŠ–›iŧÎĸÖīAāĪ?PĶá8#4Č@qPØDßœp JXy™ĸīYÔJ;™k3ã1ˆZ§ a‚4ø°øßEEŠ9üŌã!JY gĄŊ%Ī`ÍÛŋĘ jŪ”DÐAÉûĄë(7‘!1“b'e/N°6a,wDr}˜41F~Ũ„ãPÂJÓ/ÞĶóĢ€fxĸæeānü@ĨzĘBfĀ—šŦðjuäGvXĨr›aքÜÃŽš0ƒXBâžĻŧ‹Fú?ƒōÁÎí Ū+f@BnØēüāKÚėË,GbŽuekŪgđJâ`/ũ Âe§Lđ‰ƒ€ ƒŌ6}J7û†õĖĖKŨqg]Ķ=zčá;nÕõšT įÍÓĀÓÎŅĒėzZ˜ŧ ūžQ­ēIžIãš?ÚVŽ.ۊ­ŌĒĶ:vĮ:ðÜktÝM—yÉu‹Ėðî"Ô­Î]á-ÃN―ājÍþ9'Þž…zãé;tŌžû蟟·Ōą‡v^·ø\Ąr%M|ĸmzÄ :ųȓõïoVĻã^ĮhÐË5ô ĢuĖ1'jZÍíuBŸf~€ŠéXï―ųÎÛ#uzÎx=ûþũ.#]ģŋûL3KÛéŠGč€e#5üųéú“ũĖ<―Õ\ÝņØ;Î“Ķ…3ūÐČYYšð–§ôė'jÄ5įëĢ……ŠˆY>Ó1i'=Ŋģ/{RĮđŒ'.ÞA_u―Ķ›ÉŽšį^―^q[=úŌH]~âAúQ7üĪ5ŋ·YÚŠKGUXōŪ.Ú ―rļ–mÜĢó{khđž›Il8Qč*`”+`0Ķ0+ØJē”ÁfB+sØ,æ™iĮ!=sw(dL•É|ĻY)@č29OļXū"ų`aö|.–ŊĀž\æYÖ`X§@Å@Aáaržüf†ÜČ^ļĀXÎákēíĄ‰đÃąÉ€KYa“ČdģÛ$ąũf˜‚-G0fc(u°ü#aŽ+ŸãŨ’ð\ÄbžŅu 3g|ĐSļų/ ‹7p2q= N`€ôŦ:Xžjvð`ƒö`ūN• ™c0i—eĨ:ôAD52ø" ƒdĪ/ļYþqMŅĮąU”ŋ‡ˆļ íb.F™YŊ…>WUÍÔfŽýLÛx‡’Ö[ïŠefĢ…Ņ—§ýŌĖ6ōVųYZGîŌüåZšūZMĸ{įhiQÞïđŧ·lca)K‘ētdĪ„ŽX""Æ*vEA{ŒĢąũˆŠĒŅĻI4úWŠ`Ă4ĪėŌD: ÛnŲōžßœo­Ü‹š(Â|pũžó•)ï9wžų―óÎĖë”iģûËôYk—™Ó§ņÝú›xđÕlÁõū”·ýë‹Ëü?UÞĸ-!ö;ĮÔĩĘŪ8ļžõ“_(OÛáŌōöwũ{Hwýķ[Ž8úEåČĢ_XvÞŨęĪ™åyï}SyČÐiås'M+Įūþåe-Ė<ķøĶō͏ŋēøÔį”ŊšĢĖLäðĘē”õ ~þ ËķÍ.SŲiä€CŸWvØtÃēŅÜĄ2°°JåėœyāSŸ_öœ3ŧlŧįÃËz4ÝļĀE3ø.āöŸĸ“ï–…7^SÞwô3Ę ßþý2zįŽēh˜1ãW]ZpF9ôą‡”ãÏüŸüýé˜TæîũŒōÁũū§ü˛+~ü?ĘĸžóŠ Ú)lGģĀęīĀļ?Á ķ ŧj$°f Ð5čˆŠĶ  ―‡ŠÍ…‡Ï ŅnXŊWŠ#O”§0BU%æŌpšv+܄„naa,™ÚAĢ71 *Í.ðĮŨBCˆÖ€ÔŅš/-oę@ję‘z˜Žíģ / ļĢhŦâ­āĩ“āsŠ:;ĶݍšĻ€Ũ…œeģ ,ƒó―įuGW·6Āīū(ÜÔ՛ )îIð!j-GØX[ŨŸŋÚhU™QīÚ\[™™aó:Æ+=ŠÂ§ãBZÓgM$ %P^;0Ņžššúœ#ĒđŅ7ũ⥚ýÍmÅķyčÎå%l+vĀÓýímÅĶØÁđgāÜfŧ]ËĒy?/_9ũš^ÉĮĘĸøŅrÍÚ—‡l0ý ožfÁÝԊψmÅæėŧ_™ĩÉ$tŋ‹û–•ëį_QŪîķY^ÖÛhËōÐ}UöÚqƒōÓó.ø―mÅė͘―^yØ>{–ÝũÞ―l°†ßÝåĪN,?YąuŲaãģʗūzJ€{Ō+ŸųÎÖåóŸýDyō\ķã{ã'āŋ+FŨeĄ>§%äëąršņþÍņđŅņ[r î^ŽÅ7_Wé;›žôĻP„ēÁÖ;”5·-Ŋúā§ËißųVųųÏ>PĖž kÎ}4.딏―`·rė›ÞWūĸ+z'ũŦOĖāīēÍþûe[ą;nÆ=Žýo\0ĘýŠš­2U øŨ}ũ ہ%6ūq_ŌÓÞ@đNO ĐxކßFDØøŽũĻÚ<:—Š ķctQKžvŒÏk*ķeËýÂÞC‡D―Šô„o@›Ïũ>ŸČS^Ûäw€‚c@5H5ēTXeRÛ=üļcx.ŧ‰P]ĶĐ/ķc”đĶj3ë‹â˜*ž:ĨĶyŸõ>éH'J&āÎQ|@Ïō[w ^ŪšN­­.bóē#’ýMIŦëŽŲZ[ĄčēƒÔēŠBɆqcÜÂĀëÖÝžS.>—|F―2šFUž‹įtŌZ'nĶĖũîáįŅm+60eMv>ø ōħôÛۊMú#ķÛįéåŋØVė°ŨmÅúē­Ø‹Ęql+ķÂolßG”SŸytyõôW—·žâˆßŲVė åļÓØVė–_”wxfųčģëķb|Ų!åÆG_þÓmÅūø–ōþÞķbĸäŽrĖ>øûۊŅüŲ™_)OzŌ!eˆčÛý}yúƒŊ+ĸúņ›ĘĮūsNŲíÖO•xâģ;ĢËŋ‘rŽûŨc;ŠŧÔÆŲFX—ŠP0PÆOÄMŠ‚ĢÁv!Š+pīÐT1f,Uh2ĸ“Æ\0ĪaGą ,?Fq{ū ‘Ūûz nÕU€  šsĒQģ 5@ €žåžLcðÛþč $Ęä'eR-vā3pIŸ^ĒxQŽ–YũŦ°ËíÆšZvaĨmŋ‡ų qݟ–Ųky–ëĶãû•Y€tĘŅ:YrËäÏoï&#$4?Ÿ'uŌVáVũ­ðÍgÂuïu|6‘Įä5ė3fĀϚú† ·*O;ė/qŽĩöĖēģLnđôâ2‡mÅúą3sŠë–8þíķbC‹o.ëÎbũä˜4ĩėsčëĘĸnšÛbÝ\ą­Ø…Đũš§•ŦŸsL9úĐŊ+§ēo2ŧüör “Ë6{03t=ۊ=ĢėąĸÃËÆkqĮŠYå˜w팭ĩMrßá‘ļ=g^Vģoé‘ĸī{ŲóĄ›ý^Đö|üŦËwķzrV:Ō–ƒkmX6[sĪ|ōësĘņgķŅ‘åsĸ·[Y8°aŲnŧŨ–/}mïrýðīēãö•ËŊžūĖY{­ēóĮ?_76ŠxRyå§ūXVĖÞ"ųxôgËN+7Ėë‘áIeŸĢ_ZßifY4pTyØÃũ+†œøÚO—}flĘĢ3Ę ^óŪēËîg•ų·/!`i‹ēQï{ōĖ20w^™<­ėžŨūecũB―ŋD.oŋïËãŨ`[ą™Ï){ïĸ0?õ[ūayÕ{N(g\?ĩĖ_ȗŽÍŦÉã‚Ó<œP, xínWŅĨ@4 М'𔆨ûĒ4ČTOČzĐž°™° `ŠJ‹ ”†ÞiŠÕīëĶ PiũMa#ž*øWp_ úĩŌPæ“ų”ĩš\q}2.é~š–oĀeĸøÏr%XĮP\äõ•ä/Ží0,sģkō”5ZTũ”eTÅP!’h:ĩp6J֜gIËēÔą^•&õCMÆĶÔ% äýST•vNėhä<ÏŠ ã_•îØ:OUHzh;;Ž; T•x: qĄWē PÜėĶ‚Ý-Ŋ; $—ũœ―ŨYģÖ,=jWķûqųîÎŪæú\ýŽŨ[wVųû―į–Ųëĸ~ôęoÜú;/ûʎŒųíØ;ûô§?ŧ|ýūVn\ģ˘>Ģėĩĸŋsŋoû—ÜŊšíï\4sķßeÕÉu7Ûą<ŸņŽ™ëlRöÞw“ņn)svÜuÕõ‡îĸčōÐÞŧM7ŲžūZ{îŠëoĸëNÃŽķ/Ý ÔÉK7+ģķÜĐ<üąŋūŨ‡Öģ}aĸéz0uį‡PvîÞó{Ú6;”øđ“ËĶsŲô·MBÏ~ {ūî\6^zuđrAõdÝ?ëßjõ—ķĀ„āTŲðg‰J šĻ)^ Áļ ižWĩ‚4Ęc4āŠ;gúîÚÐÔĄĻ4Oéē*úŌrŽ&JŒīŌuú‡ųŠęē#H`dđpÁöŪ%*ðė# @J°eūš~īa2U9NXĮßėí2&šĪ‡īęî(âģŽZŨځHäį{mÕ…č`dų>îĩÎé$·nQ3ŪkâĖCū$lý―/.XæŧNæ*t-―Įú4;"–ē.lŊšįĢĢlÚÃküX•§‹ŠŽUДåíųQ6ŋÖÜÛØÁPÕŧœÁB=3Ë―whŧíķےŸ-&ČäÏÃø”Y›–CxŲyüí]>č=. ĖüÛ+ø_ąÄÝr Å"īŽïgœ6Ô.H „„ õ`ĒeuVŨ­ēA*&ÆĖŅ “{ęIååq‹F…’ũų>Ū][lþŨ―ðĒAcƘR’|đwˆÆ_Ļ&ا—ÏĻÓb€œÐ4FÔUp„Fį~Œ‹™„ ēĐダžë)Ģʒô2ķH]ú€Ķï]„ v ęø ŪMÁį˜ĐKÂyčŽu>§`ÁÎKTé N p3Ÿ”óšhÝóÓ:8õ#u`ĩN$D―âbôŒËЌTDýuČŠlUĐޛ-ČHĘzŪ.”āĪÞg”|]‰(ð­Óہ?ķŌ5íë°dé’UŠÖúýeŽ?Œ™2ÞũrYcíß\ÕčūWūVĒf‚* îĶĶ6mÂG(Ũb *Į,uþ+ũŠ Ōų“ĖĩķŲÐÚØ $į[šFT‘ï hņ?{zᾂĨŨ„K\ŽŠ!ōķqÏząÜgÏQ@ŦïZð‹ßL_čPuå8a76+œ‡õ^oī Â9 ·vTšÖAX GQ Đ"4pHOŪ Ũī}& ōÞĸļ‡f@M:1iՋ"ÔMŠMŌI°ū(ËĖÕ$-UĻķ1OĄ&ÏŽãJęŊ1HŠôę§kčfA: QÚTÞrøyØ10kmUĄčgWĮvG4ņPĨ֎@=o'Â)8qUįéÜÖþihhhĮã*NŸŦ‘Ĩ4æ4ðq9ŌØÛ– !Ę€W ­ķJM…jƒ< ØB4üžGé:Mã …F—ĒRmȁĶÐr\q€ę‘ĮF…ĩÐt’~U^.Ī.Ø,“`fú†ŨņšDuL3āæu1Đ:Ā0!A5‚Ōr‘Ŋc–YČ ŌģÃā9§ÛD- 3ōÓ&šGT|žēÆ­ŦjĩÜæ•ĻUËDŊŠÓP€ŒíŊŊ― +Ð…Ņ öqü/jQ!ãTOÞ+ütEŠž$”c‹Š'Užð žÉG•ę”Aģœë™Ü/€đ'ãv”3Ŧë ,SH ÓĮ35ˆĻNį°ü–9J˜čS ™Đ.—@БķŽŋ:eFgu ÅŦR3a›rRnÝĢÕU š~`í5Ę!Ī]Ð ę™tKŒŽI gĄgūą5įęR~ԝkæÝđyĩ…ÏwėĪkW`›§?ÚŅ•“Ž*9KûQvUŪĀÔVąŦųR.ÞīĢY Y Y Y` Œ NÚÝ(+Ģ4› 4ĸšÂ„Ö9į]į5îJháRĢ:ë6[BĀÆÓГ† nÃĨŧ4&ÝÎõÉĐīßæ%Œ›ë éî"Â*îXŌxiðUO‚ÆąFĻXî5%ĒÚFĨŠŠ,ŋéE•ņl^ólķô2ˆ|[­ZUjŪãXĢ`Ž °3šTĻÕ)5QļæM°O‚(ŋŠTĐîXŸ,—ƒĒŌÁāJ ŠË˜ž]ŒÁĻe]ĘąåwLsDw,6qÕ"]ÏYh_pR/Ż™‚CGĮÃ:‰Ė͌;ëúŪŸÓö ėüŠT>·ÆÍ˜­ýÓ,Ð,Ð,0ŪÆuÕ L… Ý}ŠĨ( Ą&ä*ĶFq 4ŊgĄtŪŧ`ĀQՍŪqÆ6ØŠÕJˆp―FŌ F~ ėXi§‚&qģå°ąŨÕ 2*UZLŠI‘ĘKðņ>cxäģ‚1ĘĀ*eŽcī*Ã~$™―årqUšĘMręŌėÆGUmõ>näšÏûlԝāįĮ|íļ\ŸyGýb“ķ3ŊYWŠSČ8c§€Íé8QœØÕ<„Ŋ‡öÚFņ&8É|Ē&§Ī\*H﷓bÚ*XaĐk7—”ÁúsaL^‚Û:ĮVyŠýÓ,Ð,Ð,Ð,0žlýĮ=lėU‘Qš€B8:ū͚áUvA ˜luÉöĄķFYūÎ7Q54ŌuŠę0―A)>íó.…ĸ !!„‘ĘËüĢRQR>及2 ĻÂ(“ųä=ÏՀ RW1ŠŨ ïŧ ĄtPxŽZÝÏcÔīĻO7N)áU–>ŦŦÓīkĪρ9§s]ĐeīĩNÖŋ›Đå!Ÿ(ڔ‘īPŦŠfÕ ÁNÂ˄íŒT\úvU-ĒŠĢŽđ&d…]uu“ð3ÏtH§‚•ëvlzJŌëY]‰{ģ!öóóōGŨm:õ#!Óv4 4 4 4 ܝ&§ãjšGYH[xĻĘl„LUFd,ckB!ŧ ;Õ6Âuā Ülô…Œ)BQB Ó4Õ5m…sĒMÓļWŨî XëvīĄ·BFĢÐð<|É5D)ð‹[”{ÍGˆd,84Ī2Kæ`ˆHÔ(k`DâVœÏ QŌÏø ėsĖÐ|―?ABšŪ)ŋŪláh=ž–ąIōVÓīœĻEíæ}qĢÆMj§@ĢØĢųĶNtLK°gŽ’2{=ÛQ—Ž­K S6ËĶrÚÝ+ëĐm|6õ§6.hïk·hËįIū=åÐenDpįžūŧ/J;ß,Ð,Ð,Ð,P-0.8 Šįešs‡^CþŽó U8Uý8z°„ās>Ķ ·ðēAŽZTՐžŊu?f—óëÎ5ā(kģrŸ0S9‘āęF'ÝÞeķó2-AĮîÕ!APÕg"O)•ĘQðXNóĀ–ÖU€ĒIOX /ĄÉĨ,Þ ŌŒä―nd„dՕät2 †ë‚ÏՆę„Ë ^tuAŸĩœ*[]ĢÂTx{>ÅNqŦōÞš8þé―–ËͰaĩļ ôAŅŧĐįtÁfĀV[ĨėČŊŸw;ššššÆ·Āļāt’čžīuoĘļUiĒm UCÞ#plĀmČŸkÄ €l`Í9PéÄåĘ{ï•\7PČܖK5(üĪs#ģč:00JÕēęVLšAuO ‘án|TwސĨāTĻv €ĩŠXåÆ9ēČõ(i•5€Õ};U€€ÏĻ^ĄMSnŨðM'AŠyž‰™Ū'ËŧžÕuíóvLŽeÖVQÚܛõr)ģ0ŧĩœ9žœ‹r°ÃK‡ĐéR?―nIæâízĘ-ŸÁF*RáŪŧŲǘOV*ŠÞ€ŪNđ8ņwĶÝŅ,Ð,Ð,ð€ķĀļQĩ6ð{ã…ãz°+ Ht)ē ÔëÂ(Á% ÁqN•Ķ wÜĪžXęY8…-ũŠ1.ĒÐĶūĻ!`,pœ·™g ęH …Ļ5ž›ÔSJ‰ž^uÕ"õĒęQ—#ĘËB ~ŒB;ž›âŠ@üüBÃįVz.å&ïåĻ6ŸQw:ŽZƒ ‡ušFU­ŽwúŽjēĶ‹ŦšgG†Ųd˜‡ NRY {Aæ―ÏŒØÅąFÝŊ9xÎēŠZ―6dW Ú3ÖJ9QžËw ˆÝÜEd ÐkX—ïó鮞D:I ÅiÚB^*[—•x ĒN{u2_•ĐęŲ@(ėÜÚĨØ+Kúl;ššššÆĩĀļŠsU3ŠęĄw›-ÏĐŪl uýĐmÜI7ÍĒ ÎņũJž3'`ĀŦkSeĨI:< d樛ĀqŠ„ŨhÕCu… $|ĘoŪ;î·.[pA D­JŌņBÝĒrĀĀ&A—û)Ģé(c:ޗ―:ã)č4ĸTW&e$Ÿ°„t„[Ü <Ëcõ<å֕mtŦã―Ú$s-áuę@rþšUí4TEw,Ïø^[øŸÞäļgyÆ "Ý­B’"óū§Ø3:[Ŋ;f[įmR.ō5 °jYDW RÉŧꑟ‘õ°Ģð“ķc§}\‹ĘæžŅĖ~íhhhhßã‚ÓGU_ĒTĢ+ÐÆZčðO\ŒÞĢęÔĻŦ֖^•fcîę:™ĘáýĻÓė H%nMU īUwņĻīå=w%ũå:iŠ:ýOUƒ†„Yuđ:Ž âÚĖueŌí[ƒy@5"VX95FØYnę3ÕÕK|düá_ęC™x“Õ“PĨŠíč=]ĖäcTŌBk”g―?AE>J™=tŲĖTW2HŠŠCŊ XĄ<Š‹™|uņޔ‹g3VJZ–IÛĮ‹*OQēĻŦŲ°L|0'QĘY€Þst óí"‚ýŒ ĘŠvåfŽúo^ķššššîÆ‚“ķ8 Œr]4āŠ+•–Á- °Ąņ֝)؄†m9x žš―5Įlž9l&Ýë†ô>8šjŪ!™QC4ôäcƒ/žu ÛØûZe+oÚÕÕ+$‡•Ī ĖTąߍ‘=j PōdwWá?!H….ë%TŠþĩÓāøĢÄēŪ–Áú ÝļMŧg)G HúĩkŨršv"‹UÝv8„ŸĘRĨi&*GëāĶmįA[ÆĨŠņ9ĀhŪéúķÓā5ËāøĨ.W푀*~gšt\{7{mēОŸņZ‡ZĮY}֎‰y ív4 4 4 4 LlqÁ)rO>*7ęÚŽ9I@u2ŋQĐRQõԁ@ ųlîĢ·aÏx €ĄŅVVx ;ßũT§ķqWáÛũ<+d(“ũvMūc|þčžõdœš‡°þĶSĨæ§4ó|ĀÏ[óQ•Ū‚*ã”UoīQđ>oãŒBÞCð›†ã…Ð:[·ĻgŌ’™Ýē /ó|ŠU+ž2…į°4ųU@@Å―ŠaĄĨÍ–ŅŽÍ7€åšïcĘg'Á2h›þA,Ÿų{ĘYŨš°ÎÁ=ĩ3R;6õdû·Y Y Y Yāî,0.8’jÆÆÞ†X7Ąŋ;0Ø@Ũq9A  ÂĪūwŒ.ãĄĀIwe"QI` NąĩŊjĖ{+Ü[ôˆĘ%9v—ėĘ *ŦËQÅÄ―4<=xđg§{„ĘEÓ đGčyģųxÔE,‡Š’2SNĮY3HđTÏՕ+­ŋŽ`ó―Ū]ĮP…ŠųĄŠ&ëXŠöÓ"–Óīī ÎU=Ō)Œ-,(Ķ(š;uĻ{;nbUholX›–4` yMŠ~>”™ņQíEJ]đíæŌځð3UåÚĐé"˜MÏ;ÛŅ,Ð,Ð,Ð,0ą$Éļü !Ŋ‹”;Ö&@tV·ĒjP('_ŊŦu›ÆŲWD šql.S0H<ĒCæYĒI…—ũG‰ŅØŦ"-‡Î`į+Ą5$ú8rƌ€t“mÓnÂ&Q―Ī›Tƒ`°Â3Dš‹yå*€xÖ(Y“-ĘļVASÓwĖVę2@uõrŋJSįnæOæųšŠOėÂŽÅv 2ļqķ`4ˆHŠī—ióâYm`9Yö4%?ÕĄhœLÔq\ŪšvQ’ÖW(ŠŽ―?cĐŽð$'ÆNiOfŠKVmēþ֑î’ëĸVs|-—ÛŅ,Ð,Ð,Ð,0ÆUœ>U„[Ņ߁&€ēÁWYК\8@•äõ~hTZ}€Š īęŠĸuÎĒs―W·Ŧ-xÔŊië“îĻsiÜMKĻŠčž_ØđšjÉëĒÅ9>ŋ‚q<ËVÁ€ãžu… ïSČyo‚bYŒðõ^áAęeÜ(TāpĀîī•› 8/ԎŅŪŠEïKG€tŸ‡ē,nðH[*o…ĶŽ9݆_t*ę{Ÿå ({ðŠ1)wōå\§`ĢRÉŨąTĮ$U–.š`@–uš‰Ä5OláūĻ5ð‰ å—ių{ājÊčq1SŽšĄ5iGģ@ģ@ģ@ģĀxœ6ęšc*@FubƒŽJSĩŲÛ` Š2ĩAķņ·!WõE…ĐQttT‡Q8<îýÂ5;Ī%Ė„Í€éxĒĀ5+Ģz%Žũ“DY*Ü ~!/Ué˜iĐīIïô}Ub)#iFō°ĘSÐy=ã™ÅįúPg*žĖņĪĘšBLÆ@Ą™åÆ THiĖË\ŨÍ;e*óE]2AÛý ;ÕģZ9æKš*ūļ…đÏrŠXÕĐ.`Í·‚ |~ õČ;Ū9nY]ŌF Ŧ 3f‹bvá;+v.8 „͇úEŸŨņPímÓļîį§ĘöČØąķâ―ā·.íhhhhßãšjmH…Š ĩŠŽfPŅXóšÅ# âúó…J ĀĻž2–fãMƒŽ ķBS0āb8“âbí+ÀO Ų°ũ‘Į2, -•™Ó(Ļðulo„E`tÞäkš<'œÆĒč %9Ō[FZXĀZfũ ĩĖ*+!čÂčđŠ‘OP™Ŋ #ƒÔgb"` ēéÕÉ:öģ0ĮuþfĖR˜F]Į‰æ·ā1`ĘrЅ›y ^į^ \ÁXUŸ6RMÖ|žĮNäCú^Cߒ'ðīĻÍĻa:/él`/ËlpŸų8v:RóĶā1+yšÞna>ŋx8—9Ū)ģ oÓQōjĸ4 4 4 Ü ŒŦ8}ÞÆ[—ĪJģ‹S°Ž°ąÖ?KcĐ$6xđ?d–Ŋó-?uœŌ•yxjģ1O0ïQx*C§_ĻN š‰[SðAŠxéRM  *•Z””.FÎŦ(Ģ~BîuĖH\ïJQ€Ŧž%zVĩHžý€ÜûG‰īķv›SA|Fv[f’ ĢbIg,ËÕéķĨÖBņZÐôœPĩúÜčH]ÎÏ (Ĩ$ÕĢ#BðO–ÕŦ‘ķ>>ϚD•ZG•ī6̌uĖŌąaĮ•-…ōũ Ú>Ējiv9ķ)tKEŧVhōųUčó,ĨļĄÞk™RAKŅŽffffņ,`+:ÁrĪá—.Žn0j*öĄ Ū`ĒSÜ Œ†Þ "8@ÓÅx\ÝŽFyf øL[œĻdŠåvm>ä|YŨšk+ïuÚ{­öáÖLĢážųķĢY Y Y Y`b LĻ8mdŧ@Úp6īŪ O…ã!lØU}‰âÞ߇v=0K$, }U `Øxgü˜% $…Ž.Ée—k·[_VĻęnĖô Š`ĪkÜģ)KęâĢ<ŠķJ8Áã1ėĶڔ;+rXĨ)„,G°LĀ2ē3ųôāHŅĻķÔ_ej*@uĐjƒåŒË ';‚WėĪįģ5Šx3–l§jĢļą·åÔVT‡4uýVĩ˜ *Ōü‚Þ„Ī|īƒásÚ-“0TŊ ļÔCÛĻLYkúzÚŅ,Ð,Ð,Ð,0Ą*ýÆđÍæ4cm4šŽĨŝéx J‹āAcĪi‚ntĸĄÄĒđnÃÜ42‡0y Z—ŧðS- !˜1AzUYōŅU‹Ō”*ž^qIĀĸÜmÄqBáw,iđĖžũ hZ–M0›,hđŒö<"&xsO$^Đe0B8P~Šģ“ øtŧĶy <ëŪQîvꇩԾīĢõ·ŪÚ@ŧyÎ1ČÆvHš2[ŒŧZæU`ŽãĘՕmĮÆzTĻvuÐVÕ6ŽÁĒāЇïų‡úZ'§ÂØÉĄ\|žXŨ*ķĢY Y Y Y` ôHô‡ïJ;JėJ<*>ÛņāĪá§ą86ÞŲÞ XĻ)ZaÕQR\õpøl]ÎŪBĮ[`#HuÅöqÎg…ŠnT՘.Fï~QcĀ`yŠũYJJŲjŧ(ÖŠj―&TM#ÏswŪeÁvm7Ý<‹jS‚Áõ%-ØyVPúū‚ÞšÛAÐM\Ë(€*Øęԕ:§Õ2’ë˜ų@ËŦM·n–bēZNAo}Ž RŠŦQDĘŊJUĩĒ4IÍ2T·+™—ęąõ!gōĶcƒ]MėIm…+ÛēĨLØ_ûô8Í íhhhhļ; Œ NÛX°h€UJČŨIö<*4i đÖkŒUm6Ð6î‚KÅãRwnuwUšnUáãԐęFŽy:Đ:’ŲF …ęģšo―_ [&_›QæxōJwĶGÜĻKДŲē ĢaUvŠAY ū‚Úš™jŲ―Ũ*cįī.'ßļY}RŧŦJŸõĒÚ[õŪâ7b9@ÆYM°›VxĒ,ÞŦ:ÕS`ĖÛëގffff‰-PåĘ8ũE-ö‚[ĪlÆŌt Ģ:mœuŲšŽœc•6æBLHô îÉŪqJš…’ŨĒž˜„Ŋ‚ģņ· ŨmčýÂ:Ū]îũžJ,ŊäïĨjtdd8 J` ĐTĪ’rj‡ę.ũĐęŠeÄN“qōÆ‹îÔŽ—ŠĘ ōōßŊ`ąóŒB_…7ĀÂĢt*&Y~Ōrđ>’ œ”áuŠKĻŅšUI w}ĻÛJÝ·‚€EHW š.Cl‡-ÆĨāóYĮ•y0ó]­[”5ïã§$Ú]õo‡ÃđĢFáۘŒ2EŦ4ÕĘ ^ō3ó^lá.õoGģ@ģ@ģ@ģĀÄœ6ĨB" .o„}uu‚<Þ{D•Ō >^Ũ˜ŧÁģnCĄ  ņų§Ūôę2K―ĐXUBĪU€€[VĖá9Įę2ĩÔÝU˜ęSˆÖߌ…ōå+˜ŨHž_7Šp—‰Þ›r(Ŧ Ú@ÔByŋú.TÛgu°ÎY›āÖé6€y—ã0nQ@Ģ+Ũ4ē16ŋ―Fá8—Ӂ—Ó뉀Œ™ęB™ ]YÁØŠ6œB:UeûļË ŽŲĄÐŚ|ą3ũđ0ƒõ]éŽ(ÔŅ< nÂqLĖū–ËqYŪÆÍ{XėŦ-tkĮÕÍN_‰Â%ív4 4 4 4 LlJūŧđÖÕąCÚT'ė ÕĒŪPo`ŽPŽęŅhŌDÓŌ ;Ū@ ĘžĀ.…Į›ĻĐėp>ŽLݑ4îĮóšų$A@Þw.dɘ&?"€Ð”Ņ€œŒS E`7 Ftȇ=gRŪ‹#ˆ?ŨĢÍJ;QiĀ:úއģÔ-j€’áe]*p šr Š:Úrhfm§JåPŽōcÄĒ MōQmbkZđUÐsŊ ãRŌLj―IĩĢnî!ņĖųšžŪŅĀN_qš 0ŽíëļŽ%`ėT{?oÛŅ,Ð,Ð,Ð,p,`‹>îaÃOl :ā@užž FÔĢŋmė73øĮF_Eéø_ ĘyU.VYāxĻ.X)āœE]ŸūöY:I ЈĒĶ|ķŠRJÁõ”$ĻĖOũĪîā:-(mj:šQŪ‰&Øæ!p„ˆŒ0]ӈzķĖŠ8(æÔÝĮ>yļ@ÜŅ―|ú(›å;ZĀōŒ CXWĮ- ōþž&/3XÝômãäÎÅ*ÜTé˜: ߌbŦĖÍĪ\ü~ ‚Ŋškí€xLŽâĻnFîĀÍÆŸFŨ]LlīmÜܕķūįmž3FÉóBpÕ―ÜT `üeÆY]ĻäTČļš99løMØī’ =i'‰+Bģs!›‡Ð1]AĄęr…œLÏøH š–ĘR…§zĀÅk·ŽÐÄ@’t<gÞ'ÝëÍ^Ŧ‹Ÿ3õ…2 :ļ ##mUÏĢ áIËîóQcžŠĘĨL–'Ķ,Ųå„ōÔž|ˆĀĶÅXÆĻGíC} &2čIH[áœÕ‘Ļ·å°<švB#üŧgĸęýuĸL]ŧ5ļ)u xYD1ÍLýĄþĒT)Žõé:™CŲųØ2ęŦjĨ<æÕuzŽēcšŋÍÍÍÍX`Bp&4ð6ÖōŦ›ī/ô„–ŪCváĘX0ôc šQYy/Ĩ2^ģąķĄ˜M‹ĸTnuWŠ<FŊIe”—―s- *t'āĒbtŒNx;>hzuî% ũᘎ@f^ĢĀLo8yÝg…JÆœŊ 2R-{Ī>X+cĐäkÞv(jĪmUÞĩœpÂÉN…åõyĄéØą ø|ĢuŌEŪ‘üáp|ŨŨc™<†čp_°þŸÍŋ)ģŸ…0ösņžy›§oōŽõĨNd‘kÖWÛ'X)ũĩššššÆģ€~ÐqՉ:eĻŠ°É}uMG2]3Ն> “v:S4€Ē€rÁ1N•™Ôíŧ ÕW- ŧ v‚lcS™.uÓiQNÔiސp‰z„šĶ3@ NÜąÂ{ûóšųĻ 6p =ā#džO0ŠŠâš RÜ1ÉŽ$ø.éa;ë,؃ģFRu?Žęķ\•ðâ^WJýč`XŊĄ š‘1`Mýœ§ĐË{Bv DdūĶ—ÄQå\ģŠðDâ’v€Ėuįpúž!šĐ<>ûXã7Kî‘PKŠ þĄœSpϒHĀčT§―8Ši'€éŽPÄv4 4 4 4 Ü ˆĐqėÎĻRŠ2sę7âą§#@8‚T’Äč žqœN$äT:6Ö.Ðđ: šVB˜ĸ„iĻž‡dqA(ÝĸŌīVā.֝™€n æ›< #’Â.h pļĖ5@‘ú•jī,.cĢc{Ũ|ÖN‚ÓažĩfžB†ũ.Ō  ܁uĀŽč@ËnžfĶŦO‚ˆ0‡cŊ ’JýȍÂļ„u‹Z&_§öxÞtüP~ӍÅmˆeéĮŽsæ?UŦvwLWw./s s^厚5}ĢnĩĢŠ3jŧvKïÕ§ÚŋÍÍÍÍãY`Bpzƒ ēŪCnĄĶ"ržo”Ÿ:·°Žá ĮņØīy ĨE3ÞSuFÞö"@ŲüZ Đ‚üŊŸā–1ũ Ā0ėŠ94ö*"U”HŧsevPÂ―é §ĘÔi#*ËÅ[7°vģšgŧ…âuI #bM74(Ų(›<O*.~WīĘÔ$ÜŎV +—ïđOŨŽJ𹉭9QąÜoĪąðŠĒã^Į]ę’qUî~ŠE―Ņ.XÁgƒüĐŧŦ™– ļžŸĮįŒĪÅøļ_u'ũįĶĒŠI+TíÖ`ųš*ģSžTjgEPûų’YķĢY Y Y Y` ŒëŠĩ^6ōYSÕqJ@Ũ-”ÁCĢëŽ(dÕø @…DQbu,2;™h ­·Ûr™ŪĮ$܍<`äKP”iømÜÍĖFŸĸ›ë­Ž8·(KîJq/S6]Ū–G åðP$pÅ „ŠA9ŪÎ#p„dōP#ÔÏŦŽũFÝIFþ7ÝEņ[ði#“uģ 3ÁŽ]ÍWÕũ,ÏõĢÐûQÖ!ŽéØi .ï}ŠEŸÁ đGØŧMší`^ ėē#`ūtVޟā·ĶÁ‹š>ŋÚŅ,Ð,Ð,Ð,0ūƧ LhP.F•‹ ·*f”`]–IÅ(Ėlļi“åQ ™q<d˞)*@";•pŊŠPĻũdžĒ,7aÖQD4üQ[\ÏÎ+ŪŪc0ó6M#ðō^Ā7,ĒM—ē€ŌŚép°+Į2ōvũÎ}Ŧzí;’ūŨëģ™VÃïļ•)§Ũëøh·6ˆČ ÖA "=n<éđ&-ÉV;b(į‡ęž­ ؅pĮr=eĪæŠDÁoYÄ5nĮÄC[xŊķēŽvRoŪ›ĶųŠč}ã?ėąŒēđý7Ũό2é-hGģ@ģ@ģ@ģĀÄŨUëã6ŅqŨŌûZWhæ"ĒRĻ[RÅČØšĘÉŨýˉr5ˆ•Ļbʔ jx]ŽÎŸÔõ*|ēڎ€$ņNY d••‘Š4ïĀ EÅ ƒ@€–ę‚ļ2›iYļptÆãæ ŽģŦ{2Ó7[Ô ũĻRÚ"|Ĩ―ðĶ āŠš$1#`b‚K™ëō~šŽR>:‚Ėņ_AëÂÖÕ{„™į|mīė0ųˆeëïa`”ĘÏE2Ķ"Üg' (UŊõS1fZ éđđu< Ė‚Iq{Îi+ݰĐ/'ýüšũÂÓũŠL åî+Ą/ŲĩĢY Y Y Y`b @ŒņÛÓDŋōBũb…(6æ6ö” 2uÔOoVržOÅdĢŪ"ŠciŽïU§ĒMÔ§‘ĩ<'*T…Y…†Ï#DânåuuûŌčĮ;ķ4pęGÜÂĀĨ‹Š­SL į„fuo’ũ Ŋš–ĘÔĐ-ÕMl=„™J3ó2đf ”āQ• Ŧä­*ü”CWķîOëdýŠâ3ßTãžÅåM‡ÂōŠ>íTxÔđĨ>KĩyāÚa°äŦMīģŊų(ÖōzŸ !zËŅŲÎũĐ/ķęķĢčaĪ9ĻĘ-c JÝīA;šššš&ķĀ„āīq T.ŠĀ–ÆœŨJĢÛZŲ`{> T!#\mā]Ø@`ĀīÏQ­^ĒāR6öiĖIW€čVtĄōĻRŌlœNÚqļ:!‚LBÄi2"˒gĘH:óäšðøļ?ŧš  ģŠâ&%}Ÿũ0ōvÕk ØŊŠË”ōZfŸĩîŪ{Ŧ2TsKĘaÝ|`‘ï0Ŧ YĄéóü›4ī•ũf ”:E‰ō\\āĶÝģĨeē>^ÜõsåUÕÞųLLËτ+üčŠÎ―Īeųýø—ô)ųãÆM­ÛŽfff‰-0ĄŦV Eđ j·SõØxë[YšÆ]—Īô˜nSáÁ挂ĒÓEŠ"L ­sĀÆojËÅG3.d}v€E„ˆāŒ’ĪąÏRwš\…FōЋ˜VåķbÏëÕ;@"Ÿ(ĶŽÃĒÉÛA–ó`Šc ’ąFĘĢÂՕëaPUžŲU~x^hzĻJûĐ­ė\xh3U\,ęÜÕUŅrï2ęÃ―ŠáUũ’§ų9iŦ.W…kËΕ+ø,Ģ…ÕîĩģáõІĢ`đfÅĢv†Ŋéځ°nƒ”Ygœš;ó9ųv4 4 4 4 Œk § ûÐ7eĶĶaU•ÅÍ(؝îIƒU Rež0@2˜Ep>Æôž7sy_Õc˜4ÞÁũ ™ė‚b&QžĐ΍ôÎ:OąŠP`žîWyFI‘ŽwT“%ũ…*OČ UóąŒ§d—Ž€uāš1ŅÁœ7ëāᘭK'‡þŅí-jŦPå‘ĪëoXL>@”úþ ­yÄÍ ĩT}ÂLõ,s?å°ÎT-+UĨĻšŊŪÚæÎéþĪ_ŽPčĐcąąŨŽęëįÂOŠåg†-Ė#ę˜åĸ,}­jîkĸ4 4 4 4 üa tøøÃW9ëŠ@Ë PÉøęQåĨZäV6Ė]{…\ŲĮ†Ûó*T! ÄQMzūĮĢļymģuįÂî\Žïë8ĨÛØÛЛĸĪŌæœïMËq:ŠÁ!č*ō–3ƒäéģ? č-jXĶ‘ķ–e™™sū։ī›ጚG5ķčDI!a,D}Nļđ§éf#nŌtŠD;.áy]īSŒž%K;X·ąAąe2Ÿt8ø­šô0ĀH]ĐŠĩL.ý§•3ÅDāRfT§ĶÕÏg—ÅÛ­ā‹œk~&–ŅĶ!Ŧ°ó‘āĨäŌþihhhÏ‚S…Ī4EXd•P(ĀĪU]€d4ËVÔņO˜”čQafDŽüyÉģŽËE#Oó,ā‹Ō|*ŦN‰ @A§ûUU&HUHŌÂ|ýOÕę €ą|\ dš iE=Z€^4íJîÓ}Đšs5ĄåĻĮ•{]‡ ĪÚ5Ï!ŌÕZë›@Ķä˝ÔCHQžŠĶSF‚t·ō,ïGí$ðFĩ'ðė|üX‘ŊΜb 2W"ß’ÚÆOŽ|âVŅR.]ŠBNŨķÉ4!ÓâĮqdÕtM•Šû™ŧ+Žâ§Ú];k'Wm­ãŸæÓŽffff‰-08uũÕhT  ŦęĐ.#7Jc홮-k^4ūFžĒžlÜm膊*F€!SK€Â îĩQŨ=UFZŽ_&z xŸĀQy ĢqŦ‹˜2é†6}“H°gŪĶðãœŦÕ2UUW/é —æ3ÝÝ8AĨŠã$@VY XHššƒĢĖēT` Ū0W*GÆsUj<ČbÓÕ:)·Ū\T7eĒJ”SЛķ`šÔÜ<)CĘĖ5ӐŠÂ”Iëp/oË Ï' aŧaYÁO…ÓĐČØ*eąą;ŸC­ųSUk‚°đyiK?OģÜōÚtÛŅ,Ð,Ð,Ð,0ū&gUS.ŌnDčJ`â~šrą}4žÕåˆRĢņ7ą@ēį~īwuÄø(JÓՆ–cs‹ó5csü›9ĄŦ–ó‹r8€­{žW°B‹tĢJđæžEĮaUt2OH œåäŸ5o)ŋēŠ/3}CE'ä( ÐĩuãŽV*5Ÿt..ÍŠâęœOÅYČo!dP”Ô<ūŨ-Šu —äjRP’–ØóšķÃŅĐe•́CQŌžķŪ}$;ęfß*iā'ŽĩÄ#]ʅX·xÆ/ÉĮtų•{MX0šūe­ŪjT/ų[ÆļgIÏeýŒt1ûl;ššššÆ·@•Rw{O Xq\rʔš`kæZ6ÝĶϓžw%™u#( ‡Tá(ãô §~ ZQģ.fÐ? ģōï…ŠÏ >AzPä•POC\ÂV8ļšó-§ŅąŠ/ß[Ęs–0Iũ†ß)§ŪÜ|Ė‹‚GEš*Ï]\Č"u#ĮUeWĸdęĖ;MJŽņNĢ`ĸ%ē˜ú:fÛ?Ų(\RÅØÔq ûiŧ„ꏏ{ģ`åRIšĒzÞNË uę`0ęØ~€eN$-åĩâšūĶe1oęOŽØĶBŌÏÃCWŊę—ĮøūZŅĻ]Ā܎ffff‰-0ak™čË(8rT’Ðī‘~Š9fīi{Ĩ‡.ThÝŦ^Wá@C :Í$°eÏ{s%4=0’ÏęūTÁņ6īą7!Ģz믉ų +ĮüjÚ>O5)ŊP­cĨŨ:qN%) ―GHE ’‘ĸyŋ‰Ļ4$1­#ïu[FÞFžĨœ+™bb°ûvZV!ë횉uØžôŪxī’üUč/ŠýŦÞíĄ ^riÂt0ŌYė$Îa}ĢÉĮrZw•j\Â―|Ŧŧ6äO9t‹ëēöó0/ëoÔąulGģ@ģ@ģ@ģĀĘœīŋļXYúŽF:S.hīãĘ4FmęęäĮÆÚ)šT :ÉüO\ķ^ģONãlTkIšQˆB”†Üû34âĶdBQ0čęD­ ņŽD Ž;ð ÓQIŒŽÉrĀ*Ë ŠĄlÎĩT Œļ]Óä^5p–ģ‘tvzņ,Ïø.< 9Sž(`ĘžB{—ŒŌäĮd…WÆZRāDY]ÖΆåÐl§#ãīĀŌtU’Žïjï‘ŅaęPÝČ! yÓē̌đ:~ŠMĩĢųz―ģq7/3Ũ-!叛˜Ï˅<‘NųĪ“€mtWŨû9ŲŽffffq-0Ŧķ>+Ļü‰û•FÖCå&\„Š ēĄW XdݞSÓT)u Tę5z€­Š/Ð8äc Ž{SFą)–øé‘WyŊ*Ūš‰™ëķÖĻÜĪCÚÂB :ZĮy‡-§āV ēĖÔCØJ-oðŲš^ۊķÎy„NQĨŠC;Þ# UĒ]ý;ÅįxĄŊųq3iÓĄā^ËÜ)Fí8žtĪÖuë―ÚŠšo fr,īŠwÁ–đēØĨO—ģVLzJ“Âûžv1o; Ýû,ĀÐSĪ ŌėÜcýƖ z;íhhhh˜Č€SĩSú UZI'ÚøÃš­4āŽÖŲqGU  qä}Æ!‡JUČÆ Ļ„+@\ïwfžƒŸÛ} =a'„nÔ#0‚đ/c~ž· UI%‰€W)‡`ĐŦü@ pBŊĒB’|ŽCāĖ{ËkĀ'tk°pmĻŋ 4õå·Āōaį!`ĩ“ũąĢ―vîÆÞŦ-=ú ĀâčŪÛ91UЊž'j$2V=vËŪ›X š—i \§đāūĢžĩŧ6JP‘Į8-Äj>Rĸ^9VsŌ-đf{dĸ6ýķĢY`uZ`pŌð *ū|Žĸ)b DAód,R7ĄŠÍĘģž @c(ø…ĩąŨ-iÃŊb‹”ô:ĀŠ6ëÜKU#—‰ëipœøŒXhyKZœčâ(Â2"–Đ* ēĐóý; Ē<Dt!ũ8^8‰:X/#Ą`§5Cį8 X#€Ý4yZĮ(KęĮkËŊ „ŋýßt|Ūv"LÏyšØ'åŠc–^ÓT3ķ°žYĩ‡g‡‡—æuōBS°ûc@Uz’ čânM%ÝÂŽŽ;{.ęŨ 8Ĩ‹‹8+‘ŊŸ‰@ÓīŠíîŦóð{ątxļÜyĮmPņđĩĢYāŊ`A‚Þ†ųöõéĨiGģĀęąĀāԝ‡Š!"V•Ē;TSÁ§ž”U]9(Džn̟ Ā•ČZžU…ÂŦŒcŽ\^ áá{ûSG!ƒÅĻŦF\Ę"ëˆg…ļđŊĻĀjU•9Þiđ’x•`&mEC.4ãî2x§FĒ ―IÔϚŒ  ÖĐÃHš@â!rdŅz: Š4ÕxÖåĨL)uōšĩĢāóŽËšŊųÁ-Šáâö*K§öP^ŲiÐŜõeÜn^§@@‡ņÔõŠŌĪs"ĖyLũ@û$°ÉĻåt0T™ÜŊō^Æ~ĐÚm’Ŧ#U•Šât'ÕįˆSpH# 'HäÕxX_Ó]cäÓĀđMےú#,0ÄßÅ@ĸ‚üýýĩ[›ÆĩĀ„āĖ8$0€ īđQ@‚҆ßyˆ*FŸ ˜2uj™1mzûEKšęæfÕ―;-ĘģīäQ<Š:AēíöۗCŸöŒrÞy?)gœz*_vT›Ï­DÝéšåƒal‚]ô`ֹ떃~j€ųéOĮIøBđ“`č\·}<ārvÂķĶþvQ…DīōœðŌ]ký\‹Ũh`ã14D’CCSˆxUÁ:ŦÛSõK:œUÍM‚Ú„v1}m#DT–ÕMŠŧ•Œę˜nŊcBŊXĩ8ƞŸÎI͜UŌ0ŌV°Å=Í3*ENpoípĻø+$0å‡Ąąģ•ĨOG‡ûcː›JĒ.ɧĒ(K—.ĨÃ!čWïav™"CėΰzģļOĨ–ï8ßŋæžï|,z>üķĢY`uZ`Bpv ĢK’،Ō Ŧ―„ƒ ōŧĪėļÓÎåȗ]vß}ÚöūōÓóÏ+zï{Ëeŋļ `ðÍåG˜đžk…cou™9°ŲfsĘ1/{yųÄq/§Ÿ|D!~lÐ[TY…e―͖į=ĸųeÚÔ)åļ}Ø&ōr”ÉÍķĨLĶūąĖ[`§Bôá% MĩoLčõgá#4ÍŧĄĪIj2ĘQ•vņlĀj}ĢīŦā6ga—Wx؆Ôs öáöš`A—Šã[Uš !n„*^AØ-(ïÃÃDÄŠÃ…·ŪŨ1  Þ—ąyLóŌΎsŠ`uĮŠ–ýÄLÛĘdA ^ĶÓģUŠ―Žïę>,‹Į­·ÞZnūųæēdɒjŊ՝Ņ}$―)SĶ” 6Ø Ėž=;Ÿĸ}ĪXčbøwXŋ‡Ŧĸûý€6ėžō‚ӝOdƒãe6Æīŋ4Æ4ð4Ø#,v`ĢžãNŧ”OžðŲ2gΜrúi§Ņ°Ŋ,Ûo?·LŸąF`18mjŲz›mãj=ïĮ?*Ó§MK‘ÓN6á™éÓgDõTí§:ÁÕđdīLåū=öÞ§\|áųåÖ[nMzHÐ2ĖúŠuųžŒĢB= Éí·Û!i_°X ÞqTÏÏÝaG™Q."-ëĢÛųÁswHš—\tATŊęW öĄrõ\ė―>§+ØņO]žĪŠČ ĘŽ‹›ÔëNÕņUWnōæĩ‚đŠtZÕ`V9"ýŠpë˜ĶvËô ékZ€ąÕ`―ÆIƊŠ%]̃­ŧ@ā:œ…ģ‡Ÿ›Ÿ•ŸËôY&áĐdwڎõ0}EōlÆĐý―:íī`Á‚ríĩŨöTzûęĖãū”–ciÖUïÁúëŊŸÏäūTūdYøæøYųVé{Ë‚ÓÆt™BĀq<•Ķ*ghČģĩųÔ§=―Ė™3§|ö„O—·ŋí-€e Ė˜>―Üzû­eãM6-o{Į;ĘŪŧý]€szëąĮ–Ë.―Ī<ų)‡–7ūų_⚾zþüēpáĒ4ė*Â'ōäōŌc^VfÓÝuŨå Ÿĸ\9ņģ'Å Ë%ü―áF*o~Ë[ËN;ïuwÎÎ.o;öMåAÚĪžņØ·”-ķÜ*ðļøĒ ˇ?ôÁōėį>·ėģÏ~Qw·ß~[yóÞPÎ9įŽ€OЊℎ`\Ž€PØēä'Á” =pŊŪh•ąËVᅱ/uqÕĒĀ$þ 9Uqo “PUŦÓjŒĖ­î[•bę\gg\Æö[Č:öŌ…njYĸóĸnq ]°“ŒŪĩžÜ_į°ôÄþ·Nū°~Nåéï§”īVįŨŽš‰ïškAmžĐįęĖâ>––ŸŊ; mīQ^ßĮŠø,GþqīĢY`5Z`BpÚ !Ā‹@dŠOÅ"Hmė·ÚjŦ(ŠSO=™(Ę;iØ'Á;Ó@ŋH>æĀĮ–/~á󙀸ó(wÜą |č}ï-ŊÓąe™k”O|Ųfŧm $Y#ŲtģÍŧŋ•—õĒrԋ_Z^óOŊ/]|QųáYį°>.Á.€ČFJĻæ^óOŊ+>ð1å Ŋ*n üëÛßUŪž7/.Øýķ9õ”SĘO?Š;m ”ðӞþĖrÉÏ.._ûęW˖[mY~BÕu)Ø·ŧ§Iė9cĢoãŠX›d~ĻfQÕōŸó4þívTk˜đļ­d!þčg_SÔí0ãŧü"mƒŠƒäPA $™úÓÏģYW]ۖĮŸeFCQÝį>_ƒąøŽĖˆ4F âũPĸ”(ðåė\rɗU‹xÖÆ$€ĨĘBßŽŅ―qô9 ›>PëšŌĨ­žÍ@ LNĄĪPąß­2.˜ĻNŸãpƒŒ5N# Čû–,Yšf[W mĨįöÝwŋ2þüōîwūƒë‹Qžŧgt=Ɓ6ÛtÓōĨ/~ąžûío+ÝuŨō0g6[lđezėŠÐCPžëo0›ąĖĐeóÍ·,įžu`$ĀĖFĘ<Ö_ƒēcŽŽÓíģũÞ4\Õ]šõÖ۔s~pN>Ö­ķÞ7íåÄ?ÃÔúeņĒEeà 7,[nąE9ņ3Ÿ)wĒTŒ.fŊÂnŠÚ,āÞSŲYre&4Ū"ĖTy0ûiâBõœé8ĨKU7éTŽ\]ĻŪÄÂĻAĮ4]VÕéØĪëôúކsjIq IÏ;^jPeō―Ę;Š“ņUÝ­•Í6ڐÐt(ŋŅĀ"Ŧ‚åLšÚH˜đúP{u ߍ―šu âšé–ÛŌišŋT;ûyŪ·ÞzųÎÝßë›Jþ üc[”žëß@Y[ĸ6,08ëī•• ō*ƀ”~„\đbRYxį‚ēāŽÛÓ`l‚Rt>Ē_TÍ$ĒYãé8œQžšātĘFŨP/&`D…æœ?—„Kä+°ĻcrĨLÃå{ŲĨŋ(įýä§åúëŪ­å2<“ƒÆĘ`§gčÞÂô??ĸđrÞOÏ+ĸõųÏSŠSB$@IDATÆŧʑ/~IyÅ+_UsÐAåEÏ?ž<ëO+/~ÉKË!OyjyĖc*/~Ņå{ßýNęgų…”A46~4ÕC•æ˜fU’,‹Ū$ŸĀDšm·tŸîlAŊa\Üa 7wœ―ÓÆÖmÃ$ĨÞQМPáZO•'tŽÝdĒęÐĒZF•$}LŲâūMųųhq Œ™kÂBÖeĸ„ŋÏUuŒRüÜŦV]‡u›>c&_›Ýüž䨿Zk­•ÎÍęīeKëO·_CŋåíhX=˜œķđÂS7Ą.E`ßDhՔĀ:ũÜ–Į>îĘsŸ{Xđå͛ǿT”\p~™?o>A۔=ˆķ]°āŽēíķۖŦŪž’qËŧĶđ;Ė%pį!eũ=ö,kŊ―v pëm·°wÝygųØŋ$îÎ h~uà ™ŠW°zāÛļĸĒ67EÁžyÆåžĸ•šAÜū[lą%W—WūėÆZßYķĸþqŸ‹}Û[Ž-_|qųĮŨþSŲwĸ‡g§“ÝvÛĢ|õŋŋ\nļá—(A'š#Ā·Ōý@yėÜŪLÕ&§A$ÏMĘbãĐûZ@ŲÁĻ‹˃ztėSęģ\Ėõ_+KÁŒĒĪCą‚…âëT•ú‡^Ģg§d‡wSQđŌ%‰j­.d"z-—c­”ĢŠKî!·hŦë ó™ŲÓúŽŧ ~ā-Œ}ÝđĢĩįę:tSęš2ŸŦŸmĘķš2ļĶÓ)LëyŊë}Ðü°H·ØI囨ŽfÕf ĀYöïĸVŪšęŠōĐOÕũÕo|ģ\ýõeņâÅDØN/W\v@ŸÉĩŊóĪLc°Îģž…dYüSLS˜ŽâœĖðýå}øpųČG?ZnüՍeíuÖ.ï{ÏŧË,zĸGĒ,očN8唓íoœtrđíÖےßÕW_]Ng ô°ÃŸ_yō“Ë%—\\~yÃõe€ 'ĪZķî6ŒŠæî(đĶ;åwfŠ9öésŠh•·*ĩÚŌEęę@"Ō(eŨļuüTEŪjöG5í4;*ŨŽŒ‡Û·ŲĄŅ\ˆëÖûŌÕ65ļ–ĢŠ}čÏáÔįÍú9öSN?KŪïkĘÞõ§Ö·Ÿ2Nu:cĐËÉŦšŧĸô4ۓÍŠ&­ĪÝâ{8Ŋ‘ßËŪsó§ĶŨžkЀÓá2Ô% ī_8ýūå*P]…,ŽÎ{ĢO-\XÞûη—SOúVŲeŨŋ‹:ýîß.ŨšÅ/–”§=åēĸ#ũā)ÜsýõŨ&°å=Ģ>TŪϘ–ŠÖÏŽF%ۀčM j—Ō_ Ôū|e“ËŽƒåüëï(ŨÜ~%ĨņJ;šþōÐóqûLYsVū—üÝķoã_þsļŋåØ8îö{4ƒčÓ#?Ž|ó_+3ˆx5šV ĶjąĄķNcIkÉÛ^cOËI#ž Eä‚ãqmęBÄYč•˜ŋŧ•jlė]*Ū6ø\Pd:‡îP]‰ÕMĖk!ĒâŠsëø ãNĐÐUiĀKĒúQMQX7pE ^+܀œ[5c|DŸ2>e4-ÄUŠĘN™đ) pAHzčžÖ-JBœc >ōÏb\ŦSGÜÂŦn#–hYōįĸĻF!šĐ=œęjđĻ—P Ņ,ĸ™Ŋ6ÐÖ}ôœ-o  ;@Ēiy.KRūe(Sƒ~ļ5îŲ”Ó2cÁîy]ŧ>ŊŠĩN‹ Úzîa‡—ũ|āCéqK·“ŧęŠųe*Š~ΜÍzîŪþþoÓ^FnļsŽ\ôËárõmĢe1ßÏ·ĢYāŊaÛ§élæ>gÁēãƒĶ”Ö$6€ŋ+Ï·ãeYsÅWŌžŪdXoãŽ?Õ(NUŠ·TW ų ÓhpÓŌĻg|Œ†3*ØųmĮÆßš‰IōÏ:ĖÓqÛŲkô—]7Z6[{°,Íčꟕn{ļYāOĩ€ßéiƒ“ĘšzAĶņŨĘũÓïi;šþ LNįŠ–l€mĖ}Ŋrsbŋī@r McãŸÆšđXðĘßŪĀ3ĻÂņ^`fôkČx Øā›,ôT|q}Ųļ,M!Ũ;Īaį9áe>·Øčŧ>Žũð`/XÉņAkĘi>ĶŦšM™ˆ{dŠŽ…•ÉUĨöë?%Á&v2ÅĪ$q+øUŧq‰’ĶAR_EkŅS?TĻÂËį;Ũ.™ +íc9Ė;Ņŋä]ËčŸ6ķâ‚iSl`ęz$%]§ 8æI9H+î[Ōōģðu·J‘[‡ĐËëTËdúæ·0ACÎĩ$ÖLũÏĶ&ĩčŽ!ƓÖ_cRYo†‹TˆwŨÚïfŋĪüëâÏ þ-øĶÍŦÁ€ģ‚Â|2·Ķ ­U[&šųã5A·pá]QPMĩĨÛUPļ ģŪAïsÎã8ƒĩ2™Ũ6čՍčsœå―ĘēSĒ™2áÜMLZ |![eáHX†ž乆ŦšōŲDáŠŪČ[5(L) ÐaĖð}ęœĮü…Q/§v RĮŅ€ŪBuČ2ĢŌĨË]ëKԞōÔ6ŠNŠ`GĀg„ĩ|fyÄĐ=ô<ęî+ĩ*Ŧã_+ƒ1ÚŅ,p_°@ý+ū/”Ī•áþ` ĀYĢgue  (K݆aād{*8 RZÎBé=îņŽ[ûPøÓW.biŧœsv^RĄIƒí*$·ÆŪ$ũšŪnYĮD75/Į,Uī*ŊŠzkðŒFWyft]šĖJ”į—Õ2ŦpEEuĨW·09ĸëō œyFwŪ@Đp"JTW/Ę' tuFRlUŪũZ.a†pNÝÄD?iųNe- xēBėų+iŲ9P=Ší€čöšÎx/é h!éų@ščRĩĢá{Ø_ÆX§pĄWEzDSNĄ™Ž…é;ÍóŧÖgEyö&å?Õ}īÆju[īĨŨ,Ð,p_°Āā4К5WĒ,†žS=ĨáķĄ§–Doxó›Ës{^&Û8ŧÆ {NųÞũūWĶēĢĮē#Q98H^o9ļĐCe˜Õ†–ĢøĶđð;ž.ˆ0Äë)Œ=.YšĨĪ:[^v`Ūį‡?úąō†Ũ―–Å~\ͰrOrļ.ŽFX@aŌ$!‹Âe9;!-@„—ĀpÏKcp‘Wēčn2mp‘A0.ąŨ ęū]Š"Žŧv* yĸrīûЁ,ĸóĨ/”Í7ßēô„'u:­œüÍo”ó/ø)ŪāqŨF-:!…―č`Ô"JYŧŠŽí€øSįpŽä{Á‡Â•ŋ@Öĸ́D.ĒeE+p *Š.a!œN Pô0-Ąíyï1A;Ķ%|UΞ§ģ!ԓĄķĢY Y Y Yān-08ëÜAÛTĮÖ ÞąáMĪ-ðÔ―iÔį#ņČ4þúĀûËį>}B™đ&SWgĪĄųŦĸ1‹ ļÔތ3Ęŋ°ZÏ.ŧėV^õęŨ”ï~į;åQĸũåđÏ{~9æĨ/.—2ßō]ï{nTd‡äũŋï=eÞUóĘN}h܌ÎĮ\ŠJÝøA›–}üøēívÛąŦÉŲåCĸþŅręi§”>ĸ°ŠēāÁŽYk—g?ëŲeuÖ)7ąē‹+ņ–ëéĘģkÕņ•CžðåŌË~^>ōĮ•G<ō‘”ãįŽ‚ôžōŒg=Ŧ<åā'–M7Þ4‹18§t{ ú™N( 8°žóÝïaUĒkč<,NšŊyÕ+˗ĸë ãT ŋŨ퀒MБëˆCIÜ+`čĪ]1rĀTö :l› "Ļ6d­Qž ÆĒóâs‰Ā%9Ÿå”·Ó`\ķu 4ĄŋvxTåŠa;ABr!úŽíâ­ ØŦŠ―ÛïIŧÐ,Ð,Ð,Ð,ÐģĀ„C[ĢvÍSĄi#­BĒyÏ8ā,VčŲ`ÍPLĢŲ‹pæš33^7epJÆ1u… Žoþŋo”ýöޓÅÎ+Ïfóį]Uþų ĸ”­ÂæĖ™SD·ÜxS9ü°g——ųÂļdGXp}=ũ.ß=ãôrúЧD9―ýmĸRŽ~ŧïąGŲ‹Ýĸû+_)ozÃëËYĻØŲ…e§‡î’ņRA0†ûÔņBÉqĖKŽ*ïxÛÛRíQāōōųÐ?—é.ŧíVöØkß@ó#ĸöáōøĮ=ķûÆ7dOŅ'<ņ`ÔktlZQžðļƒĘ{ÞõöōăFiN-ųð‡ĘŧÞþÖŽÅú΃Én/ÞŊÏX(ęŨq[Ë#°<į1WtæžbI€w\՟QȎÄäÜc­H4ãÉĪïupšįðŅēæĐûÕĀ%ÝÁ‰Ķõ/QĘáŪâ[šį:ø&jŲÛÚŅ,Ð,Ð,Ð,0Ū&PœĻĄ‰"šNƒŸÅ hym€U1Š)Uh_œÄøæÔ€*:ŠÉ5WUMŽ―}ýk_+—]rIų;ÖĪõ9wÍøßŊ}#éŧŠ.ßGp@yÍk_WælūyqL]–k­ĩf`―…(îļýv•ŋƒ­ÁfĪb.‘ũÜÁæé&ÂÓ(Cv&!*ŨB:Îw‹Ðŧ"ŠŨã"\―?ųáĢęÞôæcY.p“U@sÛyW_[æÍ›ĪÍ^vVōđïâþŅđgÁþ2{ÝŲĐĮŧÞó^†―“ĩu]MČq[Į`ĩŪíDá 0Tz]?ˆz ϧc"TY•w “Švs<īę96;‰ßYükޛi=„ ÏPšī}áüWŸ­cš>Õč_ÝÆ‰†ÆNz„ąĩ#īíÛjŨĀZķĢY Y Y Y`< LÎ:Ķi(Í k Ú@Û ÛØO&(FŨßĒŧ•+ŪžĒ<ėá/<æÜŊßÎ)ëŽËÖJÅĐ!<ũĄM{`ÁïëŊŋ> Ŋ/ĄŅž‚rŧųæ›Ę[ĸõ_Ëތ!ūâåĮ”kX?öŋūüߟ (8&'Ʉ‘‡ŧĐx|ã_/'žðéÜᘿ—_–`ĖaŒÔōÉ:ũSļy8Þg(Œ*.õđ{lēÉfŒÞ:CæH]†kžäm―ģ―þÖĨD š7ēĸį%tTŸ‚^UšÝÜĘÍ7þŠ,d!{Þ•ŲįUŒ Jr “Ãrvŧ­čįî§ģÁ­ <…ŽŠ4@I%kŊę0Ïōz (e: 2Y]]ļ–ËÃōh3ËŽ›WHÖf IZU—ræō|;šššš&ķĀ„āīąMƒNë%öh„UŒīĮÔ‘ąĸũĩŊfĮ‘Ã_pDŲaĮâ"]cæĖlՕQi.Į]CöQztyéŅĮŸeüō“Ÿøãs&{îĩWyü㟘hW-Œ:€―ðEGáĒݧœĖš·7Þxc9ũĻÛr Á Øå°gđ~-@ä!ãVO.(`ÞéxE;Ä{Áč!œÎĸņó—ŋęÕeó-·,ûėŧ_"ƒO;õԌ…аÝBĖųžš\ŋs晎‹û°rå9ûŽģØCt‹r!ëãščü Ÿýkï~-.dƒ”T―šF Š`@TŽ*xÚ­ŌΊ7?jđë{ė0ã$äcF…ō_‚ĩpÏJÉŅ1dž{ ÔýŦÝCÏ@YpW/‚€ķl’Z·Ū?íhhhh˜ØビÖÛ]xÖÆh2Ũ2ŠFŲkN#ųŅđ?(/}ņQååŊxEŲ|‹-ĢJ/`/ĖáĨÃÚüŽœÆøäÍįļųģcĄoeęŠ.Ũ]vÝ­lCpÏžŦیŦö ĸųyßĶ úÞwŋ[þý#Nú‚ãË_üOĶĪĖ-ž;7ŠÕâĸĩũĒĢŽ"BöĀ@î‡įž7ĶÔąĖîķrÆ·OĮm:8Z†3N?-Zëķ\„Ú=óŒo—_üâērų——Wžėķ{m–wckß_ĖæŨSč(X‡Ë RĐéÖ<ņ3Ÿ”ĸĻÚ'rHÜĮ§œ|õ ÐõŦ_EƂŲ&ŽŪéëļĪæĒũðZ°kWWKŠŠī·`wE-ōÛ―8Ĩnoí íąðV=zNŨ­@4-ÏũY/Ž=ïģþÎBéÄļä{€rÔ2ÔqԜļ—ĸąėÝÏ―œÕ}*yíßýüąëėåïvÜ―:ûúŧÍũĶ&\äýČ#/ĸû?_ Āę$ý:ÖæŸð*$ GEĻ’[à iûËëoœ:ÝN†ÓļϘ1žŪëøœøFmuxí5óø]Ąš&ۀÍD­ÞrËÍėëđ8ŠpÆ3€1ꈆÃĐ-·Þz ïĮʒEKŲčzynXģCˍļG§á2…š šY‰Ēe‘q•ÕTÆ>ýƒrK-]ĨSPē–ĄŪ%Û ū!ä―ö:ëfŒu[ĢMenĶÁvĶO›NäŦÅ ýīÜŲÅÅð“uœÖąË™kŪ™ČߌYėœIYˆ›ŧen) ĩQD‘S·:˜u Ģ<*NÝđ.ĒÐ5^ïÆGm"Ví‘J™TÏÚÉ-Í:­eí\ėBÖĢN…ÞŒÍ.(Ï|ÎsˇĸíßYýiaŪûÏŧČûŠĮyáũdŅĒEųūtõįöûÍ%ĸV ’sœ―ëčLT9ŋ~nÚËN`ū=ô―Ū­ô.­ÁpßÛv4 üŪüŧû -ōîø˜›ŽņjÃOãín―@ģŨąóýtÕä Ũ_ŸëkLŸ`úežŽ*ĩčģ|ŋË ĘÓáÆ_ݐsîūĄ[ $óTQģBœŋØíLrýuŨ ÂÄqHĮýŪ™?/c{6LĮ#måI”{ʔŠķ4NJŨU€\įÖqÏ!ęT]”Îo„ˆ0gņĒ%4TW' g*å^ÎĒ ŠŋYkÏĘ̉u}Ö1ÃI(įÛʝw,ČęEƒ”`ĐVU—ÞéôjĮX%õā§Ū4ĘkĄ'4ÝŽ.ĢgđŽ{ĘÏ5!ŧœy—Q‹ÄÄúŽ*ÓÄMÛđ˜cų™Ð! ›tœūǚÔ>YđČúSūnĄéýPɐ;î―ÃēÚđõÖ[Ó 38ėäö3ģSâtĄõčli‰; BpAr?ãz%ų"Sųƒé n“JJwĶé˜F͆P>Aá*>BJéZTkhE…HŦėL韚ÆĘ:Xuݟš[c:”H}…s—KúÅe čOul‘âÅvYČ))ĀßĘÚëqŌŦïĪü+)_‚€°›ö°>ė°ĨŨŨÅρųXïY]Ɠú€Ļeäđ@ˆ{/ĘÍŲÆmÖuk^– ˆv‹čkģ#ųLĻË'ÞÛĮ:*.ÁąšëïX8æŧ—mÝsmkw~līïÉaĮî†n<'jØŦęÜï†xTŒ+øëŋQï{đ þÚĶØÞØ!ėó{{>XÕĶāô{Ķ}ÛŅ,poY`‚Ö’†…c#nãĀßrX›'ø@ˆ/ķÜŦÛ§s HØļØ8ÛX/įĮÃÆŧŠV@čŠÐeöTYąØx;õEWîPddĢXw9qĐŧ^ڜK9(‹0r Ę Vĸņp:† š‹īûĮ7eŠ QËåý™ßé*<Ô#*ĩ]Ģ^ģáĒšq/ûÞz}š2R.;Q‘Ž%:™ŧkÔ°e”ėšTxõšupĮë"óuŽrTw,…pŲ<§žhdóķS`Ā5xĢ)Ũˆsi9ï5§§|”KĨË­…áÔ|.ýĀ_•ęóĶ[P?3wmŅ6ðe [ÝŨđWãÝKGĄy•€eŨn―2 }ëð[ũŽĪ.wÜyWšąV™Æũæ§ĸ[ ý7―üųņyŨÏkŲč’rį]‹ËĖYë°čðÂē`ņēx#úý ĸ@ŋyJøųcĮðž4ėÞįýšïœ;{Q֕žÖXÚâÏ·‡6^ZnY°ĻĖ\{BŨĪWËaÂGœŽļIú=Yrį­eņ ĶŽÍšQîžõæēb`ēÖ ރL…§ā4{rĸjĐDKägõÓļ‡_f ĸ‹ōBMUĨf   Îß\—yŸ\c͌3ÆÝHƒ“5QųãÐĨČÍŽ&TᕠœQĐNĢš‚Teiz“hø7ßbŦōú~s9ø§ķųC€‹ķČš~UĒĩYuÉšĀÐ8'T,Ã`·@;uPYåYęāĘ<*{ī% Ó­[ÚFĘë–;“žikMŨttĮš0„Š.‹Ļs/rø,õå҈iĘÄÓQĒĶašƒäĢk{MæĐ>^Á KÓCõąĖæ ŽÝ1ft˜ąYÎzÝņF"ÓY!Ģ(|ëŦŌĶ~fzLĮĸ(t€imüüŽڛw*Ü:Õ%oîÅīŦ žGuŧãšōÍ/|š|üļãĘqĮū\zãŌÔų7ŸÏũbøķrî·ūVæĸjQūKŋy}žŨ‚XEĸ‡;u+ÞXNþęWĘyóïä{Q;4Kođū|ëŋ]nZžžÜņŦ‹ËŨŋ}NYīÜõ…ĸP*ŋ}Îēþ)Į=yÎïņŌÛYūų•/”/~ų+Ž`õ_å§~ŊĖŋéN{†Jķŋ~ÆÏbņuåë'^nf:ĩßŧ{vč‰âo‰ïÞ:ėĀÝvÝųåËĸóírËb=VÚxRų內•Óŋ}IūŊÕ~úÏnŠýĸPŋ{ÎïŨ=ędüîƒí}ģĀa ĸĒüŌÛČLîđŠøĢņYWĻcgK—,.Ï;âå[§žVN9ýĖrÆũÏ.Įúģå)O& KŨ* Ëš*0ŠÆ€ÁØ Ãý·, ŋĘldéhÏÅZpO=Ļžâ•Ŋdqƒ'DĨĨą§Wï­ęV*ų‡įë b ŒÓ7Ä‚Š<Yė‚oü.ä1āŠķ,ËjËý,E’uu9ŋĻK`ĨkŨĐ.‚ŌÅÐí<φWOĸČS&ŌĩÉkžŨ6þļóŠËúĐh…Ž ÐEâ~âú(ķĻUƒ™Róœį ë}Šr;*aaïėĢ›šxdÐԉēŋó:UęBŸ‚Ĩ^‚Ôi9ŦÜāļuUĀ+Ü<›4l @klŦG`2ŨĸGõ8Ôąōŧm —–ï}óĪråĒeoĶÍYw*uaQl•ÓųpOØtðZhÛ1<QĨŦŪûýëōŠógíīøŲûųÍûáYåŽKo‰ÝQėޕĐŊoYđnÞĨåG?üI9ũÜ ĘŠdƒžœŽŌęËïÓ2>ãQ>c”čž›čũÝAäîlïýĨéuË6ēpA™wÍ­eĘĖĩËŽ5§—›.ûQų§>_Îŋö.:[vŽø.RŋgþaÚņĖð ß í‚IrÎŋ%;…9įw^ŧ`ûQ6]ðoÞïœvą%-HWūĪß{Îk+–ÞQÎþö)åšKąy ~ëîõ·ęýōŸUÎûņŲåÂknÁķäĨŽX:ėũTOyynîáÏÝŲēoX]˜ļĩdøŅeâ:w%XHlckxëŊŋ~ŲlÎ֌=§ÜÄÜJ—ÃûkÐn0{ýō‰ãþ#ŪĀ‘áŅēÓÎŧÄÍxÉÏ.Jc?HÛģ@û•W\nĮbęįýčGüąT7Ģ†ĻÂqŊĄēîąm·{pđöúëĘĩóæ—ŲĖÛÜrŦ­2­äęŦæŅ  uŧYyЃ6Β~·ÞĖ# †?ĪÄĩ9Å(XŨĒu9ūđ;<ĪLĢ ó.ŋžÜ…{g 0vÞm›D0þâRïYƒ{•wÞÎT”Kú`Y{ÖŽēõvۗsÏ>‹čÛuHsã(śXĀaõ˜Nð7˜ÃcņÂEåįLÉąãąû~{ãFšĢ\~ée‰þû;ėäĶ6DđÄÜwb ĖųÝY§–Ĩ‹Ų-†`Ëq+ã7WÏŋŠFĻŋŽđöZĖÝŠ\EŲUnīQųŲD!oĩÕÖQĸ—^r1ʛ°ėïđÉĀjx…AGØĻЎïЈø3ŋy~Ķ+ī0pš•ÎՔ ķ);ĖÝŪėðāíē{ŒÍé͗Ÿ_~tņUeåôŲ@uïēvíO΃ƒÃūÜ<-í~zYéûĸ흀UÕĩ†ŨÜéC›a€ĄÃĀЛ€ŒŠ ĻHL4Š&ÆÄnôŲ“˜hLyƞĒ11‰I|–ØbŊQĢ"v††*„ĄÃÓûûŋuæqî  >Á―áÎ―įž}vųÏđëßkíĩŨn‘gÃG`]Účų­,ķYÓÞąÅk6[FN8 ·―Ŧ`ĸ+ę—YéÚū6fôþÖ&CWS–ÕÛÖÛâó­MĮķmý›ģbĪęĐđoĩŸÄ`ŠžB7"oÝCŋÖÏ~üTŧCœāÕ$f*›9íäėîęóXËÏMģ’/ ē'î{ÔĶŋ2Ü|ļUŊ[hŊOŸeĨąVĘ3ÚzvhmE…"ŪlÝÖëÐg?ÛhK)ß`oū9ÝÖŨZũAĢlĸ~ýw΀Åį‘ëŠlÎ[ÓlþĘÍÖĶû ;xDmŋģŠõKííw?°Ēō:Ëh[`;lķéoϰđŦ‹ô[SˆĖá=}4€ĢļĘEKmæĘrËËÍē9oÎķQíĄ S;Yôœcŋ ÏL“pUÃýiĻ$ž>šÔ8}t.ĄęąžbL!hCād͏aîc Ų=öč#vņųįÚiß9Ų#ĸœ}ÎđÖ2ŦĨČ&Ũþ|ÛívÏ}ũÛŧÛþü?·[ûí­G~/ŧņ·7Û5ŨÝ óŌ#vĮ]ģ[oŧMį:xg]Ð ˜$&ŸøM{ōÏI›―˞yöyß-Ĩ\^tW_{―ýéÖŋZ‘w’īĶ]~…ýõö;œ Ý+í‚ —|ĸ‡öčOŲm·ßi?ųīĮĄ%ÞėÝũh}Ļv]Ų(ÏØŅ žpũ=ũ{p†|‘ßcO=mđývŧĸÁGė†_Ýč{k>ÜþüŨÛėž /ē^zŲ.žøû‹úsõ5Ũ)NmķĩМ_ßx“ýüĘŦėĶ›oW_w―åķmgĮø ŧëž{íG?ūÂŌå |üäío:îŲ#Ÿ:ųß*Œ(ëĸ|ÁWÜÝ2‘î—øōöv?ōø“šþ§’ë1ÛOƒßÜø[ûÞĨ—ÚcęÏåę7sČāņā#y?ïųûCęį`Ũ.™ÓdSLȌė]k—ĪGĻŌýÄäüY°'‚-NžqBøÏũ…uha{ķ·-s^°ŋ=8ÅVoÜfõ"ųâUÚó/Nģ–]ō-―x…=ûę\í ý6ô˜XŅŠyöÔS3,Ŧso‹mųÐ^~cš•ÉĒðŊ)ÚK,ĩÜŪųÖ!§ĩAšŊ^™-[ëþ(ŽĢ(L$œåÍšþ#›·"Å&(6q^UĐ-ž7ߊ€5f'†ÏĸŲþϜŋ_ŧ+ŋäæáÕP,Ģß%š0ą”6Ýlh_yðVnąŌĒeöÜóSŽŽuËĐYcÏ?õŠ•KSŸ-|cQ‰åũ)°6YV[Yjï<ĸĪ­(M·ž]ZØ[/Oĩ%ëŲēVŦaždÆóöÆŽBËïÝŲ>zïu{m^‘%•,ĩ§ŸyFæô:ëÞĢ›eg0w™jiuАæXN+9ëĻmqLpþYĄbJûö•Cöģ”-ģlá:,4ę‹ŨÔ@œŠ’ßGüšDïqŽhiHO&‰­“ęËĪ―0ɋĩ‰Õ2!ō0K:ŧ0.Ú"íLÚÚ[o―eD€éú1ēOįņ“'ÛM7þÆ~ýŦ_ڄ ŠI{ŲÕŊzŨ˜8Ņžyæöîŧïøķ^§Ÿq–Ŋ›ô‚„ûĀƒíZPš4%‚"“öâKūį„ÞxíU0`€õíŨÏĩžC;Ė* ÁVirn'ÕoüáGÚåWüĞQxū]ú}_gyõõ7øfÛŽxÔWī4ÏÆrĻ{}þK‘.ŋâ§6dčPŧė‡—Ú―ũüÍN?ãL;Z1q‘•D(šD†ĻįŸÏ=g…ŦVŅŽzôėa=zõēýũe3՗ųÂaÐāÁ"õ6Z#|Lķs=qy1=-\ļĀņĪ0}l—öÄĢYŸūýlōä|›ĩŦŪūÖšũėißŋäb›ōâ‹v‘ˆúÄožä&îÞ―{ÛЧžaŦ W9~GsŒĢíÝî―įnowŸ>}í§?ŋŌÝôëeâÄ|Æ`Ó5/ĄęDǘ„ĢųNuîSNÜÓDÂ/~ŪFëoûp”}uüþVģaŽýíþGm^áF-wZnŦķj‘ötÅ"°rîB+‘™–TŊįtCá[Ŋį1ĐJfqõkýúZ§šĘÞú°Ø †j‡ŽnÃīNír-Oīí6ČF.Ã &É’…cåžũ­ĒU†Ėŋ)ԈjlųŠ%ķa+õ@ü(NäÝņsÃĩ äïĮÎïôWÓÎe$:v|úQŦMÝcIāĶÔÛęÅ* äVKOŌ\Ēb—JÛ[ĢyÅtí7›TĶøÏåÉÖą}[‹UŪķ™ ‹tT·\KÆVŊÞ ŋīMžššMöÁžB+Ŋϔ™_Ķóm[lÅBݓŠĩtĶގ8f’í7t?ĩĸëÐū‹ĩËÎī†Xß^í$ˆSŽmuåŦlæĒMōūkcēŽTŦģ>X =oÅĖ`ÄsĒ~€–›ã›Ā5ŽÉîāŧŦũ#ä4iŠåÁÅ< Q2·Æč1‹öĨz 9§Į]Ï:?ÔdũäA&ĩ1ą‹ $qÐÁiÞ1 ŽĩnÝŧû‰_Æŋþõ]ý‹ĸķŊûu'Õ^"Ÿ)S^Œę$ÂPvÛķvß}ũØĩ"’·ĶM·NyÉTČŧĮyØũ=úŦ_yöũ-Äîŧũ^+Ōú7öÅ؈úIýeîcý ^ŠÔŋ`þ|íúžomvß=wŲQ“&Ųôi27+ęÏð#œœŽeËwųÐCČdÜÍūō•ĢÔč;ļ`{Ø82d°M{óMŸcÄ ˜õWþė ]Óݎœ4Ņĩ!Ėß=õÂëõkjG~~ūcÛĨc'[šxą&$āäãņ}8ûû?xÛöÓlųšŽ~ö.číKl]ˆ 'Čž{2JÓä~áČË艁ũúÓNņįĒ9õÐÎ^Ãūl=ú °~Čfž&s^O9^éū*øĄu,b=†·· 60§/h+zFc"†d ēōz ĩ^9y–•T%ķzÉ@Áĩ%”ņēæđŒĩIsqõ%EÖēMw[8[{ŽĶæXlÍJ[ūfĢČŠ­']ŨĻ.Չ€ß.؛švU°“?jcÜÄŲrúQaâAĨ˜U“jŠlÅ:ÍҧvķdÝũšúTY;’­e‹>6ūË~–ĢįŪÛȃ­Eŧå2óŋkĸpĩ;ū‡ÏoēIAFVwĖDëÔEkēåAL_Ģ9dųddhú!ӆo9yÝ­jåÕĐᗾÃ=ž+vįĐ­c‡"aÜ@æīKՊŲslcąöĀÍYeÓæhtË Û°ržnę=@΀ąãåõFŪO”våųJTN8H„@bâԏĄāĪĐŅ%›"ŧÆĒ96œ]HãhÁNļ9„svvŽ 2Ä5ˆó.įq^)V”ŋßwŸ"8,’āæÖpzÁŧķΗučį'MrIîõˆdŨõŧŌ8a劏|?Î/iŨ•^"ķuëÖŲïÏôđŧČ[6r$Ąþ:ąäĸŌ‹/X‘扛û€BųÝøÛßŲŨ?A‘ŒšøvbĨj#Ëč;Â{ƍvįíwØû3gšg1‚iÃÆ ^GKiÔÓ5ßđlŲ2;ęĻIN’‹-Ô\är+HԗŊ?Ųڊ°ïWŋ;æuīĢū" Wïlĩķm›ž%*p’b^TâÁqSđ+Ôt[ŠŨ1ĸÃ6{î @6—Wâ&EQîm:trŊ`pAP DÅ~ W"Î\áiœĐčžļ°WÁĀĖĀË$mØ*lÖ{ó,UėÛēÆ6KŲËč”k;f[ÛÔ%VkiCšīī-Û"áĘģ9ķÉÓüré4ŦŪÏŌ Ī…•Vé|zž í‘l3gŋaģڎąXy‰evČW`íœģdķ-ŌÎ:·nĐį\xhąrÞVšÖÅ·—ËMÖó_WboOyÂޛĩÔš ĒX99‰Ļœ ? éAŅó]ēQ›Ŋ/–ĶXmKæÍķĨ2tė(ë™ĩŌZÏZb·ÔÛ ý:YIQąú[e˗ŽīšĖķÖ§Wg›7ĢØjbílPt[ZZaÃõ‘Vą{Âđ~;ĩąÐ+ŨVK[LÏf9)•ÂļÆ:ë·ŨBåO‘—ņaÃ:kę!Í šghÞ>æAQ6ådYNv–’ĩŠzŦÍ^īÜZ<Ў:ļŊÚ­ßđ+ÜųO[šl­uÔoíŸÄž-ÎJ!>O$&N V–Yø:L‘—ÏwJļ熉‹ÆëA1r„?čßøÖɊ+;Øîžãv‘Ór™zÖ8―öĘ+†iĩ}Į<]#âÕ-!??ßF ßß56Ęe{.ˆ‚„ ĶHĘ*Į™ÇŲÉ GZ,Į˜Õ……2o>j7ĸþ/įđgŸĩ•+Vøy~ŠÂMŧ\?gö,‘ö―ÖZ‹ð[I‹dMåŽYĸRļžÍvÚégØiš ,t3ïj™Ļ đG~ЖŦžN;)ŌŅ:ÕŅәŒĩ”xK xûž•Đ™ õôũß/­ĩÐą›ņÖ ;lÜxĢž§ÜIũŦĮ+ÂÜæ1z‰#90EžŋŅgpXŊA^ū,ÂŪXūĖ:wéjs—Ѓ$ð§ÅÅ[·o6Oŧĩ°Ą 8““m§Ęü―bųr{îOĐh "Ļ7JaÄ`BHéõųP ŠJ7Û|™™ãÎę6Ô> ĀZ+ČԄąĨ6cÎL›šKŸæ,ĮôēÎ= ŽĨīĐķi`RmÓß{ĮĶ,0ËîZ`í:vģ‘ŽķúéÓmÖ;Ó-9#Ûgũī‚‘#mqņŧ6{Ö|Ë9pīĩŒ1PŠ–éWNkÃúXŨ–„IÔ .%Ãú cE–ˆ„3e:ïŠ Øīhk―ŧ+•īŽĸoäxîR[ķąüž4‘Ú\[Ŧßhšæ3ŋzŌ(ë’CdŪ>vÔáuöęôŲ2ų/‘ƒX[;Ī{gŦ*Ųdģßĸ@„™jú%˓đ6oüŅVņڛöÆ+S4XÎēácÔĀŊĨõîŲMÚ}’us„•%―aïOEå&[‡üaÖct›tx•―:cŽMŸąÆŌģ Ž ß2xĪ―ũá"û ū…vh?yũFží-Zuĩ~Ãōĩ ›8hĀ’ÖݝoÛęË,­mūuŊoĢïÍreImĒ č>G$&N Ójiþ`K@ĢyâTĒßĻ;ßÔÖģžD ôE"˜+Ï:ûAD·ÝöŧöŠ_xøđŋüų6jÔ(ŧņæ›EĒ…rþÉģ?ýáöðũŧ&„WčÃO>iđŌĘVŪ\)âđO1c[9Lć}ýåWėÖ?ýÉÎ9į™h§Z[™m_{õ5Ņ̐`ZƒÆŋ$/ĄÍˆa+yë&Ēû5į‡FĘžčI'}KņgģėwÞķYïŋŊM>°ũ$dŲH{ŠĖžóæĖQ―õv‹6đūéw·ØÝũýÝ6Ęė‹ÃŌđgŸĨp|ríWÁ,í@KcĩīŽÔ^|þy;õīӅO―ðüsōīm)ō\kŊžô’M?Á>ų.[ūÔæˆÔŽŅŽ.ËE‚{m2WL ‰Hüj°"<ˆ­ŧlÉûÝÍ7Ų•r4šũþܜ›#Âŋðüó\› °cy ƒÖîM8âHŧėōÛЧŸŪ=K[IŦý‡oovđœ’$<öȃūî“VŠ>âõ$°ã… o<ÉĪŽðĢÆi#…'–ÖēzŒcAÞđĸ—lrĸQ‹)ĖÏu6Rƒī“jÍëåõaĮŒp2SmzFõĖfķ·?ÖtŨ4n=ŧõ}íøû:9Ũ˜&ÕŨÄlðØÃ`‚%A&5*ģCþ;Ķ@óøúnÜÄ~Ÿ-k ޙđ}Ma$ęNCGéũîĪæ\‡!3ŧ“9ų$õ8J JtÅ͗­:õ·cN ïtï…'Ë_đŋČwä—FÛōĨKíõW^v‚Äī–›ÛN‹ĻsgšĢgŦUwV†âãęŸGę‘ŲēUŦÖvčĄãŽwßūķR&Ú7_]fNE(Qðlī·ö"íÕŌ87hY &RČŽs—Îrâ9RQ^ēlÆ4­5à P„™ß+ßIlĢLļ%0Ų_íšGä9}sōqÞgÎeËÓķSŨÎ"š"ĮĪņÄ#ęOƒ’M!ú…ģå;ąŽ“ÓÎŽĨô6j>pņâÅ2§.Q?Ē@ôŧ.ĨÖæÎžëuƒ }žėŠŸÉ#ũĢö æL=&ŪÎAū[eB]ĸÁzwöá˜uœĖ2Ōfį0,[ēÔËĄOĖu.Öü/Ÿi;įįϛkjí)&rL‡ÄļĨsĨƒåŌĮJ­c]ŋn­ö}Ü­Šī́ëO19C| ĒāhZÓĐXÂôđiÞ§•Āģ1DĀ=įž~RDðiĩų“.—AŋúߜD>ōžœ8·!5Žē™ÂóÅsöE{ķG&œų4hÂT+nŅæ$ˆĩ„ĖËEQwäĻ#‚Üčĩĩ2­)f(Ă'LĮyĖFhˆjH—č:ÓĨĄiųy rŪ!!ðÝđGĮÔ9ģDĶ4&bŽ>hā@Ũ†ö“Û―wßí„C{kjīA‰BˆxPĶĪĪ‹Œ0OTAmŅ?æP!ú™ŪrЧVų9†T1/y;üXš’ú˜ĒϘ i+ųŠ ÄĮžø‚ód.ýŧdFđD<čķŦnŊKs;üÐŒāņ vŽŋÃ4>īƒhJ$Ô5i””õ!ÚBĖïÚ –Q2;/ŧĄ^Ÿ“V9esOt‰Cāô/~―ÂOáågkË8‚p3—ÜT}MĸšļĮE‚ĒÄó‚ķ !6Õ?ΓÍīĻĻČĩĻDe7U^Ēkũ–sMáëÏŋ~ģhˆĄėŅ†Ý˜ŠĐ/•AÎ3Įæ2Oëüg•Ļ7Ī]C `ķkx…܁OÄÄК!F–;(âŦkihh˜]]{”YķJAÄšĶkǐ ‰Ú'Ą I@ ‘°fOZÖ†Ķ Ét‰ų nÁMÞ]åu ÆIQ=>ũĻēðÅĄ%ŪņĨ‰D|‹2]K})eČŦÃĻæíķĀ9Ä5fQLĶ‘ó’ôEĩ“z fˆž†Ō.úađ“‘:YægÚä„ qCĻīQD‡f‡‰áFā{4ôČËUƒ™sŅčļ͑ō#í\EŠ">q"ã:ÚíĶL`Ô?wôYÄŽOŪĩëÞpNŒíļRGŒv)9îÔEÕé.dvô ‚ĶŪø"Þ8ŋ:ü Æ]5‘Ä6%Mō‰“ š)rpÁóPZ˜ˆŌAKÅyˆcL•ž’! sH&Úū"@Ћ4!FˆDĮlpíe!ņ!$iD―”< đūCce~Í.Œ&ëčO|>‚"Ąų‘ßũÕyi‹|vK&eH…úÏ ‚‚Ė˜ŧuSĩÚãMŌȍū0ŊIr‡!ÕÁwšØNĒÂ"*“BE{χĒĸŪĨ냛ŒUÄF9NhĘéú|/æYÝ-ÐĄMnÎÖõŒQčũ€Dĸđ/”–Xč Xš5€ÁŠũP—z9ÏýōŒœ ) E 1qJļc†ÄĈķiš‘0‡DÝģU$ÃüšF&WāHdĨČ!B&VÍĨAŒq₠þ^ŪęāØImKņÚ#d ÁBhmŌåM‹ ĮÁ†6ą4‰%ŲČčŦ Ę$Ą…r^īĒzu―ę„Ð (H•z0B„\‹S ŨÓˆ–vSVÔ~‘ŊŪwĒÓŧ“Ī2rs3&éˆ|#’ ŨJ•sk3Í:rðÐâNCā…F΃NŌnð§ LŠ \[VYnޅIuVÍtÍ2Ĩnp[ÚčÐyęGĖŨ>ĮĻ‹ dŸó‰:ą{MĘR@ 4Š@bâDØË,ęΈđVÁŅTœœ|4o ™IļĢYB8œG’F[‚l=?Ō]/'.―'‹˜ÜAGųT”ŸĢŽ8!đāWđäũđC uæ>!?ōAĒåDŨšF+â"h\áĪH›Č+o_ÎC8ĖŊ2_O—úqâ{_zĖ]ČK}†Ž ų81RŊŠExR! š68IŅ/ÂÄđŲXeā AAˆ "\LYéš*ˆQy1Sˆ›nõ†ØÉãä-ėŦčŋōĶëžPØR·đž”Õbõ-Ý―‰!QVy"~][YYგ8Ąõ‰ēÓÓ2D֑ĨĀo‚ū ) G 1qJæYEÖ"H7MĒĨ‰ œļÅ*ih–zÅŨ<ĶŠÎļ6éõŠ`˜ï„€X‘äýUõ Ũ2ŠÖÆ1xÐNHÕJ_°l&ō.Ö AÄWŲ iģįĨ ĀXÞ§IDATēFyuĨũ‰vŠėÕÅókĪírŒ—ē/‘ `ÃĀŒŅ }`"ŌCSF;'/íĄėeH^ĮJĮÚ J­ÔĀÅŊ‹LāIj Ąéč€/ĐąŦ[Þe) š@ 1qJļē@>&ŅtÖ16hVNJ‚?rp‰kā@‚;–&Í -F‚AÏ`U…æõ­ĖĩT™$1í"č!ČŠሀE 5îÝ#RÁT2ï‰B^*‹xĄN0Š0„V-߈–ÍD úĨĐy~‘ĶČ։CφVU]‘Œj„§!H)MÎ=īÂĶMéĖ—ōOä…6čŸi—ęӁũĄŽđHåÅÉ&šĢ™)ÎL8qqŠ1īKՍGkTVdžĨūNÕq†Ļđ[Ņ N‘ķ .”ÅüąkŌ"nÚ !BÎÜ–é U§H[ŽtÏT˜;MĄŅŌ^4Oĩ•Á f_ķwãģϧŠNæVC ĶHLœšYÎNî8ú™9=ˆ3%Dq0Õæë4õ=siõZx‰§&Þ·°B%TčęhOų>o˜Į‹óŦōŠpô#ČƒˆtT•;Ōˆ:iCd>E›‹G)MšVõĒ!bwâSy`Áƒ ‰Ï”Í=æƒīh•‰9˜@Þ? 0ƒMH€@@ Ð4‰Õ qˆ‹@‡ður“öų>‘ä•,ÐI‘/aĖ–dN0ĘƒÓ ÜÝCt:YTģĖÂŊŠøÜãT2͌€Ė;"蓕WTŽãˆ€ā4VL–”í8ę/N>hZ˜§BL·DˆĐ@úėæāDčDG{q„ŠuM Ē\ÏŊ~@ČąúˆŒðū­ōp"/7?ĢņAū*[}‚ \ģqaEĢÃs6UƒĘt XýĘŦųOՅũ+ÎK8î0J›]+W=1Úp” ō(Ö,ý0ļ7Ņ-X0gK_"ŌįūÐf_Ó*\"SvCߕW0zĸũ†ZÂ[@ 4Ž@bâÔu,ĘGëIeJÐûlš“Z&RæéĒ%&šÃ„ŽÐ~ U‘„é åļš%âp2Đ@€Qlֈ€1{JÂûõ”áN4N"ĖKjŨƒrÍ5ŠņðāEÓÄŅS0&ĮwtŅĐ\ŨâÜ|Ã<ĖKB.ī RcĐ ë2ŅĪčt> Ē—Y•žNÔī_íLđ"Tixh{„ÂZšÚÍķŠ ‰āŠÛ5mX™€ĘŦV=>(PŠ„•/ƒ)ŌæøōĖØãö%'īSć†ëš$óŠôW}e âÚ1Ä­|N–ĮôÁ óÐ pœb921C”š+ ƒ5ŠV+?wËųŅViIH€@@ ÄÄ) ąR5§ũū„XČ"öĪļ6%ÁîÚ\‚ߝw"!&ІąÐ=m!Ô"€‹ Mū'€:„ÉDËD"â þ-Î:p’6W:ŅAĶ ˆˆ/2íšŨŠLŠī‡Ā…;܈ ˜wÄ ŅEáûļ–Š~L™b4ęT‘ĩčÄ Š_q/šŊ° \‘(Ú$ƒČŊZý#v.s…ÔïóÁj››`L!T ÐÁN/ˆc°ŠōE!^―@Â9ŪĐW›ˆnD~îäN;ãĶl2ûÜąÞ]óÔýņ6 OČßqS~ĩĖ+K›g~”{‚kTqX‚ŒC Ä8e4šE‚Í)ōD„; š$Z(fOLŒÄƒEûDČCR8óļ†'a !°úÅ|‹lÆ\ĐŊœ(‡yKĘÄQŌ!õ@’hž„D[*­Ï=B* ũ5ŽŌŌ0IbŪ$&,eŌ4V>ri^”+3)­hvq3&a–lP'bßQ5CŽĨ."-ĖŪh€Ô ‘Aš―šęÉę\Twd6õPšũŋŽpЏZ„vŽ$ÎGóēQ!kŸwUæxųä…O1ĄWŦ^(8†yVE°,ˆfWŋąšŽëé?}Ī^ÞqĀÂÔ[Đ9Pú@™Õąß@oJø āōĩ‘sN:‘āËĄ‰TÄgN|ŪđIčB˜‰›%ŪŅJĀî+"€  7eĒņHU$/žĻ']kišĢ Â]ĪĀ\œ;)„‰VéëubäBßÉDNF&åb΄Ĩ!\7å2/ëdIDä‹S ŨKgslÂFÚ&ÅåÅ܉FGâ;ˆŠz]KS0‘âėŅavŌQÕUŽ%…ŽĻKõšæĐ6aę%ļųÁ‹å-ýĮŽyČR–sOĢHJž=ü &HlŠa ĄđémIBAŦBĢCKîJPCHQ t–Q0ÉīˆÁ!čģļWōMRÜF9šØ5G;$Ēcũ€Õy“dŪÅۖAXAķāvNî"IWåÕrōA Ū‰BĒʇ“Xâ<ö ~Ðþņþåú€@@ ikœš#+„9HΚ&•–‘&ÂyË;Īâs”s]‡đ6ņō"AdĪh.1ŌŅÂļ&2 3O‰Đ–ųBĐ·Jn6ÕqzĶ–‘Ļ.ęá_4_(áÖ§r!Šøō•HKđ5ÁŪýAęeGd,ŌÓöd,Ÿá<ZäÅ*ģÚėD(m“ūPŊ·I}ÆY'N֘X!\úiŌ™Ž;QķðĄjīXH߉JlčĶ_L―jmÔ%ŠWƒ }rŌãNX܍œĻ!?ę$ƒF)8sÅÛI°{(ƒ;Q '€[]čXQ.åaðQŽþ†#XãÔuöHrëMÖq’ôāį:Æ<‹Ðu-N8/Õ5M‘[Z‘0ubŽ•dũroįŽä8„ÁüĒk„:Ÿ‚iSŨÖJe‚ Ņ âäEY”]‹Ķ‰ÓŒī4Ũ<1vō]8€6Ē ;ÁĻhÐn&Ą’ßįlÕ<‚ļÎ:-ĐÁÔĩþ;áę:ĘcP@‚œÜŅIuAZ,1ČãĀîČ#­3Ōþ /õOýņ9\LÛŠ3šģUĸ…æpÚÁBt<įYūâ81ï*Ōen•E%ī’wS-ŨH+ HMGkįQ5―Q›•ēĪMĖ‰ŌŸÆí‹ŋËūŸgâ2Ė•–=lhBâDðB‚ÛJĘ]xųĶ\Ī€ô†Tęj#ėĒŽ!3>ŧÐnÐ!?H„9?…]N$ĨÝŪŅ1oÍSj †Î{Ų"Uæ+X’!­e"‘ŨĐĘPh@LĘuNŽīŌøwŅü ýŽSx‘UĩHÂMÃj+s€•‘đÖ H$UZZŠëæ0uėZŦLÖj}…HSýËxĖÛōęē†šD‘jäŲÓŋäŠhþ“žNŠ $ŽF Ņ{(—ž"Jæ4!h5[Ū6 CÎq=åųŊĀ Îđ†Ŧ{ÂqY™ÚŽ~Sģŧ,að‚ųÏ­e•Û;:ýX•””ÚķmÛĒūýŸģá ėĀČo6†ßӔ8™‡ÛoøŨqXŲžÖ"Žø|Ą„īŊk”„vģŸÞ™óƒP"Í+æ^žKîDŪqŪS‚ÄMĨ‘'Šk\)2@órrց|nU"ĄÎūžŽYŒFh€">L·Ô ą(mŋ–6ęZ™kÏĘ ™‘Ïį1ˆģ)mĢü8A9éˆČŅ2ÝsŨĩePCЉūđwŪĘwōW~Úá/įčŋČÐÉMØzrâCŧÄSMó,ëGåøĢü`ĩcũøO°%ád„e€öšF y+Q–ß“͕ķP?˜rO|ðĢ:J‹‹mčÐašŸ mōŦĢþįädÛüų lãÆM ߆·€@@ °w" <Āeåžô iÓĶMýŸꙙŌT"s%Ú)~Aü8þ]üøãÎû… 8ÏŧóĩwÜpŲĮū%*kįv$ĘÛT―‰ŪÝđžËJtíĮååŧņá8žv,kW덗ß^–˜ЊŠr€ÄÏóÉãáŽG!Ī€@@ °W#€Ō€â­ŽØýŪ$$ÎÝ/6\đŊ Āā)Ī€@@ °/!€…rORBSížŪÝ7ØÓlß@!ô" ühðßĮáS@  ęœp* ;#ˆsgDÂq@  ˆ38áT@ vF įΈ„ã€@@ $@ gpÂЀ@@ ėŒ@XŽē3"á8 اˆ/ĐڗŨ$ïjãųđŅû2.;?Čņ~ïiŸqîŒl8ö ’•ŠņüŅGŲæÍ›=ó>Ņą:A?[īha;vīžžžĸˆþĩSv?ŋeË+,,ī­[·zHŌóėŦĮÄĐíÐĄƒuéŌÅÓîn?qî.rṀ@@ās;þ,_ūÜãF3ÆÚīióđnïî6Ž~Ū^―Ú,Xādy6ķÛ$[ĄÍ5–,Yb:uē#FxXÕÝ­{oŧN!fmΜ9ŪeũėŲs·ĩí@œ{۝í š…;;ĄiŽ?ÞŌĩ‰ûūšØØĄ[·nuéŌĨNˆ'›O€ ę AƒöUHíWŧvílȐ!öÖ[oY=ÍŨԉāÔBá|@ °W"ĀNžv•4ëŦŠmųŌEķpáb[ĩķČ*kšŊđÞŠĘËlŦˆĐhKąE{í tõķč­7mæG[wåĒíysss­X;ÅįņퟨáC\ãlŲēåß6ïcÅķķháB[īhđmØ\b͆ĨŅâk­ŽļDÛ6ßF ÚĨmÛķĩōōōÝÖ6Đ,hœŧyČėMÄ5Ŋæ8ƒ@*ë?zÏ~yųöÜė–Ó*Í6­1ŧāÖÛėü‰ƒņĒižëš6Đn‹ÝzĩŪģÞZĪ–YހĢėŌKÎī^íZ4KH'%ÕÚģWþĀÞ8åėáîmšu͎ ĒýÍéįŽyvüžcYÛ?Ó/íâ;ã…íŨWßb‹ŦR,ĩĒÎŌ3:Ų/ūß&tÏhV”įĪ]šÕĘŦS,ŧM KŠYeŨžõc;äúÛėˆ^ÍÃh{ŧöāCsqJTE ÎDč„s€Ā>šgâ$ŌĐ\eŋ:ųX{đÕqvßÓ?ģ~đf3_}Ų’š·Ž6 ‰`Ēc{[ßģWs‹ėÁëI{ýĶԖÛkoOĩև\fŽĻķïžýCËî7ÂŪųöANšdå:öÞÕĨ>ũʖÁW}―ĘNŪąŒîIÖ#ÚfWÅj_ퟛ€ŪĢšõ2hšÛģoŸmęö?Þ4įŸvöäs­ĸŲŋģ~þMK.[kïM{ÏšdŌnuD ü7&Ōōé›ö-ŽÅ‰\ïęˆ%iā™ŋđĘnÎoŋh’ŪËķŊœþmëÖ6YmŊ‹0mĀ“KøŽ ““é[„{'ÕŦÕÉ>ĮQb§Ý ҌV{šâ5ïi9áú€@@ ðđC "Ĩhcx6‡oė…Ð-œýĒÝģĒĩýâ†+mxÏv–š‘m}‚з“3ÊđŊØĨ§L°ącē“ÎĸĐÍZWbõ"„ĻLģ ĸ+č;Ð>âk6h@KJKē’ĩ ėܓąą‡hG{™Í+,Ó>·1ÛļümŧāØIvĀAcíÄģ/ē•åÉWÔ%§ZíÖđvÝgÚoŸžmIąĶÛïßÃÆÍLÍÃEdW[f/―ðļ•>Õ~ųó3,ŊUše·Ï·#?ŅúĩMĩeĸzÉ.ųÖ8;D}ûöEĸmó6VŠoöčÕĸmŨ\•}ĸä/Ųðņ§Ûãģ6YÕĶ…öĮ§ą'Ūĸ‰õ mÁú"›ĸÚT[ąÍlÃŧÚŪđÅn―ör;`Ôp;ãę;lsmĖŠ7žg?žðũķžĪÖbõeöčįÚmoZjŽÖĶ?ņ'›üåƒmôŨΰGgę^Ô5zwžïX!šÔī›Ā1g…Ӂ€Āލ‚ē9ŊŌ’kÓ9ÏúČLZĢMÝq.ŠÔŦšNÚ`ų2ûÞų—Ûēî'ÛýÝc]KßīÓ~ðW+Š”VØPū>HÓJķ—žËÎýúIķŧîČzûųe7ÛšJb3îu§=Ņ<ƒĐvï– Ąõ€@’N€Zϙ(Œk­šR&TiĨU•VŦķä”jŧûWŋīšý&ÛQíIëéhW}ã+Ö1Ŋƒ]øŊڋįža‹6iCēeJÔüdJ]•›[ĩ’įæČ‰ķôŸ/؃Ïūcß—gSžļÃfÎ[o+ ‹íĘ ķaÅ{mVĶ}ĸš3lh·–V,ŽÕWZ}Ę6{ðŠÓ­eũĢíūŧ/ķöąJ‘UӚ$$€V՜D^’5ŪžO0ˆ8kŠęī„ĨĘI3V[)3i’ĨĶ'ÛĘYoØG]íÆŽÔÚČ\ŧð”Ģmę…oØŌâ“lŦLãßļė;eÜöÂŦíėõĪ ŦŠKģ<ÍeæĶvą^Ý:[RåYyÕîj(›Žã§ÚŨ_dl‘ kųW+-•ãPfßLYzEØÕš'2–'ĮjlæÔG­hUĄÝzÅų+Đīm%Ų:―·ÎŽs3nã}’FŊūïi įž"Ū>·4WģbŪ/+ŧ―m,\eŋ1Į,-Ý2ēŌ­ðíŨmÁŌBKo#ÓmYą­_ŋEsn2ģŪ+īŌT9Ę$IPï åÔÖÔÚ~‡nį_ô=Ûbw>1Åļã*{cmŠýāēKlt~LÛYjZĶeĶÛGZY“ģÚ‘XUˆ;Sæá­GŲ“vŨZimŠ›ƒwŽcg­pĮãæÞˆæâR#’ėÖ1Ï^}ņU{máKNM·ī”˜U”ląšĖK-Ýfë7nÓ #É6Ž&iЖŠųÆjM7ĶhðQŽÖ^]kĐ2…Ũ ãJ‘äÆMeŌŽEÞ2m3-ĩŋŌbĐđŦ)IWZ™NÔk.ģŪķÚĘĘÞ·M%uVķjž―ĸ~‰ĨĻð6íŧXjŦūvúĨ—Û 7ßdÏ=ýë’"͕2wļ}n.Nå gcȄï/ 8đīïwļýá‚gėĮ?―ØVÏüŠ ë”l/Î]mcŽJģV]†ŲãÛØ_~w­mž=Ā^xøM+øö­WŦ ÍoŠ å^$ōŦīįï―ÕRÞŋŨžZķ͎>ļĩÞ:ߊ–Ï·—ŸĖ–Xh%-^· ĮŸoįýŨpŧî†K­lö8ŦŨڎcŋuŠU—–[ö!§ÚÏ&dۙmWKÓúÉYĮYšÕˆH>ëÛ!m―.ÕF}šþōwíĖÓÎĩ‹ŋy˜ĩŠÛf įnīÉ?šÄ&ka·ČÄšæ>öėCoÛ Sj=dŌ­.+ģš*p‘FYYfe"Āšš$ëÔŊ·Íūč/vëķvĘĪ>V_^ęäiu1-MA›ĨuVUV*í―ÞŌsó­K‹bûÝ WYUØ4‘óŨŠŠ­ũaß°ŅÃÞą{ĸô€yPū•·ąÉįoyšÞs}ēiœ“/ŧėē+›Îr― j™öˆĻSPP !,GBžŅ]‹ĨŲ€1“ėāÞ9V\īŅķ–ÖÚĻ ĮÚÄÃF[›V­íË_kđ)ķiK•øõÓė‡'äÚäā~I D?Ā ōr-ģuž}ýäïÚГ°^CŽmzŠÕfåŲ7Î?Ë:dĪYŨ>6搉V›n•Ō°ÚvîeCöĩŪ= Ž Wū 9Þ5RZ[Ėzô*°ī$1JĒöë}\ĩj•õîÝŧQsd<Ýmßū}“ļHåģäėÐ “lT;9ņl-Įĩī>Cē1ûēqcĮZk+ģĒm56vōöƒãÆļ“T‡Ū―lā⁖Ó"ÝZīëfýķN9Y–›?Üzīmšôl}úôģ‚>ų–ÓÅúčg―šfË7Õš °ū}ó-ŦeŪ}yXy<ŨØðÉßą3N8ĘúöéeíUæÄqZVe‘m.Ŋąv äŒÕÍŌ°Ą6#/^l―zõ†ÝJI Aô™cvŦĨáĒ€@@ ° ”Iëyįwlâĉūā―y—ÆīF1ÍĩG4<„lĩœaŠe‚MŠĨXfzZīBˆnÏĘĘJØGúB$%bķĒĄ‚ïMĨú:;ækčŋĖÔ{”ĒïžíÂÁ“j5ðØ~åųiK•ČޓLđåĸÎd•ņïuēĶZdė@üsîóŸe‘CTÓũE4ÂĐĻĻȟ‡ĻâÝûˆsũp WŸsRSS-;;ÛæÏŸïæËÝ 3ũ9ïĒ7˜5kÖqj‰YËqc‰s`ēbÅ Ũ<ŧwïūË! +{oøžÝ`æÍ›į;Ī@ĪÍ!܏ëW0Õ~*áŧ€@@`ŊGÁHėVv!°ycæK:šŧôģ‰ū$Jmg·—ĢE6•Ö­[įä >‰4ÎÏ;.;ũģ)œÐķŲV,??ßÍę;_ßÜã@œÍE*ä öJâQcib{eĮvh4d‰†Í\gs„Įeo#ĮæôŊą<āNÍ\4VßSm"tÂđ€@@`ŊG€ų?„åūžv…ŅĖĀ„đß/ZÚœÃ&gcȄï}OBXî3`ėБ€Ë`ėÂĮæéõŧP`ȁ}@œûōÝ } O@œŸ8ĪĄĀ€@@ ؗÄđ/ßÝз€@@ øÄÄų‰C }@œûōÝ } OXaaaģÍ~âĩ‡€@@ °— @įĖiÓĶŲķmÛyî%7.43 >{ MļÎLîßŋĸ•DĘoÝšĩĩjÕĘ#ČöM 5€@@āó‰"ØëtęÔĐûøĒãŲSŧIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-updating-introduction.png0100777000000000000000000024160413761647206022744 0ustar00‰PNG  IHDRÎbðZŊrCKIDATxėVŲoTį·*å5Ę_žķQĢ<”Ļ…mœBX毯ÆûŠmlĖRlķīÆ6c°ÂĶ/ÄöxžÎxÖ;w™{įÎÝlÏӇŠJ’JmĨž™/>šđŸ|;Ŋ RŸÏ=įw–ûŧįHrŧ݋‹‹ĸ>ūüōKÚc:‘~D&Ŋūú C)øxĶÎīÕūÂSŌ‡fþ_Ÿ'Ý=öĘۜô&ŊRZŦ•šŌüN{<-}Ð~fõŸVøøÉóÏ?ĸâ‹/>ũÜs_/ãņãĮä$@ŋ%ôÍ7ߐ= €ĖÅ‚ö ,Õčâ8 ÂLĶņčŅ#ëĻ”aķąøSŅĢ?„>€Ģ>–ē6–ūŦŨ‡vŌē Į^tÚčƒßAŋ‚™ĸúØG‚}MýøÃéxÆõŸÖ—^zé…^HÓuýÁƒðÓŧīī'ãņøĀRð—xH O3‰ --z 6ÅtK5ÂÁfáiSG5―ˆ ŽúXĒ6úÐőđRČ2Ī―>ēe Bx–õĸjôąŸ*u}Ė)–aÉJqZÚXýþ žLaõú ‘Š&ÏŽ>ˆUęCšŪ§-,,ĖÍÍÍąxÜÐu‘ãŊ‡g5ÅbĀ„œx‰Į0 Q:§Ķi$jvtå6ĀøBĢĻ ŒDĒp"Ísk⁎čĮŲ,|K s_‚e$Ļ­æĒLzH$`ôYX\zļô`‘Īš_|ÏA}–ëĖĀĸ?ęƒYŒĸW}Åþ%‡KņØ­VKþ+ŧHN b,›š>ôš!bÐ!ģ0qðca"ļ–&ĸÏ1!BH+|qČ2,Ú˃v|īŒĨš?õA'ųĐëƒÎÔõA'ÔZZô™{}Rŋ_pŪF8Ÿ@āÐú`q‹>ˆ4= Č$ų„ōxÚŽĸõÆÃŊþüčëŋj*+$4Įõôôīķķ655ĩīī|ôŅGn·›”œÃëŸ=Ņ|8kĸ›oWŋ–Q·ņāĐJĮÄp"27Ŋ/ņ>" =MÓčt>Ēa)Ž XēEÂ2˜}ČBĀĘėHÖÝÜŨNŸYq9î;§<Š>—tœ{rØ1-ƒeŌ i?2îŠĻ:=6DaIh}Ā/ąÞI—_KVĢ5_ޜ…˜.ßëíėčžzŦŸ•Ø|‚ãÁ_dU‰ð#ƒƒũî}60<&EÁoýâP ēĖú`S‹>–ą“}õāŒÓ ÃâÓûƒ|, †"ņΑĄþþ{}ƒ žš HxL―}íōĩÁÍ vƒZTrU“·@ũOŽŧ|žNū#ÅīßúF€ũ™Đčƒ2æÚčCŊÚī>Đß/œ“æÐúāi!✨•ô#E}0—š<>iŠĒD“PUUI"ār}Õõ›uRÓЇÓĢZgÛÝ­›Žo|}ĒŋēdY&|Ļg0lkkëîîęrwûöíæææééi(Ej-a+ŠË3ģŧ>§Ēië` “yĮøÞWē2ũū9ėŌT 'šĀiöĻËĀGtœipĒaq"°Úh ŸŽD`ŅĮ\Į\ŲRßœvú(\ÃïŨmČŠv̰ j`QÆo3ęf•yCSðÉĄŒŠÏ‡'>ÉzũČ#ÁŨ„âЀ„āāŸđũųĪŽ€W?€47b ã]M9u­ŒĪāQPÍÐDÏņ}Eéé;ęÏ4îJOÏ*?80™ÓdGßļOœ3429ŒtÜ)ßē!·ŽzOUYõŅSnV1t ûEáíĒōīcðþļG7ôeņß߇$ÆFĢIýuc^mŊÎŦþðþ)Ū'A’NŠéŧÃ5 ŽÜĖܔžWūgOeiÝévŸ úō‘á ! aëņ˜ÜPđskŊŽ@ ã‘Iŋ+˜x!Ęų&û‡'Dň/Čgũ–üáōPŦÂĄ$°žKÉïĩŌþŊOŊIïTĀÕĩŋ_–{Ar +Óũ wa™ū2XŸū_ĨîŨFðĪE"I’ä$ĀŨ''.žüģŋŠýwĮ…^―üŊ΋_ŸŽŋĩæÕķŌRį#I!nÝšÕÞÞÎ0 þę‹ĒĸÉíęęË&[DÏ]nÜ^ŋæŪôũE_ðoýė}# m…-Ÿ­>ē yčA?9ĄZd`;bc LE$Āēæⷈ€-ú` Ö5†” @“Íú`/l‡ŽcĢ,2§wŪųéËéíwĶī……ĢgóÚWÞÜvĀ#ëaÖïtŒŽ:Æýސxĩ073!ƒgƒ!6äŸsNøBžfĻCįOo);106Åpb˜ Œ9 +Ā °.áPĀ Ir4Ė…–ųfɂd<V7”Ą?ŸYĸË-7&…ÅÅE-pŋ`íúŠú>äŠÛ‘YÓþYŌ‰ÚŠę­Ė/ ęą9CՐ'āóē;3éœtyÑĻĖ{ÎÖūSXsÜéaā{H|Ā9:<>=+@ŦˆÄ2– ÍLONûB\0ÝÎąąÉNn„ øƒÁ k|ŌāyŋĮĮ†Z‰œkÂ9::ęe€%Ŧ҈gj|Ä1Î,Edy0ĸ@wîî#Ìū0gĀ]füž'‚ÏĮžŽ †|nÐŌ9åæEy~>rzoq}Û YUü^? ŪhTųƒ!>ô:ԉ ÖTąįŌ‰‚ƒãþ°a<ģA–‹DYf&ĮGF>F„ _ Äóė„sl ū‘ąßú:9Đïú ŸŽšÛ°Þ/KYz‡ŅCß/:7…ûøŅč‡Ó`DøCÎ$Đ#ë]ŨkŊ<ÚđõÛĘĒėŦüķšäqnFtÃkíëŨú].Q’ŸĪtvvöõõy<†a8Ž …B^ŊwddäŌĨK~ŋŸ”!‘ũ~_ÓŧåJhŊÔp[9{CnėdßŦÚYÔļÅëó+C NEyžGNK31d~„7Į1č"Â2cÎ2§˜›N…ß+‚DéjæÁ°,9iÃFõ)|kíš Å ’&_oy[úÛģũÍĘŅŧ JƊr2ŠëšƒĒý$ŊüØ4q^ŋPZ\\ĩŧ8cûæâÚæ€ß}nÎ/Öm-Ŧ:ðГék? Y…‰ŽsLDqt7—;†ģ§ĩīĪ„d՞óó •ĪˆŽIÞæc9'ŊɊ EQŊޚ_{ģŧuÓúoïČmlŋŇ"Āú{ŠōŠn8ƒĄ@€ ņë>[™YX―·0?sË͌ ―SÂLïķŨŨl|csU}ŧÏ3ÕrĪ&ŋĻ`WÎŪó=C҈ÐqŠŠ xw~aé™OGŪÔïݕS‘“óÖ[;öļ&éáķ#ĩđY™9;ĘšnŽ}ü~å{W†YļvîøöĖÂōĒü–ÞAXýÏŪ5æäįV>ï‰IDĒQÏ―îÜēC7'‚L H|ĮŅüšÆŦQUáž#5ųŨ‡Į>Ž?PZZôÎķĖc—û5]:YWräâ %â=TđįâõŅĻĄÝýSmų‰ËĒînn(-,ĘÎĖØÝÐåõOĘÞžnÓķ‚ŠFW˜k9XvĒýN8Ė}üĮšßeï*ĖÍ+ĐûÜũAP!3|Ī”c–+-ĮrtMĶeÆÃ^‚hĪ„”2kLÉdzøšŌSŅÄAáäáĢÆĶ0'ČghĘëÞ{ÞgÏŲĩŨYw•Ë5ÉŋþŧũũýûÛĸųũ>W\Þđ>ŽŌg’$)ÄTÕävEY-Y6rĮÎŽˆáŋ~ē  UUĨ†aõz―îgƒ8 ž,Ë?§ôā‘^0ĻŋބtF™Õ+ðGgBAĄF #J‚(I@‘ú ­*Œ1x2 ^E’–ˆ!ÁƒĪÖh:E)ÔĻT‚§íf‰Qm0EņÔ(…HĨ‰fí.|ęĢÍ@ÚČp‡úĀ6‡Ÿ6ÅõÏ3ím_ŸĸîĘģgZ°,ĘũŒ›š_°2#éąÎ/ëūïäÄ)―–0Žy―Cũl֚ėũ· WԀļccĮN^”•>j 1âÁ)/­Z™‘8ąó|ýå.AeR‘ŽĘĀĸ\öj`]lžÔåQA hS°ŠŒŋ Ņó}:Ņcpū—3G?46:b|Ō’yOÞŊĘ"ŅĖč LWûgŧ‹‹Þý úĖh›ŪÎ.Éõęå­|RÚŌiŠ;Yq[dŨMė?dQãđÎ6bÁĘÂ5iÛ}sÝ-ÉūxÝŌņq=].NfXÆõEÓW†!–åŊšú@Œpû_ĮŽœŒyü™ÜôxwkmKëc L”TN―zîāŪâĒũķŸi퉛8Ūí|m{·rõËŠ!fhtøÃOÏ}iuÁs#ú_øķ—†eYhNXRvc$Š*V8†AÄÃ'LÏ+(ȜýÄ­ķooãþMŸ|ĸ˜I‹—Í 3â^Ų[Č­§6õ&.Zū~ÃKCPہēÓĀ—~üÎþāšõkÆ ā— ’ĒŌþ€ķߝû‡xmįÓķ!þϗĪ1š<ÓütiÚĨڏÚâsjĻNXQ  i‰§īĘi@$Ņ…þãúøTöÝŨ`w_V "Ã͈!  „b† aÃŅ―ą(:þ‹·xŸ€ę$åĢtŸúøÆš^$xES­<ˆIrŸ~ĒëŌ'ęŦPÓĘŋ^I– ;24.ŌÖ]VęčÅĄũFõc ų$Ūõ\UŅĶ·ö|~Zô302@Uļ€ yäŅ·Áyöģčž—IoÂ"d–ļ įNn~Ó˒ŒFTŒ Œũ(óĀzÄ˒“E§Š<Ī"Žtvó*hô Æ=7@~&ŌÆ2įæÉFDAxN24Ņž“—›5iĖ OŊ[g ņČCþXbÍ―N™ŒÕ€°ÂyÜYōp%{·Ÿ<Ý9˜Ux‰ĩčb‘].ÎĢ0‘ąąþHíŠnt{xĖDnadž0bAĒ›·Îœ73ärUᆭ'Î}ßÝu‹sđūq–nß[К#šŸ:! #”Ļ=ŨÔčĒ$›ÏųúoęĢ]‹Ūĸy}čĩĀŌwY ~,q\ čĮ…FCcҰ‘pÕʑ1—,6ÃĻ8―ÉDhô]_iĄcL&“EcžN§ĢŊ’9*8VüQõ“ý‚ýú››Bތ™ï"lũęIH•@@đ$ žč8}óøh#\ŠĐ 6'ÅÃ,ņ49Ņ@ëCŸ“‹V–|Ô*§–åÓú MNdÐ$„rįúíôP„­Đņž_ä˜`―ˆYî―\Ví|äų”īg&ę‘Ę0ŠĒē:Ø*ƒtŠāöxDIF0`Tîæ-·„…ÎöãŽúGÓԟāaĀŌŦBË%ˆ$€đ>mЄޑQũ]h9õÕĨ[HĮš:ÚęÏGņŨ)ĒĀõÜļ-bLęCķˆXVÆÞŦŪ]QVtˆņjáŊ,†"•nARü –P[D|ڋ…ŊĶÆĸ^/q Eðš“dÚėĮkŨ{8Ïå {Ýýî ĩ@Ėŧ8^„ÂxEC]Ä^5hØōõk'…KGĘ[ –␰QÍ\ąjõŦŊdŒŽēI"ųž%z…éYI‘DĖĢbÃØ #KöžåÂ~7ā›úēšģ|rÎ OŒŒNe°ŠĶ õë―~ĢģûZ{˅Ŧ{Ū}}žžuÂŽŽ”§G"'1*ÉÅyß2PxĖē˜AFK`0ūÞqŧKōÜ:ĸÝ5[LĪË Uįvqœ ˆa(ļĶĀß}ĸP˜–rįóEķ=ÅÓóEĖ'mZ*•hð9ÚŊ‡t]J!ĶĨøl‚ĐQ…wŪųĩúĀėĸŧ>0‡ĢĶĶĶķÏęęęĀ;kjJ7o:đ2ĸâŪ7ý~ßĮÎWÖ^·ĶķĒĒÖé<Ā(ÅétÂĸ9ŦŽŽ„ëččhkkƒYøí-Œ"!ĻvT}ðéĶĒýđG›6ŸšļũøŲmÅ%Ëķ|ļšēŠōü„ĐŪvôeŅ$4 St‚‡€îBģĢŧ2Č@=°ÄÐEÉļÏÚ=ú(ņIîĢßgGd-R[­-ا>^ ÚúT•f.(üøÄGÉû;wv4Wþ­895ŋēĄú•%s“æÍ]’žôĖė܂·+Žî°/|ųXuCɟ7ĶæĸĐĒŪŲqdĮ„…Ÿ”ÕÔߗüü,{îĘýeĮŨ/™;gþžÜœEI3ŸÏ[ŧußŧoĪl:álvðƒä„„”īt{röûûŨô=OŊ°ŧėģžJ秃°äī5ûVՕ—ĪÎx|EņþS§škJÞOIˆŸoÏĘÎLž˜üúG‡7.ÏZũöæoäÏ~nVjf֒ é…ï9ŦJó-ˆOīgf,ž•ŸĩqOŲĄísf§æü―ŪvC^æšwö467ė~3gނųéöyiKW–:ę+>ÉHYąûÓ--uë_Č(Üöhú79įōGÕDqĸ§Qذe‡ØðŠ"$1ŠōOfē!'ķ{ú1ýîžĀ†ü=üÆG]]uœŽ ĪTFåęzœŠ{šnēð(P;―?6ž?ņæLïzb”6]ß/HTâĻ"4pō0‘SUÓũkšĸ?čkøÁs4ēÝnÉÆH’„‰ÚŠ*‹ÍŸĸþ҇ëOïf?ýØå9ÕĪĨięUĩmËãfģáŋSXŊŨ t]:™ˆJl4mýëģ_,ï~ýĸū[|ē:ýĄĻģrW 3*‘íĶĄ=BG%3Œ åtŽðI@Œ€íĶ@~öØh‡<ķ`ĢSčF§‹øœZyÔËĩ?Ö?Å0tM]deó|?ķUžîšŪívyŅu-°eۏm›§ėfŸ&ÛēŽûĄ‚Õë‡=ĨŧšH•g[ö}č;6Ļî†ūĐóŽĻËj:•U=Ž]–’SõÃXïróÊāĄóæŲúgþŋuëö;·ï?nũϛ*+rĶ?$–}ßÕuU_I‘ï†ąošŠ(3õuMnؐQnh+‡ýXtI›Šņ9uUÂO]eĸ{ïÝũŋúūāUÝ8ķôĻęnlË4%=kÚķiĘ4+ÛšÉĀŠÚąŊéCW_^^ŧŠĖýę3;ŠŠ*Ŧę0fö}M #1S–ãŲ—|W5M74gę:†-pðŧáqhr8ôßôûķ.a§jÚū­!ŠČrĖĄÝ ]%įĘōŠĘœfîŠmšŨuŨ7…^đ.2đ?š\ûƒíl‹JœFŽïūōĢĒūa4jAŽ†•dō~)™7"§ŧLÞŊpΙü*âG2ŸųoĀÏgŧļļõÁH’Ūïųîß:Cû=؊žŸŸcĪLŲėŋe;|[…äq$™ĶÄPšŊÚĪÛtč%ŋøëÅ0 â!ŠV‰ īðuwČķs4XØÎsF…Œ!;Ų:,‘gRŧܞI~·=†Ŧ` ÂăžäG-B~ˆåčc#ļ4ô[æv†<2Õš-į—Ž õT ]ė õS}…gč’įE?þņįPx(!„‡4 •8ŠG8rŌė““•laÂFĻE3€JŒŽB (ôĻ|„ĶÓTžÁ™ čDī@ŦPåLō#@ •Düšïģ_ϏĀņ›Ïc~š†ô$?úč sø!ÁüPõ:üČðĢ1~ČĮCž?ž2°~0øq2N `p:äG~ŲâG :ļÆfÄä+ųŅãäþ(íÆ{??Øņŧ ö™ä‡„ y<Ēõū? ]ϏC~tØŨåG†.Â|~0ÂKt3~pšäeü ūýGî_ ÆņņąŒP"Ïdč›+‚-ŋĢŌ“Q~äläÔĻs͚LļwïžĢ3äÍóƒį­â'‚ē?âĮž7ȏėÐyðß·s.?ØsøąÓPo!?BļžŸŋŲŧï ĻŪþāŸsÎ―ŧw ÕöÔhÔ$ͨҘK4–'ŅhĒĢÆĮωXÁBĒbėØˆBĀˆDJbÁFS:ėē°l―å· Ļ!óĖ3ŋäųæIž™ûšqĮŲ;įœÏįÜđïŲ=üąÖIþĒýąúïî4‰D"‘čOu2‘H$ýįQ+‰D"1jE"‘HŒZ‘H$ĢV$‰DbԊD"‘ĩ"‘H$ ú›C[ „þ†ĨáÖŌþŨvBð_W6””a$4ųÏũŸō?ąý" Ēŋ/DśŒ5U5*‰ãĸÍC…Zü·ēŠPņl}uUeEec“SÖčjSĘŋ)ō9ø7þΆƒN]øða…ŠIôG'ų­ßsSimiö‘ÐoĢ. ‚ŅZaÄŨU•?zTĪnbĸø>‰ÄĻÄ$˜ņ֋CFŽ9|HŊaï&Þo”Jü g6éu:/ŸQ„ŧ{9ráÔąƒ^ýĘ+cž8råæÓÅ ,EPs)Ž^Ŋ7q|ÛA˜ÓÞ[:Âë…~}šwíÚĨŦÕĖ-įĖ…ā_c- ĸį Q4yœ7aäČwCâꠧ ËBĖÆO―úũïÝĢ{—æNúŽōI-6Čhōĸ5žÐ†ŠĖāí›öĮ? ôï,@āÍ―Î`äÉdÂđM+GŽđ)ąˆĄü"1jEˆŦē—Î_{ĩFžóÁžŲþÞÝ;3,g„Ĩ2…R!' ˆ’ Įũn^ĩ.ð‘Ņ–02™”F`%R†aĪ`ÂČЄĶ%Lëp„āw"ę^äþ)SžË(ė;gÉây―ė ‡ķ-ö[―§Ė„Ĩ)HÞŋlؚôĒzFÎĀŊņ抒’Š&xaøĻŅĢ^ķdÄĀž-‘ÉŠĶđ))M@BļÄ―ŦWSq2ƚG-]Ëm,2 ̧ïČĪŠĒ%6JĨ„`DhcJ*·Ne‰@īDj]‚ĒåJ !özøO™:~ A‚ĩ#J"W4Oސ=û”IhĐŌÆŠ‘PÐB QՔ–•1ýĮŒ5ŌÂ{°Ģ-CKĨ­ûl…$RkmČR$#k™ĘzGZŊJ8Nā˜Ē-ĩŅķŠ)F&o9XĀÄú›æû$Ĩ›kĀ”ą&wmĀēïâRyFÉóĪŋũËS§øs·ãxūĨ…ēe‡ĪļeĨæÕ--B7_’[·N$F­č„°^õ$Į`nßkhČÆĀ­ÁĒÂw ínà ˜kŠ=đå#__ßũ}ž_Ū—I„é ;‚BNFœ Í(Ž5kŦcnÛq⒖ÃÄ\q8tïþð2áŠóŋÝšûÔŲ I‘ûüýüæ/[ũPc"ĸŪ/ŋĻáŅĶßTpķo|üÁĀ5ĸü:6bûŌģ{ŋ ÍQ] übKddØÎ][ΜÏÚ>Ų4ĮŲũąũDtlLtôđĻĩ ŲIgwl Íš“·oÃ'“'ûŸ|3tޅ3k·;yôó›žõ@ē^ ԔīíĀŽ”•óý\ČĄėœû{ âီņÄÝψ XėoŲÏEKÖįU뭉MpAōÉïXޛō]L‹éß”! Ā?`OLĖŅįΝ ę!ÜûfįŪ}߅W0EˆĨܘĢÁGâ~ŅŠŸÚŧ}úī)ū“ßþúø…zßrÚðô€<ÉNØīmwbN f$uEYßnZuíĶqI~jHāZK~sđp“ÃÅVG =t:ōôĐĢûöG”ë8Ûn=‡ũęá åŒ ÓX4gšeȇ‡ËŒīD"hŦ‡FĶæ%8cę”éëēŸhÅī}NŒZ‘ Œ“›Ŧ‹ž4ýüīKĒRnꁹQ2lÝí+f­Ü}.Ŋš*1ęĻĸĖ5Tęėœ,#Ģþräé‡e\ciôîŊ6†^Ö°˜æ5‡í ÜģģD‹Ø†G[‚ŋZō9‹ūØõó•Ī“ĄA—í/kjsŒ0ĨP(EAüëĻm,{PP_kįÞcŅžĐīąIĢŅ*ûūōŲÔū‚đþQÁÍĘē۷딟’›VŋyŠtę‚Ü_ēģoæßĻ5ðRÂ^ŋĩqÓŠÉ|‚ÃĒããZ―:ārą^•ŸĪ7>Iˆ ŧō@,oæ[̊îT\?ąuáÂđĩeŠų~ûöeLõ›ûųĩËË ęĒËÛ6ޚ4iJ`D|ōÅøŊVÎúōD2Æ|Lôą _­š:ų―Sq??Q7Ô=Ėܰ:(6IŗūY0wþÁĻ\ Ļ2SĢ j 4ë'7úžïqÞíŒþcÁwq9˜‘"ø-UŅík'đĨĩ2Š>―gÍšM đ• %SSxcÛÚĀGõú'ũ2v‡†Đ ĶŠėÔāsŨŸšÂ!‚=Ûíęŧ ›ŋ žrĢ”RHUnmÞþ]Ęmš.Fœ>|:šįØüŸNþáŒc7*)íãØÔ\ĻČˈ:“` ųýĄ€åQyĩ ?Ÿøú­·? O(ÐTÞ>ŧkÍŦsūH{ŌD›ëÎßĩjņ”7ü>ŽKžw.čŸkk‰C ‘ĩ"e\Üąj`gŧžØïĶŧlkX™–{˜õÓūČtÏÉŦģÏĮm^ęW›v.ŦqÆėéŽhß%4þŌĖWzœ‰PÏķÜ]ÄņĮ›k"3k”Ųŧđ/æzė‘qŪēŠØýEjŒÐģ 5Ö…8vøĐ#GÂï?iDOӖĻŦ*kR öĢûšILf€7›Č€!/#€šútįŸŽ_8 ÝšČSë&"'Ās„‘Šo_öúð!^CĮMûĪĪQ ðÛũÕwĒãįūčQWUyŋīaüʝóžÁŪßkQIi§õɉˆMŧãöR@â―Äuþžrn]Ë}LK()Į%öo.؜|%ōí Fš‘›ũĖ)7"ö8PÚã‡+šXx^0|}úŊ~<~áÍHZ@„B•ũn—”éÚŧŽ ÚsöjZš_o'Ą>?hũÉŌ!ä@lVônđŪä|ōĨĘF„qÛ?NœX;{—ũ0ŊĄ!ņīó +ĶbĩEЗŊЍ\ÆÏ?ޗŋ6Þ{@ũ!ã’Ŋ ;šĸK7sSáĩÐæøY@H ‡@ŽŊ4ÏŒh꧛._ŧ~üô‘ģĮŌŠō'å*ė2lĮÆEðڜ€„ä#=•ˆâ8ÄóRDáúümÁGÕžKPTėÕīŽ ĮÔ\9z2!ƒEk°ņ›ŋ'åĮo<Đ’ å EˆÄĻĩāü’ĸŠsŅQ[VĖĶđÆï·/_øbĨZe(M9:Ųgō氋(ŧHE(Ö$0†ÖĩÞ[Œ1ÁČšąFčæí=ņ ŊžCFžėëBĩFŊGðÂŽęþÁŊ·ïīÚĩ+xý͐Ôû՘hÆó`cg+“ƒÞ˜Ŋj‚[áúÚ2K:H°€ @„9 -Îdēé:bßÉļŸÎE†ŊqUû4w>øėËá=:šH%4B žGĻų âyŒ Š­ ŽāÐīąūI)=ŊŠÖ sfÖyÄÔUógôïæéâ X–eœįĖ{l_ïaĢû:{ï~­žC`Aæ­Úāݧ›“Že{Ž‘íõúÛc<ß9ãĸæøiģūČ-֚īŠj]ÅĶOßóŋĄānyCÖ„jóĨĀįÓ―įããbŋŸ3ĘÝ`ā―}– Ąā§’ēnæ'ė‰?Û`mQƆÅģ&ūõ֜åAåü;€’ŠFk™OœĩaƒŸ‡kg à „ˆþˆþķxžãqįÁĢú ęâ&ŸūâƒÂĢ€C|6,Ÿ&GŽ%šlÚw3ą%œ ÂRÐüÓˈbä2UqEĢF‡ą4šį%€ÁÐPU @Ņ@=[‘•ŧŽLJä jÉ#–™Rə˭Ã9ÞÆÅÃQÉ<*ŧŸœëýŽŃ + ?sCIGŨáv Įņ,€@Ie #Ņ™ĖB›Oę<ãÜþõIzXËLz=Ąg0ģR^ZŠīB`ЙĶÏ#`\ûø|ýõ†ã‰DÚūĢ›QO@A!ÄZ<ÂÖĄ €°fC“ @Ņ^)E­‹› ,Ŧ Ãóvö}&ž:čƒK1A;·'Åh4ŧĮėũâĖ–9Ï]8ÆS& ,Q8vēXN€ķúŒýÖļūÖÚÍFNoÓiāôY/­<―mCŅ mŧ-oŒnĮ–ïÛ<óX|§UÁ[Įy–,žû™Ó…á9Ä#“ĩ6ÄKAĻ-+ŅP”DSx%ðŦ)Ŋ†Å†rɁ+ö]ähš`$ðœu ĶMÐóÜ'„âx0ĖM,Ќ„5jôÔz)d6ĩü€6ī!ĢV„ˆĄ:įxtŽg·îIö­RP*eîÝx:Â―ŽŽĖ;ƒ†ũîPrįÍ:té-sD”V]wîØI—YÛKī9Đ'öïƌ?~ŦTãÜ­34ĢhüäÁøóĘ’ïŨ‰;;ķųF‹%ķNmÎ%„įŲ$u{qŅdßôo#lXėÆlëÛ_Þ‘ņÐÅÛÆÂ—‰ÁČÐpåB”‡ïþžáéôp„čŦ O í Xž§œúMÝšqžÐ’ėÏjá)ÐÜ=y&’™íÓgØ{ Šš–ykðˆžNE9LŽ}ŧΈĀZÝģú°eęKG īp+âdn-ôž7ļ“BŌ|™įŸÂ[Kī"4Ur=>ģHßsțøĶæÞþąšē‰8tÖŊã݄âkŨŌûš Gõ•%\ÛŽŒĩŪ#€u]€œÄðƒõM&°bðĻWuwðöņiw*-%1ÃsĀÛãđu%ęJ(lÛؚÓS~)o„ú›)+&ĩíó€ĀÛĩũ0&_ æŪŸŲē§ €B`Ö5 @uRRæŠĪäbMŸŸ–\;ŪŧLfc ›z%6ú…ņã^ä[įā$–šû8D\đÎŋėt,"ÎNût&ŽXîŊÏXQčoIĨnxœyŒ€…ĖÉQ€zM\p%įAcƒ*5fϘŽJPØY_ėKŌé4BVŧÓþą+RÓXūyķõHĮÎúĻgWgÏÞ Ę2Ų*)›Nō Y§~ŧ~ĘRŨŨĸÎŌÔęšâƒÛWpĩĐž\ˆ ŠNoÐĻëÕęüäãĢûķ€ÞKïŠīõŠ–~,ƒŪOķcāŨ/-­,\î ā–VĪo*ĸr\O‰SŨîĩuįŋYÐC €č~66ÖFÝ:ž·ØØ*ƒÏä4TĨO Ā}ŌŌĖ"UC―J­ižvøS‚={ôswwĀ–é_ŸwõvĐYS2ËĮ  ÃĐô"ZĨŅjrØŨ`ÄōPĩΔžg‰=@;''ZŌeÐøƒgsՍÚōŧ—ĶŋF™Œðœļ$§ī^ĢníDgTœ;Iŋæļ>üĢŲP_’î3Ô€,ؒĪmŌhT51ŧ:P”ė…q3õå–&…ļ9+―–„5ęīU…ïé V/Ė_øn{Ŋ~~\Uųpõ;ØšųÎ~ŋ““;ũŠĘŠ0Ômžþ* äÂo~<hYXšNŦ-ÍûņĢ CKmÚɰÜéģŅĨŠ&õĢī·ØÓĢW—Ļĩę{ Ý:*]_™]þĸØ;Ÿ§(Ž{<"ĒâIðæ!^AžŦ'=ėāAÁĸÁ‹„u؃zRžøƒm:īÍögŌĪMĨM›4ÓĖ›™fYe―8­T&ë^DÅK>§žé{™ïũ <æÔė/V^2ēĸ@Ȑ@L‚fĩŽí~ßäÔôrJįL>ę˜:Bš†+æ$ˆ(0 3§VFŧCŸqÏüJQŨ‹õ)™ũší–íD°ðJ/ä}õęõÛŚƒPĄŌt™āŋŊŒņ}Aûvãģü–öûŨ›wnœ?{úܙS.]ūĸd'Īāđ. jĢKĻōö8ī,SÁęŽb‡=Ól$ þ mŲŽ?›3Ïėš4ėxĄŒÁ†nKGZ>ŦĶDsˆIß2íÞ0Š—Û,GíģÍ'/>~‰\ŦаÞÁĢó~Ŋ#·IžROįáÄ1͎7ĄQčÛÍJ^ÓōļØéû|!d  GĩēŪå6ŠÝĄÔ Š} z­”g`–{YūīģLJ‚ú^  / Ŧ^@ļ="ōtlŧÕņĶ a,īu”Ŋ4ú„„Ët―‰\ ýnYĮša†„4Œ".ÕÆ3Ę›CĢ„ ؐ'ûCÆpÁJó|ŌßÓą–Ëï™åi=’‡ou―xeÛą[vÛ]u:#ĩęL“ðō@ýaÍz`‘pļčÏå=éĘĩ[=þ-Lō‡ÚøŠ„Ó&zûčÁ͍ŧo>đ\pXK;Ώ üTКšv”ŽÕWŦéLėįžÞ“ũ‡;åÃÃTĨRĒl“jÔ/)nąŠZt4ŌĄâBĩĮE˜šĻŠSCՇZĒ:9Ō- ý‡ddĢ6X4nmom―ûļú7á"9øō5I.øóĖ3s[ÛŊ į;;įģ+KvTýX+bgÛŨī%ðyŽä7^ô=úÄ[€x c1°ÄĀHŒÛļmŸĘϊÐq[ ŲîkųŠ›ŋšėŧ•™•--­ģvDýÛÓÐ]ü‘ļļĪö۟>~ā_ýü?ĸãßĸ õĸļ˜v†ðŦ_ýōŋ.―ļĪöââââ’Ú‹‹‹‹‹ÉÅ'ÉÕm~qņ)ā#Œ0TÕËˋ™UĸC)ž­”ČlAĪ—―øāĖâ7ŨsÁŨOÕĸđ/ÃTŪßļū^Îþ‡wœ ]šz `}ū.;Ėúƒ >ü. >؜ĘMɇÏööģŲ ū:@ķûýõSđ9ŽÃL/――ļøÔÄ=öÞAjß―{ũwĸĸoĸé?0S[GFŒpU‹ð*!ĐŠŲ⁠Ĩ*s­å™a4Û·RKD•{oS›:%ŠįÅîSöÁyžŠũũÞĢ;ģ3·‹ˆú!9kUõ\<UîAr*O<+ HŠTfTŌÝEÄĖxDe`ß1+—­đodŪeá_ŋgeÕĘ4ģlĻŽŠÖRĻ2#[VGøûÓ7ęĘ%UŠúÕ/ūú‹ŋüŦŋþ›ĸũúúúk}1ýčGĸĒŠrqqņ)ßĸþŸųåŸėíßTjUõŸøÃü‡ŋĸ­ũĪFfFŽeŅωYDĪ™îó,ĐÛíeæŽ3ã8nR••Ņ:•Uú„îáfFęy%ÕÖyŠ`UÍ]D ŠUéî·›ŧg8ÕĻę{ĒÚĘč›ÔågÉÛóÖē}WÖq;|ŧ#ÄÕr9ĸũ­Tö#‰ÔZGķ–ˆ’Ō˜UfvŋßąÖÜh-^Įrw)ąĩd„G oģPVĶŧŦÚ|ЌTS€{šJÍ|ïŊ~þóï|į;]üU?ųÉÏūûÝ?ýÞũþ,"åÓāââÂLüãýéOöíoų]mcĮzũŃũ{oUåíAZŠÔqīðeĻZ‰Īŧ~ņ…ŠæîĖÖö-UzlR• Š{PMųŪōųđÝÞŲē—ĩ•ū]ÕÚŪęyޗ­‡\Š ï˜k­ĘÜ­›Įqļŧvi#BÍLĩhĻéã9#‚ ­% Tf„ô2žŸGHR™-ĶëAļ§Ž[Õ―7û!Š*ÛËí%3=âv{!áūM ĪĐEŽcœõyžĮqP"áÞ9šwĩl äĄÚ_ž`ōX%JūõÅŧũ„ģÞŋĸâË/ŋŒų4ļļļ0ģũïßgæGûđU5ÓĖl7g™åą—.oûy‚ēú‚ˆhõGUféŌl”š•ûu“<ŽãQa”å!Ģ•õTsSûÞ @ĮšjŦEVÆŪšïĘÉ žÞ0$ĖĐ,)ģ•‘RB[î3RG|ÃKd­%ŒVÆąŽĖÚRãĮ#3ČQęķķUĀó˂xŠvfdŒ!vß@/ÉČxî mؘôc­ŽĘĖūãsqŋš;‰Ž2röÍVýęuû ČÔōipqqQÍĮü―ÚĘriąĻ_šĻ<ũŪJŠĒu–ŠfŦJFžl­Ép+ë8ŽĖ+JexHĨ*ĢÃ\Į:Z§ē‹˜ŧ—TIĐ,‘g !Õyi|nŽŒęÓ<Ķ…TŽŪáí6I•Šð "Ž2Ÿ ēĨswĒjÕjJðĄāUé{+õGL53Ëk=/Īē&fÁ>Éũđ&ƒžÛ‘•å{W=#ŨjēéCgkīYŧ~(NXņrqqý48€9ī‰FJŠãT)1[‰‘ĄNr·{dH_ðôž€voeiQæy?ŦBM!|nRÍLPRĻŧW”> ? ÓŦŠSÔ5§dĪõaÔĐįĘŽ…1GāÞÏŠ*"@.ģq—@QõqîT•ėŊ‘RĒäČýZöŽ–ūĖ 2ē ŋš ÄL3‚ 4î^"T…22ܝĪwßՙNIīwu?˜.)éW;‘y·€ĘįÉÅÅõ{ĩķl2ŲŽ@ĩÅB[9đÝ+Ýė N7ŠÝ^)ΈXëåÞ^Y4`ŧãĩÍo€XËzsv?ÏĘ|HϜō ÐéŠøđKjM&K-)į>I ߛd_ĖŽl‡Ý ͚ƒþ[ ”ó~'Đd> ĻôŒQgœįĐĪ@îh?™îNUiķ;Õé )1]Ņ,3ąÝôIFė}ÎĄYf’ÏmüÜ ”þü@ŠĀåj?G..W["Š $įļ| ĪÛî›īĖw{p[AĀlŅŽJ*k-Af(ޚŦ$ Ej›LlŠë8@€ŽČĨ–-p)Õm[5mēíg_!ODfTŠ ĨķïNZ‘1Ï 3ëÍ\ëÖÁîžÍόJķ T…ÔˆÔ6ÛãÍK@Ō}§ē “ĻøąÖT.)Ķkbg !ŒČČPeVöqâRUĐyŸF0ķwĶŽY•“ ØōŒÏąÍāââ’Zī܌š™Ųsý Zā"H―ĩ~I •k­ôðíÓá”ņ„$ĶûĩDÍJ*#štđoß;Âėíî;E$óaŠ3cG‰Lkęą)Á[Įkf@DmØî"2Fr"ÚeFЧĒÓÞĖRĒ$―/҆ tnð Lĩ{weŽumÉÖuŠJå8SĐ$Q"îˆR „;Īö§’·n{8ïũQcūiuîsÞL9Ï]‘ ŠTe*U>C..ŪŽVRēÕ02Šjxėä4‡Žþ–ČyžY5’TmuZe[2§õÕ# p‡·ðĄį"+hkëaĮHä(uŸŠeDx†á! ’ˆéáKˆĩVDfĨššj?Rš)Tŧ@ëFpwäŠf;ĒŠÞĖŧKŠ*1^ŧ7ӟDø 8t„ŒŪPįÞūŽURáîé D$<ūžžÛÏž-âŧ+SÕÔ<ÜLŨą[įÓÅįŒ7D8äâââóËjĘ āAk™ĮšWe’ÚžsƒėXĀ+‹UB€dÎt,ÕZžĪ€’—Ûŧ–Ņ4Séļm˜kīŌÖOßŲą@úsŸŠņôę<Ą&Q…(™)î.RA™ŽYÉ7GÞ~vŸã‚ØÍČÛí&8w‰°Ÿ{§+Ÿ9—ōųysũxÍą‘Ĩ"2ÛŊuLK†éó#3XŽ„T™šû|ĩé þ<]íÅŕ՚ïéI*‘ûyf…ŠÕ(#DÍ’%kč)Ø2ģÕzTŠH˓čŌÏjUĄfϕ‡Žŧ,™ųÎ―c&z™yØēĩî=ė0J]—ŦÛŅ32ú'pwmg5#Ōr_s̉‰cú|Ó§5] Ŋũ{dP)"án4ŧÎÖޙ܅õˆíynLĸ™HFXËĻĻ*{k&ptÂ3žKuũûų ōļÝķŧĮdÍkš…ģ rqqņųeĩQđŽÕ‡þwĮ:Zgƒ Uņģ­r~žaŦĖđOŸcĒč~Ŋe’Ļ˧ É [VR™)‚uÜ2ëÜwŽÛ‹Ÿž ĄôîūĒj‹ZÆÄ­_f:―•9ý^íŽEÕDÄ;ļmų•Šū@­*Ļ* ūã BÄöķŸ&IWЎ;Gå (`Ķ4—­CŠ"\:CðþĶøLQ^§)­DĶģ8Ŧ2ƒaŠs€V'Ŧ­,%Ũįų#^WVŦĪ”L’ŠF›ÃŠRĩޜÁZˆ3Ë œÝkká­―ĸåxįūIeŲz=ïŠiWv)ĐJK’ŠKmû9:kËÂĢDēRĄōÞnïējƂđėžŸ‘aŠ$GŒĖð‰ŒS<ķé4O4üBÅë/_;Ėĩ‘!Ę"R™ u†‰K€ÓÆ UƒČžëę ŌÏđEZīɖoT–.î―QŌޙ™ Ė(D/VG™EĢĖø/äâââģsĩĘé|ōį:OÖą2Ģ2žëu‹hÃhķÔ"ā:D; Š))ëŽSUÍØdũö† 3zÐM`gxxŠŲ æúXWrïr―…ŧïģ]Šîí|Ēˎ酘ā WšŌTšēāBæ‰ÝŦûÜmŠßâŨöžm:ADfŽ?•é~Ŧššd.ĩî—ČĢģîoĘ1§UåũÓ}“ÚÕ$3Gú'_FIe|ĢfŊþâŋą„4―ú°·?ĻŋÓã@Uí‰ĸû QHųƒųmŸ ŋM}ō;ō{ýGŌō‘ø@~ýXč%øÍîD*€ĸ RŧøžėÕ;+ QíåTmÜÜLô“žßïGG"<ÂČį"TĄ3]VĨÔ*™ÜPUã”5sjf9§ĸk‘ZYÖ3Ž―—Šjku’˜þŲ‰SõųŲûpþgĶŠæ 3ˆŠ4SŠžûŒLR –<é|`g`ōYąj§ŸtūãļæsïĖ(É{ÛR}ÓåĖ&&Ūų‰iuÂq‘1ïvƚEP%ŋ'€ßïĸÍÝwGUuuߞvÏE&E,((ˆ&vƒ5vP,DcŒÆ–Ø l `Ĩ(BTė1ą$ˆ]P `Ã(vÁ† TA:—ÛNî―úý~/‰c|cžžü‘2Î9{Ÿ}ï{Ūđ֚ŧŠĒZÆåŧœķķNcĀĨžŠĶŠÚ(Ęĸ)ÁK/î\šų „fčĸô0Ã`mÂ4#Dã­ßR”šü/Jģjēī ũΝ;YO^ƒï":äûŨɜūēēžĪļļļ°°ĻŽZú“ĩ}ĸŪũŅÖVŨs(Ðų›ĶýœNS^ óĘS­ýŦ]EyzõâõÜjúï,ķ˃ļŪēJÏËĸčÝHšī5îÝ―wĸIEņÏ&ËýÏüģ9]mMM=–kŦ+5z/ƒXWUÃq\eM-')ö=ĢeíõËŋTkÐĢĸõuĩ)ƒĀĐČŽ)Š‚ĀCé(H“`ā4Âøˆ‰S^îąEKŲØu-ĸ=hÉQë”ĖĻĖay(í‚ķZ‰eLž€ģm8&É" Ãáíš_i<‰cs™"HŪÁ’‘oÜjž#PN― °·7†E°h ÅÃO ÎQƒbÜī€Ke}ŅË6|cUļ;Cĩeüp Ö5b Â5ė7†ũd`ú˜`M3Õ/Ŋ^ôļFQŦļ”č°ow%ō„š ÃWn\nxP(RH;ķygt.jýø/œĸÁë5ĨåÕēō—ÕW—•WëÐÖĖÕÆo\{äđ†aþš{RŠ.5*xęÔÉ~ŦƒūųrÚúŸS*’R„Ōē7Z>,|ĢÖ<ûmųĒŊü6„n ^ķ;A‡vÃĸąãðč.@É–Þýɝaą Õjæo]ŊV=IÜ=ĮgaČÆð ëWýxO&Ļĸ+úiۃwÞ*TŅÔ_!iÐT––ŨĄn!Ĩ<ęÛŗ_Ö3ų·‹‘ę^lY3oŌže ĶzšĻžïČčČkKË*yé$o–.ūujYØþ#­&ëvŊ_ēöð ’a•Š!~û‹Kēü}wdäëúŸ‡$­RjĒ6­ŧþī„Ēé=Ôb2Gƒƒ+ŪþpėÆą6‚'ÄāĀ/Hôƒ †^hÄ.ČĻž!ŽĸÐ:ičt€l•$‚ÁĒQ02‚Ë-ī°j5‰ï‘Tā…or x"Ō.1Ībû\â WÂR€?Øð.ōœÓ`ÔݘCÛ04g—"ER˜ų*ļYbpŲĖ2„`â­tč]lČŅÂbôĻfwã Ā苀9 dĸPK7[;J,vĸQđŽŊūuõôŊĮnÕJDåãŦ[s3Š"pĩ2T! • Ą8ŧ‡EIÆQØÝ }Žô; ‚yNÂ6@ Ę$‚] Sp‹‡ŒžųžÁqÉđcówžĐÐZâd&zūŽ ‡ŋÛTôĨuA~IOhīքđģÚVÅĘQSSî™|,lƞs™ĪĄ0ÔŨ'áö+❄BČÆēgY†‰ –úųÏó2ĢQšwūˆ ĄË ųÖ'ņî+…ĒāDÍO \dQ=ĘH$Žu4. ú&ė ņӆwĩ{+NÕ 8t#ÖG%īæï<Ĩ/Éæ{/]áúÍČî$!փy1f0’ āąð™fNŒģš&þ,äQðg') ‰ CēvE.8lDáĪõį‹öle*áĘwO‹$ßÞņë ûȆO„y‘šíh"y*)%9åĜQEÆũJ‚ˆ',[{óĘĒЃÏęá ðį ęã‘dqėT-Û:ä\KZĻå+ ŊĪ%ýrōŪ‘!_ĶđFŌ-Ûϛýy{[ĩh"IĘ{ïMO@ÎŽŊðOk„ũ‹Ŧ2nœĸå škÃĄ,ĐIÜ:Äsä„đþ· 4&jâܖ°€Ĩ‹ŋé7ådRFėڕëV.Ÿ6xPŨQ R2ŠY–ļrĀß?líĪņÎÝÉÍĖLË(ŊeHîôķÕ#=―žÆŒ―–ŊSÓōí Ķõė=ýĀ•äûī‹ĪÍmÚļvčāæöQ[KíÎĀđĐŲo_ŲĪâų%ĸðđEđ›—Ėō9Žß4ŋôBā…(ĄÉZĩxۋZIĨ’ÛđhÏÕĩJč9rDŸŅ3bn—*u…?]Lžī'rņĖos*k2.œ~^ÎĐ(éNŌĄéãôøÔ'lßk#Đ"ßėûÖwcdÐôÏšOðŋóÚØKĻÔV’(—”;ī4ļ‡ŦŠĄsœ_âí5ÂÃký/Ũ9ÞxéōŅ”ĢąkūüęÂýĮÛŨlMÎ(cÕęĖļĩĄG.RjuÖņˆ€ukW.ýęÓ^Vï9Å).­ÚõpĩÎÏ~ųōuþmÂį>,1ðWóF ųÄÔP~ææJY*ļv|ŅXï9‹˟æ―0,ķF/Ĩ ó5rÐĀþá1Đ ËęJîm˜9?hęäé“bycMĖú)C‡ ŸüÕ͜ ü|þ ĸ6ÞÐ) |“ah„88CÅŠÔ þGÅ0Ņ‹q…j@g ĐČý ü[eųÓTX€ĄŦ†^p˜PiœÅB­^ŽP―a0.Þ8šŲÞ~w1€âį`ŋ.QKF”w †þB0†T•(‰0:Þ3nÄ}$_` …zXĀ\IaŠpx„Z­Æ27Ņ4ũ*  /Iņ°Wá—B`ýÁŠ!ĄēîãÖņynÎÝG9bŧņcÜđė‡ï—iÜ>î^ø{ī_ÄïAŅg|G7ÝYC˜Ō˜• Õũ}&ŊĪšL=qúTDČX“ŠŒ…K̜ĶG=Ũ$?aéÆDĒ‹2ŌRïW~þãāŌsūOôŲû•C~ԉ{BíĢoūũÜ{$x끰-ÏŠŒDæöýŧŧũ5.0*ĒĢ~ÃŽ…yęq'ϞšåôzÉŽāBŽbHB‘„&>ëâkúöD#I>đqŪķĪäĮûŸh Ĩ:^†7€Äĩm§ū―ûũwïlai3ꋱYũ’Ó=Lŋð|ʔ ķīöQōÖÉK6\ĻЙŦ˜w[)"&Ķ JßŌjšÆŲgēîųņŊgÏ?˜UĻ6a)’mÞūĐ­c —6­ĖX$‰0j:+õ éä1ÛŦŧ­ó'Ë'ô{yņ†ž`$+ÛeĄƒšusíÐTE5Œ ‹Œm§―?8vxĮãŸ7L›™“Yņ2ĸŌÁðY~Ę^1:hŲĘîíšĩmÛÆŌBMRf›ĒVzüj‚Qé7Å?|BũÏ&ũ°mþ0ŊŠÂžVTÔĮļ?OH:ĸĻā#ÏESŧ1ßÚ+8ĩíėŌ’PĀžŸ4ģvpģ7Ž ßS?vÛ^ŋ‰VĶ_ð|ÜiÛOĨË$#ˆˆ*Ųvs_0ĸŨĶO ûLûĐ[Ëã&tíîÄ98,•ü7C­‚å‹#$ U铠ßIÁŊŽ@û)’\IÁvˆöEÄm]HDýTø(“‚ S īœ†Â)œ"9ƒa1ÃHpá.Tę€]eqÍŋL˜VC―Ū„ļDCc™BBC(ĻM ē_ēy,f‚jĩ†ÆNސĀĒ@@BēCĩĀč‰hD°ƒ@Ú‹h8žš p‚(A?…ÔxdØã€§$.Æ%_ CÐ *–€mė5QķqíicļæÚpŊŪ čs36>ŊÜķG;3’—l]"ũHL?īÁJ1ˆx­XsKšēöŲ‹2‚bDE2kîH”—–Õ"ƒĘĒÂWž…… Ą ]S0„ĀˊQŅfc‰ZĸŽm[ŅfíæŽÞüó‘ÃũïïėÞ\-5`œĪðåe:lŋƚęßFŽ5$E֕=ãĶĶ,ŪÍĀ Ėq\Eđ šÁī)ö ė$§Ē)Ǝĩ™žl[LÜé”ĪCݛ)‚„ErŌzðpŧ›ŅG2ë$ĩč ũŸËiÖĐŦ%Kqb‰Q6ĸņM–)ĶéŊq“&îælĨČA™ŦÐðžĻ:[|ýö.‚ -ŽŲŪ―C#ũ&Üšû{ô2sBŅā8į=đJĢ#Ē"7Ÿ1élŨ„B*ĐPhžŦšNÛļïüŅ0õŲ Ēï8:ŧКšú„l9{įÖÖN–tĢ )órģÎ=Įû|œĮ@SĘĨ‡GWŪ8xđß#ŦAž―mO„OûųR뛃―\-u˜Ð4hτÞxŋĒ^ŠÏp#―ŠĐÚėņé€ĀMWnÜ:ģ_{Ž–h$ßqåeZ™&H˜“ĪØ·s‹ ĘĩEČEE’•%CČH&‚@:2û~Đ@―FŦ4í=böū_UæĨkYÖĖiėž ƒ1‡ï=<čÝÓAŒ•oę9L>ģŽķFŌVÞļ^,ę4Qš kjī2Ačjjt| +5 Œ$Ęm{{(y‰IéOÜ{ŧuîóqÚOņö-Úĩ·§ąŪP#iōýf.xj>:5jąšŪz~Ų7ð‡AþßÎß"[.^— R_PRŠ%ˆÚ‚gee•臯i KʍĒō/PŦ,Bó>rVÁ5^8iŽ\g)‚”1ÎŌ8Ė{Y(„–StŠ"ĀZš€wâŠDĖgqQ2ú›A°Ę—CŸ=WX\å—ä9LŦšĀgí€=ú^!ˆDˆ)cÅá0>öã/ƒU\ãÕ #“$ŽKŪ2Õp ‰ É$LÔ! Āņ dېŽ é/(„’ —Ģápd™†ž`Üh‹É;Ę 0šJÓaRÞX—†&ÝÐû‹„…ãČvM,Ļ6Ÿī7ģwëŲL6kŅá KŠč6pĘ8ãŪïvÅÄFĮIÐ*,!ŌŨÄąĸâŪŽ{}ūÞūų(Ņ~ðčŌڀĀČÍŦƒŋđtē5!―§ķô`Æ&ÄŲļ|:ÎŧytÄö#qąûöƗč @F›ē­ģKqB\øķC”ó’1CŲžj㖈ĄņÃ<wą§hâČĪu'—ËßmÜ{2Ų 0‚Q‡ļ*AˆžĪŨó6ŪCuwŠßw4úČá|-Ua’@x.ÜÜÁ"{îóķïÜđtî܌7íĒ–O7·oÕřM<ī=:îÅÐ DÐĪķúJxŠÕAë~|­W8ƒÄãQ$ĢAäĩÅÛŧ˜„CÛbOäx-ņékþ bĮū̇î8þ;2·7$AbúāÕ~ĄAQ)žÓgÚŅĒŅ 7p"0kQ yI‘ĩ9ŧüÖÅ'ßĻĨŽ;ؚ9ļOíiącÔ/ņŅ?î;QÆËÔŧܑ˜}!Ú?pM@€ß†įõMg nsëęÕAsfX+rSkĮŠWwbbâSŠđS§~Í­IÁ`äyš}'{r[pĀߐÛE„Ī˜Y:ƚü„č# yڋɉ ÏkœšuÉ9z0â‡øjž$zįûLÔ―bÅēˆāe[S Ÿ-ýÜDâD―ōO‚QßXȰėãĪ―+—/Üš5dwēŦûĀ.=ŋ˜ÚíÂþÝŅ1GöíŽÎ.ŪģjÛ^w7-býæ\­yŊŽŋîݰtÅųĮO%‰SSú^Ėþ5›ý|VļôŸÔߙ—$øfŠ>áČXąíÚŲ3-;ôh"[uė0 )ķü3šŪÝąãü͎MËnZŋ6ōŨJÎÔʔŋr6îĖoéųU9—Ū?âR6131ðéĻŽ‹Į|WŪZę·'#ŊŽ51­}œøåė€Ė7CĸŋNm退€ĸýY–MMIÉÍÉibŌD–%ð§’áėXT†‚ÉDIÅ"΃(72ļI ]A•Ūà _V”Æ<8âcà l(Î ļЌn| ކÄėŦŦĮcĮ,8ü―lîÎbT @?ƒÛ0jƒá" üÆ$I‚iãzW…"°d,Ęļċœ€"#„§ĶāēZÍbAƒ ąPit9ĖûįbĀ…r]Žx‘H‚į,+îĮedŒėČŊG!€éĢ9Ò*ÄĮŧ :LāųÆÔ_MM­JÅXýÞŪĨĮm* ĮÛą}ýŠ8qĮo;~ÄŊt&nŌÎLœĮ jU™ŽŠ‚ú€ŌŌ"ŠÄïaƒøėø ,ŲtƒT$Ė Ô*S&ƒÛ6l`Ãę^ÝÕųtį|ŸŪÎĮēĸÂ3Ū@ƒhâíų;=.ƒÆdksvuÃĘ('m―đ %φcŠē(ŧiĪ Un°Øõ5ęŨĶZ~·kÎÆ9ŸBôâîĢÆN‘"57ōš&@+Še}'ŅšægëQŦ&NóĐB•–§(w}OÁačœƒšŊwQtwļ›'âÚģãĩpįîĢ{SP°Éŋbmđ#ŨÅĶĨuĢĀŌ ī Ë"ĐŲČöæNY—EÅðl/jßsšEKŨŊLTâôįßNžĸøôû§Oūýé XoíÖpÅēŠŊŽéV0)$ƒą"pž 4›’íũ’0ðÍŽ–%à cŸeđ4―Ā$AI―lc’įČïË2Î*ŽkKuŲðÂ(āh†~ųú‹ŊŌk Ģûožĸ`ąQz^ BŨæÉBԂEĩį92KâĨËį+tppûÞˇ~g6‘ˆÕr…HŠëuåĘڟĀ)É tåŠŊâ2LUč„Ņö|įÚåÎäÞeÏ ËœsĸÎAÜ$%Ű―0pLž­oRAû{7?|oß7U+ļØOåģ2óöÍ[W‚US’dĶ-Ē‚–m)€nÎÆÛ•“gÖžņāãwJĄųAâÚ:Ŋ zŊ@Áôž4Įļtú2mëûŸ<ūÎcXv)ÛTņkļŅ2=OŦ5ÔäĒÃbgm;ž 7Ú ÕHFÞƞXŊ>ųæËïäŅëą”ėĢOï›ėßD§g8į Ģ*L{:/y/ũaýĀw”ĪÍÉkÝvfŦž ûik3„OÎŌéþ^ÞĮčšĶšašv:ÍB äÕ`;lã%d4ŋqįÖUWĶęšū§Køzj‹‹ttTL†þOýĄÃÃÃŪ>üŲėËŊfŨQöëēÖÚïéôÝÛíîļ;íîī› ‚ĘÐđ‘Ā &H BĘĀ2% !ĪOƟð ”Q@ČܔQ)BKøŌNŒÝww§/ĮįÝk­ŠbŧjŸ#hŲ9qö#ŦÛįž7GĨzŦžú=ûŨÏæœÍýŪėAđĖB"uę—Įƒ‹ĐFömo-.w™Ø}]FČs°bo9šzā•Q{mQˆÁ™ķŲ·q’ĀLÖŧ qvö•ø‘;žûÔbƍ'FpX"OBgßø5ål]ŧvæ„f]Ä}Þh]§?ēųšËZoáÐBb0ŋāHb 4í‚ifæz1Įˆ&óČ& „“ßVmķ𡚚{9Ē]ũqŊ—'ïßĮqýЧžú―/~éî]·ĩûpãå—_ŲØX>}ę]†“s^e–qÝ iŠķÚDý^ —Ė0Ét+įÂÐĮĶHДķœq]ŌP’ĸŒÕ?“aemėjÓĸ@Đĩ+į!C_7AâRēĸŪÕqTƒYHŦĄ€Y­Ģ•ĄP|oküL‰‡’MĨķžōā/ĮRdŽým/ ęļŽ_ QJ99Hs}į;ĸøŊ}íï?ú+ŋõɟ>í#Ÿ6ŽōöĮ—ŋ– ũÖşÝ‡åŸ ™ķą Ĩ\Ē#6Ymþ.ýæSŋņ‹ð§O=~ßÎŧHeEZŦ·„)ÔÖ‡UÁ·―Óú|ÖĢÂ,gģd\·øØÛ8ŠYžlŊÉF­6ČK­âŸ<ĢCCdlŠÃ8u_ZmŠþÉëX[*ƒķQԈSÉ)šËÚš–Õ uôÏaEþČoaąFî­v1Āĸ|ÖüßzFÄ6ŪJÉ5@āôõßþüúÄß<óˆPþ°Áv•°ŊĮČŦ!7€4nĩ#įœfi­RI„ĶbČ ―yžKĮ@ÅË0ÓøĒŽĀCaĸ?áĸ\8ų‹/ūdf?|ēÖöc(ĩ_øÝßųŦŋü‹}ûömũģ·Š(ŌsJĖĐI4ðâÛÅ?” šŠ ―æúŲ€ųŌ,đjŦ͆ņEÞÜc€€2ŨY€Øáø—'™FgÍD jbš}L :óįf#Ï‹ ‡")‘>;īrîãh”&‘3ŋĪ”âÜGA·ĀėvāĘ5åœc&ĀHˁëU€™DĢb)â ã`ÆØÝá$#$u@eŪ­Æ0š”|ûöO}ú3_üŌūÛRŧČ’áoUģÝzXŋúōkNž>ēb3XtÏ.ïĩ Ũõ‡NÃ=‘ũ#—Ú{ÏjĢr€Í'Š1Ÿ$Ÿ‚Į͂Ŋģc­õ+!asžwė–ÖuŒč5é*)OJ―6é_ØcÄîŊcģ+óĐ#$Ÿ! `ʙ)™ßđúwsŠĩĩÞĢŽ›úS8Cb5ióm›Šö.]8'é\DuwsYx$fDŊúÔVDjoėãÞŲ(†6soÙëïr̈́AĖQg*‘ž+*a<0ÅļHœ<˜8͉ŋōÞÎÁ™…CÍvņ9`uúėŲĢK}'gũŅ|čÜĐũĸˆuv!{adßĶ\kCŸÃķ*mĮĻÔzÏ9—\š/ļĸ#F w_~D@“Ėį”4ÉÃÄÔ{XrDˆõÖÅÃcŠŽfá™Ĩūĩ%*ŒÄĀcm€ĀœĪ;a ,qĮŅĀØ+]ā JÎ5°/)ƒZ—ÖĪÅj―ĩ…>ö-Ĩtß\ĨėßF›gî"fâ§ÐlÜŲ’•Ý%V―ģž†âm{§ė‡d=&Ũî‘h&ƅ}oŨK.āþ35āp›ųģ$Ēd°č›Lz‡wŌ"ýïΐ.ĨVÜîڐ€Ü0·Ē&<ýÐÓeb>ë·ânjÐbdæc:ú,Ĩ4ŽkĘŦ|0âdâî@M Ņķãã8B]ĀehØcŊS8Oį!iSžÓųXĀOla―ĩūqýŠvą™tŪ":Į#ø@Ã4a3&Ŋė―ĩ–rA@™ŧøŪāϘœcān° :Č|–6ķŠŦÕJMÄ{eōŧqĀb…ˆ ô―§E‹–R›ž–õĶ9sðeâ5ĶchH‡ ).fëĘ>ēŽ"ū(ó=˜t WT“8č―ÅĩęÁƒ?ų駞xâ'§Ą°ŠÜ+}ïõ·.ó†;ĸö?–RzéĨ—þߟüņĨ‹ŊĨ’ƒoāĢ€Č k€˜‡ÁgĩŠˆ…KlSJņš―ĢώÄíÄTVEÝ;ƒäŅd­É°*`6nEāBũ1hō|ØžEÚXĖ=ČÏØ`/jŅĒĨÔ:į;ØWĒ‚óČUmR„ÎļĮ€L™Z­4§|ũč4}Š%•˜y^Fųî^ŧ"Ā Î}øüī‚ûö·Ÿ{ōÉ'k­ŧ=ŋßØØ˜Õŋúgĸ_Zo―3Qö֌—ev7đõ‹#-ĶĻâFũruUɉ)%™ÝČ9Čė­:Ļ윘"ųŅ1ū)·ÞˆT-.)ōÏ0 öž-ZJ­QD!Ļ€ÍuĘ·RĘ.Sí=\Ē(ŌÉŋ3xü—pŦÓŠØcukՑZ ė%W˜úuïųÐã?þĖ3ϜáMžAŸ•*û~ÉŋÏôÂC‡čøOœ9“sþĘWūōå/ųĉŧímšžôģŸûõkWŊ}ïÂËč~^BĘ95Į)$žŋÝĮ‰SĶ ƒĻ ŧzõ#ą”IĒųe ĀyÔ\ó|ó@JƐÁm ļQÁũ*aBpčĖÔĒEËZĖæ6Ęâ6áŦŨ&ö/ĀÝK’ãgŨMDzž‚ĶqîŜÃ^ĘfōŽˆũ{ĸ4ĨE€S§N=ûėģO?ýôŅĢGÍ vAf&ŪóįÏïßŋĸÐáC;Ų3iöĖB‡w0äˆÔ[°aĩr;}åļ>5 æđó%AÄ6{$8>.œÏŨe)Íat‚ŸüC)Cð―Ā`/jŅĒĨÔzųÔÍŽË‹Ec ó;ŦąV"Ž^UæÁE?ëåĩĻjxøã”VEį#ą!HĮ:qęôéÖÚącĮVŦÕå˗/]šŧ# PÃz―~óÎí+—^ƒÝéy[k‘5Éä\GT"G ßë"XŸĐ4Ў5ōēé:Ū—}°ÛØåÍŊîä˜ĐÏē lŽ• =C ŧt$HœĢÜ{öe‚―ĻE‹–ŪV$§,](ÄÔý Š‰·ųؘ8ü°’ōÜ*{ K|7Ä9=Ũœöârģ*™Ų4Ĩ―}ûö­žĨ@Âî(z˘Õ9räÚå‹j“4į2įÓpšÔÆjĶCÄ9ßCĩq;Å ]ĶĶǜH&ÅéWɓŋu*yįÏ?6ÕŲW^yåÕW_ 'Ųî•ÚH!›č-ãzkóî’fũĻ5ŋcŸĻZ†ØþđÔTŧ°Ÿņ!!8đâ‹Uaë‘^žÍŽŽc y}V`%$ßÜBtč(g‡YX2šĖ ÁTÜĢZīh Ļ‚:ö°G”KaFwCiĪ―ķÖݧ„―u•ÎŽķ )SŠ Æ·cŅîvĐä ‰pôØąã':õðĐëŨŊOĨv"‚ÝŅNøá#‡Ŋ^đ,―—2ī^ÁsÎëõˆÛ€Zŋ4K€A#“IðŠĄmėyßjœ1ÖqtX3Ēīˆqų1T4“Ž„œ8qŠĩ"`.YšLBâD$~X {S‹-ĨÖĖˆ‰―I5óÛÖljMü(ÖÔÁƒa `% H8ŽÁrā E#AÜÄü;x>{öÜĄƒ‡Ũëõ /ž0ý9đkwĩĨ‘1­mmn"b+Æ}p&gŲPōķTTČj`æ„I\‘˜)aņ( ƒaéŽw"LÄ4ŪG`ČĐD˜˜‰ņÄUœPS{%ĶIē ĻEښŊØTķũīhŅrÂ`†LÜ"{†€™ŦŒ*VRvP‹j΃ˆöqnRÁo€ ĩ† ąa· ,:\†r)gÏ}x:ŧråōtÁĩZ­ˆhWĩĖ\˜ƒ-+^î‘ØĢÂgÛ!īÖÅī872°ŨŽŒ9ρļæģ°˜x#eK™ŊË</{R8’‘LĪ‹ĸÅŅycĖYį,Ȃ`Î?Û{Zīh9aH‰ŧHö/NaáĒÂ<_ž:d ÐÝDĀ)ĩÞÃąfuŽ)% DÃVŦŧJđõFˆę&ŠÕjcēөʝ;w.^žq^°; ‹U˜ ØŋywÓLËj0@éĒæuv6Tā*•؉1s„3š PByFx`ís"ūõæA“ŲcØ ‚ŲŠ'K2!Q_”åD>Ä(Ųo‚kĶD„"Ė`jŅĒe€ÐýnTM}r2 ƒē(q >†—Ö­ēēR­ cbÉÉCiˆŲG™§ųātķĩĩuëÖ­iVįŧØÕš8ðÆõëVJ1gƒsÁ@{s˜Ylĸü^Ö ÕFnČBÂZGïЍÜÍŧ‚Å4w58í!ŪāÛ8‚§ėN8AĒ·*ŧ˜ôæŨ n}K”(që•Ðy7{Q‹-„IL‰“rxq†·ÆÝjJ™4C™ "Fh":ķÍæZf€ÞÁŅ8Ž„4y:$"Ï?ĸ|$„ĸŨG 0éų@ @øęl c'Ōöwŋóž[ēĀq—Iž(9gąÚōayZā €0Ē}‚ey”j°ąZ‰jï’sĀ―ZÐlA­5q›ä8ĶÂ\[4īÞ(ˆ6{O‹-Ĩ6j„ˆxĖƅ^ƒM'‡Ųã/iU˜’kîä qęĮŽįXú8tðÁįœĮq|îđįþģũĀĖĻ‚―žFŌn+Ûx€@ė`›)Ý`ŧÃÖÁ‹•ĸIpŊĘÛZWb·ķĪũœ‹HI]­ŨāÅtðĖŲ-ŒŽŒ€fþ )aĮ⠙ÛXÉÁ\âP§Ė˜Ûf#}R|†íütĢ9ĨžšÏA“ã‰ØK6Ę2ŦÝĢZī8zí%gÎ [Ŧ„˜†Ük7PG_Į*†iÔG–p!qX-įģÁ·ã:įDhïŋĸÁĮŸxĒĩöýï:aˆÛ_py]|aã7V7nōú}g˙Žø‹§[ó›Ôî°nß!ūÅx›é nēÞ$kÛƒBÂQĮŸ7Ū'Î]#€™ĻŽ•ˆsI† Ú1Šoëäo<Ī:ŽfūÜģ8ý2ĒGkrv—ų›EöXöˆ*ņĶ7Zp~ {ßŠŪœǧK8~7厛šø―öĻ-ĨVÔ;8N`Ð{‹*ę™4–óĖaa"ÃĻ­s9Ļib‰H­-%Ķ”}Ȁ‘áxĸ<ōČ#Ó ö… ;Ósā…ýWū·ĸ’Đ>pnßđðôZÐĩũ°lvīÃ1P4ôļqëofú·ūžá6a#ėĪĢÁĶQĢÞäū‡ïŧvéĒF„…"gį\Ķ8ýŌI ‰ÂĸkM‰œĢŠÞšĶGnf Z8ÆĖO<ī+˜ãĨ·Ö•―T;\Jœ)ũÄ ‹-ڃĨ6r -\ĩ^"8–ŲÓąĀĸ);Ë5zÃÞšÅÏäŌję,m‹‰b]=öXPŪ^―ęn§EÖĖ@ôBÞ|eߕdæ|ė@T—Ë@æūlÎ ‡ūާŦĪøvĒŧ naš&ý&Ūî$É[빉QÁšö”Ý'į|0cæ:VĻRũė/&/Ūó3ŸýØÃgĀzõ͗ŋņÆŨŸ―úįWęĩŒBfØD3C5)číåЌúLjK`N@ģ "ŒžÕ%Ž­22"xÚãˆÄŒÖ@`>Hæ `­ š›$ōÏ'a@~â“TÔĖq6‹ŲkojŅŌÕ*ŧnmhĘŲŊMÕJY™Aëü>ÔČĘĐĩfjĨ””ØīŦ)1{Ž‹Ļé‘ĢGxāÁØĸžøâ‹á=øá1Ĩ―Ãkežvyü§ŋŧõ…_øýŊ~ęégï=ĀĢŠķöņ―O›IOHÐB/‰T‘Š("ŠQT,ČU6ŧ é Šb‚Ø+―ũÞB‡Þ&sĘÞûŋŨÚaū\ÂåúýŪųîýþߎįŲģgŸÉ™ã3ïŽóîw―KálåĻŲøÖzw?ÕôåÚūWļ*e„n^›kokõN›ÏßmóAŦčt‡;gŅķš*2FÁ$ÅmÐW>‘“r€ŧžā ( ØZ!Ôâðō3-Ų5Š‹ņ(ÞU– ŠüWUë °,ð§as,áĮĸ9ĻŠÜ‹`grĖePˆ hÂU–§Ō:―ËŅq%P.%ØîÁ…nĀŧÄ'$5kÞ\VˆIíl&ÚŦLŨžw#LØ6ßēėô•íÞÓíFŋŪ‘3QTĖ.+=mÛþÁī'bõĒ2MOäï+žĩÉÅõ#ë6Šj‘h%qÁÏb8 ĩ\ĸUËĀåų[ūðÁ‰ð ĩ…„ \°ëUûcĘÄK Íą]U˜ evgÐTý1\9Ó0!Ÿå ?°ãęŪS &†šō$áøOˆpV˘ %ĸ`.C<·Ē6LpáánŧúŪ*ų”ŧr…įPÁ$“vuD[H­Zĩš4i"'U[\XŽŌŋ3g`ôĻmĸĶ‚:ŽþôëˆŌÐüŪ’ÍũnųÛUï\ĸø‚ņÏQ“zôMîWÅžī°ØqŅÍķ&į•+Ē„ðģĻ1@AęgĄ[š ķ;:ō†åũđŪ§œm1y'Wˆŋ”õé˜`ŠŠŽSÂ+r[č―n(ū”›mõõSöøņãëŨŊ—āŋýöÛ5kÖ;vLýfœĩVÓ+BĢôÏžĩ͘ĸĨGj!Ļå·4Mĩ{a*ĨļÃĶ*Pė„ķÐkK†ÚãrS]Č 1tTæ Á[ĩn­ëšėÞ(KÅ@)u&*ƒ‚ŒsŌr6'ĀŽî ^ÔūWƒ„ÚĄųB7ĸ­ŽĖlūÝß,wâ/SÞ^þ;ƒY}SÔņ' í<“’R;)U̓mŽðÎ\JFŅ·ÖC……ÍĒ'åÜsŽS°ƒŽŠÜ‚@YĶúꗆ`Ens1U”"0Uė 8S6ęīÂÂÝ Ęļ‰ęIfƒÁ↠öėŲ#5v]štéÚĩk͚5eį ‰žRįšĖÎ;yėÐĄCĮNä9\þ‡nčûķ―t‡.sû"aĻE@ļ;Ų–a*9Sm Qąï üū!$ËīTųŋʕ  ĖuÏčO‰ãâÓÓ3äw[)―T=ŪV)Ļ íÜ~ˆršðīcjQ͚īŊ<ŋ­xÃÆâMQzTtbt­ôÏþōþÉēB‚Q˗rĄŅįĀÞō+jöþ[·Æ$Đų83.Έ€`ĸ•ÏĒ0ME"-Ā‚!Yđ­ōYՒ]Óa%*b=ÕĐAĀAhœŦ|xlČý!āC)ķŨē čŽS’_[F2Áȇęé@ąkŨ.MÓzô葞žžˆŅžysųÔįóIģ`ĮqÎīm7'ķ―úØĢžéÁĄ7?ôōŧ‡Š=CĢĸj͜•‹_ųøû2ÎlĸŸ#aĻ…­å]-ģ˜Į\ĮA6@sd`D a S8Ќ$N!f %°óƒ!įk&'KĨ—˰dsÜüü|ųÚY8Ŧ)<œ{CĖ9eŨŅĢ7ŧĻōüĘÜ_"õH:3Z#ŅGōef‡înĢöŽŅ&_ýúK7ŒŠ2,5{―á“3fŋžþvãč–!‹E!*îî-Ky0Uģ tēŠÂ]Í*š“{žŦŠw•|Bŋ빀˜8ėŨ€ H^ķ x+ <―PIFuZ­:ĻY'"Ø.žðÂģšdFDDtėØŅē,I‡VóԜžrũ–ûŸyōū^[į>ŧhåaŪŅ tŦ°zķ!ÁBĀČBX€Î$Qo\Ã4Î‡mRA@'Ũێ'—âz œäŒƒō8•eSÁämËÉYä20Äąm—ÝÐ\Įv\ļ°$ôķgNCĀRM07hۂTLđ6œę`6<;t\õŋUÍļA9Ã*œ“ðï Ïq=FÂņo‹0ÔŠ&…2Ô[ā?‹ô+vļ1ĀøÕóT!™rb˜ļÉāï%ˆRŠ]xų=OKk,Į’%\·n"2"ą [*@ünC;ύąĒWb'í:~S#ąwËrË B ââkéūĻHÄPÔ°’åæXëØvņf ĩ?F•ÛįĘĻ›1eĻĻ, 0‹D~ÕĐFUđB$0'ŠdYí8qŽV0 SumPė6ÃXßĖ<+]äĞNuŪįʧÕáWË“}Û6lM%Š„ĶiŌĘ2;;;äž.­Ņú‚f=úl_Ŋ–(\0yôå}ŊđīGŋ7ŋÜ ĄôțĢï―ü’ÞWõ―úĮýÅš \3}Fųũӟųځ`ɒYOô―ęęK/ŧlęW+uŋ/X•ųð]}Ūė{įýũ ūë‰ŲŽ[rdúSũö―æŠkŋåī{&kĶÂÉĸøųŋðʀ~—ũé3ėÓÏ>šĐßÝzt[°ėˆezŸd>‰§qý;‹öX>ßū_ÞđolæčáwõčÚþĄĐŸ9Ķ?{ËŨũđēoï·Ž|ųxđ04oåŨ3ûuî9ðūûđí…Öø|dõ7ïÜÞŧOŊkMĸa‡áóïZœųøÓ̆ ―~ڂĨÄį 'æáø·éjŅ_Æ2–ĸãeüDđĻČI•bØ`° :QA(˜„šĶAŠí#MŪ•"C)§Ué•Ā`jų#'–0ŠÚ j”ya™W+­Uåy›]5l*'Ōü5Éūž}HE4NLn\/þ―-ßuNëØ5Ĩąš<Čũģb9ĶeyȧRū @‚({Y—žš&Ũ‚ eķxn›6ŠŠ͋/8ÆŌUoÜÐ39~LŽ_@Fķ*ũ€üÕÁ9—æäädĮqäļ*˞CĨĨĨj?Ūģe:§-þhæĒõ?Ŋ>ŌdPÛ†É nX|ßËë§ö|&sáЁŋžöDæRgÎû Z'pģfÔéMÂ4ƒ?Ï}îõé‡_^ô|Œá4íqÛgwžšō݇'Ï{{ØM—üöþË37ûüjŅņ2oûɂŌ#Ÿŋ2gGÔ‹?›vß-/MMĸōĩ4hãõg;Ũ.^yÛû“Þüîņ?˜ûÁÔ-Ÿ<üáܟôÚĄŨ ÅeۚØãĨĖEƒožĀËÏú|æWOM™ųö­]zfĘĄŧĨÔhøÐÄŊ›Ð-7ôŋ{ÅÁ‘u▍|æý›'ž{w†=üķ!?n8ųÜ?>4vÎÃģŋh}pÚ —&^wŲûvöÞÏū^ŨĸŲ7oŋē1u8Âņoë˜k`é?ð•*kĻÛŨMÓu<9äŧķ€A7”ü ÔKa"Ž# É9l3c;JēOg)3ĘPëšŪ„åĐ(\V`–ō~‡@5ÂmÎmÖĶnģĘóģ]~Æc‘ƒC Ņĩ=ųŲĄ-k$·đ0æąš―įČŪFŦÉŽÍ\•ŋ"֊/ôNųuEVKˆãšBã&tÏÕTE‚ĶÃ'WÍu9p=.\Unā:0Ā: ē{ƒ‚Øķ=ēÜ ƒpJ€“e2<ĶВeŪtĩÄũ/Gí+––AoûWRð+ŠVˆPīŠĻŒÂÕ ËKv:ÔšUŸ·îŋŠKãčï?YþäËShņqĶåŲĒ|Åoû/č?åŠķiŪᙆ‘ãÛ―`ę―Aúāī•—ĨĮ9å—ū<öÅr­€jMí@ášß6]ríŒujÖŋļWį†?ˋö.ĸ>wwōïĘ9‘Uė(ĒAY'6öĀØËÚÅėéÔĐŨĨ_Ųó"gWŊ_W”ęD;ēoų˜ņÓDŅIŪâ‘ēķ7Œ=ôŠō“ņ-Ž/&4nņİc5#N5ĄÓŋ~ã%tūģO‡ä:Ļkę ÏØĩōŧÂã'Þ~ęŸKKOÔ.qĻôÚx`âm― ÏF?åp„ãßeLjG‚[ ð ŊƒĢ:ÉÐ•Þ pËóYTŒrĨ:ĘPČ‹ ’’ā6CGí‚Ē2a&Ôũüly$–Äåqĩ*Ï{ÂÅ­-:éäx 8īĀŊGúM?,ǐ•ŠüÓÞáB~ĘĪ&Ô#T ŠrXzFĒÞ ;§ 萯}9ÅäW1ķ°˜PHK…ðų}āĒ`{Ā Z:sTúâ"U a˜Ð—ƒ'8…Ðω01- `XnQōŸÏ'%ĖR{Ā9ŊúŠŽŪÜÞsœÄšMoņâ%õLAčŅÕï<1iþ}GŋxüÉoL‹F$Ũôĸ°wcąŨ3†ēr‡z·EŊþŨ‰õ‹§ļĄĮįþM {cÉK_}Ī­˜þÖ'}ņuë§üķ~ÍĐü–ÛŋûmËýŪčĻ„Ú-ëĪw}gÎÃŅüŒ [!@…­Q?ós<æ`õ‰įËaÛüéÓÓŋœôŅ7Î'ŒýÅôšƒiZ 'ÂvŅýZök#ÛÓ{ˌ[Sp·.|ĐM[šŲ?ŊÚ{Ž‹ĸВïOŅ>zrƒ&ftÓû_ž|yģá‰øxšJhMƒ^„öï…Ųp„Å^č‚mâÖÅŪ–’~!L!€_Š\„EŠÄõJϜĮÆÝ @ÐM‹Äˆ€W―üüŸeUŌV­_úG{txË&DFĸý ųŊ’*Þ%Ïģ+:ƒ˜äï+#tĒ›ÔōiūΊ·PŪ:M'4 .ŨA·oÉ#dcUbÎ`‘°][Ž5tK°Œf,SĮPÄT—yhnxsŽo!(‡Ž+ž%þĒ Ü2Ėę€ZIHE­œóUé,ëĪq'zÐĘãÂs‡™ūČ8įØĒũ'}ũëŪŦ~{`ðØ’w―sۈĮŸyęņųŦŽčĖ)ņ§=øĘ‡ŨÕ9qß=ũvcâÍĒ/ߛņÝĘíNlþmSVŊۆE|}ϏMŸŧ$ķmrJäËoŧ+šð—ņ™Ógž9eÁ7„aÐP}JyĀö8vÞAæ)Ž ÚÂōGÆõþĪ~ßS°cõ·?ŋ<ā eô,g4ĒvjÂîeKæĖýėˆ[ôí‚đzúMýŊŒyöÉGžzbâ^QÜŽUíÔķýŊŧ:qæsãÞ}wÆĪ‰Ÿpˆpƒ CÂŽ;W‹+Q]Œ Ë2ĮÖp#C‘ķ::Ņr@ 49ÆÝv_„ÏÔ-d'9ömigiIĐëšj+ĸ,!m(4 þAÔ?T|Ä&āŒD™þĘ-ĮĄÜŠúwé/ņ<įïy^ü läc;ķ’ïƒTÖq>Ë"DĻ”{+Á8vvÐ\Ũƒ ` WĖđâžŊNŧ(}S-ËLj ušÁ!…õä"ĩØó\90 Ó0#uĻŊ͛7K/v)gMĻß9ÉŌfeeĩlŲŌ0#ïE§u~ėđÔÚ5ˆ ÝĖŨ―ývėæE-‡ ė·;‹Ä’Ô‹†Ė{ŋųĘ ;-ēmZ\Æ·ūЊÆÄ§=:í›NËVĨuļxęŧÉvlÕaČ “ŧžHÚĻmĸf§ï?ZĻ孟<ígŪëÍšÜúųû-XĩEâc㖠ĩ C3A}‰w=7CŊïxFŋŧ_žÄĻã8Ž[ŋa {ú’'ŋ=ó-YÅ­† š~įA=Z4Nxr+?s\_BëįߜTŨ}ĮŦÓęüūÆ_ŧyĸ~7î9ZČ#SŸ?åÆ-ûŽZQ ŧŊĀЅŋáøĖw–ýøËÁ‚`“ĶMb˜Óúæg^pâ}”‘o„#ĖÕáxFõe`ˆ‰ĢšÅv(Õ ųāsęRCj‚%pß G)ŋ+@ĢīīĪž<`YūНlĨŊ=î†QõþĢ” "ĸ)G1x$ĮáŽBHí\įMþD(iQ(xE‡4*ðÝĮQ 5VļDPÃ2aTíRÓcŪęÞ(8mØÖ2 å?+Į؛kø!4ŠėÆQ:ÆļŠt@éŪUhZ5ĖžjájSRRĪAv€—˜+ŦõĪ;Ĩ4 ĘýIiC‘””$ÖB‹Í˜äŒöĩ™ëĻŌ5N|­ŧ\wA7’Œô 8sÝ ]§YĮ-/m‰k3ÛĄ6ËóˆĪÞŨÜā:Žváe­/ŌĀfĻu+Mc;–-xþĨ[uoûĮü›]ýP‹ššcŧ MÚ iÞŪ$s—šŋyûnÂs<.4m“F`TŦAÓ:`;ÉŌŧõkÓOĢuũ\Æĩ.ĩ„í2͗Ņĩ‹gÛ4đé̓›Ģ§iŅFĢÞŅŅ#-Nnéî_ŋéxë)—4—gË} =oÔS€Š îÓÚ%QîļųwF8ÂPKĐōˆŽX:Q™Ŋād‰†ƒP[ĨŒīŅ5œ+ĖÄ.߂ž)—ŌučËmÛA9öû#ääY)­†!— Æ4+wpmĄëčÝčæþJå|Ģu ~ąŠß EäßC-Ž2ô(@ā…x&˜·JáfDŒmb *LŽhVÕŦ†ŦęjĀYB6Ė‚đžĘō0YŒ+åīrRB­Ü(kР| ËÞDˆ@pĘˆ/\'芥KTxŪãáÃåx`0#æ8Ī" S|à .úŲ”Žcų―æÝÖþ‚Æ–įĀ%tæ’*!\ĮVĢÐ} 0.8ĻrÜægėĒ„4ķŽŌ‡Öï{ú™m;š—ôÓåÂÚŅã\.ē+-‚sōŸáwĖÅīÔDģZ‚<&ŽĀŽšĄU r€2LĐJĮ7ŝīÔšõtÍ(**šwđ(-Ŧ\Ē ŠW•.Uh1s堀þ·nSŪÃû Aäž°Uœ)B­JMĐ2dā"Ҍø/TžË\"4…ĐŒÁnfĘðÏūÂæ\þīĘČ”KžĢ˜á6ã:r@—qï‹Ļæļ"ÔŠk;šøøTy$ũ@ČɊ€\ۛS•)#™ šcô<ģ€X ↯ĩĪBé‚[īh‘šš*+GĪG°œ”ō/Y3&i\AŠ'āŨČŨĶË%ít*˜õĘä&āęÖjÔšnģ ”āėr„#Ü15ģ6‚… Z.Ės‘ÍÔ<Žäy mØVĄm ÁāÄ^‡ ; ļéæžžžĢG˔JN:Ū+ŋíCÃP­v)ēīĨž"5K c{ĘųraóĐ#  S-14ÓĪĐHká@R#cԙAKí’r; @ũrbŒĮŪ#Ļ.`ų]æ‰ä؄k°rWþH3 wi‚AYj•Ÿ—[R\,'ąCšãØķúk6 P‹wÜĀÕZ&$bœë\‰œ­įz0eĒ+ ðŅPH͊bõ3åՉ=rÏ=611žV0.Üóā_õƒw]‡ļä>8ólæ‘ĸôGj…@ãjĶų}„T$h(ÐdļŽ5Ž>‹säPšoÛšē_ÉÛ·ušĻģLĐdõ―Úï–ĩI2·ō’{ð˗N?ķ}ëVËgAՆã`™ē—Ýŧ€ŸĨx[Ā…\ƒ·īžtMà :ð”V—ƒĒëēuëNnޕ“]#)JÎė:Xĩádë& íÛ§DD˜•ā†rAŘC~˜ĨnÉūƒ'SĨEšĻ‚Á‰þĸeņo8óp„·ÅWųŽ@Ą’eZrā9$e>“ *_yŊPĒū–šōĖV:ĸĒâĒ;ķĩiÛVãŠj‰SꛮcX€U“ÆMZ·EĮąO—Ū8―ũ·}›lý#ßÎ 0ÛGĄ=x9#$B/* ,ËÚv•ŋSđi lķŒJ_U°6JŨ™ rŪþąéJĘJË˂YđGŠ‹ĘHÐ+))>™ŸSh—ÆNNiI^iđ_žNAš›kÔ#PV+á?ÂôW"ðģ+B9äŌ Įĩj%_yU_?$°2CkútUĩ`;6T1ût9ŽZ.Ÿ…dŪG)1ĀÅ^ >ÐđRƒéðPMÜÁšĩĮķ.ËčÚ4đVŒaj(‚y9Ĩ[Ũ,,ΚŠOÔ]€IÛĐ-?ū9oÅcÆ6­á#Ĩ{^xqQĸG†§'ûϙĩBó_ûČcō―ÅÝëÅģĘā3ķaZĸ ÝlAÞŦë–a„ Âņ?•ÕęšÚÑ(#Å|ķĒ!zfƒMŸ|ŠvŪš‡í`)šzķĮ…whĸþžž\Y­TUHŦô !ŊīpÕĢcnOïõhÏ[žúzį—ëģ7Ŋ<ž&7P,ŽĄšew\RŊĩfčúýĶŋM|gzė=BĻÃDA)ã5b#bˁüâÂÂâĒ=đ KˌØäÔĪ:ō ĢõČHÓqŪõSüF„OģLÝ0Đnif‚ߊgDȄės T·͜s·Rxžį`ČzbU9ķfõŠ}{vų|Ô#`đŪR/č†Ķ>–?hčŅm€Ø64WýDQbę`đP šZzð@ÞĶÝų=/ˆNˆ(ą™î4æþļč–5ßžtĮÞ}đ-[$ãí )9•õËÏëŊ{Buņ þąbUáC5=~”â™yķ‹b5Ë^’Q~Ûm@„._ĩ|ĶúĻÐ9-p|ÁŧoŨéóāåéĩ%·Ū–‰ŨÁąƒ‡Ú”Z–OĄąk™ >ŋŸq0QéąĨHŲP•lš%Ÿ&_ĒĻÁ—lîũYúÛx8EcŠÐī`öĄsģmWP Ü€›R3Ä)[ðú”ÃĮôŪgŲķįSoČáÆƒ„#ÕÃÕĒ0î!…ĐŊ Á—s,pBy˜q"BŪgéʎįBu™îÏÍ͑ĶĻõë7TKīRϧgÍH”” iÐĩëÕŪsoûŋž@VááŊķųņöEÅ~Æ―ā‘ƒÛēÛöāO(qŅŨ$ēE·„î+‹–“rýԎžŋu˜/ÁýtaÞņ‚KOŪæž1óîņ}wķˆ:s6(îųĻJ$ˆĀŠ.ėýe‹ r―ąm[fßJðŊ+[7T’7ĩ­'ũýķnÝ"T°ˆ[\.1 0ĩ唂>ėҌ†€’đŽW!Ây\u8{ņu›Žųë$ɟ˜ĒČõvíØäyŽuz†nÔįKl\gÝĶÍÓ ÄItüW" fž>Ÿ/{ó 7Ÿ$§Ũ/ü5ŦũíO<0čŋWļpę―o-ÉMo֩ȖŦ,Vrė­7Æ,YŸ[Ģ~Æ ãžnųúĐį'Džĸû‡Æ―ŦëÖog?=eA\ZÛį^Û,Á§ôT7ÜĒs§?õåĘ\‘”ņŌŦÏ·ÏŸ4>óûU{’RŊ{æ•ÛZ$ęŋ/úh·]kËó—E|úąŽ·Į}yĻüú‡Ÿ―ïōæKÍ9Áb—~ģ +W{ė•ĖÞuíÂŽ§F―ļqωšuûÏžģn$ĸõërŒZŧ~ļ6Ž—Ųģe ž?fÔ'ëũÔí5,óĄþĒ=ïÎü6ŠvîW ŨGu>éŅsV}:öõ7SÝļgäĻÁ=k>óüļ­YyÍû™xOæ„ÛĮ‡ĢšļZÐuYĶÏņ\Á<;wswÁĶ.à :šNU?åg`š&ĒŨąŌ4čØōɁ}{ ōĨóŋB(…°UĄ§BĶ īÛóX̘īĮŧ=*ß/såÛąuükũm^yhgo_;Ã4"ýþ8#~PęÐÝ%‡Wn8tyƒ+―ėŽ`YYNQ^aQņš“kvåėžÚq@Ë%ų%E(†Udˆ((3*Fåą’ĘĮĘh(°ī|Ý―cŧįxšYĨ}„fi!A‚œä(ÏPfĩŒ3uIå?ÛB1Cu@í‘…uŧ·(sĀį‡Å_ϚôšāžïMƒîņ g˟ŋwã6ĮqMËwîžØ0Ëē·―öŌī î}ņþÁõ_zaHôŨūûüžāK“Į”þúŅįûO™dy n·!o Œįőģ—,{äÂúm“ę_7ôúéŲkŋþėĒ'§Ž+X0qĖøOfŋzW$ᐋü·2GMZ=uėØÛŪE ÞzüŽÏóšLũâOSŸųāķų―yxÅü1ä=ýÂĻ”­ïūšÏ}ĢF_ŧôÃSođtV֊ųÏ}é{ėÉĄMö~~ߘņ_LvŲļ;·—<;nøũ“Į>ųJų›Ŋ/zčĐ;n~ĸũįwšðČŌũ_þðpäļ ÏĖóøĖ†-ïmņÚ âÖw ðބĖ_ŪŧĒOƒæÓRZßqũeĸôéóëŠ^}}4e–†ŲpT_GtS*~ØÕŅt4ĸv8ZvUļĻ܀;2pĻ觐ĒûĒéšč―ĒG9pā"éđĢē58āÍáÆŧíėgäĒԎQÂ2âMÍ([žzIv~ž”aĘAMÐ*ķýK§Oļjúž{&ĮßéüÜâĒ’ĢG~Ë^ŪđtX‡!ÄĨ!Ų―ÂvŠ…ę€Ŧ2œûg ęŒb™ĸŪ[―ŠļĻ[éŠQ.ĨÐ+H‰‚Õ!įŠ’X@2Δeķ:ũhÛäÐ―ÔJäË{=ât€Î)]·f•]ZėĘķnZŸuŠčt€ +ŋ$2“„<ÐJ˜ÏĄˆ.čĪ\3|î#CŊzoŊu—­Øšbïîžŧíę‹;u_ģôšNЎŽYŋNiîŋ,-aþēâ`z­[·ÉhÞūKŧf‰;–Ūܓ_ļö—oŨn?ļ|ŲķbÛS ~éņëŋßüäϧûõęqŲ—&GýPÐåŪą=:vūwÄPó螭Gó]âŋäÖgŸļwЅ­[vôÜĢ#ŪūļK7Ȅt#ïõÜ#ÃoxāþaõJOïÚķnÉoĨŨŲ―c—ûF =īiëöã5>2aôˆ;nė{MliIIyɖ_—:þíâ_NDÚ}ļ„‘ĻæžðüËŊŧšC3RæēØÔf­.ˆËč|YŦFuĪĩČ?°}þŨ?“Ļ8VS„#œÕŠÍ°}ÂUD,zÉú”_ÐĻ.8„XB3@„Ë=ÃgęDÏËÍŲđm[›6mä6=ÁĻĘTĶÔS‰Īrŧ_YüŲžÓđ^§ŽÉ­—ŲÝ0vݞĩO}ųāļčŸå‰~býIõĨ7ëЂœü‚ÂĢ9‡d}–UxīGƒ {Ķõ,+ŠØ‹Ŧ|ïŊfT(âẌ́š„fTĻą" *įŋēgŨÞ―{(§ D)ވF°3#ÚĨ›ĮK§P5įšrŽ€đZŠ5A孄þÕ\-ņûhv~YT\īϊn~A‡uK&\4i•!"ãōƒDČų ‰‚úhZ\bRD|I~€QóJâã",NHÝŸPV’CT ė’;hûĢčšųSž·ũ‰Gnl°gU€‚ĢBÐÍuDP]·š‰)éÍ3âÛwļĢv“$ zˆ šĐYīÜ ž1ą„ßŋ͘ZÏvå~=*"‰·ÜõÅEÕēą]y6õq3§ŠŨFĻŠ?“ŠÃ]›cE‹/"9Œä]LJą§|TRj“vm;^ØþŠ&-[ŠōmÔ2"üšķAý5ž2Gb9—ËÛ_yĸÉ4ečý+ūúü“ĶĖ ŦÚŠ#Â―Å 2ÁqąF <–ÔÍ26žą ĀĮKplxVhLĢ I@‰Ža™:Õ]Ũ‚ïØąUķ0Mã,„=o+ģZÏó"ý‘+-ŸšbJŒ/ĶwÓË|ÂljoąrÏÏ~7kĮáŌįÖuÜ cËė­ĻīäT~öęcŦæø`{Á3/Këæ~Ũs΂ōŠJÏÄđf ΙáJĨí†uk ōĻŪÉXĶ ‚—…3ÜNDR{ŽP4ŦaUÍ\L? Ø8đÝLýÚ~žw,!ڈōé}ŪŋņÕ)Ó^™4y與"}FBīŪ—æÔ­iš–|ŠHLŧ SĘáÉã^üîįŸÞš2Ûé˜^7Î0#Í­~8kւOgūšž,æ†+:·oŲúĢđģĶÏ~ũá'&ŽÝ–oz°0?;Č=ŧôøÉ㛷ŽÎõĒԏYþÃgŽ9Ųîęk[ø·o™;ïģnƒýk.üėÂoŋĘ|ó]ŦM—6uǃen Ø…ëæÚēØP`5-xQŸÏ |3ĸ•ŋþæĩiï-ÛuéÔíÆūq_Nyõëoŋ|ý­ũŌ{t̀Ý@ĀÅ_`Ģ4_ôÅ7ßrdĸ–%„Ø'Nįįs"œŌ2ĀUÁíō287_”ß-ý|Úė'rv­ĸiÝáēzŌÜ`đāZ55Ŧ G8ŦUõVDåģČWBrËЂbE?ĖCÏB‡ŧ:Ęô•!, T@Ó3PZķ{ŨŪĶM›PŸįÍj!ÔX­ÖŠYËoEä”å–öhŌ=zéœĒ@‘ijĩšDČ_zĸûïļ°ĸÐރRk•Iß钒-'6ŋ―wv čR4ˆKđĐM Á*YTÉėY8ĘsÏĸxÖē^bïÞ―;wlSĖw]M. Ø—―ĘāŊĻŊ :ŽNІâ.:.ZĶ…ō†;éųŦC7ô6-ëYąßlEˆŅšKwJH™KäcYđ}tO›ôÓgbŧÏĻŅėĄįí­™ÓĶûjķœ6fh’Ar<žØūîáÕßlbÞČ :ÕŦ)Ž|üÐļ•ß-ïØeČ éeąÔhÚĸށ{2·ĶÏ ‡6/ýugĄyóíúÅâÅŧšžté”Ėņ/Oĸä―$ēCĸkĐú-授|ïØ`ÁŦŋ-úRŊ™ŅņŠkîxvŸ6éĢ9'Õï1éą§ã žÞ}€ŸÖbŒ7iÛãú˜hÆXrZŧëŪOō‹ræŦҰfܚ%æ‰SĮŒh=ä™wr'žöáœOk6ļô•GîˆÓÝ šßTš/ŠÕĻý•—đcÝŊhüĐÉ.|ŸÓĻëîhŲŪięõ$ų8'1]ûÞRŊ†Áô˜›F=l֗vũĖ0ė_ūú‚ic^—JRްŪVmsđ ˆē'5 ÐDw\(KE%āhŦĻUæq‚™Œ3}bĘĘJ7mXņ%—Čę{Îye„=wz‹héÚ]Óšķ­ÝÆc^óZÍZÕhžžp-5Ėr'&E”dOX8ÍHŽýpŨkóŠ NæžōJIĪYj  ―hHýø†'ēOTaΎģöëFÕ46īXąīëÖŽ)Ė/0tDB@ŋKŨ!ĀŽĮõ˜ŽB ‹UMŽƒžvdP•fĘ’üÕ‚$#ĢņĐėÜ­ŦĸhÕíÂĔ$]‡y?#…9ųGWŊkãķoŨ 9eĄüak4é9eöĨęãsÏárō$ã zŋ6ãáXLGƒŽC"’Įūú&ÁP:-ßj›óÆíoó[Ī ˜õÉyt0č4ļðšđöSg$ÓK!pÄ=âK1~ęˆ ßš 'ę =mxÅSÛaâŌïė%Ü ÍÚ^ÚŊc/!ߊNÛ+ïîHYyN ėtŧžŊŒÖ’VŨWĢĻīŅŊÎ ’ÃÍËnš“2ĮvÝzŪš­‘Ú&fߟđúAu.ā`1lĖS A#‰7ß?Ũōķ—ÜōáĨđįrÚoQeĖAĮ#ĸZ„#Tj•ŠÎĘǃQ>žčëŊ"üv˜æ*;mÕÁE7ÐíĶUý‚‘ĐfPĩ5TŅÓ@äNŅ1qũŒļĸĒ‹:WFŪšÞJ—U IAÉxŪ$~ßýÛ ™3ýQriĪN…EģũúöļņõëĖ.Ę;vúÄá“Įũæî9Tz$Ļ>ų^,‰q\'$ĻĻ,Ļ<g"4>kFŪfBОzõęįÎ.‘ŌaráRp/„ŠĢ`Žn 4ŠĄ<ƒũMuÕGÃncē:ų恃ÆOȔV“Ãįó8áoذ<ä_Đ ”–.Ûļ=ëT|jíÄÔZÕōOåæ9ÚžnRũŪmjğ]œ[‰īÖu=ĸОͧEŨvÍ,­ZJϐĻýïÂíXŒnÞŠq" ũŧ Įĸl†ąoß~!DýúuĮýWģZåDĨšuŦ*~Є ZrąáģĖāļ*ÞU=š…@įo]ál”9óˆĶ›–%}―6oÚÔū}UäZ5Ŧ­Jã*ŧ?°XEЀíÚíŌ:īNi―#{ŸĐéåž§QË'vl]ŋŪõC9ŲEEqĒFK3ķmûf‰þåeå!Þ@ Bï2០šŪK9ÚÆë$Ίj‰3Ø,ššĄ[pđ—bšÂYĨo`Ū@oxpîiT™ĸšgۃĻĢ™Čψ+zwi’utßūÃG7l‚ĪĪ$u―īm“& TļsSĐÕc|ýf—5 ÕŨ}KüŋĒ7ĖčJãėĸúĘ|ŋĸÔu7€š‚ŠQÄV°?k€YÐ]9əaÂ>˜2@ږjó€·Ī„3Ļz8°wT}edd0ÆŠ’ģjæŽyÛķvĻUÅ1ūĻŦÚôÞ°p‡î‹āT” V#9âčŅŽq‹ßŧ)―§ J;.ĮuĢĢĢŪír áä,Ü<į ęX *+ ŠjĪýëŪmÛĮ1ÂV%šx刭(CÐ\ÛÛ3Ãä2ĻāhēÎđPíuŅT >™ĘmIõz‰i͚5jŅĒąĶQ•ks!ãOÎĸEĨxRáøßaĨMŊ ÄY^Ņ ]Đ,Óļ‰ UüŠ{ĢĘæ4ĀY—1j@_bæĶi”“'ïŲģÛó`›ū*oŸ5/ŅVđÓŠķ`5ęĢų˜- ð‚"ūfDÖÉM3V-X}xӑÂcĮŠŨIMŪ§ēōsVLĻwŪŠ+ĻšŽęKÐ*ĶŽlÕĘųyy:5@ËEe‚p‚šYâĒZ9ĻVÃ2L1N3MĨŲð.:á―­Vƒô—prsó>zčБœœ\ÕOþ?ŲóEi64ŽþĮĸo# ĩ2VMIĩ° Úq+Ģ/•Âly °UWŧXĖcĻvŌąĒ_čv,RBėˆģuÓ&đ›ĪōåĘ% įKĻõų|ĘŨÆvÚeÔmémŽŦ`þïšÜ—`ėõÅkĘþuMáōīFĩ9ã*W=O%BÕųs?bT&=öïÛŧkû6ėȀš-ü!ĄPēėa94ýFÏIčŨbęŠFã\ꎕ_$Q ä<Đķö•7nÜšuë^ Y*-ŸJCË*ŋŊšių0,Cĸ·1ĨđíWpŊīļČaœ„#ĸŋnx)&T‘rĮąuČÃ(A+9ī”›5š)ĘÉ3’Rå'ĀäĢŽûþ€,ŒC6‡•ûũïÝ―{wÝšu•‰xÕLķęŒB…Áæ>F|L|ßö}6îÛ΂_* ĩŠÆTUážWzÏ~õ“BąŠâYįĶŠÄY”BčŽ$KŧzÕŠÓ§ģĄ™#ļ( ˂O+Đßo9ŪŦSM`[ITpÃ0°'LÛrîxĀÚbĮrČûņØę0Q]—‘ĸāøˆöp„›“Wˆ dd ÅĒ4Ä\O@…ģÁ™īŠTĨ‚`‘”iČ99Ŋk ŠÚīq,ëNāžQ9―u'ôī4PÖ§Ýeq‘ņ·z‚x„ĻÜã&ÕG\sŊc;gÁk՛åĘïĸg B)íŪ]ŧķnÞĪ~\ÏAGs=ī0'0%H š â ĸĒ›WĶāļ͈L#ß1ÓsårO՜ņ—[•6YâlŧvíĪA;ā,†Üi”]Å:vė(}„sss+ļMwsö-üâĢÝĩ`æa#Ï*ĩLM3|~ •æ2íĩL5cęšïĖHÝöÁ†%_ 2YöûäøĖË •Ēō:JßܜãEų…Tļ'Š ŠÁާōZýĖZ )ÃŊÂgâ*júü–åSsšnœ9yXkÁKĄ3<ëOû`Ũ˜ĶïÜkācâįRW@ÍPMļ§?ûA‘ gDõŠ—|†Fþy„# ĩ‚š TĪęPĶ)>QÕĘÅóäž9,ėķÍ)ÞsđXŪó˜ŠvĮw€€Ū åÁōÛ·Ëæ ”jįÁÖĘ0§6̐Ó4äØõœF)š&7Ž'<ŽVY‚ŧB8+åSÛī–ô‚cŸ“u­gA’ŠóĢ­Ūë2ŋÞ°~]!p :ó.-ˇ5`P_ ;„ŽŦ„n HBë^MŽÎĪ­ŠÄs]ÕĶ .‘Ū͉ŸąZäēýļĖI;vQ%d{ąúõëËĸÕĶČsę4öāč9KÞėÎ?TLuŦôøę3gÎų&ÏÖ Ęn_·nũĄųž=qÆžCÅÁUóįū1yæŠyšĄÔYþיŊŋþÞ+ʄ/?kÃįŦö‚//%wnXī|Ŋi–/ýrJfæÔ•;ģu] a§°‹~ýjVffæėO80Åå›é Ū-$mU ;ZyáĒŲoËÅ [ëę&ąOΟûÖë™o|ģá 5MâvŪYšwŨš93ĶĖ]°žžäčžw§Ï˜ýq^€éž|ûę?ķoY6û­‰oÏûūÄÓ`{Øß|6/óõĖ9ŊqˆIY`ûęĨûũmš;sęŽåŠh^úõ'ïffN\ū?Ũ0õžŽÍ+w^ņ͂‰“&/ߓkęîڅģ^œðjæäÅŧޔ؅?|wō뙓—ïÏĸSv―áÛÍPJQe$#\ŠxóŦšRl0 0ˆ ' .ÚD„WØ5ãL`ŌD <ŌÜÓ9RõÅŊlõrV’Ŧ 5Vf†ÐöCĢúČk‡ąŌ24Ėb_T^dL^tt^TÄ)ĸČŦFÄGĮ Bþ‘}Ė9ĄüÜtíđmĐ Øše#8˜šžú°ķm ü°„€‚< ÏŠtár™hĄĪ]:UĖ5AšÛu<”!ƒmĄËR \-cL&­’:·Jxž';“Kę\ŽC?čóōeÉÃÎ}vrRíļÂm?ōäąųŧ™Oū4‡™ū5 ^éwõĀïŨd­ĸaÆU―{ÍúyÍæĨŸ<ōÂkÅÜX2åþ‡ĮŋĨEû™3zäØ ų9;ėąÍ9ÔôōÞýȇ{r?9rĖǃQfΓ#]w< 0TÓÍ`ÞáûOFEŌŊf>ųÞk 1ĸÁ^™!ŠO{jÐøK…Ķ•–KŒësë'?œˆīō2ïúî{ _pÁØþŨ<2qã‘Ã<= ũŪÚēáôf}ą•˜öügûũ{jÚæ“y ßþŌ;ómĒ-|ãÞq,1ĒĖïÞ~üÅwæ…3ĸđþŨ {ymÖÁ^zðƒEM“-xý‰ũūßgą“ãîxsŪvjõGýŪî;õģå6/|hÔĻ“ •Œ—åxNΞįþGq\Œ”BŠŽp„Â8ONĪš`ĐmBD8ũä,B§Æ<ŽŲ™&8ņžŠÂ\hÂ0đ`ƒ-t˜Ö<Æ(ūƒĮøĶM.ïÝ;))Đ2OZĩ„Ąrxžjyāļv—V]/ŽŲmũþn iËŧKû /éÔÝqÜĘØĘ’üsʄæÕļ*{‹“!–v…Li•]ŊŽžģg 5`ū*YWB*ynPĨ KˆiXŪįb3‡Ģ †`kKέąį\š4H_vIÎV͚UĄ„ĖÓC%šßÏo~bÐåGŽÝ>ý‹~ą?Ïþö‡e/ŨŪs:ŲXļâ·<įoN9kŅyč[“ï]6gÔ֏Nū2}ZÞŊ3^œīž(Ũ{ïŽŋčåųÞ’~ đïžQŸäÝ=ëúĻ)3nnŅmëϧã?î“üÐôßj_ņX”ˆĀđģō/JMå@OđQuZ\wąsē$w―:ĮŽžúĮŌqr`ísū,œðËü~é5—ŸÜ8ïÓb}ÁÔÛÔô’íá3ĸęÆ+†™5o―ĸđįú֛V°sWĘ―ÓÆöZ8ŲýáØ7,ôÕ6ō•§Ŋhš9Ýũėĩ;Ūh:gÎÖ[į|û@ũzWĨiwNüuĮ•J}‰7Ýóė‹76™QļcĮÁ}ĨÞ{ÓŋŊ9|tÝZÁCŋÍûuóą+ī`­—ū:卄‚ßïžųųÜ`Dũ~ýÚžyøĢweDdĸX–[\V\/―į–5Âī?aŪķĒĀ ÃV=É•É1ĮvX€­„·B€ÆĀŒFp,‘B:Tærô]\>”ĩe˖JĸqĻW+ŧj) ‹ŒˆėÓ―— ū_2nÍŧšuęƒÄ=ŋlŦjŠģŽŠ”üęŌ—vû–-ŽíPŽ6ö\ՇQÃŦį†ĨŽãėëÎG›ĻfCē…Šđ6dæĒĒ’0ĸÕA1ĪÍĢ}ŪP]$*_Ŋ"éĩëčũEpÆ 7d,đV­ŧn,ä<Å`•ĢjB}þē1™.[ö‡ė8yÆQ—OBĄēÃuŽØjšãxęäå EĘë/āAé \Ča™Đ+Ü·ĐsžÁ'―‰Ē&SZɌKÉGՆ:ĘÆAî•ÉQ!å<*9}”ąoūåÅV ïŽß&Ã[zÅ-Oũï—[P}(ĶĜÛŪS&pŒÜbuïā­ĸüã#íýļ`ÁéĻīôņ‰―ŊŊû^Ÿ1ģšýēŋ ņÛ―cknōu>s°/pʎÔÔ­’Ą{;ĸqwíSFžõÔ°ÃŲyäãî*‚ )Ž9ŨR3.ęXoƌw?Ļ9ĪköiŊ~lĢä“f/ŲxwþÝįKZvÁÛöā 5f{^9W%‹P'bčöéc?/øĨË=ß.YÜ8ãÆ&ZwÍŽ[īäĘÚ=-ø<ąÉ­ëÆ- –ãáš<ĘaˊIë~eÃ}Mŧ{ėvVpJ‹ķØĖ.vŅŽYOŲ3íØwĻQ‹Ļ{ʆŋôV˘k^ûbåØĮúEXŽóEØD‘1`$ĐnčĶ.ļP–ÚĶÏįyž’hgŠđä<Ė@-ņûüBmņ+‚kššÝ†4ÉÔAÆŋaݚÇ[–uEmĨGÕÅK=ĩ§ãmÛĪ·`—SqÏ ÛëĪÔV)­BÏóXzŦ·=Š[ipđcĮöÍ7Á-ÓĀū‡š’s‚- R\-Ę7 ĢW’8"t |ÓĄ•~įUρæ[(žPŪEéïĢ6ūBxZđîÐĄC’ÆQĨŌ`Ō™ÐĻYKŋ°ã[öyå…1[>\bī―yęŒ[įz]ŋŊÍúÔÕ#ëĪujZ?šs‘XŧI‹&iœóčø”ôMLĖÃoĖh͗điČ;œW'―VŨôĒęe\zËÝŨ=uG›ä[Ä=ýÁŽŽQŸÞvÃu·ÞõāΜ †ĩČ.7;]?ĻUéo{āŲȌÞĨ›æĸt0§v―FMë$R#ūQó ŅÕÃĖsĢÓ.zeęĒ•Ü}ŨðYK–iõ/y띧7ū9rāmoōĀč}LŨk–‘ĐqŪ§4j›š ØkÔnÔ0ĩ–`܊76ĸøÝÍýŪ|ïčĨGŠ’ëuLoœNÄVL› ZGé"29ýĶSõێc;wkŋþïŽōWúõ„ãü훉~äĄû—,^Ë@ų)”G™(ÕtĩÍřgš>.g ØðšÁ+ĒBŽ=Į“ģ˜kÔ ĀEÁŅMsØß†2DačųÍBĄˆ E/&Ä'L™=sŌŧ38óâãâūũy­Īšr^―aUû5þ§Î2•ÍeB)­ü‹sįĖ^īðKKŨ=åÛ Ø ŲĻę…Ģœ%rZä^ Ëp= ãš\VĄĢÐág įQ†æ ōýođeÐKã_•tð_h7ĢØƒĩkŨJ‚Twa?yâĐ%"Å^;wŽå ōnI:W˜œÎuKãCE ÜŲĶN˜ãq\K  0Čų4Ũq–vyĖÓMŸ\ÂÐ5úæRn+g,EķļŽfX‚đLˆ~ žÔ‰niÂc„cëF9ãy Čæ˜ŲV{™š`ā%Žvõ XæŒÁJī› Ð­Ųģ‡?MĀ[MčpÛEėžŽQ7ÝŌqÆwĩŠt%ÐRĸ4* ÓĮqwmĶš@ĒšBšA€&ŅtÁåsÃŌļí2‚] ]Û_ õ9&gŅ}šp―pņEØnæŸCmtôCũßũӏß[ĶOÝÁY–ß* ÃE+[ÆpˆP_p —]†aĻŽåšŽ—Ę'b Ŋ S― t]6|æđįSSSCPr~ĩ€ĘCÕ―ž<Ä2­#ĮÝõćđč=OÜ;’Cüs§Ū?ïãĨĶiĘōŠW_yą ?bþN …Â8B*æģ'ÂgY`ßۊ2eáqŽÁ2 ĶM9I5rĶvÍ8Ð―Áōō7ßüĘŦŊWƒģHk7mÚäšŪ,aÞäŒlĨ.óY9~JöÏßE]™?jwņŋ―@ŲØ eũ'* ÄŲŸ7„]üÍ_ÔđvPįš‘žËE•SúŦ>ŨyÎ&agŊ*!˜Ī0. †ūˆš4Ūėö€ 6HiîÂS‰2Š{ŪRmyĘåÜY1åüÕžāŽDÉ mg<ðõÂŊšvïҰAƒ5j(6öIșPNŊ%vÉš#kŧ5éÞši S7nūĶŋiķãĻ•UÅUgBMnB3j|ÖQ`âUVķ|Ų%ÅÅrđžÃ91 Â’w…­JBŦM Ó—ŠRýÔáí)"ąŠŅt K!Ā8­šœ―âããeę*é™ÃîÜđķ­ââĪĖ+---""âOaBĨEĸōZXpžŲ?ũ—ÄĸÃųQ_ėĩw…ęB—Wýãáį Ãl8þ;\-Þ 2PŋÂN9ėĨŦ܊ķ ũY”hŊŸÏô–KišYQĒZa’tlžå“ŊčgĻģ←ōēŌâÏ>ýøĩq/O2ųũß?•íyĖÉšFŦFĨÍ.Ó0󃓖O,*/ė{Iš6iØHâė9%ąU'Ïc.ĢâŽ5YRx°m›žĮĮ—ÃŪĀ:lbãqč§ 0Wîģ|hŧãaŦ ļŒ )3 KŽ5ðŠœ3.#äŠēŊī•ÅK͚5ëÞ―ûĩ—\rI˖-###ÉĸĩáōŲpüį)Ļ| ›Ęƒ6“0ÆYЁØĖŅ#Q7*ʍytĮv­|p€C jįĮžęĪ 4ĨF}†ę`}+[—=rxÅŌ?ę5ĻQ—níÚĩ—!ģ-‚QĩßĒ’IՋŦ;îŠņōMJ‹‹/ŋøŌģžZÎĘUÏŊ1Pémå™›IÐ4réïŋgíß§zYRTŋ)ÃoÕ#KÓäb{ĖãØ·F„PĄQe݋~‰šã9‚ ÓgÉĘ}ïEEË4ŦĩŒ^Ý TþøĸÉW8†Z–€„š„|d˜gš Á…į*5°šßÃķ.”đ^EŠGσđ˜+pCÎ˕u–”:čãđUIYņÎíÛöïÝûÛÏ?7kÞĒ[ũîí;tÄĒ”"a—~JZ†ÕŽfóŌ@Đ]^~qŨî’―­œ‡žĮ”öŸ•‰ ]ŨWŪ\đaÃ:ĮsåÉŦí,B !@aÂQÝnäܙ9ĶĄŪK%ÚšnĘÅĀb (ã.Ā2XCXĶįđ h°6„“jŽĸDl G8…đÂQņ•čųÍ)ī\0éŽŪ`!ĘëtJ•kĘûaąį!…Œæy^û CĶĖÃĄŽŋüüݔI™/―øüóæÉJYïĪū!LT~‚ đ―ÓûōÞUĢ!x=?] ë˜XbāyBž.‰é†#iMéŌ"w“V,[–}ōÔũS e]BĪĨT5āR=ƒ!ëĮ3”3hîâ‡Â?ĄĐžløC ķP Ž*wĐjûĸ$ †#áŽóY.°č•U8 k†œi%†nšĖSŽB…_"ÖāžÉžEtfr „!‡ ‰Á2lŸÃ%<J<øI&Vø-P@­žÜœÓŲŲ[7oübÁüvԁęÂNŌ›ŠQĢF mQ҇Øķ-·wŠķhĪgĒŠô ÔRLĘŠ$R`Čąã8ÅE…r&7'Gþ+)+ņl§,PV^`ˆėŒ_#`ŪNm˜–úĨĄļč2P€Qu%ĶeŠæļ\pŸÏ6Œ-D`°P€šĢXf„#ĸ#ėWKgĘÆs]Ĩå’32õģ|ŠÁ”ĀU‰'đŪ­‚˜ĘŲ‹"ú(.•ĒUāa&Z71—2ÕßPŪ2}†ē­Ņ-Ãs―“'ŽŸúæÄŋþŌŽeË /žH 4*Q]Ũ%i’’"7Té 6Ą0Į‘c ĮĨ21.-•đj^^nžü/eēy_*.(ČwmWÓ5đB"#`šîđžnhÔLUĻÏgyw™ŦRc…v‘+@y&Ą―Â𠀩Ė™†OÓϜĄļkdZ>ėzí(,æ˜J• cž+@x ˆčĘŒĸ―+Øm*ˆxlŋ7~õ‚ā â|5BEâ@Š„€JÜPQÕRĩ É[{ŧØŧ)?ŅĖ*ŅFIŽwYöxŽ:TŦũ@ĢÖÉ –eũéã‡ŊŦÕņÛ7Ÿ<}ųęuBvDĀRJÐîvŧÝ$֗—W..NO…ĐUdĐŧmĻø·›õudŊņnf"2˜˜€Y§Ô™SëËšX§Ihï€ūŪQޒKģĨō9.ī,eo‘N)öGZš2ˆž™žƒĖãN“έO2ˆ0˜oƞœFqRwĀÜ9ŠíYĻŧ‹*(Đ3îDÄŌ-Y›§>3·%4&0“íWp§•x1KΚï[Ķ{MXÁT―ÛŽ03ļšÂnŠĮĖ™išfģĨÖ&ŠĘž~UïĐũčjõßŋý<9yĸîøŅŅŅģį/BĻp~įüėėwíöïn―đÚe·ēėŊušÔÝ,,RJ<á/}ņŠÞŽŸ"7w%Ī’483V ‚åÕX“‡— Ėû>ŌΚmĪF]Q‘hÔ֛ŦÕį/}2ēG4§.AËÎ[kĢ”‘ĄŠóTŦ1g`ûĮÞß&ĮŪä<Ģ(@2Uûĸ\o[Ę$qb‘åxî,ŪÞn‡\’ýÅBâãq3óŊõ /ë ēô§—ēTūĄsƒáœĪ᧊ĒTk­{?&Ō0Œ’8cø"0á*_Ą‚Jbđ{ÎŦđSØg 0wnÞyį Q<ÝŠ=/—‡ ―AŸÏÕș$eÐPķáY9ēYũČÎS _FžÞāŽG%`tĐŋÉâfyūŦ-ÏQ#'@+ËÜ(A_빌Š—eŦJPŸÏĸ}>U āó―uhĪVYĪģÁĩŸfaīėuûZŨÞgbđ=šĄóÔÝ@äNHœĖ:IiŌØ8Ý[S*Ž›Ūn„ĻĻŽTußð§2gƒ&;­Šŋþ“õTïžóŠ―"ž4ųc­u*Ŋ‰ųiAī!Ŧ<ÂïpÎV D‡ØÖœ†đY•Ž"•{z_ĖUJÍ:?ûLöŦ ûþ!ļŪ8gïģûnžįœéHŋ>U5AšFŧŸ§ôï›gŸ9ykwVfö㙕æŸēÎó<„MzHUÓÄ'ģķŠd8-1ū‚nC[3žúÞ Üþė-āŠ‹dVísOt­: ášVã>ÜÍmýüü {Ð^ŧYh§ýgņÎ;ïüĩÆ\”T%Ýũ9óõįZÕãĪÝÏmĪ…CŠ*6 đŸ0s._ûŲ3p[Y%Ā˜œ07 ëÎó2zļßû†šĐKßƜTIð‰;U}^gnûđÛ°Ø+ŠTã[ŦJ-üyî&” ›dfįŲčŊQʆõŋïĘ1§Û~žđÝōŦ?Ý D‹‚ŲŌöhÆiNƒ*,Š‡ÆˆKĐŽ hy#x(~Ũjc]ž4ÐWĖ2þĩïžóGkS2ģÏįÓ2Ž2N]ÍFŧŸÜĖ-••æƒģĖØœPæN‚0#%œo8–ï–”šûZ_―ÔÕÝeį<ЌÎsĪĒYĨRIúƒy· ę˜]ëãæRđE\Ũްī3ØŦĶē7aŒĩ$ jfw7G1üFøåîäöTw…aöqvþ›ïĮļÏ9f.âä俐JeîąŪg?§ ˆ••ã4sóį<"Ö(ÓØ ŽwÞyįŊAmƒK­eĪtóˆpēhÝ{gûSžędĐč6īŌ4ēsV>ŨįZß4qsJÔ6·iÄipô“9!āý‘6đbŧ…VĢEÍģÉN/Ž‚°ÖÅfģĘÜJyzõö`æV‡į6Œþ|õ·J -ķĘĖč5ˆkfkï=FŒo%ûũv―–JfD)Ïȍ‘ ņËWũ=n>rãQ;ļýŠĮčíSøģœ4V:ģ°ÓïŠk€ûåjßyįÏjÞSÂw­ģ@˜k·i+VU m°uDöŦóŋÖEã―oŠ–™‚ČވwJ°ßÔðßķĮŊaw­uūnß0‹iî2Z_ĖįŲÖÉcŠ‚(e\ëdVöãđÓ^ܝvŸc=ØGŠsˆAöčóļÉâŠðj Ūvp ěûšŪ<ýƒîæąwĸ‚Ũ‡Īž _>1’ėÚįĐķ,›ąēÜÂĐ-b:ĖW\#ÏĀ;ïžó7 o”đsœOôŒŽŌsoJnþėgïgzh@fíf”ÅŊFęŲ@: Ϝ ;îSYé_ûėÓ_A§{·Ė,+Ŧdĸ†ßļšđÍ"ŲxmSîsŠVEÊKĨË_ÅX^q•tr[w/ÖIІī­fí”%Ý=UûđŅø AŠXa§ĩ\Yē°―@ã‚{îĮš˜XÄūËzÚũņûFŌF‚øBŠĶ’ nýü§*ņÎ;ïüAáTļŪë”R ™€SŋēČ`+ŪOjÞÏíq­9—' a?BãžĐR*kčÉ3~VŦ*ĢõP…l€#ŽŽĖlÕ,Ņ}E<Ï]ƒ"Ï1ZĢĄö™4w e―T’`f}k˜/wĩWMM>ī0AîArTk hĶŽéAųķ™YD\y$iŸÏĩŸ#\sāýUUålĐ+ōËHļ›M§ŊŧĘS„Yŋō~žÂÆ>·û5 ïžóÎß#āîąVŧžXFAyēóVf=áÃ}é[úĪ,ŠĻŨīŠĩtjWđŪuęTŽFŠÅķ}FCũFTx| OXák?s8vy€y#āIkķ_-Õh^%0Fī‘á7xŽ5+$ †Ū‰, rįģĮXLĢ=ŧ čĩĪŠ”oœžÝ{Ÿ“Ũš~! Œ5Ë/Üýwƒ™Ŧ*ó\ĸ}P8•Nsũ―OVŪ^ŸĮQ†wÞųkóZŠ ģ.}XÔ*›°Ú‰Cl’qvĮðT(R]­zgSEr}ŪĘĢ#§E3•Sß}TÝöæNģĘq­ë|7M#YyJåūÜÚðęî†sŽRFĸ\Ÿ2iÚÏ}~#ĮLÃcĄxNša…ïs#ÁŪ°­’‡ŧEfæŨšĀšŽl]DJ°`ÄęN0Žĩčl[h†NæÍĘøj~įQãœ,Õ7.ýŲYr_NeUŪk“Ų”1ÍŠŠ4Hxįwþ^ OÕnČÚyŽQ­2gíŌÆ'3Ũšb*ļĨðP•ēÜ\ ŠŠĨĢė°Ä)é3ũgÏĮj|­% Ķ[ ˜œ\ĢŲēŽBCž{LÞ`YĮ0ú’ņÉ=ŊāÆgwÓÁšDå‘:dā|ígãÞīŠZW<]đ8õũóØšÂÜ"<ōŒ@ÂÜü§ũîu]P5(Ó†}ĶīŪØm‹Xßō…Ō”ãBpįī6ÜÏF›ē îā Ice―[í;ïüÁn1@rJŠïnX%õīC7ë{ÚÎ{?§’öH˜Ņ(Oî Ũ>$Ý<ÖĩÏ6Āà žįĖ9>ĀŊĘÕ]Ân2ī= 9u^S?Ü-3)ôåUĐÔš>NĶûú\ĸ™Y5ÎöúœRāûÄÆXqßOeķÅËNf?ÆjĐÖþ søZié–%ģV ĀōdĨbAJPv,: _> ÉÃe–_qÅ:yZxÛڕĀWÏIFũð?·ÕūóÎŧÕēĸkˆƒL$ģaƒ ŪߊóčÓ*Ð<\ŠNķEÐNåĪŌ|֕u&jËÂũ>å46đÚŠęCüé,ˆÎŽ9gß?74!XûWÜęÏ~ĒSžÐ8ÕåŸRubļyVBiī1eę ó‡†á žFðÏuMŪ hą:ŠąŧvŒ&`cü89 UUĐ sčŧĀ}úõãbriIaÅrģ}iŅ–„ģũDĮ ĢbcY>ŧ4Pž{ïĶķįOT’ˆ7mæOÎ;/ÔŠ€āËĪ}8‚}Ûm7˜TėŠķEŔ‰UsŨ ’ûÔ5gJߨ@ԜWG؀0ģŲ@uČq=€äĀÓQõŦ‡°I<™6\€ûÞŧ*ndæ1cīŸm ïšæ‘Ę—ßĖōpöŨ―w[þæuõÂ^lt_gzkÜwf Ól6 )ˆÆįLBúõL}N„?Ï>ë>Kî1ēgú._ŪöOÎ;o9y€ C‰ˆ}ž/Ø7Sf… ķï'Ėicå9_™>ÚĢ™Û”ãöĶƒtmĸ―Ne]xsĸüfü―uŸPAH•đ-I@ßÃØ [eXRîg·°õ:uŠäąÆ]vōīJėÛŨëFŸ{ŊˆîūÝÞĐšßsšåIAÎ9Žŧi―ŪRĩVÄ}ß=Üčcą5ēĪzŽyyęÔI:#Vf*"ūķÔu]Ĩڕ„VÄĸTįž- tÞyãf €›_Ÿ•_ūá^yĖÂĖč^•4ÂXU(Ļt­Ļ<Îh@äė‰tē-^îæßåW$–GîĖÞ]#Ūó7ŋŪ‹ÎR júB-b­§“éftfÖũbãÞŲy8VÐއ”U5ÄĻõvÉÞ(!Üũýœ=ižOSWŽ― ØÞ f.á<‡“RæĐ°_Ĩƒū|ïDĂŲ>H ņék5éžŋ§pΓ‡ŌTTPTĶÁRĘS/}ðWįũX pZïģ§QŌįëÁP‹ČĖŅޟ:§“đãZm ĀŽ5üæÏ󘇙Ÿ―3(UŊŪþ-Ũ"KYYĘ óĘüy~Ė-<*ëdéuē*I<'Ŋ/7pÚnĖ:æ$0Ï―‰1“aWNYšX ôˆû~H˜Ņ;Ú&+aýtDBq]Ī••Ö$ÃĪJzįËädt°X?f؈m0í}OWúīAdƒîŲģn; Ak­ˆ·ðæÎ;ïV;ĩXī“ûœýéũđ7a+bJp++—›d4ßÅ?9ïžŋáßcôï†ðÛÜÍžĪ<)ĐÏūŽm­ōÁ#s~…nóJ’(ŽOė<(@?iîFðdéŨŠĘ“5 !ŦŒĪÛyÖ·oõÖĩÚuč6eã"%^Ũ?ķŨ‚A3íbĸĀQđšJũ>W„_WũlšƒžïÐV[ewŊ*͎:ゑnV’…­ :‰Đx+%e/žĒ™ÁÂGœ@F$ę<9AN$ÍÜŽ%q/‡ð'įW`€*ŧũ3U.óũđ3Ūk…aĖÆāāáĪ•Ā~#ŊJݧš—ŸÓ*6g%”$íNW4wÂū­āÔ9Į<ļ™klĒtúŲf ŪiØ―V§―”ÉŽí'w_ng?t6ˆkį1'œÏģSŅē3ŠF€ļ›~u3kĪ-vÉœ\-wu@8 ŋï:3õœ‡œn…C‚€™,ˆëaSFŒƒ6†ŸĖĄ7þâžóÎëÛŲXÖ“ūJ0OÍCК€ð;Ąfy<{‡Į˜žįYąÂŧō·c\‚Ņā]åp?Óė=’~wefB™p\vg{›õ­ŒSfSS9aįœ)$‡Y+ÃŌ=Ôæ1ÔЧÍ]F]ûóĸûųĩ°NB°ÆúģũZø€ė—ŊFv•9ĩųMk]îææ•ØøÁÆOA'ČÜOĶ>ŸKĀ>‡ftÛgŌÝĸ"ðÎ;ïąXÓŦņkö ÛÁ€&&&ÜūÝąôĶ\OĐ`0Ņ0’ŠĸMÆöŲgį&-< §§Āĩ‡Į…ĪĐ~˜úœßֆĮ8's>īˆ)ôu·Ę*Uy˜ŧŸįV# ŧCjÁŌt}hR­5Å\Ûhî>=ƒ_ŲĻÖAĸ ĪŧUXAģģĢ=?·Ž^™ú•jÕ7>FYĩó”r­ØgŦ0ë#ݍåã€@7UA!WģĀՑē$žįĐĐaGíį&8}k#9ð–d |w§Ų# $†\@­n)d͟1sŲ'LýwÞųcŲV҈ŌÎÃ&/GāĻpÆįį†ŲHĶZB@§ëW5ķ|5PÃ@šĩSܞŽp‡AU Đdf2kÞgŸ WÖĐ]⠗@ÉūÝ· ûXžšGķu]Ŋý~ð™Ö†eNؔ62ĶÐ7â ä/IÂŽl\ŨG…*đđŒįŲģŠžŸÛÜâZû~@tctóX†_F<ûFxsĩđŋw ŊÔéTs> ĘĘņÎ;ïü-ĻĘą N RĻęú|)$ ™yÔ ĩÄólŪĸŪ“‰ûƒüsĸī* ™[ĘNã>ėW–TáūNW™ųœ}TšHŲÔt2.a‰†ûņ€™›ŲsßtCÏÉ4X•čëÄl{3^î?ũÏ„Ō ŠsŽ‹ys蚟<9žAĘlÂVž,(ĶŨēĐáëšĶ^W•嚎K‘íĮ=}Ū/e1ÛŠĘę;:ó7°Į#^cî;ïüEąŨÕÐđwšÖĨŠÉûZ UeîÁ+ģ^ŒßHėߓ4Ą<âđÕĀ‘b\Đûū9[%-ŦƒŲÉa'<<ö~PęERSasčOÁÃwmų2@9Þ āˆŊwAļĄOÛ&.Öhãžh…>Ž ëļņ‚^Wė{Ģđa˜īsX`’Y bŲu?7@3Ō(Uešŧ~ĒSĘŪƜw‰ý눈C'hæ@ļ"öÊü‹bŊwÞy- ;wUQ4Töþ(wS•ČÖ!°U*ݞA–ÏĒ/ų†ķœLÕІ%IõŦYKb‘Ųˆ#7Ë}ØxéaĸŽ‚đÛŊ.5ÂU’4Đ4%™y|Vxœ}JpÉRģ[lû āß^tw3+Ąlš!ØŊl]œþėý,k]• ”ûÞ|đÐaĩŨ)Ū4ÝkĘāYI8;ĩ6UÞy7“1æ+Ü};ŧ§N‚qšäý›HûÎ;o^-I3ŽuŒ*øÕ˜•r3Ï}NÖrwģĘo`Â9ų<›ÆÉxíāÄˀV/ĀIkPvũp+•ĶuÖŋŒtŪŽãr7sŊŌޛfڒí-‹HÉhŅ$nIÞn6ãþ\WUVŊÛëZ}ĒŅįéÄ[ Ôx(3ŦÔøŲhčc4ģ°ëTóŅUĒaÂ*ˍëģ*sīÍüHa‘įhÃNäąæ—KŲęæV(sÆuÍšMČý5æūóΟÔՎĐTîmfŨu$í2vW„:jvp6ÏÛÐÍrÂŋ—zöy­ Ō99dž3Ŋ0ōt?˜™IØ{ŧŲWl@Lbė|rŊŽĸþŧfÉM ųŪ0#TUčņ,'Žōߘ;g§ŨįjaBšûõ錱R\Ëh•)”·„ ŧŲŨ„Ė~iV)39žAáûFÂnÕ-Žë‚ņį~ŒÆïûÄcôX1aHaþóÜĢÆU)3-ĖÍĸĪŌëwÞ­VčjEôž*ÕPīäóØš jˆ\ë2ĸFeĮZĨ~i73Ŋ, ‹@ĐŠjķ`*ŲØR·ÜÂ,TîŦtF—jž'w· fÕQĨ† ĄŠœÖX†X“Ïp$õóctÁîÜÏ6`°{š€=,ÏĐ,H”=?Ï ĩ {—›­~5•*ՏTÏóDgØĒԈ.ž)`īĘ}ØšĘĸÂZ_˜ŠVøÝĖÉZzÓOĐŠðÎ;ïüÁĮŠĐ —ŅúhūĖđVÜ?ÁpŦŌs?yŽŅŠrüWėÔðįūÏN-Våu]NžąŠeeӝŒ˜œėŠ+<,ëT@“Ÿ0æąAsĒ/î@/[—įI@íjðû~ht§ēĪ/ML#ŠØNē“1Œęyö öŲ#@c ls3ú„+šÎžiž”ē―Å.Ý9YÐy];OšÛ€8iŸÏ5 5Ģd8yŠ˜ œ=Ž4ÔûŽ™ŅcĸŽĻöwÞ€ŋ‰‘―į&:F6Ð>…‰ģ1^Đé°É“ąâú\J 2’8'+§‘ĖG~KZĄęĖęj-Ī s7ģýŨœŋA\ūNÉÆ=Œ ŪdÏl 37áķV<Ï#23­i֒Ūϒ0ÁŋŧŠŪëŠðf$dæcœc?°ŠĸMp­sjqHžóÎ;jÉ>@ϝ­™ú–]ŧ˜ĩΌM_ž†Ŋ,”bÅxX'{rdĖän#‰—Ī:%āëŽ5ĐĐóX óŨ0vr(‹îVøMq?Oe:ýė3i5_˜Ō/}QĘÜÍÍL;0!`ĻL6‚ŸSó[|~š­+$dMÃĢs<‚›kx[ĒþÍp‹NÐæXo|ÃH†Qhü&'°đó.iÂ;ïžóWŧÅ2yŽ+HĻûōNbesÕÎĖüÕuŽōeþëâuĸŠm}iIéŧ)gNQîïũ' ͐.UVaę É:ƒŧĐô՗u@-JŸÏ§”BĄ3ķgĐ$ū>ą&…͝Í8pĸüĖ1]WØfšđ/ĸöĒà ÕÐÏŽšø˜vŸÁė;ÕĸY€UĐ_xâ%Ĩëúüïį§ÓÜú3ËݍvN Xį°ģ43—RõšÅÞyįOęjUyN*ēŸû>[túU(oõhė#ŊڇÎå‹ÏÏ&†PĨi&ÏĘ߯o>―ŠĒ!pïsž=ZubŽĶ ąī>ŸÔļ–Ó›Āð ­óȟģÆŋYûypD°{î<ĩÖ2Zíä7œĖZ1Üc IϓŨčTRôF@ ‘~ūnãÎüÎb/Čß@۔ŧKęį”3†ũŋˆÆęĒÓ܈Í8ïP,s—þ°Žöw^ŪvEĖÁ: uEĖn=p[ …j$ ItRFZûĶĖhRRÉ 3‹RļeĨJÓD›y]ŸK™&póŽdŋÅãyĘÍÝ\čHNō‹đŅþ”fýëė˜Î“‘"ŠeácfÛÏcüúŲÎÞ@õĶđá$ÄÄÐyjg ’•…öãúZ™‰Šu­éš‘ĘÜzÉ>MR;“ÝôĖ3―„eë~ŠÜ9Ĩðn”Č‚čŅ`ýÎ;ïü―†0ĸßu}zÝ;ģÍ 'wSŪquWXNö}ß> ÜÔū·úČhïýdÁāæĪÝ?ŽÂĀÉ=!ŠßrŲųŽ=đÎðļŸ‡ė ™Ŧƒ°ß`Äés§EØHzĄOĮnUE™rï~ÃæŒ.:ûæqsˆýÓęxÔûļ{ŧÎĶ,}pģûnˆÉëšwšLhúâÞ ãZКîÞ)ÓĐwf’"HtŲûŋ1·nŸ$Þyį?x,֌ją Š}o·ædKߖÚɷ߃4‡‡–Ôu-Uw/nŧsŅ(Y•īFpáįįqøI˜Öī=žÃž&nÖTíJĻėĮÆHČhģ§V„Ró!}ōČGD1 5ŠĒÁÜ~Ķį~’~tšð)H‡@ô!ÞŧvŌø‰ ūĢŦe$õŦ9Ũ>WinĻ?ûd•E&J7 ïžóÎßãjsčTĢđŸ<$̓fŠ$mˆ…Ņ„w-ØŲjōgÍ֜JuMÂZ ßĨģŽĮþŊ\—GÄŋJžû-­{îyj?ŧ2Ŋĸ>ÅŠ*ũeæûyR)Ž}Öž­; 0# îq]WUĐd}`WĨq=ĖQ[ïŧĄĐņĖĶņ'=þMÖQÖ/_QgCwÕPîūۘ1r‚Ė'jgÞŪ8ĩ“*‘æ?i}Âh°y‡f@îŠüFVoĮ―)Kjcņ•›:iāýsÓ|Úsį1æžŦûzōėd0Y9Đ:#™€ði[pI$Fœ€ņį°öwÞžZÁÍŦŧķŦsÛÏ6Úõß5e6æF°2itsĢíüĒäéYgÕĐ4óöÚÞÂŌsķÃČso3N•øĖāquŽAyXeíž‹äįŋπēIf9óŊŠŽĪú›'íšâä*Âiþ4óëæ€Æ| °)ŨōvCôbNwĮwSĶ1JjÅ7†Q,þ›xžÍ–@ļMkCũ<Í&ÞLŌīH<σū5ÁÞm Ą·ðæwþ$@īLķ&LäaMũâHBW,FØý,ƒģËžI[Ðé+Ē ŽĸöAĨ2ģk]Rîį^+Ūus„ïYį@5ÛÐ!„kR@Ė9’ēzg\U5ö-@įŲBg9džSvũŧ +–™g·―užT初6đ}KÏþ z]͎ 5ŠûōŽėÆ_ó_NYaŋ…7^SĐ;5æ§N& æœeķ}w!˟Ą&%RxįwþäąX!ģŌc‘œ —)ņžæÄ6æ>ė1ÚDüŋë3pcfã§2§·‘Ą·NĢā7#FB'l™ŧũMØhÏsOp"ÍÏ)3ëōóė h2A­Ï5ÅŅōÏ™Â…Đ 2“ī*éeÓ=Ē&vŦ—ņ/W―–šóä>{G\ÂoōËô0–čáä|_æÄ°~3šĖLāŲĮĖ|” YÕl‡đŸ{\ŨE ąbčl: ž<æ^Ō°ÃӘ{ęĖ‚üÎ;ïü9ąŨ ßŽÕ9įŠeāūo î6Ū-wŧ"TYŲÄŪÏþĻ’Ö‚Æffĩ BĖAY:Ķ KYō^WÏNB<û‘īÚ 0ŽąŅZú*$ũó28ūÆ4\ŸOMúŽ41ēY‡ģĨ*%ņsï<UƒxüũƒGg_ö!/ÅįjÞĢ,|yÔ·;îĄs‘íŲ{Ÿ'ŪEãŲ[ÔØŌžĄŒŊ4Ņ6ŲUŧ?SŧÛo ÐÝE„û+?xį?J P$ŧ-ņŲĻð-}c°ŦcĢiÖg'T @ïÔp­ˆ ?ĸŧ―ŧ %ėûW Ž“ÖŪŽt3ŌîÆV'ņósŧŲęĶI`óģYĒ܃āóÜŪøTĐ*ŦīŪČŽŪÃišõߔq^Šf~ĸüh­Ļ$0ž™­ĸ>;ËŅ!čQĒ;hužĄVól„› VîiŧY}ų†Ø‚0d–mv˜į·0>Ï 3s?'Ąr·XĢ&>™‚Ų ķïžóĄíˆÝũîčn'lÔøænÄ9ŧã§š;ĮõôÜÝ+ŽĄ$mĘ―atēR0uPÖ%•$‚ÞŲÞ*}þûdfŠHóÏiÕĩöóx8Š,=įĄ1čÕÆ sŋ:6UfėĮxĀi,į0k­Ž1žÃny&ü›öM)“™ĩŒũ6ĘēŠ* _í ŦJsƒ8ô+:l·‚XĒ›U Zƒųœ_ķwŸsÖĩĶÄw…›đϚPpũėČ/ĶzófÞyįOޘõþe47ŠzÝ#ažï'OMlÕißŨĩšĨÜéáfĖ!@›@Ļ*í @h°6ĐNžÁŲSîëZĢÁÂĄēNî_7W“ā?ûaŪģDPYû9J™ÛÉėgī‰ Sés]Fž―ĮųV§0Þ°ĶYU…FÚĖãkEDAcąöST&PKĐĖëZkÅ~tũåũģĨęĶ ÕÉAŌöū>î ÓŊâ<§ î^'đyŊØG•Ä;ïžóŨj‰1ƒ…YMÛ Q€JåŒX%QcCčîDÄ Œ7§p2GÞ?Ņ‹M{úó<ģÄuöÔ9uvuėĩŸgžĒ―Uó1ß%T€}ëÖ˚Åu:§đÚ+ŠÛ―@š‰ÝvdĨ4ķ"I7sëuĩüŨgŅ,„AŠŠčéßzâÄ]U(Ð-ģJãÐå„$Ė aKtŦ•mĸ“ŲGį„OąÍ9ÛÃMíĸŦĖ’Ü]xįwþ Ūöß$asQRĢ-ÛËs S€”›7 &~CÁÅijhŧŠ {ï<ĮšœœÜg}Ņũ Ņ|j&§ÜŽoyŠ߆]€Ĩ"zÄótïÊoVųlåĘÆč.Ûų>0TMfŪYãŊ/§ĮÂųrĩïžó7ĄÖŧüɇäu…™i@ŦđŨ1•ÆŠ:ؐ:‹ä―ŸĪđŠöģ3ĩV€ŋÞ°Ï'wVÉÂۃ[“ēčaßĒrũéÎņ0csģYЇ!Ĩ5ó+|Ū‹N€­ûŒælŒŲŊÖÎ/+% MđžģEƒ• Æéúíô2đӜ'ĸ[ü"§& VŠ. kšä71r$ŦÏëö>4\Ũzžû<éīXąï‡ÖŪŲ0îkï}ĸ'ŒÞ.ą|ŪOÎ)ü7Õ% FpŸ-ÉøorŸÚ ąÍŊ{”Īņ Va‚ki°65Hû7m BfĄ)ã~`ô+žýĻeŨZÏý”ōóßUĐĶ_eĪЏäü\Ī š1ZMŊđ n5?ĸý·ÆŊëí€žßHö9 ī†B™™‡ ELûdŨAJĢ ūũc ðÎ;ïüA]íɉTŽa,="įô†ôp@bųĩHÞũÝŲ—›UĨEĶ „Eœ―sš†`ũaÚŠŽ’žÓž]ēvĐ°š”Ąšøvy o{}›cÆX hN_ü*ČiV'—_dãėtDŽÞ ŸŸ§ÔŒ*M_ūŪkï–Á&nįš"Ūõt6­Đ€“nf47;{ÓđĖ ÁœėŒA.옠,ĢSUg?čc·R)eft;ÏQÕyÃÎBÅZöރԭd 3NŨΈuöÃþ?0Ô)öŽ=ŧð„ęž―iDēĘCÚu-ũģÝĖ'n< ę_J ŌÜTPĨ9 VbŸmN·˜N n|îGÁ ŦMåĩBšä^ķîÜđËL_-PC–ÂcįŽÕ>Åė| oÞyįo*šR6Ũg)kĘ `–5ÔdKž3ËãŊÏĘi†T:§@;đŦôM\|NU™y%;ËÕÜ ęh–' ÃÜŦĻk-ÎÖŲ% Ĩdî+\*)I›’.š5áĢåúÍc,cÞjŸ“ZÄizøō€ņŲŠÉĸ–ĶüÆũŲ•ščîÞmįh˞ó4:P•SŦãÏ(Æ3ŧn˜Âž_I'Óh§YF\ŸÏéĶ\ˆWÄČ!ÖZa#Ą›'~įwþÔŌ°ÖŠ,5"~>W<{{˜„ĖūÂû‚,|ÖÆ] `uœUPõ+)Ĩ RŊ„Ũį‚xÎQjuUxf ą ŋŪ™Uf•ŽũI5ð™Ā<é ‚' sk øpÜlĀrŅ&1Ĩ&svĸėïÅÆ>mû’ įœÞŽãœĒŲ88ZÍÆFėzž'üß|3ȍNPĻþvt?Ø@ąí“™ÕųõėMũuu(ío.Ÿ―'C]Ā>énáþēïžógCĐŌŽąëėݰ 4Āå)’Õ0Á804Þ°•§h\WļYžrō['*Ėž[hz·Î3YŪáîĨâ/ęä9yÎu]hălēoÆ50 Ŋ$+k,j1ŪģÁ_ónņBŽÕ.ƒī0A“ģUYÝ"Áɟ5óR™Ą2I|IÚŊ­ËŒVUBejj$kc~—éaŦĘáaĄoۂ‡UÉļāÉD TšÞ §åšxįwþ Øk–ēŅųW›ųH öTiūĩÏ1c,Ï:RMõKÖÁŊ#vj|ˆQ Ûŋ· ˜ųkĘ"23 OgßhĶĐÝ]áh„ũ+ĮV`l+ð9C"Oz5DŽgaï3ŋįs‚íaËā>=’rsĐz]ĩFjR!Âg-­SMđĶ9=ĒZzŽN5ƒI(3†Ee‘6ëöč |ĪĮUFŋŪĐJņÎ;ïüEˆXҚÓĒ›/'ÍÜÖfÜÏ.ÕÕ%7•yE€ĖŽ:“€ŽjÔsRYĮÜ>ݧų!XIĒĻ*dæī}Wic·ČĻ*ĢûÁ;ķ6Ėv ÐØ‰{WĶ@Ucex‹ĄáLÃ#ï}Ė­*sïØZ#{_yŽ;Ýč'{ÝĶĮōtv?ģ5†Đ xÅ2ũįyz vïþöļüÓ‰ģģRĪí|2SĐąûŨӌĶE@ÓîE’o Ã;ïüIĻ͓e9ý.“É"Ոĸód„uÄõĐJĖ\PuåâĩVž<φŽJ Ę]Y§Ã\ĖÂÎ>yrlĩŠ#НUŠ#·/ýj2U(Ý―Ãjĩ–Kę[ĸkυU,|ûÏģÐ/ũ 75đ.4wŧ5aWŽ:I˜@óĻ<ÖR‡æj‘ŨĩÔā>hÐŊLÎFėãBn27,žsÎÓåËO€fÞų“FÐHLđäōUU―…W-ū!Šïžó7đÚSóã۔Ęh O:ĶŠŠXÞíßY_\ĢY„Ë0ÂgŽJ•˓ĨôÎ4PJfn†ĸÝw­åŲ†*ãĄ'O9øEXwßN4—Œ<'Axßäyž’Øe_·ãoŒ u}›ū ņŋĸũ)dĐ,Ž3ûâ — 4Ķ:r·JUĄŠķģvš„…§j?ŧNY0b‚ū Áh‰y†čFēĢIMâ—[—ķå>‡xįwþžŪöœL•›ŽSfF‹YÁ<ģ~{Ķõā4ÎZee$îFšQužęCĸëäVkKÍyß'8Id7sóĮh˜ņĻŠŌĖÞũcfS†xžp]Wę PŌ§ë͍l2”Ï>Íu8ø­ ŋâs”ÃZļGÓÄŲiķ‡†îņė%[UÆý ņ™ÐæA5ØģspžJ'ė1Ï]˜ąwÛyßĘĢRVeFĪMŲŧē:ÞėwÞų‹\mcŒJėŦēōäÆÄĶv~KÚ]ĄčŒ>IKr6ĘC2ÆN0%7q}í°ýŋį9Dxø9‡ôö/€ ĶĢ· *‚îv?·q°L§_$"7'$aÚgéNzf‘˜ûķŽLæqz{T*æ—ØĩÕ蔍›ĸ“ĮJŠÏ"Đü†óf–đÁéf§‰iwwX",šī=E3ŌZ| 4ũûđó$ĸ Џýđ–JŒ ëZU%ČÖ+özįŋšāîŨgÕĐa*Ļ}Œ'Ļá%ËÚ(4ýú@āå$ēDáZWkĀ”™ë7âŠČŽ18˜QUámiVB3Ë*Đ/X~ö6šđyūģ_5ƒánÏTãxžŸ§‘$$@eæĻÚuVļҔըoކûÆz Ï―ED_ŽíÁ=Óąx­NŦró‰kv}ËŌiö~܌&våđŧšųęs-jÜ·oāoĘÍP% pÞyįÝjí{ƒŒ+œ–'ÃÝ/—ôÜÛčĸĩö2cGk(KQ{ŠÝΆ*3ëgđŊRMC­đ흊"IÃÞ§ēĖYUgo7›Ä[û–ãbšÂbE•ēWæX(OÎRy&­ĶīŪKUŋMš_íōÕÝļåîŅb5 1Ý·ŋHMģyŒĄV§d,R›Ânb$K56Ýy$3ŦūßdG” %·č}VĨōÃ[xóÎ;RėģS§Sĩî =eæ+âė$ļŪkRiŅĻԘwÃ]ŠY =BŌ7Ĩ;X§(Ņ8ŪiەôĩŪ†gîŠ"ļo=KĨëĸ*ŋRR­CاvD # Žĩ”8ûLTXœŊîËĖÖōÏsJÕYýÎa}ë˙ŲošđīģOG#‚@)%™Ōē1wŒc,žÂˆąHt.">ĸ}(Hó:­ @ė{qĢēÎų“…7ïžós˜ŽŠh.á7ÁÚ*‹ 4(ŋūUįė)gÜgï―'SĶģZN„_Ũuö•(Ôé |y'ØėÓŸJÕ_TĢs‰ƒæÃN4bIÍüfz-_j'Å ũsƒC WVy4Ζ@”Đý…H+åi-Y` #Š+VoÍCDÄúŽ•k2Ț iįšp}ŪęįD|Ý―ÓF~wœMWNdUIč2ąį(Ũį›\S(ŌU―þ…wÞųŦ\mûj­ØyL†Ą5ģ$pĻĖ―éĻ’ÏÞáķÖ:ÏSYcóϊ܇4šĩŠF2%š;Å9Į__―°Ę-čšŪ/Šæöėm§Õņ<ƒč]:knä@‹ueS§$9ý‡ÛÄuŨœÝđņ<ÛÍÛðķO [sšbąíž4sH' „ŊÎč’ÖĩÜ#ŸSiî,ĨPŨuôøËP—r ‹æa†*Ô6Ð{'i䛡øÎ;”Ŧ5·9&2ÁøŧÍĨ8ŪęS,·ĐV°ųÍĘ*ubƒČs:DÁũýäI 'Ņ!VōpA;‰čž.•"VŽõ<·wZ įđÏ>;žĢõÁVóö2Ät/‚u? 3ĸæČ4„I*wÆ •€Uf~2-ÂÂŧ­VßģwóķFVøãdîģKéҚ3§ÍįVðŽYxž=+öų•7R îĸJƒP*ÍŠ0h.(›‡°åĩÅņw^cnDUQ07vė! 0ŒÞŦč|üw·ÜYgJíūwœ62œēąÕ<\ŌðĒãî•ū3ÝōÍq ėý4jGf/•‚™?ũ“UZØģz7UXSņįļõžRjųeæũÏSUk-€RœbąĄK~éāIĸōĄ‰—ŧE°TUŨúHĨūÜŧxüœgy‹T·/™*ĘP•ŠŽNŊ“}ųōøúq͕ĨTAfŽŽŠÂ;ïžóđZeĄ@'ĀĖ5‚„Ęœ\‚cĨ ģĢ”JŊĘ"Ĩę&Ý’ģÝī*į„Šŧaäá#Z]kYøP0+en•[ęm [Ïs”Ē4‹$V,ˆ#m%ۑ…ē0‹hwŽVŽ,eîÜ鿐ŠĘÍWŽsJG›Œ°îH>ŸĸDÝ{ۈ!qíŧŅ‹ÍDäÎų­OuþŽô‰ÆYĐĩGíb–; ũ ·Īėøq{&0ĄNËËHõÜØj :ØÜõ­{`ļČSąÜú՘Õ*+Đ7ÉļĒóOvVÎÞ'φčü ŋĖ ēVĻÕ;—ų™·Áú%ôōÎßvœ.NgÉ`æĖK+X5Ý ĐēÞ$uRđ WPŅĪĘ*o§ėxúė+žnxĪYI{?*t5ä0jUĀ™SŽV ”Ī&y ts#TY{'<@ËŨ7ėQeîÕhé=@IĘ͔zō€t7ÅjNF€Ėčn­9KvÞdŊwÞų› ĢŦ nUâėŒœ@ĩŪkrēWtŊøóH03Ģíe3ŌĻŠ­ęîŲŽÞm‰Ĩ>„ĐÃĶÆ4ĄÁŽ”4ņäĨoä‚đUJl•D sũŠĶ‰ŌGį tĩâÝŲ1a…NÛ"W‹jģäÐÄûėðčĩzęÓÅéU#°]™…ĪŧGÛĪōp°™kƜÕÕdÖRUįg›ÛoØ#;éœ??ĸC{@~[sdæ_§ƒÜ! ïžóΟ„Ú*eeúDÃĻŪļĖ-‡|ž#ZrãƔÂý{ÔMŦn\KUU07oœ@_ ũĐØBÛ†ē0oÃîsŠĶĩaÝëëYhÃØ T–™ƒļŸ§q“ēj^ BUõŞU'Ïĩ.v―9„č}öþßÏdãVęäq SIPę„}Î>_‚›îėüŲFj·ęW&đ|í―ÐXUģðÍ#æŽŨuõ;M1ūUzÅ^ïžóWđZĐ:ÖPUŠėÄÂ3ëŠGĻPUTiZrAÕIW\fÖüŽV ŅXVÄð―ČIū5ûŧ‡ą4ŽýwÍ#€iä/JŌėđ[ 5°LXĄ™ âîÏnķŨBŋ @ÝũwŸo‹XŨ―D8›pØ4^k=ϓ™sņóėŽėĖYdæ@*‰ģÓ`ŨuwŌÂĶÛfÞîû60Vėóœsl ĸäwywÞyį?™Ð™2Y‚ųŨ‹Ĩ*› ðÓĀį&iķTsW)UF€ÚgÜh:Ąk]yŠŊīņãJgÐîåq]Ÿéaô0˜ÚZs'uöoŋ9á jF_|ÎqóÎū9•'ūÅ6ÖĖoeóļÖÕ'iPËýŒ ÁHöÝËĖĻ4ƒįyū-8fõëģ ÝõrŸ4įįsí&s;ÉėšÜk-ĢAČJM^ÚųŠŋéæ‚ÎIâwÞųƒ\­™NáĢFĪŦ*Ū+&Ŋ@†+Ï·4ĖČýëëBï';W…Š’Ę­đŠPĮAUšÓ8ÞV€ēēzõģ:‰*‚æD)3IBȔ$:ŸÓ{gî&ˆįČËá0c‡ĀpL_™‡›íýĻŋéîęŨpŽ”Ä͌­Ty<<š-m•UĘÜÃ{T+X0·ý<Š"âū7Isũso‚ øýÔЀ*)hĸ§žį~™Æą&ükŌĶ<ē_G™›+eF#ņįwÞ­p7§ŸŠ&Öh  ÄĐTÕ7eņđaąÜã. * î!åÄ0ųs?—Et‚xĶ î viÆ(Ïū>Ë`ũî;.ŸŽņ_œ<Ü&ŽŦA Y#ĩÂĮ?QæfįäHŧ–[ílt$Įœ%ģp6äŸĘÏõŲ•â4JDŊĒcûũĖ&šQ†Š” ōdõðßįƒŌÎ. ëЙhÜ/åӇf ŠtžcNw{ž‡ Ļ“„ĖmÂmßyįŋĩӘ›UgâW|ÞÍ7eĒô%FũÆ‚&M<Â!äĮ/?cEßģÝNšį|° Ûëũ~‹ÎBüÉÛZ’åÝÉčîĄo*˜O™3mŸė$­ĨÖÚėÝķę€qEî 1z;>gOā ”įĻk];Ó þÅ i+(@Â2g8ĀĘÓ >ī@Âú.'Kåfþí°/îKtpģĩÝíėæ"éTåN–tšÚþsóÎ;Ŋ1·JûUEįŒ„Ë"šë,ũΔĐĒD†:5ęQIgŪeӞKX’:ËUÞúfŅTĒuŽ—‘f‚N~Ó sžaąŽŸMacUAZW8Ō8Ŧ™C,t lĉ”ĨĖH·ŧëjV,(Aøšā@7ŅÅó<"ëœ!LĖ|*|âōXæ§ÜĶ3áW5HŽûĪ  ͙ķĮXŪĂĖՈþÎ;ïüEąWĻÔī(ö‡ß[YĪY° NaD"éN”Æũ―u>m~%đŸFhT U™īo,ĀÔ3–Úâaų’f$ZQBāė“uŠ‹f•˜ŧÕsïsē/ÏÂhž,wvÚKĖM'Å͉]}ŦmsĢDã―Ÿį<Ž7ÂDÁpö6q­5}6R}ŪŽo DÛN% NccĨ›ÁPUÓĒV%ô­ÍíôÅ0c›‰Ï~܈ŠŪ –›ãwÞų‹P;BŽFŠ”`4_ËÝÏģŦĄ%™"l]+Sā·ÐûđŸA―1eąUf Öāõųp(UĘ yÎÞŧ( rįԗĨpę€ōkĐĘkwfŧ[#āōļ>Ë=öó•— ‚kÝũ3ŽÞŦm`$í7ïÆ`ĸ}þ3:šPĶ[•2 ĪÓîggÍÐŒŠ™wæėS'A@ĘTUfŧ{+ŨõumTåZ1đīđ[ĮëT‡DÆÞŧJąb$ūĨ Ä;ïžóGuĩ•5’ŽÆ\)Ëh>m]ßã,Ĩ›ûreeĶ„fQ7IMŠJū ë˜ė=õ3ŠšZÜĐi_wŲIôĸq7Ļf$JĢ(ð°9­ZąŽ‘‘Ēŧe‘•ÃNĖĮüĩb·ÝĀiïû.Hƒþ!ÖŠ~Ž/}‘mKûÍ)šŧu{îƒéŨĐa@ēTõ[Œ–'6 YIōš.ĩĘb~Y•Šī<ÂlþĪ0_ĐŲDßūåäïžów“―T%é7ē`jÃãœsę˜YUC`eW$<{Ÿk]+VMķ,ŋ§íSûčæãsmčDîƒâ,žĢ37eŅø­VŽ"đgóŽÎ?ûŒųĩ•XwUÅĨ.@;M_ëZøũ‹ĩâZ‚4îųtôZXu~„é^lˆŸû'+ÝÍĖ æýŊYâ=,6ČÎ/üęŌ§X·ĸ\đϙ8ˆóe{ÓP$$íEÚwÞųŦåäUÕåēũ~ēZ ~îĸ‘æfÜ;v­OMí‹ÓŸį‘ī"$í=đV.čŲŅV\™Đ‚…ũ1ŅåÞ^ÛjÔĀĘsüŠS‰sË}žˆĄ‰ĪŠ! æËĨo§dtŨŅØŧíY뚮†ŅŌvĘBĢŽJSˆ+Ôóĸ­s… #UĐáj•YĐ^ũˆú.ķ­ßÚF“nÏÏÝ[°QŽĘ'tA( šÐ,s/%įŲÍÉĖRŨ†ŸL‚FkPþ–Ë^ký<a"c UM`‚zlöõ*ũ°vÐ-ĖöÉi‘ Ą 08hšpzU~Đ P%Ĩ„oĘmfE﷟ÍĖ͙gVbŽÏgp6Kn–y&Čó<#ɘ\4ĢÅŽŌ…Éųþd“ã;ïž‚[œT4ēwØoė–$âwÓŽ|ÎÉöPDbĩƋ€õu§„k]%ä)ûký&Fe™ŅIVXĢįį”6Îķwy }ŅqÝ}ĩxN^Ũ2â”@öãąTîķÜ Pt_srE§Ņ:7ŨZķŸsN*EōŲ[Ð 7§Rûïú@ĻÝâŠ―ŸÎåZß7•%};M6ųrIųÍØõ―Ÿ.r4ģœx°s2u>ŸUĨ’ˆwÞyįFƒWēĸ辟G(3BjS€ÁqjW•ˆ1MIĩĖÜÏ q}.HÕ+Š·ųuZžsōĄhĖ,ĢëÚį[ŊKáŨ·jõožcÍÖš”õÜw*#âT5Č'Ąė+éĀXŅŠĖĻŊ ŠŌ4ÃhfĖ”yÐã“9‰ÖI’ãāȓSŠ~ĸïQ‰ƒ­Y Žˆm„%=û™uzŅWŽÉdðÎMûô­ÍŪLų~ēŠð"í;ïüIĻåŲ§JĪ•ŠŨ―Ŧ€§QÁžqAtÚuM‘Œ Ī›fCSƒ(Āß―UåÆho•Tn~­ëŲÏ9ÛÝT<)'§NĄĨSÕpyúvN ģĖÜÍēŧsHģ&FÏģ!™ÅÉŽBUǘ'Û"@G ĻL+UU„§ŠÆå•YFÐļO?·Q$óŲTu?yž9õ#ö}›yŽH•‡E†dpĮŨk'ĢõģÉÂ&[rw+U?›Ė žóÎ;°œœæÎŸûGÅ+.ˆįyĻęÕʓÐmš%ŅįL ŸÏeŠo#JŠ#ȖÝ―sZÅú&‹w"cš{kķTÔįŋU§—Ô*)Uf8Qß^Þ빔%}ŧjvįrđ1–Ļ*šĨN/•óÝHŠéBß AwÝðXŨ #öyĶ莠Ö~Ĩ9gÅn*císhF’‰į9pũ0eē„’Ņrï§ģAœ Į ›Šģ_WsĘUj*ÃéūŸCžóÎ;îXLc„ýï?swvðŦyX+–Ī/?ũ&Hc4EÐŅ0VjwŲdĮėsŠÂ.k"šW°aHāÕĘÖŪ)ÓgÅčŠŦtÎÎĖôŪĸ>; ‚Ü­ÍŠX°2ëï:wĢ›@Ð~ƒd|ĨĒyŊØhw=g_!Ó~vgË~JĘSá)3KRüwíŸg"ÄÐIáe DĄÜy-ŋïgV~'ZÔeΉ.cNs#Z?‹uųėË#Ø'i YB:eaxįwþāV›YM[•ûˇôo•V5IJMÞÁįœ'XY$,|ô[ ,LÍÓN<ë9Ó[ãF%a]WB ÝãšŪaK{ *ŦÐ/8N_Þô‚ŠŠÆ<‰Ōėā'ÏĐûr€ÓÉĻDHþíÔQ'ÞšŽNĨŊøŠĸvŲīSFšŅzáĨV„ÃæïšÖ3o$fVõ-4û- ŧ“#°…ÛpÉ;á!;iauDū†wÞųŧnąNYúŽÞFÝhn1SĨĮÜÂWVUâڊÔŅ\•=ū;ČĀ vž‡†ëšÝįQņģÚîõ…ÎþA|yîočA„g?ƚحŽŋq‹ģ@Aæ.M qö)ÁÃdՔãV Pęã,Sģ˜ÍŒIėėĮŒcrŦL'IõŨî᧚ĩXU+‚nOîĘcfĘÚÏŪŠųSŒfv< ęĸŒvß7ĪގŅ4…<ĒŊyįwþÐszhŒˆŲs'd`bĪŲPĸ}ŪSĩM”WŽŽDĩþŸĖsĖÂÄĘRA öÅ7kvBŨšĪÚûŒk@j“ë—„R]keŋÔ)Ję2›OĮ†Ýæq]‘YĻ2 sBÅ„ÍóÏÖđŸãîë{B%°û"O3=?ĸŧĢcpJÕN3w·ĸŋ4[Ŧ”‹ŒĻŠHN§YĐžŊVŋÔ|ý<đũ5V‰*]WėÃĖ$Þyįŋ§@ A;úWfN57ÏsïóôðF=đۄÕķ3jU}ƒh:ߠІDá-ˉ_ô\ë[t8Ð3…7î>N3‚îĶʎ\øæČLüÍj%Öô0‚8]væa$Ī1û9―Wyø7Yą―ē7Vïģ ČÍ$MõŨ<35Ëŧ™Ņ0.•û>ĸCî$ĘÍÝģįÜŧ?iĘÔÖmÛ2•ëF@ĢŊŠūČä„(J–.5`ÐÐĄąĢī,ÍÆ)æÐËï6kI‰ž2ĸ‘Āž4d°—vK4ōļÛēi&Ü⍊ŧ͒,Xøī@fSO“‘ĶdT”‹?ˊF.Ō8ėš,á%ÜŒá–ī°M$x8VærĖĶčĮ›~Šû`ZŽf’(XÜ3Ԉ…C[Æ  )ØÕR,#―·še–YÛb$B™]srQ!RJpŅíÎŦ5tÄȆ ĢÁÆÉS'æ|ųåĨ.ņllē_E8FŧĀHEo‘ĻJ•ŠĢFųiÁü=;ķ›N ĀF™=#}ĢŊŊ_ĸýý\ ~˜+ŲXLĨŽîü‹l˜„,0QQðå%0§āxžRKՃŲŲbJÝÓ°ĐöP€cZˆĶĐeücŠķŽ@ÝĶ_$œãOPÍ_Z† -g4eZ@ėTĩĢ_̊‹n;IÁū.n#{&a LŦ34LÄ―ĀēiÄ$ęĀ{Ļ|Jc ý,ģĖēâ˜ėĨPRIYvĻĩųˆ?[čÎ/ĻYĸįÅK{öėuåōe[ŦVí€Ā …CøBuĢęååįÛ―%uŸÔۊ•žĐ•——‡§É/ģäā;6iÞŌåråfį},ĐÅÕîŠO5u—Õ9]+"ĒúsÏĢĀû #ī­S/Šnd―‚'ųŠOðĪf툆ŅMüüh˜ÂŪÎ2xSxšÚ°B“ņ*shŌœnŒų€0+KJ&Žn”ißŧ†/DY\=⧘ဠ†Đ:fƒ;ÂŨ&RĀ1“ÄÆXŧŠ8j›OŌD~M?đŽ"Ieó1u”eĻôļÅÚâh–Y^­„ LE}šĮYËw?a_+ϝŨģũUŦV]ēxQ|Ütä_Ī?Ļôlåļ3^lð49{öô§ÓĶ]š˜Ô―GŊ§~4SŪ_ÏĘĘ1xĢ]šu5š|HHfæã•Ë—-]ēXÓcĩëŒZņ™ĐÓ?ŒŠXGŽŽ›6å™gžýxÚô°ðęôÜŲ3ßÎųæíū}›6mŽ›™žþpęäÉGŽü)1O­ĩ5ŧTkiMƒÄ_U‘ž^S'i âCCÝõ“š\TÚÃSĮv‡_kŨvōΉū>ÎÏâgĶ$'"hÞĒåŪ;OžHôsđ‚ƒzŋņVŌųs›6n ŊþÏ?—DáEclná–ō§I!0ÅĖŦĄX/ēķ@'šM?SVk“WmO< p:|đq6ýė^âÝCKãëƒQöĖšīÅõ$a-~ÉôčÄ[Ģ †ÍFYAĄ[ĒWĄGX%Ō‹$B@ėMÂēĘ=XfYą4Ŧ0Ũøv#š@-ôņõóũāDnnžČYÉæđ?›5k~ýúõ/>Ÿ1ãģOϞ=K·\ųōU*WÞņûï_ÄĮ͝óMff& ŊXą"`·nÝC*”ũũóŦV-ÜĢ$4õļLR!22 Î7mŌĪaÃFļąÏ=ũ|ZZWUýđį@įŌĨŋ’Ar\EâĀóuؘ cBÓ_GCҜ` ĢŪĘÚČ.Ii|ޚĄå1˜ėä@1íKŌ2`-ðU-1ÕļąYfYņ3ËŦ%XéŅâ~oÂģÄ7ÉuRÏ+ ŠeĪßgŦT!1KŸ–u·ÞĮĐš\’ŅEdT|ääæB(Ē·xŧRÚŦĢý.]üįDâÉÛ·nēŠI‰ĩaŽŦʄŌč[[.ŪXūėÄÉŦ—/Ïzœ9tøˆąãÆ·íÐá݁úžŲ{øˆØn=zķmßaøŧƒØÏušø,›NÚGųÞX@ýV-Ĩõ—xŒõņv’`ĘyĶų6_ ô@™iïĻ)en›ö`įĘÅųeB“‹B˜·”xāïja…S—~ĒņY)V0rÚ$ßķĀĶåsÔþō!1RÝj[ĄŅTÔÏÄ2Ë,+†"Šē5D“ņÄpČ`(„‚ĮŽg@ßūý:vމnÜĪcLLhhÅëÉŨ+UŠÝ0:**ę…^ļuón,ČŦQŧvDFŅJ—. <|ˆ3?þáûđ?Ė›ŧsûoĐĸþkš„2ļxøðÁý{ũ@Þū―{gÏúbݚÕΟ ŋy3eÜčQGŽĐQ‡`…;??núīïūÃĖÍZķjÔīéČŅãļņ:ņK…t0U―\t;į4 Cņ+5øx Jē2oÔK=ô6ōēvĄĄĶĘ:Dī‘Á* Ū)Ļ‘UÆ"NÍr35u„ŒÅ Æ4ė-…alšiņŪi'É,äâ‚hLŽÃf™eÅÐŽj1Ýēũ˜„xaęĒŋę·rÅRō †ķjÍ:†fffulũÚôĐ-HX4oþOœ!íé‡ïŋŧvíĘŸp<7nýíöíÛ999W.]ZšäNnųm{nn.œy§Ï›xvęę ō\~.žæŋýföW_;wÞžīÔīŌeJ5ë‹R%K{ũîÝōåËïÜđŽoÝūãáƒ‡Ė™’’ēgįÎ~vëÞ=)éÜŋwn;y`ũhÉŊ S{=ĻĶKTDĸ“Áá5ĨīļÞzif;ËĢ+Š?k\Nuâ=FíAĢ(š+žrãy‰š&"!ƒĪSŧĒĨ]Mā"—ËŪ _üÉË$ÐfVaXŧ@/Y.žø6žąĖ2+€āņ([}œjëaĮú ŪĄę‰‘ƒ—‰:vĄz… PÝn/ÁŧO˜ÖđâÍąŊ歘Pļ„ ĩõ] ÐM‚ÁNČÅōLĒĪ֞ŧŠ& ŌÝO8@ŧK°Ŋ!Wӌ֘NåņVA/ÕēAe0 AķKĪ΁#i@›iüĐMÖ­Ųã fŨč)gđZ&áuõRU―Ė4gt˜F82 +j>˜ÎV(A.ã5ӐœóŠļ`ÂöBŲ+d ՟,â 8še–YØbDgŒÎĉ…1øoœ„YY™x|āŌä-1œrĻaŌEI\uįđ§>ĸi~ÃWēŊ0|Xãį2ģÝ#.ĪĻ―2lDôd 9öpėQg“Á Lųe—Î]ĘDī ą§O^ŌÚÖdYQðŠŒQðå2Üāš}åeîOôšLOIU:dnĄŠTˆT žĩÆgÕ―VÏUÝU.°>U‘.-KcB­Jģk؁/kŦëjš,ĻoŦųžÄP“Wkš—ó ęŋp―xöģĖ2ËŦÅëTGĖôŠ֓/2Ž6ŧŠâÃvčØiō”Đ“>šŌķ}GАÁ2BāårAĒS%W8mŨT Eso`ƒ§Đþ,Ý―ī8Õ(ā-$QОl!8†Ū*.ã€uĶ)/J9˜fó25ÔæĀô­^ތýÃB ·T˜Ë5 sEv–ø­ŅņÂ6F†|%øí;N1&Äü#·)Zqž5°KĖŽ,­ēßU·ÚĪ{Ūiē€ŠúĒ7ģ9]Eé,N˜˜[S-Ģ&Ū –Águ†KģĖ2+€ā0i^ð ĘhV“iy ĀÔäĐSüéįqïM3nüÜy?F֍ĖÏéðiņq%@ Ûôî|w^nxB―0'7į–čjn~><$t[ģF­]{ũGÕ‘?,ŠŊ_UÕgL:ŠGå­".œ7ÍĘøÕĻWnpA@˜Í/ÍËwCGí'_ÆgŠ–+xŲ™Ë͑"]›6\.íŧ#\ī‰ôļšZ9ĶyÚ’Ærhęna+Lͅ“R46ЄâúÂÜT—i34†1Üiž~fŅ W+kÕ5įĘŽtŊâh–YĻ…AðLãŠNĩô=;;Ŧ[Ï^C† ŋ›–62vøĻØ æĢ&ÓĐsLĸAƒ#Ģę?žjz{ĩnÓöĢ)ÓGŒõBÍZųî—+ }ûŽï8iZÜgŊūÚĶT™ŌaaaM›^722vô˜qï―ĸ(33ĪBhŋƒââŋˆéÜ5 0˜ĀÄfËČøîČQbštŽé2í“ÏÞxã­°°ę2í“:A=ˆXŪ\ų·ßé;-.~øˆ‘Tēåäå M3yęôjÕÂzŋõöoũuđü"jŨ7áÃĐÓãÐĐÓ切–*6éÁ%9Az+Ļ:Hį…čŦ]u9ŊW….Ā“ĶāAƒ$|Vš†‡-ærújF‹Áðm•Úð. öåå"áŧÍjÄP<Í2Ŧ0W$[―ėFVT=Õ|ååWðpį|={ŲĒÅÁ%‚pņð"Įžũ>T‚~2}Zýú Æŋ7áĀþý­_}ĩoĸĢb‡_ž4óŦŲŠfë0`āėŊf%_KŽŽWYÃÃŦįåæUzĶōóao“ûŅäŅHDqąM›vũÓîčũvėÐ!“'~āvįG7jr`ïcņþâã>6dHÃhŠ|›üšnݔɓþĶkW??ŋđßΙĸé―{ũští†ęcėšö@ڀäĒiEþTQG§ÔŨŠģIÐAzŦ#Y@äZcxūÚȉŦŦM å<;uŒÄ}eˆ]ã„{1‰&0ŒSĶxĖĶÞąŽ4t†ÔÅ1|`™eV^-leO)Ā!YŦ@ā”áúáâ!>>xĶՍi-OķlÚt))éĨčFŒ,[ķė†M[™M­Ûī™ðÁÄŠÕŠ!/ ĖJ–,ąr ·Û2ŌÓedē0ŪqįÎ1L Ęý]~x“ĒÅeËČH?tð@ ;{æLâņŋaé”ĐÓ*VzÖĀņÄßĮ“Sn&''CŊō!åŊ]―ÂÉöĸuė0éå˖įŠfÎú’ æz?~L\$?7ÎęĶĄš6:‡›Ō˖ÛÁåųÓÄmEÂFi‰ÉJ&’:ī€ÐÞkĶ™· 4kæ–TÎ2˜™9dŽ6°(\öĩāō!dåd+Ð-ģŽšÕðF%Žk†Đ“‡ßėĖė+WŊīhÕŠMÛ6öĸļW™ēåØÄ—þ1*RĢūĪĻ ÝÔarsē]~~ũîÝýôģϚ4m:vĖĻ))ŦŨþ*%ŋŠ fzŒģ"ę_üëÖ-K/âՀ  +—/ąÄœp r™RS:!ņP-?3xFFĸ>ûlîĮåōet~~ūLŦÛýøŽėååį‚ˏ'MLJJÂ―e"Þĩ#îĨĨfefzÉÔ:ģ˜4h„§FvĮĻ‚ÁYøĐb4ZEĮ‹[Zíöh.€g§ÝÉwƒ·–Ĩ1%+rÞdā2ÔĐlՔŒ"SSį.`°·ÕœžØše–4ļîųÛE†Uŧuųx4įßŨÏwóĶk 48Ēn$ötrDÃw3e­ÄCϞ>Õšõką#G%%' ûóO?đÝBŪFwęCŋE é ‡ž;Žq“Ķ;ķĸŽ(mŨŪÝ-„Ą*TčŨįMi‘°ŒŌ[TÉ―US–y|1mg‹A―Sĸ ŲĮŒŊZxxÓfÍēŲ―k‘\ðLÍ0›]„öïÛŨŽy‹Áï;üįŸaáagNŸAÚfņ’e[7o"dQä1jđðP€čãPœXlĸū―ˆl‘3pųŌĨüžü‹ÎïÞĩ“(%’ûéÔĐŋŪ[ƒ’wŨî=lš·°rÅō‰‰l—Ą þýÜoÜŠÖŪZq`ĸūšĩkŨĻY:4i"ý^kÛ.šQãīīTžĘMã]TÁöþą‡Ą*KėÝģûė™Ó<‰gįdïÛûođ|åōØŅ̈° †d8ĮįΜNøKštéxæ }é/‹P ėŌ­[åĘUŌŌîÃ›Æ2ĐĐ8īä_rģ*c$ `(xįÆĸïIãĒJįĮ' YžXӒaš-VĜ8ÂÚ=·ÐHŒÎ6ýŒ>ƒ‘ƒāŪ4_íŋ f°YfYą3ËŦe?G €,ĪŸýĸ")Ād>x ņøąÐ $$ü{ûĶŋ_ĀǟüøC``€ËŨ`•+—c‡­XąnéÍɧðũDâßÁÁÁũïßËÉÎa6ĻĮ°7{ũŽTéŲîûlÞ°aũÎ!ĄĄ9YY0 xŨļ„ééũĮމčįōC Žgũ.x›AĸÞūÝĢkv­XåāÞ='ĸ*]Ķ,ąāėĖ,öčNœHėÓ9Ā?€ē H Ŋg͜ąhaod ô™Ýb:’ü`BĨDφÐJađGčI ú­ÞúiHm…$ۚĘc‡œ—*r •ĮØU‘[ĢĒ ņ›æu=UO™“žŅMĄģR›dۜbŦĩĖ2+€ õþ”Į‚5“…`€Āq@` čžsû6ĮAÁ`ČEÞŽŋŋ*ˆ?• 4_)™MK―ß~~.Ü8čEÜ6?/ÄĀPÄķ―‘ÝĒƒGKr ģâ#Þļž đ`%kU6á` ã4t L°KÛpõ7yŊ·ÍiËÉÎÍÎNa·ŠžéĢĐ]ŧõ0ä‚ÏĸáRO/… ÂŨ%Ð#RĶÉ# Y–uĄļn4Đv ņPĢŌ âMÐĘŌ&0Ę[eā`ŠôĒGa.žē*č0VHËĖžEpïåŒ%J–č?dČØũÞGRĮKe҇oŦ9`^ųnÖ0BčĪmSd͙Y<}ŪY[šËeŠë,|Ũ―&ö-*ãâþÛīæ—–YfY1D-FĒ’·F0ŅN„đhĮô<čwĘfũėÛ{čpÂĒ%=Þx ·Ve`ÁÎĢp€ŅŸOPå`Ī%ļ;Ŋ@CķÐÐgƎŨđsgœG!Žt2^F™[Pρ=Œ‹ČÍÎa}‡ŊęoŲ8Ž;/(Ŧ"8€sã5r#\/\0 Ä2ŊÛÍ øâbkũM‘ąG5h8`ž]Ý?j|íšÞ‹*’]*ģ íÉE#4LþŲ;ïôs8xUÛ'*‚ķqs €ļz˒xŦ) PX\WŅu”+ÔūčÎĸĒ(vĶqHV­ę&@x>ū48oģĖ2ˊ!jĨ6ķ‚ ĄYÍ(0RĨjUŠđŽ=J’ÖÜđó† Ĩ 9ĸYŲŲÔ­WGs éïïŨāĨčĀ€ RĨJ5mŲŌnӝwÅ8Ðb>_É%Đ. ­ô,„ .Õ šQíČššoVTéŲĘ-_i]ĄB(ÃoóČsų3•*―ذĄŊ˟+ĄoÃFMčóHč4((ļQģĶĩ"ę0U×6 Ŧž—ųY―Q“\|é2eę֋z)šq•jáxŽ>ūNĪp5iÖžUŦ:‘‘P’ŊrokÔŽÅā   ņR §ŲÍĢĢIóV~~þ\ ĐšyųyÄ6HJŦ\ĨŠĐS(Qšä‹ ĢIo(]ķ\ý@ðü‚ü°ęÕ4Œ†þÆŧ%ÎĀõð@аĐeĨs‡ÓRõēĖēbŠZí؈+)^$LÁ•ó  lē?17ŽĸuLė°þïôĄúkČÐaþĨK•™Ÿ°p؊•‹–,ĸóÂråËUĐ6û›9ŸÍ˜đjíŊ‹~YōcBBđō南,ĀĩÛ{ôzcóķí ‹~ųíũĻ|å忯ÅþÏ?• A§åƒ‰“ZļČČÞĪzbėøũŨoڒ°pņÆÍ[:@Ö`éē‘‘2E7nžtŲJę&ŠU ß°e낅 WŪųuæŽŲKDFEÍĸ)aÄĻŅŧþØ7jĖØ?/ŒûlFPpÉŋ€/g=uú§_Ïų.nÆįeJ—íÖŦũ/˖0i2ßÝ{ôZēlyÕ*ÕļTxLXČ·íØõZŧöđYŲ 71WōëÆÍLú˜8F―Ļú_Íþf܄ 6o8q21kîeÍŊģlÕÚZĩ"pcņō=š{@HYyœw*Ÿ/)°D-ģŽ8Ē–^ó.‰JvéAĀ/iVÚŨFÂŦ"ãQúĨ‹Ž?N-ƒŊŋë~ýŧũčņõlzæ~Lâ„'([Ū\›ví~ûm[bâß_ï4`ā`ęLtĒV͈øŸãZRŅ€L,•GýLŸ2yÁónßū…ŧJüã3čSĢÆ |ÏT%,ÍÁĄC;węĀ*ÍZīdŅzõęuęԉŦ ŊnwˆĶ˜EΆ­9;y Q}†°@k™eÅē0W‘JČRiĀ>ūHbë+°ÂžJÜķdÉRuęāŊ]XÉy°HÄvՊļ{”Ĩjũi­H€’C<8&`™MeLĩ+Š]’Þïįšuû&zĩ ĢĩkßþîÝŧ§OôŌiĐĶRŦHÅīþØ―kݚĩˆ-Ž^ĩĒråĘ]ŧũŽXņ™åKS• ïļxŪōþý‹.ĒiđC[9ÜpŸĐƒŽþ“âāöí;īlՊrĩ”ë)T eggSC\šlY4vÞŋßūcĮ hBff>æĶa7^6|äŪđ}Qf°›\.S-\ļð\Ōy_—‹[{øð>›b%J”"#BóɞŲžiuÉ{)*r?qÛ―1‡ÖžÉf“-ģĖēbV˜K^­6—õŌ ­@AÚkkó.Éý‚)õ_ŽÏ^{ï·úDDD,^īðæÍ”;wRÁÜÁýû ”ŦĒŲZŌąZĩjõĢāE2Ō…BlåA›yę֍ŽŲįūœžzųōĸÝī~ýœïæōŪíŋĸ~ëÆ ―fēd`üųsgW­XČ^.'1„ôôôþ"eðÏ?—‰6ÜI―S!ĪÂúukRnÜ­š–z·ZĩŠrGŌÓĖIŅëþþÛ6Īpũę•+ïĶþËÍ;~ėåWZóÞ-76F'ĶKfffōĩŦxôZf’ä€ŧļwũ.ŲO%`―îFĘõŠÏTšïåÅĶB—Uēē Į IIKR‚Œ•*UēßĀÁ„ķ·oÛĒIn|ņlÉ^ŧÅ0€`™eVAŧ%JY4į~ŠŅÍEęū 9‚YØā!CŲ‹ŒŽ—°ā“iSxÄ^0ÞõääŲsælÜķmã–míÛŋîÎËÏ#ÕtÝæÍėŅ:aõĘZ§kCšāÐūý?þðC˖­vėŲ;zėļƒnŲļž#ęuÂĩ?öėÎĘĘr`NÉ?]đléîÝŧ énŲöûú-ÂJbĶgNŸ>qâo@vüčŅ įÏ?JOŸûÍŨh$.]ąŠíĐĩë7ÕŠ][|Fé†āā€ßœÜœÝ;wâÆÂý];·ûûÞMMÛĸĮŽsóƍë)Éį“’ðÐSRۃE§ü8TpŌȆëŨŪ};įky—Ŋ\―qËo+WŊ%iÁ„)ļYĐ#sŧŨŪ^˜˜øáÄIë7oÞ°iKï7ÞŠZ-lâĪÉÃccÉ^(ŌĒ1)’à.ŋÅŅ,ģĖQ6ÉÓ>vÆáŅjïnß?de ĶĶņKãØÔī;ˆ…ĢøEäīkĖë/ŋō*^^â_Įþþë8M"’Î͛ûmÍZûũîA,ļTÉÖ-šggeúļ|gÄ}ēkĮïäHĨ$'Úŋ°úļ™īĀ}įÎ^ōöņÆĀEééb‡nÕę•ðįŸŋuóÆáC‡čæ<ß7nVŲø;ĐĐĶĢĖž]ŧÚ―ú2ÍHĖ:väð™3§€lëVÍø2pĻæ ”§Ķ ;wŸøīīžąûŽ_ģæČáCéÔ,ŽZķtÏÎxĩāØåë6t))æÕÞÝŧ”īrÉŌÄŋþ"OŒ'š‘r=:·jÞ|ąß•šz§ĸ;o5mÖ",<üĘåŽ=’þ0}ôČXž`c.ClĩƒEđe–YVüš0-ÉŪįHƒ°°ö…īŧĐIᎠ}™ę,™p HļníjP+ņōîƒ9H=|˜uĻy9đ.&I‹\ööüuü@Ôļ§Ðžĸ !íÚķ­QĢæŨ_}IŽÖ…Ž­ö0WŅĄØM›~…N6L[Ïš|}‘ ŧ›–Ęã=ĐŊ,MđÄÕŦW“Ŋ]`ø°Þu.Ģ/ÃEr,)kÜĐIܚžŠ Û,ģĖēâØœ\MËþw,2ŽĘ…BĐ[ÕÞïo 6LðgšĘą—üāZŽ=rÎėŊØV3BfHjmĄģGč €ĩfxčĸÉ'}zũš?ï{·–ciŽøƒøŒĢ` ĸš1xĖ‚g•ïÂ8ËŠL—ĘÓĐĀ…Ô†ĪŽ‡ņîŧƒúŊĸėÁŪėL’›IFd֝·ąý؆Î=čîĸ”2"čūŌđcÞÎb€Sߊ Ī2Ą ‹ 2Đĸõ?ŨÞëĩ ũī"Öë5žSĮ·ĪzB ęĐ=ó{iļ=’‚z*"B1ó-Đ Î9ãŲ{ƒčûšBÏé2Ą €$>|øq|ēgr%ĐŦ.™YįŒ-jïUÓcČ uÎĨˆ?vï^kW @ûߏB“īįņ†"ËÉfwu7āõZĸę·Ÿî˜ĻS Ā8îL‰1ÓÆ·”WÕĖ0”™įI0"óšÞ6ö~QŠëZũÅkė@üŦŊöœVd„@<7fÄõūÆCjŋvuSĪIŠš"ô§ 먨kWWUe„"šš4ïsx­mŧ§žtÅ5ãđqĘ6Ą§Ü‹bFč'Jí‡WkŊ\n?ÂAišIíĩ#TžęJbwÃHėšÚk―î(@’íøN ė1О>į$U3ķ13UÄÚŊSŋWÉ|æVŨĘEpl1ÝuÛŊĩŦŧN‡€ĪĩōÔÕ=vwÕ=Ų7‘AɆÁĖÕ㞉ˆÎu`äZÏuXđIúæ;Ķ2cåžĀđēŦgœ·5}*hũÞmH!ŠŧEý†œ’Ą€Ý݆ũZ·:C s.Ûkí―_3ÓU’<>uDJšÓęœÕE€T†NÛũ"h ö\ŨõôüÎ lkížĐęĩŒSe82m\íäÃ'ŦUÝ5Ĩ`fvũ­nKŌ隚―wDTÏdÄüÉ7aT!*T3$`Hš™oééŠ:ö)`$…Ô}@„ršß_ïäĘByęT ĖgWˆ\IâšÞ0_ûuŪ[ §2TUĪ†dÐc]uŠū_ôM+dōŧöÛcx<§Ū™ ́Ŧ‹dd‚Pˆ ]m@ ŊS _ąŒ}ŠDg€―^+ŌŠPðýþĒôˆoŧ žöŊ:åņĮÕþ@>|ēZ61Ūsa:VÐėžHøzŋEp§íņ„˜+ŊũQbÄ:ŨÛĶĪXŅÓ (šM2#$;ŸM…ĪũulÅZ *3ĶÆcIÉė* v.@į\ąVz4—ÁÓĮÚĐļî`wį2Ü3  RŽëawHŽXïó†AU%)#”qÎE>ųĀ!EbïuŪCޓ‰Óc;3Ë5c†V|wĄŅ–ēęô M„ÛŽû+ē§ ņáÃÏã#ĩÄôH~åëŊë‹DŪ°<5ŧút\iEŠ`D0ãúšLŊ\Î9uúûÍ@0Û#Bïë"™‘‘yÎ!ą^{šjL0WNwAŪĖžn;S3ŪúēÓ°ÍýzMÏÔ(ĩ”§ÏkåĖxPŪd(ÔÕ3óT ‘kÝ;œđIØ―V‚Š:SĮ·Xũô”sÐû:3ýoŋv5î·mĖ•=ƒāTT@ĄdčzŋSĐPuŅR€sNP+ó}§%„">üD>§Åi―Ï% ’hĶHá:‡ŌZÛeOO§“VdāŽ5ŧö~EFuMĪî-0”ÝeFPUÅ{@•™=UÝ"vŪS§š%’ Đý뗁îō8"ę<Š<ĄļþœA y‹b*ž:Ïɂ™Á€@î5Ó ņŪk€'ŸÅ@ņ›[ĩM’lØđŌxĪóÎ^kš{ïsN%)ĢŦ(#"ŪsŠÄôL›B§ÛöÉÄ`ðáÃOä“ÕŪåGYö Eũx Ðm‹Š\ã,EŪ8ufžŨRęôEjí­āy_#ĢĶ`b™u†ŠˆPc`ˆŠŒigdóüȕïëkÚAQžęˆ uŠdū–i‰ÆėÜ]5c˜Rī[ŽßH§{ŒĖžEo"˜;įš·ēwPKkÆ=Ý€ßGŅĶWfWŨTfĪâ\‡ũéd€3Ũšĸ@‹„}]ï™Þ+IÖÜĮ”Ũ/]sĐ&œ+ôM|øðųļÚvWÓ>SķEuW―/ØĄ8__] 3"lũÔī{ĶOÃĖuG!M5z@C–2# ã§ņáÃ'@Eæ:įÃvu)cåwõō}]°%’lÏRĀči"ĒšŠ.Û{í™ņi1šŠ*"Cņ>ï:™ä·ÞdčœŦŠũĘýÚķAfĘÆī‚Šž2,iĶđrU@Ĩ \ïũôÕ}ˆX{Ũ” ÚsOž$ÏU.ŊĖq{ÆF0NÕ#‚+óŽŒ+"M·ýĖc˜ÂZëL Ž•4N—iš`wOĶ$yFRJį\ïs"Âð™!ˆĮ‡Ÿš™{Ðæ"ÂUqŽĻ:°% :§f&aOŧĪP kíŦ.ĩVJU!ŪĀ3Ŋ―>Ý)íýšÛDƒã ĀÞËvũ‰X"Ï9‰X;Ŋũ1ķßįšgûeŒíĩž đĨîī7,\_o+ˆS‡ŌĘuŪwaú]Ų#BĻ:ï2œë’bÏĖ9Áˆu―ß(ĶēúĖX’B_ïũĘĖ\ëœĸz―ŪSwl’î~$>|\-Ĩ™‰Ėé>Ũą_ŧ{HDæZŦšj*2"8öØŧb˜nOß"ģŦ Ī$ŨŸ-Ĩ zšŠöÞcOOˆĪzšũeīó(IӃ?N@DތŠžÖÎįúĖÞë^ž§ĄS§g!ā:—Äņˆr·grĨq ī'#íīs­―Ÿ|VЈuUu21ÓSĄˆČé6L+s}ņˆLEuÍxå @ŪTJÂđ.Ãûõę™HeĪ€žfČ6~">|új1*‘‘;vũø7°}Î;ÞŨ5Ýš’PėnI§P<§ÎDF€Šųú·_ķįžX”áŪóøÁîē-…įmUîUU$!FDwÏLū–oÉÎ\ûõØ3žYkMũØĢ<‚ŊŧeqfÖ^Š öÝŨÕu‰PÎ<Ę zJbîeĢĮdͰcåx(Ī’äĖČĀíïÕŧæ^;wÕ!3}/MAŸ„ŸÉ‡OģWP5&ųhkdˆŽSOîЈëûBLUÍØ+OŒIūöŦšIØōœ ãÜŧК•+5ũ`’ņ˜RJIūßïČif<ÃÛxžëęi1<0 €Īís]RäZvCˆˆžïڗG[)EÆØ]%éĩvwSŒÜ4nï\É'$!3“äéÀ3Ņݙ9]6"ģęRFBķ=CJDWļ^ŲShĻEР93øĸāð_ƒ>ðÆöŽÔžŪëßĸþWwŊ•UÁ–b:{ŠŧĨȈîîjJ ý9Ϛ]uŠ1ÃÐ___"‚Āųûą-ЧßįxÜåĐ+"CųžŪ*Qk­ŊũÄŲ3”úŠýÚ_ó5ÝaāÏT#’āp’qČžéŠ―öŨ{šāĘøĮ?þņä‘ņ á/w7îĸƒŋÎ?ï ĐČéŪnIqéņݙ9ÓbŒ'îEŧ'ĪH]ïũÓË3MτRRU‹XkõLCÅZëŸĸü‡Ė<ĀÕãËāßþų~þąðĸ`ûïĸĮŋ>%ŲÝøŊÁ‡"ō_zōëŨŊĸĐ=UĸíŋĸsŪŨëόĪĻs.’BQS0ĢęDAĀã{åęi""ÖÜ2úxÞ&HbÆßyBfũķkwþFŧŽ"(øŽĻ:Ī œnJ?2*҆íGøžŊ3DĻŠũ~UŠ0öLƒ’Ôį("ĪąĮ3=k­Ūú~pÅLČHÃU5ž• u§ĀЧ+(?ŅAßXSƒPÄô (ÅĸiïÞĢĢ*ō<€WÝGw:Īóėžy ‰d„,ēš*‚Ę:*Ē ‚Ļ€^ĘS$<#Ļ€Ē;šŒeÖœQģBØÃČS°ĘÃĪ%$é<š;ÝũUõÛNįėÎn'gā$;Ųß᜜“ŪšU}óGS§ęvÞęv˜§ëÆõ9}î\UCƒ“„„c,7wĀlĐÓé ķ*‹%°hī―Īýjxīœ\A‡ŋw:y—ïđÓނ”ÓiHnžįā )Õ5]Q|ŨlýY/I"A…J‰a0]ŨoÎ9éYĖ2IŒ#Ŧ‰úuKÔ2ÆG]]Ē(ĄŸģaaa‰‰‰)))‚ „B æė™OÕÕV— @zY€›œ—aŧ%ÎHÛŪŽZJiMMMKKË AƒâââHČŦŊŊĸþûï ###Æķ!JˆW'?Ö+įŦ›Ģ"­Ų·D‡™L=éī'€&·ũŌÏΓWZ,ĶļĖ*‹š6jāęÕŦųųų="gýėv;?~Üĩ$ „(qĐüJĢFeóÐ~I9ĐÖÎ'=;‘RBĀÜĖ,bWģ\Jä~JŋŧÜPë6RmĒI"]ĩ>Ÿ/66–tÔÚęj·Jã“Sb",ä/Š·•Čáaē@šT||žŨë%!!ĪāÓļ%Üc•m‘tJó8Ŧk„˜cââĒc"rCļâņIáVI ]H 46Ęj@ĢĒƒîY€N·ÅĨÔh~{ÃËoí<FÛ]Ŋ|þú4ÓõWS †ÚčōEŲĒLĒ û<- ÄÆD āų`áģîŨߝÖĩĸ‚Ü-B(FЁLép8Š)ĸdýŦoþ IēÂÍaÉ+~[vOFØu-‚·SZ[|šmģRĢúÕ§ÝQōî――­ÐU·ÍųÍLxH7ąWc‡7-HZuÅkïŸ\UöՃéîÃ?0níG)p %@Đ^wŽļpÛīuoôŽŧúĮíÅïÔnúÍš$‡ŸėíÅXāōĀPJ8ãm Å@üU8gā/Ą„pŌþGwB(Ä „(IÎïūxæáýŸŲ\ūô1Ņ[ûmå·Đāy"PāŒņö| ÐT”ŽoXđ)úcDß?uRzŽČĸï\iŧŠ­ĄĒHã8ä›c@ü=ý9N;ŠĄ­9ãĀš7j€sÞŅđTtMauÄãē%ö›HTÍð:NnX?ũŦSzþļÂWį>ð՞OĘ>ýøðÅš9 Š.ė.ûŨ]UœŨÞ(]Ņ|þĻ+"ohBCéÜÍ<ËzxOy}ÆCïŽ{);^ŽŪøíē’ĩ?ļ~‘?(6"ģ`QŅļc;JKķýÎMŲėMeãĨ1Æ;›ĐA… ļaÁ"JTÛWþ;oþ”ĩK§%F2ÃÚkÔŊúpf\:ĩoóšŨū­Q3ođč•đ‰°kÅÚ*YržŲ{āZîŌkĮeīlŲû/ŧköO?öyņšyįíįŲwÉUŸŽ+ŊïCjvėþ2ûÁŨ.˜Ųø§…ŊUÎX5ģ—UÝ―ąļ!ņs#’þcũÛŨ펎Ϛŋ|ÅøIŒó Qk0Ý:ŠĨ”þ9mIP\5§åÏøŧŽ%ÓÆVL,œóė”Üt^2kæÁėįv•å>ý3ˆ ū/77+~ĀôEKš#ũŧË―ĸpÄūjÕĒÜ$ӖßէL~â6õ؞.{lõęĩ;fÏŲqtÂÚ;=sŸX>ąīlFæúÉ3ūŪąÏŸ3ļtÉVXüë=ĢS[Ėąí‡ôļĻE‡F˜Ņân88/6œ*ŠÆh†lV~œ=kąuôėē CKįO›6ß~ðý§§}pZ}å7Ó·Î{ïÓýãV>xwĸ>Ũš=į‘äpïŨûöŲ&/ÏlĐþxÃú“Ū_3ŦčĨĩß<öøHę8päČ$ý9ÎŲÅÓšÜGWŠþíŲ%­øp§íðō›†í^'ŧ7J€óöđî@Ð4­“íĮĐųÔ{Ý^ņåæ/LþæĀÛWTzkū?ã|xÕOÎÆ5r@Ŋh{bjf†Í™œÕßjŧŌŦo͉6 Ķë^•Īôšŧlå}Œ#·šŒđۜ=—xëûsG§Ä‰ó>ýK‡č&ÞąĄīxzՄÅ/LŽ ïlAE‚ =2Ęn{ņÉąû_<|Ņ=ą…ą V=yŨ°ōƒņTŅļ)ą·5NN흞BÕ* ÔÐ5Us& ŸēąĪÐNþ3/b{kŦG #‚háŽ-ÎD"ˆ‚q|ĸ§M5Žm‹Ÿ<Šë'zÍĢFųë!ČĻVUÁ`ŽÛŋ˜ËH˜ęSīð!#'ž•&Ý3fÞŅ+î(ƒ ü‡I/=28L6ĮĶĶ+õ—TÝĄp] LÕTÕpϜ‘qÞÖ3㜠Dóųk 8#’LšgÎýÜŧŊrp_%ĄŋԙôĀžÕÃ9[2ý…ghüŨËÆsÞã&BøČS5€Ķ'%|ûāĄ'―ŋ‚Č Ÿ§™[bäVW]ƒKė__ëh5É2á:IÐ}šĶęL–€3ĶęZƒËËÚōšs ž*ȉ‚áS ÕË€qĶ{―'œîm>{â„'á°%ĪʑYS‹ˆķÉrļ]2tF‚ „ó›YHŨdS݉Ï.ZēĄītýÆí–~y·gįL9æâŪßė)ĸúó=;OþTßŦo‚ûãw·ýþˋĐŲCĒĩo·oúį —[đáS  „ÞVƈŸækU4=<í—Sfū7ÎĒ%…~u† „ĻŽk^ĸė›Ó^nI‹!!ô74.į:ĩßÕ§ŸšQēé­·6­[PļŽJĘs—õÍ ŊūąiõËoĸ1gĘĢ™áÔ™šÆĨ†ęõŠ:7hrŋ>g~ýÎķOöš™ūV„pÁëVQŪĩ% ˜ãzĨZݛŨŽ\>gEe­4―ψ ųyę‡[?>tĻ|Ïî͜ Ī+I7w : éý‹yîkž˜ėûß(Ÿe!Bņō-#öVœļF, I&ÃũJɖ/^äģö*ذvý7UÜ áã^X­$Å(BTáŠÕ) ē‚ŋÄHUxäģïþӈãĮ\aÉđÖâ―Wía–čܜ>'ëš Š–―g8į@)ÅQ-B=KįaB˜.Åf­|sŨĻ/þpŌŅωQCîÖ?5yØŌŨû~öyM―gĘËëî+ļ]õéÏ]FÓú>ßmŋ*.Ō™æÍ]TšųũnŠ1É>sUI‚]ˆŠ˜øZ1 ̌‹öįW•$&ÉzxŸŨŨo,?úCæãM!jRŒŅk떭_ėųũęV=!5ðÍ JhÐÝȂÔtOԒŽ O0iúmífšŠŒq1gøÄž TÐUŸfðīÁũÎBSU ōFM4šëšJoE Eetčč҆âc eŋŠÎÜ;f< sPŪëÝ/Ž·Ė,)jæáOLų{Bļŋ Ɓ Ô3aԊ”@u„ëRDÂ―OLÉ9ĨĒ pŧpš0áÉé@9W5•4įÎ{‰Ąiš‘’wgŠn°ļGŸÎW5-aÔ}LņąČþcԈOŅ :Ú_Ēœd5kČhÎ  "1T•éĶØ[ž1‹rB)óyÕ ] íQĻčÆs+**ü DGG†g1ü"ļþ5\_ÓQou—ŋ?qî’G“n2|@Z”Áøĸę0xCI’O:UPP OŨ"„(%ÕÍėÐWƒK)ß/^ĶzÖý{TRųĢįlMSÁûā4sļ‰rčę‡―ėvûŲģgsrrl6ųŋ’š5(3{%Ā ƒqņ/|ļĐĐéüųóIII$D „€D™…ŒđūĄéäEgƒ+Ęd’ƒ’rđķ19ʔ)J ĪË·›ÉĖĖžtéŌącĮTUíčšÐ9Ýl6ûs6===D†ī! $ÜDúÚÃ\­Qj[Í „PŌ̈”'EJy™ŅþĻ Ý1āĮÓu―Glį+‚,ËĄöh-BHgÐāa?·hM^Æ8éYÂdš%'Ûä3õë†đÚļŽšãY„bpÂxÏûŒ ”H")Ąī{–ÅBqôƒ›ØÛˉBĻ›aÔ"„F-BaÔ"„ÂĻE!ŒZ„ú@p8‚ „BÝ@1[YYérđ0mŧBsÖ°þ˜%EEEÛķmóoÕÐÐāė"!„üĄęVĀúcöŋãT/ģ<;ĶøIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-user-flow-adding.png0100777000000000000000000000515113761647206021554 0ustar00‰PNG  IHDRŪ|ŠĪ8PLTE " !#!"$#$/..555>>>EDEJJJSRS[ZZcbbeeefffggggggnnnvvvzyy€€€€€€€€€€€€ƒƒƒ†††‡‡‡‡‡‡‰ˆˆ‹‹‹–––ššš›››ĶĶĶŽŽŽąąąššššššžžžŋūūÉČČĘĘĘĖËËĖĖĖĖĖĖÍÍÍÎÎÎÕÕÕÛÛÛÜÜÜÝÝÝÞÞÞßßßäääåååææææææææææææįįįįįįįįįįįįčččëëëíííîîîîîîîîîîîåíîÍëîĐęî„ęî„ęîƒęîƒęîƒęîƒęîƒęîƒëï…þþþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŅTņh pHYs  šœIDATxÚíMoŦ:†―°j]DˆdéxUu·ôuT õ.îĒ;ŊîĸäOÞČG{’0Í;ŠZ ļ1óĖ—ĮQ*ȂD@Ā.pļ Ā\ā‚pA€Ŧi6#ËbqÅИM5Š,W”ЉŨī~ƒļĖĘ^ŨĪ*ŧEïzZWU‘=Û‘â2™™ŨŊUf{Šų.}Ž|0Đ—ė™§ķÎ^bõŪbÅÐLĩþõ'ļīū–fŠĘŪ{ЉÃŧ^ží>ŊLīÁÐþō֛ЃáÏ=ÕÄë‰ ŽX?oĖ•péóåãŪīÕÓÔļ6e_5ßē2aFÁý3K1iZ\úéÛōŨŸÐSÆßŨķŌ›EV†#7M–[ČGĐāŪŦáštrĀ\ĢāŌ pÁŧ€ ļ  gÄuÉPāۘpýwĐpíá:ûýÓāŌ_”o‹ëÜŋq Þu}LŠëŒ7Ĩ "WīĨÆËããoäŪÅārŦŧŧëŪEāz!ųýŨĮžnŨãzý3ķÜuŨI3ŪqZsŸ<GY!ŋ \“{Ũ?$?ïNņšĩĸ,yÝ Ū—­ĸ[!RãP^Ũ,”ÓWn‘…ü-V†Å)ZhņFˆë4-t5–šîB‹7–Bþ \hņ.Åŧ Ņ„.ā.āÂû ŊëýaPã<žWtģęÞãóþ\1ãڌ7aā‚wMk HAûį3âBî:6PðþųŒļP‚!pĄÔ.āZ4ŪG•/âštrbŠ.āŪøp― ŠĮŨ#nŨë`aĸðvxa\ÃĩŲý‘ 7Šëþ}Ø5;ž0;Ū·û#fÄõķŨšzÝ7z6ōąp―íãz‹Ũë}ïáï_\˜Ũ~cø~ßčYkcÃūXPj|ōš›c—PƂkÏŧ84CԈÞ5*ۘĸĘĩŌaŽö—>ƅģĪĘđëŨĒļ€ \ā.pA€ ļ Ā.āMĘDˆĪîΔüŌĐše|“ķáŠS!=–ũŊŌ™ēó<ļ“ôÂĐ:ŦõėhōC{Iӝĩ‰2|‚‹_ȒÔŨðlZįôq6•ĻhVėd„ŦTBŌÃįR$NAÚĘe&Hu"Ô Võ'ļÆō.ÁŸ0&-ų˜õQČÕB‘N„Uķš~2M‘NFJtí;oī"\NjŌPíĪĄ/ō. †9M+KXI|4ŪT‘ēčþŽB7Ī'áÉĖwÞ%Rē3ē{6·‹xdL&uŲú“2dÕɄ3:J •ĢWvɄYÏiÅVb}•ēŧĸĻC0ôļXiôÛĶIfÂE3īĒĻéGAvE†SŌa­d—äû\íÍíJļKf’mÃC*·ļ(ވRÓo‹‰‹C/Ë>.Jes`sŅėá*`:.ÉsąeëÜ]0ÔĒ+ã{+Ëæ–] ŋ>ewTk~ļR͑iš+ ÎnēÖ~ é"óŪÔã"ïøÔiM–ßĮeý―šË&{\>ąÓ§X~œLu-gũۚ’ŠÎ]d˜!w•Ē ÄÕ$!Úâš5wĩB·áÓJ$Úę‘q5ŠŠŊR:9s‹ËîpMŧļâáÐLĸPú'—\)&ū2 ļĻ2LäĖļ8ý+>5Ō#ļŪ yÝÅŨ2 ‘Ķ™ĮeBečqųŠZFšĶŪfX3ũpq™Q+ÍeŠĨÐlŽÃÚG‡+æŪÏ%KcdÕZڜÞEĶ,RGÉB8^iQāšj!ĸÁIö›B‹DŦïÚ3ünBËģĶ’ļ–âY‚;ĀõÝe!ļ’d›Ôw­–Ó['í]>í_dÅVŨŠsÅíŠۿ̭“öیö*u‰æ5p}AŒáū/bhu^ųĨ0ųUØ:ņ‹ĀŠQÔėNŧ~xĀV`EƋgę3PZpã‘}’ŽÂē{72lʄÞqāAļ.Y咗2ū™’øFá깅%ÅNĐšâ~xÁŦӀËv+yE !œ5ZæNŅžKâĻÁ8ŲnĘī1ä]FïļΗ"iïu…Ö!ĮEđÕŅU' acēí Ō―ŠësГpžË‰ õAƒēƒ‘íĶLÛĖb\R;Ë:(ž_’6a# Ý$ŲâōaRä-.j?‹WÞz—a•ĮĨ.ĸ'#{›2—―p-ŽĩKŧ%Æï9öuÂŧJĄMÕá ec)úÞĨNz—Ü)-.rË$Ū ŦjfásWšË]U—ŧĪk}DÖtK‹‹W†Ų6wípĨM—ŧš‘íĶL‡‹Ō\âšÄŨŲĒĘ6Y_Ö]eķNšú.(k@iŧuWÛ=č*ÃŪÄŋeĒ?ēݔiqĄ2LpÍ/1žŨ ļ€ \ā.pA€ ļ Ā.ā‚ļnLþjŲ!ˆÃōIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-user-flow-installing.png0100777000000000000000000001163513761647206022476 0ustar00‰PNG  IHDRģ )b9ĶPLTE!!!"!!# !$"#111433555CCCEEEGFFPPPUTTXWWaaaeeeeeefffgggmmmsrrvvvwww{{{€€€€€€‚‚‚………‡‡‡‡‡‡‡‡‡ˆˆˆ‰‰‰———™™™›››ĨĨĨĐĐĐ­­­ĩĩĩšššŧŧŧžžžĀĀĀÉÉÉËËËĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖĖÍÍÍÎÎÎÐÐÐŅŅŅŌŌŌÓÓÓÔÔÔÕÕÕŨŨŨÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßāāāâââãããäääåååææææææææææææææææææįįįįįįįįįįįįįįįįįįįįįčččęęęíííîîîîîîîîîîîîîîîïïïðððōōōųųųþþþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ-8Q" pHYs  šœCIDATxÚíKoÛ8†‡  †€%"… ļƒCS5P“ĨķPģÐ&ÓUWÝj“Ÿ§_ũCRķ|‰'–­‹íũ õ8šóáđčĨų­†šý†!3˜ÁĀ Ė``30ƒ ĖĀ f00ģ`ģž­‹SôiRˊ^­ģ‰ų4öģĖFöį™%ŨĖvŲü:ĶĘâ{7™8û|Ûōh|f{ÏĄíĖĖ~ķÓ%{ËčnãĮÙĮĐĮøĄåŅâlß9Ô{nžŧãzļN&“+GݙkZï=‡zg6Ëé%ŧ}˜%SaöŲī=?ÎöžC―33ŸŅ7yĄŨ?ƒūąßGøŲ`'õxy0;Af#ûf`f`f`vLƒŲÓÂđ§Iõi/ïķ 07N™ŲwžÓ7Ûæôļ:ČVdÏĄ—‰æÆWŠ-žÏķ†útzýW‘]ķō4å^ĸ$ĩ+hÄ'Ę 1r#˜xf`f`vZĖðýƓc6ž?`f`fÓeķ}agcëöÃĀlfÛP7ķn? Ė ː҃ô݃üėÕš1›˜O`v‚ĖFöĖ΄ŲsŧnÎ>}{Ó­ū­žôžđaxf+„?ĮƆģaķÚÞüšÓ­îWOúīđaxfŦöý– Ã2;Îzģį72{^gö<-fÏũ[6 Ëė8sh+ģoũíŽvĸÆÜļ~ŌķŦ ĖlÅö`cÈĖ:Ï!ô C2;Îģ3čAðũbNŽlúsĖNÏĀ Ė``30ƒ ĖĀ f003˜ÁĀ Ė`'Î,Zü/ĪqšķŦųĘïÖÔĐČW#„°Sp„o'…ˆŋ)ŧēģPî ČLý3c†&UÖđHĮw„,§ŧ—ĘžÂ,UĢꊔˆęˆ&ķR".ĩ ų"…9OgúWŅÎÔ Ņ{ŋŋĶG·(áĀÝÍŽcFwŨåŠ#Þí:—"ęqĒÓüŅ.ÖČÁũ#fđ’î˜arĘäžŅZÐ4#w•ēƒ0Se!2Ž3EîĐĻ.Ī­hĻĖ‚™•Ĩ•q)Éï/É}ÚÔÛ8 ã>zĪŦBĶ4(tF­:âÜŪĪsīGf…p3ˆî]TšFËV’ï_æ"̟ÔåFō RIEīcfÖÍffÉÂfN%;Û0Ó&ĪĪT„ý<õûĖãiĖqUŅTŠML7J4§ČĒåHp›­zeV”RT^k—}č–ÏUer#3Ģ4QÉċg–‹’ˉe‡Ė|žŧĄ ûûfÆCĨiØ"7‘Ųō–#ÁíāhÏ5­ŠdĨœ g"qė‡VčgĒ7ÂĀ vĄĖüSŦˆ^ë9ž`ëŽ1õVc‘âjjŧuƒÖ\TœŲzyÐõYũ/ÔöaQĮcV)ęðSŅ傿ō˜åÔŌCĩPÂõÞĐû6D Æ\TN/ö –%/Ą ~Œk$•[ý*;?Ãų'‰Ä.žLéâĪĨĐ2•|+ŊũW‹e§ų{Ÿågđô‚˜‘R^ÐØÓ@ĩ#Ļû­8c™‹™éf €Ĩ V+Ō…`ÃĐüŠJ'‹›õÎæ‚qmdJ2~J‰™―QeĨãÅ2ƒÓüƒÎOŽ’˜sČúĮIæFådē *u•Yę5‘°Pų­*m ĢĩN›UáÖŲČĪĂžáRGRŋ—e‚ætfv˜þxrĖJà ŦNđōę}PũÛĖ*gž0ÚŽxf­ˆÚÆĸÖÍLˆģÖyqš˜y§Ø Ú$ëĨæï™•>s^ ģJFĶ”+qŊũ <Û8skkœU"éœéޕŦjí8SŊƙŨü—ĖÜėÅ0+)Ûg­zÆëÔqŦoLßŊp1KĪ[ĪX,@p›p@†ō}cû‚ 3ŧĻgŅb™Áiþ 3*sj2ŧœÜHĐ0Šb7ęA―ũę~úFķdą(ëŨļoĪC’eßČĖlũÔHŽüóŲō‚õzŲ7ÚzĐųf™ïčøO\9D―Ē>žüUĸú„™Ķޗü(0ƒAo„˜ÁĀ f`3˜ Ė``f00ƒ ĖĀ f003˜ÁĀ Ė``30ƒ Ė``f00ƒ˜ÁĀ f`3ØQ™Ízķģđņj“Yql›_ß-™Þ―æPŅŦËŽ(ŪŠ"‹gw‡0mˆ†s(‰“Đ0›ŧ8›ßÞ>NŠYrXüũ1‰ēkö+)nįc3‹?óëÃuRL+Î9þÓŪņß3;įWs;Û?ÎĖÛė­žÜåÎËCt3ģŊí·.Îf·Ķkœs\‡ŠkOîúóčđŅ|vБĶgŨ>Í&“]9{ˆmü8zrP­ïÍŊ܅Ųãíž[üũ0PŸc~―ĩ…™Ųör‰jf {;•8›PŊ?MfÓëõ;3ëY=8fĢ Ôé0›š_`f`f`fO4ØŲ3;ö˜ ΐÁ ĖĀl’õlgRïÆėw>f=ļdg`6ģūūfˆģq™Ąž^réqöņææËԆh>Ÿŋ€Ųë—ywuõebqöåęęÝ īŦ­[ЄžžÚmðzöã‰ėýëÐ.=ΞŪ{š ģyãŌ+Ð.Ųũ6Ÿũ5˜Rßø~ē‘zý/ȍŧ.ŋY›Ų‘‰ÎĶÁ3õéõú]ó„v…8쁘 WÏĀ qf`†qv Ė~}ZYõýô Ė&߃ŽAúõ Ė&gģþĖzb†8C=;”ŲË_æÃŋüæßæoÔģ“čŋš‡ŧ?ų͇?ŋšŊˆģS`öðWýpį>ÓŨ—`v Ėþgþ2ŋÉĖó˜Ä3õ?áË_þĐÁ :HWfúNęÏ^m/fĢđ2Õi f`f`6afSó Ė.‰ŲóšâõíįÏok›ždÖū7ÝxÕ?vn fßîÛãqĸmsðĖ֕åûŸ?ïŨÅæ™ĩïM7^õƒŲę=ßĸž^ a™Í6Ŋīđi@fÏ;˜=O‚͜ÕY=8ģĩ8ãaYEÃÆY;ëļœģūa fŦõƒ2ôjõp9|HfŦĐŲ Ëæ&ô gÞ7NôïÅLŲtþ^ĖT {čô˜ÁĀ Ė``30ƒ ĖĀ fgkvTfZïvÎÔ&~HĪņâ7ĩ:B•*K‘ŊŸ’ņįÐĒŽë$IEkĮ–cũģRlē­Ð^ú‰Ēá˜JŧN2f„YœÓ0—ʞŽd0V‰ŠþI:Tgk‡ÁlČ8K’ˆĮĶÐBá5WBæĩŅRčĘ QœĐH šHđŅĄ#ðĶ0Ó.Öę:|[bæ}ŠSöI‘Š<•ī“Ð’Ëž)ĄĘd3<Šģā1Ÿ@GŅĮÐ]ĩĒč-DEgęj/fV°+UkúO™’ yŅk\-ã,Rī3ĐŲĨĢ ÓVfēH%đéÅO%MŠŌˆīŌ†ãŒ™ĐēYEģØ ÁŽQâSdÁ>(|ŠdB?g;) TŽyŽR?͓ĪNâLr’dfÞcá<&ÄĩQ+Š&DFWRɞĖ"ŠþĪVq]’/g‘ŠčŋķÅĖ—QĩĐ({õĮ,ãđ—šuxÍ(ÉÐ0ÍģīafyýJĮ ĀŽ.Œ*Ŋuâ|P6ø”đŽØ0Ŧ#gv혚ÞT‚þN·cķðļyģã™ĖŽĶ Ģ˘bÏÜhų>,TŲ&7–+ĖĪÛ@S…čE<§Ÿóý+ū– Y.V˜YÅé;ĶĶU‘Ž”s…ĮÞûä{‹6ģœ)FūœHĻ)Œ–Ė‚Į.ý‹4NâDĶtĨL›îɌëjÄI6ķYjhfĩ™EîØ”]ĘûcVņõ9UīãLúæcÄ8s™‘Ðøâó>íŒģ:扞hJõ f™›úMœeZfą’aFtbVWF í~…1ŲĖŽ }UēDúWŪđČĻ ļz/™ VÏ\…ŠĻôPGD>ųz–sAMj§ģV=ã>ąÆõ’YðØÕ3YQũBMUFYÛnĖÜ}Jú•K%ųīÉŽïÜĻܕ)ƒPĮH}™ĨK7õÔ(eūoīū{ã.Ž 1ōó™.\ęÖečyŒļ ,é),]0Ģ&MKŧėÉÝP.˜yCßH)™žŧŽ*š0Ŧˆļ›LT_eĖãĩɌ{ēÏdï3+ŦzbVôúí8ãđCôK)2Ūą–Ām0ë―Ũ߇;Ģōiã‡$[OÎŌ­ÏýÐ'j=ÆUZŨ`vJúąd­Ė.Õ~Û&ÆšųðVå>ŧŋĘĄũ’•ĐÖJ{AĖÞjRu•+ĐÚ·ŒgÂÉ\öĒâŽĒ,u!5Ŧ‰2ÜŨĶķîÅI§yuߐþö5gŅ%r#TđX Í―ä•pĨý˜Õ­{TAŋ/…–ë?ó"„ūi71RKÚ°ˆK§ŊģĮÏÞîļģdf%nEŠ~!S}~jÔŽ_WA[wâåqڂ‘eĢŧ7g‘d"SRĖ+9ËįgþJ{2#đïaTYé8čĨc‘ądËę‡R…SčIšĄĒī{Ž*Īm˜_ĢΒ™ÃRņ˜8|Zítž ­Ũ~UQ›:ĻŽ\ýūÖYž/2ÍĘ@äŪĖĖô~IËÕ3Rqų œï2Qx]ąYŋ Ú kĩ `· JÁŽXûpĮ&zÁŒ‚TįČĖUŠŌÕþ(|ÚŌeĨ ­ŧ‰Ï#Y­œĮÓïkÅ™fe`ÁĖ_ißÜč{#f’‹ÔëũŽYnxĩÓ13YˆģÔ1sĘŠ†Ų‹ĢÄYfqģ.#í2DtęĪĸvœŲzõ,ÏŽYX0ŦũėÚĖ6â,&)֘đˆo˜ĩâŽ8ë8ĢzF#ąž™fô…Œ’– ―ķNĮ*hSÏĒšŅݗgyfÍĘ@`ŨþJݘđz-ęį_Ú°Î,gņ6UAÍvõŽĒÚgüzö™Õ3ķ4ôAÞlâŒŧ=Óhë4@6Pöęū{Ķóû–gyfÍʀg–ųūqŸŽŋÍlŲ7jßWTÜJŧĘŽÎ#ĸ|ÆĖ|ßČUŅøūQŸSߨ]žAÝïĶß§'cGd6ŽšßYŋ3˜ÁĀ Ė``30ƒ ĖĀ f00ƒ˜ÁĀ ķÝþƜïī9nÍIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-user-flow-removing.png0100777000000000000000000000676613761647206022171 0ustar00‰PNG  IHDRÕäų6NyPLTE"!!%#$/..333777BBBEEELKLVVVZZZccceeeffffffgggooovvvyxx}}}€€€€€€‚‚‚†††‡‡‡ˆˆˆŠŠŠ———šššœœœĶĶĶŦŦŦ°°°ļļļšššžžžÂÂÂËĘĘËËËĖĖĖĖĖĖĖĖĖĖĖĖÍÍÍÐÐÐŌŌŌŌŌŌÔÔÔÕÕÕŨŨŨŲŲŲÚÚÚÜÜÜÝÝÝÝÝÝÞÞÞßßßáááãããåååææææææææææææįįįįįįįįįįįįįįįéééėėėíííîîîïïïïïïðððņņðņņïðņãîðūėï•ęî„ęîƒęîƒęîƒęîƒęîƒęîƒęîƒęîƒęîƒęîƒęî„ïōŸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ=HÓ pHYs  šœ œIDATxÚí]oĢš†-YÖX"䌮A:ĘVę]ą›j˜đāŠÕ\ eWęEŊļ˜ëó'ý ÏZ†ī…tŌ|ðaČûŠĪ jxXë]ķĢD8h~ļ  *ŠĻB  ŠĻB  *ŠÐŸĻŪzVŸ§2åķũL5ïUýR šíƒÞs :Õ![ŠR簁SMâdŠ·‹˜ŪÍ&ū·ß&ŦwËw-2V7 f›äËÛcϚÓtð?Û%Ã]Æ?†ĒÚUÓÄũïZ$U{ëOxđ:ûÆŨæ~‘L.ĸðMÞĩž ŠætnâĒbŧļšę*ãLąž_%SĢzgÞ·<ČX­îŧØR:–ŠđC ÜWëîb~\ÚÜŽP_aÏĶß1Õd~ņáAu–T‡lĻ‚*Ļ‚ę(TÍYUÄ*Ļ‚*Ļ"_ÕMĸõ)Õs|1Õï[ÕĸŦþoØDĐ$HЇ[6}ŠOiÚÅĐ=ĨũÍĸÞēūļxĢQýīeŧÝͅjŪĩsLöĢe™þy[sÉõŨfË~Šþų”ęÉïŧŒękËþ :VÏļzÕĮ˜Eąøý9ÕS/âeTw-ûō_=Ŧ\:uę oÎŧÜW7Ÿ@Õ󠎗đþ ęÄ}uôþę850úŦ  Š ÚÕ~†Ü†Ģ:žŊ"V :lÏTĪ:hÏT‘Ņ_EĩŠ :[ŠČĀQ―dtĸwžŸqjŋĄ9VýLÜ߉gŌhųõwĩÜÓĖýęMž^ÅKN/IŋúW œę/ƒįÍŦ(äå鉖Īڄ _Eĩ4Õþj·ū ŠaPíÖWCĨúrÓpô›Œ-K5āũ·0ū܀jX9îŽÝWýĩxæū2Õk‹Õî|5dŠðÕsÞļrtÝÚÏĮĪzm5pwo€ĢŨ~ŠSôUPĢŊ"ĢgŠ zŅîÏ―ę0Õ!ĸwŨū:RÛAĩW_ÕĀĻv’"AõÕmcäæáĻÃ>4wÚîŊ—jã„ų|ũVĖ€jģþYuØus§›ýáújģOŧþ`ŘT·­qƇvqȜJu{$Õm›ęöŠãújㄷëVŒIĩ='°n‡_ÜÏĐ>Žßßë#3p{§Žhn4•[š·bLŠŦý#íŊBĩ4ąjĐŦœ:šyðļXE5(ŠÍĪ·ŸKüŠÃTGúŪĩN|5čï‰ģ†zó‡ŋ'š…ĄÚ…ŊBÁQý óĢ *4Š9Pː*|UP…Ŋ‚*|T!P…āŦÐgT‹H•Ņw?4ū킞) _,Õ(rΊÂĐU•âjM™ŠØÐƒīą6ÓBčēJŽē…0ô›Ą‹(LKķRˆøíVlf—\đBdc6/â )úސÐÄŌdutŌ·då‚X&Õ3ú+"Ēe&ēRwJĩ+_Ĩ–đB™?PMÕØ7įAf[ _-YíïũúŽb–Ų+ՌïvC[7RíĘW­öņJ·&eO5SBRó!LFa­ŨZĻÂôØcĨpˆjAųŪĪęœnCþ―QBåUĒIčĘR{sʘ”eÚUūŦĨeŽ…áŒŧG52!&ā\DI•ˆóRjq)KE‘‰ ýĪ>Ę4”„č§bŠ”ĸ\Ž IJ{šnQD8-5)q’N!‘tÍšĄš‰Ōņ§QĮRF͐CÄjwX/āuÂw&ĩxÃgĢlĒę Ė­§+kĒBð'ŸŽBĩÔēāXt%U.|cIšžFhūð’đÃu:î(VÝE™Ž nœŲÅŠ}ĢŪŊēJ _Þ jqęĸ°&jSÍØÛĒÁĐúæčĖUíbŠ™GČT}=@‰…R0A/ŠWDöWųJčbÐQĢØSMŠØSåŒŊeˆūęóo!Š:)VŦf†ŦV†—ŋ–wmŠĨ”€‹óíáü€‹# žSFĘY*>"]ûjeŠd%Đ|Ģ:ĒŊZáŧ{TwØÅJÅU^’jFĩš.BĪęËH*-đĶV5p•x(—RžQĨXËqŠĨ˜5’9ŨBïĐrĩ”q/r#Øu­HéJÛAcĩã"gΊ9…j)UQ’ÏIۈUKZŋ]rÅJwĒ0nÂTGŪŦ‡k1„@Õ°|T§áŦõ CkXå}Z?œ ŠÁĘÏĘĪ­)‘OĻō˜ĒÕÐĐ:‘ųũsäŽŧþ=Ô?­æŠđŊQo"ލÅY%ĐoHÓ8ŪÞGEŠ7q/ÃøJ9ō}[J<ÏlAux_õTéFŧ’ÆgŽ,h:XYK8Ŧđâ’úˆ4iSÏéxŠIĖĢsÂÕû(UøQXž Ë-=‘4ĨË\Ķ~žTGōÕzR’âģ§ônīAņ !M•dõœŽ§JCÅV§b·įë*gÓ8ĸ‘D%õ˜xäũQ\{&%†óhEGIžۿЭōšžÓņTÜhËTßöá‘FCI:ĢüílTMŸD :2ÕH›,~Ušï*ęđâ]Žūú#Qi\–ĻÖûTT3a’ü-Vó:vAu4_e %ãˆ}u#rBCDŦđâŊVs:ՍÐôęÝ>ÕT4…œ―ųjĄPËWÕŦŋjšÓâ˜gûÝF–Õ\1ŨšB/ÞÍ:U&MTë}*Š„T$ī>’ÞŽĀ5p„X ZÖψŦRMnāęĻrÔĐãCŽF'Dė@u\_…æčŦÐÕú*ĻB  _Uø*20Š  _Uø*ĻB  ÁW!ø*ĻB  *|ūzŠÂþĶ8dā3Đæ― TįB5‰PŨWûˆÕ͂Ų&ųōTGōÕĻÚ[~4Ëbuž lNŨaŠ‹ŠíâTgT-y[―müTgãŦw1?.mnV :_EÏýUPíęĪ_Õ+ōUPEUPUø*ĻÂW‘ATAuūj.ĻÂWATAū _…Ŋ"VCŌæööTįFõņ‹úōŠÓõÕ§ôþtŽ Õ}zúnųŊn9íOUëVP <ïÅę+UõTgãŦŋ’þ!ĻdāŲUK‡ ‚ęT{6ßŅģ™UŒB€*Ļ‚*Ļ‚*Ļ‚*Ļ‚*Ļî_ö—›Æ‡éÜž€ę Ļķ0ū܀ę ĻŪúCЈUP…Ŋ‚*j`PUPUPUPÕó.ûsŊUPUPUPUP―ZŠÛÖ8ãÃóóCkÕT§Fĩ='°~~^·§ @ujTWûGÚ_ŠÓŽÕ-Įęą:qŠ놉Ū>ZŠĻAĩ+ŠøžļR…@T!P…@UTAUT!P―@™ðŠKPՌĨÕŲQuFŌĮ˜j!ĒŌY aŽšâŨ!S—HúӊēĪ-:ÕĐPĨ+Uä =C‹*ra]B[Øä‚>7OĮ.օ‹d ŠÓ šŠ„c‘>#OäV䎉:eœLh̊ų§Ї[ō&PDĩd|ēee–N‘2UĸËÅ)˜ §Õ+@uąZh•WÖĘúˆ*E)%āTĖŅSg›K% gkfïĻūf`'# Ņ|Ža:c_ÍEėJIEoÄĐö*WK–Ý4ėš‘ĖéiŠЁ-‡"õltֈU6[•ú—EôXFÔŅąˆUT!P…@UP…@UT!P…@T!P…@Uč(ý"1̐’ŒöIENDŪB`‚qt-installer-framework-4.0.1/doc/images/ifw-user-flow-updating.png0100777000000000000000000000512413761647206022141 0ustar00‰PNG  IHDR­}&ÁĖžPLTE" #""&&&222>>>EEEMLLXXXbbbeeefffggghhhnnnvvvwwwzzz€€€€€‚‚‚‡‡‡ˆˆˆˆˆˆŠŠŠ–––š™™ŠŠŠģģģđđđšššžžžĀĀĀÉČČËĘĘËËËĖĖĖĖĖĖĖĖĖÍÍÍÎÎÎÖÖÖÚÚÚÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßāāāâââäääååååååæææææææææææææææįįįįįįįįįéééėėėėėėíííííėííéėíŅëîŸëî…ęîƒęîƒęîƒęîƒęîƒęîƒęîƒëï‹ėïœïņķóôßöööøøøúúúüüüþþþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸo}Ņ% pHYs  šœúIDATxÚíAoĢ:Į-YĩqdiRīŠÜĨtÅîCĒ―žC/>ūOĘg|36ΐĪ݆&`šĸ(j€€qü›gP*ČrD`@ Z …!-h†ī  ZЂ€h ö67–1=ŒąO‘Њn*ãhEاđ” ī>KkĘîÝ­lec§•élZ?VšÆĶÐÏö[4ķõīîõ(NÛ*VĖ,ŦÖ?>@Ë\&ïÞØŪÚZĸú,­kué—~îõ(NZö‡ĸÆëÍĞðÛ7›įU'üåŧŌõč*īĖåō~WŲęibZ›’ {ýžÉbĄõdú=ŠÓķ‚BiKö?)-ó„˜ðr…Ōüwm+ģĐÁ™þķKņÍdMŨoý&ų™žë.mëQëïŅEð uâqþ‰-‚­3ōį‘äûÃļfŽāĸ6qÝÝzëũA‡ŸeDOk§Yh6_9DðËČeoĀBVũ/īæČęū YÝĨæ ‘Õ]-xÂҚ#Ę-Эi―lSæöåîiÅü<áž—í―ӊŦOGŨonŨeЂmÝ5-Ė[G „†ãxVZˆ .!WsžZ Zð„ˆ2@ ī>rýŋ7•wiMyë‡ī@ ī@ë·Þ –óÛýééiíqãîˁ{Ĩ5 Ē_ķ§ͧuī&;s`VZûĢ|ÕîXįYĮoDkLk­ýöˁYiä‚ÏšÄîNLOk·}Ougũ„›Ó–N!ʈ$Ę82$oüûil ī>éŽÎÎ[ŧũiáĸ˜,(&„Ä­L ĩ$-Ђ€ī@ ZÐ-hA@ ī  Y­2"Đŧ=e:UŨnjŊÓvZu*„ĒŊŊóþQÚSvžïí$Ý8UoЊE=;™üT]ŌôUŲD^· Åũą4j@kļ7­i ú•šJTÔ+61ĒU*!éŧįR$NAƒ•K-h8ęDĻ”ę#īnd[‚3LZē0ë]Ŧ…Ē!VŲZzg˜"Î‡:•˜Úëž1Šh9ih€j'3z‘m‘'ĖĐ[:á1â­9hĨŠ+Ģą‘B˜†ÆIøMŌōWÛ)ĐĐ=kۘĩaÏwB+5ė–͋ے`ę™nÕ§~#2ÛJ=-ēÁū‰w1Īø}Z֟k8bēWĄåįtú5'SSËŲmŦf•Īļ‡į-RË0o•Ē IŦI4:КuÞji5ųíŒw+‘knKŦQw•2Ā)Ȓ[Zö•ÖÔó;ė—)ļ!ĮbBĸÅ%Įˆ‰ -Š 93-žúïfėŌ3īŪé y―ÅÍf‚CĪĐöīēzZ>”–‘.ĨŦ–Ę=ZaÔĘp€jÉ/gįđ‚*4Ŋ})K@ĐeÁICŪBŌVX5'UĢ(Á6m5%TPļVĀ™6š·Ą…>­Ū ZŅ‚?š3-hpgÝB\Q6‡aš12wŠŠ%‰Ģä Ŋ`ŒrJÕ§Ģ|5Ĩ­ “LîĒĩ˜Ð–oĢé™Ptā3ÓÄU2­ËiĐÎÆ(g›%œLÉ å0™‚ēšŌˆN\…y'ڛ<eåüAäŋ_ũâƒüÁųāiÅŧX,>M&“Ųl6ýÕų|–(ŌyZš\.u†Ī~ˆ<ØE•ÉLĒjķļv""ģÕétē­R’æ(~_>ވô?ōĄēΐÎÎĮNZ,}>ęũųÐņę'Īþ|üâjðkŠėðv| ყu>ŸO§ÓŅn·kÛOoŨuˆ†u]·‰dRƒĐÔІīēœ%jÛN V0S)Š&ZŒDŋ‚ķš|ˆ'âCŦ>*nųÐ5éó!3ĩ!†ũį#~Ÿš‡ði\]Ï'm?XĄNh%ūčÚp2ðþzņQ>{z-žį ä#<ģĢBY–ÕKÅũûýfģÉó|―^E„%I`@.1„ķ,Ë·Û­ŽĶŌS°„SóoŲ—§Ï_ģ§ĒøŽ–dQmĪôh™Á‰:š’ŸķXĨį:Ļr%ËGũRŪNjR 6>!ÖP 2Žņ ķMxg>Ą’Vp%#ēëųŲō6>(‰ÛĢåÃNš?ŌLP°ō―U(Ŧ2$ēĸxÂ'ķÝó?zæÄ‡võŧ?äÁP"ņœŊF>NjBŨŌō!€ĸ–â>ˆ=øĀó*ČōQýĶķĘ{ÚĘŪxūS+uĪvReĶ“v ė!dē@˜dŌIfJT–„€A˜d’Įą 6ÆûóÛũũL SUŠ*UšŊÐcßčČõË0iúOįH\Ÿ{îïüîđįsÄĄ\AĀpˆ†ĄđļļxĸþýþþþÁÁA·ÛĮ Ė*ÅāĄĄ!&„č‚ĖéLâëĄîšŪĢĮÏtæō‘ŦßtÃþüÉë=†‹ÝaE#‘b~˜ïøīĢžÓn―”/k~`Ĩ9øč§CA)wrŠŦ5?hÁ-üiðøyÕț_ïilō•[- `ąšX~0įÖüė―Ųóš'§ÖâoöĖÄæfšW.?f~4įwšDXÅ(ū—đԚCá"Û1IËíZōŒ`ĖOū1ōŋ˜4ō–]•ŽŒNQúIÏĖĪÛŧŧŋWRÃ%ĩA K„^šÝ3ó OSŒšG`Ņš—ïž’ïh-Ôß 8ā‹“ÎB‹5?Dð€ü Zû IČÏûũŲþųÁ8ņRT~*? ŋg~ЗÜōų9ĪëšVÃ0ô‚Ð4=111??OQ@a’>{ö fčÎÎ0ŠŠJð Ã āņņņw‚‚~X ݈'cįnÖ·ö—{2đýdˆ[ꚮŪū|Ôŋé5 “ nĩØTDp‹FC"DŽĻ”QuTÐn ‰HI~ŠyŠ™­œÄ‚‚Aâ+ðčāüč†ĐŅ›―Îc]ÃÏĩÝ―ýœøõ%gÓ_C "†ļ™A_TLreQlÄH ˆX‰D@ØČYn/7Þ\eōü}ŸŋfŊ™Ü5ß2cØP‚yK!{ĀąôúÂĐ|žL ·ĩe~-óöœÜRôRŒƒŠÎū\ēĩõz2ZÎĖÛņu˜LŌ!WĨŽge…V}ÞBĒ.ņĒúDU€ßũ8*Ŋßž†l’.R|1,øQt3_}pŠâøđk7œUŋŋ:éßß5ˆaƒ3ĩí_õoƒ–ßcō@žPļģg­â‰_ßZ?%õ†ųąÖa€ÓŸíŊ’ū ūƒĖÖþ"RŌYļĒ‚z1ĸ;û Ų~ĄųË!EQdYV :ŽOŸ>…éIÓ4ÎlI’āĸÖŲŲYAC`DÁ sđž°°077'Š"ŌŪÐĶîžėýÍē|ĸq-û/ũãj`Ė1tĪû^‡ ðCrt,Œ؊íV ? Ē")@Úâ+ĀŽI [$īæ§$%GÖ0ä‚@V0Ų"ÁĎäyÏüėđūO~kðđäúƒōcM!F…Ï.0Đ­Pp3H…* ,•eeð…Dš’UMļ,ÃR‰ČN"B°øv8 %)ÜÍPMgw6C‘XZÖtEéL†fčž%ž–`įô™Ū† ĢSW3‰'Ę*Ā$>Þ ƒÉ, ŽéÄÎÆÆÆv,-Āģļä―K'œo‡Ó°Qé4ËąĶ*Üv8q†—`+ •ÉpLzkk+Eįƒy› ]ÏŽ?ēĩu{Ԛ.óYšå™t8NfĨð :Û nDĒ1QQc‹Õĩ ‹ū8Į <“ o†B[ŠáĢӉ5G­}ƒÛõOvÔwĖŧÐ+J&ķ‚X:IYŠfŲl2Mō’ĖšĐŧ{NWŲîĸðÏė+ä_jĻbh#qAŅ S{tí|yį―pŒežÎÐŽ!‹Îr žĶ–MD·ķķcžųý/ęĮÚ ãéÔ@âĐƒ%ŠėŊbĢĩ†Ņbí/ŦïûôČ/%?0 AˆðCVĒLOOŊŽŽ$“IšĶ9Žc&•JAWŒQ…xĒxuuĩ`Xg2 VY”.Ýģw.•M1]KĘŨÏôūĮęiöú—ÞZŨēT:)‰Č,ž ķ<ÏĢĢĩ"ņĻx /Į0Ž$`'‚˜bŊb—âK‰ĢÂï €BN­lx)Ō"ĀŠŸĸ°Čš)%ū°—wÜčŧÚiŋģč3r9&ęëķŨŲÎÚšš}Kžn„ ĩ9LI&·đ`kŧe•Í'Ã.—―ŪŪŠ·o”ŨMā‚A^knt69k*/œĄeîī8œ.WkuͧŽéwočXėŽ·–Ú·_ÉĐÓ_Ø:G<Ķ–ūÕj_k|ęÁWå§j]ށĨ—T,xûRģĢŅuúäŲ‘Ĩˆ°ģtâðGGþðųđÞ)*æ―ÕÕđø*ĨpņŅî‹uu톆Zį…ū8ŦĪ7žt7V·wīŨT•W;zü1 u\ä:wÓVģO.6;ÚÏĩWŸ)ŊqôlĪD6öŠÅfŊ·ŧ:ŧzĒ3ŅÓōŧÇOÕw}ï<™ļåhlķՔĩÞČĘ:_ĩŸuXÓ7Ųaë˜Ņw•ĀÂĻËvÖŲP}ūũ^RÐËėÍMŽúޑ­ŒĻĀwWõĩá Ÿ~ÞôgSÖ M‘š―ÓfsVWÕß|ð\ĪĢWętļĒýB?ÉÎôīôÎø ][›ļÖØíVMqĶÛYßŌÞÜÔPqôhïÐ')’ĨB°۟’’°*8 ~pĩÖĪĩŠąSÁŠÄ̃ûËšĒ#örþŸääýósˆįy‘,Ër-LÏp8 SķdšdģŲD"ņðáÃx<Hū Äå`€\ˆī,Ã^Ļ―vļ•+OĖ[Ëđoū7oÏŠŨŌmmeŅX„aXŲđ,%§*d% ę%J‰ ‚Kķ ےü”`~ʏŠPAABō@šĶ1HīĀéųa‹…ĄEO<ŋĸņŊUŲüUZÎéRfâv›í‹a1ũ7-ą\Uvzʗ đĸZ­?ÁëŲĀdÝŲî펜,;íZQ018–jŽį*I‹šÁo7ŨU >hršĮY{uhÓŒõņë'*ÛÂ\ķŨYseðąœŽl qĘt—ãâČšŪĪ/ŧę'―‘õ‡w>9ÖėKōĶiBéæ“ĨuþķņHSŨĻĻËc+[ŊiûoĪø‹/Ï9-ĮVĶoVœnÝæĀųŠ­ķgüyĖũļđėčÝYŋ”ņ·œĻ\ôņ‚ÏD)ķ:ßxþÆZBNûŋŦ:vōîœ_ĒüÍ#O7‚ÏÆ>þSëBˆ15•įE*þÂŲÐčctCēTZT͔oĶēķþUJĘF— .Ĩz':s ãi<]Ö=å“/ęϔy3ЕþĘãÃßméPåSųøĖÄ·—Ž}öYSįmo\Lžč?Uvęņ6~ÜwĒÂā”gūäč™T]V…Ņ &ž0Ģ_ ·;ÎÏČš8|ūúĖ•ĄŽĪ'―“åUKÁŽ* @{@ýÕZ?Ī*> ~`%F\‹{ÅÚSĻ#3rZ žā ?Œģ"Ģ*Ąú7­ÖW†Ï9ũ1sįN&“i2i;5Ęū[ éĒ>(Ē‚ŪÄEqQ7RðđĐĻ-š·ĻŠiDŽ RŽļ+]ÔķÖWZ[›:mšIfæÎđįí™9ôgļĄ‚”|‹áÜĸ|ũ;ßýōŸXßd>™…Û]š|cL\‡”ŌþFQ„1. ÅbąT* Äqėûū­#„ī֜sGVJŲ"!$C‚ĀV,SöĀ{ÐÆ Ŧ † ĨŅBĩVŽ-G+…R‡CŅ0!žR]A'kaŲ5ëÁūnŨÎ,°óciöDøĻ;XAW‘Åj@p: ›É§íČÎ3ų8<:qG)ČĮ1°•1ĶnœOŋ%!UÚnƓwÜĩqíúíũ ę$Ĩyn6L+Ú4quhđŨėPĄMÎ#VQkŸx>ጧbxíÔú‘ˆÛ•TĒįŠ~þįCoŋųîÁÃsųXŲļNŽYísķríj/—\Y`ÂÏMŪ[JūbÍ$ ÛWR„‰Ņ]2!)>7ß WmŪFļÝn[‡Éü…/?;ôÆ[œšõB’ ÆQ­SJđT˜xČĻ&eÓãĨĢ(đĩÚam™ŠüōÉ­›'°RaĄëåúũ Ĩ FX+))+ÞķejÃ8â"û’ĶՉ­OÅGÞ}ĸ/ŪķR­ïaÍSÆ:gŽûÎþý;ž@*یueO !͒ ðđãŸŋwð+–CÄy+?šeÛÆ‘4ĄÝČÝEũïxzï‹O†—O~úÉŅsŨ5m~óҁŋ›.UVaÎmj^ˆM9“ĢŪ>1AÖ/"ŅÄÆÛ‰†jy/ŨJ4FĶ ˜é^č­u† n·ŋ\7BóC3ũ 8€LÛCqąøtd~‹ï5Ā’û-ÁA7™Oæ,ļ\K—qÛÆårđÕjåóųB(Ĩv†zžCVũp#ēÁ–Ü–ÅXeŋŠs2WÉ-[U+ųá"*ĪuVXMįĄ!Ü\e Ôݜ‚‘Rý!Z‚KÐÕøn†8ÏäÆā—îu8ôá8XgZ”fu2"ö•ĸ•}Ē Bßó0eLco Îþô{“Éųúųæ5U‰}%K9ë4~ûåtÓBAˆčīÝĄ)ãÚÂ ŽšĮŽ|O7=īû™'ÆĘąVØ& Š_šĄœMŸš‚ĩAlãŦ_šœ0ö§­„+o)e0ÆĶ›+&R“ÁÁ2™=ýëLƒóNcnþˉĢg“øųÝÏnŦUéŽHâ!Ū˜5ïæœŅ…ĻаĸŪ;›tþ™9_ŊÄ+F°ąÃš ŽĩŦ„ö=bũš"Ë$i§B ÔŲ-&ï{ėĐWwïlž>qrú’*ŠqAӇŋ>uįãÏíÚqoLjîōĨ‹õđbmówŅÆÜĘņąĻ\{ðŅ]{ö―ēïå#ĄZŅŦ„wÛDrÍoÖĸøņėE”GÝHtkæBƒēŲ‹áЊ}.ĪîôüB3üGĸ?Ór™þąČÜ#@æļ_ýčŋG!Ļ8~æĶôƒ1dø„ÅWØa™ ‹óqÎo”Ý]š|Āúá_ÆĖĩ7i0ŠãŸN_Lį.lczĨ-ĨēaęC\ܝÅLpld Â`ƒ†K—Ūė…Ņŋ€ Ŋų>Ū͚ūŅįÅÉÉéïüÏÉ?ϛæQUUĮwüøƒĻiZŧÝES$tĸá:̈́ÖWƒĮ5ijŠÏ0ĸ―ë ÞðóuÉēŒlņ5ëFâ$s~eM”Ģtč—‰Æ %ņ,ÎØĘ"TzJïøÛüĻWMF#'å፡ðOw0†ÂÁî] *'1’.ũtSždüūÃģ†fčö-ŸČHĒ24@BEŸđŌ'wLĶÔhUód ģ4‚=iŠ†Ū “ô朝ŨÓQt2ąmls‘;<ítk4F4Õiã‡ģ9óÛ­X-PkK8ESyÚRĨękMũÄ?ũøšKŌ0F° é]…ŠÛ[óóņÞÚĘĶ ‚ŧ5đ‘ÝZ^ĶļT[6/øÄ#ÏLąĄ įōËČÅý ká0y—~2k5=vApĸi.œ8åF8☠B…pĄ%Há€ßģÏãųðĮØŊļ!~eŨŠôbŊũC\ԊFíîęęvđ'+%ûözšífîí폖 ö?ũAaVũK ۖlïËę~‰DÃ(Ļsį~­øxôÁđ§1WnąŠŠ€†cŒÁ9 ÎĒ(ē,;"‚ĀŽĩDĘïûyž ŒĀv1ÂäÄūýĢøųÍoß|ûˋŪŋ|—ýZŨÔ ĮX•Ðį#ģðyr:"ĻÁč#ļÂSk˜"—x Āļ:nõYÍ#rÆWúЈÜŦ·[érԊ_ïĢÎ}} ūcßīõÂãę6ÞĪޔĨõÍt“ĀŽHŨ†ŌÚ!M) ÁųĶíÆÔģ_Ä:?ŒH™* <cųü“gŊý3XšaJ}[ĸ5GŪĩ5ŪéÓÐÚĘõģ5eåcŨ]ðu‹&Ŋ0hŨ#–bë sÐAmŨöãÐSBýSŠąŧu{ƒ9Ŧ$ãtÓ‡‰ŌÔ/Cų>MŨĮƒķMJHÍeãąü3fLĀ ÕĖbVqŧy‚†ˆDށ/)ŠÐÄÔG4jâÐu­l;ĪąoËóyžĶöMŒý8zĘC}Ž‹]cÍ9ÏOaFGψEĢóđŽëķqķéĮ1}|‹{ä+Ũt7O1FëĖëOŸ=ĸî}\UwSýÎþpuũö‡x^Þ{öGK"0ÚmÂT.ž›ūîŨŠ…Xx*’{îWY– jžíýÂųH}hšđ[}hOŌGå||Ī>Wx·3–‚1āÆqÄœá7ÂpNÓ4ģøe8 tÃ0Œßl ˜$HÁQÕétB*Ĩ4ƒĸøøÔ—Y牖hšC> ķP;f5§850dX'M +}tМ‘=}`nI4†ŠpŪ8™ÝęĢwę#ŲŅĄĪ‘žâŪ KZÃ#ÁRhYþĄ>gþð*ÍēRĶøęՋ7ï2\+p•ˆšâëÏ_ýøûÁ;\ģÛI0|ØÜĘnbø3WĄāôŽƒ/ÃÜ —(ô䜄#á”n°óm ū*Cŧýąę8RÖyîó’By0vžQ4`RdĪŋņĀ‚>og ?0ü돰Ė}Ėė– ģ CĩHðýËÏūxûū†v€ÝýY-ö‡Đ{öGUĖ>iÔNäŦûE’釅Ûŧ°âWVÎę~)ŦĮD1<ĻÏ.pžįČá<8Į#‚EQ°€>R8éËXūĀpp*΃ėƒÃöčEķŒ…œ‡ĩâQ9ÉséÐP Ïž ėnSG$öôá L’=}á—PųJU1NÚ=}Īvqú@Ÿ;ÛӇŊÃāƒú }Ė‹š`ÏŌᘟššõæ”eķ{Ī>dXéÃ7š_‰YĪø –>Û|ë}ֆūMBÉQGN".?%S—ûƒŒŊ}p†Đ§ę#rÂŲę“e‘L=ĻÎõ~ŦRŨįðŧæēâF DŅNþðOļߓU~ËŊ'‡>pR$†d Ī,ŠRõU=ŪÕÚīųų9|ŋôwøAÆüĪN§Ÿį‡ÆüpÕīïûē,ëē:˜ĒįĮž^ēņ[VôãņXæeÛķ}ÛÁĢÅã9öƒGx€aļ$Oņ C§ ÍGD`˜…2æyÆFˆé’DÆ) )ØéyœÖcĐØNĩā*ę7;ŅĮqĀ/qĄ`I䰉Ä!gKĖZ+ėĢšJEy’Č]Ō$’þüëaķ·ÍYĘu„ĀKģ‰-c ZjĐĩģˆŠbAUû,3%ŽMĶČDÔjQ3-óc>äôOÖE–â zČÖ]•ž3ÛgíÐ7„ŋŲû 8)ŽėĸŪj[wÃa'ļŧ;Áu‘`!@‚!ļkîūļÜ—eYw›鞖Šũ,!đËï.C’ŧOþÜūĖ3ÕOkvū]ýŠę•ŠÅŲøŋ3“EBˆ‘Ó\%ÞĢd‚ÃfģZī'wQtðļfÉá+OŽĒ()ˆĀHršaĩņŦüPHR4Į2āßb –mĮ\ļãĖmSü+&éÎąõŦ^*üCĢfŠĄãoŸZķp҃ ž„āÃ,väÝŋqîÖëL€ß^e9Ž&á_$m}}gåōÅįŸeijĸãTĩEÄē„^Oču.ūMŋ;ĖūM—$Åęõ:‚dįņ“  ™˜kW'ųųĪņýŧ·mÛđÏØOĮš07úŅÓõNž{^āåëãïëk2X†Â ")Æ`4ęXæŨ°@Ódâ―cŸ~ģŅŊJM?―‰ÕLnĢNĮąIQŠE>%:jŨ);ÁŌ,g4đÓbvÔîM§§ Fw?/w‰4& dY–Ēh“›ŧ‡›Āy8#`9ÃPZûaĸ)›`į  hƑŧqîWCĮMšņ @ZĖIØąiÓÅë—\žōâãŠŌFÖĪŦ8þÓDs@Č=đgĮíWfɒžÅũąîĀŲ,‹BaåŅŲ;ĒŪH$“sqÚíIYÖÂŪæ%‰s^Þ_4á“!CFo:z_at,‰nÚ4f䈉KweZdŠDŠ6æF’ēs`þŽQƒ‡l<|ģz;sÂÎU_ŽųÅũ{Óâï3eLŋaÃĶŊ;˜nUŲ1sgLŒ6ýäíŨ€‚Šŧ/ŊŸøņ˜ĨĪĨqŋþš râï.›:yäÐa‹wžĖą#B°,ŠČxrqÃæĻKį5gQ&“ïžýfØāĐģW>M·Ó4LxteųwĢ#G~žpŨ™lŧBRī#ûåօߏŸ2íZtÆ:āȉڷa}Ô†%Þ:ąõĀåင •‘õúņMC˜ŧöDRy“ķ­_ūíôcЁOÎíß°į'‘*VūzïČōþIšSŸnY=gð  휰KøzÔę~ý63ęÚKšïŸ>0møÐČ!_žyĻÝ)ßüDÂÃKKŋ9zĖâ=gsÄBĮCÛ·žtóØķqŸ}ķįĘ3)(åœÜēbÔØĐ{Ï^Q™S―+Ēĸ`Ūķˆ ”1–Ēŧ/[HÛ,B—°!pĖ?oÜDÏvm,ŧš(īpœéQ eߎGĩ· Įyûúzx!%‘:S á°eÛi―#ûƆïøbôņŸž™-^ËfuÝ?­įÆĮ%ũŠŋũëYũ:Oœ;ĢÐ\ĀHUåfðĒ$B†’=cÏëįl~Ö―o›ĖGûûöŠŲļw6Й,‹ïDmž4}QÉöý3Râē•ę +e>þtōô Ŋ†mÃėËĶôũÜuĢ9•ļýĮđɂXP­É-æ.ÏOÍ=yĶSŚ5āÃSóVþ•ĸŽOĶ<ũčÝĒꉅSŊEũø~ōϘŦÛvgWíŅŦuâóKß,ŧÚ CÅâ@t>ąŠ™Ņkŋî·/§õĻ.UŒŽ$Ëâĩߍ[7`HÛW'Ķ-.(˜ōQ{–…HËēŽí_uޛT§UÕ;ĶÏĪtÅFķ%ŋî3ė„ĐTįÕM Āâ@DVķž&HD9ŌL9ū FËjū™3gÎЭ\[Á|dИEaĩÚ[îßČBĩĀŊĮ&rŌë8ŦGDƒÐÔ_ÏTũøūÕ Ŋ“Į>ūęTÖþScÎ>"舯•37.U@íœÞ.láũSwœã#G4‰ūų"GVĮÜėóK‡ŨžßQ7КõęÜ%:MĸQKŸĨĨßÏZtėvįA}nėýX€†ŨzrũōÞŧ$ˈ —TūšC–3‡Ö›ë…vĐëŧlŅ7;NáĐ_v"iJedĩą’™aŒņfL™Ðt|Ëâ$ÆâÛēī-=9ýˆÔUlT!eã‚QVvïôķ!ûíÜûSb―ZÅēŌ’Î]ËĐyzųý…ßŧįbƒ>‘ũŸĶdä+ hīö…ÚĒ- BŌÞýîŦ—ÓžQĪ‹Ëž0Išg̓ÅóōtœGÓĶP’\@Yðϟ~mKuCF…’ĒhkceīĸÅ|;lØá“Å“ëwŊv3õaFRđûSQųJFw'<đũč@ŽĢK('Ęëý"Úķ­}:ëUũÃÍWwEíĐ5`ŲĪÏz%fFN^p"úãv* óÓoÝ9ĸÂĢÃÆĐ“ýsnÆ<ļ )2ųÉÅGwï„ũjKTFjúđI­kŅ“5úLųajW­VbJÔŠWŸu#OÞū}7įp”Oý&e-wĮĪãac'MRĨÓsÓÁ‘6Šd$h‡ųkĄ”ģDtáŌ@s4f 2’óĪšĩB‚-õâ-„Đ™§š!˜3·ŸGvo œ3LöôgÛöå{6w3zļąÂó[ÏŊ6ôDû2ˆ)_NÝ&Üaw@šlRÏxïŽįþ]ÐåŲG2­=ƒ}ÜAĘÝëŅS…gëlŊq_|ŲÐ?/į§Ý üŌ߀.]ūnfîô\ldÍf‹€~uãC„˜O–^0geĸÆūóG―ĮUïë.ÆŲ3âÖÜIÛ wK&ú~|BĄ_ee&äÜ―tšÞð}S't―mŒąė”ƒôëÔŪŌķKÛũŸœž°―€kŲŪFĻĒ @RrnüĐû7_ŧUðņtįdáÄŪŲÃÛ|ņųøŒĢ'üĒëø9‘íë€Ü'A’Dh  Ŧ%3)GlßĒ”ú°_ą~Rþ|―ö=ÚÔ)΃ȷfĪĪpĩۖõonøH’˜z―[Fß{˜˜ü0. · ąLø7ųvýŌŽÃ&Ū―óâĖãčėā_}1IšnŠ™ī)˜øQQĄ(o #äØīŲsų"š· H:G—ŪūŠvËÉöúnVÞŅcˆ$ŅĄjNûG% ÔTžm€mšˆįy‡ƒ€PĮq”zj3ðKv‚4•,é­Ģh ‚ˆ°*'b”á <û}ŧfÚčÁ:ė@„ÓВŋŠ$MŒÁN°zã\ŌE@$˜c(,Đ iķ[Ėj)\įđÐčL˜ŠĘÍĘcüŦ-XĩqpÃR ÖԁĄ!Fˆ5č#5W1 +ÖėØ―†eþ7ãöD ―#‡ée hšbI@ēFwÂĄÕëiQ”ŽV!7#‡Ðé95jΜwՑßš3īÁõ-ßô2ïnĒÍ 2‚’Âķ6{Ųį‘!n€įeŧÝnģŲ‰' …`Ï[>ēKKÚaVÉĻĸi˜­ŠSdŒpá[mNM!ėv.ĻŌÂģÛWņá‰QÝbiņfųËÍ ,™·Õ{åÞģ„ÁŨÄi9nþã°  Oˆ SĖY‚C o?jÁڍ•uđËŋųxĘú 4gP•såĖ…F=GAÅ&hiEJ5ŌØ/äôâq_îâLėîÀ_­$„Ų&*d§ŅS~øĒŦ`ZgbH!BËëĶTŠÝGMøfãԁ‰—·õéÝįôĢx °ŒĩŦHâÃęMXšr[ŨrŌũ“FFÎ<ÄÞÁ!EX“—ýņīÍWXV=ĪiPxĐdé`7šĪICŲÁ˂–…@āeEŅBøPÔå $„Ä―û=7ü@:xô‡Ÿ’tËÉōZ2?ĸčqDÓÄŋœķ4Ģws32ī†UÚT•ž%kŽôzƒŅ` $m4M―Á`44D’Ē:YÎ`4ęU^IVXŽĢ–垊UÜ3Äj“-ˆóÖC‹ÍBŌ U+ŽŅ͍!ą Ę4ÕĻRŋC›Ëũ8x`ᙯV튗ĶX‚Ē ‡HąŠ5ĐŽ#‹—Ï›·riLŠdéjÍ+T.—ĸō!įW˃ēedŲTŧI2MjļOŠŽõz€‘WņrĩÚķ‰―û˜m1 K9SHM―ø›ûnßģkëŌ“õë•Ŋę­ÎÅ?yžxÞĖ•{.,‹HŌ™ Õŧ{ļÛRãΝŋčũAãF?Čįh ĻŨõ#:įyvÝĮ“ËÏ- HĮĘ Ãú—Ū9Ļ‹GĖŦóv#ģē2―+6ŊËåŊ[9{íÎĻ#GĨÛIwCAęëûNSauûP‰ÉÉÐč øė„Ôž’ÕZō‰/|3sÆĻ/O>ącE~ûlGFękÂÃCGËIˍg2lHÅHQd‰°ð’$KÐŦeóāb~ĘÝØ\ow!+93Ŋ %)3‡2p$ķeŲâÜ5Óa%J–9ētþŒ)_ŽX!ƒŨPqĄ―ú6°Æ? ­[ŋyĩR!§Q…ō jQŲÛ—dÞnLZ +ŸąrÆ7·C:ÍøēįŅՓÖūĶ :ȜzôÔuÅ―Tƒę”L/`šÕq4qõäąkRž]<~3ÝRąNĢÐbÆD›U)ģ;'%“3si =Ëĸð^ēUŅ6‰XĩÕ#HEY›ƒó *Y†đmú·ÓgŪښe+ZéõŸÚĒžĒH;wyŽ^F‰‚6&ýĢ$Sī{n–ŨŌųæ3gEýËA-„E―ÐBmųķļ§69ĶQá–Ąĩqˆ)žFӆՊ“Ð9=íQŽkĮÖ5Ã}ĶË7ęÕŠasĢÎ―ĸ·Į§õo|ïԞ-{Ž$dåęXš!IßЊmšÔ4qtúųÂI]B.‹J"Ë-Ýķčƒ NïÞēm 7ƒwįž#Įöi‘›œëW§_dĸÃ9&čƒK—uũ;spûþ“ŨdĪPFß&-ÚV)åõ& ’Ō<'0ÖđGø…û•Û·%ĨHưÚ+ķ.nZ\Ø―ûļĐÍĮ‹fN u§Š·ŠZŊdAAÐØąúwĻčÁ`‚p:H܌Ž‚W[ÖþðØītöĮuJų50}ҘÞYũ/ŪßžëUZ.ŦwŦÚļKÕrÁ4į;xöņĄÃnØ―}ĸņ,sūG‰zK6Ío`=―oÏÕû1ˆ€5ŧÎė^ŧĘՓwó™ĘK·/Ŋáe?°eÃū7s-ļBŧOūߍČ}ĨkÚqĖčÎĩ˗f!*Ü%Aē>íĮĖũæÓ/ū"‡§3g&Ĩå„VlОV8KÞĄÛķ­écĒž=ĒãŒyßÏņɰyÓķģ7ï1ūa‘nIĨÜK„‘#†G€WYLąqĶtŪã‘jWš:ļw§æaĀR5?ðō,Ũ―C›ðóz^äđÞSf|ĸyÏĪ['6oßw/Ž7gÄåÁ y“ÆŒ:îÓȎÏž*€šZ [Ö-H’dNęӛ֝›ŋĻeĨ Sp&2bÏ_Ęôöį_9ōÆ―týaJ7#,\—,Ó>ŇtlB$ÜOcôQ8LHķ j5ęØļDēGąšÍZöōũ ?n ķ5RĖĩ; éŨĢCéƒK;ī‹(įýĒėė댌ŒøøøčččëŨŊŦ'9þUšsóō2ģē’įĖĩE”u”-Η+ųį_R™bđ5ŠÅnݖ™——››û§]ĖĩØxŧĩāg‡Í·äeįäZėŧ͒›ĢūÍģjŦs-6Ŋþûk“ųfŦ`·ååjĘģĐ*›ÕjÉÏSŧ5/ß öü\MŊ*Ļ^ģÚŽ{†yR.>OVŦbģ―åF<srÔvėŌz[ĘX_°vMA•*îþïr :$åÜK'ŸŧŪۘ,õŅđ•žŅ™ƒ[œŧïRuĀÐnĨýÝē^=8u3ūJŋKŠAõ ę(Æ]˜8îóXĄō§c{ķkWũÉąMgŊÝĘäJwhÛĐiēīO‡ķuRëųÐYÏĒÝōČļtô1ëßŦsŊJÅÜøœÄC{öĸô ÖXŽÁð{„ęģü ËOGœŋ~'‹+ÛĐ}ĮÆ”Î}|éôýĖōåÎ9l,Y·[į6XCũâzM! J~|ņÔõī ý~ÚXŪØ`h—ޜüâæ™ {Nšló.[W"ŋ1øX2ÕĄĮļņĢÛdÜ?q*ę\2A7ęŌŋuíJ:D(R)·o!ˆ„ûŽŸ:t^ãé: ]툎ŧĮĮŒ›ęŲ|ذČŠ7ŦU[ô‘ !dŸÛĩĸÔĨþ4ėÚĐs)?æÁŲĻÁĢH=|öVÕV:4ŦHýÃĶ(@RĘÅõ>[~wĖĖeƒÛÕäGFJ–ÉÏíŽY’|iÏō 7uÐŽFļŽD/ïž=žóHæÚôˆlTĨMƒÜĪ''lūōJĐÚŽ[ŊV5ÜX*7éņĐS§Ū܎)۠ˀÛxqrÜÍ#ëwQ áîUĘÏĻȊ37Bdžļ·ËÁØKđĶ{ījčĨ#Œß uJJŠŲlņööbYÂŋ-ÔbEAåˇY–ĸ*Ļ-‚Z €]€[ŽØ\ðķÛl8;CčĒ-,ðV‹Åčį ]=€’ĪIëķÏ'-ļö"ĒM‡ŠžČjÎÜ`ÅėÍą―#Û§GïÐįŅ–ĻE\ú͍óŋ!‹Ũ ŌĢݧ+wôDJRžČēXČyp2Đ\ËæÔŲÕófGŧ­Ý’q{óž+újmË(/,™‡õÞ5ÂÝÏ\ya)p_2ŦûąåfĸTjčFL8 Iˆ&”íđNĶ„·jNž^5wö]Ӛm‰W—ĖÝj*Yĩ›þPtķūĖũ}+ðžĪųM Äû‡~ŒökŲĄUVėYßl(^,ČCþiĸÕððjuØØ/ŽrĸðĢúá~H°b…Ëy­čK ķ{ÏR ejUČđųýčĖĶ՝ÂiĻ D‘íwcŌ ek•ÏšĄōč·Ž,Ï[ō3E:ŒÕé)(ælÝ·Wø ĪGŦāĢĮíxnþðÃ6ŪwéĘŌĩ˓nŽųvWbDšōƒ[įŸe”Đēūš?åŅ/UˆŽëg^•.ŨbpÏÖÁīÁ î^~@ēŅŽ.åڑåB†1íîîGDԆŊ|N}2rĶo“nUMųߌčÛmöšŠR_úņ5đjŋF^QóG_}6sÓÄ&Ŧ–ÍÞrLšōEG’fŒŪF7§bŊþdėŅO)Ŧ§32ÂÐ*0Ø<ËŨ NZ5s&VŒęUƒø―XīŪ‚ŽŊŊŊ7Įý}§ÅTĮâãÔepnnÆŋfT[Døn° (;ûčĖͅ\ŨĄ@Ļ E5 tåļ_HąbĘ―ý4™īųŧ~& .ïÚXsÐÖĐSú%§Œžuâî„>zšA“ũ Né9xT\bAéõë–3—lŲ§KBvīÞęÁËDŠņS—ūLĩ‡īčp@ I˜%ŪA› +f4^ØģüՔĐCšKYiY\―n­07ĒpЉs/ÖaxŦ‡ŊiÖ7K­Ē›ZFŅXįÛkÔĖĘĮFt^`퉅xĻyNHēč€P6ƒ€!Ó7ī{1ąwĮG‰)õ*čd ĶĪf0 VŽáéŊoß·æƒÛÞýu pCÍÖyø$&ÅN‘ržUP FÎûyŠ 1^-ÔyøôYŠ†RžŲŽKÕn\ĩNXÆ-ûunBå\ĩŠÐ|ÜíÃÏâ‚Ú}7ųó.ąå冏]|šY‚’<ƒ*}ŧh-qņû‹ŊåŲ$†âýž,@5€Â Žžƒē„ L(ēŽå€‘äQŪųĒ…3ō/Ík3?Į!ŊšïÕøČįSxeūŽ―ĩjĸõZ8uN?øÅČ~Ķä—KķJÝԍž-'-whîĨS.Þ<MkęDåš_=xëõGýK„›ģ"|xåųÖÛéđĪ›ÎbķŠĐõæû‘DÐ;ÉËËëĶ)gBĸ\mā.õ,Pĸƒ JOŅ€ē7ӒAaŨ4hķ°Fš2W#UFVĨhڐ€PœB˜Ð8ķŒRI*ĒRđdI&äÄH!‚­"ĶŲĖ[ÛGM\Pŋo]7=Mp$‰‰·0ƒ›{™&𠠁ĄĄãØý^᧏œØŅ{õöÏæ.›üaYAI§ÝÞ9jԚ }k›ô eŨ‘$Âc0øøc9FõõŸ@o Īxû…„z3ðÍŠLø—ož`ώG­ŅtüxïÜÏ0’TŠb„ĖčoGuģUéßēž;K ­…íėą7Ę!EņéOūÝÍVu`‹pwŽ&XšÄX–‘\ȅ–Õ7Š""‚ )gð d,ó"(OÏŠĄþ†Ũ ĶĪ -ųEo0Ō…uČĄÞßOŽ}}áYfJ^žCŠ:`„Lþþ^]Žâ,pI`EÅŅ@+ŽËčôŠY%aŌĀ@RZ aE ÛˆÏūŽĻyyĸŪm―7ü°xϐ$ Ŧ Ų…Ru:oĻîÃȊö… Gîķi}NÚ*uk_ËČb†"ĩČßŧÃÉ éïé'Bïî[Ôš†}ĀųÂ.%ą’šJh5Đ(c%%ČesïLH‘uĨë/ąåÄܙ%ĩ}pPD•*;Î[đeŧ·ãÅÕs™lģÖՊKą’ ð’„Œīų Ed\Zģýd…*éŊģø`1ÎfMK‹yúžŠÖĢEjL oį^ąsPDËų#‡maU7ŪđýþÅ›ã-xŲēŌ_dōĄ>ŽXŧSOlE#v‚$)@ÁŠĒō]áœÛąģBķÚEPÅUN}qįڕ—55|zlÃKķI/ĸôũwGíPžĖČËRŸ51ČÍēžžxårÛēĩEQ;žÁ™öŅÂmyiyYþūÞdgY^\ļ|ĐCÅFîúSgGÕ k%QPÝKŨĻpęÄĒݕíVn/Q,Ļ^…ĀÄóvžwĄĢš(âėžĄ+ŸŪŲXÆĪH ’ą{ûGo=gʘãtŊ.î}Þ|X„äBAB’ ‡QlDõÖA?ĖÞšĢ\‚1įލĪÞÓëTĐ,Ö/ŋhöš-šôāCũÐí> 3Žūi *ŨļVås—ÎÛeķrĩfeҜŨ™ÖFÕJūzü:― īŸK`ŒeGZĘKX牁ÅɖųÖųĪÎՂ-+ZðŒjÖŨU~Qj–$PĩÉĐ4€ŧ*þGNŲFēLzŸ7/āĮ9į/Mæļ!ÕZülūŒžÞŋSō*>óؚA\zVÉÆ-šx0„žõ›4/fr(úö̆Äü°ûâ… õ†v›Ú*îėÝknmŧ O*9OˆRe[6mæM]@ŧÖMŠ•ņRŠLínČԐ4ȎÚī9æÓqÂė}ĐDÝ?owéîuÏvöO UO‰r-›ZB―(Ú­Xŋ6MJ—vWdüö6^ŧ%ĨŨS„g`D›ķœŊč]ĩq·Ā’Å%-þęÉÓŨICĩČ/Ž 2Q†6ÆŋZōā§CõëLí2lŌé;ũb}[ÖũYėã,G―ęu›å•FYĄZÝvĨËúŊÖičÄsŅwã|ZQybf‚n"{[6ŦhvĶN…5jęP˜°Đ‹þļāāŽÝL`Ãyã?ŪĀØĘ6ĻŊŦ‘ėÞŠ ég€–2Å‘QObŒÞˌ„Öėĩ-xŚ­·Oė@b%°Zį·Ðˆ:MýKē4.ņÁ‡­3L:*ĒYŋeóģķ=ŧËŪïúÅę!=ë›X~įŧßsĄô€Ŧz\čߗ.$^4žÛ)ïäėîZ_Zü-ëĨ ŧâoOEPëBĄˆsN đœ@v씕ÉJđ9ؒ‡).›C ĸĖæ7]ú坋bŋÃæĒž?fä·J] ōwÜþƒÎšÞĮøwÛÔÏïĻü}ÁŲĒ\mÂü)@Āu  Ít'%UŦČIɄ$ w™ėBø“ˆ8Ŧ „ä\…1˜PÛÔÆÂýõjíęõĸŊ<Ą%ĐÝĐĒe;\í-oŪ`üŨԇ@ē‚ĩކ……~Į2ø·%dŠĻĻBáwy―)šŸœ BIM!dz7 *?Qs…Ę~vaÉŠî$ÚÅŽ§WoF'YM‚ė˜óģ'<|ÚÅč;ϊ4xIÔ‚"‰?GĒX–āŸë'0 óŨ4ÃüSų’ŊîžþrôČĄĶ_‹ÍfŌ•į|ą ũöå‹ÉyV@Wp™aYšü?8IšNˆ>ģzåŽT‰ē%FŊ[―âblĸ9ÞÂ―Ë$Ðp֜üāĘ­û9ĒčxŲ"Ļ-Ē9Ė,\„āú‹ĀXJNVeĨ”TėõÞæ]{eckܖ…?ŪŠģĻüĩŸÛũ€Ŋ\ŲïøæoūÞr%,žlAuĢÉôËųþڄMëô BýĻ·ĢãhāžĖpËÐ4Ŧ3 IŲŌŪÞx"QzõÓ[|!”üGÚE“ŠJ§WM˜ :VeÁNĐFFU­ãTšÓ݌Ŧ6rŠN•Ã)bp3Xštã*Į=šŸ#ęXęí^-Ōŋrþįį_â°Ŋ›ĻzÂi"ŠŦopŸbXÍWVoÔą PŠ"Đņ;æÎ}˜œĄÝ!œą0œÞh4ÐtzNĐhrsÓŦJÔā°tïÚÍø‘e(Õ$ŦÓkQhį€HÓyOïÞx0_Ē”œį{wmøéIEQŋæQ]R,™Ũ.ß)@ZŸe=^3gý–;õĪhƒŅĻ2vŧÖąŽ;UčŒîEô?˜@("Ī―0~—ü)F%§i‚ĐéX–1M―ƒŽÓÖĀY ĪïYŋįV:*FÜ! Ėb™ņëŌąarý`ōÂĄ­GŸČA5Ų€€€ī›Éî~!^~Õ#{ŨásâwŪZwό›vКn„”—tęė ï2Å_>MÕ0ŽšņČķÝG.ĮŨlŅĩWį::)ïÜŪSvŸ2yŽp;wЧeíÐûVOž―ÓŦT‹ÉÓGÔ XXū~öāÅĐe[…V*Ó°]풖äįQ^}’W­qó;5ōdГ‹ĮžŲÝ…û§r‚?ëŨÁDbBAīŸ_­î‚―ý1Ÿsôč " ™~ûâS[ĮÞýj• ,H{~ðÔɋ·Ÿ•ĐŨ)ōÃÖÏOý8xÂʀæ>2ĒuYōØÖĻģŅIĄektü°M…â’Á$H-5Ã@HéXڑä`ÔđŧO§í#<åUóŋ\°ýFĢ!̧îëÚįÆ9•ÜH™ÏnlÞ}8ÅllÛĢs‹šåĄ#ĸė҃TņrâÓ+?ÅäuQđĪ!ĸOžC[ĩE[õõNéR%ņuþÕkō‹į$Æï$‹þČ.ČPü†é_ŪļōēEũWŊ%[ī6äLđđaįE]åú%É Dƒ=ËR`“ –„)Bnō­}ģ‡^G]›·Ï9ÚōCCŋäS›>―f-Ģ+^ĶoņīSŨny’ÓūmĢ―+ŋLfVӔÞļuííWBí*þ1Ï_=~AŪ]ÔOIÏäH üžƒ+ĒÍ,I‚"ëi@+‰WŸŲ„āš-6|jgķ~ŨģĘõËGfŽđ\"ĖģjËþŨvŒšķô~ąšÝ=/Ŋ[}&ŦËÄ2Š[§õú:ĪbƒPfÖŽ–ŲsŠÃ"‹Jþer KVÉacl$‡%þúÔÉ_ڃŧ6ÛŧōŦ —†­[ųúĘĘow'z— óŠč‰0r&K)ŲĩyŒhú‡ã؞•į^3+•É|týD’ÛՕ=W/ýnC”mâ”N4„‡,› (!Dˆ@$Ÿ—,põ딏ÚķęĀkáüēā7íĐqÉ]ƒ:ķŊ:˜(Ÿýš―”žÍa+Ā0?þŌšOĘ5nÏ&îëýņēŌuÚDxd|9f\ōW‹‡tðŧūũ‹ýņA˕Nđp&žZsÎ`•pØmēČ4ėŌąöW;a…ž#>î}(į§ļXĸ!Ã{e_Zŧûˆ―úGÞ^ÞČ>}-æq=_ņ|Ëū“gęŒŊôXt/7Ī}p ‘—}dĸýé­jÛeÅ#žûÜÍï|ŨfÎĨ iԗm›ļß>ï1hPß0/YtBĨhÝķÅÖ™múö­āįQÐ΁E+!ņ% uũŸ§HĻ’DHžąÆž­Ëę†ĒŊŧėf―kÍ^8=āåŪeg—"@Ĩ>8w8Õ^đzų‚Ô/Ÿ<—žqTĮ’KNīîÞŠj1ŦģH †Låzu+~_Ąa§~}[Ü_?ėé“}–­úīMh`څŲ7w?MîÞ›_đ•+7Gx3Âļ°cą(ÚŽHÁH–ƒjõÝžĪÏėOĸ˜'€ƒēŒ^€;ķ ww7”Ŋ_ŧt ―Z›žę•Bšę•PR|ē‘YŊģĘĸąaÏ―DÕy Y/Ó%C`ófĄG<ęÕo`ÅbŅ7Ā Čw­°ë=>™úyu·ôÜK―zđcãŪ„ÃRĐųĀĨSûøūßŌĪ ŧA"įô]ýŊäj‹pVAڐM!äę K Ãtëé;k–Ū_Ī cäē8ĀČjÐ4ýNKDŧÕYī…e(čdT˜0&€FŠJYÂHF Ąūœ+ú‘F„]ÍÐŦüØĨŧŨ-O(‚‚ý#ʄs4ÄÎ4Î3ó 9eÆw‘u°Ž`HąeËIŠAT5#cgzöŨĩĖUQ‘Ð|€”˜ĩzōg+ŽKŠc,­ĢīŒ.@/æ­CZWĐǐ!IŧÕTwÂXF8ß žĘÎYüÝGMŠņEiā/6КŽ9‰‘zEoā‚Ņëœ{dUíîQ-ÄßT86t†Ģ’ęgĄ­|BÔPH„Ô&,ÓGãgmZ>(åęķÞ―zŋĸ“„‚ H’zFÚą~^ŸČ•é ëi0čt4 ßšņÃu”ļMåžZãŅ9•`kķ!ųvÓrá"Y…aĩđDƒ;dQQdYņ /UŅˍVų9• Kæ|3/ĘøŊ­F/ėúŋC!ퟟÏĸŋ9'ÃŲRĩïßB/H’yšY=Đ(.Ū P$Ī1Âgöl·†z͜e˜~ðxzūøËO€4ųŽîß›žž”’E™Üõī%ĩ ééÃÄ|Q‘>O;|UD\Åž9Ŋ.Ðĸģ "(%°|ƒúd^f"įĪ#lI) ‚ÂPbę“ŦOßK~›ŠÁZ…r,)LŊŌÖÏ7tËwŦîüqé…lŊĀå‚ ‚`W#)Ü}UČŊݰâāUŋ5ˆtžÕjWÛĩ;Ôk§ÎÝ&ž"šÕŦ*§ÛŽ6…f8–·Îž~;îeR’]ä―°ÍkyôčqĒ gEr„$Qí!áe|"Ŋōx#ŦkyøðQĒÍ`â°`=}čðË+$­ĪšLVhÔےķ~ųæ}{·î|ŌŽZu_ÉÛÕþīŧŒŽj•…ŽĮ·îēáČmĀęĀi‘,+ˆ ÞđÐË_YŠūBB%öáí˜4 âsnßļ—g—Á››D|öۖũ*PD4IÛ·Oāųb;ķčEA‚ŋs: –eähėډÔë1Æ$˘:ķģDíSßý;ķJ1đŋčÞŦtóæ&ƒBāę_0’ŌũóņcåÅĒfķé4Ðëy’'StĐĶë‡zӈ0ÕjŲT*E(J@Ųęõî”,č‚j}ščžpÝÞMk!F]GWd‚ýŠ5lægÄē$Ŋq‹ú­ĸņėŅ·TķWZ_ŧ^#s‰$!ŋr ›ˆū> öí0íÃGËoŸ―_Ŋ۟Ŧ!—‚}#jENxøöë ›wí:üųúCŨžvúhøđˏãsųВ›Öņ$ …Ļ6ãŲ―7œyA6ŽXæBĖQõA5n]úã;vþ°JÁžĩ›ôÅú ØtėæĐŧąĩĘøÓZVŅFïzÍ[ öBĒāVĄíĒųšUË6mÜrÏXŦĸ—c#Ý É·lƒšl+oÆkŠ ˆę|ë6kâÅaŦÔjäę)t― r Ę04ĖH|xųč1’`Fŋ ÝōŒß€~“w^xzðlވAƒlķÝį/Ä4ę6šņęQ|në°Š 𨠄(sūĩë7 hзžeÏų ąŧ Īožūĸ"sxãŅý;‰ĮoÜxXŦiĩâš7"=9\šÅĻußÖï;đ;–é4iîĻÞõH)­X•Æ\ˆ'RpHųš žCš.Wķž‡/”ĸÎĢ›ėp8Ę Ģ%A HįHüūūŲʆDÁYŽ"ĸė`“dđįĮķœĀ5ÖMmŋkÎ4šÛÜ/šæMŸ°í‹5+šTadŠ!ōïL›°{ÚÚå+k-ïO „ĒsBĒ$åäåe8škŧA°Kĸþv*ˊPāÖú2Ĩąsģ€#3+eČ`ðäw –F(ŲË'đï€â͚úü?öÞÜēĢŽó~/UëēOwŸū§“4äΝHŒ$Ÿ ˜@DQBÔ ÃÄĻ#qfÐpPĮa"‚ŒIĮoĖD?ýž ãŒH€ĪӝĪIČĨÓgïuĐŠũývUģsŌݞn“˜îŽß>ÏÞkÕŠzë­Úëüw­wÕZkkUUygfĶĩLZð}Ó^WÁ·­Ģõ UģīŸGŨŨĶï°^Ļ5ô]į­,kÓī Āl ËA„Čhč@YUū›8/ˆ€hŠē@ ŠĖč›&Ý4@bMĶYÝĪ2eebûDōåŊųŅ;Ļ"Ád›šā]ŊČ*>„|5’-wĸųŊžĸwoÜļnaũĸýĸîîßó‘ūâ)š <Đę24ûé 6K œ—Žœ€\FęšÞKēÅÖĀū}KS @T§4õđWˆˆïšFëFĢQéÛÆ( ;í"5Å4ĐĀ0n]lHŽ7ļŪ ē*@Ņ`ŒAĖQõ} [Z˜ÜĸÄã↠āŧ€Ķˆy(ųz/TVVÃŊ`Ŧ’ÛĶY~š(ZŌĶëU@5îflŽ5Æũ­rąnýHšķw!GfĘĶ:wEoJ("A"gČ~ŪDĸs"b.2Ÿ’KønŌŦĐËč-0Sī6k-f#ËåR"„ļP]—| c)g[.‘}KĖD9ŋå„^ŅmŠōĸûýOÞZž|ņEO}ßĨßÃŊzïÛžßžäŋũ“ĸö―ÏĘ:„LvĸÁK~äšw―ĸįŋåÉë―Hūz‰9 ―JðA† sJˆĻ*Ë­›6…—į.‘'|ōã ͒'†ƒ€ÆčÞ;îûýÏ?ü&.Ëāý}ŸýŽĸŌ …1 ÅĮâæ[/đôÔ .ؑũČÞĨnˆBĪāŧvŒD1tKãÎõm߇qÓæ9§Íøū{;@eYĀļkš(+Z”•ĩĶYšŋ4NÁE]bŨĩ„•GBßvũß?ŪŠZÛýãķïÃŌØÖUIâûŪï‚pQU9ÜĮ°ą"šš.5ļhhęĀRįÉZkŽ[ũÄoþæoÐ[öÜyús.ųĄo{ÉģŸīØų0uxiÜ ›ķ+ xYÚ_jŌėSP횉sņŨĒŠ,aD‚·Ýīšūï‹ē. n—îÝŨ{UīÅđ‡ÄOöŧØ!^‰Ā{Ž ›Œũũs:išŠ* dj žj) ĐHÛ4hĒ’ö]'ĀeiÅ·ƒŠïïßwOðMbqíûĶw‘ËšÖ‰ŸV' !h_W\4>WõČö\]œ[SBߌŅT•Õfiė§•đ˜ÅÄPŦxïÅX‹ ­ ÆJöŪęjYė$t]ë| ķUU1oŧTÉ#ÅŲÆ†|·’RÆN%…‚HP 2ž‹;†ŠMs]›œád@ÛŪwTĄŠŒH@a p}ß9€ķĻ ËičŧŧÅūÅ,öÚ· pa™Ķ%Ð4wI4ûŋūg—Yˆ|éqÉUũßĸÛßöéëķ=킟yũÛÏÚą~Ï?þŅ/ūýįĸū)_þÖw_þâģ(8=JcĩEQlÛšeû+_đį’KĮEÍ"‡ļTŒ-íûāŊėšâŠ;>úŅ]?óÓũžį―F―ވ aÏâæ›ŋį’Ó.|áņé øp(hHaØÖ1QÖę8ÚmûüÜÆū‰ Ŧˆ\ÕĩĨŸØ·­KĸoL5%—… ]õ"Ðöu6Nû/0ĨšáÔĒ*ĀõMӇā'“Nļ,,víÄi'c þ‡•PÓļW‘Č 1eeAœÝô”WŋîMo}ÛÛôM—=ûé' Š"cT6kō*paięA2uļXVĨD)Xų—$"DŠÃtCĄïšŪOŌĖ.ßĒ7ŠÓÕÞAzĻ"Ļ ‚ôÍ$ Ņ ïâgQL(’Į‡Þ9BčúvŌõABŸrBRų4F6ūsÎ{7­šƖŌĩˆDÅ jŠ‚Ÿ4=™Â6“ÖÍ2‚ŅoĮž―Ē-S4žiąeYpė_T‚ >ĩDƒũŅ1ÉÜ$[œûŲ%SÔUĨūÏB,ÁũÎS:Bé&m 1Åå”6Ķ(čŅR$ˆwMÓ›ŠŪ ʊqđ2čb…LSL™ęõÞïúIįlY…éšÆyQ;Īē…ŨQTČĻ„ļ{›ÖöAdšSŲÞóÕŋýÓoSƒîåf7ýŲgĸĪý…ũĸâÆ[Ŋyóû~/ī·ü؛Ŋ}ũŋųžW]ýs?wýw3ÓŅŦ@ÄŠ(ŽÛē…_ņĘÝHĮüęõÍÄãA‡˜%öáSŸÜũ_?ÎG@Š)ų@XŅ[ķnĸÚkŋũôóÎßąukY–ˆxD‚hŅØ‘ĩÁ!ĪCn'ŧŪÓDĒ€ŠŌu.zUÁXãZŨŠ”UaŠsÄĢÎfĘ.ûÎl um+EQ!(0qT Zú6Öb‚ė;ČĩUGcWšŊ€DL‰Ų0čļiŧBįļĻóý—ģFĶ)‚@EYWŨƒH4‚—VEEHAAb Ņ.1“!ÂÞ@k #°õہÍō<ŊĀĨ5Æ(ƒ Š:ģÁåĢ)ĢįLģ#^6Üķ>I6•é’W- Ģzd5(vļŨÝ ―v BÖäXGĨ|ï%D=ũ ųÆ·üĀYũĒ,œ\”†ĒKŌtˆŲ&=‚i6y-Ú.ĶÆWîĨŠâ\/ATó`ULY66đ—(ŽSœ"8AļBlpTMÂ)ŠeÝy $]bR$&T‰RŸPĻ2™>Ę/@æ| žKįîE6FÛԋĖĻašāŒ˜p="„°/lþÖũčĮŸĸäõÛßxÁkûŪ[ŋôŨ·ÝtóÞŦ?ðĨší†ðõû&Š›ŽnĐÔķL‘yųËo9þw>ķ~žä™ĶķTLÉ;úAþķÅÍ_{Íe§ūā‚ã6m:b]Ã|ŒFˆ€â&Ÿ‘ˆ˜ĘÂĶ%ŌāÚķ3EÉĻÎĮšØ#âūcĻ…ŠȘ82DDà Š_@ČeUąëŧķCâ’ŧ@ĖĒDi(JĐ.Čb_ó${1;c&“†‰G†qþV‡Ųn‚ō|ĩø–·Ĩ›ė211#ĖÃü‡ŲBJ‰úIŒ˜sDD%z%A(A<3H’{s_Æ œIa‹šã@°36ibšēœ)ĮP˜mQdáGȎįF+"ŲTSÚHęŽ)$"‚Ķā7NÁđ+ c“@rGŜóCZŨķ9íbiïĖTW6KĄčõ<MŠhÚŠ ÁũmŨE) y\ýŅ"‰Đ ĖíÍ _e]‘ČtM+e]§gŽOĻĻģ ŦÐÕkõ4ŋ€Ýŧîčyg―n#Ų/šø^úM§XZ|ÂiÛBĮÂdŊ!’°uóæŊxÅÞŨū~ĐŠMúOÝĄæ`p·mÚšįâKO›Æg7mŠŠęˆu0ū0ļr1Ɇ ‰<Ų6Eé‚Ī‘S eŅAČĮß·§ŋ9ï5ft)&ã !4MÛöņX;* ۂ)x/ @. ĮdŨMģĖäģVâėģ( ϐąLŲlӀ68Ÿ—qÖĀ’ĩ5äĢ`QYÕ đ [ĪaęÛīþh įíHdØÄ`ítKŨĮv•Æ <`P1đ—ĸf "[ƒ‚h Ãķ@ÖhÅcœ ”1–sÏŪÜp sí)ļ!mó!ÉŌ|j&ķ˜ĒŪӗYcHEú˜ä‚ df­^ATó—BPQP˜–‰ßCÛŅōIĘå”všbŠ4|ĮY‹­ĩ–5uR Š$ÍÕ ņ?E™8ÅžŠâōžfAýī@Œ—D‡™ó gNŪ ›‰ 3€ĩlŒa(LôB|›gûÉØ{A…É$øų‘Ũĩ7þÁ/ýōŋųõüŌOþî­―â[N8õŲ―ėī?üÝkþöþþóŸûÃ[Ā>>dWå?ī)äĐį„1eõA0Î3+ŦŦÁtš†‘ņ°žFÄÃi4lÊËkÄU ĸ”{xH·ÖþÅáĄ[uč*TĄ(+Ā äú|Ęj{ˆ­ R)yëēđųï1…mŊCč›I~āMÛ˜GÃ|JF%&W‹ŧsĘrûæÍüŌ—ÞūyóøÖ[aÍðЧžņgOËÎ΃=VP…ųG‚Zw˜sôČÉgĒá‘dS'$eā(‘Úa'.ŠbËĶMö/§ļð=ëëzĄŠ<ža“™SGnayú:B‰øāķb^bFxäĪvĀZŧ‰yãÂÂa…ÕîÁŽŠw]Ðē,™QvķMÕw­ŨĒŪļoZ(둃…Ã]ÓųŅh!ÖöH300HíæCéY’x^žFĐ+Ó0mÂåÕøŪŪk=p]• úāKéU4įEAPQAĀ•™–ģû2jTPó: <>æÕ(,?þ6ô}Û6Mģīī4îû  âûņ8Ūķ^Ō „ŪkÚIӉHÛNöO7Œ'>f<€UŨ·ãýûũO3xɆfēīiŌvNĐ}Ą‚ó!ĐĄïÛϰŒ―syŌŧUUi Ð1›t=0›š*QӕôøÐ­ë›ķįĒ4ÚĶ•nŌxåš,0_:000HíãPoģDrQ–ea -π7FƒkŧNâ3Ōō“DBŨö!IôjåLę‚ô]ëBŠņŠz€Ē°lļĻ ÄTĄF````ÚĮ8æ`SÔuE*MŨ+䍚o ÛõÞXËÄ é•Áü†Ē"=6<Ý&Q“âF$Ė”]dPہAj/āL#Wn‰S‚wÞ+ PJF&Ÿžņ"ųŽMI+Ãüs}ģķĨ!ð>HĖ#€d˜šDÛ;՘+‚› pŒ300Ė@ĀĻ‚ķd Ɵˆy‰‰€ %ĪðŽeD*J Jķϐœ(T ĩDc+$B[–@Sx4BįžæĄ2qUŨÔĮ"u=B6U?}Đ 66ļ’b™í\p‹ŠUaJÉŽ˜mOyĀX €ŲlÉ&'Š"—Cd%Ĩ`Ģ0000HíãŒŊƒ^öp@t!<ŪĪŊJA8†Īv``āąøãĶ pŽ0HíĀĀ€ˆNœ.uę‚ÂcÃļŪđE&„ĢAj‚čūVöÜö.I딌ÛŨņ‰xóˆ #Õ R;00čėÝŲ}Ÿĸōímw6KK^ĸŏÛ1ū-Œė ÛŠþøZĀl=ŠÕvÚq§ŧï:{Įã­G§ï,x$ÂĢæwQļo_ŨŨÆ" 0*ŲlZ;HíĀĀ€ÜÛĘmûÂíwN6/ŽÎ8i‹eeB$ „@ŅmŨÝĖtĮ]ũŨ ÅÖZŽ áčcÚ…ÆéþN–öw'°ĩë] $„5ƒHĆōC}C~ž$HÕüH aíQ‰d\Ѕõuģûžým˜ô*ŠŒ p2HíĀĀ€& A=@@Aa­ qwÏMŨú#_øß76tö‹_wîYg2õ7~ö·î?ņ…į>í “―ý§ô…3ŋýē‹…Y›Ô"ˆ:čEEĢ“G=ƒÔ (Ļ Ú †ĩ뎥ý_ýŸû‘[ý9Ŋđü]ÍõûĖŧ^ũĩ7ĸÎwžčī={Í.óžģO―ýũ?ôæÛ6ŋåđÓņĐsrþ@čÃ1ĪēƒÔ H/Ð H°F ÉWĸęSŧšS/ûП:eۈžôn•ÉuŸųį~ëŋ‡ÚÔUøÜÕ?scýí—}ĸŦÔđðI›ŽĐFĩa&ĩΰ6PĀýŪ―[ÏÅyAŽWOũĩAC?Ųõåé;žÐ~‡Áā!]˜AB€ÖŦĻÎr(ÕĒ;HíĀĀ€h;čU‰ ŨöØ!dF1Ģ/Ý|Į7ėë7•dïŧņ/ö•ĖõÂ]ã…3.ŧjÓ?ūãš|ĸy?ô‘íČl"`NÅ Ŋ*ˆ€ũ 0Ū9ЊˆīÂ#>iLƒÔŪ•ņÞÃąË€*ô.â}Ïā “ËÚO‹=áY/=îú+ŪŋvĮyœïoĸË?žæ:zÎ[OX/{›}ŊūņēŒßĸęÏĸęå]þKÛ­ˆĀ*˜™ˆWR4õ^PBðŅđ!ĄūęEqË-·Ü{ï―›7ož.?\R‹ˆLܰaÉ'žļ}ûöÃPÛAjōpŽ]Đ5$–ęƌjcˆaíbD'Ÿsé[ÞóŲĸúõŋö9}ÖËŪ|öyTäŽ?ãœr{ĩaņ”―åãĸãÃ?{Ũ—ŋxĘóÎĨÐéC~Î)‚+5* ž@-wũY6lM†Ph>å”SžņŒglÝšĩŪkcĖ#7Š !ėÝŧũ+_ų MŦ; ĩĪv€™áØeZbafb\W›õ#2ˈ@k#•õg<ũ ïzžë=‹ žŠųĶKĨó!āqOûŪŦŪUßïæQ!é5ÎĨæt(ЄHgĖyŪŦôôÐÃ3ã•ZcĖI'ä―ßĩkŨqĮwØ…ƒÔ ĒŠ>4ņČĢYŽãÐŲņH žŽf0LEÁ$íĻÚ` ÖNĩE€TĢŅH;wĐí €WĐü”,ĩLąPFœ$€ķíŒ!ÃČŦī_#é0ĄŠŊvĐļéĶ›ϟAj…Ũ'UQ@5ÞFô€ĸ !xQc‚xUk ŠÂƒrjJ@MŽ<6įPh|I3Á%fBĖž?КÃų98öĩy}A›kÚļ8ÚįÛ6U<ÄFĒ#k6î˜:žŨZÐķDœ4Ýýw}mÃĻÜ<2ë+DŋĀĄï:įc RYU†).Ūág7Ķ>’`BDāHĪv@UE\ÓjYZ“Ö•um™fz·Ïës^UQ ÂyÉN›T|ß4ĖӅ^ ӜĒ+hŠP)†Ðw8Öž"ÜsŪXÕÐķ'ˆ"Ģv0đķ \օ™Đ6*čęûžũŲwřóō~uæ+G™8#Ā͚NÞÄaįĶŊÞúõ/þŊŊ"#ŌĢÕÕ ŠÄœQˆ8įˆŽ5'íÜrĘģeÄÚĮŌ΀Ž!Ũķ-ņĻ,óæ;ABPņ!1!xÐ ’UâV/€)9Ēއ#–ÚŽŽė ĩY5ôĒ%‘$ĻŪčĐŠŅl'!"!ApÝÄÁĻ*ōwÁ˜3 ų#’,ų˜!•EõŪïúPÖĩ!$6)Ũfyˆ’ôÍČÅ ī1eaYŏĮMÓðÂBÉķ Θ-ĒNJHđiaæ<œ}"ßt-āĻ\v$ĩ‰p–T‚Æ•d+&äÔĢJm+K',€Z`۞ŧÛqӋÂĢ…†4ŽebĀ™D*õČ4ŠË·T§Wï\äÚ"Ėņ@/[c„9ˆĻøÖuĒUYĒøŪïEÕØrqãÂ'>ø'_øœŨ\īþS?ĸý_9áŧüû^üĨÏ|čs“3/>ŊüÉŦūrGwÖeïzßÎíũíþðûŪú―?ŧáėW^~å~į†#č ":Â!í ĩ ņ^Ų0‚@&*iëUBTuUBðmÓ[”Ĩeį\čĨÕPFĮÄ=ˆ’)Ŧ‘}°mĀ4ŪhÚNTÉuiĒmģ/ŒJ >‘5ÁũMŨƒĒĐFĨAmÛ( âUõČ . 132-Ô2é\žBf^öOŖ5ƒt]DØUU †éFŸ†ŌSũ]pÁCŦRU5ˆoŧ^SÅEQ†\ŨÄõ Ė䁊’Pûķēqô}ô€ë ĸéŋŲĩîūwūã/ŋðå[ïýŧ/v/=É;' óūå…CwĶũ~Ú#xĄ’ų!sØËē°  Âķ2~ŌL&ķŒú‹ų槄y Gĩģ3Įø A &ÝvqŒĐSb‡Nð•PŌ4–ú˜—Đ( e‘,“ŦHK"ˆÉ•@žĩ…eõBÐŪ ĻˆF%ˆē5L˜Û†q%ߐĘ "ŪÓäē5EÁ š"†ÓDT@cãķĢ D°Œ…ÁG=þOКĪ6ƒYj‘UA.lČĶ(lĀĶé{1!  Ō,քР·õÉÏyÂ?öö·õÍoųЎŊūãM?üÞs_þ―§ŸļļųÄïųčŊ>ýÚĸüūwþô;ŸúąũŽЧûÂ7ūęlüŅß~ÜIãûũĮĄ^ĻĨk'hG…ŪÉ tĐGNð˜qÕÉæĪPÓ'UĢuÁuMÛXŧDTÓŲŠÎĩQ?iý|ä [RņÓ2TŒ,úķũ@1‹Ūž 9ŅHPDš?ۖÐy­•Ū됎a ģæoD•ˆ MY—6oé<8 J€Y˜E–]@Ä‰„ļ†Ëþäecl;n<@ĩ°žRĘŅHęģG{VŊh|G…yD“C‡"‡ó{ >YÂv%$cĐoŧŪgRīŽ žxÎÓõŋO{îÓwlyþŨ~á#ß|æ…'Œš?ĸėuĩ hÝķDfįÅoþö·~äšŋų†ã7ëþÝÍÆįîųü·ý§~ášOžxįÞ+/}õöË?ņÎō•—~ũq—ėíÚ8‡™Aj4 ģAJę’D˜Sšœ\Û92– īMÛ6UYë$PïBÁYófēEÄL}ß"Uč}ϘúIӍę2įdcËBúvâT ŠKMō;s( }ŨxOdëēdĪ€ąŽyW‘bdĢíúĶ ˆhŠĒŽ+iÚņxBķĻąÐ·M‡S eQī]ŽXD§QēĐôÆÆXF§Æ23wņÐ[Ų%Q(ƚ!ÔŠdš‚ĻdęšęĀŠŠJË"æž7\uŌwŲgĮĶūä·~ãĖģÎ;Åũ°ļy{ũwĢ‹gĸōUßyœiwžęĘĸđ?þë/ÝNĢ'Yl8þÜ+Š8u=nzņũýÄš36õJia‹=˜‡˜ĪvāÐ)ĀÆ DˆėÂ(ÉŪ-G&ŦœĐF#$S•TcfBDcG Ļ Ä\Õ !DZ–ÖkDāt~ŠËŅû”A HDĢ™ē4€DTT;Rt/J?hYqžŌ`Sž)ÕhAB*ËsČŌÖč1ÎĒž–#f4 oĖ9Z $6‘‘°˜ŪŠÚē"ãĢ3”MÎ fŅڂĄ}t ķ%ÛŊÍ3‰VĎØTlVT[eûĸÏģvlíyó)ŊzíSŧÉĪuúĪg]ðį\ΊÁ5­ |ÖųŊ8įBBD‰?Á'ūæŌģšfÉɆ /đXŧĶõ0[xŒH-Þ}ũÝĮ˜Þ„šĶ™ķŦïû§>õĐ!„Ģô&2ČLkČ1†UÄ9ÏEÉEžkWŒ*CSÖ|š^2áažų3ßpà EQlŲēĨŪkfž—ÂՓÂWæJ ˆh­ÝģgÏôNÏ{Þóœs‡uQïM7}YUŸøÄ}ï†QíãDēE™Ŧ!"Ö)‘!Dp@M#Ē•)Øĸlē”—3ēÔ>rã˜ŧîškũîÝ'Ÿ|ōa ņ€ęš.›Їï!XCX6iÓūįõŸÝ­EQüĸėÝÁnâ0€áÝÆc1DHģÞĸex‘Ū".ČĄ;ĘHĮ]‰neëĸČęĄĒJųc…0ØĻ­išž‡(~Ý’sþĩúۓ.ĐÅöOųĸÔú™þ%ŋĸ|>Û6ót:Đę—îj―ėūwæmą€ïM-˜sô’ƒŠ–RŽĮãóĩÚãÓbðųäG[ÝĪH-€ÔĐR‹oÕČû°B“}úđōï:öu]7Ÿ~ŪķgīÍŋŠÉïĨ%ĩÕØ"{―^/—Ëý~·qĻËēTôąw{þ·Û­ëšÝnį[ Õ—ŠˆÄK)ö ÝïũöR[ĮÁsŠjšĶižg˖ÕķĒ_!„ß1Æa8ĩ:x[Ĩ”Žģöš†AUmáHm|HZßũķķāZgGEĐ‘bŒ2Žïm§ĪVD|ct8lÍŪķĶÎv]BPUëTŒqY>TQj%Ĩ4Ž#ĐEÛ#Bq•s‘VŊ؆†/ųiÓ:kûY VEЍQæų͚l œoÆ[Rë##"öXÓĪ:RŧÕÖ-ēuĨ6ĨXJQM}ߓZ4?ėmeÍõΒÚjøÄb?„[aëJmÎjrÎm§Īv[oļV[“í˜ys+ęŽ Aėoüūā?ėÜ1N1†ŅYm:"R“sPä`9kÄķðR:öPAOdGïÝaūnþ`rX[>X/ÐōËxĖ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@jĪАZĪ@jĪАZĐ@jĪАZĐ@jĪ@jZĐ@jĪ@jZАZĪ@jZАZĪ@j8ÄĻX~0ŌUfæ“Ī–Ė,ĨlÛÖZ1빖ē/ϐZzïįóÛýþđï_1 ĩ~đžũžR;―Zëéôz―~dÆP€e‰ĮĢÕZãOķ€ÔNZĪ@jĪАZÖÛí32sĒĄ€oöî=*ŠëŽø―sg—‡+ÝEX(*Ôw‚Ŋ†Bi4*ĐVc=ÖÄÐĢ5F,TTDÔ(V^‚‚ŠŌ 1ÖĻąõ­­‰īb#Ĩ€…Ļ^ Ž ÂšŊŲyÜ{ŧKþču·œ49G8óųëž3?vįũÏw~įΰó?k\tÔ0 Óßþ1W&“Aív{ssģŅhEņÅ?[//ŊĀĀ@NįXŧŠéîînkk3™LcgYßáááĄÕjCCCBrÔö2!ĪĐĐIĄPÄÄÄøøøžøgk0ęęęX– "„<ũĘŅÐÐééé ú”ŪŪۚš―^ÖûĐ:ũke2Ų ŒįųĘĘĘØØXĮ<úˆÆÆÆúúúĻĻ(I’þûĮąZ[[Ífstt4č›i[^^î8ĸþóÓā2™ ũčMÎÎxŋķĶŠú^CóN$Āj·˜Ÿ>yōĪģ[Ī h]Ųĩ;FÐ;Æbą@]í‡ĻT*Ð ÖnCMuuuÍýöĮFŨ đ‚ÍÝÏėß7ĩZÍqĨTÞ@ÉúÛ‚û›HÂGåđķ\―ĸLëŦ|Ü"ŪÜĸŅŠ™€ŌįWcqö†+ũ:U ‹vȍЉÃĐÜ~>.ÉŲxóCgÂüz1ī‡ûĢî:r†īPvéØÎmûZ€—ŌŽŌfýäƒ=Ü9„3wYEĨÆ_ĨÖ܄ SōÍũĶô‡ŋEŲoĒV&“Į[W Cí-;Ėŧ°āÔĨīájPuëė/aŒ ĪcB„%ŽbĀ s7ï~ĨķyM$Ž_ēæĢ—ĢrM’D)e˜ž?"Ž*‚+Č(’Ũ4”ß~ „ÐMÞBzsņpŅEŽĒĢúrbÜŠąIÅWÓÞFÜĢÞĐ övÁÎoGA0!a –(D Īąų™þą'WÏfˆßÜÄĨ!„1ÐŲ&Îî(%Bį‚Bøí Ä0X’mũôíρÐuƒýð ™LF{H’äâŲ#ķ―æęqƒæČÁ-ĄūLjĢĶÏ%’ˆ)mŽūš7/·Ē…Ũ™ô^úæņÞ˜PĀ–„ذa#Ē'‡ŽÆząÃ7kŨŪŦÓwzúÅgŒ:ÐðāVzrFe—íGĢ&~PČ@BęŠĘÚļkāŽ””9/‹"þÎQëķ#ČB[éį…Wã·o^ĪņƒWčÔ_ %XzxũʞžíUíbHÄÔÍéi‚á‰ßoŦe˜îšÏŪFm)Ø=/ÜT|ųüĨÖ wK6æ§V~öWûðÉĻödÎåöÃą‹%#gŊ,ؒčÓõũũ2˒vŽWņÉOîøŲ֕“ŊŸþ`OÁ™Vĸ°u9ó'c‚Ýž‹Ažjeēþ‰ôpuÐjĩú„‡øˆvNĀĀ)ė ëVma§%.œRīiÉŌu~q0y Kõ€ĄŌã‡~wļŪŲcr֌ŸÆÆeësÃBÉÖ·gūļpĖŌ€ėeKõc>N‰c8›ŠÚ1D7î^‘Wnš}0vŒĀŧÜãíÍÛ·Ū;‚Kf 1~‚ŊäP J %ũpmRšßœÔ3EQë'l8üÕŅxCííĸ’Ōūo͑OŊÍËúõô—†uütfjĘü`oë­ē2íR)ÜÜvöŧ^{7íý=)ÉŦvÜ^īx:cļYQąD"„āæÚŠæ‘ũͧË3NįœúÄïfúŠM{']ØĄE„š}ŪB(G­LÖßĶZAxžÏà ,ðX%Þ΋Œ„Xņãí9xbÜėAõ-6]ö[ŋÔj–/|ãōēēú.[„ÄģD˜økBĒ"Gé/^ųó…ōÔŨƒ.,ŪŽílÓ[§-·jĪė|gīNeԀō™NmŠW…Í9~4IívžļŲ@øÏļęzėå{<ũ8ãhF 6ÎŅē€$SĻðD­Õ·ZÅД7cÕj͊…ģ>Oú[ƒy ãļõY 'ŋRRŠđy+īC―ÕĘ !š@Čß'ŠĒĀ šWßݙ―"<ŦōąŲŽ‚'`O‚A‘cÉHĸøōėģöķũS Uīīybá}―Ķîv?úÛT+“ÉÜ΀€ŽRv·ëO_ŊÚ4wǧ'2T–›Õ“•Éd/ķóA.= Qýņ€ĘÃð0Pk Đ@FEJLLOSPS^NMmRH]J„WSƒV]sOecSfZPdY]b^`d]af\cgWctSa‹ag‘hgikzmpwsuy}vvŒ}u™|rЂrĩ…mūjĘx_ĮjYÄ`NÄVC`ˆîA pHYsÃÃĮoĻd4IDATxÚí \Wķĸ!ŠĀ§ëC’gdKÔ1š|& 4‹ÍŌ€ĻãPYīãÖpmÆ5‚šA‘Ļ •mf@Dâà ãļ°ïf&Šļ&Œ@ģ) 4ŌŽÎäýÏ―ĩtuÓlŠÍžP?ąšŠúVÝŠoŸ>ũÜS·ŠĩÂŋk“JŸ LMMMč?LUß ßĪ_Ø"·BSÕ]ĐĢŨ?kzĶū’Á‹Ú5]?S3ßĪ| ęō™ęiáŌŌŠį€V>ïOMŌ*ųåd­ïäéf†}ËH!cSSSø31Aĸ2U]AĘŌŌÄM•eÕS|%áU–Ž)šy-õQ™ĒV8TcZĶxbŠ8+ Fčt #/ï2‘sÄéĪŅĢúSĮėtiÓe­ķÆHP ˜Ģ$;FĀž–ƒƒÐŲŲÛÛW­žZĘŌ’%KÐŽÅ”]ޚ1>ëž?ÖMŅĨÔþîŧQō—ėUIõĀÝÍb/P]™ŧ―öðÞėæTe~Y?Ø=Õcg>ž’ÅŦnČĶÕY <;Īņ%nG—(SũėÝÖAŸNr§Bņ€'Ņ/€? Š̘†t3ë)s‡̧= åãáBWܰz)‚ŠûՐ°ýH!YáĮåCðėų_~ų_ķjRfĖ:þDiÕË#UîsÂÝQÅāU„ŽŽlFØW­BÜcïÔûįŽX2 Į4Ŋíáō  ]]@—$"6YoēCãã#8ÚÏę7Đ ―‘Ô‘lioÏâN|?ÆÎNÓôĪūr%ĶūrK:ɚ ]…yðþ~~CŌPāaûŔ―CÔ°~Ã:e?óÅ(ŪÁž“ŸKÛ;îĢóSžïÉKY™*jŊĐŦ­­­ëUĩuõÉ|[[†ŧŊÄũgėw!Nõ ūgĻŊ&ГØiØ―š:ݏzOŠ!ûkr_īhæ9ĸþƒßēyÍŠ%nK)ðwčŽxáS$Ą‹ EæmnFÉ\!ģþdn Øiîd‡ßÅ4ýŧĒeUõ3+)ŅĖWŊfaĢzG}Q§úMlïáá1”ÜÉå%)ŋÐIðāiæ/uCāįbá> tIð+WbîdšÂG{{ŧēíKwœ]ôĨ<}ĸÖîā€cx/:ēÖËXČIÚ8C#ýwI• ûũPĀlZ)ƒG.Þ<ÔĩŽjXæŽāŊß°zņüĨsiÁîzSķ…ģÁ"‘ˆLxāĄ†žšč„ængĻÄĮ’‚^ũÜ]ž|ė+YķūzuČQÎu • (ũ‰íá)?ďC?ē&Uî_ėî[ÖŊYĩØMÁý•&Á“^ŦzðvâNžPÅāíz‚w ļ QSĢ‚}%mę}# ÖØ@ɗÏûĪÎöðČÁƒÁ‹‡ÞāÉŪSI"ōÛ)ð;Āí ƒwsSÏøR|ÎĪÅ3žf`ŊėgČū'î<ÅÛÛŦëĨ*bHž#ôįĀāW*S_Ĩ 9n#û㞧"ÁK“ũï]ĘäÅoÂÓ`ƒPĸÖlņ$x7Ęϰė}mņy_/|?&O.ąíęóSŲ&„·ë ^ÝQÜ―–õ0öŦ‘ĄŊŲ@‹Î/*sũũ8wŋ! iOƒƒYägÖŊ Ē] ÍĀo]ŋayÉDAŌM*fF‚GÐHîý˜ž<͝2xoøæ ģŠÃnĮP§ļøe,S'ąoDĖ7nØ  ^™{?R iPįÉcč=6øíÛOģuÝ1 Ïg.%0ČWĀ?āūRī|™· jZíû'O/*s_. >TXžßūÅE$>ö=―;ĶÎīŽ(a‡đŊZĩ‘bū‘Ϙ;ūē€Lޟ}-)…”J.1gåāq L_jõĘž$›;Ō09ŠûÆÓø{. ÁϟOgĩYØAĒMˆŧŊ· cð}‚g)î8Đŧ\ēŋĻ ý5 /.–ø8ô fHėä éáQSØ7*°xp6dË ÄÉĀ]ZÃ3eëėĖ;>`ePðI}8”\ôF< Í=ˆ %ą―tĖ}+ãiÜ`4Â|ú*1ųýĶĀ“ÁÍ2hZbņôĒˆâîãģ\RxðŦCŅ……EÅ_ï -ą,ž !t;ž=NKŌā‘—Yĩšö4Ļŧ„;OkPLģÆG8žtï‰dĖ\ĄRōŽK€dÖŌӓîčÂėb ―€Ėæ.x]îóX! éiø ­TüŽŽ}åiVÓ?‘§Ž”g]ą þ!ôĪÁ BžZĒļĢī˜HRz Ļ0?þō ‹ũ–ōqî™îvtŠŪ<9“āą  î­Ē…%(L•Ŧčœ0&‰HŦ\æ^ž_žBßeÅ ú4a]ĨÃæ#ōCái)bÉ ,îdüūc'nZIO3ŸēwũU8ˆûĒĀSAžPÁ―wðôĨ#†ûrÉŨ… óKKũî”Þ.(>PļÃŧg‡ Yŧ­5Č4ÍJšïDķēÐ―€ĻÖGũˆų2z  f•úd b­ó‚„ŧ„™ŋ`(cx&ĪĄ< eð;w‚ģ!›V ~>ž2,ø~ŊØļ Dü2dðŽ ‹·ëž=Gú,„–öŊâŦē2Zę,T6vžWĀ.@c mų|`ČÓ az\‡7Nąy;/G#kÐooČÃwŅ•é…RÛū>ÎôõKĄ#JČAĸM\pæJ}—Ģá%.ŪB!þH\ð5f„`Þkƒ§\ž˜ęPÄķåÞøÖ0ŽŨĀϟ?Äé1vËĘ2ø_lGžÆ}=ö _Lį[!€Ûī‰ÞŨ˕2ø~ZWî·Ü{PDК&{pïþ[;%ꎰ_{[[kŦk—ē.’V^4šf|9,ĪõđDāœ]Õ&ļ|­JnžŲ*üV*ƊägVfųdUe…——_štŸQŲ$ĩÉ+/ðm­ÚŌCēĨÁyezey–äyÕ% iDVšÅŠlAVë_ųÖō6sK˰Šįax[Ļvbį .~ˆ;OŽĶu; áɀ<€_ãđ˜Æū`>jņé,·ÂÞy*ˆ§Āũiō wSŠûÃG#‰·ß6—HNšō觇ũ%Ö*ØŅnŧeäógæģĨ#Ĩ‘mW ÛŌS*BĀ—„ĪWDķUFķ^šP~C~B*’F\“GJl#Ō+"䙿mé#3ä‘å/V Ž-Û.§ü3Ī­-Žņ”yú3ŅėðŒJģÆČŽËŠŌ[Ê2|ÖÎmá’Ęm7ÐķW`óō°ër—đntDóZÜį‘ģiŋžjZÉŪ h‡îâÅó(ę$ũÅtîO <^ŪŊÂ}߃>™:-ėÁƒ>|ô@æmŦĘö Q$Ÿß”id&f…eĨf]NiG,i}þĀ―|ã‚Ü(Ē-B*j oMąī&Ũ§ļô,ÃČķЏĪJÄϓ"7đ —īeŋ ·ˆxö ĘGd]ūüøđ<Ī1Äü‘IXã…>†·5‚Dn"_á4WaïîŊÝēĒ Jžf;ÕuډĢIKŪņtĮãžæŅ#đÉë dGQað+WúöäŪÞŨ(qũv–Ýpĸþý°SQEũïÝŧĸāÁý|+jNÆu‡m­MēӍgW…™5žČČ4oLOyŲã”FspÐrsųÅ UĒËm'ŠDԐŽ6ÁXŌ–aŅ–~ąŅįRø}I•Äšßv5Ĩ•üŽŽ”į晙ôýhKĸNę Ž>ĖV ņ i ŦŒ46m33ÍÓa·érĄËpg‡4b•Ķu;íßQŋm]šÅîԈ3ŠoąŠēölō+Hƒ:ögōž‚ŧ°øþÝ{wïÞ=|žčö·îÞŋ{?„ïГ;€·ƒˆ&ÅŌ2ĪâņEcIUĨôBX*ieSdVUEŦų…ŠĘŠHIŦHâýüq›Īąēi߅ŠôŲ%°þރ+SēŽÃēöWT„IŠä!•Ō6‘<øúw‚ķĮ•am!BĄýõĮ)V—W·UüŨ‚vŧ5Žó†llÝy `‚x2W@q‡Ķõ KRā1wOŌÞŨŽîÁö4ŽŽýš<›ŧģHvëGЭ‚[ĸøžÞËæ z`b‹·Gą;š OlííP$ ‰{°bˆ=ūkX œÎЧBĄ9ģpŽ}8˜ĀWgčėÚ lmmėŽmímlm…ķķöB[;ĄĢ ŽęŅŽþ ÚRZm­q<3ÄÜų`&–dļC·uëhZįąĀŊ"/Ŧü&ĖÝĨ‡ÁŦsōlîނýũ~üû?þŽõŋߒ‰t\Ī0v!õyâþd Ð.`l 9NŲ[Ðv€_lEņžï2VoŠįÝ708•%rð-yKŅ\EúŽŪĻ Äüķßĩ: Qü>oÞPbbē~ėl xhZŨx.ĀÉ!ũhDģ'ÎzV žj ZO‰ūâ§ļÖA%yՈ•’'G<ĄÉj4ÐRė &:ĪÃöč4MŊM+ö4âE‹ywōŽ1O^UÛL‹ïBųƒūČģļS&/ðą–HJųâ‘!ŽJԅlæs™ĄÛ<āūaū_‚ž"(YzYĮų Ļ\jõSŅįJĒîyÂýa„Ĩ§‡ĘEî!IÄû1A|POƒbÉõ~žČâ,Ķļ‹ĐÓÖoTâžÆkŪ eņ}š<›;ûr`ˆ <‹;CݍpûŊĮ—)é{'pķ#ˆ%†~ 3l WšÉBô―f~Cv ÃĀã+\JŲķÁCŊÕ_žČ'oĢņXüÆÍ,)7­}‚gļ+nß †Þ-C§ŠøÆØÝšįĮ@];ØNýĮRÃ}2ũ€gfÃm­C8@˜ôð‹č;oX—ü”šÖ/ķ­ũCMĪɓwH)îÔaƒ_ĄäizkîĘÐ鑯ä>„ŽBķWW2õųÔxˆwœWę!ķÕŊe+pĀbĘÅY1ußü"JîŊŠEˆšöïb<:Û{ūĀÍPĮMŦ'YuÛ*N݈đ݈ï;ތîī_Š QîÁŅą˧âo_|)ƒoþã+IXÖøų JÏT`Ą€Ū8Ų°dW[]é[Rž”ƒs&DW•–cßÂeĻōčLze6Ŋ#úĶ\zh }‹6y‹9ÎÎFčH ōU)Ū°ĢmQ_RýĢ)ĻįKðíĐ<°——0âŊC ŋõŊŋþĮk°Į=øÓ‹äÛSöîÅŋ:ëSNšŅŽŦ& î7Æœ4ĢņJÜÃҐ&q܇‰ŧ%Į}xļ;Ðņ Į]ģÜ8îÃĮó3wŽ;'Ž;Į“ļëK$[õO0‹ûž>ãúŠâĖMCŽģ}qŸžz;?ï‡Đ{Ø+ĐÅĢũwÃôíÔ{}UqŽ'ũ™{ ؋žS#–{/ņ;ï›RCBßûĖ]§·‰·ß!Ũ―CāEÄ―øëæÜõ„‚ïPï)oþæNŪĨķûmâč-Cr†úJĨÞ|‡ĩ8ÂėÝ[wý#· bTÎýŧŧG••Ý]H―]pg ZDÜoįĸMKÅoŸžSvÓjTAqŲÝ=ÄŅ’ąÄŅõ3ee·ŽŽÝN-ŧ·˜œZVvÓX?ĩ ïf„ė~ĐĮīüēēÐÔ݄~ĘîĢũïßþÞåü;#݂ēb'â­;NÄi'd§Gïï"ð"âþCønbBþÞŌĸ>]š—š{”ė&ïč]ĢĢ7ûhÛž?QÆĮîíÖK―Ĩwéķą^ÞÍą—îÂĶGoÓËđ9nŠqOÝÍK―I-5ž 2ÜįÎå_UŨŪō"óïė –ĘîZaq†æþÖ-Ŧ37g•z―_Zz`þĢĘbîČÞõRïė?sˀ8{ë·eŋ‡ŲR+@Œļž)sB†á~ZvËrDÆ3―q:ßÜ:uĮI7ï–čĻ*w―Ô]ĐŧF•Šŋđn,F!îw€ŧɝÐ;™{ËĩŦgïÎļģ Ž3ÜĮ―kErį‘܉ĐĐww@{7žëŠŽ;ÏĖ0ýxšĖitŲïõS)îoÝĨļo•–ØŒ*õ8T'3ÜK-õōŸŅs&tïýžä>;į& ūiHq7-ÛMŒ7Ký]†đOĩ„†Âr$q§ÚUõÜõSËJKoŊWš'õîí<Š;ZDø~$ôōv`ïāQJoŧ"ýĖäžēÛy?`ĸ^zįĶ ÉÝęt^iéÍđú˜ûhŲí…ĮrKKũŒ’•”î&ŽÝŧ~§ôÎîą#ÐÏx{Ŧõ3á)Ö1YÄŨ‰&Î6˜0­,B/ã-ā?„™ģĮúf"gýŲcņ‘ũD (N‰ŒˆņPtžđl#2&x“,pÖOųSDÎãM ý™ū“`#Ņŋŧšry‚áāîĖqŨ0w|Ïȅã><öîÂqŨ$wĮž a$tąš:‰Ē9{'ĮqpÜ5mïäógŒ„BŽŧfý ~ū˜‘ĢВãŪQîĪ―;:ZpÜ5ęgæ`{wpāė]ģÜÉxÆÞžãŪQîķĪ― ėM8îånËqîĶ$wÃ9s8îšänLs·í›ŧþÔwú]3xM ŦäMyÅõĶ’%õ§ð[;Úv@Ōĸ”4°Ģęw‡=ļ[ũÍ}LÚeô€=Bë…}0§E0―OąNęüåÃFo‰čEÝHāqö° ņVļ‘ĘŲG°Óėúįā)ršÆPMįœALŪ!.Đõ"ōļĒv―“æ―”―π9fīí€Īõt!sōėĢÂ'ÕĢFÞŲÍę>wÍÕÃÞmmÕqŨíÎîȧĖý\!FĀڝÞđ֌l^ÏÔÄKüų ^ũ#§ūļó{Č•ÔzqLQû˜ŽÞ>ģ˜Cú.Œ(ũ19Ėž•ŽJKmžølËŪÂąƒænjmMq7UĮ}LýâÝîJŲ‰ģ`ęĶ]SQRW^` ũēžQVûļp2ZIču:°ūŧēaoZmîđō†ĩžĪ'gkehŦ™Pō|1_Lč~ūĩæ1\Ύ/ŽÎąJJ{ZÝüWóî é‹ÚĮ2BŊ{ũ˜ŽāŪ Ųék6ZŲ6DtūvýÂĪāĊG Óvę^NËÓŪ}üÓ8“äīœÓõĄņU _Dô?>›ØpōĩEŅ5UĄ:•2§—åēc0ĸ1ĶŪžđęÕŪŦĖ·$tÚk{Ōü-Ú*Ķâąė<ĖCųíÕēŽŠĩSߊ­Č3$`š .ģÂĩĢ“z ûÏģŌš5ã2ø;‘öBŧķĒālūat>˜EwEó7ĩ•ųgåč4‰Ņh·9' 0*cφŧĩZ{'þԘu ūár}vvbÃåÚüŽ=ï‚sx™žvÍ-YZi@ÄÔd6ã}+­îvgáXô ëŸ+Ū~ mUŸ]JP`LfZÃÂØ;†DÜĩÄŽýŨš[LēsÎg[éÖęīÃEÛØŌ˜ÜÄ‹ŪŽ'īíßt„~þéÂxYæ^ÝĖīėÎBŌÞÓ2šZiUßč”ÙM ôš‹ÞÓŠÞĢS—ÝųČ):­æft.ž_ˆZ Ô+ëlM“OēKŦĄ―ÅmuĨnÖ‹Ū+":­éoO‚ëJ ‰„‡ Zō`‹Žę2Š―” Úĸ 8°Y{QL(ķzWWáhyZŪ!|yqŲÖĸĨwūģ™:MžÛė.ØU'”ŲĢÄ}pgmmÚKŧzîaZsÆÕoēŅô|‹ é°Ÿąó‡•؉Æ4ė?WĪ]ŸÕŅ’‰ļØ S{ô-.ðM*Isχ܅vZNrWqR‘”™ oéVôĨÖél? +ä-6ˆŧ^wÞųŽïÎįD?ÍÂÜÉbˆ{MÃۘЌŒÃāņ3ũžō ĮtāŠĩžfeĪÆĘ3ęKĒóÆ<y+t0ŅyãĒģ;Z3Ō—Ą2cęē‹Ņņ$<‘Ąc+& ü“Ėœ™_aëiÏ7BÓkøÃFĩgĢ=Ï O s'Ë`7[íÕëĖĖ į…Z,―„ÖŒō4yänOĪĩgĒ2Ą îF|>æÎįŦåŪuídtÎųÖÏfhŋ@Ó)ŋ”œšØâŸcÃqôÉĢ•Ķā=öŸéØ{.'Fæ“(˄vïÉSpĐzÓÉÚĻdZÎĐšBðŒČ.ĀíŽé*Uwš„s™9įåÁg:č"§ųvâ#§ļ§ÁWžˆčDžýŲēhŨx™ÛYݘ–ÓUýų™ī˜ãmGžė1yáâs°I‰~BþĐč§1uĄ3ĖófuF7œ@óÐØäÄķÆätåϘþĄÕÛ 6ŠĻļ>4Ų*ŸõbVĮ~8Θ?&=uŌ‡i]Ë^ݎïQíøĪšóOEfÖYtlRë‰' ąûķé΋n=ĸ4øe įR|ķ‰[ÂŅĄ’§‰w{1vUôā>ķ^įî7_‰Ö +ÅBžžĐDãÕ&]5äó þƒļ“5Ā@o:+î{+"ŌhúŦFĸQÜuϧX‘=Þ(ŅŊ:O@Ųŧ……aßÜĩÐu.Ŧƒwv=ęÄæ+6T·KŅ ûUrgaAq§–ŧþé(ĢĶF™ÄĘ|ðüīY†o4Ž xãŅúÉQQ>ëý™ĶÄä(3ô5|e8: ĮeþņLS―Ļ(ø?[ŋ;ÏÍÃNgFAG›7qZÔlBöņá{&ņĀÃčÔéF™C„09ŠŦˆĐnrŨûSScŅ9iuåž•gŸĮó-(Ð$…>'^ÛT]xŪŠZVsûtgS3DJqåÍįŦŦrųLéóý M ĄgÛŦsÍj.ė†y"›šwAüW-mþ Þ=Üy !O'ʈ)ŊĖŠ­j>žsĒŪŠĒ0žŪnrŨĐiŪyԑG$jį!į‘ŧ‰nŊ)3ā%æÂzŽšių12íiōJčŧjå|ÔŠÛ~Žũŋ‰˜f­ry̓š›}_Œį- ýxyåMwëuĪý,Ŋ‘ĨzYð lŠ›đ=.HČÎNË#âo(ŠûrÏÂĪ/îZOœŒJB]͘Ü1Ô<`š?‘ė›%eÔ‚>HqtęEž2GÞY·sę›!7;.Ķ!ōdTgÁ 9ô*ĩ`ÞĖ€wîEdW!ęgBo°ÖÄfæïڍr{Á­'īĒėđĖV\ÞTƒ_#ũą&͘ŧ‰éXĩųČį^<œXˆė―úP9.üéũe†ú0îZû•Ū‡iE1-Ð5}r%eJN]éjN“-&ô^ķ|ŪÅPŦîÚÅāŪŽīŠ=ņ )0ĸ•/ūõûZÔw…>*^ĢS{3šéŋQžooĖ“ŋ=O]ĨŨtáębPÂëWČݔänŠž;Ą“–Y|BBœ‘@6q9:™)ÁĸEs{öÉ}[čŨœ†LĄĄģ)îBqŸÜ7ŋĮy…!Ô&Šûuįŋūđŋ;°Î8ÉA€–3ÜŨų‰―'Ë9ĻÐ šŧKP`Üy3gÍV·ÞdÖhŲ#mÔÁpũÞšŽß7w―øĘŠRu9p­ēÆc&sÜĮ}[P?ÜĮÍČ1 ŌĮKģęe0’6QŽÖpÜÉ}§ o{ŨíŽĻ(9[SŅ|ĩĶĒĨVT~Ÿ—ęę`úŦýrũyņ^Ôz5orR•é΁r·XÁiåü_äÎéMˆãÎqįļszóÜ―úá~äŌENC§K3ČýâĮp:ųv€Üŋ›Čy…!T8ĮýĸwíýėO'˜ƒ:äÜĮÔĘŽúޟvŠuPÜw €{lv'ܰŊ?ýÓąÄäéŋ!&LŸþóž ŸĀ́xŸN‡7uú8î@ļ{€ŧ~ÂĄøîĘæßEŨT–Œî”ķøtVåžĐĐ*yŦŪēō Vėŧ' áŲcŦŦvqp‡ŠŧN͇V›S| <ĐĻîšKüđ­úoŧˆXxPIb‹aœ\ŧúwZOū­iŪ-ë.å~q€Ü·ũÏ=ķžĒĒ|OÜJŠŸy– øøLgŪylmIBÝÏaŅzrĒĶø˜dtRõnîĀļï@Ü-ûāŪŨUøÛōĒkRÃgw·$KbĨ)áģŽ%d{ĪŦ öiJg‘púŲ/đGöIŪ+áā†ŧ{ܓÜāq!‡ bÛ3tŧÚqíYĮÓÚh·gŊāÅ·_1Öđ`…þ:ۋbÛóļļf Üoũ9˜ŧŧ-ŨoŌ(ũíũaāîĘqî.ÛķےÜm8îlW9îÃÄ=h Ücâ…ģGčnҘï‡^x҇{t”Ļ·Hé'ķĩ·_ab‘žÆaqßÖ?wÚfüÔĢx怚äÜĻ“h|L*M_·ËC/‚ÅV?ú|yA“ģŅVƒô@ý^ô“\hýMqÜýĀ}ö/7ÄåÄĘôP:,.Į8>ü{tüð]wüuŒ!3b_vǟ2[Čî—ŧx ܍ãģâsÎÔ4JŋĪļT'3ë~\UōļĮV4>%3‘Ú5•đu?ŪäüĖpŨŸHžý.šNž>éņïà üM˜>Vú ‹ņïÞãM3o0a,oâ{Ä䟠õâūđۉņs đ~Į}dpũäļw1Įý?•ŧþĪũ9dšįþVüþũizŒ™áū.w[OÏþļC&’xkV=sÃX\Žðĩđ{ô˝—(s%Ë퉗ʜĒ;š—ߎI5ŠIÕéĖĻ åPū*w~ýŒ^âcļa2Ôhôũ5%qķ$ūðQņ/īĘKbđ”Āä#ÆjÖïŌí~^ ČPڀJŅčÖr·Ŧū1îúg—ŽŪ=TŋGëĄSW ķtŦØV›—2­ę]ŅOđŦoŒ;/ķĒĒðÝUčŪ|v öšą6 KíŽhūĶ]#­āîV}Ģ~F­`Ā’ã>bļëøō•ûŦŊΝÓës·ōāļk”;ó;qwÍr§'ŽãŪQîŽ~}ĸ>ĮýpŋŪø}>îųšäîčÏqîë0wą˜ó3šäîDþNœĮ]ģÜ·QÜđvUģÜ·ãßįãûsöŪQîū;ðó 8îįŽŸ?Ãðģįļk’;ųû|ցwrĮÏKĩôįļk’û2ŠûÚGŽûpp_ĮqįļîAk9îÃŅŪ­rÜ5ÏݖãÎqQ~&ȅã><ÜŊsÜ9îŋvî^wŽ;ĮãÎqįļsâļĸ_įūƒÎÏpÜ9îŋ~îÞ î\ž@“Ü·s܇‡ûŽ;Į}Äq_ËqŨ4ũ9wsŋÁq.îÛ9îÃĀݕü=JŽŧ†đŧ0ÜđëښlW9îÃÄ=ˆã><Ü·q܇‘;7nIģí*õûŦwsĮŋĮų sŌÜŨqņŧFđŊãļ+wŪŋ:LÜ9ĸŪIîŽũaâūŽã>,ÜŨr܇ƒ{ gïÃÂ=€ã><ÜņïŊrÜ5Ė݁ãÎqQÜúæ>žƒõ&ļSŋ{kØ ũ —.r:ĨÏ wâ]NCĻ· †ŧ?É=°îœÞ€ÜŨrÜ5Ë]ĖqVî―<ũ‡Ó›áNýÞpïí*§7Ę}-Į}8ļó9ĸŪaîäïÞōŨŪãļũuũaáÜđ˜Ķ4‘þg>ôWŊG͘ÉIšuúgĖ}æ'S9iBŸĖĪļ;^Ÿņņ'œ4Ąg0Ü8îånģˆēũŽŧFíݝã><ÜÝG.ũÉŊ )ÔķS&―‚>TøwwËĘý·Ÿœ ŽB‚ŋ%Á8óøąÁ+ęCUî#û”ý?ücÐúûM ?eÖåï ZÉ'?dļ“þÝäqĸīð‡ß^/™ŒĖ=âûÞý`zũíðä‰#žûo§ßúÃėÁ:čß8ýPˆđO~ũã)ƒÔĮO^Pp'ÛUĸÉ]Eð_yQY“Ü?PQŨqˇS”–'`sĮþýsŽ;čS3‹ŲæŠEssÕģ—*ļ+õü'Ÿ>ųí4•tĀĮÚ؟)Ĩ^>äļ“Üm•ĄþĶû§/u:Î61šm<1Đаwîã?e+ąēōŅþũ??uĘo>˜0í“>ø“>ø šE2]hŠîŸsÜgtŪš`zĮÁų‹ ĪâÎŪýЄß+ũ‰, Į>ÝóÏ_HŽt=ŋb]ĸ|ïđįųg_(sĸļw+ņˆäþ™’ĖŌō;ŠÛŊ<đŌž{ū!―uo§ė€Š‚îŸF)4Ŧ;Į,jÖĖĢuđĩēī†”Ú‚äī§OēZ‚ĢؚІŧÃäūųģl}––žĩ%ģžŠRķðeųnóī/å+>û’á>ã”B§ŧrgŠ:ÛYYŅÜVŽÝÞ!ó™Ų]^YŲÖ|Š­Ļˆž~F<đoųl[Ā}eŨO™ ŋ·qþŽSšŋĒ+oĄrM―pĸ6I:ëhŨÉĀýl{ÆÓ―3še>ÓcšCúán5BđK6ģ%I+p;ŅÚųsE^gîņ†’ðĮ·7Ŧ”PpŸu’ĨSݏ?JĐ}\ÕÜÜSš~ŪļXûø§Ė֐SJĨ8î˜ûî›·°ĩyĸõëWŊĸmËūŊv~ąeóķ/ķėÛđEY›YÜO°tōdÄņˆ“'ŽGĒyX:~""ŅKjļ‹Åö#‘ŧ ÕÃÍ ų[z—‚{Tä‰ÁęĪ:î#ÍÞ?™~û‡Ý*úNÁėî]{v3ų™i'­ėü ÉÝÓÓ~Äåĸøãāó‘ĸļĩį#Ģ2’ZáĮ?TĩwÏgïSĶ…žöQųũSÉŊ ãŠųwð3v#îzÓo'Ož&S8ņÔãzø;îúŠĶÄæ.ķŋÁqîœ―sÜGwOŧ3Ķ|ĖIšÂâîawƒŽąņĀũį&žŽ!Ũo(éúë°æšzÝP)üęš> ý_qïƒ>ĩ; qtw7yŪ%ÍsŸïdgggoïāāHI"§H.äT!xÓÁ6ąĩéEķvý‹Ž†ÚĢ+–··Ŧ—Š\]á@úω-;{Ø%ėŠÞ’-UŅ'į8`ąËÛÛSgaKÉfĀrt›į&’jUĶÛxļ{zzŠÅ~âÏ?ũũũ  \ļþz(i-žā'öđũ"þ%ö`í3h;[;íØī.PėéąČ―yxŠýUöÄ(ˆ%ĨS °čōþþbąXųlÜŪyólŌk=—ÛĖó@ÜşcðˆûZĻEÁ=ˆ(h;Z ð‡šÝ=^‡{ ―Sž;v*kĮķ u~:1ÏÏÖQێ;úâĸ ā™-^ž›MĪīJ+ĢQš.2ąBâÃ-ëÞe‹&PocŲ‹Žú—Ē[…æ(ÕņûĻHđRīOf'sæØöTogÅïG*e{œå@eė“.­lÓú>ĢąBúėYĨg &fЧžaáWfĐ5õ'ЈúâÔĘgJ‹ýŠĐũŠû;īþöÜóȟ―šĪŦÚ2ĸ?š‘ŅķōcPĐ §â‡øÂECÅÝšTyŲЁ@ՕŦÁkÞítÁõ7KoÝÚîÜ―wĸĄï!!•Ŋį‘°ÞIENDŪB`‚qt-installer-framework-4.0.1/doc/includes/0040777000000000000000000000000013761647206015453 5ustar00qt-installer-framework-4.0.1/doc/includes/IFWDoc0100777000000000000000000000607613761647206016462 0ustar00#pragma once #ifdef Q_CLANG_QDOC // installer #include "abstractfiletask.h" #include "abstracttask.h" #include "adminauthorization.h" #include "binarycontent.h" #include "binaryformatengine.h" #include "binaryformatenginehandler.h" #include "binaryformat.h" #include "binarylayout.h" #include "commandlineparser.h" #include "componentchecker.h" #include "component.h" #include "componentmodel.h" #include "constants.h" #include "consumeoutputoperation.h" #include "copydirectoryoperation.h" #include "copyfiletask.h" #include "createdesktopentryoperation.h" #include "createlinkoperation.h" #include "createlocalrepositoryoperation.h" #include "createshortcutoperation.h" #include "downloadarchivesjob.h" #include "downloadfiletask.h" #include "elevatedexecuteoperation.h" #include "environmentvariablesoperation.h" #include "errors.h" #include "extractarchiveoperation.h" #include "fakestopprocessforupdateoperation.h" #include "fileio.h" #include "fileutils.h" #include "globalsettingsoperation.h" #include "globals.h" #include "graph.h" #include "init.h" #include "installercalculator.h" #include "installer_global.h" #include "installiconsoperation.h" #include "keepaliveobject.h" #include "lazyplaintextedit.h" #include "licenseoperation.h" #include "linereplaceoperation.h" #include "lib7z_extract.h" #include "lib7z_list.h" #include "lib7z_facade.h" #include "link.h" #include "messageboxhandler.h" #include "metadatajob.h" #include "minimumprogressoperation.h" #include "observer.h" #include "packagemanagercoredata.h" #include "packagemanagercore.h" #include "packagemanagergui.h" #include "packagemanagerpagefactory.h" #include "packagemanagerproxyfactory.h" #include "packagesource.h" #include "performinstallationform.h" #include "permissionsettings.h" #include "productkeycheck.h" #include "progresscoordinator.h" #include "protocol.h" #include "proxycredentialsdialog.h" #include "qinstallerglobal.h" #include "qprocesswrapper.h" #include "qsettingswrapper.h" #include "qtpatch.h" #include "range.h" #include "registerfiletypeoperation.h" #include "remoteclient.h" #include "remotefileengine.h" #include "remoteobject.h" #include "remoteserverconnection.h" #include "remoteserver.h" #include "replaceoperation.h" #include "repositorycategory.h" #include "repository.h" #include "runextensions.h" #include "scriptengine.h" #include "selfrestartoperation.h" #include "serverauthenticationdialog.h" #include "settings.h" #include "settingsoperation.h" #include "simplemovefileoperation.h" #include "systeminfo.h" #include "testrepository.h" #include "uninstallercalculator.h" #include "unziptask.h" #include "utils.h" //kdtools #include "environment.h" #include "filedownloaderfactory.h" #include "filedownloader.h" #include "genericfactory.h" #include "job.h" #include "kdtoolsglobal.h" #include "localpackagehub.h" #include "lockfile.h" #include "runoncechecker.h" #include "selfrestarter.h" #include "sysinfo.h" #include "task.h" #include "updatefinder.h" #include "update.h" #include "updateoperationfactory.h" #include "updateoperation.h" #include "updateoperations.h" #include "updater.h" #endif // Q_CLANG_QDOC qt-installer-framework-4.0.1/doc/includes/installerfw-examples-configuring.qdocinc0100777000000000000000000000222413761647206025473 0ustar00 \section1 Configuring the Example Installer The installer configuration file, config.xml, in the \c config directory specifies the text and default values used in the installer: \list \li The \c element specifies the application name that is added to the page name and introduction text. \li The \c element specifies the application version number. \li The \c element specifies the installer name displayed on the title bar. \li The \c <Publisher> element specifies the publisher of the software (as shown in the Windows Control Panel, for example). \li The \c <StartMenuDir> element specifies the name of the default program group for the product in the Windows \gui Start menu. \li The \c <TargetDir> element specifies that the default target directory is located in the \c IfwExamples directory in the home directory of the current user (because the predefined variable\c @HomeDir@ is used as a part of the value). For more information, see \l{Predefined Variables}. \endlist ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/includes/installerfw-examples-generating-online.qdocinc������������0100777�0000000�0000000�00000001147�13761647206�026571� 0����������������������������������������������������������������������������������������������������ustar�00������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \section1 Generating the Example Installer To create the example installer, switch to the example source directory on the command line and enter the following command: \list \li On Windows: \code ..\..\bin\binarycreator.exe --online-only -c config\config.xml -p packages installer.exe \endcode \li On Linux or macOS: \code ../../bin/binarycreator --online-only -c config/config.xml -p packages installer \endcode \endlist You should now be able to run the installer and install from the repository. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/includes/installerfw-examples-generating.qdocinc�������������������0100777�0000000�0000000�00000001060�13761647206�025301� 0����������������������������������������������������������������������������������������������������ustar�00������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \section1 Generating the Example Installer To create the example installer, switch to the example source directory on the command line and enter the following command: \list \li On Windows: \code ..\..\bin\binarycreator.exe -c config\config.xml -p packages installer.exe \endcode \li On Linux or macOS: \code ../../bin/binarycreator -c config/config.xml -p packages installer \endcode \endlist The installer is created in the current directory. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/includes/installerfw-examples-packaging.qdocinc��������������������0100777�0000000�0000000�00000001224�13761647206�025104� 0����������������������������������������������������������������������������������������������������ustar�00������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \section1 Creating the Example Package Information File The installer package information file, package.xml, in the \c meta directory specifies the components that are available for installation: \list \li The \c <DisplayName> element specifies the human-readable name of the component. \li The \c <Description> element specifies the human-readable description of the component. \li The \c <Version> element specifies the version number of the component. \li The \c <ReleaseDate> element specifies the date when this component version was released. \endlist ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-cpp-classes.qdoc���������������������������������������0100777�0000000�0000000�00000005203�13761647206�021262� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage Scripting API \page ifw-cpp-classes.html \nextpage ifw-knownissues.html \title C++ API The C++ API documentation is written for developers who develop the Qt Installer Framework. It describes the internal API, so there is no compatibility promise. Further, the documentation is a work in progress and therefore parts of it are missing while other parts might be out of date. To create customized installers, use the \l{Scripting API}, instead. For more information, see \l {Customizing Installers}. \section1 Namespaces \table \header \li Namespace \li Description \row \li \l{qinstaller-module}{QInstaller} \li Contains classes to implement the core functionality of the Qt Installer Framework and the installer UI. \row \li \l{KDUpdater} \li Contains classes to automatically detect updates to applications, to retrieve them from external repositories, and to install them. KDUpdater classes are a fork of KDAB's general \l{http://docs.kdab.com/kdtools/2.2.2/group__kdupdater.html} {KDUpdater module}. \endtable \section1 QInstaller C++ Classes \generatelist{classesbymodule QtInstallerFramework} \section1 KDUpdater C++ Classes \generatelist{classesbymodule kdupdater} */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-examples.qdoc������������������������������������������0100777�0000000�0000000�00000003015�13761647206�020662� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \group qtifwexamples \previouspage ifw-customizing-installers.html \nextpage ifw-reference.html \title Qt Installer Framework Examples \brief Illustrate how to customize installers. These examples illustrate how to use component scripts for customizing installers. */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-getting-started.qdoc�����������������������������������0100777�0000000�0000000�00000011474�13761647206�022161� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage ifw-overview.html \page ifw-getting-started.html \nextpage ifw-use-cases.html \title Getting Started Qt Installer Framework is developed as part of the Qt project. The framework itself uses Qt. However, it can be used to install all kind of applications, including (but not limited to) applications built with Qt. \section1 Supported Platforms You can use the Qt Installer Framework to create installers for all platforms supported by \l[QtDoc]{Supported Platforms}{desktop Qt}. The installers have been tested on the following platforms: \list \li Microsoft Windows 7, and later \li Ubuntu Linux 16.04, and later \li macOS 10.12, and later \endlist \section1 Building from Sources The following steps describe how to build the Qt Installer Framework yourself. You can skip this if you have downloaded a pre-built version of the framework. \section2 Supported Compilers The Qt Installer Framework can be compiled with Microsoft Visual Studio 2013 and newer, GCC 4.7 and newer, and Clang 3.1 and newer. Currently, the tested combination for Windows is Qt 5.12.4 with MSVC 2015. \section2 Configuring Qt If you use a statically built Qt to build the Qt Installer Framework you do not have to deliver Qt libraries, which enables you to distribute installers as one file. Please read SSL Import and Export Restrictions from http://doc.qt.io/qt-5/ssl.html if you are statically linking against OpenSSL libraries. The supported Qt version is 5.12.7. \section3 Configuring Qt for Windows We recommend that you use the following options when you configure Qt for Windows: \code configure -prefix %CD%\qtbase -release -static -static-runtime -accessibility -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests \endcode Build Qt: \code nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras \endcode \section3 Configuring Qt for Linux We recommend that you use the following configuration options for Linux: \code configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev \endcode Build Qt: \code make module-qtbase module-qtdeclarative module-qttools module-qttranslations \endcode \section3 Configuring Qt for macOS We recommend that you use the following configuration options for macOS: \code configure -prefix $PWD/qtbase -release -static -no-securetransport -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -no-freetype \endcode Build Qt: \code make module-qtbase module-qtdeclarative module-qttools module-qttranslations \endcode \section2 Setting up Qt Installer Framework \list 1 \li Clone the Qt Installer Framework source code from \l{http://code.qt.io/cgit/installer-framework/installer-framework.git/} to get the sources for the tools. \li Build the tools by running the "qmake" from the static Qt, followed by "make" or "nmake". \endlist \note To contribute patches to Qt Installer Framework, follow the standard Qt processes and guidelines. For more information, see \l{http://wiki.qt.io/Contribute}{Contribute to Qt}. */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-overview.qdoc������������������������������������������0100777�0000000�0000000�00000011344�13761647206�020716� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage index.html \page ifw-overview.html \nextpage ifw-getting-started.html \title Overview of Qt Installer Framework The Qt Installer Framework provides a set of tools and utilities to create installers once, and deploy them across all the supported desktop Qt platforms without rewriting the source code. The installers will have the native look and feel on the platform where they are run: Linux, Microsoft Windows, and macOS. The Qt Installer Framework tools generate installers with a set of pages that guide the users during the installation, update, or uninstallation process. You provide the installable content and specify information about it, such as the name of the product and the installer and the text for the license agreement. You can customize the installers by adding widgets to the predefined pages or by adding whole pages to provide users with additional options. You can create scripts to add operations to the installer. \section1 Choosing Installer Type You can provide end users with an \e offline or \e online installer, or both, depending on your use cases. \image ifw-overview.png Both installers install a \e {maintenance tool} that can later be used to add, update, and remove components. Offline installers contain all the installable components and do not require network connections during the installation. Online installers only install the maintenance tool that then downloads and installs components from an online repository on a web server. Therefore, the size of an online installer binary is smaller and its download time is shorter than that of an offline installer binary. The total time spent downloading and running an online installer might also be shorter than dowloading and running an offline installer if the end users do not install all the available components. End users can use the maintenance tool to install additional components from the server after the initial installation, as well as to receive automatic updates to content as soon as the updates are published on the server. However, this works for an offline installation only if you specify a repository address in the offline installer configuration or if end users specify the repository address themselves in the maintenance tool settings. Create an offline installer to enable users to directly download the installation package on a media for installation on a computer later. You can also distribute the installation package on a CD-ROM or USB stick, for example. Create an online installer to enable users to always install the latest versions of the content binaries. \section1 Promoting Updates Make online repositories available to promote updates to end users who install your product. The easiest way to provide an update is to recreate the repository and upload it to the web server. For large repositories, you can update only the changed components. \section1 Providing Content for Installers You can enable other content providers to add components to the installer as add-on components. The component providers must set up repositories that contain the installable components and deliver the URL that points to the repositories to end users. End users must then configure the URL in the installer. The add-on components are visible in the package manager. */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-reference.qdoc�����������������������������������������0100777�0000000�0000000�00000003460�13761647206�021006� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage Qt Installer Framework Examples \page ifw-reference.html \nextpage ifw-cli.html \title Reference The following sections contain detailed information about the Qt Installer Framework: \list \li \l{Command Line Interface} \li \l{Configuration File} \li \l{Package Directory} \li \l{Controller Scripting} \li \l{Component Scripting} \li \l{Operations} \li \l{Tools} \li \l{Scripting API} \li \l{C++ API} \endlist */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw-using.qdoc���������������������������������������������0100777�0000000�0000000�00000043211�13761647206�020173� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage ifw-getting-started.html \page ifw-use-cases.html \nextpage ifw-use-cases-install.html \title End User Workflows The end user experience is similar for offline and online installers. Along with your application, the installers install a maintenance tool that consists of a package manager, an updater, and an uninstaller. End users can use the maintenance tool to add, update, and remove components. The maintenance tool connects to an external repository to fetch the components to add or update. You can specify the repository in the configuration file or end users can specify it in the maintenance tool settings. You can support the following end user workflows: \list \li \l{Initial Installation} \li \l{Adding Components} \li \l{Removing Components} \li \l{Updating Components} \li \l{Specifying Settings} \li \l{Using from Command Line} \endlist */ /*! \contentspage index.html \previouspage ifw-use-cases.html \page ifw-use-cases-install.html \nextpage ifw-use-cases-add.html \title Initial Installation The following image illustrates the default workflow for installing applications: \image ifw-user-flow-installing.png "Installation workflow" This section uses the \e {Your Application Installer} example run on macOS to illustrate the default workflow for end users. The installers have the native look and feel on each supported desktop platform, and therefore they look and feel different when run on Linux and Windows. The example files are stored in the \c{examples\tutorial} directory in the Qt Installer Framework repository. You can use the \c binarycreator tool to create \e {Your Application Installer}. \section1 Starting Installer When end users start the installer, the introduction page opens: \image ifw-introduction-page.png "Introduction page" You specify the name of the installer and the product to install in the \c config.xml configuration file. When end users select \gui Continue, the target directory selection page opens. \section1 Selecting Target Directory End users must specify the target directory for the installation. You can specify a default value in the \c config.xml configuration file. \image ifw-target-directory-page.png "Target directory selection page" When end users select \gui Continue, the component selection page opens. If the directory already contains files, a warning page opens: \image ifw-warning-existing-installation.png "Warning page" \section1 Selecting Components The component selection page lists the components available for installation and a short description of each component. End users select the components to install. They can select \gui {Select All} to select all components, \gui {Deselect All} to deselect them, or \gui Default to revert to the default selection. \image ifw-select-components.png "Component selection page" You add the installable components to the \c data directory in the package directory. You specify information about the components in the \c package.xml file in the \c meta directory. You can use a boolean operator or a script to specify whether a component is selected by default. When end users select \gui Continue, the license check page opens. \section1 Accepting License Agreements On the license check page, end users must accept the terms of the license agreement for the installation to continue. \image ifw-license-check-page.png "License check page" The license check page is displayed, if you specify a license file in the \c package.xml file and copy the file to the \c meta directory. \section1 Selecting Windows Program Group On Windows, the Start menu directory selection page enables end users to select the program group for the product in the Windows \gui Start menu. \image ifw-win-program-group.png "Start menu directory selection page" You specify a default value for the program group in the \c config.xml configuration file. When end users select \gui Next, the ready for installation page opens. \section1 Installing Components The ready for installation page informs end users that the installation can begin when users select \gui Install. \image ifw-ready-for-installation.png "Ready for installation page" During the installation, the perform installation page displays information about how the installation is progressing. End users can select \gui {Show Details} to view more information. \image ifw-perform-installation.png "Perform installation page" When the installation is complete, the installation finished page opens. \image ifw-installation-finished.png "Installation finished page" To this page, you can add the option to start the installed product upon closing the installer. You specify the product to start and the text to display in the \c config.xml configuration file. */ /*! \contentspage index.html \previouspage ifw-use-cases-install.html \page ifw-use-cases-add.html \nextpage ifw-use-cases-remove.html \title Adding Components If end users did not select all the components available for installation during the initial installation, they can use the package manager to install the remaining components from a repository later. The package manager is part of a maintenance tool that is installed together with the application during the initial installation. This only works if a repository that contains the components is available either locally or externally. The following image illustrates the default workflow for installing additional components: \image ifw-user-flow-adding.png "Add components workflow" This section uses the \e {Maintenance Tool} installed by the Qt 5 installer run on macOS as an example implementation of how end users can add components after the initial installation. The Maintenance Tool contains the package manager, updater, and uninstaller. \section1 Starting Package Manager When end users start the Maintenance Tool, the introduction page opens: \image ifw-add-components-introduction.png "Introduction page" When end users select \gui {Package manager}, and then \gui Continue, the component selection page opens. \section1 Selecting Additional Components The component selection page lists the components available for installation and a short description of each component. Installed components are displayed selected in the list. End users select additional components to install. They can select \gui Reset to display the currently installed components again. \image ifw-add-components-selection.png "Select Components page" When end users select \gui Continue, the ready to update page opens. \section1 Installing Selected Components The ready to update page informs end users that the components are installed when users select \gui Update. \image ifw-ready-to-update.png "Ready to Update Packages page" The update page displays information about how installation is progressing. End users can select \gui {Show Details} to view more information. \image ifw-perform-update.png "Update page" When the installation is complete, the update finished page opens. \image ifw-update-finished.png "Update finished page" */ /*! \contentspage index.html \previouspage ifw-use-cases-add.html \page ifw-use-cases-remove.html \nextpage ifw-use-cases-update.html \title Removing Components The following image illustrates the default workflow for removing either all or some installed components: \image ifw-user-flow-removing.png "Remove components workflow" This section uses the Qt 5 Maintenance Tool run on macOS as an example implementation of how end users can remove all or selected components. \section1 Removing All Components When end users start the Maintenance Tool, the introduction page opens: \image ifw-add-components-introduction.png "Introduction page" End users can select \gui {Remove all components}, and then \gui Continue, to remove all installed components. The ready to uninstall page informs end users that the uninstallation can begin when users select \gui Uninstall. \image ifw-ready-to-uninstall.png "Ready to uninstall page" \section1 Removing Selected Components End users can select \gui {Package manager}, and then \gui Continue, to select components to remove on the component selection page: \image ifw-add-components-selection.png "Component selection page" When end users deselect the components to remove, and then select \gui Continue, the ready to update page opens. It informs end users that the components are removed when users select \gui Update. \image ifw-ready-to-update.png "Ready to update page" The update page displays information about how removal is progressing. End users can select \gui {Show Details} to view more information. \image ifw-removing-components.png "Update page" When the removal is complete, the update finished page opens. \image ifw-update-finished.png "Update finished page" */ /*! \contentspage index.html \previouspage ifw-use-cases-remove.html \page ifw-use-cases-update.html \nextpage ifw-use-cases-settings.html \title Updating Components The following image illustrates the default workflow for updating installed components: \image ifw-user-flow-updating.png "Updating workflow" This section uses the Qt 5 Maintenance Tool run on macOS as an example implementation of how end users can update installed components. \section1 Starting Updater When end users start the Maintenance Tool, the introduction page opens: \image ifw-updating-introduction.png "Introduction page" When end users select \gui {Update components}, and then \gui Continue, the component selection page opens. \section1 Selecting Components to Update The updater displays a list of available updates that end users can select from. \image ifw-updating-components.png "Component selection page" When end users select \gui Continue, the ready to update page opens. \section1 Updating Selected Components The ready to update page informs end users that the components are updated when they select \gui Update. \image ifw-ready-to-update.png "Ready to update page" The update page displays information about how updating is progressing. End users can select \gui {Show Details} to view more information. \image ifw-perform-update.png "Update page" When update is complete, the update finished page opens. \image ifw-update-finished.png "Update finished page" */ /*! \contentspage index.html \previouspage ifw-use-cases-update.html \page ifw-use-cases-settings.html \nextpage ifw-use-cases-cli.html \title Specifying Settings Settings pages enable end users to specify proxy settings or install add-on components. End users select \gui Settings on the introduction page to specify the settings. \section1 Specifying Proxy Settings By default, the installer uses system proxy settings. End users can select to use no proxy or specify the proxy settings manually. \image ifw-settings-network.png "Network tab on Settings page" \section1 Installing Add-on Components To install add-on components, end users select the \gui Repositories tab. \image ifw-settings-repositories.png "Repositories tab on Settings page" If the web server requires authentication, end users can add their username and password. To display passwords, end users select \gui {Show Passwords}. To add their own repositories to the installer, end users can select \gui Add and specify the URL that points to the repository. Temporary repositories can be used only once, for initial installation. After the installation, only default and user-defined repositories will be available. */ /*! \contentspage index.html \previouspage ifw-use-cases-settings.html \page ifw-use-cases-cli.html \nextpage ifw-tutorial.html \title Using from Command Line Qt Installer Framework 4.0.0 introduces a new command line interface workflow. Most of the end user use cases can now be performed using a text based interface, either interactively, or unattended by specifying the desired options beforehand. This topic describes the basic use cases. For more information about the syntax and a description of all supported options, see \l{Command Line Interface}. \section1 Installing Components Both the installer and the maintenance tool support installation of new components from command line. The following will install the components given as an argument and their respective dependencies: \code maintenancetool.exe install componentA componentB componentC \endcode If no components are specified, the default set of components will be installed instead. This includes components with elements \c <Default> or \c <ForcedInstallation> set to \c true. The default installation can be only done with an installer binary. The \c --root option can be used to select an installation target directory: \code installer.exe --root "C:\Users\MyUser\MyInstallation" install \endcode \section1 Checking for Available Updates To print information about available component updates, run the \c check-updates command with the maintenance tool: \code maintenancetool.exe check-updates \endcode \section1 Updating Components Running \c update without arguments will update all components that have an update available. Essential components are always updated first, same way as it is done when launching updater from GUI. To update only a specific subset of installed components, they can be provided as an optional argument for \c update: \code maintenancetool.exe update componentA componentB \endcode \section1 Uninstalling Components The \c remove command can be used to uninstall selected components. This will automatically uninstall their children and other components depending on the components about to be uninstalled: \code // This would also automatically uninstall componentC.subcomponent1, componentC.subcomponent2,... maintenancetool.exe remove componentC \endcode \section1 Listing Installed Components To get a list and print additional information about currently installed components, run the \c list command with the maintenance tool: \code maintenancetool.exe list \endcode \section1 Searching for Available Components The \c search command can be used to search components from available repositories, or from integrated binary content in case of an offline installer. It can be used with no arguments to list all available components or with a regular expression to get a list of only components matching the pattern: \code installer.exe search "expression" \endcode \section1 Performing Full Uninstallation To uninstall all components and remove the program directory, including maintenance tool, run \c purge command: \code maintenancetool.exe purge \endcode \section1 Unattended Usage By default, the generated installers may ask for additional information during installation, which requires user attention. Unattended usage is possible by providing all information beforehand with appropriate options: \code installer.exe --root "C:\MyInstallation" --accept-licenses --default-answer install componentA \endcode In this example, \c --accept-licenses is used to automatically accept all license agreements required by components to be installed. The \c --default-answer option is used to answer all message queries with their default answer. Alternatively, \c --accept-messages and \c --reject-messages can be used to accept or reject all message queries. To provide unique answers for individual queries, for example to confirm overwriting of an existing directory, you could use \c {--auto-answer OverwriteTargetDirectory=Yes}. Automatic answers are shown on the console output and installation log. */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/installerfw.qdoc���������������������������������������������������0100777�0000000�0000000�00000206466�13761647206�017065� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ // ********************************************************************** // NOTE: the sections are not ordered by their logical order to avoid // reshuffling the file each time the index order changes (i.e., often). // Run the fixnavi.pl script to adjust the links to the index order. // ********************************************************************** /*! \contentspage{index.html}{Qt Installer Framework} \page index.html \nextpage ifw-overview.html \title Qt Installer Framework Manual \section1 Version \ifwversion The Qt Installer Framework provides a set of tools and utilities to create installers for the supported desktop Qt platforms: Linux, Microsoft Windows, and macOS. \note Report bugs and suggestions for the Qt Installer Framework project in the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker}. \list \li \l{Overview of Qt Installer Framework} \li \l{Getting Started} \li \l{End User Workflows} \list \li \l{Initial Installation} \li \l{Adding Components} \li \l{Removing Components} \li \l{Updating Components} \li \l{Specifying Settings} \li \l{Using From Command Line} \endlist \li \l{Tutorial: Creating an Installer} \li \l{Creating Installers} \list \li \l{Creating Offline Installers} \li \l{Creating Online Installers} \li \l{Promoting Updates} \li \l{Customizing Installers} \endlist \li \l{Qt Installer Framework Examples} \li \l{Reference} \list \li \l{Command Line Interface} \li \l{Configuration File} \li \l{Package Directory} \li \l{Controller Scripting} \li \l{Component Scripting} \li \l{Operations} \li \l{Tools} \li \l{Scripting API} \li \l{C++ API} \endlist \li \l{Known Issues} \endlist */ /*! \contentspage index.html \previouspage ifw-tutorial.html \page ifw-creating-installers.html \nextpage ifw-offline-installers.html \title Creating Installers The following steps are needed to create offline and online installers: \list 1 \li Create a \e {package directory} for the installable components. For more information, see \l{Package Directory}. \li Create a configuration file called \c config.xml in the \c config directory. It contains information about how to build the installer binaries and online repositories. For more information about the file format and available settings, see \l{Configuration File}. \li Create a package information file called \c package.xml in the \c {config\meta} directory. It contains settings for deployment and the installation process. For more information, see \l{Meta Directory}. \li Create installer content and copy it to the package directory. For more information, see \l{Data Directory}. \li For online installers, use the \c repogen tool to create the repository that contains the installable content and upload the repository to a web server. \li Use the \c binarycreator tool to create the installer. For more information, see \l{Tools}. \endlist For an example of how to create a simple installer that uses the predefined installer pages, see \l{Tutorial: Creating an Installer}. The following sections describe how to create different types of installers: \list \li \l{Creating Offline Installers} \li \l{Creating Online Installers} \li \l{Promoting Updates} \li \l{Customizing Installers} \endlist */ /*! \contentspage index.html \previouspage ifw-reference.html \page ifw-cli.html \nextpage ifw-globalconfig.html \title Command Line Interface Installers created with the Qt Installer Framework have the following command line interface syntax: \code installer.exe [options] command <args> <key=value> \endcode Here \c [options] is one or a combination of supported options in either short or long form. In addition some options may require mandatory value(s) that can be passed using the assignment operator or space. The \c command is one of the supported command line installer operations to be run headless in text mode. Some commands may be provided with optional \c <args> separated by space. The \c <key=value> list is used to set internal key-value pairs by the framework. Installer will return an exit code after it is executed. Exit code can be used to determine whether the installation was successful, if the installation has an mandatory update etc. See \c PackagemanagerCore::Status. \section1 Summary of Options Options marked with \c CLI are only available when running in headless mode, the rest of the options can be used also in graphical mode. For the most up-to-date list of available options with a specific version of Qt Installer Framework, refer \c --help option output of \l installerbase. \table \header \li Option \li Usage \row \li -?, -h, --help \li Displays help. \row \li -v, --version \li Displays version information. \row \li -d, --verbose \li Verbose mode. Prints out more information. \row \li -g, --logging-rules <rules> \li Enables logging according to passed rules. Comma separated logging rules have the following syntax: \c{loggingCategory=true/false}. Passing empty logging rules enables all logging categories. The following rules enable a single category: \c{ifw.*=false, ifw.category=true}. The available logging categories can be referenced with --help option. \row \li --ar, --add-repository <URI,...> \li Add a local or remote repository to the list of user defined repositories. \row \li --at, --add-temp-repository <URI,...> \li Add a local or remote repository to the list of temporary available repositories. \row \li --st, --set-temp-repository <URI,...> \li Set a local or remote repository as temporary repository, it is the only one used during fetch. Note: a URI must be prefixed with the protocol, i.e. file:///, https://, http:// or ftp://. \row \li --sp, --system-proxy \li Use system proxy on Windows and Linux. This option has no effect on macOS. (Default) \row \li --np, --no-proxy \li Do not use system proxy. \row \li --su, --start-updater \li Start application in updater mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. \row \li --sm, --start-package-manager \li Start application in package manager mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. \row \li --sr, --start-uninstaller \li Start application in uninstaller mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. \row \li -t, --root <directory> \li [CLI] Set the installation root directory. \row \li -p, --platform <plugin> \li Use the specified platform plugin. \row \li --nf, --no-force-installations \li Allow deselecting components that are marked as forced. \row \li --nd, --no-default-installations \li Deselects components that are marked as default. \row \li --ns, --no-size-checking \li Disable checking of free space for the installation target. \row \li --sv, --show-virtual-components \li Show virtual components in the installer and the package manager. \row \li -i, --install-compressed-repository <URI,...> \li Installs a QBSP or a 7z file. The QBSP (Board Support Package) file must be a .7z file which contains a valid repository. \row \li -c, --create-local-repository \li Create a local repository inside the installation directory. This option has no effect on online installers. \row \li --am, --accept-messages \li [CLI] Accepts all message queries without user input. \row \li --rm, --reject-messages \li [CLI] Rejects all message queries without user input. \row \li --aa, --auto-answer <identifier=value> \li [CLI] Automatically answers the message queries with the message identifier and a button value. Several \c{identifier=value} pairs can be given separated with a comma, for example \c{--auto-answer message.id=Ok,message.id2=Cancel}. \row \li --da, --default-answer \li [CLI] Automatically answers to message queries with their default values. \row \li --al, --accept-licenses \li [CLI] Accepts all licenses without user input. \row \li --file-query <identifier=value> \li [CLI] Automatically sets the QFileDialog values getExistingDirectory() or getOpenFileName() requested by the install script. Several \c{identifier=value} pairs can be given separated with a comma, for example \c{--file-query filedialog.id=C:Temp,filedialog.id2=C:Temp2}. \row \li -c, --confirm-command \li [CLI] Confirms starting of installation, update or removal of components without user input. \row \li -s, --script <file> \li Execute the script given as an argument. \row \li --ss, --start-server <mode, socketname, key> \li Starts the application as headless process waiting for commands to execute. Mode can be DEBUG or PRODUCTION. In the DEBUG mode, the option values can be omitted. Note: The server will not shutdown on its own, you need to quit the process by hand. \row \li --sc, --start-client <socketname, key> \li Starts the application to debug the client-server communication. If a value is omitted, the client will use a default instead. Note: The server process is not started by the client application in that case, you need to start it on your own. \row \li -q, --squish-port <port number> \li Give a port where Squish can connect to. If no port is given, default port 11233 is used. Note: To enable Squish support, you first need to build IFW with SQUISH_PATH parameter where SQUISH_PATH is pointing to your Squish installation folder: \c{<path_to_qt>/bin/qmake -r SQUISH_PATH=<pat_to_squish>}. \endtable \section1 Summary of Commands \table \header \li Command \li Usage \row \li in, install <pkg ...> \li Install packages given as an argument. If no packages are given, install the default package set. \row \li ch, check-updates \li Show information about available updates on the maintenance tool. \row \li up, update <pkg ...> \li Update packages given as an argument. If no packages are given, install all available updates. \row \li rm, remove <pkg ...> \li Uninstall selected packages and their child components. \row \li li, list \li List information about currently installed packages. \row \li se, search <regexp> \li Search available packages. If no search pattern is given, show all available packages. \row \li pr, purge \li Uninstall all packages and remove the program directory. \endtable */ /*! \contentspage index.html \previouspage ifw-cli.html \page ifw-globalconfig.html \nextpage ifw-component-description.html \title Configuration File The configuration file customizes the UI and behavior of an installer. The file is typically called \c config.xml and located in the \c config directory. A minimal configuration file consists of an \c <Installer> root element with \c <Name> and \c <Version> elements as children. All other elements are optional, and can appear in arbitrary order. The following example shows a typical configuration file: \quotefile examples/config.xml \section1 Summary of Configuration File Elements The following table summarizes the elements in the configuration file. \note We recommend that you place all files that you refer to in the configuration file in the \c config directory. However, you can also use relative paths, which the tools resolve relative to the location of the config.xml file. You can use predefined variables (embedded in @ characters) as values of the elements. For more information, see \l{Predefined Variables}. \table \header \li Element \li Description \row \li Name \target ProductNameTarget \li Name of the product being installed. This is mandatory. \row \li Version \li Version of the product being installed in the following format: [0-9]+((\\.|-)[0-9]+)* such as 1-1; 1.2-2; 3.4.7. This is mandatory. \row \li Title \li Name of the installer as displayed on the title bar. \row \li Publisher \li Publisher of the software (as shown in the Windows Control Panel). \row \li ProductUrl \li URL to a page that contains product information on your web site. \row \li Icon \li Filename for a custom installer icon. The actual file is looked up by attaching a '.icns' (macOS), '.ico' (Windows) or '.png' (Unix) suffix. Deprecated, use \c <InstallerApplicationIcon> or \c <InstallerWindowIcon> instead. \row \li InstallerApplicationIcon \li Filename for a custom installer icon. The actual file is looked up by attaching a '.icns' (macOS), '.ico' (Windows). No functionality on Unix. \row \li InstallerWindowIcon \li Filename for a custom window icon in PNG format for the Installer application. \row \li Logo \li Filename for a logo used as \c QWizard::LogoPixmap. \row \li Watermark \li Filename for a watermark used as \c QWizard::WatermarkPixmap. If \c <WizardShowPageList> is set to \c true, the watermark is hidden. \row \li Banner \li Filename for a banner used as \c QWizard::BannerPixmap (only used by ModernStyle). \row \li Background \li Filename for an image used as \c QWizard::BackgroundPixmap (only used by MacStyle). If \c <WizardShowPageList> is set to \c true, the background is hidden. \row \li PageListPixmap \li Filename for an image shown on top of installer page list. The image is shown only if \c <WizardShowPageList> is also set to \c true. \row \li WizardStyle \li Set the wizard style to be used ("Modern", "Mac", "Aero" or "Classic"). \row \li StyleSheet \li Set the stylesheet file. \row \li WizardDefaultWidth \li Sets the default width of the wizard in pixels. Setting a banner image will override this. You can add the \c em or \c ex suffix to the specified value to use the \e em or \e ex unit, as in a CSS file. \row \li WizardDefaultHeight \li Sets the default height of the wizard in pixels. Setting a watermark image will override this. You can add the \c em or \c ex suffix to the specified value to use the \e em or \e ex unit, as in a CSS file. \row \li WizardShowPageList \li Set to \c false if the widget listing installer pages on the left side of the wizard should not be shown. Defaults to \c true. If visible, this widget hides \c QWizard::WatermarkPixmap on \c QWizard::ClassicStyle and \c QWizard::ModernStyle, and \c QWizard::BackgroundPixmap on \c QWizard::MacStyle. \row \li ProductImages \li A list of images to be shown on \c PerformInstallationPage. This element can have one or several \c <Image> child elements that contain a filename for an image. \row \li TitleColor \li Set the color of the titles and subtitles (takes an HTML color code, such as "#88FF33"). \row \li RunProgram \li Command executed after the installer is done if the user accepts the action. Provide the full path to the application. \row \li RunProgramArguments \li Arguments passed to the program specified in \c <RunProgram>. You can add several \c <Argument> child elements that each specify an argument to \c <RunProgram>. \row \li RunProgramDescription \li Text shown next to the check box for running the program after the installation. If \c <RunProgram> is set but no description provided, the UI will display \uicontrol {Run <Name> now.} instead. \row \li StartMenuDir \li Name of the default program group for the product in the Windows \uicontrol Start menu. \row \li TargetDir \li Default target directory for installation. On Linux, this is usually the user's home directory. \row \li AdminTargetDir \li Default target directory for installation with administrator rights. Only available on Linux, where you usually do not want to install in the administrator user's home directory. \row \li RemoteRepositories \li List of remote repositories. This element can contain several \c <Repository> child elements that each contain the \c <Url> child element that specifies the URL to access the repository. For more information, see \l{Configuring Repositories}. \row \li RepositoryCategories \li Name of a category that can contain a list of \c <RemoteRepositories> child elements. For more information, see \l{Configuring Repository Categories}. \row \li MaintenanceToolName \li Filename of the generated maintenance tool. Defaults to \e maintenancetool. The platform-specific executable file extension is appended. \row \li MaintenanceToolIniFile \li Filename for the configuration of the generated maintenance tool. Defaults to \e {MaintenanceToolName}.ini. \row \li RemoveTargetDir \li Set to \c false if the target directory should not be deleted when uninstalling. \row \li AllowNonAsciiCharacters \li Set to \c true if the installation path can contain non-ASCII characters. \row \li DisableAuthorizationFallback \li Set to \c true if the installation should not ask users to run the authorization fallback in case of authorization errors. Instead abort the installation immediately. \row \li DisableCommandLineInterface \li Set to \c true if command line interface features should be disabled. This prevents the user from passing any consumer command to installer, like \c install, \c update and \c remove. Other options can still be used normally. Defaults to \c false. \row \li RepositorySettingsPageVisible \li Set to \c false to hide the repository settings page inside the settings dialog. \row \li AllowSpaceInPath \li Set to \c false if the installation path cannot contain space characters. \row \li DependsOnLocalInstallerBinary \li Set to \c true if you want to prohibit installation from an external resource, such as a network drive. This might make sense for e.g. very big installers. The option is only used on Windows. \row \li TargetConfigurationFile \li Filename for the configuration file on the target. Default is components.xml. \row \li Translations \li List of language codes to be used for translating the user interface. To add several language variants, specify several \c <Translation> child elements that each specify the name of a language variant. Optional. For more information, see \l{Translating Pages}. \row \li UrlQueryString \li This string needs to be in the form "key=value" and will be appended to archive download requests. This can be used to transmit information to the webserver hosting the repository. \row \li ControlScript \li Filename for a custom installer control script. See \l{Controller Scripting}. \row \li CreateLocalRepository \li Set to \c true if you want to create a local repository inside the installation directory. This option has no effect on online installers. The repository will be automatically added to the list of default repositories. \row \li InstallActionColumnVisible \li Set to \c true if you want to add an extra column into component tree showing install actions. This extra column indicates whether a component is going to be installed or uninstalled, or just stay installed or uninstalled. \row \li SupportsModify \li Set to \c false if the product does not support modifying an existing installation. \row \li SaveDefaultRepositories \li Set to \c false if default repositories \c <RemoteRepositories> should not be saved to \e {MaintenanceToolName}.ini. By default default repositories are saved. Not saving the repositories means than when you run \e maintenancetool there are no default repositories in use. \row \li AllowUnstableComponents \li Set to \c true if other components are allowed to be installed although there are unstable components. A component is \e unstable if it is missing a dependency, has errors in scripts, and so on. Unstable components are grayed in the component tree, and therefore cannot be selected. By default, the value is \c false which means that the installation will be aborted if unstable components are found. \endtable */ /*! \contentspage index.html \previouspage ifw-updates.html \page ifw-customizing-installers.html \nextpage Qt Installer Framework Examples \title Customizing Installers You can use scripting to customize installers by: \list \li Adding Qt Installer Framework \e operations that are prepared by the scripts and performed by the installer. \li Adding new pages that you specify in the package.xml file and place in the \c packages directory. \li Modifying existing pages by inserting custom user interface elements into them as single widgets. \li Adding language variants. \endlist You can use both \e {component scripts} and a \e {control script} to customize installers. A component script is associated with a particular component by specifying it in the \c Script element of the package.xml file of the component. The script is loaded when the component's metadata is fetched. For more information about component scripts, see \l{Component Scripting}. A control script is associated with the whole installer by specifying it in the \c ControlScript element of the control.xml file of the installer. Control scripts can be part of the installer resources or be passed on the command line. They can be used to modify the installer pages that are presented to users before components are loaded. Also, you can use them to modify pages in the uninstaller. For more information, see \l{Controller Scripting}. For more information about the global JavaScript objects that can be used in component and control scripts, see \l{Scripting API}. \section1 Adding Operations You can use component scripts to perform Qt Installer Framework operations during the installation process. Typically, operations manipulate files by moving, copying, or patching them. Use the QInstaller::Component::addOperation or QInstaller::Component::addElevatedOperation function to add operations. For more information, see \l {Adding Operations to Components}. In addition, you can implement methods to register custom installation operations in the installer by deriving KDUpdater::UpdateOperation. For more information, see \l {Registering Custom Operations}. For a summary of available operations, see \l {Operations}. \section1 Adding Pages A component can contain one or more user interface files, which are placed into the installer by a component or control script. The installer automatically loads all user interface files listed in the \c UserInterfaces element of the package.xml file. \section2 Using Component Scripts to Add Pages To add a new page to the installer, use the installer::addWizardPage() method and specify the location of the new page. For example, the following code adds an instance of \c MyPage before the ready for installation page: \code installer.addWizardPage( component, "MyPage", QInstaller.ReadyForInstallation ); \endcode You can use component scripts to access the loaded widgets by calling the \l component::userInterface() method with the class name of the widget, as illustrated by the following code snippet: \code component.userInterface( "MyPage" ).checkbox.checked = true; \endcode You can also have a callback for the page that is added. To access it, use the object name set in the UI file (for example, \c "MyPage"). Then create the \c{Dynamic${ObjectName}Callback} function (for example, \c {DynamicMyPageCallback}): \code Component.prototype.DynamicMyPageCallback = function() { var page = gui.pageWidgetByObjectName("DynamicMyPage"); page.myButton.click, page.myWidget.subWidget.setText("hello") } \endcode You can access widgets by using their object names that are set in the UI file. For example, \c myButton and \c myWidget are widget object names in the code above. \section1 Adding Widgets You can use component or control scripts to insert custom user interface elements into the installer as single widgets (such as a check box). To insert a single widget, use the installer::addWizardPageItem method. For example, the following code snippet adds an instance of \c MyWidget to the component selection page from within a script: \code installer.addWizardPageItem( component, "MyWidget", QInstaller.ComponentSelection ); \endcode \section1 Interacting with Installer Functionality You can use control scripts to execute installer functions automatically in tests, for example. The following snippet illustrates how to automatically click the \uicontrol Next button on the target directory selection page: \code Controller.prototype.TargetDirectoryPageCallback = function() { gui.clickButton(buttons.NextButton); } \endcode \section1 Translating Pages The installer uses the Qt Translation system to support the translation of user-readable output to several languages. To provide end users with localized versions of strings contained in the component scripts and user interfaces, create QTranslator files that the installation system loads along with the component. The installer loads the translation file that matches the current system locale. For example, if the system locale is German, the de.qm file is loaded. In addition, a localized \c license_de.txt is shown instead of the default \c license.txt if it is found. Translations need to be added to the \c package.xml file to be activated for a component: \code <Translations> <Translation>de.qm</Translation> </Translations> \endcode Use the \c {qsTr()} function for literal text within scripts. Additionally, you can add the \c Component.prototype.retranslateUi method to the script. It is called when the language of the installer changes and the translation file is loaded. The context being used for translation is the basename of the script file when using \c qsTr or the class name of the UI file when translating a user interface. For example, if the script file is called \c installscript.qs, the context will be installscript. \note The translation system can also be used to customize the UI. Use e.g. an \c en.ts file to replace any text in the installer with a custom English version. */ /*! \contentspage index.html \previouspage ifw-globalconfig.html \page ifw-component-description.html \nextpage noninteractive.html \title Package Directory Installers contain components that are either embedded to the installer or loaded from a remote repository. In both cases, you need to use a file format and structure for the components that the installer can read. \section1 Package Directory Structure Place all components in the same root directory, which is called the \e {package directory}. The directory name acts as a domain-like identifier, which identifies all components. For example, \c com.vendor.root. Within the root directory, create subdirectories called \c data and \c meta. A package directory can look as follows: \code -packages - com.vendor.root - data - meta - com.vendor.root.component1 - data - meta - com.vendor.root.component1.subcomponent1 - data - meta - com.vendor.root.component2 - data - meta \endcode \section1 Meta Directory The \c meta directory contains files that specify settings for deployment and the installation process. The files are not extracted by the installer. The directory must contain at least a package information file and all files that you refer to in the package information file, such as scripts, user interface files, and translations. \section2 Package Information File Syntax The package.xml file is the main source of information about a component. The following is an example of a package file: \quotefile examples/package.xml \section2 Summary of Package Information File Elements \table \header \li Element \li Description \row \li DisplayName \li Human-readable name of the component. Required. Specify translations for the name of the component as values of additional DisplayName tags, with the xml:lang attribute set to the correct locale. \row \li Description \li Human-readable description of the component. Required. Translations may be specified similarly to DisplayName tag. If a localization that matches the locale is not found and an untranslated version exists, that one will be used. Otherwise no Description will be shown for that locale. User clickable external links, for example a component's homepage, can be included in component description by specifying a URL address like this: {external-link}='https://www.qt.io/'. The URL must be valid and contain a full path to the desired resource. \row \li Version \li Version number of the component in the following format: [0-9]+((\\.|-)[0-9]+)* such as 1-1; 1.2-2; 3.4.7. Required. If a package needs to show the version number from a child rather than it's own (due to grouping of child packages) one can specify the attribute inheritVersionFrom with the package name the version needs to be inherited from. \row \li ReleaseDate \li Date when this component version was released. Required. \row \li Name \li Domain-like identification for this component. Required. \row \li Dependencies \li Comma-separated list of identifiers of components that this component depends on. Optionally, you can specify version numbers, separated by a dash (-). You can prefix version numbers with a comparison operator (=, >, <, >= or <=). Keep in mind that you have to use the character reference "<" to escape the left angle bracket (use "<" instead of "<" and "<=" instead of "<="). Optional. For more information, see \l{Component Dependencies}. \row \li AutoDependOn \li Comma-separated list of identifiers of components that this component has an automatic dependency on. The component is installed if and only if all of the specified dependencies are fulfilled. If a component has an automatic dependency on other components, the check box will not be visible next to the component in the component tree. The selection will be performed automatically. If the component was not installed before, it will be selected for installation only when all components from this list are also selected for installation. If the component was already installed, it will be selected for uninstallation when at least one of the components from this list is also selected for uninstallation. For more information, see \l{Component Dependencies}. \row \li Virtual \li Set to \c true to hide the component from the installer. Note that setting this on a root component does not work. \row \li SortingPriority \li Priority of the component in the tree. The tree is sorted from highest to lowest priority, with the highest priority on the top. \row \li Licenses \li List of license agreements to be accepted by the installing user. To add several licenses, add several \c <License> child elements that each specify the license \c name and \c file. ASCII and UTF8 file formats are supported for license files. If there are translations listed for this component, the installer will also look for translated licenses. These need to have the same name as the original license file but with an added locale identifier. If for example the license file is called license.txt and there is German translation specified, the installer will also include a license_de_de.txt file (and show that when installing on a German system). \row \li Script \li File name of a script being loaded. Optional. For more information, see \l{Adding Operations}. \row \li UserInterfaces \li List of pages to load. To add several pages, add several \c <UserInterface> child elements that each specify the filename of a page. Optional. For more information, see \l{Adding Pages}. \row \li Translations \li List of translation files to load. To add several language variants, specify several \c <Translation> child elements that each specify the filename of a language variant. Optional. For more information, see \l{Translating Pages}. \row \li UpdateText \li Description added to the component description if this is an update to the component. Optional. \row \li Default \li Possible values are: \c true, \c false, and \c script. Set to \c true to preselect the component in the installer. This takes effect only on components that have no visible child components. The boolean values are evaluated directly, while \c script is resolved during runtime. Add the name of the script as a value of the \c <Script> element in this file. For an example script, see \l{Selecting Default Contents}. \row \li Essential \li Marks the package as essential to force a restart of the \c MaintenanceTool. If there are updates available for an essential component, the package manager stays disabled until that component is updated. Newly introduced essential components are automatically installed when running the updater. \row \li ForcedInstallation \li Determines that the package must always be installed. End users cannot deselect it in the installer. \row \li Replaces \li Comma-separated list of components to replace. Optional. \row \li DownloadableArchives \li Lists the data files (separated by commas) for an online installer to download. If there is some data inside the component and the package.xml and/or the script has no DownloadableArchives value, the repogen tool registers the found data automatically. \row \li RequiresAdminRights \li Set to \c true if the package needs to be installed with elevated permissions. Optional. \row \li Checkable \li Set to \c false if you want to hide the checkbox for an item. This is useful when only a few subcomponents should be selected instead of all. Optional. \row \li ExpandedByDefault \li Set to \c true if you want this item to be expanded by default. Optional. \endtable \section2 Component Dependencies Components can depend on one or several real or virtual components. Dependencies are defined by using the component identifier and, optionally, component version. Use a dash (-) to separate version numbers from identifiers. You can prefix version numbers with a comparison operator (=, >, < (<), >= or <= (<=)) to indicate that the version number of the package is compared to the required version and has to be equal to, greater than, less than, greater than or equal to, or less than or equal to the version number specified in the dependency. If no comparison operator is given, it defaults to =. \section1 Data Directory The \c data directory contains the content that the installer extracts during the installation. You must package the data as a 7zip archive (.7z). You can use either the \l archivegen tool that is delivered with the Qt Installer Framework or some other tool that generates 7zip archives. */ /*! \contentspage index.html \previouspage operations.html \page ifw-tools.html \nextpage Scripting API \title Tools The Qt Installer Framework contains the following tools: \list \li \l installerbase \li \l binarycreator \li \l repogen \li \l archivegen \li \l devtool \endlist \section1 installerbase The \c installerbase tool describes the core installer itself. All data and meta information will be packed to this binary. For the installer creation process you will not need to call it directly. \section1 binarycreator Use the \c binarycreator tool to create offline and online installers. Component information and data are appended to the offline installer binary, which enables the file extraction and post installation scripts to work without an Internet connection. Online installers store the location of the repository that contains the data. On startup, they load the component information, not the data. You can also create hybrid installers that store some components locally and receive others via a network connection. For more information, see \l {Reducing Installer Size}. For information about how to implement data integration into the installer binary, see QInstaller::BinaryContent. \note If you change this configuration, you must recompile the \c installerbase tool. \section2 Using binarycreator You can use the \c binarycreator tool to create offline and online installers. Some options have default values, and therefore, you can omit them. To create an offline installer (in Windows), enter the following command: \list \li On Windows: \code <location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> <installer_name> \endcode \li On Linux and macOS \code <location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> <installer_name> \endcode \endlist To create an online only installer, you can use the --online-only which defines all packages to install from an online repository on a web server: \list \li On Windows: \code <location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> -e <packages> <installer_name> \endcode \li On Linux and macOS \code <location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> -e <packages> <installer_name> \endcode \endlist \section2 Summary of binarycreator Parameters The \c binarycreator tool accepts the following parameters: \table \header \li Parameter \li Use \row \li -t or --template file \li Use \c file as an installer template binary to which the component information is appended. If you omit this parameter, the \c installerbase template is used. \row \li -p or --packages directory \li Use \c directory as the \l{Package Directory Structure} {package directory}. Defaults to the current working directory. \row \li --repository directory \li Use \c directory as the repository directory with packages to repack. This entry can be given multiple times. \row \li -n or --online-only \li Compile without any component in the installer binary. \row \li -f or --offline-only \li Create an offline installer that never accesses online repositories. \row \li -c or --config file \li Use \c file as the \l{Configuration File} {config file}. \row \li -e or --exclude p1,...,pn \li Comma-separated list of packages to retrieve from an online repository. The packages are not included in the installer binary. \row \li -i or --include p1,...,pn \li Comma-separated list of packages to retrieve from the installer binary. You cannot combine or merge \c {--include} and \c {--exclude}. \row \li -r or --resources \li Comma-separated list of resources to include in the installer binary. \row \li --ignore-translations \li Disable the use of translation files to make testing faster. \row \li --ignore-invalid-packages \li Ignore component or package directories that do not have valid metadata information (package.xml) to make testing faster. \row \li --ignore-invalid-repositories \li Ignore repository directories that do not have valid metadata information (Updates.xml) instead of aborting. \row \li -v or --verbose \li Display debug output. \row \li -s or --sign identity \li Only available on macOS. Allows specifying a code signing identity to be used for signing the generated app bundle. \endtable These parameters are followed by the name of the target binary and a list of packages to be available for installation. \note The listed packages are included in the installer, as well as all their dependencies and all packages that share the same prefix, unless you specify the \c --nodeps parameter. In the optional resource files specified via the \c --resources parameter, a special \c fonts/ path can be used to ship custom fonts. These fonts will be loaded automatically and thus become available in a stylesheet which can be specified via the \c StyleSheet variable. On Windows, the name of the target binary is automatically extended with .exe, if you do not specify the extension. On Mac, the target is created as an application bundle with the extension .app, which is automatically added, if not supplied. Additionally, you can specify the .dmg extension, which creates a DMG disk image that contains an .app bundle. \section2 Using Icons On macOS, if the target binary is suffixed with .app, a macOS application bundle is created. The icon that you specify in config.xml is extended with .icns and used as the icon for the created bundle. On Windows, the icon that you specify in config.xml is extended with .ico and used as the application icon for the .exe file. On Linux, the icon that you specify in config.xml is extended with .png and used as the window icon. \section1 repogen Use the \c repogen tool to generate online repositories. The \c repogen tool expects the following parameters in the following order: \code repogen.exe -p <package_directory> <repository_directory> \endcode When the repository has been created, you can upload it anywhere. You must specify the location in the installer configuration file when creating an installer for it. You can use an existing repository to repack packages to another repository or offline installer. \section2 Summary of repogen Parameters \table \header \li Parameter \li Use \row \li -p or --packages directory \li Use \c directory as the \l{Package Directory Structure} {package directory}. This is mandatory. \row \li --repository directory \li Use \c directory as the repository directory with packages to repack (not to confuse with the mandatory target repository directory). This entry can be given multiple times. \row \li repository directory \li Target directory for the repository. During an initial installation, the directory must not yet exist. When updating, the directory may exist and its contents may be overwritten or removed. This is mandatory. \row \li -e or --exclude p1,...,pn \li Comma-separated list of packages to be ignored from the set of all packages in the packages directory. \row \li -i or --include p1,...,pn \li Comma-separated list of packages to be used from the set of all packages in the packages directory. \row \li --update \li Update all packages in the packages directory. The list can be further filtered with the \c {-i}, \c {-e} parameters. \row \li --update-new-components \li Update only components that are new or have a newer version. The list can be further filtered with the \c {-i}, \c{-e} parameters. \row \li -r or --remove \li Force removal of existing target directory before generating it again. \row \li -v or --verbose \li Display debug output. \endtable \note We recommend that you use the \c {--update-new-packages} parameter to update an existing repository, especially if you have a content delivery system. This helps you avoid updating components that have not changed and this makes it much easier for a content delivery system to distribute only new files, because only the updated components are assigned new SHA checksums. \section1 archivegen You can use \c archivegen to package files and directories into 7zip (.7z) archives. The \c archivegen tool expects the following parameters in the following order: \code archivegen <name.7z> <data> \endcode Where \e <name.7z> is the path and file name of the archive to create and \e <data> contains the paths and names of the files or directories to package into the archive, separated by spaces. \section1 devtool You can use \c devtool to update an existing installer or maintenance tool with a new installer base, to dump binary content from an installer or maintenance tool to a target, and to execute operations. For a summary of available operations, see \l {Operations}. \c devtool expects the following parameters in the following order: \code devtool [options] binary \endcode Where \e binary is the path and name of an existing installer or maintenance tool. \section2 Summary of devtool Parameters \table \header \li Parameter \li Use \row \li -?, -h, --help \li Display help. \row \li -v, --version \li Display version information. \row \li --verbose \li Display additional information. \row \li update <binary> <installerbase> \li Update an existing installer or maintenance tool with a new installer base. \row \li dump <binary> <folder> \li Dump the binary content that belongs to an installer or maintenance tool into the target. \row \li operation <mode,name,args,...> \li Execute an operation with a list of arguments. \c mode can be \c DO or \c UNDO, depending on whether the step contains instructions for the installer or uninstaller. \endtable */ /*! \contentspage index.html \previouspage ifw-offline-installers.html \page ifw-online-installers.html \nextpage ifw-updates.html \title Creating Online Installers Online installers fetch the repository description (Updates.xml), in addition to the one stored inside of the binary. Create a repository and upload it to a web server. Then specify the location of the repository in the config.xml file that you use to create the installer. \section1 Creating Repositories Use the \c repogen tool to create online repositories of all packages of one package directory: repogen.exe -p <package_directory> <repository_directory> For example, to create a repository that contains only org.qt-project.sdk.qt and org.qt-project.sdk.qtcreator, enter the following command: \code repogen.exe -p packages -i org.qt-project.sdk.qt,org.qt-project.sdk.qtcreator repository \endcode When the repository has been created, upload it to a web server. You must specify the location of the repository in the installer configuration file. \section1 Configuring Repositories The \c <RemoteRepositories> element in the installer configuration file (config.xml) can contain a list of several repositories. Each of them can have the following settings: \list \li \c <Url>, which points to a list of available components. \li \c <Enabled>, with 0 disabling this repository. \li \c <Username>, which is used as user on a protected repository. \li \c <Password>, which sets the password to use on a protected repository. \li \c <DisplayName>, which optionally sets a string to display instead of the URL. \endlist The URL needs to point to the Updates.xml file that lists the available components. For example: \code <RemoteRepositories> <Repository> <Url>http://www.example.com/packages</Url> <Enabled>1</Enabled> <Username>user</Username> <Password>password</Password> <DisplayName>Example repository</DisplayName> </Repository> </RemoteRepositories> \endcode The installer works only if it can access the repository. If the repository is accessed after the installation, the maintenance tool rejects installation. However, uninstallation is still possible. A repository can be enabled or disabled by default. For repositories requiring authentication, the details can also be set here, although entering a password here is usually not advisable as it is saved in plain text. Authentication details not set here will be gotten at runtime using a dialog. The user can work around these settings at runtime. \section1 Configuring Repository Categories The \c <RepositoryCategory> element in the installer configuration file (config.xml) can contain a list of several \c <RemoteRepositories> elements. Each \c <RemoteRepositories> element within the \c <RepositoryCagetory> element is considered a category. Each catecory can have a \c <DisplayName>, a \c <Tooltip>, a \c <Preselected> element and several \c <Repository> elements. Repository categories are shown in the component selection page, on the left side of the component selection widget: \image ifw-repository-categories.png "Component selection Page" By default, only repositories with no category are shown in the component selection widget. Checking one or several repositories and pressing \uicontrol Fetch will update the widget to show content also from the selected categorized repositories. Components in the repository categories are marked as \e unstable meaning that you can install other components although some components have missing dependencies, script errors and so on. For more information about \e unstable components, see \l {Summary of Configuration File Elements}. Example of creating a repository category: \code <RepositoryCategories> <RemoteRepositories> <Displayname>Category 1</Displayname> <Preselected>true</Preselected> <Tooltip>Tooltip for category 1</Tooltip> <Repository> <Url>http://www.example.com/packages</Url> <Enabled>1</Enabled> <Username>user</Username> <Password>password</Password> <DisplayName>Example repository</DisplayName> </Repository> </RemoteRepositories> </RepositoryCategories> \endcode \section1 Creating Installer Binaries To create an online installer by using the \c binarycreator tool, enter the following command: \code <location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> -e <packages> <installer_name> \endcode For example, enter the following command to create an installer binary called SDKInstaller.exe that will not contain data for org.qt-project.sdk.qt and org.qt-project.qtcreator, because those packages are downloaded from a remote repository: \code binarycreator.exe -p installer-packages -c installer-config\config.xml -e org.qt-project.sdk.qt,org.qt-project.qtcreator SDKInstaller.exe \endcode \section1 Reducing Installer Size Even if the components are fetched from a web server, \c binarycreator adds them to the installer binary by default. However, when the installer checks the web server for updates, end users are spared a download if new versions are not available. Alternatively, you can create online installers that do not contain any data and that fetch all the data from the web server. Use the \c{-n} parameter of the \c binarycreator tool and only add the root component to the installer. Usually the root component is empty and hence only adds the XML description of the root. For more information about the options that you have, see \l{Summary of binarycreator Parameters}. */ /*! \contentspage index.html \previouspage ifw-creating-installers.html \page ifw-offline-installers.html \nextpage ifw-online-installers.html \title Creating Offline Installers Offline installers do not try to connect to an online repository at all during installation. However, the metadata configuration (config.xml) enables users to add and update components online. Offline installers are especially useful in cases where a corporate firewall does not allow end users to connect to web servers. The network administrator can set up a local update service within the network. To create offline installers, use the \c{--offline-only} option of the \c binarycreator tool. To create an offline installer in Windows, enter the following command: \code <location-of-ifw>\binarycreator.exe --offline-only -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> <installer_name> \endcode Some options have default values, and therefore, you can omit them. For example, enter the following command to create an installer binary called SDKInstaller.exe that contains the packages identified by org.qt-project.sdk and their dependencies: \code binarycreator.exe --offline-only -c installer-config -p installer-packes SDKInstaller.exe \endcode */ /*! \contentspage index.html \previouspage ifw-online-installers.html \page ifw-updates.html \nextpage ifw-customizing-installers.html \title Promoting Updates Create online installers to be able to promote updates to end users who install your product. The following steps are needed to promote updates: \list 1 \li Copy the updated content to the package directory. \li Increase the value of the \c <Version> element for the updated components in the package.xml file. \li Use the \c repogen tool to recreate the online repository with the updated contents and to generate the Updates.xml file in the root directory of the repository. \li Upload the repository to the web server. \li Use the \c binarycreator tool to create the installer. \endlist \section1 Configuring Updates The installer downloads the Updates.xml file on startup and compares the installed version with the version in the file. If the online version number in the file is greater than the local one, the installer displays it in the list of available updates. Increase the value of the \c <Version> element for the component in the package.xml file. \section1 Recreating Repositories The easiest way to provide an update is to recreate the repository and upload it to the web server. For more information, see \l{Creating Repositories}. \section1 Partially Updating Repositories A full update of the whole repository might not be optimal if: \list \li The repository is very large, as uploading would take a long time. \li You want to deliver only the changed components. \endlist \note repogen recreates the 7zip archives each time it is being called. As 7zip stores the timestamps of the included files (which are moved or copied during this process), the SHA sum of each archive changes. SHA sums are used to verify the download of the archive and hence the SHA needs to match the 7zip. As the SHAs are stored in the Updates.xml file you will be forced to upload the full repository. This can be circumvented by using the \c{--update} option of repogen. \section2 Creating Partial Updates When recreating the online repository, use the \c{--update} parameter. It takes an existing repository as input and only changes the components that are specified as additional parameters. Only those SHA sums are changed in the global configuration as well. \section2 Uploading Partial Updates Upload the following items to the web server: \list \li The component directory (usually something like \c{com.vendor.product.updatedpart}). \li The global \c{Updates.xml} stored in the root directory of the online repository. \endlist \note The order of uploading items is very important. If you update the repository on a live server, first update the component and then Updates.xml. The package names include version numbers, and therefore, end users receive old packages until the new ones are fully uploaded. \section1 Changing Repositories To have the current update repository point to other repositories, edit the Updates.xml file in the current repository. You can add, replace, or remove repositories. \code <RepositoryUpdate> <Repository action="..." OPTIONS /> <Repository action="..." OPTIONS /> </RepositoryUpdate> \endcode \section2 Adding Repositories To update a repository, add a \c <Repository> child element to the \c <RepositoryUpdate> element with the following options: \code <Repository action="add" url="http://www.example.com/repository" name="user" password="password" displayname="Example Repository" /> \endcode \c{url} will be used as a base URL to resolve an \c{Updates.xml} file against. If \c{url} is itself relative, it will be resolved against the base URL of the current document. \c{displayname} specifies how the repository should be named in the \gui Settings page of the Maintenance Tool. \c{name} and \c{password} optionally specify credentials for a protected repository. \section2 Removing Repositories To remove a repository, add a \c <Repository> child element to the \c <RepositoryUpdate> element with the following options: \code <Repository action="remove" url="http://www.example.com/repository" /> \endcode \c{url} must match exactly the URL that is to be removed. \section2 Replacing Repositories To replace one repository with another, add a \c <Repository> child element to the \c <RepositoryUpdate> element with the following options: \code <Repository action="replace" oldUrl="http://www.example.com/repository" newUrl="http://www.example.com/newrepository" name="user" password="password" displayname="New Example Repository" /> \endcode \c{oldUrl} must match exactly the URL that is to be replaced. \c{newUrl} must match exactly the URL that it is replaced with. \section1 Relocatable Repositories Some projects contain multiple repositories. To create a relocatable set of repositories you should use relative paths. So if the generic repository available at the address \c{http://www.example.com/repositories/generic} and \c{Updates.xml} contains \c <Repository> element with the following options: \code <Repository action="add" url="../module" name="user" password="password" displayname="Module Repository" /> \endcode Then the resolved address of the added repository will be \c{http://www.example.com/repositories/module}, so that the repository does not contain information about their absolute location. If you want to change the address, you can simply copy a set of repositories as is. It is recommended to maintain the old generic repository for some time and replace the addresses as described above. You can also provide the updated installer with the new generic address. You can use relative paths for the arguments \c url, \c oldUrl, and \c newUrl in the \c <Repository> element. */ /*! \contentspage index.html \previouspage ifw-cpp-classes.html \page ifw-knownissues.html \nextpage index.html \title Known Issues Check the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker} for known issues in the Qt Installer Framework project. If you cannot find the issue there, create a bug report. */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/messageboxhandler.qdoc���������������������������������������������0100777�0000000�0000000�00000007215�13761647206�020215� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype QMessageBox \inqmlmodule scripting \brief Provides a modal dialog for informing the user or asking the user a question and receiving an answer. \code var result = QMessageBox.question("quit.question", "Installer", "Do you want to quit the installer?", QMessageBox.Yes | QMessageBox.No); if (result == QMessageBox.Yes) { // ... } \endcode \section2 Buttons in Message Boxes QMessageBox defines a list of common buttons: \list \li QMessageBox.Ok \li QMessageBox.Open \li QMessageBox.Save \li QMessageBox.Cancel \li QMessageBox.Close \li QMessageBox.Discard \li QMessageBox.Apply \li QMessageBox.Reset \li QMessageBox.RestoreDefaults \li QMessageBox.Help \li QMessageBox.SaveAll \li QMessageBox.Yes \li QMessageBox.YesToAll \li QMessageBox.No \li QMessageBox.NoToAll \li QMessageBox.Abort \li QMessageBox.Retry \li QMessageBox.Ignore \li QMessageBox.NoButton \endlist \section2 Scripted Installations Sometimes it is useful to automatically close message boxes, for example during a scripted installation. This can be achieved by calling installer::setMessageBoxAutomaticAnswer, installer::autoAcceptMessageBoxes or installer::autoRejectMessageBoxes. The \c identifier argument in the method calls allows to identify specific message boxes for this purpose. */ /*! \qmlmethod Button QMessageBox::critical(string identifier, string title, string text, Buttons buttons = QMessageBox.Ok, Button button = QMessageBox.NoButton) Opens a critical message box with the given \a title and \a text. */ /*! \qmlmethod Button QMessageBox::information(string identifier, string title, string text, Buttons buttons = QMessageBox.Ok, Button button = QMessageBox.NoButton) Opens an information message box with the given \a title and \a text. */ /*! \qmlmethod Button QMessageBox::question(string identifier, string title, string text, Buttons buttons = QMessageBox.Yes | QMessageBox.No, Button button = QMessageBox.NoButton) Opens a question message box with the given \a title and \a text. */ /*! \qmlmethod Button QMessageBox::warning(string identifier, string title, string text, Buttons buttons = QMessageBox.Ok, Button button = QMessageBox.NoButton) Opens a warning message box with the given \a title and \a text. */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/noninteractive.qdoc������������������������������������������������0100777�0000000�0000000�00000044747�13761647206�017565� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage{index.html}{Qt Installer Framework} \previouspage ifw-component-description.html \page noninteractive.html \nextpage scripting.html \title Controller Scripting For each installer, you can specify a control script that interacts with certain parts of the installer's UI or functionality. The control script can add and remove pages to the wizard, change existing pages, do additional checks, and interact with the UI by simulating user clicks. This allows for example unattended installations. The script format has to be compatible with QJSEngine. This section describes the functions that are called to implement such a control script. It also gives an overview of installer pages and the widgets that are available on each page, such as push buttons, radio buttons, and line edits. \section1 Writing Control Scripts A minimal valid script needs to contain at least a constructor, which can look like this: \code function Controller() { } \endcode The following example presents a more advanced script that uses the \l gui JavaScript global object methods to set a new page title and welcome message on the introduction page and to automatically click the \uicontrol Next button on the target directory page: \code function Controller() { } Controller.prototype.IntroductionPageCallback = function() { var widget = gui.currentPageWidget(); // get the current wizard page if (widget != null) { widget.title = "New title."; // set the page title widget.MessageLabel.setText("New Message."); // set the welcome text } } Controller.prototype.TargetDirectoryPageCallback = function() { gui.clickButton(buttons.NextButton); // automatically click the Next button } \endcode For more information about the JavaScript global objects that you can use in control scripts, see \l{Scripting API}. \section1 Predefined Installer Pages The QInstaller JavaScript object provides access to the following predefined installer pages: \list \li \c Introduction \li \c TargetDirectory \li \c ComponentSelection \li \c LicenseCheck \li \c StartMenuSelection \li \c ReadyForInstallation \li \c PerformInstallation \li \c InstallationFinished \endlist The \l buttons JavaScript object provides a set of buttons that can be used on installer pages. The following sections describe the functions that you can implement to interact with installer pages and the widgets that are available on each page. \section2 Introduction Page Implement the \c Controller.prototype.IntroductionPageCallback() function to interact with widgets on the introduction page. Wizard buttons: \list \li \c NextButton \li \c CancelButton \endlist \table \header \li Widgets \li Brief Description \row \li \c ErrorLabel \li Displays an error message. \row \li \c MessageLabel \li Displays a message. By default, it displays the "Welcome to the \l{ProductNameTarget}{<Name>} Setup Wizard" message. \row \li \c InformationLabel \li Displays progress information. \endtable \table \header \li Radio Buttons \li Brief Description \row \li \c PackageManagerRadioButton \li The package manager radio button shown on the page while running as maintenance tool. \row \li \c UpdaterRadioButton \li The updater radio button shown on the page while running as maintenance tool. \row \li \c UninstallerRadioButton \li The uninstaller radio button shown on the page while running as maintenance tool. Selected by default. \endtable \table \header \li Progress Bar \li Brief Description \row \li \c InformationProgressBar \li The progress bar shown while fetching remote packages. \endtable \table \header \li Qt Core Feature \li Brief Description \row \li \c packageManagerCoreTypeChanged() \li Connect to this signal if you want to be notified when the type of maintenance tool changes. \note The signal is only emitted when the user has started the binary as so called maintenance tool (after the installation) and switches between the radio buttons. \endtable Example code: \code function Controller() { var widget = gui.pageById(QInstaller.Introduction); // get the introduction wizard page if (widget != null) widget.packageManagerCoreTypeChanged.connect(onPackageManagerCoreTypeChanged); } onPackageManagerCoreTypeChanged = function() { console.log("Is Updater: " + installer.isUpdater()); console.log("Is Uninstaller: " + installer.isUninstaller()); console.log("Is Package Manager: " + installer.isPackageManager()); } \endcode \section2 License Agreement Page Implement the \c Controller.prototype.LicenseAgreementPageCallback() function to interact with widgets on the license agreement page. Wizard buttons: \list \li \c NextButton \li \c CancelButton \li \c BackButton \endlist \table \header \li Widgets \li Brief Description \row \li \c LicenseListWidget \li Lists the available licenses. \row \li \c LicenseTextBrowser \li Shows the content of the selected license file. \row \li \c AcceptLicenseLabel \li Shows the text next to the accept license radio button. \row \li \c RejectLicenseLabel \li Shows the text next to the reject license radio button. \endtable \table \header \li Radio Buttons \li Brief Description \row \li \c AcceptLicenseRadioButton \li Accepts the license agreement. \row \li \c RejectLicenseRadioButton \li Rejects the license agreement. Selected by default. \endtable \section2 Target Directory Page Implement the \c Controller.prototype.TargetDirectoryPageCallback() function to interact with widgets on the target directory selection page. Wizard buttons: \list \li \c NextButton \li \c CancelButton \li \c BackButton \endlist \table \header \li Widgets \li Brief Description \row \li \c MessageLabel \li Displays a message. \row \li \c TargetDirectoryLineEdit \li Displays the value of the installation's target directory. \row \li \c WarningLabel \li Displays a warning. \endtable \section2 Component Selection Page Implement the \c Controller.prototype.ComponentSelectionPageCallback() function to interact with widgets on the component selection page. Wizard buttons: \list \li \c NextButton \li \c CancelButton \li \c BackButton \endlist \table \header \li Methods \li Brief Description \row \li \c selectAll() \li Selects all available packages if possible. \row \li \c deselectAll() \li Deselects all available packages if possible. \row \li \c selectDefault() \li Resets the checked state of available packages to their initial state. \row \li \c selectComponent(id) \li Selects the package with \c id (string). \row \li \c deselectComponent(id) \li Deselects the package with \c id (string). \endtable \table \header \li Push Buttons \li Brief Description \row \li \c SelectAllComponentsButton \li Selects all available packages if possible. \row \li \c DeselectAllComponentsButton \li Deselects all available packages if possible. \row \li \c SelectDefaultComponentsButton \li Resets the checked state of available packages to their initial state. \row \li \c ResetComponentsButton \li Resets to already installed components. \row \li \c FetchCategoryButton \li Fetch components from a category. \endtable \table \header \li Widgets \li Brief Description \row \li \c CategoryGroupBox \li Contains checkboxes for selecting repository categories. \endtable Installer Framework 3.1 introduces repository categories as a new feature. When you use an installer that contains repository categories, you can select a category by its display name, fetch its contents, and then select the included components for installation. You can fetch the components from a category as follows: \code Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName("ComponentSelectionPage"); // if CategoryGroupBox is visible, check one of the checkboxes // and click fetch button before selecting any components var groupBox = gui.findChild(page, "CategoryGroupBox"); if (groupBox) { console.log("groupBox found"); // findChild second argument is the display name of the checkbox var checkBox = gui.findChild(page, "Archive"); if (checkBox) { console.log("checkBox found"); console.log("checkBox name: " + checkBox.text); if (checkBox.checked == false) { checkBox.click(); var fetchButton = gui.findChild(page, "FetchCategoryButton"); if (fetchButton) { console.log("fetchButton found"); fetchButton.click(); } else { console.log("fetchButton NOT found"); } } } else { console.log("checkBox NOT found"); } } else { console.log("groupBox NOT found"); } // you can now select components from the fetched category } \endcode \section2 Start Menu Directory Page Implement the \c Controller.prototype.StartMenuDirectoryPageCallback() function to interact with widgets on the ready for installation page. Wizard buttons: \list \li \c NextButton \li \c CancelButton \li \c BackButton \endlist \table \header \li Widgets \li Brief Description \row \li \c StartMenuPathLineEdit \li Shows the directory where to create the program's shortcut. \endtable \section2 Ready for Installation Page Implement the \c Controller.prototype.ReadyForInstallationPageCallback() function to interact with widgets on the ready for installation page. Wizard buttons: \list \li \c CommitButton \li \c CancelButton \li \c BackButton \endlist \table \header \li Widgets \li Brief Description \row \li \c MessageLabel \li Displays a message. \row \li \c TaskDetailsBrowser \li Displays some more detailed information about the installation. \endtable \section2 Perform Installation Page Implement the \c Controller.prototype.PerformInstallationPageCallback() function to interact with widgets on the perform installation page. Wizard buttons: \list \li \c CommitButton \li \c CancelButton \endlist \section2 Finished Page Implement the \c Controller.prototype.FinishedPageCallback() function to interact with widgets on the installation finished page. Wizard buttons: \list \li \c CommitButton \li \c CancelButton \li \c FinishButton \endlist \table \header \li Widgets \li Brief Description \row \li \c MessageLabel \li Displays a message. \row \li \c RunItCheckBox \li Text field that informs users that they can start an application after the installation process has finished. \endtable \section1 Custom Pages Custom pages are registered as \c{Dynamic${ObjectName}}, where \c{${ObjectName}} is the object name set in the UI file. Thus, the \c{Dynamic${ObjectName}Callback()} function is called. Widgets can be addressed using their object names (from the UI file). Example code: \code function Component() { // add page with widget \c SomePageWidget before the target directory page installer.addWizardPage(component, "SomePageWidget", QInstaller.TargetDirectory) } Component.prototype.DynamicSomePageWidgetCallback = function() { var page = gui.pageWidgetByObjectName("DynamicSomePageWidget"); page.myButton.click, //direct child of the UI file's widget page.someFancyWidget.subWidget.setText("foobar") // nested widget } \endcode \section1 Message Boxes While executing the installer application, for example, the application might show some message boxes about an error that occurred. This is fine while running the application on the end user's system, but it might break automated test suites. To overcome this issue, all message boxes shown by the Qt Installer Framework are addressable by a specific identifier. \table \header \li Identifier \li Possible Answers \li Description \row \li \c OverwriteTargetDirectory \li Yes, No \li Confirmation for using an already existing directory as the target directory for installation. \row \li \c installationError \li OK, Retry, Ignore \li A fatal error occurred while performing the installation. \row \li \c installationErrorWithRetry \li Retry, Ignore, Cancel \li An error occurred while performing the installation. End users can select \uicontrol Retry to try again. \row \li \c AuthorizationError \li Abort, OK \li Elevated permissions could not be acquired. \row \li \c OperationDoesNotExistError \li Abort, Ignore \li An error occurred while trying to perform an operation, but the operation did not exist. \row \li \c isAutoDependOnError \li OK \li An error occurred while calling a package script. It was not possible to evaluate if the package has a auto dependency on other packages. \row \li \c isDefaultError \li OK \li An error occurred while calling a package script. It was not possible to evaluate if the package will be installed by default. \row \li \c DownloadError \li Retry, Cancel \li An error occurred while downloading an archive hash from a remote repository. End users can select \uicontrol Retry to try again. \row \li \c archiveDownloadError \li Retry, Cancel \li An error occurred while downloading a archive from a remote repository. End users can select \uicontrol Retry to try again. \row \li \c WriteError \li OK \li An error occurred while writing the maintenance tool. \row \li \c ElevationError \li OK \li Elevated permissions could not be acquired. \row \li \c unknown \li OK \li An unknown error occurred while removing a certain package. \row \li \c Error \li OK \li Generic error. \row \li \c stopProcessesForUpdates \li Retry, Ignore, Cancel \li An error occurred while updating a package. Some running application or process needs to be quit before the update can be performed. End users can select \uicontrol Retry to try again once they have been stopped. \row \li \c Installer_Needs_To_Be_Local_Error \li OK \li The installer binary was started from a network location, but the installation over network is not supported. \row \li \c TargetDirectoryInUse \li No \li The installation's target directory already contains an installation. \row \li \c WrongTargetDirectory \li OK \li The installation's target directory is a file or symlink. \row \li \c AlreadyRunning \li OK \li Another application instance is already running. \endtable Example code: \code function Controller() { installer.autoRejectMessageBoxes; installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes); installer.setMessageBoxAutomaticAnswer("stopProcessesForUpdates", QMessageBox.Ignore); } \endcode */ �������������������������qt-installer-framework-4.0.1/doc/operations.qdoc����������������������������������������������������0100777�0000000�0000000�00000030721�13761647206�016703� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage{index.html}{Qt Installer Framework} \previouspage scripting.html \page operations.html \nextpage ifw-tools.html \title Operations The operations are prepared by component and controller scripts and performed by the installer. \note Operations are performed threaded. Internally, each operation has a \e DO step that contains instructions for the installer and an \e UNDO step that contains instructions for the uninstaller. \section1 Summary of Operations The following table summarizes the available operations and their syntax. \table \header \li Operation \li Syntax \li Use \row \li Copy \li "Copy" \c source \c target \li Copies a file from \c source to \c target. \row \li Move \li "Move" \c source \c target \li Moves a file from \c source to \c target. \row \li SimpleMoveFile \li "SimpleMoveFile" \c source \c target \li Moves a file from \c source to \c target. \row \li Delete \li "Delete" \c filename \li Deletes the file specified by \c filename. \row \li Mkdir \li "Mkdir" \c path \li Creates the directory path \c path. \row \li Rmdir \li "Rmdir" \c path \li Removes the directory path \c path. \row \li CopyDirectory \li "CopyDirectory" \c sourcePath \c targetPath \li Copies a directory from \c sourcePath to \c targetPath. \row \li AppendFile \li "AppendFile" \c filename \c text \li Appends \c text to the file specified by \c filename. \c text is treated as ASCII text. \row \li PrependFile \li "PrependFile" \c filename \c text \li Prepends \c text to the file specified by \c filename. \c text is treated as ASCII text. \row \li Replace \li "Replace" \c file \c search \c replace \c mode \li Opens \c file to find \c search string and replaces that with the \c replace string, using \c mode that can be either \c string or \c regex. For regular expressions containing capturing groups, occurrences of \c \1, \c \2, ..., in \c replace are replaced with the string captured by the corresponding capturing group. Note that testing the operation using \c devtool does not support commas inside the \c search pattern as they are used as argument separators. When using \c regex mode you should also ensure the \c search pattern adheres to \c QRegularExpression class documentation, particularly to the escaping rules for characters. \row \li LineReplace \li "LineReplace" \c file \c search \c replace \li Opens \c file to find lines that start with \c search string and replaces that with the \c replace string. Lines are trimmed before the search. \row \li Execute \li "Execute" [{\c exitcodes}] \c command [\c parameter1 [\c parameter... [\c parameter10]]] \li Executes the command specified by \c command. Up to 10 parameters can be passed. If that is not enough, you can use a JavaScript string array. Optionally, you can pass a comma-separated list of exit codes within curly brackets ({}) as the first argument to specify the exit codes for successful execution. This defaults to "{0}". Other optional named arguments are: "workingdirectory=<your_working_dir>"; "errormessage=<your_custom_errormessage>" In addition, a special argument, UNDOEXECUTE, separates the DO step of the operation from the UNDO step. Example: \c{component.addOperation("Execute", "touch", "test.txt", "UNDOEXECUTE", "rm", "test.txt")} \row \li CreateShortcut \li "CreateShortcut" \c filename \c linkname [\c arguments] \li Creates a shortcut from the file specified by \c filename to \c linkname. On Windows, this creates a .lnk file which can have \c arguments. Furthermore, \c filename can be an HTTP or FTP URL in which case a URL shortcut is created. The operation is currently not implemented on other platforms. \row \li CreateDesktopEntry \li "CreateDesktopEntry" \c {filename "key=value[ key2=value2[ key3=value3]]]"} \li Creates a .desktop initialization file, as specified by freedesktop.org. This operation is useful only on X11 or Wayland based Linux distributions. If \c filename is absolute, the desktop entry is stored there. Otherwise, it is stored in the location specified in \c{$XDG_DATA_HOME/applications}, including the default path, as defined by freedesktop.org. The key-value pairs are written to the file. The file is set to use UTF-8 encoding. \row \li InstallIcons \li "InstallIcons" \c directory \c [Vendorprefix] \li Installs the contents of \c directory into a location, as specified by freedesktop.org. That is, into \c {$XDG_DATA_HOME/icons} or \c {$HOME/.local/share/icons}. The files are removed from their initial location. Make sure to add this operation after the operation that extracts the files from the archive. If you provide a \c Vendorprefix it replaces all characters up to the first dash (-) in the filename of the icon with this prefix. \row \li Extract \li "Extract" \c archive \c targetdirectory \li Extracts \c archive to \c targetdirectory. \row \li GlobalConfig \li "GlobalConfig" \c company \c application \c key \c value or "GlobalConfig" \c scope \c company \c application \c key \c value or "GlobalConfig" \c filename \c key \c value \li Stores \c value for \c key in a configuration file. The configuration file is specified either by \c filename (using \c QSettings::NativeFormat, which might be the Windows registry) or by \c application and \c company name. Set \c scope to "SystemScope" to create an entry in the system scope. \note The operation is using QSettings to store the key value pair. QSettings always treats backslash as a special character and provides no API for reading or writing such entries. Do not use slashes ('/' and '\\') in section or key names; the backslash character is used to separate sub keys. On windows, '\\' are converted by QSettings to '/', which makes them identical. Because the backslash character is used by QSettings to separate sub keys, you cannot read or write windows registry entries that contain slashes or backslashes. You should use a native windows API if you need to do so. \row \li EnvironmentVariable \li "EnvironmentVariable" \c key \c value [\c persistent [\c system]] \li Sets the environment variable \c key to \c value. If \c persistent is set to \c true, the variable is set persistently. This is currently only supported on Windows. If \c system is set to \c true, the persistent variable is set system-wide, not only for the current user. Note, if you set path to environment variable, use '\\' as separator, for example: @Targetdir@\\lib\\system. \row \li RegisterFileType \li "RegisterFileType" \c extension \c command [\c description [\c contentType [\c icon]]]. \li Registers the file type with \c extension to be opened via \c command. Optionally, you can specify \c description, \c contentType, and \c icon. This is currently only supported on Windows. \row \li ConsumeOutput \li "ConsumeOutput" \c installerKeyName \c executablePath \c processArguments \li Saves the output from running the executable located at \c executablePath with the arguments \c processArguments to the installer key specified by \c installerKeyName. Additional arguments can be passed. \row \li CreateLink \li "CreateLink" \c linkPath \c targetPath \li Creates a link in the location specified by \c linkPath that points to the location specified by \c targetPath. \row \li CreateLocalRepository \li "CreateLocalRepository" \c binaryPath \c repoPath \li Creates a local repository in the directory specified by \c repoPath. For offline installers, stores binary data in the directory specified by \c binaryPath. \row \li FakeStopProcessForUpdate \li "FakeStopProcessForUpdate" \c processlist \li Matches running processes against the comma-separated entries in \c processlist during uninstallation. If matches are found, shows a messagebox asking the user to stop those processes before continuing. \row \li License \li "License" \c licenses \li Copies the license files specified by \c licenses to a subfolder called \c Licenses in the target directory. This operation is automatically added for packages declaring \c <Licenses> in their package description file. \row \li MinimumProgress \li "MinimumProgress" \li Increases the progress value by one. \row \li SelfRestart \li "SelfRestart" \c core \li Restarts the updater or package manager specified by \c core. \row \li Settings \li "Settings" \c path \c method \c key \c value \li Sets or removes the \c value of \c key in the settings file located at \c path, depending on the value of \c method: \c set, \c remove, \c add_array_value, and \c remove_array_value. \endtable The Extract, License, and MinimumProgress operations are automatically added for matching components that do not overwrite the component::createOperations() method. See also component::autoCreateOperations. If errors occur, you can test operations manually using the \c devtool. However, variables are not resolved, so you need to use absolute values. For example, to test copying a file: \code devtool operation <binary> DO,Copy,<source>,<target> \endcode */ �����������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/�����������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�016416� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/buttons.qdoc�����������������������������������������0100777�0000000�0000000�00000004575�13761647206�020777� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype buttons \inqmlmodule scripting \brief Provides buttons that can be used on installer pages. You can use a set of standard buttons and some custom buttons on the installer pages. For more information about the buttons used by default on each installer page, see \l {Controller Scripting}. */ /*! \qmlproperty enumeration buttons::QWizard Specifies the buttons on an installer page. \value buttons.BackButton The \uicontrol Back button (\uicontrol {Go Back} on macOS.) \value buttons.NextButton The \uicontrol Next button (\uicontrol Continue on macOS.) \value buttons.CommitButton The \uicontrol Commit button. \value buttons.FinishButton The \uicontrol Finish button (\uicontrol Done on macOS.) \value buttons.CancelButton The \uicontrol Cancel button. \value buttons.HelpButton The \uicontrol Help button. \value buttons.CustomButton1 A custom button. \value buttons.CustomButton2 A custom button. \value buttons.CustomButton3 A custom button. \sa {Controller Scripting} */ �����������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/component.qdoc���������������������������������������0100777�0000000�0000000�00000032006�13761647206�021271� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype component \inqmlmodule scripting \brief Represents the current component that the Qt Script belongs to. A minimal valid script needs to contain a constructor, which can look like this: \code function Component() { // Access the global component's name property and log it to the debug console. console.log("component: " + component.displayName); } \endcode The \c Component class and the script engine both modify the script before it is evaluated. When the modifications are applied to the above snippet, the script changes to: \code (function() { [1] var component = installer.componentByName('Component.Name.This.Script.Belongs.To'); [2] function Component() { // Access the global component's name property and log it to the debug console. console.log("component: " + component.displayName); } if (typeof Component != undefined) [1] return new Component; [1] else [1] throw "Missing Component constructor. Please check your script." [1] })(); [1] Changes done by the script engine. [2] Changes done by the Component class. \endcode \note The \e component (in lower case) is the global variable the C++ \c Component class introduced. The \e component variable represents the C++ \c Component object that the script belongs to. The \e Component (in upper case) is a JavaScript object that gets instantiated by the script engine. */ /*! \qmlproperty string component::name Returns the name of the component as set in the \c <Name> tag of the package information file. */ /*! \qmlproperty string component::displayName Returns the name of the component as shown in the user interface. */ /*! \qmlproperty boolean component::autoCreateOperations Specifies whether some standard operations for the component should be automatically created when the installation starts. The default is \c true. */ /*! \qmlproperty stringlist component::archives Returns the list of archive URL's (prefixed with \c installer://) registered for the component. \sa addDownloadableArchive, removeDownloadableArchive */ /*! \qmlproperty stringlist component::dependencies This read-only property contains components this component depends on. */ /*! \qmlproperty stringlist component::autoDependencies Returns the value of the \c <AutoDependOn> tag in the package information file. */ /*! \qmlproperty boolean component::fromOnlineRepository Returns whether this component has been loaded from an online repository. \sa isFromOnlineRepository */ /*! \qmlproperty url component::repositoryUrl Returns the repository URL the component is downloaded from. When this component is not downloaded from an online repository, returns an empty #QUrl. */ /*! \qmlproperty boolean component::default This read-only property indicates if the component is a default one. \note Always \c false for virtual components. \sa isDefault */ /*! \qmlproperty boolean component::installed This read-only property returns if the component is installed. \sa isInstalled */ /*! \qmlproperty boolean component::enabled Indicates whether the component is currently enabled. The property is both readable and writable. */ /*! \qmlsignal component::loaded() Emitted when the component has been loaded. */ /*! \qmlsignal component::valueChanged(string key, string value) Emitted when the value of the variable with the name \a key changes to \a value. \sa setValue */ /*! \qmlsignal component::virtualStateChanged() Emitted when the virtual state of the component changes. */ /*! \qmlmethod string component::value(string key, string value = "") Returns the value of variable name \a key. If \a key is not known yet, \a defaultValue is returned. \note If a component is virtual and you ask for the component value with the key "Default", it will always return \c false. */ /*! \qmlmethod void component::setValue(string key, string value) Sets the value of the variable with \a key to \a value. */ /*! \qmlproperty stringlist component::userInterfaces Returns a list of all user interface class names known to this component. */ /*! \qmlmethod QWidget component::userInterface(string name) Returns the QWidget created for \a name or \c 0 if the widget has been deleted or cannot be found. */ /*! \qmlmethod void component::createOperationsForPath(string path) Creates all operations needed to install this component's \a path. \a path is a full qualified filename including the component's name. This method gets called from createOperationsForArchive. You can override it by providing a method with the same name in the component script. \note RSA signature files are omitted by this method. \note If you call this method from a script, it will not call the script's method with the same name. The default implementation is recursively creating Copy and Mkdir operations for all files and folders within \a path. */ /*! \qmlmethod void component::createOperationsForArchive(string archive) Creates all operations needed to install this component's \a archive. This method gets called from createOperations. You can override this method by providing a method with the same name in the component script. \note If you call this method from a script, it will not call the script's method with the same name. The default implementation calls createOperationsForPath for everything contained in the archive. If \a archive is a compressed archive known to the installer system, an Extract operation is created, instead. */ /*! \qmlmethod void component::beginInstallation() Starts the component installation. You can override this method by providing a method with the same name in the component script. \code Component.prototype.beginInstallation = function() { // call default implementation component.beginInstallation(); // ... } \endcode */ /*! \qmlmethod void component::createOperations() Creates all operations needed to install this component. You can override this method by providing a method with the same name in the component script: \code Component.prototype.createOperations = function() { // call default implementation component.createOperations(); // ... add custom operations } \endcode The default implementation calls createOperationsForArchive for all archives in this component. \sa component::addOperation() */ /*! \qmlmethod void component::registerPathForUninstallation(string path, boolean wipe = false) Registers the file or directory at \a path for being removed when this component gets uninstalled. In case of a directory, this will be recursive. If \a wipe is set to \c true, the directory will also be deleted if it contains changes done by the user after installation. */ /*! \qmlmethod void component::addDownloadableArchive(string path) Adds the archive \a path to this component. This can only be called when this component was downloaded from an online repository. When adding \a path, it will be downloaded from the repository when the installation starts. \sa removeDownloadableArchive, fromOnlineRepository, archives */ /*! \qmlmethod void component::removeDownloadableArchive(string path) Removes the archive \a path previously added via addDownloadableArchive from this component. This can only be called when this component was downloaded from an online repository. \sa addDownloadableArchive, fromOnlineRepository, archives */ /*! \qmlmethod void component::addStopProcessForUpdateRequest(string process) Adds a request for quitting the process \a process before installing, updating, or uninstalling the component. */ /*! \qmlmethod void component::removeStopProcessForUpdateRequest(string process) Removes the request for quitting the process \a process again. */ /*! \qmlmethod void component::setStopProcessForUpdateRequest(string process, boolean requested) A convenience method for adding or removing the request for stopping \a process depending on whether \a requested is \c true (add) or \c false (remove). */ /*! \qmlmethod boolean component::addOperation(string operation, stringlist parameters) Creates and adds an installation operation for \a operation. Add any number of parameters. The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained. The method is typically called from within \l component::createOperations(). */ /*! \qmlmethod boolean component::addOperation(string operation, string parameter1 = "", string parameter2 = "", ..., string parameter10 = "") Convenience method for calling addOperation(string, stringlist) with up to 10 arguments. */ /*! \qmlmethod boolean component::addElevatedOperation(string operation, string parameter1 = "", string parameter2 = "", ..., string parameter10 = "") Convenience method for calling addElevatedOperation(string, stringlist) with up to 10 arguments. */ /*! \qmlmethod boolean component::addElevatedOperation(string operation, stringlist parameters) Creates and adds an installation operation for \a operation. Add any number of parameters. The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained. \a operation is executed with elevated rights. */ /*! \qmlmethod void component::setAutoCreateOperations(boolean autoCreateOperations) Setter for the \l autoCreateOperations property. */ /*! \qmlmethod void component::addDependency(string newDependency) Adds a new component \a newDependency to the list of dependencies. \sa dependencies */ /*! \qmlmethod void component::addAutoDependOn(string newDependOn) Adds the component specified by \a newDependOn to the automatic depend-on list. \sa autoDependencies */ /*! \qmlmethod void component::setInstalled() Set's the components state to installed. */ /*! \qmlmethod boolean component::isAutoDependOn(QSet<string> componentsToInstall) Determines whether the component comes as an auto dependency. Returns \c true if the component needs to be installed. */ /*! \qmlmethod boolean component::isDefault() Indicates if the component is a default one. \note Always returns \c false for virtual components. \sa default */ /*! \qmlmethod boolean component::isInstalled() Determines whether the component is installed. */ /*! \qmlmethod boolean component::installationRequested() Determines whether the user wants to install the component. */ /*! \qmlmethod void component::setUpdateAvailable(boolean isUpdateAvailable) Sets a flag that the core found an update. */ /*! \qmlmethod boolean component::updateRequested() Determines whether the user wants to install the update for this component. */ /*! \qmlmethod boolean component::componentChangeRequested() Returns \c true if this component will be changed (update, installation, or uninstallation). */ /*! \qmlmethod void component::setUninstalled() Sets the component state to uninstalled. */ /*! \qmlmethod boolean component::isUninstalled() Determines whether the component is uninstalled. */ /*! \qmlmethod boolean component::uninstallationRequested() Determines whether the user wants to uninstall the component. */ /*! \qmlmethod boolean component::isFromOnlineRepository() Determines whether this component has been loaded from an online repository. \sa addDownloadableArchive, fromOnlineRepository */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/console.qdoc�����������������������������������������0100777�0000000�0000000�00000004323�13761647206�020732� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype console \inqmlmodule scripting \brief Provides methods for logging and debugging. \keyword console-object You can use the \c console object to print log information about installer functions to the console. The following example uses the \c console object \l{console::log()}{log} method and \l installer object \l{installer::isUpdater()}, \l{installer::isUninstaller()}, and \l{installer::isPackageManager()} methods to display a message that indicates whether the maintenance tool is currently being used to update, remove, or add components. \code onPackageManagerCoreTypeChanged = function() { console.log("Is Updater: " + installer.isUpdater()); console.log("Is Uninstaller: " + installer.isUninstaller()); console.log("Is Package Manager: " + installer.isPackageManager()); } \endcode */ /*! \qmlmethod void console::log(string value) Prints the string specified by \a value to the console. */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/gui.qdoc���������������������������������������������0100777�0000000�0000000�00000011416�13761647206�020055� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype gui \inqmlmodule scripting \brief Enables interaction with the installer UI. */ /*! \qmlsignal gui::interrupted() This signal is emitted when the end user chooses to cancel the installation and quit the installer. */ /*! \qmlsignal gui::languageChanged() This signal is emitted when the application language changes. */ /*! \qmlsignal gui::finishButtonClicked() This signal is emitted when the \uicontrol Finish button is clicked. */ /*! \qmlsignal gui::gotRestarted() This signal is emitted when the installer is restarted. */ /*! \qmlsignal gui::settingsButtonClicked() This signal is emitted when the \uicontrol Settings button is clicked. */ /*! \qmlmethod object gui::pageById(int id) Returns the installer page specified by \a id. The values of \c id for the available installer pages are provided by QInstaller::WizardPage. */ /*! \qmlmethod object gui::pageByObjectName(string name) Returns the installer page specified by \a name. The value of \c name is the object name set in the UI file that defines the installer page. */ /*! \qmlmethod object gui::currentPageWidget() Returns the current wizard page. */ /*! \qmlmethod object gui::pageWidgetByObjectName(string name) For dynamic pages, returns the widget specified by \a name read from the UI file. */ /*! \qmlmethod string gui::defaultButtonText(int wizardButton) Returns the default text for the button specified by \a wizardButton. */ /*! \qmlmethod void gui::clickButton(int wizardButton, int delayInMs) Automatically clicks the button specified by \a wizardButton after a delay in milliseconds specified by \a delayInMs. */ /*! \qmlmethod void gui::clickButton(string objectName, int delayInMs) Automatically clicks the button specified by \a objectName after a delay in milliseconds specified by \a delayInMs. */ /*! \qmlmethod boolean gui::isButtonEnabled(int wizardButton) Returns \c true if the button specified by \a wizardButton is enabled. Returns \c false if a button of the specified type is not found. */ /*! \qmlmethod void gui::showSettingsButton(boolean show) Shows the \uicontrol Settings button if \a show is \c true. */ /*! \qmlmethod void gui::setSettingsButtonEnabled(boolean enable) Enables the \uicontrol Settings button by setting \a enable to \c true. */ /*! \qmlmethod object gui::findChild(object parent, string objectName) Returns the first descendant of \a parent that has \a objectName as name. \sa QObject::findChild */ /*! \qmlmethod object[] gui::findChildren(object parent, string objectName) Returns all descendants of \a parent that have \a objectName as name. \sa QObject::findChildren */ /*! \qmlmethod void gui::cancelButtonClicked() Asks end users whether they want to cancel the operation and quit the installer, uninstaller, or package manager. */ /*! \qmlmethod void gui::reject() Quits the installer, uninstaller, or package manager. */ /*! \qmlmethod void gui::rejectWithoutPrompt() Quits the installer, uninstaller, or package manager without asking end users for confirmation. */ /*! \qmlmethod void gui::showFinishedPage() Shows the InstallationFinished page. */ /*! \qmlmethod void gui::setModified(boolean value) */ /*! \qmlmethod void gui::setTextItems(object control, stringlist items) Updates the model of \a control (which must be a QComboBox or QAbstractItemView) such that it contains the given \a items. */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/packagemanagercore.qdoc������������������������������0100777�0000000�0000000�00000057127�13761647206�023101� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype installer \inqmlmodule scripting \brief Provides access to core functionality of the Qt Installer Framework. */ /*! \qmlmethod array installer::components() Returns an array of all components currently available. If the repository metadata have not been fetched yet, the array will be empty. \sa component, finishAllComponentsReset(), finishUpdaterComponentsReset() */ /*! \qmlsignal installer::aboutCalculateComponentsToInstall() Emitted before the ordered list of components to install is calculated. */ /*! \qmlsignal installer::finishedCalculateComponentsToInstall() Emitted after the ordered list of components to install was calculated. */ /*! \qmlsignal installer::aboutCalculateComponentsToUninstall() Emitted before the ordered list of components to uninstall is calculated. */ /*! \qmlsignal installer::finishedCalculateComponentsToUninstall() Emitted after the ordered list of components to uninstall was calculated. */ /*! \qmlsignal installer::componentAdded(Component component) Emitted when a new root component is added. \sa rootComponentsAdded(), updaterComponentsAdded() */ /*! \qmlsignal installer::rootComponentsAdded(list<Component> components) Emitted when a new list of root components is added. \sa componentAdded(), updaterComponentsAdded() */ /*! \qmlsignal installer::updaterComponentsAdded(list<Component> components) Emitted when a new list of updater components is added. \sa componentAdded(), rootComponentsAdded() */ /*! \qmlsignal installer::valueChanged(string key, string value) Emitted when a value changes. \sa setValue() */ /*! \qmlsignal installer::statusChanged(Status status) Emitted when the installer status changes. */ /*! \qmlsignal installer::currentPageChanged(int page) Emitted when the current page changes. */ /*! \qmlsignal installer::finishButtonClicked() Emitted when the user clicks the \uicontrol Finish button of the installer. */ /*! \qmlsignal installer::metaJobProgress(int progress) Triggered with progress updates of the communication with a remote repository. Progress ranges from 0 to 100. */ /*! \qmlsignal installer::metaJobTotalProgress(int progress) Triggered when total progress value of the communication with a remote repository changes. */ /*! \qmlsignal installer::metaJobInfoMessage(string message) Triggered with informative updates of the communication with a remote repository. */ /*! \qmlsignal installer::startAllComponentsReset() Triggered when the list of components starts to get updated. \sa finishAllComponentsReset() */ /*! \qmlsignal installer::finishAllComponentsReset(list<Component> rootComponents) Triggered when the list of new root components has been updated. \sa startAllComponentsReset() */ /*! \qmlsignal installer::startUpdaterComponentsReset() Triggered when components start to get updated during a remote update. */ /*! \qmlsignal installer::finishUpdaterComponentsReset(list<Component> componentsWithUpdates) Triggered when the list of available remote updates has been updated. */ /*! \qmlsignal installer::installationStarted() Triggered when installation has started. \sa installationFinished(), installationInterrupted() */ /*! \qmlsignal installer::installationInterrupted() Triggered when installation has been interrupted (cancelled). \sa interrupt(), installationStarted(), installationFinished() */ /*! \qmlsignal installer::installationFinished() Triggered when installation has finished. \sa installationStarted(), installationInterrupted() */ /*! \qmlsignal installer::updateFinished() Triggered when an update has finished. */ /*! \qmlsignal installer::uninstallationStarted() Triggered when uninstallation has started. \sa uninstallationFinished() */ /*! \qmlsignal installer::uninstallationFinished() Triggered when uninstallation has finished. \sa uninstallationStarted() */ /*! \qmlsignal installer::titleMessageChanged(string title) Emitted when the text of the installer status (on the PerformInstallation page) changes to \a title. */ /*! \qmlsignal installer::wizardPageInsertionRequested(Widget widget, WizardPage page) Emitted when a custom \a widget is about to be inserted into \a page by addWizardPage. */ /*! \qmlsignal installer::wizardPageRemovalRequested(Widget widget) Emitted when a \a widget is removed by removeWizardPage. */ /*! \qmlsignal installer::wizardWidgetInsertionRequested(Widget widget, WizardPage page, int position) Emitted when a \a widget is inserted into \a page by addWizardPageItem ordered by \a position. */ /*! \qmlsignal installer::wizardWidgetRemovalRequested(Widget widget) Emitted when a \a widget is removed by removeWizardPageItem. */ /*! \qmlsignal installer::wizardPageVisibilityChangeRequested(bool visible, int page) Emitted when the visibility of the page with id \a page changes to \a visible. \sa setDefaultPageVisible() */ /*! \qmlsignal installer::setValidatorForCustomPageRequested(Component component, string name, string callbackName) Triggered when setValidatorForCustomPage is called. */ /*! \qmlsignal installer::setAutomatedPageSwitchEnabled(bool request) Triggered when the automatic switching from PerformInstallation to InstallationFinished page is enabled (\a request = \c true) or disabled (\a request = \c false). The automatic switching is disabled automatically when for example the user expands or unexpands the \gui Details section of the PerformInstallation page. */ /*! \qmlsignal installer::coreNetworkSettingsChanged() Emitted when the network settings are changed. */ /*! \qmlmethod void installer::selectComponent(string id) Selects the component with \a id. */ /*! \qmlmethod void installer::deselectComponent(string id) Deselects the component with \a id. */ /*! \qmlmethod void installer::setCompleteUninstallation(bool complete) Sets the uninstallation to be \a complete. If \a complete is false, only components deselected by the user will be uninstalled. This option applies only on uninstallation. */ /*! \qmlmethod void installer::cancelMetaInfoJob() Cancels the retrieval of meta information from a remote repository. */ /*! \qmlmethod void installer::componentsToInstallNeedsRecalculation() Ensures that component dependencies are re-calculated. */ /*! \qmlmethod void installer::clearComponentsToInstallCalculated() Forces a recalculation of components to install. */ /*! \qmlmethod void installer::autoAcceptMessageBoxes() Automatically accept all user message boxes. \sa autoRejectMessageBoxes(), setMessageBoxAutomaticAnswer() */ /*! \qmlmethod void installer::autoRejectMessageBoxes() Automatically reject all user message boxes. \sa autoAcceptMessageBoxes(), setMessageBoxAutomaticAnswer() */ /*! \qmlmethod void installer::setMessageBoxAutomaticAnswer(string identifier, int button) Automatically close the message box with ID \a identifier as if the user had pressed \a button. This can be used for unattended (automatic) installations. \sa QMessageBox, autoAcceptMessageBoxes(), autoRejectMessageBoxes() */ /*! \qmlmethod void installer::setAutoAcceptLicenses() Automatically accepts all license agreements required to install the selected components. This can be used to skip the command line license acceptance query. The names of the accepted individual licenses are still printed to a console. */ /*! \qmlmethod void installer::setFileDialogAutomaticAnswer(string identifier, string value) Automatically sets the existing directory or filename \a value to QFileDialog with the ID \a identifier. \sa removeFileDialogAutomaticAnswer() */ /*! \qmlmethod void installer::removeFileDialogAutomaticAnswer(string identifier) Removes the automatic answer from QFileDialog with the ID \a identifier. \sa setFileDialogAutomaticAnswer() */ /*! \qmlmethod boolean installer::containsFileDialogAutomaticAnswer(string identifier) Returns \c true if QFileDialog with the ID \a identifier has an automatic answer set. \sa setFileDialogAutomaticAnswer(), removeFileDialogAutomaticAnswer() */ /*! \qmlmethod float installer::requiredDiskSpace() Returns the additional estimated amount of disk space in bytes required after installation. \sa requiredTemporaryDiskSpace() */ /*! \qmlmethod float installer::requiredTemporaryDiskSpace() Returns the estimated required disk space during installation in bytes. \sa requiredDiskSpace() */ /*! \qmlmethod boolean installer::isFileExtensionRegistered(string extension) Returns whether a file extension is already registered in the Windows registry. Returns \c false on all other platforms. */ /*! \qmlmethod string installer::readFile(string filePath, string codecName) Returns the contents of the file \a filePath using the encoding specified by \a codecName. The file is read in the text mode, that is, end-of-line terminators are translated to the local encoding. \note If the file does not exist or an error occurs while reading the file, an empty string is returned. */ /*! \qmlmethod string installer::readConsoleLine(string title, int maxlen) Prints \a title to a console and reads console input. Function halts the installer and waits for user input. Function returns a line which user has typed into the console. The maximum allowed line length is set to \a maxlen. If the stream contains lines longer than this, then the line is split after \a maxlen characters. If \a maxlen is 0, the line can be of any length. \note This function can only be called when installing from a command line instance without GUI. */ /*! \qmlmethod boolean installer::fileExists(string filePath) Returns \c true if the \a filePath exists; otherwise returns \c false. \note If the file is a symlink that points to a non existing file, \c false is returned. */ /*! \qmlmethod boolean installer::addWizardPage(Component component, string name, int page) Adds the widget with objectName() \a name registered by \a component as a new page into the installer's GUI wizard. The widget is added before \a page. See \l{Controller Scripting} for the possible values of \a page. Returns \c true if the operation succeeded. \sa removeWizardPage(), setDefaultPageVisible() */ /*! \qmlmethod boolean installer::removeWizardPage(Component component, string name) Removes the widget with objectName() \a name previously added to the installer's wizard by \a component. Returns \c true if the operation succeeded. \sa addWizardPage(), setDefaultPageVisible(), wizardPageRemovalRequested() */ /*! \qmlmethod boolean installer::setDefaultPageVisible(int page, boolean visible) Sets the visibility of the default page with the ID \a page to \a visible. That is, removes it from or adds it to the wizard. This works only for pages that were in the installer when it was started. Returns \c true. \sa addWizardPage(), removeWizardPage() */ /*! \qmlmethod void installer::setValidatorForCustomPage(Component component, string name, string callbackName) \sa setValidatorForCustomPageRequested() */ /*! \qmlmethod boolean installer::addWizardPageItem(Component component, string name, int page, int position) Adds the widget with objectName() \a name registered by \a component as a GUI element into the installer's GUI wizard. The widget is added on \a page ordered by \a position. If several widgets are added to the same page, the widget with lower position number will be inserted on top. See \l{Controller Scripting} for the possible values of \a page. \sa removeWizardPageItem(), wizardWidgetInsertionRequested() */ /*! \qmlmethod boolean installer::removeWizardPageItem(Component component, string name) Removes the widget with objectName() \a name previously added to the installer's wizard by \a component. \sa addWizardPageItem() */ /*! \qmlmethod void installer::addUserRepositories(stringlist repositories) Registers additional \a repositories. \sa setTemporaryRepositories() */ /*! \qmlmethod void installer::setTemporaryRepositories(stringlist repositories, boolean replace) Sets additional \a repositories for this instance of the installer or updater. Will be removed after invoking it again. \sa addUserRepositories() */ /*! \qmlmethod boolean installer::calculateComponentsToInstall() Calculates an ordered list of components to install based on the current run mode. Also auto installed dependencies are resolved. The aboutCalculateComponentsToInstall() signal is emitted before the calculation starts, the finishedCalculateComponentsToInstall() signal once all calculations are done. */ /*! \qmlmethod boolean installer::calculateComponentsToUninstall() Calculates a list of components to uninstall based on the current run mode. Auto installed dependencies are not yet resolved. The aboutCalculateComponentsToUninstall() signal is emitted before the calculation starts, the finishedCalculateComponentsToUninstall() signal once all calculations are done. Always returns \c true. */ /*! \qmlmethod boolean installer::gainAdminRights() Tries to gain admin rights. On success, it returns \c true. \sa dropAdminRights() */ /*! \qmlmethod void installer::dropAdminRights() Drops admin rights gained by gainAdminRights. \sa gainAdminRights() */ /*! \qmlmethod boolean installer::isProcessRunning(string name) Returns \c true if a process with \a name is running. On Windows, the comparison is case-insensitive. */ /*! \qmlmethod boolean installer::killProcess(string absoluteFilePath) Returns \c true if a process with \a absoluteFilePath could be killed or is not running. \note This is implemented in a semi blocking way (to keep the main thread to paint the UI). */ /*! \qmlmethod void installer::setAllowedRunningProcesses(stringlist processes) Sets additional \a processes that can run when updating with the maintenance tool. */ /*! \qmlmethod stringlist installer::allowedRunningProcesses() Returns processes that are allowed to run when updating with the maintenance tool. */ /*! \qmlmethod void installer::setDependsOnLocalInstallerBinary() Makes sure the installer runs from a local drive. Otherwise the user will get an appropriate error message. \note This only works on Windows. \sa localInstallerBinaryUsed() */ /*! \qmlmethod boolean installer::localInstallerBinaryUsed() Returns \c false if the installer is run on Windows, and the installer has been started from a remote file system drive. Otherwise returns \c true. \sa setDependsOnLocalInstallerBinary() */ /*! \qmlmethod array installer::execute(string program, stringlist arguments = undefined, string stdin = "", string stdinCodec = "latin1", string stdoutCodec = "latin1") Starts the program \a program with the arguments \a arguments in a new process and waits for it to finish. \a stdin is sent as standard input to the application. \a stdInCodec is the name of the codec to use for converting the input string into bytes to write to the standard input of the application. \a stdOutCodec is the name of the codec to use for converting data written by the application to standard output into a string. Returns an empty array if the program could not be executed, otherwise the output of command as the first item, and the return code as the second. \note On Unix, the output is just the output to stdout, not to stderr. \sa executeDetached() */ /*! \qmlmethod boolean installer::executeDetached(string program, stringlist arguments = undefined, string workingDirectory = "") Starts the program \a program with the arguments \a arguments in a new process, and detaches from it. Returns \c true on success; otherwise returns \c false. If the installer exits, the detached process will continue to live. \note Arguments that contain spaces are not passed to the process as separate arguments. \b{Unix:} The started process will run in its own session and act like a daemon. \b{Windows:} Arguments that contain spaces are wrapped in quotes. The started process will run as a regular standalone process. The process will be started in the directory \a workingDirectory. */ /*! \qmlmethod string installer::environmentVariable(string name) Returns the content of the environment variable \a name. An empty string is returned if the environment variable is not set. */ /*! \qmlmethod boolean installer::performOperation(string name, stringlist arguments) Instantly performs the operation \a name with \a arguments. */ /*! \qmlmethod boolean installer::versionMatches(string version, string requirement) Returns \c true when \a version matches the \a requirement. \a requirement can be a fixed version number or it can be prefixed by the comparators '>', '>=', '<', '<=' and '='. */ /*! \qmlmethod string installer::findLibrary(string name, stringlist paths = []) Finds a library named \a name in \a paths. If \a paths is empty, it gets filled with platform dependent default paths. The resulting path is returned. This method can be used by scripts to check external dependencies. \sa findPath */ /*! \qmlmethod string installer::findPath(string name, stringlist paths = []) Tries to find a file name \a name in one of \a paths. The resulting path is returned. This method can be used by scripts to check external dependencies. \sa findLibrary */ /*! \qmlmethod void installer::setInstallerBaseBinary(string path) Sets the \c installerbase binary to use when writing the maintenance tool. Set the path if an update to the binary is available. If not set, the executable segment of the running installer or uninstaller will be used. */ /*! \qmlmethod string installer::value(string key, string defaultValue = "") Returns the installer value for \a key. If \a key is not known to the system, \a defaultValue is returned. Additionally, on Windows, \a key can be a registry key. \sa setValue, containsValue, valueChanged */ /*! \qmlmethod stringlist installer::values(string key, stringlist defaultValue = []) Returns the installer value for \a key. If \a key is not known to the system, \a defaultValue is returned. Additionally, on Windows, \a key can be a registry key. \sa value */ /*! \qmlmethod void installer::setValue(string key, string value) Sets the installer value for \a key to \a value. \sa value, containsValue, valueChanged */ /*! \qmlmethod boolean installer::containsValue(string key) Returns \c true if the installer contains a value for \a key. \sa value, setValue, valueChanged */ /*! \qmlmethod void installer::setSharedFlag(string key, boolean value) Sets a shared flag with name \a key to \a value. This is one option to share information between scripts. Deprecated since 2.0.0. Use setValue instead. */ /*! \qmlmethod boolean installer::sharedFlag(string key) Returns shared flag with name \a key. This is one option to share information between scripts. Deprecated since 2.0.0. Use \l value or \l values instead. */ /*! \qmlmethod void installer::interrupt() Cancels an ongoing installation. \sa installationInterrupted */ /*! \qmlmethod void installer::setCanceled() Cancels the installation. */ /*! \qmlmethod void installer::setInstaller() Forces an installer context. \sa isInstaller, setUpdater, setUninstaller, setPackageManager */ /*! \qmlmethod boolean installer::isInstaller() Returns \c true if the application, binary, or executable is executed in installer mode. \sa isUninstaller, isUpdater, isPackageManager */ /*! \qmlmethod boolean installer::isOfflineOnly() Returns \c true if this is an offline-only installer. */ /*! \qmlmethod void installer::setUninstaller() Forces an uninstaller context. \sa isUninstaller, setUpdater, setPackageManager, setInstaller */ /*! \qmlmethod boolean installer::isUninstaller() Returns \c true if the the application, binary, or executable is executed in uninstaller mode. \sa setUninstaller, isInstaller, isUpdater, isPackageManager */ /*! \qmlmethod void installer::setUpdater() Forces an updater context. \sa isUpdater, setUninstaller, setPackageManager, setInstaller */ /*! \qmlmethod boolean installer::isUpdater() Returns \c true if the the application, binary, or executable is executed in updater mode. \sa setUpdater, isInstaller, isUninstaller, isPackageManager */ /*! \qmlmethod void installer::setPackageManager() Forces a package manager context. */ /*! \qmlmethod boolean installer::isPackageManager() Returns \c true if the the application, binary, or executable is executed in package manager mode. \sa setPackageManager, isInstaller, isUninstaller, isUpdater */ /*! \qmlmethod boolean installer::isUserSetBinaryMarker() Returns \c true if the magic binary marker has been set by user. */ /*! \qmlmethod boolean installer::isCommandLineDefaultInstall() Returns \c true if installation is performed with default components. */ /*! \qmlmethod boolean installer::isCommandLineInstance() Returns \c true if running as command line instance. */ /*! \qmlmethod boolean installer::runInstaller() Runs the installer. Returns \c true on success, \c false otherwise. */ /*! \qmlmethod boolean installer::runUninstaller() Runs the uninstaller. Returns \c true on success, \c false otherwise. */ /*! \qmlmethod boolean installer::runPackageUpdater() Runs the package updater. Returns \c true on success, \c false otherwise. */ /*! \qmlmethod void installer::languageChanged() Calls languangeChanged on all components. */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/print.qdoc�������������������������������������������0100777�0000000�0000000�00000002613�13761647206�020424� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype print \inqmlmodule scripting \brief Provides compatibility with QtScript. For new code, use the \l{console-object}{console} object instead. */ ���������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/qdesktopservices.qdoc��������������������������������0100777�0000000�0000000�00000007774�13761647206�022703� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype QDesktopServices \inqmlmodule scripting \brief Provides methods for accessing common desktop services. Many desktop environments provide services that can be used by applications to perform common tasks, such as opening a file, in a way that is both consistent and takes into account the user's application preferences. This object contains methods that provide simple interfaces to these services that indicate whether they succeeded or failed. The openUrl() method is used to open files located at arbitrary URLs in external applications. For URLs that correspond to resources on the local filing system (where the URL scheme is "file"), a suitable application is used to open the file. The displayName() and storageLocation() methods take one of the following enums as an argument: \list \li DesktopServices.DesktopLocation \li DesktopServices.DocumentsLocation \li DesktopServices.FontsLocation \li DesktopServices.ApplicationsLocation \li DesktopServices.MusicLocation \li DesktopServices.MoviesLocation \li DesktopServices.PicturesLocation \li DesktopServices.TempLocation \li DesktopServices.HomeLocation \li DesktopServices.DataLocation \li DesktopServices.CacheLocation \li DesktopServices.GenericDataLocation \li DesktopServices.RuntimeLocation \li DesktopServices.ConfigLocation \li DesktopServices.DownloadLocation \li DesktopServices.GenericCacheLocation \li DesktopServices.GenericConfigLocation \endlist The enum values correspond to the values of the \l{QStandardPaths::StandardLocation} enum with the same names. */ /*! \qmlproperty enumeration QDesktopServices::QStandardPaths \internal */ /*! \qmlmethod boolean QDesktopServices::openUrl(string url) Uses the URL scheme \c file to open the specified \a url with a suitable application. \warning A return value of \c true indicates that the installer has successfully requested the operating system to open the URL in an external application. It may still fail to launch or fail to open the requested URL. This result will not be reported back to the installer. */ /*! \qmlmethod string QDesktopServices::displayName(int location) Returns a localized display name for the specified \a location or an empty QString if no relevant location can be found. */ /*! \qmlmethod string QDesktopServices::storageLocation(int location) Returns the specified \a location. */ /*! \qmlmethod array QDesktopServices::findFiles(string path, string pattern) Returns file names matching \a pattern. Searches the files recursively from \a path. \a Pattern understands * and ? wildcards. */ ����qt-installer-framework-4.0.1/doc/scripting-api/qfiledialog.qdoc�������������������������������������0100777�0000000�0000000�00000006261�13761647206�021553� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype QFileDialog \inqmlmodule scripting \brief Provides a dialog that allows users to select files or directories. Use the QFileDialog::getExistingDirectory() method to create a modal dialog that displays an existing directory selected by the user. Use the QFileDialog::getOpenFileName() method to create a dialog that displays matching files in the directory selected by the user. When a command line interface is used, a dialog is not displayed. Instead, the user can type the directory or the file name in the console. For automatic installations, \c{--file-query} with \c{identifier=value} pairs can be given separated with a comma. For example, \c{--file-query filedialog.id=C:/Temp,filedialog.id2=C:/Temp2}. */ /*! \qmlmethod string QFileDialog::getExistingDirectory(string caption, string dir) Returns an existing directory selected by the user. The dialog's working directory is set to \a dir, and the caption is set to \a caption. Either of these may be an empty string, in which case the current directory and a default caption will be used, respectively. */ /*! \qmlmethod string QFileDialog::getOpenFileName(string caption, string dir, string filter) Returns an existing file selected by the user. If the user selects \uicontrol Cancel, returns a null string. The file dialog's caption is set to \a caption. If \c caption is not specified, a default caption is used. The file dialog's working directory is set to \a dir. If \c dir includes a file name, the file will be selected. Only files that match the specified \a filter are shown. Either of these may be an empty string. To specify multiple filters, separate them with two semicolons (;;). For example: \code "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" \endcode On Windows, and macOS, this static function will use the native file dialog and not a QFileDialog. */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-api/qinstaller.qdoc��������������������������������������0100777�0000000�0000000�00000005606�13761647206�021453� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype QInstaller \inqmlmodule scripting \brief Provides access to the installer status and pages from Qt Script. For more information about using the \c QInstaller object in control scripts, see \l{Controller Scripting}. For examples of using the pages to support end user workflows, see \l{End User Workflows}. */ /*! \qmlproperty enumeration QInstaller::WizardPage The installer has various pre-defined pages that can be used to for example insert pages in a certain place: \value QInstaller.Introduction \l{Introduction Page} \value QInstaller.TargetDirectory \l{Target Directory Page} \value QInstaller.ComponentSelection \l{Component Selection Page} \value QInstaller.LicenseCheck \l{License Agreement Page} \value QInstaller.StartMenuSelection \l{Start Menu Directory Page} \value QInstaller.ReadyForInstallation \l{Ready for Installation Page} \value QInstaller.PerformInstallation \l{Perform Installation Page} \value QInstaller.InstallationFinished \l{Finished Page} \omitvalue QInstaller.End */ /*! \qmlproperty enumeration QInstaller::status Status of the installer. Possible values are: \value QInstaller.Success Installation was successful. \value QInstaller.Failure Installation failed. \value QInstaller.Running Installation is in progress. \value QInstaller.Canceled Installation was canceled. \value QInstaller.Unfinished Installation was not completed. \value QInstaller.ForceUpdate */ ��������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting-qmlmodule.qdoc�������������������������������������������0100777�0000000�0000000�00000003064�13761647206�020517� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage ifw-tools.html \nextpage ifw-cpp-classes.html \title Scripting API \qmlmodule scripting \brief Scripting API reference. The following table summarizes the global JavaScript objects that you can use in controller and component scripts. */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/scripting.qdoc�����������������������������������������������������0100777�0000000�0000000�00000030347�13761647206�016526� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage{index.html}{Qt Installer Framework} \previouspage noninteractive.html \page scripting.html \nextpage operations.html \title Component Scripting For each component, you can specify one script that prepares the operations to be performed by the installer. The script format has to be compatible with QJSEngine. \section1 Construction The script has to contain a \c Component object that the installer creates when it loads the script. Therefore, the script must contain at least the \c Component() function, which performs initialization, such as putting pages in the correct places or connecting signals and slots. The following code snippet places the \c ErrorPage (which is the class name of the user interface file loaded from errorpage.ui) in front of the ready for installation page and sets its completeness to \c false. \code function Component() { // Add a user interface file called ErrorPage, which should not be complete installer.addWizardPage( component, "ErrorPage", QInstaller.ReadyForInstallation ); component.userInterface( "ErrorPage" ).complete = false; } \endcode For more information, see the documentation for \l installer::addWizardPage() and \l component::userInterface(). \section1 Installer Hooks You can add the following hook methods into your script: \table \header \li Method \li Description \row \li \c{Component.prototype.retranslateUi} \li Called when the language of the installer changes. \row \li \c{Component.prototype.createOperations} \li See \l component::createOperations(). \row \li \c{Component.prototype.createOperationsForArchive} \li See \l component::createOperationsForArchive(). \row \li \c{Component.prototype.createOperationsForPath} \li See \l component::createOperationsForPath(). \endtable \section1 Global Variables The installer puts the following symbols into the script space: \table \header \li Symbol \li Description \row \li installer \li Reference to the \l QInstaller of the component \row \li component \li Reference to the \l Component of the component \endtable \section1 Message Boxes You can show a QMessageBox from within the script by using the following static members: \list \li QMessageBox::critical() \li QMessageBox::information() \li QMessageBox::question() \li QMessageBox::warning() \endlist For your convenience, the values for QMessageBox::StandardButton are made available by using \c QMessageBox.Ok, \c QMessageBox.Open, and so on. \section1 Adding Operations to Components You might want to add custom operations after extracting the content, when copying files or patching file content, for example. You can create and add update operations to the installation from within a script using component::addOperation(). If you need to run an operation that requires administrative rights, use component::addElevatedOperation() instead. Operations need to be added before the actual installation step. Override \l component::createOperations() to register custom operations for a component. Each operation has a unique key used for identification and can take up to five parameters. In the parameter values, you can use variables as set in installer::setValue(). For more information, see \l{Predefined Variables}. For a summary of all available operations, see \l{Operations}. \section1 Registering Custom Operations You can register custom installation operations in the installer by deriving the KDUpdater::UpdateOperation class. The following code displays the methods that you must implement: \code #include <UpdateOperation> class CustomOperation : public KDUpdater::UpdateOperation { public: CustomOperation() { setName( "CustomOperation" ); } void backup() { // do whatever is needed to restore the state in undoOperation() } bool performOperation() { const QStringList args = arguments(); // do whatever is needed to do for the given arguments bool success = ...; return success; } void undoOperation() { // restore the previous state, as saved in backup() } bool testOperation() { // currently unused return true; } CustomOperation* clone() const { return new CustomOperation; } QDomDocument toXml() { // automatically adds the operation's arguments and everything set via setValue QDomDocument doc = KDUpdater::UpdateOperation::toXml(); // if you need any information to undo the operation you did, // add them to the doc here return doc; } bool fromXml( const QDomDocument& doc ) { // automatically loads the operation's arguments and everything set via setValue if( !KDUpdater::UpdateOperation::fromXml( doc ) ) return false; // if you need any information to undo the operation you did, // read them from the doc here return true; } }; \endcode Finally, you need to register your custom operation class, as follows: \code #include <UpdateOperationFactory> KDUpdater::UpdateOperationFactory::instance().registerUpdateOperation< CustomOperation >( "CustomOperation" ); \endcode Now you can use your operation in the installer in the same way as the predefined operations. \section1 Predefined Variables You can use the following predefined variables in scripts to facilitate directory access: \table \header \li Symbol \li Description \row \li ProductName \li Name of the product to be installed, as defined in config.xml. \row \li ProductVersion \li Version number of the product to be installed, as defined in config.xml. \row \li Title \li Title of the installation program, as defined in config.xml. \row \li Publisher \li Publisher of the installation program, as defined in config.xml. \row \li Url \li Product URL, as defined in config.xml. \row \li StartMenuDir \li Start menu group, as defined in config.xml. Only available on Windows. \row \li TargetDir \li Target directory for installation, as selected by the user. \row \li DesktopDir \li Name of the directory that contains the user's desktop. Only available on Windows. \row \li os \li Current platform: \c "x11", \c "win", or \c "mac". This variable is deprecated: Use \l systemInfo instead. \row \li RootDir \li Root directory of the filesystem. \row \li HomeDir \li Home directory of the current user. \row \li ApplicationsDir \li Applications directory. For example, \c {C:\Program Files} on Windows, \c {/opt} on Linux and \c {/Applications} on macOS. See also the table that lists examples of \l {Applications-directory-on-Windows} {applications directories on Windows}. \row \li ApplicationsDirUser \li Applications directory for user-specific programs. This is useful on macOS, on other platforms it is the same as \c ApplicationsDir. For example, \c {$HOME/Applications} on macOS. \row \li ApplicationsDirX86 \li Applications Directory for 32 bit programs. This is useful on Windows, on other platforms it is the same as \c ApplicationsDir. For example, \c {C:\Program Files (x86)} on Windows. See also the table that lists examples of \l {Applications-directory-on-Windows} {applications directories on Windows}. \row \li ApplicationsDirX64 \li Applications Directory for 64 bit programs. This is useful on Windows, on other platforms it is the same as \c ApplicationsDir. For example, \c {C:\Program Files} on Windows. See also the table that lists examples of \l {Applications-directory-on-Windows} {applications directories on Windows}. \row \li InstallerDirPath \li The directory that contains the installer application executable. \row \li InstallerFilePath \li The file path of the installer application executable. \row \li UserStartMenuProgramsPath \li The path to the folder containing the items in the Start menu of the user. For example, \c {C:\Users\USERNAME\AppData\Roaming\Microsoft\Windows\Start Menu\Programs} Only available on Windows. \row \li AllUsersStartMenuProgramsPath \li The path to the folder containing the items in the Start menu for all users. For example, \c {C:\ProgramData\Microsoft\Windows\Start Menu\Programs} Only available on Windows. \endtable The variables can be resolved by calls to installer::value(). If embedded in '@' they can also be part of strings passed as arguments to installation operations: \code if (installer.value("os") === "win") { component.addOperation("CreateShortcut", "@TargetDir@/MyApp.exe", "@StartMenuDir@/MyApp.lnk"); } \endcode \target Applications-directory-on-Windows For example, applications directory on Windows: \table \header \li OS (Windows) \li Qt Installer Framework \li Variable \li Example Path \row \li {1, 3} 32bit \li {1, 3} 32bit \li ApplicationsDir \li \c {C:\Program Files} \row \li ApplicationsDirX86 \li \c {C:\Program Files} \row \li ApplicationsDirX64 \li \c {C:\Program Files} \row \li {1, 6} 64bit \li {1, 3} 32bit \li ApplicationsDir \li \c {C:\Program Files (x86)} \row \li ApplicationsDirX86 \li \c {C:\Program Files (x86)} \row \li ApplicationsDirX64 \li \c {C:\Program Files} \row \li {1, 3} 64bit \li ApplicationsDir \li \c {C:\Program Files} \row \li ApplicationsDirX86 \li \c {C:\Program Files (x86)} \row \li ApplicationsDirX64 \li \c {C:\Program Files} \endtable */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/systeminfo.qdoc����������������������������������������������������0100777�0000000�0000000�00000010270�13761647206�016715� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype systemInfo \inqmlmodule scripting \brief Provides information about the operating system. */ /*! \qmlproperty string systemInfo::currentCpuArchitecture The architecture of the CPU that the application is running on, in text format. Possible values include \list \li "i386" \li "x86_64" \endlist Note that this function depends on what the OS will report and may not detect the actual CPU architecture if the OS hides that information or is unable to provide it. For example, a 32-bit OS running on a 64-bit CPU is usually unable to determine whether the CPU is actually capable of running 64-bit programs. \sa QSysInfo::currentCpuArchitecture() */ /*! \qmlproperty string systemInfo::kernelType The type of the operating system kernel the installer was compiled for. It is also the kernel the installer is running on, unless the host operating system is running a form of compatibility or virtualization layer. For Windows, Linux, and macOS this will return \list \li "winnt" \li "linux" \li "darwin" \endlist On Unix systems, it returns the same as the output of \c {uname -s} (lowercased). \sa QSysInfo::kernelType() */ /*! \qmlproperty string systemInfo::kernelVersion Example values are \list \li "6.1.7601" for Windows 7 with Service Pack 1 \li "3.16.6-2-desktop" for openSUSE 13.2 kernel 3.16.6-2 \li "12.5.0" last release of OS X "Mountain Lion" \endlist The release version of the operating system kernel. On Windows, it returns the version of the NT or CE kernel. On Unix systems, including macOS, it returns the same as the \c {uname -r} command would return. \sa QSysInfo::kernelVersion() */ /*! \qmlproperty string systemInfo::productType The product name of the operating system this application is running in. Example values are \list \li "windows" \li "opensuse" (for the Linux openSUSE distribution) \li "osx" \endlist \sa QSysInfo::productType() */ /*! \qmlproperty string systemInfo::productVersion The product version of the operating system in string form. If the version could not be determined, this function returns "unknown". Example values are \list \li "7" for Windows 7 \li "13.2" for openSUSE 13.2 \li "10.8" for OS X Mountain Lion \endlist \sa QSysInfo::productVersion() */ /*! \qmlproperty string systemInfo::prettyProductName A prettier form of systemInfo::productType and systemInfo::productVersion, containing other tokens like the operating system type, codenames and other information. The result of this function is suitable for displaying to the user. Example values are \list \li "Windows 7" \li "openSUSE 13.2 (Harlequin) (x86_64)" \li "OS X Mountain Lion (10.8)" \endlist \sa QSysInfo::prettyProductName() */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/doc/tutorial.qdoc������������������������������������������������������0100777�0000000�0000000�00000017204�13761647206�016364� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \contentspage {index.html}{Qt Installer Framework} \previouspage ifw-use-cases-settings.html \page ifw-tutorial.html \nextpage ifw-creating-installers.html \title Tutorial: Creating an Installer This tutorial describes how to create a simple installer for a small project: \image ifw-introduction-page.png "Introduction page" This section describes the following tasks that you must accomplish to create the installer: \list 1 \li Create a \e {package directory} that will contain all the configuration files and installable packages. \li Create a \e {configuration file} that contains information about how to build the installer binaries and online repositories. \li Create a \e {package information file} that contains information about the installable components. \li Create installer content and copy it to the package directory. \li Use the \c binarycreator tool to create the \e installer. The installer pages are created by using the information you provide in the configuration and package information file. \endlist The example files are located in the \c{examples\tutorial} directory in the Qt Installer Framework repository. \section1 Creating a Package Directory Create a directory structure that reflects the design of the installer and allows the installer to be extended in the future. The directory must contain subdirectories called \c config and \c packages. \image ifw-tutorial-files.png For more information about the package directory, see \l{Package Directory}. \section1 Creating a Configuration File In the \c config directory, create a file called \c config.xml with the following contents: \quotefile ../examples/tutorial/config/config.xml The configuration file specifies the following information that is displayed on the introduction page: \list \li The \c <Title> element specifies the installer name displayed on the title bar (1). \li The \c <Name> element specifies the application name that is added to the page name and introduction text (2). \endlist \image ifw-tutorial-introduction-page.png "Introduction page" The other elements are used to customize the behavior of the installer: \list \li The \c <Version> element specifies the application version number. \li The \c <Publisher> element specifies the publisher of the software (as shown in the Windows Control Panel, for example). \li The \c <StartMenuDir> element specifies the name of the default program group for the product in the Windows \gui Start menu. \li The \c <TargetDir> element specifies that the default target directory displayed to users is \c InstallationDirectory in the home directory of the current user (because the predefined variable \c @HomeDir@ is used as a part of the value). For more information, see \l{Predefined Variables}. \endlist For more information about the configuration file format and the available elements, see \l{Configuration File}. \section1 Creating a Package Information File In this easy scenario, the installer handles only one component that is called \c{com.vendor.product}. To provide the installer with information about the component, create a file called \c package.xml with the following contents and place it in the \c meta directory: \quotefile ../examples/tutorial/packages/com.vendor.product/meta/package.xml The elements in the example file are described in more detail below. For more information about the package information file, see \l{Package Information File Syntax}. \section2 Specifying Component Information The information from the following elements is displayed on the component selection page: \list \li The \c <DisplayName> element specifies the name of the component in the list of components (1). \li The \c <Description> element specifies the text that is displayed when the component is selected (2). \endlist \image ifw-tutorial-select-components.png \section2 Specifying Installer Version The \c <Version> element enables you to promote updates to users when they become available. \section2 Adding Licenses The \c <License> element specifies the name of the file that contains the text for the license agreement (1) that is displayed on the license check page: \image ifw-tutorial-license-check.png "License check page" \section2 Selecting Default Contents The \c <Default> element specifies whether the component is selected by default. The value \c true sets the component as selected. In this example, we use the value \c script to resolve the value during runtime. The name of the JavaScript script file, installscript.qs, is specified in the \c <Script> element. \section1 Creating Installer Content Content to be installed is stored in the \c data directory of a component. As there is only one component, place the data in the \c{packages/com.vendor.product/data} directory. The example already contains a file for testing purposes, but you can place basically any files in the directory. For more information about packaging rules and options, see \l{Data Directory}. \section1 Creating the Installer Binary You are now ready to create your first installer. Switch to the \c examples\tutorial directory on the command line. To create an installer called YourInstaller.exe that contains the packages identified by com.vendor.product, enter the following command: \list \li On Windows: \code ..\..\bin\binarycreator.exe -c config\config.xml -p packages YourInstaller.exe \endcode \li On Linux or macOS: \code ../../bin/binarycreator -c config/config.xml -p packages YourInstaller \endcode \endlist The installer is created in the current directory and you can deliver it to end users. For more information about using the \c binarycreator tool, see \l{binarycreator}. \note If an error message is displayed when you run the tutorial installer, check that you used a statically built Qt to create the installer. For more information, see \l{Configuring Qt}. */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/examples/��������������������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�014716� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/examples/changeuserinterface/������������������������������������������0040777�0000000�0000000�00000000000�13761647206�020723� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/examples/changeuserinterface/changeuserinterface.pro�������������������0100777�0000000�0000000�00000000534�13761647206�025454� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README ��������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/examples/changeuserinterface/config/�����������������������������������0040777�0000000�0000000�00000000000�13761647206�022170� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/examples/changeuserinterface/config/config.xml�������������������������0100777�0000000�0000000�00000000525�13761647206�024161� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <Installer> <Name>Change Installer UI Example</Name> <Version>1.0.0</Version> <Title>Change Installer UI Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/changeuserinterface qt-installer-framework-4.0.1/examples/changeuserinterface/packages/0040777000000000000000000000000013761647206022501 5ustar00././@LongLink0040777000000000000000000000016213761647206010120 Lustar00qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.changeuserinterface/qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.change0040777000000000000000000000000013761647206030665 5ustar00././@LongLink0040777000000000000000000000016713761647206010125 Lustar00qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.changeuserinterface/meta/qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.change0040777000000000000000000000000013761647206030665 5ustar00././@LongLink0100777000000000000000000000020713761647206010115 Lustar00qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.changeuserinterface/meta/installscript.qsqt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.change0100777000000000000000000000307113761647206030670 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { gui.pageWidgetByObjectName("LicenseAgreementPage").entered.connect(changeLicenseLabels); } changeLicenseLabels = function() { page = gui.pageWidgetByObjectName("LicenseAgreementPage"); page.AcceptLicenseLabel.setText("Yes I do!"); page.RejectLicenseLabel.setText("No I don't!"); } ././@LongLink0100777000000000000000000000020213761647206010110 Lustar00qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.changeuserinterface/meta/license.txtqt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.change0100777000000000000000000000012013761647206030660 0ustar00The fantastic license, have you heard of the Beer Public License Agreement yet? ././@LongLink0100777000000000000000000000020213761647206010110 Lustar00qt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.changeuserinterface/meta/package.xmlqt-installer-framework-4.0.1/examples/changeuserinterface/packages/org.qtproject.ifw.example.change0100777000000000000000000000074713761647206030677 0ustar00 Dummy Component This example does not install any components. It demonstrates modifying the text on the next page. 1.0.0-1 2013-01-01 true qt-installer-framework-4.0.1/examples/changeuserinterface/README0100777000000000000000000000032013761647206021576 0ustar00Shows how to change small things in the ui from a component script. This shouldn't be used for translations. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/componenterror/0040777000000000000000000000000013761647206017772 5ustar00qt-installer-framework-4.0.1/examples/componenterror/componenterror.pro0100777000000000000000000000053413761647206023572 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/componenterror/config/0040777000000000000000000000000013761647206021237 5ustar00qt-installer-framework-4.0.1/examples/componenterror/config/config.xml0100777000000000000000000000051013761647206023222 0ustar00 Component Error Example 1.0.0 Component Error Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/componenterror qt-installer-framework-4.0.1/examples/componenterror/packages/0040777000000000000000000000000013761647206021550 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root/0040777000000000000000000000000013761647206022533 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root.component1/0040777000000000000000000000000013761647206024615 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root.component1/meta/0040777000000000000000000000000013761647206025543 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root.component1/meta/installscript.js0100777000000000000000000000276713761647206031010 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { var error = true; if (error) { installer.setValue("component_errors", installer.value("component_errors") + ";;;" + "Error in component: " + component.name); } installer.setValue("ComponentError", true); } qt-installer-framework-4.0.1/examples/componenterror/packages/root.component1/meta/package.xml0100777000000000000000000000045613761647206027665 0ustar00 Component 1 This component contains an error that prevents it from being installed. 1.0.1 2013-08-21 qt-installer-framework-4.0.1/examples/componenterror/packages/root.component2/0040777000000000000000000000000013761647206024616 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root.component2/meta/0040777000000000000000000000000013761647206025544 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root.component2/meta/installscript.js0100777000000000000000000000276713761647206031011 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { var error = true; if (error) { installer.setValue("component_errors", installer.value("component_errors") + ";;;" + "Error in component: " + component.name); } installer.setValue("ComponentError", true); } qt-installer-framework-4.0.1/examples/componenterror/packages/root.component2/meta/package.xml0100777000000000000000000000047313761647206027665 0ustar00 Component 2 This component contains an error that prevents it from being installed. 1.0.1 2013-08-21 qt-installer-framework-4.0.1/examples/componenterror/packages/root/meta/0040777000000000000000000000000013761647206023461 5ustar00qt-installer-framework-4.0.1/examples/componenterror/packages/root/meta/installscript.js0100777000000000000000000000474513761647206026724 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function abortInstaller() { installer.setDefaultPageVisible(QInstaller.Introduction, false); installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); var abortText = "" + qsTr("Installation failed:") + ""; var error_list = installer.value("component_errors").split(";;;"); abortText += "

    "; // ignore the first empty one for (var i = 0; i < error_list.length; ++i) { if (error_list[i] !== "") { console.log(error_list[i]); abortText += "
  • " + error_list[i] + "
  • " } } abortText += "
"; installer.setValue("FinishedText", abortText); } function reactOnAbortInstallerChange() { if (installer.value("ComponentError") === "true") abortInstaller(); } function Component() { installer.finishAllComponentsReset.connect(reactOnAbortInstallerChange); } qt-installer-framework-4.0.1/examples/componenterror/packages/root/meta/package.xml0100777000000000000000000000044013761647206025574 0ustar00 Root Component This component handles the errors in the other components. 1.0.1 2013-08-21 qt-installer-framework-4.0.1/examples/componenterror/README0100777000000000000000000000025613761647206020655 0ustar00Create an installer that shows how to react on errors set from a component. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/dependencies/0040777000000000000000000000000013761647206017344 5ustar00qt-installer-framework-4.0.1/examples/dependencies/config/0040777000000000000000000000000013761647206020611 5ustar00qt-installer-framework-4.0.1/examples/dependencies/config/config.xml0100777000000000000000000000070613761647206022603 0ustar00 Dependency Solving Example 1.0.0 Dependency Solving Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/dependencies true true qt-installer-framework-4.0.1/examples/dependencies/dependencies.pro0100777000000000000000000000053413761647206022516 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/dependencies/packages/0040777000000000000000000000000013761647206021122 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/0040777000000000000000000000000013761647206023225 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/data/0040777000000000000000000000000013761647206024136 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/data/installcontent.txt0100777000000000000000000000007313761647206027740 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/data/installcontentA.txt0100777000000000000000000000007313761647206030041 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/meta/0040777000000000000000000000000013761647206024153 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentA/meta/package.xml0100777000000000000000000000043613761647206026273 0ustar00 Component A This component does not depend on any other component. 1.0.0 2014-08-25 100 qt-installer-framework-4.0.1/examples/dependencies/packages/componentB/0040777000000000000000000000000013761647206023226 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentB/data/0040777000000000000000000000000013761647206024137 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentB/data/installcontentB.txt0100777000000000000000000000007313761647206030043 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentB/meta/0040777000000000000000000000000013761647206024154 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentB/meta/package.xml0100777000000000000000000000043513761647206026273 0ustar00 Component B This component does not depend on any other component. 1.0.0 2014-08-25 90 qt-installer-framework-4.0.1/examples/dependencies/packages/componentC/0040777000000000000000000000000013761647206023227 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentC/data/0040777000000000000000000000000013761647206024140 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentC/data/installcontentC.txt0100777000000000000000000000007313761647206030045 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentC/meta/0040777000000000000000000000000013761647206024155 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentC/meta/package.xml0100777000000000000000000000106513761647206026274 0ustar00 Component C (depends on A and B) This component depends on Component A and Component B. Selecting this component for installation also marks Component A and Component B for installation, which in turn marks Component D, because it has an automatic dependency on Component A and Component B. componentA, componentB 1.0.0 2014-08-25 80 qt-installer-framework-4.0.1/examples/dependencies/packages/componentD/0040777000000000000000000000000013761647206023230 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentD/data/0040777000000000000000000000000013761647206024141 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentD/data/installcontentD.txt0100777000000000000000000000007313761647206030047 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentD/meta/0040777000000000000000000000000013761647206024156 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentD/meta/package.xml0100777000000000000000000000072213761647206026274 0ustar00 Component D (auto depends on A and B) This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. componentA, componentB 1.0.0 2014-08-25 70 qt-installer-framework-4.0.1/examples/dependencies/packages/componentE/0040777000000000000000000000000013761647206023231 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentE/data/0040777000000000000000000000000013761647206024142 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentE/data/installcontentE.txt0100777000000000000000000000007313761647206030051 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentE/meta/0040777000000000000000000000000013761647206024157 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentE/meta/package.xml0100777000000000000000000000052613761647206026277 0ustar00 Component E (forced) This is a forced component that is always installed. true 1.0.0 2014-08-25 60 qt-installer-framework-4.0.1/examples/dependencies/packages/componentF/0040777000000000000000000000000013761647206023232 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/0040777000000000000000000000000013761647206026026 5ustar00././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent1/data/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0100777000000000000000000000020313761647206010111 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent1/data/installcontentF_1_1.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000007313761647206031012 0ustar00This file will be installed into the target directory.... ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent1/meta/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000044413761647206031014 0ustar00 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 ././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent2/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent2/data/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0100777000000000000000000000020313761647206010111 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent2/data/installcontentF_1_2.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000007313761647206031012 0ustar00This file will be installed into the target directory.... ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent2/meta/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031010 5ustar00././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000044313761647206031013 0ustar00 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/data/0040777000000000000000000000000013761647206026737 5ustar00././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/data/installcontentF_1.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/data/installco0100777000000000000000000000007313761647206030652 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/meta/0040777000000000000000000000000013761647206026754 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent1/meta/package.x0100777000000000000000000000042513761647206030541 0ustar00 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2014-08-25 100 qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/0040777000000000000000000000000013761647206026027 5ustar00././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent1/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent1/data/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0100777000000000000000000000020313761647206010111 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent1/data/installcontentF_2_1.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0100777000000000000000000000007313761647206031013 0ustar00This file will be installed into the target directory.... ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent1/meta/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0100777000000000000000000000044413761647206031015 0ustar00 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 ././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent2/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent2/data/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0100777000000000000000000000020313761647206010111 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent2/data/installcontentF_2_2.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0100777000000000000000000000007313761647206031013 0ustar00This file will be installed into the target directory.... ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent2/meta/qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0040777000000000000000000000000013761647206031011 5ustar00././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2.subsubcomponen0100777000000000000000000000044313761647206031014 0ustar00 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/data/0040777000000000000000000000000013761647206026740 5ustar00././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/data/installcontentF_2.txtqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/data/installco0100777000000000000000000000007313761647206030653 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/meta/0040777000000000000000000000000013761647206026755 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/dependencies/packages/componentF.subcomponent2/meta/package.x0100777000000000000000000000042413761647206030541 0ustar00 Subcomponent 2 This component contains 2 leaf components. 1.0.0 2014-08-25 50 qt-installer-framework-4.0.1/examples/dependencies/packages/componentF/data/0040777000000000000000000000000013761647206024143 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF/data/installcontentF.txt0100777000000000000000000000007313761647206030053 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentF/meta/0040777000000000000000000000000013761647206024160 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentF/meta/package.xml0100777000000000000000000000041713761647206026277 0ustar00 Component F This component contains 2 subcomponents. 1.0.0 2014-08-25 40 qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/0040777000000000000000000000000013761647206023233 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/data/0040777000000000000000000000000013761647206024144 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/data/installcontentG.txt0100777000000000000000000000007313761647206030055 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/meta/0040777000000000000000000000000013761647206024161 5ustar00qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/meta/installscript.js0100777000000000000000000000367013761647206027420 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { component.addDependency("componentA"); } qt-installer-framework-4.0.1/examples/dependencies/packages/componentG/meta/package.xml0100777000000000000000000000074413761647206026303 0ustar00 Component G (default, depends on A, dependency added dynamically) By default, this component is selected for installation. It depends on component A. Dependency is added from inside component script. true 1.0.0 2014-08-25 30 qt-installer-framework-4.0.1/examples/dependencies/README0100777000000000000000000000022413761647206020222 0ustar00Create an installer that shows how the dependency solving works Generate installer with: binarycreator -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/doc/0040777000000000000000000000000013761647206015463 5ustar00qt-installer-framework-4.0.1/examples/doc/changeuserinterface.qdoc0100777000000000000000000000631213761647206022342 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \example changeuserinterface \ingroup qtifwexamples \title Change Installer UI Example \brief Using a component script to modify the installer UI. \image qtifw-examples-changeuserinterface.png \e {Change Installer UI} demonstrates how to use the \c Component() function to modify the default text for the radio button labels on the \l{License Agreement Page}{license check page}. This example does not install any components, but we specify a dummy component in the package information file, because installers without components are not allowed. \include installerfw-examples-configuring.qdocinc \quotefile changeuserinterface/config/config.xml \include installerfw-examples-packaging.qdocinc \list \li The \c element specifies whether the component is preselected for installation in the user interface by default. \li The \c org.qtproject.ifw.example.dynamicpage.node1 ././@LongLink0040777000000000000000000000015013761647206010115 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0040777000000000000000000000000013761647206030610 5ustar00././@LongLink0040777000000000000000000000015513761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/data/qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0040777000000000000000000000000013761647206030610 5ustar00././@LongLink0100777000000000000000000000017313761647206010117 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/data/data.node2.txtqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0100777000000000000000000000007313761647206030612 0ustar00This file will be installed into the target directory.... ././@LongLink0040777000000000000000000000015513761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/meta/qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0040777000000000000000000000000013761647206030610 5ustar00././@LongLink0100777000000000000000000000017513761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/meta/installscript.qsqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0100777000000000000000000000270613761647206030617 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { // default constructor } Component.prototype.createOperations = function() { // call default implementation to actually install something component.createOperations(); } ././@LongLink0100777000000000000000000000017013761647206010114 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.node2/meta/package.xmlqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage.no0100777000000000000000000000052513761647206030614 0ustar00 Example Component 2 Dummy component without default property set. 1.0.0 2014-04-07 org.qtproject.ifw.example.dynamicpage.node2 ././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0040777000000000000000000000000013761647206030576 5ustar00././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/installationwidget.uiqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000001616613761647206030612 0ustar00 InstallationWidget 0 0 491 190 0 0 491 190 Form 0 6 Qt::Vertical QSizePolicy::Fixed 20 20 0 0 :/icon.png 0 0 Complete 0 0 Typical true 0 0 :/icon.png 0 0 :/icon.png Qt::Horizontal QSizePolicy::Fixed 20 1 0 0 Custom Qt::Horizontal QSizePolicy::Fixed 20 1 0 0 Common program features will be installed. Recommended for general use. 0 0 Choose which program features you want to install. Recommended for advanced users. 0 0 All program features will be installed. (Requires the most disk space) Qt::Vertical QSizePolicy::Fixed 20 20 Qt::Horizontal QSizePolicy::Fixed 20 1 defaultInstall completeInstall customInstall ././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/installscript.jsqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000001522113761647206030601 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ var ComponentSelectionPage = null; var Dir = new function () { this.toNativeSparator = function (path) { if (systemInfo.productType === "windows") return path.replace(/\//g, '\\'); return path; } }; function Component() { if (installer.isInstaller()) { component.loaded.connect(this, Component.prototype.installerLoaded); ComponentSelectionPage = gui.pageById(QInstaller.ComponentSelection); installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); if (systemInfo.productType === "windows") installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); } } Component.prototype.installerLoaded = function () { if (installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory)) { var widget = gui.pageWidgetByObjectName("DynamicTargetWidget"); if (widget != null) { widget.targetChooser.clicked.connect(this, Component.prototype.chooseTarget); widget.targetDirectory.textChanged.connect(this, Component.prototype.targetChanged); widget.windowTitle = "Installation Folder"; widget.targetDirectory.text = Dir.toNativeSparator(installer.value("TargetDir")); } } if (installer.addWizardPage(component, "InstallationWidget", QInstaller.ComponentSelection)) { var widget = gui.pageWidgetByObjectName("DynamicInstallationWidget"); if (widget != null) { widget.customInstall.toggled.connect(this, Component.prototype.customInstallToggled); widget.defaultInstall.toggled.connect(this, Component.prototype.defaultInstallToggled); widget.completeInstall.toggled.connect(this, Component.prototype.completeInstallToggled); widget.defaultInstall.checked = true; widget.windowTitle = "Select Installation Type"; } if (installer.addWizardPage(component, "LicenseWidget", QInstaller.LicenseCheck)) { var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget"); if (widget != null) { widget.acceptLicense.toggled.connect(this, Component.prototype.checkAccepted); widget.complete = false; widget.declineLicense.checked = true; widget.windowTitle = "License Agreement"; } } if (installer.addWizardPage(component, "ReadyToInstallWidget", QInstaller.ReadyForInstallation)) { var widget = gui.pageWidgetByObjectName("DynamicReadyToInstallWidget"); if (widget != null) { widget.showDetails.checked = false; widget.windowTitle = "Ready to Install"; } var page = gui.pageByObjectName("DynamicReadyToInstallWidget"); if (page != null) { page.entered.connect(this, Component.prototype.readyToInstallWidgetEntered); } } } } Component.prototype.targetChanged = function (text) { var widget = gui.pageWidgetByObjectName("DynamicTargetWidget"); if (widget != null) { if (text != "") { if (!installer.fileExists(text + "/components.xml")) { widget.complete = true; installer.setValue("TargetDir", text); return; } } widget.complete = false; } } Component.prototype.chooseTarget = function () { var widget = gui.pageWidgetByObjectName("DynamicTargetWidget"); if (widget != null) { var newTarget = QFileDialog.getExistingDirectory("Choose your target directory.", widget .targetDirectory.text); if (newTarget != "") widget.targetDirectory.text = Dir.toNativeSparator(newTarget); } } Component.prototype.customInstallToggled = function (checked) { if (checked) { if (ComponentSelectionPage != null) ComponentSelectionPage.selectDefault(); installer.setDefaultPageVisible(QInstaller.ComponentSelection, true); } } Component.prototype.defaultInstallToggled = function (checked) { if (checked) { if (ComponentSelectionPage != null) ComponentSelectionPage.selectDefault(); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); } } Component.prototype.completeInstallToggled = function (checked) { if (checked) { if (ComponentSelectionPage != null) ComponentSelectionPage.selectAll(); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); } } Component.prototype.checkAccepted = function (checked) { var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget"); if (widget != null) widget.complete = checked; } Component.prototype.readyToInstallWidgetEntered = function () { var widget = gui.pageWidgetByObjectName("DynamicReadyToInstallWidget"); if (widget != null) { var html = "Components to install:
    "; var components = installer.components(); for (i = 0; i < components.length; ++i) { if (components[i].installationRequested()) html = html + "
  • " + components[i].displayName + "
  • " } html = html + "
"; widget.showDetailsBrowser.html = html; } } ././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/licensewidget.uiqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000000346713761647206030612 0ustar00 LicenseWidget 0 0 491 190 491 190 Form 0 0 Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation. true qrc:/license.txt I accept the license. I do not accept the license. true ././@LongLink0100777000000000000000000000016213761647206010115 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/package.xmlqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000000124013761647206030575 0ustar00 Dynamic page installer example Can be used as reference on how to build installer independent of predefined installer pages. 1.0.0 2014-04-07 targetwidget.ui installationwidget.ui licensewidget.ui readytoinstallwidget.ui org.qtproject.ifw.example.dynamicpage ././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/readytoinstallwidget.uiqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000000411713761647206030603 0ustar00 ReadyToInstallWidget 0 0 491 190 491 190 Form 0 0 Setup is now ready to begin installing Dynamic Page Installer Example on your computer. Show details true Qt::Vertical 20 0 label_2 showDetails showDetailsBrowser verticalSpacer_2 showDetails toggled(bool) showDetailsBrowser setVisible(bool) 63 37 85 89 ././@LongLink0100777000000000000000000000016613761647206010121 Lustar00qt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/meta/targetwidget.uiqt-installer-framework-4.0.1/examples/dynamicpage/packages/org.qtproject.ifw.example.dynamicpage/me0100777000000000000000000000402513761647206030601 0ustar00 TargetWidget 0 0 491 190 0 0 491 190 Form Please specify the folder where Dynamic Page Installer Example will be installed. true 0 0 0 0 ... Qt::Vertical 20 122 qt-installer-framework-4.0.1/examples/dynamicpage/README0100777000000000000000000000030513761647206020055 0ustar00Shows how to build an installer from script side using dynamic pages. Generate installer with binarycreator --offline-only -c config/config.xml -r resources/additional.qrc -p packages installer qt-installer-framework-4.0.1/examples/dynamicpage/resources/0040777000000000000000000000000013761647206021211 5ustar00qt-installer-framework-4.0.1/examples/dynamicpage/resources/additional.qrc0100777000000000000000000000017013761647206024026 0ustar00 icon.png license.txt qt-installer-framework-4.0.1/examples/dynamicpage/resources/icon.png0100777000000000000000000000446313761647206022656 0ustar00‰PNG  IHDR szzôgAMAą üa pHYsÂÂ(J€tEXtSoftwarepaint.net 4.0;čõiģIDATXG•W PVŨŘ&1ąŅīĶĩ5ŠĶĐK­Ķ ĒĻüīŅA ŠVRDGë§6‚Jl2u2étL$NŽ#Ē֘1ÖÔJ". "ĒâēĻ€€, (ēœžsó_Ä6ÖæĖ{ũ―ûūsūåÞûý.ž%:9Ąq§ûũï{VWWI$‰D˗/$,[ķŽyóæÍ_ŌÎâ)BäēŊHŒ„XrÁEsâ9Ē?l>pā@̇‡FõCóÝÝÝ icĄp‹\Ä"Ō―8~ä ōþ{„>ZQ___]VVÖæp8ð(ðôôĄ ré@0íüŒčM(įē­hˆGW‘+  Ð@/fmÚīĐ)!!AÆ­^^^•111ąīáI(Ï ũó„-F›nËĨk'+@:Q―Ģīīījåʕðóók‡ŋï$Lôņ3ðóó}čāëë{ËÛÛûC~ïF;ōR+Ŧ'!råÞŪ4‘vÐYUϰēĪĪĪ~ōäÉ „Ū.Ą°øëąˆNõnĮšĒO8°4v<Â"'"0ħâWÞŊŋGŊŌÆb1А›K,Ļ&ÄûŒļý?.Ģ —.]j FPP^ tkRĸīD§:Š(,ųO'&‹;ĸNE֍Ãëiģ;!"‰ą­+·ð 1uĸþýe™™™ 1Œ2ūƒðâĮ&ĪMĒ%W:äđˆWéĨ›kĀðđggg.ZīsæĖ1MņxXC?þã_Ģņ~3?RŠĸöm:ønÕQņ UÎ)È.„`S!č~ (ũ[ZZ‚“““kÃÃÃ1þ|L›6í?"Ð{Å`N(__H6ũuMUæ]—đýÍØ Ē€ģzŠŪ("UQ* ŠLO ÐRéĮ­4þėŲģ­K–,Á… 1}útü|Šgŧžû.§į*Íģ·>ýģ4Ņs6ĸÞžģQ €‹zÝ›s‰ėŠxZF>ÛķmËÔō‹ŒŒÄŠ+Š3ū-B\{ĖMÍMœ ėČúƒyÖgųX3ßm„ú9äðևø!R9j‹Pžš>Ū›_AëŨŊŋĪÐ ģgφŋŋ?<ρđ–ÖVN>Θežu_øŠįUĨawÆsŋ:ÅË Čäp<ĄíWivC yn#`hóˆ*((Ļ]°`„°°0`HāhļüvVq`æÎ‘hĨyųįô· IŨŠ1 ī6§]@‡ĻâPKŅHˆGŦÂրĒŌŲ…ûó,ßÚÐÐÐaÞžyb™Â" î‡Ĩôþ7ąîĻŧSgD|’ņķ!é1ÂĘŊN7š››)Ö Ŧ(8účë­ī[ÝØØ˜Ã9ߐl7ą“XIhŦ6Å)cSΟ?‹/bŨŪ]P-LŸŒ—'ŧÃeJ_ˌŊābNššš°3;Ęp]扆Æė9ģ[îFQÉ5,Þ;‹ĸá‰Ĩĸ‡ØļXlßū;vė@\\ķlŲ"ÁÍlxōîÝŧÅû>Jïž={N§ĶĶâøņãHKKCzz:Ν;‡ŦWŊâdÎYøū?“>Š€ÕĄ(Ŋ(Gfy‚ õČĩČ―’wD}öâS’°úŦÄĨ­CjÁ>—–˜FåōåËČĘĘ… Œ]mv<ōkČ=C~A%_‘ļõäɓČČȀš!MTTB\ŋ~Ŧķ†ãIWK;ŠGĀ_'Ąžēŧãũ"pÝkļråŠ!ĘÍÍ·spSk'äō›œ:uĘ8xâÄ ]ĩ›%I€Šbb|||đ&Yr},Õ2VZV‚Úš:x-~ ÃÞĢÖˈH<šŸw‡ĒĻâ*XÄFD~~~ŧĨTNȞėĘ9EũÐĄC-tú4y#$@ËÁ/™Ló>”999ČËËÝ;wĀcsÝ0fžžxģ/.åå`í'ŅðŒpOPj+BßH„lȖœ‘m‰`Ú‘„ũCï!ýQSScŌĢũ§đ6ķ:ĶbÆ ·ÉFĻðÅŲ]Ė–čžNßļqc―õZFE*’[·n›ũę†ŅoŒ3ϔ‚Ž"$ڊ°Đ°"ļSĶ’CZÄ%ĮŧI€Îe5 zð,Ũýg4tßz-É[­†ĘĘ0ŅžÓ3+ÂֈM…DtŽvÚwYg‹Č!ïÅĨ˜U :2më䯿d/Ûģ&ÕĸÚqĨ(ŸņyûX"EáßëÁĨRA›§h[‡’MđŪÏwŒĀ‹„͍ęá}*ÎĶŅzî\m"Ą<ֆRWWg g)Šį71 e$-fÞkxÎT0­đī7ŸP[&ûâ|ŽxUDŪpčÖĶU§RG$ąƒų;B!gH–wũîÝæøæáLjVn0·ų.‹ë=‘ïÖqū?1‰PČC õúĮl―į"@ÔčI€`'ĻH-Aâ^dD†ņ8ÃpNä8ˆ˜įĖ뛄Z{ĨR]ūU4õ‡D-™‘*ō^ŽōŸ2Æý īĻ :OĀIENDŪB`‚qt-installer-framework-4.0.1/examples/dynamicpage/resources/license.txt0100777000000000000000000000012013761647206023365 0ustar00The fantastic license, have you heard of the Beer Public License Agreement yet? qt-installer-framework-4.0.1/examples/examples.pro0100777000000000000000000000043513761647206017260 0ustar00TEMPLATE = subdirs SUBDIRS += \ changeuserinterface \ componenterror \ dependencies \ dynamicpage \ licenseagreement \ modifyextract \ online \ openreadme \ quitinstaller \ registerfileextension \ repositorycategories \ startmenu \ systeminfo \ stylesheet qt-installer-framework-4.0.1/examples/hidecheckbox/0040777000000000000000000000000013761647206017336 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/config/0040777000000000000000000000000013761647206020603 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/config/config.xml0100777000000000000000000000047313761647206022576 0ustar00 Hide item checkbox 1.0.0 Hide checkbox The Qt Company Qt IFW Examples @HomeDir@/IfwExamples/hidecheckbox qt-installer-framework-4.0.1/examples/hidecheckbox/hidecheckbox.pro0100777000000000000000000000053413761647206022502 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/hidecheckbox/packages/0040777000000000000000000000000013761647206021114 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF/0040777000000000000000000000000013761647206023224 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/0040777000000000000000000000000013761647206026020 5ustar00././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponent1/data/qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0100777000000000000000000000017713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponent1/data/testF_sub1_sub1.txtqt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000002513761647206031001 0ustar00test sub sub versio3 ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponent1/meta/qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponen0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0100777000000000000000000000016713761647206010122 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1.subsubcomponen0100777000000000000000000000037113761647206031005 0ustar00 Subsubcomponent 1 This component does not depend on any other component. 1.0.2 2015-12-01 qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/data/0040777000000000000000000000000013761647206026731 5ustar00././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/data/testF_sub1.txtqt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/data/testF_sub0100777000000000000000000000002213761647206030604 0ustar00test sub1 versio3 qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/meta/0040777000000000000000000000000013761647206026746 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF.subcomponent1/meta/package.x0100777000000000000000000000046113761647206030533 0ustar00 Subcomponent 1 This component contains sub component. 1.0.2 2015-12-01 100 true qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF/data/0040777000000000000000000000000013761647206024135 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF/data/testF.txt0100777000000000000000000000002213761647206025755 0ustar00test sub1 versio3 qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF/meta/0040777000000000000000000000000013761647206024152 5ustar00qt-installer-framework-4.0.1/examples/hidecheckbox/packages/componentF/meta/package.xml0100777000000000000000000000046013761647206026267 0ustar00 Uncheckable component This component is uncheckable. 1.0.0 2015-12-01 40 false qt-installer-framework-4.0.1/examples/hidecheckbox/README0100777000000000000000000000022013761647206020210 0ustar00Shows how to hide top level item's checkbox. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/licenseagreement/0040777000000000000000000000000013761647206020230 5ustar00qt-installer-framework-4.0.1/examples/licenseagreement/config/0040777000000000000000000000000013761647206021475 5ustar00qt-installer-framework-4.0.1/examples/licenseagreement/config/config.xml0100777000000000000000000000053513761647206023467 0ustar00 License Agreement Example 1.0.0 License Agreement Example Qt-Project Qt Installer Framework Example @HomeDir@/IfwExamples/licenseagreement qt-installer-framework-4.0.1/examples/licenseagreement/licenseagreement.pro0100777000000000000000000000053413761647206024266 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/licenseagreement/packages/0040777000000000000000000000000013761647206022006 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0040777000000000000000000000000013761647206030677 5ustar00././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/data/qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0040777000000000000000000000000013761647206030677 5ustar00././@LongLink0100777000000000000000000000017313761647206010117 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/data/README.txtqt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0100777000000000000000000000011413761647206030675 0ustar00This README file can only be installed if the user accepts the licenses. ././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/meta/qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0040777000000000000000000000000013761647206030677 5ustar00././@LongLink0100777000000000000000000000017013761647206010114 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/meta/cc0.txtqt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0100777000000000000000000001550713761647206030711 0ustar00 CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. ././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/meta/gpl3.txtqt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0100777000000000000000000010451313761647206030705 0ustar00 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseagreement/meta/package.xmlqt-installer-framework-4.0.1/examples/licenseagreement/packages/org.qtproject.ifw.example.licenseag0100777000000000000000000000076613761647206030712 0ustar00 README (requires license agreement) README can only be installed if the user agrees to the licenses. 2014-01-01 1.0.0-1 true qt-installer-framework-4.0.1/examples/licenseagreement/README0100777000000000000000000000020213761647206021102 0ustar00Shows how to ask interactively for a license agreement. binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/modifyextract/0040777000000000000000000000000013761647206017600 5ustar00qt-installer-framework-4.0.1/examples/modifyextract/config/0040777000000000000000000000000013761647206021045 5ustar00qt-installer-framework-4.0.1/examples/modifyextract/config/config.xml0100777000000000000000000000053113761647206023033 0ustar00 Modify Extract Installer Example 1.0.0 Modify Extract Installer Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/modifyextract qt-installer-framework-4.0.1/examples/modifyextract/modifyextract.pro0100777000000000000000000000053413761647206023206 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/modifyextract/packages/0040777000000000000000000000000013761647206021356 5ustar00././@LongLink0040777000000000000000000000014613761647206010122 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0040777000000000000000000000015313761647206010120 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/data/qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0040777000000000000000000000016613761647206010124 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/data/my_content/qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/data/my_content/test.txtqt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0100777000000000000000000000004713761647206031016 0ustar00test test test test test test test test././@LongLink0040777000000000000000000000015313761647206010120 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/meta/qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017313761647206010117 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/meta/installscript.jsqt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0100777000000000000000000000306613761647206031022 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { } Component.prototype.createOperationsForArchive = function(archive) { // don't use the default operation // component.createOperationsForArchive(archive); // add an extract operation with a modified path component.addOperation("Extract", archive, "@TargetDir@/extractToAnotherPath"); } ././@LongLink0100777000000000000000000000016613761647206010121 Lustar00qt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextract/meta/package.xmlqt-installer-framework-4.0.1/examples/modifyextract/packages/org.qtproject.ifw.example.modifyextrac0100777000000000000000000000051113761647206031012 0ustar00 Modify extract operation A component that uses a hook to modify the extract operation. 1.0.1 2014-12-19 true qt-installer-framework-4.0.1/examples/modifyextract/README0100777000000000000000000000026513761647206020463 0ustar00Create an installer that uses the extract archive hook to modify the target path. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/online/0040777000000000000000000000000013761647206016202 5ustar00qt-installer-framework-4.0.1/examples/online/config/0040777000000000000000000000000013761647206017447 5ustar00qt-installer-framework-4.0.1/examples/online/config/config.xml0100777000000000000000000000101413761647206021432 0ustar00 Online Installer Example 1.0.0 Online Installer Example The Qt Company Qt IFW Examples @HomeDir@/IfwExamples/online http://localhost/repository qt-installer-framework-4.0.1/examples/online/online.pro0100777000000000000000000000055213761647206020212 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator --online-only -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/online/packages/0040777000000000000000000000000013761647206017760 5ustar00qt-installer-framework-4.0.1/examples/online/packages/A/0040777000000000000000000000000013761647206020140 5ustar00qt-installer-framework-4.0.1/examples/online/packages/A/data/0040777000000000000000000000000013761647206021051 5ustar00qt-installer-framework-4.0.1/examples/online/packages/A/data/A.txt0100777000000000000000000000004013761647206021764 0ustar00Example content for package A. qt-installer-framework-4.0.1/examples/online/packages/A/meta/0040777000000000000000000000000013761647206021066 5ustar00qt-installer-framework-4.0.1/examples/online/packages/A/meta/package.xml0100777000000000000000000000036513761647206023207 0ustar00 A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/examples/online/packages/B/0040777000000000000000000000000013761647206020141 5ustar00qt-installer-framework-4.0.1/examples/online/packages/B/data/0040777000000000000000000000000013761647206021052 5ustar00qt-installer-framework-4.0.1/examples/online/packages/B/data/B.txt0100777000000000000000000000004013761647206021766 0ustar00Example content for package B. qt-installer-framework-4.0.1/examples/online/packages/B/meta/0040777000000000000000000000000013761647206021067 5ustar00qt-installer-framework-4.0.1/examples/online/packages/B/meta/package.xml0100777000000000000000000000036513761647206023210 0ustar00 B Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/online/packages_update/0040777000000000000000000000000013761647206021322 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/A/0040777000000000000000000000000013761647206021502 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/A/data/0040777000000000000000000000000013761647206022413 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/A/data/A.txt0100777000000000000000000000005713761647206023336 0ustar00Example content for package A (new version!). qt-installer-framework-4.0.1/examples/online/packages_update/A/meta/0040777000000000000000000000000013761647206022430 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/A/meta/package.xml0100777000000000000000000000036513761647206024551 0ustar00 A Example component A 1.0.3-1 2015-01-01 true qt-installer-framework-4.0.1/examples/online/packages_update/B/0040777000000000000000000000000013761647206021503 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/B/data/0040777000000000000000000000000013761647206022414 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/B/data/B.txt0100777000000000000000000000004013761647206023330 0ustar00Example content for package B. qt-installer-framework-4.0.1/examples/online/packages_update/B/meta/0040777000000000000000000000000013761647206022431 5ustar00qt-installer-framework-4.0.1/examples/online/packages_update/B/meta/package.xml0100777000000000000000000000036513761647206024552 0ustar00 B Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/online/README0100777000000000000000000000124213761647206017061 0ustar00Shows how to set up an online installer. The example uses a very simple web server shipped with python. Generate online repository with repogen -p packages repository Generate installer with binarycreator --online-only -c config/config.xml -p packages installer Now launch a minimal web server in the example's directory (admin rights may be needed) python -m SimpleHTTPServer 80 This should make the content of the local directory available under http://localhost You should be able to now launch the installer. To deploy an update, run repogen --update-new-components -p packages_update repository and launch the maintenance tool in your installation. qt-installer-framework-4.0.1/examples/openreadme/0040777000000000000000000000000013761647206017035 5ustar00qt-installer-framework-4.0.1/examples/openreadme/config/0040777000000000000000000000000013761647206020302 5ustar00qt-installer-framework-4.0.1/examples/openreadme/config/config.xml0100777000000000000000000000047413761647206022276 0ustar00 Open Readme Example 1.0.0 Open Readme Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/openreadme qt-installer-framework-4.0.1/examples/openreadme/openreadme.pro0100777000000000000000000000053413761647206021700 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/openreadme/packages/0040777000000000000000000000000013761647206020613 5ustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/0040777000000000000000000000000013761647206027601 5ustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/0040777000000000000000000000000013761647206030512 5ustar00././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/README.txtqt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/0100777000000000000000000000001113761647206030504 0ustar00README qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/0040777000000000000000000000000013761647206030527 5ustar00././@LongLink0100777000000000000000000000016413761647206010117 Lustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qsqt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/0100777000000000000000000000451513761647206030536 0ustar00/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { installer.installationFinished.connect(this, Component.prototype.installationFinishedPageIsShown); installer.finishButtonClicked.connect(this, Component.prototype.installationFinished); } Component.prototype.createOperations = function() { component.createOperations(); } Component.prototype.installationFinishedPageIsShown = function() { try { if (installer.isInstaller() && installer.status == QInstaller.Success) { installer.addWizardPageItem( component, "ReadMeCheckBoxForm", QInstaller.InstallationFinished ); } } catch(e) { console.log(e); } } Component.prototype.installationFinished = function() { try { if (installer.isInstaller() && installer.status == QInstaller.Success) { var checkboxForm = component.userInterface( "ReadMeCheckBoxForm" ); if (checkboxForm && checkboxForm.readMeCheckBox.checked) { QDesktopServices.openUrl("file:///" + installer.value("TargetDir") + "/README.txt"); } } } catch(e) { console.log(e); } } ././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/package.xmlqt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/0100777000000000000000000000066013761647206030533 0ustar00 Open readme Show checkbox asking whether to open Readme at the end 1.0.0-1 2013-01-01 true readmecheckboxform.ui ././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/readmecheckboxform.uiqt-installer-framework-4.0.1/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/0100777000000000000000000000140713761647206030533 0ustar00 ReadMeCheckBoxForm 0 0 412 179 0 Open ReadMe true false qt-installer-framework-4.0.1/examples/openreadme/README0100777000000000000000000000024013761647206017711 0ustar00Shows how to add a 'Open ReadMe' checkbox to the final page. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/quitinstaller/0040777000000000000000000000000013761647206017616 5ustar00qt-installer-framework-4.0.1/examples/quitinstaller/config/0040777000000000000000000000000013761647206021063 5ustar00qt-installer-framework-4.0.1/examples/quitinstaller/config/config.xml0100777000000000000000000000050513761647206023052 0ustar00 Quit Installer Example 1.0.0 Quit Installer Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/quitinstaller qt-installer-framework-4.0.1/examples/quitinstaller/packages/0040777000000000000000000000000013761647206021374 5ustar00././@LongLink0040777000000000000000000000014613761647206010122 Lustar00qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstaller/qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstalle0040777000000000000000000000000013761647206031051 5ustar00././@LongLink0040777000000000000000000000015313761647206010120 Lustar00qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstaller/meta/qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstalle0040777000000000000000000000000013761647206031051 5ustar00././@LongLink0100777000000000000000000000017313761647206010117 Lustar00qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstaller/meta/installscript.jsqt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstalle0100777000000000000000000000437313761647206031062 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { var result = QMessageBox["question"]("test.quit", "Installer", "Do you want to quit the installer?
" + "This message box was created using JavaScript.", QMessageBox.Ok | QMessageBox.Cancel); if (result == QMessageBox.Ok) { installer.setValue("FinishedText", "The installer was quit."); installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); gui.clickButton(buttons.NextButton); } else { installer.setValue("FinishedText", "The installer was not quit by JavaScript."); } } ././@LongLink0100777000000000000000000000016613761647206010121 Lustar00qt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstaller/meta/package.xmlqt-installer-framework-4.0.1/examples/quitinstaller/packages/org.qtproject.ifw.example.quitinstalle0100777000000000000000000000050513761647206031053 0ustar00 Quit an installer Quits the installer in a nice way, if there is something missing 1.0.1 2013-02-27 true qt-installer-framework-4.0.1/examples/quitinstaller/quitinstaller.pro0100777000000000000000000000053413761647206023242 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/quitinstaller/README0100777000000000000000000000022413761647206020474 0ustar00Shows how to quit an installer from script side. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/registerfileextension/0040777000000000000000000000000013761647206021337 5ustar00qt-installer-framework-4.0.1/examples/registerfileextension/config/0040777000000000000000000000000013761647206022604 5ustar00qt-installer-framework-4.0.1/examples/registerfileextension/config/config.xml0100777000000000000000000000053713761647206024600 0ustar00 Register File Extension Example 1.0.0 Register File Extension Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/registerfileextension qt-installer-framework-4.0.1/examples/registerfileextension/packages/0040777000000000000000000000000013761647206023115 5ustar00././@LongLink0040777000000000000000000000016613761647206010124 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0040777000000000000000000000017313761647206010122 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/data/qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0100777000000000000000000000021113761647206010110 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/data/registeredfileqt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0100777000000000000000000000007113761647206031002 0ustar00This file should open with notepad.exe if double clicked.././@LongLink0040777000000000000000000000017313761647206010122 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0040777000000000000000000000000013761647206031002 5ustar00././@LongLink0100777000000000000000000000021313761647206010112 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/installscript.qsqt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0100777000000000000000000001076413761647206031014 0ustar00/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { component.loaded.connect(this, addRegisterFileCheckBox); installer.installationFinished.connect(this, addOpenFileCheckBoxToFinishPage); installer.finishButtonClicked.connect(this, openRegisteredFileIfChecked); component.unusualFileType = generateUnusualFileType(5) } generateUnusualFileType = function(length) { var randomString = ""; var possible = "abcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < length; i++) randomString += possible.charAt(Math.floor(Math.random() * possible.length)); return randomString; } // called as soon as the component was loaded addRegisterFileCheckBox = function() { // don't show when updating or uninstalling if (installer.isInstaller()) { if (installer.addWizardPageItem(component, "RegisterFileCheckBoxForm", QInstaller.TargetDirectory)) { component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text = component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.text + component.unusualFileType; } } } // here we are creating the operation chain which will be processed at the real installation part later Component.prototype.createOperations = function() { // call default implementation to actually install the registeredfile component.createOperations(); if (component.userInterface("RegisterFileCheckBoxForm")) { var isRegisterFileChecked = component.userInterface("RegisterFileCheckBoxForm").RegisterFileCheckBox.checked; } if (installer.value("os") === "win") { var iconId = 0; var notepadPath = installer.environmentVariable("SystemRoot") + "\\notepad.exe"; component.addOperation("RegisterFileType", component.unusualFileType, notepadPath + " '%1'", "QInstaller Framework example file type", "text/plain", notepadPath + "," + iconId, "ProgId=QtProject.QtInstallerFramework." + component.unusualFileType); } component.fileWithRegisteredType = installer.value("TargetDir") + "/registeredfile." + component.unusualFileType component.addOperation("Move", "@TargetDir@/registeredfile", component.fileWithRegisteredType); } openRegisteredFileIfChecked = function() { if (!component.installed) return; if (installer.value("os") == "win" && installer.isInstaller() && installer.status == QInstaller.Success) { var isOpenRegisteredFileChecked = component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.checked; if (isOpenRegisteredFileChecked) { QDesktopServices.openUrl("file:///" + component.fileWithRegisteredType); } } } addOpenFileCheckBoxToFinishPage = function() { if (installer.isInstaller() && installer.status == QInstaller.Success) { if (installer.addWizardPageItem(component, "OpenFileCheckBoxForm", QInstaller.InstallationFinished)) { component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text = component.userInterface("OpenFileCheckBoxForm").OpenRegisteredFileCheckBox.text + component.unusualFileType; } } } ././@LongLink0100777000000000000000000000022213761647206010112 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/openfilecheckboxform.uiqt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0100777000000000000000000000136513761647206031011 0ustar00 OpenFileCheckBoxForm 0 0 400 300 Form Open registered example file based on suffix: true ././@LongLink0100777000000000000000000000020613761647206010114 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/package.xmlqt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0100777000000000000000000000102213761647206030777 0ustar00 Register a file extension Register a randomly generated file extension to open with notepad.exe 1.0.0-1 2013-01-01 true registerfilecheckboxform.ui openfilecheckboxform.ui ././@LongLink0100777000000000000000000000022613761647206010116 Lustar00qt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.registerfileextension/meta/registerfilecheckboxform.uiqt-installer-framework-4.0.1/examples/registerfileextension/packages/org.qtproject.ifw.example.regi0100777000000000000000000000135213761647206031005 0ustar00 RegisterFileCheckBoxForm 0 0 400 300 Form Register example file extension: true qt-installer-framework-4.0.1/examples/registerfileextension/README0100777000000000000000000000023313761647206022215 0ustar00Shows how to register a special file suffix on Windows. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/registerfileextension/registerfileextension.pro0100777000000000000000000000053413761647206026504 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/0040777000000000000000000000000013761647206024535 5ustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/config/0040777000000000000000000000000013761647206026002 5ustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/config/config.xml0100777000000000000000000000064713761647206030000 0ustar00 Register Component to Uninstall Example 1.0.0 Register Component to Uninstall Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/registercomponenttouninstall controller.qs qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/config/controller.qs0100777000000000000000000000033413761647206030532 0ustar00function Controller() { } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName("ComponentSelectionPage"); page.addVirtualComponentToUninstall("component") } qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/0040777000000000000000000000000013761647206026313 5ustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/0040777000000000000000000000000013761647206030315 5ustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/data/0040777000000000000000000000000013761647206031226 5ustar00././@LongLink0100777000000000000000000000016513761647206010120 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/data/selectedcomponentqt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/data/0100777000000000000000000000000013761647206031216 0ustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/meta/0040777000000000000000000000000013761647206031243 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/meta/package.xmlqt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/component/meta/0100777000000000000000000000046013761647206031245 0ustar00 Component selected from script This component is selected to uninstall in script 1.0.0-1 2018-02-02 true ././@LongLink0040777000000000000000000000020113761647206010112 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.ifw.example.registercomponent/qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.i0040777000000000000000000000000013761647206031264 5ustar00././@LongLink0040777000000000000000000000020613761647206010117 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.ifw.example.registercomponent/data/qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.i0040777000000000000000000000000013761647206031264 5ustar00././@LongLink0100777000000000000000000000022713761647206010117 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.ifw.example.registercomponent/data/registercomponentqt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.i0100777000000000000000000000000013761647206031254 0ustar00././@LongLink0040777000000000000000000000020613761647206010117 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.ifw.example.registercomponent/meta/qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.i0040777000000000000000000000000013761647206031264 5ustar00././@LongLink0100777000000000000000000000022113761647206010111 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.ifw.example.registercomponent/meta/package.xmlqt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/packages/org.qtproject.i0100777000000000000000000000052013761647206031263 0ustar00 Registers component for install Register a component for installation 1.0.0-1 2013-01-01 true component qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/README0100777000000000000000000000025513761647206025417 0ustar00Shows how to register virtual component to uninstall in component script. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer ././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/registercomponentforinstall.proqt-installer-framework-4.0.1/examples/registervirtualcomponentforuninstall/registercomponentforinst0100777000000000000000000000053413761647206031636 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/repositorycategories/0040777000000000000000000000000013761647206021203 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/config/0040777000000000000000000000000013761647206022450 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/config/config.xml0100777000000000000000000000257213761647206024445 0ustar00 Repository category Installer Example 1.0.0 Repository category Installer Example The Qt Company Qt IFW Examples @HomeDir@/IfwExamples/repositoryCategories http://localhost/repository Releases Category 1 Contains repository1 and repository2 http://localhost/repository1 http://localhost/repository2 true Category 2 Contains repository3 http://localhost/repository3 qt-installer-framework-4.0.1/examples/repositorycategories/packages/0040777000000000000000000000000013761647206022761 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/0040777000000000000000000000000013761647206025530 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/0040777000000000000000000000000013761647206027551 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/0040777000000000000000000000000013761647206030462 5ustar00././@LongLink0100777000000000000000000000016413761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/A2_category1.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/0100777000000000000000000000006313761647206030463 0ustar00Example content for package A2, using category 1. qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/0040777000000000000000000000000013761647206030477 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/0100777000000000000000000000041113761647206030475 0ustar00 A2 (from category 1) Example component A2 1.0.3-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/0040777000000000000000000000000013761647206027552 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/data/0040777000000000000000000000000013761647206030463 5ustar00././@LongLink0100777000000000000000000000016413761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/data/B2_category1.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/data/0100777000000000000000000000006313761647206030464 0ustar00Example content for package B2, using category 1. qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/0040777000000000000000000000000013761647206030500 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/0100777000000000000000000000041013761647206030475 0ustar00 B2 (from category 1) Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages/A/0040777000000000000000000000000013761647206023141 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/A/data/0040777000000000000000000000000013761647206024052 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/A/data/A.txt0100777000000000000000000000004013761647206024765 0ustar00Example content for package A. qt-installer-framework-4.0.1/examples/repositorycategories/packages/A/meta/0040777000000000000000000000000013761647206024067 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/A/meta/package.xml0100777000000000000000000000036513761647206026210 0ustar00 A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages/B/0040777000000000000000000000000013761647206023142 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/B/data/0040777000000000000000000000000013761647206024053 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/B/data/B.txt0100777000000000000000000000004013761647206024767 0ustar00Example content for package B. qt-installer-framework-4.0.1/examples/repositorycategories/packages/B/meta/0040777000000000000000000000000013761647206024070 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages/B/meta/package.xml0100777000000000000000000000036513761647206026211 0ustar00 B Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/0040777000000000000000000000000013761647206025446 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/0040777000000000000000000000000013761647206027405 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/data/0040777000000000000000000000000013761647206030316 5ustar00././@LongLink0100777000000000000000000000016113761647206010114 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_category1.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_0100777000000000000000000000006213761647206030556 0ustar00Example content for package A, using category 1. qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/0040777000000000000000000000000013761647206030333 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/pa0100777000000000000000000000040713761647206030657 0ustar00 A (from category 1) Example component A 1.0.3-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/0040777000000000000000000000000013761647206027406 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/data/0040777000000000000000000000000013761647206030317 5ustar00././@LongLink0100777000000000000000000000016113761647206010114 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/data/B_category1.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/data/B_0100777000000000000000000000006213761647206030560 0ustar00Example content for package B, using category 1. qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/meta/0040777000000000000000000000000013761647206030334 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory1/BCategory1/meta/pa0100777000000000000000000000040713761647206030660 0ustar00 B (from category 1) Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/0040777000000000000000000000000013761647206025447 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/0040777000000000000000000000000013761647206027407 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/data/0040777000000000000000000000000013761647206030320 5ustar00././@LongLink0100777000000000000000000000016113761647206010114 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/data/A_category2.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/data/A_0100777000000000000000000000006213761647206030560 0ustar00Example content for package A, using category 2. qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/meta/0040777000000000000000000000000013761647206030335 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/ACategory2/meta/pa0100777000000000000000000000040713761647206030661 0ustar00 A (from category 2) Example component A 1.0.3-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/0040777000000000000000000000000013761647206027410 5ustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/data/0040777000000000000000000000000013761647206030321 5ustar00././@LongLink0100777000000000000000000000016113761647206010114 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/data/B_category2.txtqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/data/B_0100777000000000000000000000006213761647206030562 0ustar00Example content for package B, using category 2. qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/meta/0040777000000000000000000000000013761647206030336 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/meta/package.xmlqt-installer-framework-4.0.1/examples/repositorycategories/packages_forcategory2/BCategory2/meta/pa0100777000000000000000000000040713761647206030662 0ustar00 B (from category 2) Example component B 1.0.0-1 2015-01-01 true qt-installer-framework-4.0.1/examples/repositorycategories/README0100777000000000000000000000210713761647206022063 0ustar00Shows how to set up an online installer and how to use categorized repositories. Categorized repositories are not loaded to the tree view by default, instead you can select to show categorized repositories in a tree view combobox. By default, repositories without categories are always shown in the tree view. The example uses a very simple web server shipped with Python. Generate the online repositories with repogen -p packages repository repogen -p packages_forcategory1 repository1 repogen -p packages2_forcategory1 repository2 repogen -p packages_forcategory2 repository3 Generate the installer with binarycreator --online-only -c config/config.xml -p packages installer Now launch a minimal web server in the example's directory (admin rights may be needed) python -m SimpleHTTPServer 80 This should make the content of the local directory available under http://localhost You should be able to now launch the installer. To deploy an update, run repogen --update-new-components -p packages_update repository and launch the maintenance tool in your installation. qt-installer-framework-4.0.1/examples/repositorycategories/repositorycategories.pro0100777000000000000000000000055213761647206026214 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator --online-only -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/startmenu/0040777000000000000000000000000013761647206016740 5ustar00qt-installer-framework-4.0.1/examples/startmenu/config/0040777000000000000000000000000013761647206020205 5ustar00qt-installer-framework-4.0.1/examples/startmenu/config/config.xml0100777000000000000000000000062013761647206022172 0ustar00 Start Menu Shortcut Example 1.0.0 Start Menu Shortcut Example Qt-Project Qt Installer Framework Examples @HomeDir@/IfwExamples/startmenu qt-installer-framework-4.0.1/examples/startmenu/packages/0040777000000000000000000000000013761647206020516 5ustar00qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/0040777000000000000000000000000013761647206025535 5ustar00qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/data/0040777000000000000000000000000013761647206026446 5ustar00qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/data/README.txt0100777000000000000000000000013313761647206030141 0ustar00This file can be opened through the start menu, "Qt Installer Framework Example" section! qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/meta/0040777000000000000000000000000013761647206026463 5ustar00././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/meta/installscript.qsqt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/meta/installscri0100777000000000000000000000337213761647206030742 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { // default constructor } Component.prototype.createOperations = function() { // call default implementation to actually install README.txt! component.createOperations(); if (systemInfo.productType === "windows") { component.addOperation("CreateShortcut", "@TargetDir@/README.txt", "@StartMenuDir@/README.lnk", "workingDirectory=@TargetDir@", "iconPath=%SystemRoot%/system32/SHELL32.dll", "iconId=2", "description=Open README file"); } } qt-installer-framework-4.0.1/examples/startmenu/packages/org.qtproject.ifw.example/meta/package.xml0100777000000000000000000000050513761647206030600 0ustar00 README.txt A README.txt, accessible through a start menu entry. 1.0.0-1 2013-01-01 true qt-installer-framework-4.0.1/examples/startmenu/README0100777000000000000000000000023013761647206017613 0ustar00Shows how to add an entry to the Windows start menu. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/startmenu/startmenu.pro0100777000000000000000000000053413761647206021506 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/stylesheet/0040777000000000000000000000000013761647206017107 5ustar00qt-installer-framework-4.0.1/examples/stylesheet/config/0040777000000000000000000000000013761647206020354 5ustar00qt-installer-framework-4.0.1/examples/stylesheet/config/config.xml0100777000000000000000000000065513761647206022351 0ustar00 Stylesheet Example 1.0.0 Stylesheet Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/stylesheet Classic style.qss #FFFFFF qt-installer-framework-4.0.1/examples/stylesheet/config/style.qss0100777000000000000000000000114613761647206022246 0ustar00QWidget { color: white; background-color: rgb(65, 65, 65); } QPushButton { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(150, 150, 150, 60%), stop:1 rgba(50, 50, 50, 60%)); border-color: rgb(60, 60, 60); border-style: solid; border-width: 2px; border-radius: 9px; min-height: 20px; max-height: 20px; min-width: 60px; max-width: 60px; padding-left: 15px; padding-right: 15px; } QPushButton:pressed, QPushButton:checked { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(50, 50, 50, 60%), stop:1 rgba(150, 150, 150, 60%)); } qt-installer-framework-4.0.1/examples/stylesheet/packages/0040777000000000000000000000000013761647206020665 5ustar00qt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/0040777000000000000000000000000013761647206030074 5ustar00././@LongLink0040777000000000000000000000014513761647206010121 Lustar00qt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta/qt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta0040777000000000000000000000000013761647206030743 5ustar00././@LongLink0100777000000000000000000000016513761647206010120 Lustar00qt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta/installscript.qsqt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta0100777000000000000000000000375213761647206030754 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { // constructor installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); } ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta/package.xmlqt-installer-framework-4.0.1/examples/stylesheet/packages/org.qtproject.ifw.example.stylesheet/meta0100777000000000000000000000035213761647206030745 0ustar00 Dummy 2015-09-09 1.0.1 true qt-installer-framework-4.0.1/examples/stylesheet/README0100777000000000000000000000022113761647206017762 0ustar00Shows how to customize a UI using stylesheet. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/stylesheet/stylesheet.pro0100777000000000000000000000053413761647206022024 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/systeminfo/0040777000000000000000000000000013761647206017116 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/config/0040777000000000000000000000000013761647206020363 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/config/config.xml0100777000000000000000000000060213761647206022350 0ustar00 SystemInfo Example 1.0.0 SystemInfo Example The Qt Company Qt Installer Framework Example @HomeDir@/IfwExamples/systeminfo qt-installer-framework-4.0.1/examples/systeminfo/packages/0040777000000000000000000000000013761647206020674 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root/0040777000000000000000000000000013761647206021657 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root.i386/0040777000000000000000000000000013761647206022347 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root.i386/meta/0040777000000000000000000000000013761647206023275 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root.i386/meta/package.xml0100777000000000000000000000041713761647206025414 0ustar00 i386 binaries Binaries that require a x86 CPU. 1.0.0-1 2014-12-01 false qt-installer-framework-4.0.1/examples/systeminfo/packages/root.x86_64/0040777000000000000000000000000013761647206022614 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root.x86_64/meta/0040777000000000000000000000000013761647206023542 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root.x86_64/meta/package.xml0100777000000000000000000000043013761647206025654 0ustar00 x86-64 bit binaries Binaries that require a x86-64 CPU. 1.0.0-1 2014-12-01 false qt-installer-framework-4.0.1/examples/systeminfo/packages/root/meta/0040777000000000000000000000000013761647206022605 5ustar00qt-installer-framework-4.0.1/examples/systeminfo/packages/root/meta/installscript.qs0100777000000000000000000001103113761647206026041 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Skip all pages and go directly to finished page. // (see also componenterror example) function cancelInstaller(message) { installer.setDefaultPageVisible(QInstaller.Introduction, false); installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); var abortText = "" + message +""; installer.setValue("FinishedText", abortText); } // Returns the major version number as int // string.split(".", 1) returns the string before the first '.', // parseInt() converts it to an int. function majorVersion(str) { return parseInt(str.split(".", 1)); } function Component() { // // Check whether OS is supported. // // For Windows and macOS we check the kernel version: // - Require at least Windows Vista (winnt kernel version 6.0.x) // - Require at least OS X 10.7 (Lion) (darwin kernel version 11.x) // // If the kernel version is older we move directly // to the final page & show an error. // // For Linux, we check the distribution and version, but only // show a warning if it does not match our preferred distribution. // // start installer with -v to see debug output console.log("OS: " + systemInfo.productType); console.log("Kernel: " + systemInfo.kernelType + "/" + systemInfo.kernelVersion); var validOs = false; if (systemInfo.kernelType === "winnt") { if (majorVersion(systemInfo.kernelVersion) >= 6) validOs = true; } else if (systemInfo.kernelType === "darwin") { if (majorVersion(systemInfo.kernelVersion) >= 11) validOs = true; } else { if (systemInfo.productType !== "opensuse" || systemInfo.productVersion !== "13.2") { QMessageBox["warning"]("os.warning", "Installer", "Note that the binaries are only tested on OpenSUSE 13.2.", QMessageBox.Ok); } validOs = true; } if (!validOs) { cancelInstaller("Installation on " + systemInfo.prettyProductName + " is not supported"); return; } // // Hide/select packages based on architecture // // Marking a component as "Virtual" will hide it in the UI. // Marking a component with "Default" will check it. // console.log("CPU Architecture: " + systemInfo.currentCpuArchitecture); installer.componentByName("root.i386").setValue("Virtual", "true"); installer.componentByName("root.x86_64").setValue("Virtual", "true"); if ( systemInfo.currentCpuArchitecture === "i386") { installer.componentByName("root.i386").setValue("Virtual", "false"); installer.componentByName("root.i386").setValue("Default", "true"); } if ( systemInfo.currentCpuArchitecture === "x86_64") { installer.componentByName("root.x86_64").setValue("Virtual", "false"); installer.componentByName("root.x86_64").setValue("Default", "true"); } } qt-installer-framework-4.0.1/examples/systeminfo/packages/root/meta/package.xml0100777000000000000000000000044413761647206024724 0ustar00 systemInfo example Shows the use of the systemInfo JS API. 1.0.0-1 2013-01-01 qt-installer-framework-4.0.1/examples/systeminfo/README0100777000000000000000000000067013761647206020001 0ustar00Shows how to use the systemInfo JS API. The installer rejects installations on Windows XP, and OS X 10.6 or older. It shows a warning if it is run on any Linux distribution other than openSUSE 13.2. It also shows only one of the two sub-packages, based on the CPU architecture: "i386" on an 32-bit system, and "x86_64" on an 64-bit system. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/systeminfo/systeminfo.pro0100777000000000000000000000053413761647206022042 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/translations/0040777000000000000000000000000013761647206017437 5ustar00qt-installer-framework-4.0.1/examples/translations/config/0040777000000000000000000000000013761647206020704 5ustar00qt-installer-framework-4.0.1/examples/translations/config/config.xml0100777000000000000000000000053013761647206022671 0ustar00 Translations Example 1.0.0 Package Translations Example Qt Project Qt Installer Framework Examples @HomeDir@/IfwExamples/translations qt-installer-framework-4.0.1/examples/translations/packages/0040777000000000000000000000000013761647206021215 5ustar00qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/0040777000000000000000000000000013761647206024746 5ustar00qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/data/0040777000000000000000000000000013761647206025657 5ustar00././@LongLink0100777000000000000000000000014713761647206010120 Lustar00qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/data/installcontent.txtqt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/data/installcontent.0100777000000000000000000000007313761647206030721 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/0040777000000000000000000000000013761647206025674 5ustar00qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/de.ts0100777000000000000000000000115213761647206026633 0ustar00 Page Translations Example Beispiel fÞr Übersetzungen This is some text. Dies ist ein Text. installscript This is a dynamically created page. Diese Seite wurde dynamisch erzeugt. ././@LongLink0100777000000000000000000000014513761647206010116 Lustar00qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/installscript.qsqt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/installscript.q0100777000000000000000000000406113761647206030752 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { // constructor component.loaded.connect(this, Component.prototype.loaded); installer.addWizardPage(component, "Page", QInstaller.TargetDirectory) } Component.prototype.createOperations = function() { try { // call the base create operations function component.createOperations(); } catch (e) { console.log(e); } } Component.prototype.loaded = function () { var page = gui.pageByObjectName("DynamicPage"); if (page != null) { page.entered.connect(Component.prototype.dynamicPageEntered); } } Component.prototype.dynamicPageEntered = function () { var pageWidget = gui.pageWidgetByObjectName("DynamicPage"); if (pageWidget != null) { pageWidget.m_pageLabel.text = qsTr("This is a dynamically created page."); } } qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/license.txt0100777000000000000000000000012013761647206030050 0ustar00The fantastic license, have you heard of the Beer Public License Agreement yet? qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/license_de.txt0100777000000000000000000000002413761647206030523 0ustar00Lizenz auf deutsch. qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/license_pl.txt0100777000000000000000000000002413761647206030546 0ustar00Licencja po polsku. qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/package.xml0100777000000000000000000000122413761647206030010 0ustar00 The root component This component contains a license and translations to German. 0.5.0-1 2015-01-29 true page.ui de.qm pl.qm qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/page.ui0100777000000000000000000000201413761647206027144 0ustar00 Page 0 0 400 300 Translations Example QFrame::Box Qt::AlignCenter QFrame::Box This is some text. Qt::AlignCenter qt-installer-framework-4.0.1/examples/translations/packages/com.vendor.product/meta/pl.ts0100777000000000000000000000143413761647206026661 0ustar00 Page Translations Example Przykład obrazujący przekład na inny język This is some text. To jest pewien tekst. installscript This is a dynamically created page. Jest to strona utworzona dynamicznie. qt-installer-framework-4.0.1/examples/translations/README0100777000000000000000000000065013761647206020320 0ustar00Shows how to translate the installer UI. You have to call lrelease on the included .ts file before building the installer. Generate installer with binarycreator --offline-only -c config/config.xml -p packages installer You can now run the installer in German. Linux: LANGUAGE=de ./installer On macOS and Windows you need to adapt the system settings to set German as preferred language, and then start the installer. qt-installer-framework-4.0.1/examples/translations/translations.pro0100777000000000000000000000053413761647206022704 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/examples/tutorial/0040777000000000000000000000000013761647206016561 5ustar00qt-installer-framework-4.0.1/examples/tutorial/config/0040777000000000000000000000000013761647206020026 5ustar00qt-installer-framework-4.0.1/examples/tutorial/config/config.xml0100777000000000000000000000047213761647206022020 0ustar00 Your application 1.0.0 Your application Installer Your vendor Super App @HomeDir@/InstallationDirectory qt-installer-framework-4.0.1/examples/tutorial/packages/0040777000000000000000000000000013761647206020337 5ustar00qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/0040777000000000000000000000000013761647206024070 5ustar00qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/data/0040777000000000000000000000000013761647206025001 5ustar00qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/data/installcontent.txt0100777000000000000000000000007313761647206030603 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/meta/0040777000000000000000000000000013761647206025016 5ustar00qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/meta/installscript.qs0100777000000000000000000000451413761647206030262 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Component() { // constructor component.loaded.connect(this, Component.prototype.loaded); if (!installer.addWizardPage(component, "Page", QInstaller.TargetDirectory)) console.log("Could not add the dynamic page."); } Component.prototype.isDefault = function() { // select the component by default return true; } Component.prototype.createOperations = function() { try { // call the base create operations function component.createOperations(); } catch (e) { console.log(e); } } Component.prototype.loaded = function () { var page = gui.pageByObjectName("DynamicPage"); if (page != null) { console.log("Connecting the dynamic page entered signal."); page.entered.connect(Component.prototype.dynamicPageEntered); } } Component.prototype.dynamicPageEntered = function () { var pageWidget = gui.pageWidgetByObjectName("DynamicPage"); if (pageWidget != null) { console.log("Setting the widgets label text.") pageWidget.m_pageLabel.text = "This is a dynamically created page."; } } qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/meta/license.txt0100777000000000000000000000012013761647206027172 0ustar00The fantastic license, have you heard of the Beer Public License Agreement yet? qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/meta/package.xml0100777000000000000000000000076513761647206027143 0ustar00 The root component Install this example. 0.1.0-1 2010-09-21 script page.ui qt-installer-framework-4.0.1/examples/tutorial/packages/com.vendor.product/meta/page.ui0100777000000000000000000000115313761647206026271 0ustar00 Page 0 0 400 300 Dynamic page example Qt::AlignCenter qt-installer-framework-4.0.1/examples/unstablecomponent/0040777000000000000000000000000013761647206020456 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/config/0040777000000000000000000000000013761647206021723 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/config/config.xml0100777000000000000000000000070013761647206023707 0ustar00 Unstable components Example 1.0.0 Unstable components Example Qt-Project Qt IFW Examples @HomeDir@/IfwExamples/unstablecomponent true controller.qs qt-installer-framework-4.0.1/examples/unstablecomponent/config/controller.qs0100777000000000000000000000050013761647206024446 0ustar00function Controller() { installer.unstableComponentFound.connect(unstableComponentFound) } unstableComponentFound = function(type, message, comp) { console.log("Unstable component, type: " + type) console.log("Unstable component, message: " + message) console.log("Unstable component, name: " + comp) } qt-installer-framework-4.0.1/examples/unstablecomponent/packages/0040777000000000000000000000000013761647206022234 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentB/0040777000000000000000000000000013761647206024340 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentB/meta/0040777000000000000000000000000013761647206025266 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentB/meta/package.xml0100777000000000000000000000043513761647206027405 0ustar00 Component B This component does not depend on any other component. 1.0.0 2018-02-02 90 ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissingDependency/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissing0040777000000000000000000000000013761647206031234 5ustar00././@LongLink0040777000000000000000000000016413761647206010122 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissingDependency/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissing0040777000000000000000000000000013761647206031234 5ustar00././@LongLink0100777000000000000000000000017713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissingDependency/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentMissing0100777000000000000000000000072713761647206031244 0ustar00 ComponentDependsonComponentMissingDependency This component depends on component which is depending on component with missing dependency. User is not able to select this component for install. componentMissingDependency 1.0.0 2018-02-02 70 ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInvalidScript/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInv0040777000000000000000000000000013761647206031253 5ustar00././@LongLink0040777000000000000000000000016413761647206010122 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInvalidScript/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInv0040777000000000000000000000000013761647206031253 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInvalidScript/meta/installscript.jsqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInv0100777000000000000000000000247613761647206031266 0ustar00/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { component.addDependency("componentInvalidScipt"); } ././@LongLink0100777000000000000000000000017713761647206010123 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInvalidScript/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentDependsonComponentwithInv0100777000000000000000000000065613761647206031264 0ustar00 Component depends on ComponentWithInvalidScript) Depends on component with invalid script. User is not able to select this component for install. true 1.0.0 2018-02-02 30 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentE/0040777000000000000000000000000013761647206024343 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentE/meta/0040777000000000000000000000000013761647206025271 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentE/meta/package.xml0100777000000000000000000000052613761647206027411 0ustar00 Component E (forced) This is a forced component that is always installed. true 1.0.0 2018-02-02 60 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF/0040777000000000000000000000000013761647206024344 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1/0040777000000000000000000000000013761647206027140 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0040777000000000000000000000000013761647206031062 5ustar00././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent1/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0040777000000000000000000000000013761647206031062 5ustar00././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0100777000000000000000000000044413761647206031066 0ustar00 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2018-02-02 100 ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent2/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0040777000000000000000000000000013761647206031062 5ustar00././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent2/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0040777000000000000000000000000013761647206031062 5ustar00././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1.subsubcom0100777000000000000000000000044313761647206031065 0ustar00 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2018-02-02 50 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1/meta/0040777000000000000000000000000013761647206030066 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent1/meta/pack0100777000000000000000000000050113761647206030723 0ustar00 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2018-02-02 100 componentA qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2/0040777000000000000000000000000013761647206027141 5ustar00././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent1/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0040777000000000000000000000000013761647206031063 5ustar00././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent1/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0040777000000000000000000000000013761647206031063 5ustar00././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent1/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0100777000000000000000000000044413761647206031067 0ustar00 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2018-02-02 100 ././@LongLink0040777000000000000000000000015413761647206010121 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent2/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0040777000000000000000000000000013761647206031063 5ustar00././@LongLink0040777000000000000000000000016113761647206010117 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent2/meta/qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0040777000000000000000000000000013761647206031063 5ustar00././@LongLink0100777000000000000000000000017413761647206010120 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2.subsubcom0100777000000000000000000000044313761647206031066 0ustar00 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2018-02-02 50 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2/meta/0040777000000000000000000000000013761647206030067 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF.subcomponent2/meta/pack0100777000000000000000000000042413761647206030730 0ustar00 Subcomponent 2 This component contains 2 leaf components. 1.0.0 2018-02-02 50 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF/meta/0040777000000000000000000000000013761647206025272 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentF/meta/package.xml0100777000000000000000000000041713761647206027411 0ustar00 Component F This component contains 2 subcomponents. 1.0.0 2018-02-02 40 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentMissingDependency/0040777000000000000000000000000013761647206027567 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentMissingDependency/meta/0040777000000000000000000000000013761647206030515 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentMissingDependency/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentMissingDependency/meta/pa0100777000000000000000000000063713761647206031046 0ustar00 ComponentMissingDependency This component depends on component which does not exists. User is not able to select this component for install. componentDoesnotExists 1.0.0 2018-02-02 80 qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/0040777000000000000000000000000013761647206027404 5ustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/data/0040777000000000000000000000000013761647206030315 5ustar00././@LongLink0100777000000000000000000000016313761647206010116 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/data/installcontent.txtqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/data/ins0100777000000000000000000000007313761647206031031 0ustar00This file will be installed into the target directory.... qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/meta/0040777000000000000000000000000013761647206030332 5ustar00././@LongLink0100777000000000000000000000016113761647206010114 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/meta/installscript.jsqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/meta/ins0100777000000000000000000000245113761647206031050 0ustar00/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { component.invalidScriptCall() } ././@LongLink0100777000000000000000000000015413761647206010116 Lustar00qt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/meta/package.xmlqt-installer-framework-4.0.1/examples/unstablecomponent/packages/componentWithInvalidScipt/meta/pac0100777000000000000000000000057113761647206031023 0ustar00 ComponentWithInvalidScript This component has an invalid script. User is not able to select this component for install. 1.0.0 2018-02-02 100 qt-installer-framework-4.0.1/examples/unstablecomponent/README0100777000000000000000000000025413761647206021337 0ustar00Shows how to setup an installer that allows install even if there are broken components Generate installer with: binarycreator -c config/config.xml -p packages installer qt-installer-framework-4.0.1/examples/unstablecomponent/unstablecomponent.pro0100777000000000000000000000053413761647206024742 0ustar00TEMPLATE = aux INSTALLER = installer INPUT = $$PWD/config/config.xml $$PWD/packages example.input = INPUT example.output = $$INSTALLER example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT} example.CONFIG += target_predeps no_link combine QMAKE_EXTRA_COMPILERS += example OTHER_FILES = README qt-installer-framework-4.0.1/INSTALL0100777000000000000000000000422013761647206014127 0ustar00How to build ===================== The instructions should help you build the Installer Framework from scratch. Get the sources --------------------- Use Git to check out the Qt Installer Framework sources that are hosted at: http://code.qt.io/cgit/installer-framework/installer-framework.git/ Build a static Qt --------------------- Building the Qt Installer Framework from sources requires at least Qt version 5.12.7. Supported compilers are MSVC 2013 or newer, GCC 4.7 or newer, and Clang 3.1 or newer. Currently, the tested combination for Windows is Qt 5.12.7 with MSVC 2015. If you want to ship your installer as a single file you have to build Qt and the Qt Installer Framework statically. See the Qt documentation for the prerequisites and steps to build Qt from sources. Please read SSL Import and Export Restrictions from http://doc.qt.io/qt-5/ssl.html if you are statically linking against OpenSSL libraries. ### Windows Recommended configuration options for Microsoft Windows: configure -prefix %CD%\qtbase -release -static -static-runtime -accessibility -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests Build Qt: nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras ### Linux Recommended configuration options for Linux: configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev Build Qt: make module-qtbase module-qtdeclarative module-qttools module-qttranslations ### macOS Recommended configuration options for macOS: configure -prefix $PWD/qtbase -release -static -no-securetransport -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -no-freetype Build Qt: make module-qtbase module-qtdeclarative module-qttools module-qttranslations Build the Framework --------------------- Run 'qmake && make' (or 'mingw32-make', 'nmake' ...) to build the Qt Installer Framework. The documentation can be generated by 'make docs'. qt-installer-framework-4.0.1/installerfw.pri0100777000000000000000000001030413761647206016144 0ustar00!isEmpty(IFW_PRI_INCLUDED) { error("installerfw.pri already included") } IFW_PRI_INCLUDED = 1 IFW_VERSION_STR = 4.0.1 IFW_VERSION = 0x040001 IFW_VERSION_WIN32 = 4,0,1,0 IFW_VERSION_STR_WIN32 = $$IFW_VERSION_STR\0 IFW_REPOSITORY_FORMAT_VERSION = 1.0.0 IFW_NEWLINE = $$escape_expand(\\n\\t) isEmpty(IFW_DISABLE_TRANSLATIONS): IFW_DISABLE_TRANSLATIONS = $$(IFW_DISABLE_TRANSLATIONS) isEqual(IFW_DISABLE_TRANSLATIONS, 1) { DEFINES += IFW_DISABLE_TRANSLATIONS } defineTest(minQtVersion) { maj = $$1 min = $$2 patch = $$3 isEqual(QT_MAJOR_VERSION, $$maj) { isEqual(QT_MINOR_VERSION, $$min) { isEqual(QT_PATCH_VERSION, $$patch) { return(true) } greaterThan(QT_PATCH_VERSION, $$patch) { return(true) } } greaterThan(QT_MINOR_VERSION, $$min) { return(true) } } greaterThan(QT_MAJOR_VERSION, $$maj) { return(true) } return(false) } defineReplace(toNativeSeparators) { return($$replace(1, /, $$QMAKE_DIR_SEP)) } defineReplace(fromNativeSeparators) { return($$replace(1, \\\\, /)) } defineReplace(cleanPath) { win32:1 ~= s|\\\\|/|g contains(1, ^/.*):pfx = / else:pfx = segs = $$split(1, /) out = for(seg, segs) { equals(seg, ..):out = $$member(out, 0, -2) else:!equals(seg, .):out += $$seg } return($$join(out, /, $$pfx)) } isEmpty(IFW_BUILD_TREE) { sub_dir = $$_PRO_FILE_PWD_ sub_dir ~= s,^$$re_escape($$PWD),, IFW_BUILD_TREE = $$cleanPath($$OUT_PWD) IFW_BUILD_TREE ~= s,$$re_escape($$sub_dir)$,, } IFW_SOURCE_TREE = $$PWD IFW_APP_PATH = $$IFW_BUILD_TREE/bin isEmpty(IFW_LIB_PATH) { IFW_LIB_PATH = $$IFW_BUILD_TREE/lib } RCC = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_BINS]/rcc)) LRELEASE = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_BINS]/lrelease)) LUPDATE = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_BINS]/lupdate)) LCONVERT = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_BINS]/lconvert)) QMAKE_BINARY = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_BINS]/qmake)) win32 { RCC = $${RCC}.exe LRELEASE = $${LRELEASE}.exe LUPDATE = $${LUPDATE}.exe LCONVERT = $${LCONVERT}.exe QMAKE_BINARY = $${QMAKE_BINARY}.exe } win32-g++*:QMAKE_CXXFLAGS += -Wno-attributes macx:QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden INCLUDEPATH += \ $$IFW_SOURCE_TREE/src/libs/7zip \ $$IFW_SOURCE_TREE/src/libs/kdtools \ $$IFW_SOURCE_TREE/src/libs/installer win32:INCLUDEPATH += $$IFW_SOURCE_TREE/src/libs/7zip/win/CPP unix:INCLUDEPATH += $$IFW_SOURCE_TREE/src/libs/7zip/unix/CPP LIBS += -L$$IFW_LIB_PATH # The order is important. The linker needs to parse archives in reversed dependency order. equals(TEMPLATE, app):LIBS += -linstaller win32:equals(TEMPLATE, app) { LIBS += -luser32 } unix:!macx:LIBS += -lutil macx:LIBS += -framework Carbon -framework Security # # Qt 5 sets QT_CONFIG # Use same static/shared configuration as Qt # !contains(CONFIG, static|shared) { contains(QT_CONFIG, static): CONFIG += static contains(QT_CONFIG, shared): CONFIG += shared } QT += uitools core-private CONFIG(static, static|shared) { win32:QT += winextras QT += concurrent network qml xml } CONFIG += depend_includepath no_private_qt_headers_warning c++11 win32:CONFIG += console exists(".git") { GIT_SHA1 = $$system(git rev-list --abbrev-commit -n1 HEAD) } isEmpty(GIT_SHA1) { # Attempt to read the sha1 from alternative location GIT_SHA1=\"$$cat(.tag)\" } DEFINES += NOMINMAX QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATORS QT_USE_QSTRINGBUILDER \ "_GIT_SHA1_=$$GIT_SHA1" \ IFW_VERSION_STR=$$IFW_VERSION_STR \ IFW_VERSION=$$IFW_VERSION \ IFW_VERSION_STR_WIN32=$$IFW_VERSION_STR_WIN32 \ IFW_VERSION_WIN32=$$IFW_VERSION_WIN32 DEFINES += IFW_REPOSITORY_FORMAT_VERSION=$$IFW_REPOSITORY_FORMAT_VERSION LIBS += -l7z win32-g++*: LIBS += -lmpr -luuid equals(TEMPLATE, app) { msvc:POST_TARGETDEPS += $$IFW_LIB_PATH/installer.lib $$IFW_LIB_PATH/7z.lib win32-g++*:POST_TARGETDEPS += $$IFW_LIB_PATH/libinstaller.a $$IFW_LIB_PATH/lib7z.a unix:POST_TARGETDEPS += $$IFW_LIB_PATH/libinstaller.a $$IFW_LIB_PATH/lib7z.a } qt-installer-framework-4.0.1/installerfw.pro0100777000000000000000000000111413761647206016151 0ustar00TEMPLATE = subdirs SUBDIRS += src tools doc tools.depends = src requires(!cross_compile) include (installerfw.pri) BUILD_TESTS = $$(BUILDTESTS) isEmpty(BUILD_TESTS):BUILD_TESTS=$${BUILDTESTS} !isEmpty(BUILD_TESTS) { SUBDIRS += tests tests.depends = src } BUILD_EXAMPLES = $$(BUILDEXAMPLES) isEmpty(BUILD_EXAMPLES):BUILD_EXAMPLES=$${BUILDEXAMPLES} !isEmpty(BUILD_EXAMPLES) { SUBDIRS += examples examples.depends = src } !minQtVersion(5, 12, 7) { message("Cannot build Qt Installer Framework with Qt version $${QT_VERSION}.") error("Use at least Qt 5.12.7.") } qt-installer-framework-4.0.1/LICENSE.FDL0100777000000000000000000005466113761647206014525 0ustar00 GNU Free Documentation License Version 1.3, 3 November 2008 Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. The "publisher" means any person or entity that distributes copies of the Document to the public. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License. However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING "Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site. "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. "Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document. An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008. The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. qt-installer-framework-4.0.1/LICENSE.GPL3-EXCEPT0100777000000000000000000010701313761647206015601 0ustar00This is the GNU General Public License version 3, annotated with The Qt Company GPL Exception 1.0: ------------------------------------------------------------------------- The Qt Company GPL Exception 1.0 Exception 1: As a special exception you may create a larger work which contains the output of this application and distribute that work under terms of your choice, so long as the work is not otherwise derived from or based on this application and so long as the work does not in itself generate output that contains the output from this application in its original or modified form. Exception 2: As a special exception, you have permission to combine this application with Plugins licensed under the terms of your choice, to produce an executable, and to copy and distribute the resulting executable under the terms of your choice. However, the executable must be accompanied by a prominent notice offering all users of the executable the entire source code to this application, excluding the source code of the independent modules, but including any changes you have made to this application, under the terms of this license. ------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qt-installer-framework-4.0.1/no_app_bundle.pri0100777000000000000000000000024413761647206016421 0ustar00!isEmpty(NO_APP_BUNDLE_PRI_INCLUDED) { error("no_app_bundle.pri already included") } NO_APP_BUNDLE_PRI_INCLUDED = 1 equals(TEMPLATE, app):CONFIG -= app_bundle qt-installer-framework-4.0.1/pax_global_header0100777000000000000000000000006413761647206016443 0ustar0052 comment=457a4a6c203c030b48ad9d9ef34d5b17d5158526 qt-installer-framework-4.0.1/product_dependencies.yaml0100777000000000000000000000006413761647206020152 0ustar00dependencies: ../../qt/qt5.git: ref: "5.12.7" qt-installer-framework-4.0.1/README0100777000000000000000000000153113761647206013760 0ustar00The Qt Installer Framework provides a set of tools and utilities to create installers for the supported desktop Qt platforms: Linux, Microsoft Windows, and macOS. Documentation -------------------------- The binary packages for the Qt Installer Framework include documentation in the doc directory. The documentation is also available online at https://doc.qt.io/qtinstallerframework/index.html Notes -------------------------- To build an installer, it is advised to use a statically linked Qt (5.12.7 or newer). The tested and supported Qt version is 5.12.7. See the documentation at https://doc.qt.io/qtinstallerframework/ifw-getting-started.html Getting Help -------------------------- If you think you found a bug, please report it to https://bugreports.qt.io/browse/QTIFW General questions are best asked on interest@qt-project.org. qt-installer-framework-4.0.1/src/0040777000000000000000000000000013761647206013667 5ustar00qt-installer-framework-4.0.1/src/libs/0040777000000000000000000000000013761647206014620 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/0040777000000000000000000000000013761647206015511 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/7zip.pri0100777000000000000000000000121413761647206017114 0ustar00DEFINES += _UNICODE _NO_CRYPTO win32 { 7ZIP_BASE=$$PWD/win INCLUDEPATH += $$7ZIP_BASE/C $$7ZIP_BASE/CPP DEFINES += WIN_LONG_PATH _CRT_SECURE_NO_WARNINGS QMAKE_CXXFLAGS_RELEASE -= -Zc:strictStrings QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -Zc:strictStrings } unix { 7ZIP_BASE=$$PWD/unix INCLUDEPATH += \ $$7ZIP_BASE/C \ $$7ZIP_BASE/CPP \ $$7ZIP_BASE/CPP/myWindows \ $$7ZIP_BASE/CPP/include_windows macx:DEFINES += ENV_MACOSX DEFINES += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE NDEBUG _REENTRANT ENV_UNIX UNICODE } unix|win32-g++* { QMAKE_CFLAGS += -w QMAKE_CXXFLAGS += -w } qt-installer-framework-4.0.1/src/libs/7zip/7zip.pro0100777000000000000000000000044413761647206017126 0ustar00QT = core TARGET = 7z TEMPLATE = lib include(../../../installerfw.pri) INCLUDEPATH += . .. CONFIG += staticlib DESTDIR = $$IFW_LIB_PATH include(7zip.pri) win32:include($$7ZIP_BASE/win.pri) #7zip unix:include($$7ZIP_BASE/unix.pri) #p7zip target.path = $$[QT_INSTALL_LIBS] INSTALLS += target qt-installer-framework-4.0.1/src/libs/7zip/installer_framework_changes.txt0100777000000000000000000000404413761647206024016 0ustar00There are deleted files and very small changes to get the integration process of new versions very simple. --diff-filter=M means "modified" and --diff-filter=D means "deleted" files === output of: git diff --diff-filter=M === diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h index bc2a034..9b8cbd3 100644 --- a/CPP/7zip/Common/RegisterArc.h +++ b/CPP/7zip/Common/RegisterArc.h @@ -27,6 +27,6 @@ void RegisterArc(const CArcInfo *arcInfo); #define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \ - static REGISTER_ARC_NAME(x) g_RegisterArc; - + static REGISTER_ARC_NAME(x) g_RegisterArc; \ + void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #endif diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h index 786b4a4..d53c434 100644 --- a/CPP/7zip/Common/RegisterCodec.h +++ b/CPP/7zip/Common/RegisterCodec.h @@ -22,12 +22,13 @@ void RegisterCodec(const CCodecInfo *codecInfo); #define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \ - static REGISTER_CODEC_NAME(x) g_RegisterCodec; + static REGISTER_CODEC_NAME(x) g_RegisterCodec; \ + void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; } #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x #define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \ REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \ RegisterCodec(&g_CodecsInfo[i]); }}; \ - static REGISTER_CODECS_NAME(x) g_RegisterCodecs; - + static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \ + void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; } #endif diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index eb3c52d..f483e39 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h @@ -7,6 +7,8 @@ #include "MyVector.h" +#include + template inline int MyStringLen(const T *s) { qt-installer-framework-4.0.1/src/libs/7zip/patches/0040777000000000000000000000000013761647206017140 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/patches/0001-Adjust-7z-and-p7z.patch0100777000000000000000000004371213761647206023614 0ustar00From f643c01e4e8534f26a5a2d260caa566d23cdcb13 Mon Sep 17 00:00:00 2001 From: Karsten Heimrich Date: Thu, 4 Jun 2015 15:41:51 +0200 Subject: [PATCH 1/1] Adjust 7z and p7z. Change-Id: I3b96d2b02e5a0908fb4cf5b4262cb33516a10098 --- src/libs/7zip/7zip.pri | 11 ++++- src/libs/7zip/7zip.pro | 14 +----- src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp | 2 - src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h | 32 ++++++++++--- src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h | 29 ++++++++--- src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp | 2 - .../unix/CPP/include_windows/include_windows.pri | 3 ++ .../unix/CPP/myWindows/myCommandLineParser.cpp | 56 ++++++++++++++++++++++ src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp | 42 ++++++++-------- src/libs/7zip/unix/CPP/myWindows/myWindows.pri | 7 +++ src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp | 2 - src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h | 32 ++++++++++--- src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h | 29 ++++++++--- src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp | 2 - 14 files changed, 194 insertions(+), 69 deletions(-) create mode 100644 src/libs/7zip/unix/CPP/include_windows/include_windows.pri create mode 100644 src/libs/7zip/unix/CPP/myWindows/myCommandLineParser.cpp create mode 100644 src/libs/7zip/unix/CPP/myWindows/myWindows.pri diff --git a/src/libs/7zip/7zip.pri b/src/libs/7zip/7zip.pri index 823e3ab..85574ce 100644 --- a/src/libs/7zip/7zip.pri +++ b/src/libs/7zip/7zip.pri @@ -1,7 +1,11 @@ +DEFINES += _UNICODE _NO_CRYPTO + win32 { 7ZIP_BASE=$$PWD/win INCLUDEPATH += $$7ZIP_BASE/C $$7ZIP_BASE/CPP - DEFINES += WIN_LONG_PATH _UNICODE _NO_CRYPTO + DEFINES += WIN_LONG_PATH _CRT_SECURE_NO_WARNINGS + win32-g++*:QMAKE_CXXFLAGS += -w -fvisibility=hidden + QMAKE_CXXFLAGS_RELEASE -= -Zc:strictStrings QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -Zc:strictStrings } @@ -14,6 +18,9 @@ unix { $$7ZIP_BASE/CPP/myWindows \ $$7ZIP_BASE/CPP/include_windows + QMAKE_CFLAGS += -w + QMAKE_CXXFLAGS += -fvisibility=hidden -w + macx:DEFINES += ENV_MACOSX - DEFINES += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE NDEBUG _REENTRANT ENV_UNIX UNICODE _UNICODE _NO_CRYPTO + DEFINES += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE NDEBUG _REENTRANT ENV_UNIX UNICODE } diff --git a/src/libs/7zip/7zip.pro b/src/libs/7zip/7zip.pro index 01b69da..70a51c0 100644 --- a/src/libs/7zip/7zip.pro +++ b/src/libs/7zip/7zip.pro @@ -7,15 +7,5 @@ CONFIG += staticlib DESTDIR = $$IFW_LIB_PATH include(7zip.pri) -win32 { - DEFINES += _CRT_SECURE_NO_WARNINGS - win32-g++*:QMAKE_CXXFLAGS += -w -fvisibility=hidden - CONFIG += no_batch # this is needed because we have a same named *.c and *.cpp file -> 7in - include($$7ZIP_BASE/win.pri) #this is 7zip -} - -unix { - QMAKE_CFLAGS += -w - QMAKE_CXXFLAGS += -fvisibility=hidden -w - include($$7ZIP_BASE/unix.pri) #this is p7zip -} +win32:include($$7ZIP_BASE/win.pri) #7zip +unix:include($$7ZIP_BASE/unix.pri) #p7zip diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp index 8af28b9..e20858e 100644 --- a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp +++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp @@ -4,8 +4,6 @@ #include "../../../../C/7zCrc.h" -#include "../../../Common/AutoPtr.h" - #include "../../Common/StreamObjects.h" #include "7zOut.h" diff --git a/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h b/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h index 1e9bf14..82bd096 100644 --- a/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h +++ b/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h @@ -5,6 +5,8 @@ #include "../Archive/IArchive.h" +#include + struct CArcInfo { const char *Name; @@ -24,19 +26,35 @@ struct CArcInfo Func_IsArc IsArc; bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } + + std::once_flag once; }; void RegisterArc(const CArcInfo *arcInfo) throw(); #define REGISTER_ARC_NAME(x) CRegister ## x -#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \ - REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \ - static REGISTER_ARC_NAME(x) g_RegisterArc; - -#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) { \ - REGISTER_ARC_NAME(x)() { g_ArcInfo.Signature[0]--; RegisterArc(&g_ArcInfo); }}; \ - static REGISTER_ARC_NAME(x) g_RegisterArc; +#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) \ + { \ + REGISTER_ARC_NAME(x)() \ + { \ + std::call_once(g_ArcInfo.once, [] { RegisterArc(&g_ArcInfo); }); \ + } \ + }; \ + static REGISTER_ARC_NAME(x) g_RegisterArc; \ + void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } + +#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) \ + { \ + REGISTER_ARC_NAME(x)() { \ + std::call_once(g_ArcInfo.once, [] { \ + g_ArcInfo.Signature[0]--; \ + RegisterArc(&g_ArcInfo); \ + }); \ + } \ + }; \ + static REGISTER_ARC_NAME(x) g_RegisterArc; \ + void registerArcDec##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define IMP_CreateArcIn_2(c) \ diff --git a/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h b/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h index 4222a30..0c6662a 100644 --- a/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h +++ b/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h @@ -6,6 +6,8 @@ #include "../Common/MethodId.h" #include "../ICoder.h" +#include + typedef void * (*CreateCodecP)(); struct CCodecInfo { @@ -15,21 +17,34 @@ struct CCodecInfo const wchar_t *Name; UInt32 NumInStreams; bool IsFilter; + std::once_flag once; }; void RegisterCodec(const CCodecInfo *codecInfo) throw(); #define REGISTER_CODEC_NAME(x) CRegisterCodec ## x -#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \ - REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \ - static REGISTER_CODEC_NAME(x) g_RegisterCodec; +#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) \ + { \ + REGISTER_CODEC_NAME(x)() \ + { \ + std::call_once(g_CodecInfo.once, [] { RegisterCodec(&g_CodecInfo); }); \ + } \ + }; \ + static REGISTER_CODEC_NAME(x) g_RegisterCodec; \ + void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; } #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x -#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \ - REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ - RegisterCodec(&g_CodecsInfo[i]); }}; \ - static REGISTER_CODECS_NAME(x) g_RegisterCodecs; +#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) \ + { \ + REGISTER_CODECS_NAME(x)() \ + { \ + for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ + std::call_once(g_CodecsInfo[i].once, [&i] { RegisterCodec(&g_CodecsInfo[i]); }); \ + } \ + }; \ + static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \ + void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; } struct CHasherInfo diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp index 03f31fa..5f94254 100644 --- a/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp +++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "../../../../C/Sort.h" - #include "../../../Common/StringConvert.h" #include "../../../Windows/FileDir.h" diff --git a/src/libs/7zip/unix/CPP/include_windows/include_windows.pri b/src/libs/7zip/unix/CPP/include_windows/include_windows.pri new file mode 100644 index 0000000..5ef72fd --- /dev/null +++ b/src/libs/7zip/unix/CPP/include_windows/include_windows.pri @@ -0,0 +1,3 @@ +HEADERS += $$7ZIP_BASE/CPP/include_windows/basetyps.h \ + $$7ZIP_BASE/CPP/include_windows/tchar.h \ + $$7ZIP_BASE/CPP/include_windows/windows.h diff --git a/src/libs/7zip/unix/CPP/myWindows/myCommandLineParser.cpp b/src/libs/7zip/unix/CPP/myWindows/myCommandLineParser.cpp new file mode 100644 index 0000000..5d7f6fd --- /dev/null +++ b/src/libs/7zip/unix/CPP/myWindows/myCommandLineParser.cpp @@ -0,0 +1,56 @@ +/************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "../CPP/Common/MyString.h" + +#include + +namespace NCommandLineParser { + +void SplitCommandLine(const UString &s, UStringVector &parts) +{ + parts.Clear(); + + const QString cmdLine = QString::fromStdWString(static_cast(s)); + const QStringList args = cmdLine.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); + foreach (QString arg, args) { + if (arg.startsWith(QLatin1Char('\"'))) + arg = arg.mid(1); + if (arg.endsWith(QLatin1Char('\"'))) + arg = arg.mid(1); + parts.Add(arg.toStdWString().c_str()); + } +} + +} // namespace NCommandLineParser diff --git a/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp b/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp index 96554c9..9ebfe37 100644 --- a/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp +++ b/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp @@ -32,19 +32,18 @@ ** **************************************************************************/ -#include -#include #include "windows.h" +#include + void FileTimeToDateTime(const FILETIME *source, QDateTime *target) { ULARGE_INTEGER store; - QDateTime tempDateTime(QDate(1601, 1, 1)); - store.QuadPart = source->dwHighDateTime; store.QuadPart = store.QuadPart << 32; store.QuadPart += source->dwLowDateTime; + const QDateTime tempDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 0), Qt::UTC); *target = tempDateTime.addMSecs(store.QuadPart / 10000); } @@ -60,6 +59,13 @@ void DateTimeToSystemTime(const QDateTime *source, SYSTEMTIME *target) target->wMilliseconds = source->time().msec(); } +void DateTimeToFileTime(const QDateTime &dateTime, FILETIME *target) +{ + const qint64 nsecs = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 0), Qt::UTC) + .msecsTo(dateTime) * 10000; + target->dwLowDateTime = nsecs; + target->dwHighDateTime = nsecs >> 32; +} BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *source,SYSTEMTIME *target) { @@ -70,21 +76,6 @@ BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *source,SYSTEMTIME *target) return TRUE; } -BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME *source,FILETIME *target) -{ - // TODO: Implementation! - // This doesn't seem to be called at all - - qDebug() << "SystemTimeToFileTime"; - - target->dwHighDateTime = 0; - target->dwLowDateTime = 0; - - qWarning() << Q_FUNC_INFO; - - return TRUE; -} - BOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *source,FILETIME *target) { target->dwHighDateTime = source->dwHighDateTime; @@ -137,3 +128,16 @@ VOID WINAPI GetSystemTime(SYSTEMTIME *st) QDateTime nowDateTime = QDateTime::currentDateTimeUtc(); DateTimeToSystemTime(&nowDateTime, st); } + +VOID WINAPI GetSystemTimeAsFileTime(FILETIME *time) +{ + DateTimeToFileTime(QDateTime::currentDateTimeUtc(), time); +} + +DWORD WINAPI GetTickCount() +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + return DWORD(ts.tv_sec * 1000 + ts.tv_nsec / 1000000); + return DWORD(QDateTime::currentMSecsSinceEpoch()); +} diff --git a/src/libs/7zip/unix/CPP/myWindows/myWindows.pri b/src/libs/7zip/unix/CPP/myWindows/myWindows.pri new file mode 100644 index 0000000..0875fdb --- /dev/null +++ b/src/libs/7zip/unix/CPP/myWindows/myWindows.pri @@ -0,0 +1,7 @@ +HEADERS += $$7ZIP_BASE/CPP/myWindows/StdAfx.h \ + $$7ZIP_BASE/CPP/myWindows/config.h \ + $$7ZIP_BASE/CPP/myWindows/initguid.h \ + $$7ZIP_BASE/CPP/myWindows/myPrivate.h + +SOURCES += $$7ZIP_BASE/CPP/myWindows/myDateAndTime.cpp \ + $$7ZIP_BASE/CPP/myWindows/myCommandLineParser.cpp diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp index 8af28b9..e20858e 100644 --- a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp @@ -4,8 +4,6 @@ #include "../../../../C/7zCrc.h" -#include "../../../Common/AutoPtr.h" - #include "../../Common/StreamObjects.h" #include "7zOut.h" diff --git a/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h b/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h index 1e9bf14..82bd096 100644 --- a/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h +++ b/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h @@ -5,6 +5,8 @@ #include "../Archive/IArchive.h" +#include + struct CArcInfo { const char *Name; @@ -24,19 +26,35 @@ struct CArcInfo Func_IsArc IsArc; bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } + + std::once_flag once; }; void RegisterArc(const CArcInfo *arcInfo) throw(); #define REGISTER_ARC_NAME(x) CRegister ## x -#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \ - REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \ - static REGISTER_ARC_NAME(x) g_RegisterArc; - -#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) { \ - REGISTER_ARC_NAME(x)() { g_ArcInfo.Signature[0]--; RegisterArc(&g_ArcInfo); }}; \ - static REGISTER_ARC_NAME(x) g_RegisterArc; +#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) \ + { \ + REGISTER_ARC_NAME(x)() \ + { \ + std::call_once(g_ArcInfo.once, [] { RegisterArc(&g_ArcInfo); }); \ + } \ + }; \ + static REGISTER_ARC_NAME(x) g_RegisterArc; \ + void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } + +#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) \ + { \ + REGISTER_ARC_NAME(x)() { \ + std::call_once(g_ArcInfo.once, [] { \ + g_ArcInfo.Signature[0]--; \ + RegisterArc(&g_ArcInfo); \ + }); \ + } \ + }; \ + static REGISTER_ARC_NAME(x) g_RegisterArc; \ + void registerArcDec##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define IMP_CreateArcIn_2(c) \ diff --git a/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h b/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h index 4222a30..0c6662a 100644 --- a/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h +++ b/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h @@ -6,6 +6,8 @@ #include "../Common/MethodId.h" #include "../ICoder.h" +#include + typedef void * (*CreateCodecP)(); struct CCodecInfo { @@ -15,21 +17,34 @@ struct CCodecInfo const wchar_t *Name; UInt32 NumInStreams; bool IsFilter; + std::once_flag once; }; void RegisterCodec(const CCodecInfo *codecInfo) throw(); #define REGISTER_CODEC_NAME(x) CRegisterCodec ## x -#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \ - REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \ - static REGISTER_CODEC_NAME(x) g_RegisterCodec; +#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) \ + { \ + REGISTER_CODEC_NAME(x)() \ + { \ + std::call_once(g_CodecInfo.once, [] { RegisterCodec(&g_CodecInfo); }); \ + } \ + }; \ + static REGISTER_CODEC_NAME(x) g_RegisterCodec; \ + void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; } #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x -#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \ - REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ - RegisterCodec(&g_CodecsInfo[i]); }}; \ - static REGISTER_CODECS_NAME(x) g_RegisterCodecs; +#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) \ + { \ + REGISTER_CODECS_NAME(x)() \ + { \ + for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ + std::call_once(g_CodecsInfo[i].once, [&i] { RegisterCodec(&g_CodecsInfo[i]); }); \ + } \ + }; \ + static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \ + void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; } struct CHasherInfo diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp index df86620..13d2ad2 100644 --- a/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "../../../../C/Sort.h" - #include "../../../Common/StringConvert.h" #include "../../../Windows/FileDir.h" -- 2.3.7.windows.1 qt-installer-framework-4.0.1/src/libs/7zip/unix/0040777000000000000000000000000013761647206016474 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/C/0040777000000000000000000000000013761647206016656 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/0040777000000000000000000000000013761647206017116 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/0040777000000000000000000000000013761647206020007 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/7zip.pri0100777000000000000000000000034313761647206021414 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/ICoder.h \ $$7ZIP_BASE/CPP/7zip/IDecl.h \ $$7ZIP_BASE/CPP/7zip/IPassword.h \ $$7ZIP_BASE/CPP/7zip/IProgress.h \ $$7ZIP_BASE/CPP/7zip/IStream.h \ $$7ZIP_BASE/CPP/7zip/PropID.h qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/0040777000000000000000000000000013761647206021370 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/0040777000000000000000000000000013761647206021730 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7z.pri0100777000000000000000000000260713761647206023011 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zCompressionMode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zItem.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zExtract.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandlerOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.h0100777000000000000000000000157113761647206025474 0ustar00// 7zCompressionMode.h #ifndef __7Z_COMPRESSION_MODE_H #define __7Z_COMPRESSION_MODE_H #include "../../Common/MethodId.h" #include "../../Common/MethodProps.h" namespace NArchive { namespace N7z { struct CMethodFull: public CProps { CMethodId Id; UInt32 NumInStreams; UInt32 NumOutStreams; bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; struct CBind { UInt32 InCoder; UInt32 InStream; UInt32 OutCoder; UInt32 OutStream; }; struct CCompressionMethodMode { CObjectVector Methods; CRecordVector Binds; #ifndef _7ZIP_ST UInt32 NumThreads; #endif bool PasswordIsDefined; UString Password; bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } CCompressionMethodMode(): PasswordIsDefined(false) #ifndef _7ZIP_ST , NumThreads(1) #endif {} }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp0100777000000000000000000002453613761647206024112 0ustar00// 7zDecode.cpp #include "StdAfx.h" #include "../../Common/LimitedStreams.h" #include "../../Common/LockedStream.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "7zDecode.h" namespace NArchive { namespace N7z { static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, CBindInfoEx &bindInfo) { bindInfo.Clear(); bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); unsigned i; for (i = 0; i < folder.BindPairs.Size(); i++) { NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; } bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); UInt32 outStreamIndex = 0; for (i = 0; i < folder.Coders.Size(); i++) { NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; const CCoderInfo &coderInfo = folder.Coders[i]; coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) if (folder.FindBindPairForOutStream(outStreamIndex) < 0) bindInfo.OutStreams.Add(outStreamIndex); } bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); for (i = 0; i < folder.PackStreams.Size(); i++) bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; } static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, const NCoderMixer::CCoderStreamsInfo &a2) { return (a1.NumInStreams == a2.NumInStreams) && (a1.NumOutStreams == a2.NumOutStreams); } static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2) { return (a1.InIndex == a2.InIndex) && (a1.OutIndex == a2.OutIndex); } static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) { if (a1.Coders.Size() != a2.Coders.Size()) return false; unsigned i; for (i = 0; i < a1.Coders.Size(); i++) if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) return false; if (a1.BindPairs.Size() != a2.BindPairs.Size()) return false; for (i = 0; i < a1.BindPairs.Size(); i++) if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) return false; for (i = 0; i < a1.CoderMethodIDs.Size(); i++) if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) return false; if (a1.InStreams.Size() != a2.InStreams.Size()) return false; if (a1.OutStreams.Size() != a2.OutStreams.Size()) return false; return true; } CDecoder::CDecoder(bool multiThread) { #ifndef _ST_MODE multiThread = true; #endif _multiThread = multiThread; _bindInfoExPrevIsDefined = false; } HRESULT CDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ) { const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; CFolder folderInfo; folders.ParseFolderInfo(folderIndex, folderInfo); if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) return E_NOTIMPL; /* We don't need to init isEncrypted and passwordIsDefined We must upgrade them only #ifndef _NO_CRYPTO isEncrypted = false; passwordIsDefined = false; #endif */ CObjectVector< CMyComPtr > inStreams; CLockedInStream lockedInStream; lockedInStream.Init(inStream); for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) { CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; CMyComPtr lockedStreamImp = lockedStreamImpSpec; lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStream = streamSpec; streamSpec->SetStream(lockedStreamImp); streamSpec->Init(packPositions[j + 1] - packPositions[j]); inStreams.Add(inStream); } unsigned numCoders = folderInfo.Coders.Size(); CBindInfoEx bindInfo; ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); bool createNewCoders; if (!_bindInfoExPrevIsDefined) createNewCoders = true; else createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); if (createNewCoders) { unsigned i; _decoders.Clear(); // _decoders2.Clear(); _mixerCoder.Release(); if (_multiThread) { _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderMTSpec; _mixerCoderCommon = _mixerCoderMTSpec; } else { #ifdef _ST_MODE _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; _mixerCoder = _mixerCoderSTSpec; _mixerCoderCommon = _mixerCoderSTSpec; #endif } RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr decoder; CMyComPtr decoder2; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS coderInfo.MethodID, decoder, decoder2, false)); CMyComPtr decoderUnknown; if (coderInfo.IsSimpleCoder()) { if (decoder == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder; if (_multiThread) _mixerCoderMTSpec->AddCoder(decoder); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder(decoder, false); #endif } else { if (decoder2 == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder2; if (_multiThread) _mixerCoderMTSpec->AddCoder2(decoder2); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder2(decoder2, false); #endif } _decoders.Add(decoderUnknown); #ifdef EXTERNAL_CODECS CMyComPtr setCompressCodecsInfo; decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif } _bindInfoExPrev = bindInfo; _bindInfoExPrevIsDefined = true; } unsigned i; _mixerCoderCommon->ReInit(); UInt32 packStreamIndex = 0; UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; UInt32 unpackStreamIndex = unpackStreamIndexStart; UInt32 coderIndex = 0; // UInt32 coder2Index = 0; for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr &decoder = _decoders[coderIndex]; { CMyComPtr setDecoderProperties; decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); if (setDecoderProperties) { const CByteBuffer &props = coderInfo.Props; size_t size = props.Size(); if (size > 0xFFFFFFFF) return E_NOTIMPL; // if (size > 0) { RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); } } } #if !defined(_7ZIP_ST) && !defined(_SFX) if (mtMode) { CMyComPtr setCoderMt; decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(numThreads)); } } #endif #ifndef _NO_CRYPTO { CMyComPtr cryptoSetPassword; decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { isEncrypted = true; if (!getTextPassword) return E_NOTIMPL; CMyComBSTR passwordBSTR; RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); passwordIsDefined = true; size_t len = 0; if (passwordBSTR) len = MyStringLen((BSTR)passwordBSTR); CByteBuffer buffer(len * 2); for (size_t i = 0; i < len; i++) { wchar_t c = passwordBSTR[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); } } #endif coderIndex++; UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; CObjArray packSizes(numInStreams); CObjArray packSizesPointers(numInStreams); CObjArray unpackSizesPointers(numOutStreams); UInt32 j; for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; for (j = 0; j < numInStreams; j++, packStreamIndex++) { int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); if (bindPairIndex >= 0) packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; else { int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); if (index < 0) return S_FALSE; // check it packSizes[j] = packPositions[index + 1] - packPositions[index]; packSizesPointers[j] = &packSizes[j]; } } _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); } UInt32 mainCoder, temp; bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); if (_multiThread) _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); /* else _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; */ if (numCoders == 0) return 0; unsigned num = inStreams.Size(); CObjArray inStreamPointers(num); for (i = 0; i < num; i++) inStreamPointers[i] = inStreams[i]; ISequentialOutStream *outStreamPointer = outStream; return _mixerCoder->Code( inStreamPointers, NULL, num, &outStreamPointer, NULL, 1, compressProgress); } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.h0100777000000000000000000000254713761647206023555 0ustar00// 7zDecode.h #ifndef __7Z_DECODE_H #define __7Z_DECODE_H #include "../../IStream.h" #include "../../IPassword.h" #include "../Common/CoderMixer2.h" #include "../Common/CoderMixer2MT.h" #ifdef _ST_MODE #include "../Common/CoderMixer2ST.h" #endif #include "../../Common/CreateCoder.h" #include "7zIn.h" namespace NArchive { namespace N7z { struct CBindInfoEx: public NCoderMixer::CBindInfo { CRecordVector CoderMethodIDs; void Clear() { CBindInfo::Clear(); CoderMethodIDs.Clear(); } }; class CDecoder { bool _bindInfoExPrevIsDefined; CBindInfoEx _bindInfoExPrev; bool _multiThread; #ifdef _ST_MODE NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec; #endif NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec; NCoderMixer::CCoderMixer2 *_mixerCoderCommon; CMyComPtr _mixerCoder; CObjectVector > _decoders; // CObjectVector > _decoders2; public: CDecoder(bool multiThread); HRESULT Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.cpp0100777000000000000000000003357413761647206024126 0ustar00// 7zEncode.cpp #include "StdAfx.h" #include "../../Common/CreateCoder.h" #include "../../Common/FilterCoder.h" #include "../../Common/LimitedStreams.h" #include "../../Common/InOutTempBuffer.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "7zEncode.h" #include "7zSpecStream.h" static const UInt64 k_Delta = 0x03; static const UInt64 k_BCJ = 0x03030103; static const UInt64 k_BCJ2 = 0x0303011B; namespace NArchive { namespace N7z { static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo, const CRecordVector decompressionMethods, CFolder &folder) { // bindInfo.CoderMethodIDs.Clear(); // folder.OutStreams.Clear(); folder.BindPairs.SetSize(bindInfo.BindPairs.Size()); unsigned i; for (i = 0; i < bindInfo.BindPairs.Size(); i++) { CBindPair &bp = folder.BindPairs[i]; const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i]; bp.InIndex = mixerBp.InIndex; bp.OutIndex = mixerBp.OutIndex; } folder.Coders.SetSize(bindInfo.Coders.Size()); for (i = 0; i < bindInfo.Coders.Size(); i++) { CCoderInfo &coderInfo = folder.Coders[i]; const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; coderInfo.MethodID = decompressionMethods[i]; // coderInfo.Props can be nonFree; } folder.PackStreams.SetSize(bindInfo.InStreams.Size()); for (i = 0; i < bindInfo.InStreams.Size(); i++) folder.PackStreams[i] = bindInfo.InStreams[i]; } static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) { CMyComPtr setCoderProperties; coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); if (setCoderProperties) return props.SetCoderProps(setCoderProperties, dataSizeReduce); return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; } HRESULT CEncoder::CreateMixerCoder( DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce) { _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderSpec; RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); FOR_VECTOR (i, _options.Methods) { const CMethodFull &methodFull = _options.Methods[i]; CCoderInfo &encodingInfo = _codersInfo.AddNew(); encodingInfo.MethodID = methodFull.Id; CMyComPtr encoder; CMyComPtr encoder2; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS methodFull.Id, encoder, encoder2, true)); if (!encoder && !encoder2) return E_FAIL; CMyComPtr encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2; #ifndef _7ZIP_ST { CMyComPtr setCoderMt; encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); } } #endif RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); /* CMyComPtr resetSalt; encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); if (resetSalt) { resetSalt->ResetSalt(); } */ #ifdef EXTERNAL_CODECS CMyComPtr setCompressCodecsInfo; encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif CMyComPtr cryptoSetPassword; encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { const UInt32 sizeInBytes = _options.Password.Len() * 2; CByteBuffer buffer(sizeInBytes); for (unsigned i = 0; i < _options.Password.Len(); i++) { wchar_t c = _options.Password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); } if (encoder) _mixerCoderSpec->AddCoder(encoder); else _mixerCoderSpec->AddCoder2(encoder2); } return S_OK; } HRESULT CEncoder::Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector &coderUnpackSizes, UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector &packSizes, ICompressProgressInfo *compressProgress) { RINOK(EncoderConstr()); if (!_mixerCoderSpec) { RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); } _mixerCoderSpec->ReInit(); // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); CObjectVector inOutTempBuffers; CObjectVector tempBufferSpecs; CObjectVector > tempBuffers; unsigned numMethods = _bindInfo.Coders.Size(); unsigned i; for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CInOutTempBuffer &iotb = inOutTempBuffers.AddNew(); iotb.Create(); iotb.InitWriting(); } for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp; CMyComPtr tempBuffer = tempBufferSpec; tempBufferSpec->Init(&inOutTempBuffers[i - 1]); tempBuffers.Add(tempBuffer); tempBufferSpecs.Add(tempBufferSpec); } for (i = 0; i < numMethods; i++) _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); if (_bindInfo.InStreams.IsEmpty()) return E_FAIL; UInt32 mainCoderIndex, mainStreamIndex; _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); if (inStreamSize) { CRecordVector sizePointers; for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) if (i == mainStreamIndex) sizePointers.Add(inStreamSize); else sizePointers.Add(NULL); _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL); } // UInt64 outStreamStartPos; // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; CMyComPtr outStreamSizeCount; inStreamSizeCountSpec->Init(inStream); CRecordVector inStreamPointers; CRecordVector outStreamPointers; inStreamPointers.Add(inStreamSizeCount); if (_bindInfo.OutStreams.Size() != 0) { outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; outStreamSizeCount = outStreamSizeCountSpec; outStreamSizeCountSpec->SetStream(outStream); outStreamSizeCountSpec->Init(); outStreamPointers.Add(outStreamSizeCount); } for (i = 1; i < _bindInfo.OutStreams.Size(); i++) outStreamPointers.Add(tempBuffers[i - 1]); for (i = 0; i < _codersInfo.Size(); i++) { CCoderInfo &encodingInfo = _codersInfo[i]; CMyComPtr resetInitVector; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); if (resetInitVector) { resetInitVector->ResetInitVector(); } CMyComPtr writeCoderProperties; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); if (writeCoderProperties) { CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; CMyComPtr outStream(outStreamSpec); outStreamSpec->Init(); writeCoderProperties->WriteCoderProperties(outStream); outStreamSpec->CopyToBuffer(encodingInfo.Props); } } UInt32 progressIndex = mainCoderIndex; for (i = 0; i + 1 < _codersInfo.Size(); i++) { UInt64 m = _codersInfo[i].MethodID; if (m == k_Delta || m == k_BCJ || m == k_BCJ2) progressIndex = i + 1; } _mixerCoderSpec->SetProgressCoderIndex(progressIndex); RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); if (_bindInfo.OutStreams.Size() != 0) packSizes.Add(outStreamSizeCountSpec->GetSize()); for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; RINOK(inOutTempBuffer.WriteToStream(outStream)); packSizes.Add(inOutTempBuffer.GetDataSize()); } unpackSize = 0; for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) { int binder = _bindInfo.FindBinderForInStream( _bindReverseConverter->DestOutToSrcInMap[i]); UInt64 streamSize; if (binder < 0) { streamSize = inStreamSizeCountSpec->GetSize(); unpackSize = streamSize; } else streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); coderUnpackSizes.Add(streamSize); } for (i = 0; i < numMethods; i++) folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; return S_OK; } CEncoder::CEncoder(const CCompressionMethodMode &options): _bindReverseConverter(0), _constructed(false) { if (options.IsEmpty()) throw 1; _options = options; _mixerCoderSpec = NULL; } HRESULT CEncoder::EncoderConstr() { if (_constructed) return S_OK; if (_options.Methods.IsEmpty()) { // it has only password method; if (!_options.PasswordIsDefined) throw 1; if (!_options.Binds.IsEmpty()) throw 1; NCoderMixer::CCoderStreamsInfo coderStreamsInfo; CMethodFull method; method.NumInStreams = 1; method.NumOutStreams = 1; coderStreamsInfo.NumInStreams = 1; coderStreamsInfo.NumOutStreams = 1; method.Id = k_AES; _options.Methods.Add(method); _bindInfo.Coders.Add(coderStreamsInfo); _bindInfo.InStreams.Add(0); _bindInfo.OutStreams.Add(0); } else { UInt32 numInStreams = 0, numOutStreams = 0; unsigned i; for (i = 0; i < _options.Methods.Size(); i++) { const CMethodFull &methodFull = _options.Methods[i]; NCoderMixer::CCoderStreamsInfo coderStreamsInfo; coderStreamsInfo.NumInStreams = methodFull.NumOutStreams; coderStreamsInfo.NumOutStreams = methodFull.NumInStreams; if (_options.Binds.IsEmpty()) { if (i < _options.Methods.Size() - 1) { NCoderMixer::CBindPair bindPair; bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; bindPair.OutIndex = numOutStreams; _bindInfo.BindPairs.Add(bindPair); } else if (coderStreamsInfo.NumOutStreams != 0) _bindInfo.OutStreams.Insert(0, numOutStreams); for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) _bindInfo.OutStreams.Add(numOutStreams + j); } numInStreams += coderStreamsInfo.NumInStreams; numOutStreams += coderStreamsInfo.NumOutStreams; _bindInfo.Coders.Add(coderStreamsInfo); } if (!_options.Binds.IsEmpty()) { for (i = 0; i < _options.Binds.Size(); i++) { NCoderMixer::CBindPair bindPair; const CBind &bind = _options.Binds[i]; bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream; bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream; _bindInfo.BindPairs.Add(bindPair); } for (i = 0; i < (int)numOutStreams; i++) if (_bindInfo.FindBinderForOutStream(i) == -1) _bindInfo.OutStreams.Add(i); } for (i = 0; i < (int)numInStreams; i++) if (_bindInfo.FindBinderForInStream(i) == -1) _bindInfo.InStreams.Add(i); if (_bindInfo.InStreams.IsEmpty()) throw 1; // this is error // Make main stream first in list int inIndex = _bindInfo.InStreams[0]; for (;;) { UInt32 coderIndex, coderStreamIndex; _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); int binder = _bindInfo.FindBinderForOutStream(outIndex); if (binder >= 0) { inIndex = _bindInfo.BindPairs[binder].InIndex; continue; } for (i = 0; i < _bindInfo.OutStreams.Size(); i++) if (_bindInfo.OutStreams[i] == outIndex) { _bindInfo.OutStreams.Delete(i); _bindInfo.OutStreams.Insert(0, outIndex); break; } break; } if (_options.PasswordIsDefined) { unsigned numCryptoStreams = _bindInfo.OutStreams.Size(); for (i = 0; i < numCryptoStreams; i++) { NCoderMixer::CBindPair bindPair; bindPair.InIndex = numInStreams + i; bindPair.OutIndex = _bindInfo.OutStreams[i]; _bindInfo.BindPairs.Add(bindPair); } _bindInfo.OutStreams.Clear(); /* if (numCryptoStreams == 0) numCryptoStreams = 1; */ for (i = 0; i < numCryptoStreams; i++) { NCoderMixer::CCoderStreamsInfo coderStreamsInfo; CMethodFull method; method.NumInStreams = 1; method.NumOutStreams = 1; coderStreamsInfo.NumInStreams = method.NumOutStreams; coderStreamsInfo.NumOutStreams = method.NumInStreams; method.Id = k_AES; _options.Methods.Add(method); _bindInfo.Coders.Add(coderStreamsInfo); _bindInfo.OutStreams.Add(numOutStreams + i); } } } for (int i = _options.Methods.Size() - 1; i >= 0; i--) { const CMethodFull &methodFull = _options.Methods[i]; _decompressionMethods.Add(methodFull.Id); } _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); _constructed = true; return S_OK; } CEncoder::~CEncoder() { delete _bindReverseConverter; } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.h0100777000000000000000000000252113761647206023557 0ustar00// 7zEncode.h #ifndef __7Z_ENCODE_H #define __7Z_ENCODE_H // #include "../../Common/StreamObjects.h" #include "7zCompressionMode.h" #include "../Common/CoderMixer2.h" #include "../Common/CoderMixer2MT.h" #ifdef _ST_MODE #include "../Common/CoderMixer2ST.h" #endif #include "7zItem.h" #include "../../Common/CreateCoder.h" namespace NArchive { namespace N7z { class CEncoder { NCoderMixer::CCoderMixer2MT *_mixerCoderSpec; CMyComPtr _mixerCoder; CObjectVector _codersInfo; CCompressionMethodMode _options; NCoderMixer::CBindInfo _bindInfo; NCoderMixer::CBindInfo _decompressBindInfo; NCoderMixer::CBindReverseConverter *_bindReverseConverter; CRecordVector _decompressionMethods; HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce); bool _constructed; public: CEncoder(const CCompressionMethodMode &options); ~CEncoder(); HRESULT EncoderConstr(); HRESULT Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector &coderUnpackSizes, UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector &packSizes, ICompressProgressInfo *compressProgress); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zExtract.cpp0100777000000000000000000001521113761647206024327 0ustar00// 7zExtract.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../Common/ProgressUtils.h" #include "7zDecode.h" // #include "7z1Decode.h" #include "7zFolderOutStream.h" #include "7zHandler.h" namespace NArchive { namespace N7z { struct CExtractFolderInfo { #ifdef _7Z_VOL int VolumeIndex; #endif CNum FileIndex; CNum FolderIndex; CBoolVector ExtractStatuses; UInt64 UnpackSize; CExtractFolderInfo( #ifdef _7Z_VOL int volumeIndex, #endif CNum fileIndex, CNum folderIndex): #ifdef _7Z_VOL VolumeIndex(volumeIndex), #endif FileIndex(fileIndex), FolderIndex(folderIndex), UnpackSize(0) { if (fileIndex != kNumNoIndex) { ExtractStatuses.ClearAndSetSize(1); ExtractStatuses[0] = true; } }; }; STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) { COM_TRY_BEGIN bool testMode = (testModeSpec != 0); CMyComPtr extractCallback = extractCallbackSpec; UInt64 importantTotalUnpacked = 0; bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = #ifdef _7Z_VOL _refs.Size(); #else _db.Files.Size(); #endif if (numItems == 0) return S_OK; /* if (_volumes.Size() != 1) return E_FAIL; const CVolume &volume = _volumes.Front(); const CDbEx &_db = volume.Database; IInStream *_inStream = volume.Stream; */ CObjectVector extractFolderInfoVector; for (UInt32 ii = 0; ii < numItems; ii++) { // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex]; UInt32 ref2Index = allFilesMode ? ii : indices[ii]; // const CRef2 &ref2 = _refs[ref2Index]; // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++) { #ifdef _7Z_VOL // const CRef &ref = ref2.Refs[ri]; const CRef &ref = _refs[ref2Index]; int volumeIndex = ref.VolumeIndex; const CVolume &volume = _volumes[volumeIndex]; const CDbEx &db = volume.Database; UInt32 fileIndex = ref.ItemIndex; #else const CDbEx &db = _db; UInt32 fileIndex = ref2Index; #endif CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex]; if (folderIndex == kNumNoIndex) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif fileIndex, kNumNoIndex)); continue; } if (extractFolderInfoVector.IsEmpty() || folderIndex != extractFolderInfoVector.Back().FolderIndex #ifdef _7Z_VOL || volumeIndex != extractFolderInfoVector.Back().VolumeIndex #endif ) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif kNumNoIndex, folderIndex)); UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex); importantTotalUnpacked += unpackSize; extractFolderInfoVector.Back().UnpackSize = unpackSize; } CExtractFolderInfo &efi = extractFolderInfoVector.Back(); // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; CNum startIndex = db.FolderStartFileIndex[folderIndex]; for (CNum index = efi.ExtractStatuses.Size(); index <= fileIndex - startIndex; index++) { // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize; // Count partial_folder_size // efi.UnpackSize += unpackSize; // importantTotalUnpacked += unpackSize; efi.ExtractStatuses.Add(index == fileIndex - startIndex); } } } RINOK(extractCallback->SetTotal(importantTotalUnpacked)); CDecoder decoder( #ifdef _ST_MODE false #else true #endif ); // CDecoder1 decoder; UInt64 totalPacked = 0; UInt64 totalUnpacked = 0; UInt64 curPacked, curUnpacked; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) { lps->OutSize = totalUnpacked; lps->InSize = totalPacked; RINOK(lps->SetCur()); if (i >= extractFolderInfoVector.Size()) break; const CExtractFolderInfo &efi = extractFolderInfoVector[i]; curUnpacked = efi.UnpackSize; curPacked = 0; CFolderOutStream *folderOutStream = new CFolderOutStream; CMyComPtr outStream(folderOutStream); #ifdef _7Z_VOL const CVolume &volume = _volumes[efi.VolumeIndex]; const CDbEx &db = volume.Database; #else const CDbEx &db = _db; #endif CNum startIndex; if (efi.FileIndex != kNumNoIndex) startIndex = efi.FileIndex; else startIndex = db.FolderStartFileIndex[efi.FolderIndex]; HRESULT result = folderOutStream->Init(&db, #ifdef _7Z_VOL volume.StartRef2Index, #else 0, #endif startIndex, &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0); RINOK(result); if (efi.FileIndex != kNumNoIndex) continue; CNum folderIndex = efi.FolderIndex; curPacked = _db.GetFolderFullPackSize(folderIndex); #ifndef _NO_CRYPTO CMyComPtr getTextPassword; if (extractCallback) extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif try { #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; #endif HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume.Stream, #else _inStream, #endif db.ArcInfo.DataStartPosition, db, folderIndex, outStream, progress _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , true, _numThreads #endif ); if (result == S_FALSE) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } if (result == E_NOTIMPL) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod)); continue; } if (result != S_OK) return result; if (folderOutStream->WasWritingFinished() != S_OK) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } } catch(...) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } } return S_OK; COM_TRY_END } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.cpp0100777000000000000000000000537213761647206025602 0ustar00// 7zFolderInStream.cpp #include "StdAfx.h" #include "7zFolderInStream.h" namespace NArchive { namespace N7z { CFolderInStream::CFolderInStream() { _inStreamWithHashSpec = new CSequentialInStreamWithCRC; _inStreamWithHash = _inStreamWithHashSpec; } void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles) { _updateCallback = updateCallback; _numFiles = numFiles; _fileIndex = 0; _fileIndices = fileIndices; Processed.Clear(); CRCs.Clear(); Sizes.Clear(); _fileIsOpen = false; _currentSizeIsDefined = false; } HRESULT CFolderInStream::OpenStream() { _filePos = 0; while (_fileIndex < _numFiles) { CMyComPtr stream; HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream); if (result != S_OK && result != S_FALSE) return result; _fileIndex++; _inStreamWithHashSpec->SetStream(stream); _inStreamWithHashSpec->Init(); if (stream) { _fileIsOpen = true; CMyComPtr streamGetSize; stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); if (streamGetSize) { RINOK(streamGetSize->GetSize(&_currentSize)); _currentSizeIsDefined = true; } return S_OK; } RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); Sizes.Add(0); Processed.Add(result == S_OK); AddDigest(); } return S_OK; } void CFolderInStream::AddDigest() { CRCs.Add(_inStreamWithHashSpec->GetCRC()); } HRESULT CFolderInStream::CloseStream() { RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); _inStreamWithHashSpec->ReleaseStream(); _fileIsOpen = false; _currentSizeIsDefined = false; Processed.Add(true); Sizes.Add(_filePos); AddDigest(); return S_OK; } STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != 0) *processedSize = 0; while (size > 0) { if (_fileIsOpen) { UInt32 processed2; RINOK(_inStreamWithHash->Read(data, size, &processed2)); if (processed2 == 0) { RINOK(CloseStream()); continue; } if (processedSize != 0) *processedSize = processed2; _filePos += processed2; break; } if (_fileIndex >= _numFiles) break; RINOK(OpenStream()); } return S_OK; } STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; unsigned index2 = (unsigned)subStream; if (subStream > Sizes.Size()) return E_FAIL; if (index2 < Sizes.Size()) { *value = Sizes[index2]; return S_OK; } if (!_currentSizeIsDefined) return S_FALSE; *value = _currentSize; return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.h0100777000000000000000000000240313761647206025237 0ustar00// 7zFolderInStream.h #ifndef __7Z_FOLDER_IN_STREAM_H #define __7Z_FOLDER_IN_STREAM_H #include "../../ICoder.h" #include "../IArchive.h" #include "../Common/InStreamWithCRC.h" #include "7zItem.h" namespace NArchive { namespace N7z { class CFolderInStream: public ISequentialInStream, public ICompressGetSubStreamSize, public CMyUnknownImp { CSequentialInStreamWithCRC *_inStreamWithHashSpec; CMyComPtr _inStreamWithHash; CMyComPtr _updateCallback; bool _currentSizeIsDefined; bool _fileIsOpen; UInt64 _currentSize; UInt64 _filePos; const UInt32 *_fileIndices; UInt32 _numFiles; UInt32 _fileIndex; HRESULT OpenStream(); HRESULT CloseStream(); void AddDigest(); public: CRecordVector Processed; CRecordVector CRCs; CRecordVector Sizes; MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); CFolderInStream(); void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles); UInt64 GetFullSize() const { UInt64 size = 0; FOR_VECTOR (i, Sizes) size += Sizes[i]; return size; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.cpp0100777000000000000000000000714513761647206026003 0ustar00// 7zFolderOutStream.cpp #include "StdAfx.h" #include "7zFolderOutStream.h" namespace NArchive { namespace N7z { CFolderOutStream::CFolderOutStream() { _crcStreamSpec = new COutStreamWithCRC; _crcStream = _crcStreamSpec; } HRESULT CFolderOutStream::Init( const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, bool testMode, bool checkCrc) { _db = db; _ref2Offset = ref2Offset; _startIndex = startIndex; _extractStatuses = extractStatuses; _extractCallback = extractCallback; _testMode = testMode; _checkCrc = checkCrc; _currentIndex = 0; _fileIsOpen = false; return ProcessEmptyFiles(); } HRESULT CFolderOutStream::OpenFile() { Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract) : NExtract::NAskMode::kSkip; CMyComPtr realOutStream; UInt32 index = _startIndex + _currentIndex; RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode)); _crcStreamSpec->SetStream(realOutStream); _crcStreamSpec->Init(_checkCrc); _fileIsOpen = true; const CFileItem &fi = _db->Files[index]; _rem = fi.Size; if (askMode == NExtract::NAskMode::kExtract && !realOutStream && !_db->IsItemAnti(index) && !fi.IsDir) askMode = NExtract::NAskMode::kSkip; return _extractCallback->PrepareOperation(askMode); } HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res) { _crcStreamSpec->ReleaseStream(); _fileIsOpen = false; _currentIndex++; return _extractCallback->SetOperationResult(res); } HRESULT CFolderOutStream::CloseFileAndSetResult() { const CFileItem &fi = _db->Files[_startIndex + _currentIndex]; return CloseFileAndSetResult( (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ? NExtract::NOperationResult::kOK : NExtract::NOperationResult::kCRCError); } HRESULT CFolderOutStream::ProcessEmptyFiles() { while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) { RINOK(OpenFile()); RINOK(CloseFileAndSetResult()); } return S_OK; } STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size != 0) { if (_fileIsOpen) { UInt32 cur = size < _rem ? size : (UInt32)_rem; RINOK(_crcStream->Write(data, cur, &cur)); if (cur == 0) break; data = (const Byte *)data + cur; size -= cur; _rem -= cur; if (processedSize != NULL) *processedSize += cur; if (_rem == 0) { RINOK(CloseFileAndSetResult()); RINOK(ProcessEmptyFiles()); continue; } } else { RINOK(ProcessEmptyFiles()); if (_currentIndex == _extractStatuses->Size()) { // we support partial extracting if (processedSize != NULL) *processedSize += size; break; } RINOK(OpenFile()); } } return S_OK; } STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; if ((int)subStream >= _extractStatuses->Size()) return S_FALSE; *value = _db->Files[_startIndex + (int)subStream].Size; return S_OK; } HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) { while (_currentIndex < _extractStatuses->Size()) { if (_fileIsOpen) { RINOK(CloseFileAndSetResult(resultEOperationResult)); } else { RINOK(OpenFile()); } } return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.h0100777000000000000000000000263713761647206025451 0ustar00// 7zFolderOutStream.h #ifndef __7Z_FOLDER_OUT_STREAM_H #define __7Z_FOLDER_OUT_STREAM_H #include "../../IStream.h" #include "../IArchive.h" #include "../Common/OutStreamWithCRC.h" #include "7zIn.h" namespace NArchive { namespace N7z { class CFolderOutStream: public ISequentialOutStream, public ICompressGetSubStreamSize, public CMyUnknownImp { COutStreamWithCRC *_crcStreamSpec; CMyComPtr _crcStream; const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr _extractCallback; UInt32 _ref2Offset; UInt32 _startIndex; unsigned _currentIndex; bool _testMode; bool _checkCrc; bool _fileIsOpen; UInt64 _rem; HRESULT OpenFile(); HRESULT CloseFileAndSetResult(Int32 res); HRESULT CloseFileAndSetResult(); HRESULT ProcessEmptyFiles(); public: MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) CFolderOutStream(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); HRESULT Init( const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, bool testMode, bool checkCrc); HRESULT FlushCorrupted(Int32 resultEOperationResult); HRESULT WasWritingFinished() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.cpp0100777000000000000000000004435313761647206024303 0ustar00// 7zHandler.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #ifndef __7Z_SET_PROPERTIES #include "../../../Windows/System.h" #endif #include "../Common/ItemNameUtils.h" #include "7zHandler.h" #include "7zProperties.h" #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY #include "../Common/ParseProperties.h" #endif #endif using namespace NWindows; using namespace NCOM; namespace NArchive { namespace N7z { CHandler::CHandler() { #ifndef _NO_CRYPTO _isEncrypted = false; _passwordIsDefined = false; #endif #ifdef EXTRACT_ONLY _crcSize = 4; #ifdef __7Z_SET_PROPERTIES _numThreads = NSystem::GetNumberOfProcessors(); #endif #endif } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _db.Files.Size(); return S_OK; } #ifdef _SFX IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { *numProps = 0; return S_OK; } STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */) { return E_NOTIMPL; } #else static const Byte kArcProps[] = { kpidHeadersSize, kpidMethod, kpidSolid, kpidNumBlocks // , kpidIsTree }; IMP_IInArchive_ArcProps static inline char GetHex(unsigned value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) { int len = 0; do { s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; } while (id != 0); return (unsigned)-len; } static void ConvertMethodIdToString(AString &res, UInt64 id) { const unsigned kLen = 32; char s[kLen]; unsigned len = kLen - 1; s[len] = 0; res += s + len - ConvertMethodIdToString_Back(s + len, id); } static unsigned GetStringForSizeValue(char *s, UInt32 val) { unsigned i; for (i = 0; i <= 31; i++) if (((UInt32)1 << i) == val) { if (i < 10) { s[0] = (char)('0' + i); s[1] = 0; return 1; } if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); } else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); } else { s[0] = '3'; s[1] = (char)('0' + i - 30); } s[2] = 0; return 2; } char c = 'b'; if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } ::ConvertUInt32ToString(val, s); unsigned pos = MyStringLen(s); s[pos++] = c; s[pos] = 0; return pos; } /* static inline void AddHexToString(UString &res, Byte value) { res += GetHex((Byte)(value >> 4)); res += GetHex((Byte)(value & 0xF)); } */ static char *AddProp32(char *s, const char *name, UInt32 v) { *s++ = ':'; s = MyStpCpy(s, name); ::ConvertUInt32ToString(v, s); return s + MyStringLen(s); } void CHandler::AddMethodName(AString &s, UInt64 id) { UString methodName; FindMethod(EXTERNAL_CODECS_VARS id, methodName); if (methodName.IsEmpty()) { for (unsigned i = 0; i < methodName.Len(); i++) if (methodName[i] >= 0x80) { methodName.Empty(); break; } } if (methodName.IsEmpty()) ConvertMethodIdToString(s, id); else for (unsigned i = 0; i < methodName.Len(); i++) s += (char)methodName[i]; } #endif STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { #ifndef _SFX COM_TRY_BEGIN #endif NCOM::CPropVariant prop; switch (propID) { #ifndef _SFX case kpidMethod: { AString s; const CParsedMethods &pm = _db.ParsedMethods; FOR_VECTOR (i, pm.IDs) { UInt64 id = pm.IDs[i]; if (!s.IsEmpty()) s += ' '; char temp[16]; if (id == k_LZMA2) { s += "LZMA2:"; if ((pm.Lzma2Prop & 1) == 0) ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp); else GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11)); s += temp; } else if (id == k_LZMA) { s += "LZMA:"; GetStringForSizeValue(temp, pm.LzmaDic); s += temp; } else AddMethodName(s, id); } prop = s; break; } case kpidSolid: prop = _db.IsSolid(); break; case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; case kpidHeadersSize: prop = _db.HeadersSize; break; case kpidPhySize: prop = _db.PhySize; break; case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; /* case kpidIsTree: if (_db.IsTree) prop = true; break; case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; case kpidIsAux: if (_db.IsTree) prop = true; break; */ // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; #endif case kpidWarningFlags: { UInt32 v = 0; if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; if (v != 0) prop = v; break; } case kpidErrorFlags: { UInt32 v = 0; if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; prop = v; break; } } prop.Detach(value); return S_OK; #ifndef _SFX COM_TRY_END #endif } static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index) { UInt64 value; if (v.GetItem(index, value)) PropVarEm_Set_FileTime64(prop, value); } bool CHandler::IsFolderEncrypted(CNum folderIndex) const { if (folderIndex == kNumNoIndex) return false; size_t startPos = _db.FoCodersDataOffset[folderIndex]; const Byte *p = _db.CodersData + startPos; size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; CInByte2 inByte; inByte.Init(p, size); CNum numCoders = inByte.ReadNum(); for (; numCoders != 0; numCoders--) { Byte mainByte = inByte.ReadByte(); unsigned idSize = (mainByte & 0xF); const Byte *longID = inByte.GetPtr(); UInt64 id64 = 0; for (unsigned j = 0; j < idSize; j++) id64 = ((id64 << 8) | longID[j]); inByte.SkipDataNoCheck(idSize); if (id64 == k_AES) return true; if ((mainByte & 0x20) != 0) inByte.SkipDataNoCheck(inByte.ReadNum()); } return false; } STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) { *numProps = 0; return S_OK; } STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) { *name = NULL; *propID = kpidNtSecure; return S_OK; } STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) { /* const CFileItem &file = _db.Files[index]; *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); *parent = (UInt32)(Int32)file.Parent; */ *parentType = NParentType::kDir; *parent = (UInt32)(Int32)-1; return S_OK; } STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) { *data = NULL; *dataSize = 0; *propType = 0; if (/* _db.IsTree && propID == kpidName || !_db.IsTree && */ propID == kpidPath) { if (_db.NameOffsets && _db.NamesBuf) { size_t offset = _db.NameOffsets[index]; size_t size = (_db.NameOffsets[index + 1] - offset) * 2; if (size < ((UInt32)1 << 31)) { *data = (const void *)(_db.NamesBuf + offset * 2); *dataSize = (UInt32)size; *propType = NPropDataType::kUtf16z; } } return S_OK; } /* if (propID == kpidNtSecure) { if (index < (UInt32)_db.SecureIDs.Size()) { int id = _db.SecureIDs[index]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; if (size >= 0) { *data = _db.SecureBuf + offs; *dataSize = (UInt32)size; *propType = NPropDataType::kRaw; } } } */ return S_OK; } #ifndef _SFX HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const { PropVariant_Clear(prop); if (folderIndex == kNumNoIndex) return S_OK; // for (int ttt = 0; ttt < 1; ttt++) { const unsigned kTempSize = 256; char temp[kTempSize]; unsigned pos = kTempSize; temp[--pos] = 0; size_t startPos = _db.FoCodersDataOffset[folderIndex]; const Byte *p = _db.CodersData + startPos; size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; CInByte2 inByte; inByte.Init(p, size); // numCoders == 0 ??? CNum numCoders = inByte.ReadNum(); bool needSpace = false; for (; numCoders != 0; numCoders--, needSpace = true) { if (pos < 32) // max size of property break; Byte mainByte = inByte.ReadByte(); unsigned idSize = (mainByte & 0xF); const Byte *longID = inByte.GetPtr(); UInt64 id64 = 0; for (unsigned j = 0; j < idSize; j++) id64 = ((id64 << 8) | longID[j]); inByte.SkipDataNoCheck(idSize); if ((mainByte & 0x10) != 0) { inByte.ReadNum(); // NumInStreams inByte.ReadNum(); // NumOutStreams } CNum propsSize = 0; const Byte *props = NULL; if ((mainByte & 0x20) != 0) { propsSize = inByte.ReadNum(); props = inByte.GetPtr(); inByte.SkipDataNoCheck(propsSize); } const char *name = NULL; char s[32]; s[0] = 0; if (id64 <= (UInt32)0xFFFFFFFF) { UInt32 id = (UInt32)id64; if (id == k_LZMA) { name = "LZMA"; if (propsSize == 5) { UInt32 dicSize = GetUi32((const Byte *)props + 1); char *dest = s + GetStringForSizeValue(s, dicSize); UInt32 d = props[0]; if (d != 0x5D) { UInt32 lc = d % 9; d /= 9; UInt32 pb = d / 5; UInt32 lp = d % 5; if (lc != 3) dest = AddProp32(dest, "lc", lc); if (lp != 0) dest = AddProp32(dest, "lp", lp); if (pb != 2) dest = AddProp32(dest, "pb", pb); } } } else if (id == k_LZMA2) { name = "LZMA2"; if (propsSize == 1) { Byte p = props[0]; if ((p & 1) == 0) ConvertUInt32ToString((UInt32)((p >> 1) + 12), s); else GetStringForSizeValue(s, 3 << ((p >> 1) + 11)); } } else if (id == k_PPMD) { name = "PPMD"; if (propsSize == 5) { Byte order = *props; char *dest = s; *dest++ = 'o'; ConvertUInt32ToString(order, dest); dest += MyStringLen(dest); dest = MyStpCpy(dest, ":mem"); GetStringForSizeValue(dest, GetUi32(props + 1)); } } else if (id == k_Delta) { name = "Delta"; if (propsSize == 1) ConvertUInt32ToString((UInt32)props[0] + 1, s); } else if (id == k_BCJ2) name = "BCJ2"; else if (id == k_BCJ) name = "BCJ"; else if (id == k_AES) { name = "7zAES"; if (propsSize >= 1) { Byte firstByte = props[0]; UInt32 numCyclesPower = firstByte & 0x3F; ConvertUInt32ToString(numCyclesPower, s); } } } if (name) { unsigned nameLen = MyStringLen(name); unsigned propsLen = MyStringLen(s); unsigned totalLen = nameLen + propsLen; if (propsLen != 0) totalLen++; if (needSpace) totalLen++; if (totalLen + 5 >= pos) break; pos -= totalLen; MyStringCopy(temp + pos, name); if (propsLen != 0) { char *dest = temp + pos + nameLen; *dest++ = ':'; MyStringCopy(dest, s); } if (needSpace) temp[pos + totalLen - 1] = ' '; } else { UString methodName; FindMethod(EXTERNAL_CODECS_VARS id64, methodName); if (methodName.IsEmpty()) { for (unsigned j = 0; j < methodName.Len(); j++) if (methodName[j] >= 0x80) { methodName.Empty(); break; } } if (needSpace) temp[--pos] = ' '; if (methodName.IsEmpty()) pos -= ConvertMethodIdToString_Back(temp + pos, id64); else { unsigned len = methodName.Len(); if (len + 5 > pos) break; pos -= len; for (unsigned i = 0; i < len; i++) temp[pos + i] = (char)methodName[i]; } } } if (numCoders != 0 && pos >= 4) { temp[--pos] = ' '; temp[--pos] = '.'; temp[--pos] = '.'; temp[--pos] = '.'; } return PropVarEm_Set_Str(prop, temp + pos); // } } #endif STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { PropVariant_Clear(value); // COM_TRY_BEGIN // NCOM::CPropVariant prop; /* const CRef2 &ref2 = _refs[index]; if (ref2.Refs.IsEmpty()) return E_FAIL; const CRef &ref = ref2.Refs.Front(); */ const CFileItem &item = _db.Files[index]; UInt32 index2 = index; switch(propID) { case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; case kpidSize: { PropVarEm_Set_UInt64(value, item.Size); // prop = ref2.Size; break; } case kpidPackSize: { // prop = ref2.PackSize; { CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); /* else PropVarEm_Set_UInt64(value, 0); */ } else PropVarEm_Set_UInt64(value, 0); } break; } // case kpidIsAux: prop = _db.IsItemAux(index2); break; case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; case kpidAttrib: if (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); break; case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; /* case kpidIsAltStream: prop = item.IsAltStream; break; case kpidNtSecure: { int id = _db.SecureIDs[index]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; if (size >= 0) { prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); } break; } */ case kpidPath: return _db.GetPath_Prop(index, value); #ifndef _SFX case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); case kpidBlock: { CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) PropVarEm_Set_UInt32(value, (UInt32)folderIndex); } break; case kpidPackedSize0: case kpidPackedSize1: case kpidPackedSize2: case kpidPackedSize3: case kpidPackedSize4: { /* CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { const CFolder &folderInfo = _db.Folders[folderIndex]; if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) { prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); } else prop = (UInt64)0; } else prop = (UInt64)0; */ } break; #endif } // prop.Detach(value); return S_OK; // COM_TRY_END } STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) { COM_TRY_BEGIN Close(); #ifndef _SFX _fileInfoPopIDs.Clear(); #endif try { CMyComPtr openArchiveCallbackTemp = openArchiveCallback; #ifndef _NO_CRYPTO CMyComPtr getTextPassword; if (openArchiveCallback) openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif CInArchive archive; _db.IsArc = false; RINOK(archive.Open(stream, maxCheckStartPosition)); _db.IsArc = true; HRESULT result = archive.ReadDatabase( EXTERNAL_CODECS_VARS _db #ifndef _NO_CRYPTO , getTextPassword, _isEncrypted, _passwordIsDefined #endif ); RINOK(result); _inStream = stream; } catch(...) { Close(); // return E_INVALIDARG; // we must return out_of_memory here return S_FALSE; } // _inStream = stream; #ifndef _SFX FillPopIDs(); #endif return S_OK; COM_TRY_END } STDMETHODIMP CHandler::Close() { COM_TRY_BEGIN _inStream.Release(); _db.Clear(); #ifndef _NO_CRYPTO _isEncrypted = false; _passwordIsDefined = false; #endif return S_OK; COM_TRY_END } #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); _numThreads = numProcessors; for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; UInt32 number; int index = ParseStringToUInt32(name, number); if (index == 0) { if (name.IsPrefixedBy(L"mt")) { RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads)); continue; } else return E_INVALIDARG; } } return S_OK; COM_TRY_END } #endif #endif IMPL_ISetCompressCodecsInfo }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.h0100777000000000000000000000676613761647206023756 0ustar00// 7z/Handler.h #ifndef __7Z_HANDLER_H #define __7Z_HANDLER_H #include "../../ICoder.h" #include "../IArchive.h" #include "../../Common/CreateCoder.h" #ifndef EXTRACT_ONLY #include "../Common/HandlerOut.h" #endif #include "7zCompressionMode.h" #include "7zIn.h" namespace NArchive { namespace N7z { const UInt32 k_Copy = 0x0; const UInt32 k_Delta = 3; const UInt32 k_LZMA2 = 0x21; const UInt32 k_LZMA = 0x030101; const UInt32 k_PPMD = 0x030401; const UInt32 k_BCJ = 0x03030103; const UInt32 k_BCJ2 = 0x0303011B; const UInt32 k_Deflate = 0x040108; const UInt32 k_BZip2 = 0x040202; #ifndef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY #if !defined(_7ZIP_ST) && !defined(_SFX) #define __7Z_SET_PROPERTIES #endif #else #define __7Z_SET_PROPERTIES #endif #endif #ifndef EXTRACT_ONLY class COutHandler: public CMultiMethodProps { HRESULT SetSolidFromString(const UString &s); HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value); public: bool _removeSfxBlock; UInt64 _numSolidFiles; UInt64 _numSolidBytes; bool _numSolidBytesDefined; bool _solidExtension; bool _compressHeaders; bool _encryptHeadersSpecified; bool _encryptHeaders; // bool _useParents; 9.26 CBoolPair Write_CTime; CBoolPair Write_ATime; CBoolPair Write_MTime; bool _volumeMode; void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } void InitSolid() { InitSolidFiles(); InitSolidSize(); _solidExtension = false; _numSolidBytesDefined = false; } void InitProps(); COutHandler() { InitProps(); } HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); }; #endif class CHandler: public IInArchive, public IArchiveGetRawProps, #ifdef __7Z_SET_PROPERTIES public ISetProperties, #endif #ifndef EXTRACT_ONLY public IOutArchive, #endif PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp #ifndef EXTRACT_ONLY , public COutHandler #endif { public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) #ifdef __7Z_SET_PROPERTIES MY_QUERYINTERFACE_ENTRY(ISetProperties) #endif #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY(IOutArchive) #endif QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) INTERFACE_IArchiveGetRawProps(;) #ifdef __7Z_SET_PROPERTIES STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) #endif DECL_ISetCompressCodecsInfo CHandler(); private: CMyComPtr _inStream; NArchive::N7z::CDbEx _db; #ifndef _NO_CRYPTO bool _isEncrypted; bool _passwordIsDefined; #endif #ifdef EXTRACT_ONLY #ifdef __7Z_SET_PROPERTIES UInt32 _numThreads; #endif UInt32 _crcSize; #else CRecordVector _binds; HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); void AddDefaultMethod(); HRESULT SetMainMethod(CCompressionMethodMode &method, CObjectVector &methodsInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); #endif bool IsFolderEncrypted(CNum folderIndex) const; #ifndef _SFX CRecordVector _fileInfoPopIDs; void FillPopIDs(); void AddMethodName(AString &s, UInt64 id); HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; #endif DECL_EXTERNAL_CODECS_VARS }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp0100777000000000000000000005415013761647206024767 0ustar00// 7zHandlerOut.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" #include "../../../Common/Wildcard.h" #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" #include "7zHandler.h" #include "7zOut.h" #include "7zUpdate.h" using namespace NWindows; namespace NArchive { namespace N7z { static const wchar_t *k_LZMA_Name = L"LZMA"; static const wchar_t *kDefaultMethodName = L"LZMA2"; static const wchar_t *k_Copy_Name = L"Copy"; static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; static const UInt32 k_NumFastBytes_ForHeaders = 273; static const UInt32 k_Level_ForHeaders = 5; static const UInt32 k_Dictionary_ForHeaders = #ifdef UNDER_CE 1 << 18; #else 1 << 20; #endif STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { *type = NFileTimeType::kWindows; return S_OK; } HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) { if (!FindMethod( EXTERNAL_CODECS_VARS m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams)) return E_INVALIDARG; (CProps &)dest = (CProps &)m; return S_OK; } HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) { if (!_compressHeaders) return S_OK; COneMethodInfo m; m.MethodName = k_LZMA_Name; m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders); m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); m.AddNumThreadsProp(1); CMethodFull methodFull; RINOK(PropsMethod_To_FullMethod(methodFull, m)); headerMethod.Methods.Add(methodFull); return S_OK; } void CHandler::AddDefaultMethod() { FOR_VECTOR (i, _methods) { UString &methodName = _methods[i].MethodName; if (methodName.IsEmpty()) methodName = kDefaultMethodName; } if (_methods.IsEmpty()) { COneMethodInfo m; m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); _methods.Add(m); } } HRESULT CHandler::SetMainMethod( CCompressionMethodMode &methodMode, CObjectVector &methods #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { AddDefaultMethod(); const UInt64 kSolidBytes_Min = (1 << 24); const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; bool needSolid = false; FOR_VECTOR (i, methods) { COneMethodInfo &oneMethodInfo = methods[i]; SetGlobalLevelAndThreads(oneMethodInfo #ifndef _7ZIP_ST , numThreads #endif ); CMethodFull methodFull; RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); methodMode.Methods.Add(methodFull); if (methodFull.Id != k_Copy) needSolid = true; if (_numSolidBytesDefined) continue; UInt32 dicSize; switch (methodFull.Id) { case k_LZMA: case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; case k_Deflate: dicSize = (UInt32)1 << 15; break; case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; default: continue; } _numSolidBytes = (UInt64)dicSize << 7; if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min; if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max; _numSolidBytesDefined = true; } if (!_numSolidBytesDefined) if (needSolid) _numSolidBytes = kSolidBytes_Max; else _numSolidBytes = 0; _numSolidBytesDefined = true; return S_OK; } static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined) { // ft = 0; // ftDefined = false; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) { ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); ftDefined = true; } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; else { ft = 0; ftDefined = false; } return S_OK; } /* #ifdef _WIN32 static const wchar_t kDirDelimiter1 = L'\\'; #endif static const wchar_t kDirDelimiter2 = L'/'; static inline bool IsCharDirLimiter(wchar_t c) { return ( #ifdef _WIN32 c == kDirDelimiter1 || #endif c == kDirDelimiter2); } static int FillSortIndex(CObjectVector &treeFolders, int cur, int curSortIndex) { CTreeFolder &tf = treeFolders[cur]; tf.SortIndex = curSortIndex++; for (int i = 0; i < tf.SubFolders.Size(); i++) curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); tf.SortIndexEnd = curSortIndex; return curSortIndex; } static int FindSubFolder(const CObjectVector &treeFolders, int cur, const UString &name, int &insertPos) { const CIntVector &subFolders = treeFolders[cur].SubFolders; int left = 0, right = subFolders.Size(); insertPos = -1; for (;;) { if (left == right) { insertPos = left; return -1; } int mid = (left + right) / 2; int midFolder = subFolders[mid]; int compare = CompareFileNames(name, treeFolders[midFolder].Name); if (compare == 0) return midFolder; if (compare < 0) right = mid; else left = mid + 1; } } static int AddFolder(CObjectVector &treeFolders, int cur, const UString &name) { int insertPos; int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); if (folderIndex < 0) { folderIndex = treeFolders.Size(); CTreeFolder &newFolder = treeFolders.AddNew(); newFolder.Parent = cur; newFolder.Name = name; treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); } // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; return folderIndex; } */ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { COM_TRY_BEGIN const CDbEx *db = 0; #ifdef _7Z_VOL if (_volumes.Size() > 1) return E_FAIL; const CVolume *volume = 0; if (_volumes.Size() == 1) { volume = &_volumes.Front(); db = &volume->Database; } #else if (_inStream != 0) db = &_db; #endif /* CMyComPtr getRawProps; updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); CUniqBlocks secureBlocks; secureBlocks.AddUniq(NULL, 0); CObjectVector treeFolders; { CTreeFolder folder; folder.Parent = -1; treeFolders.Add(folder); } */ CObjectVector updateItems; bool need_CTime = (Write_CTime.Def && Write_CTime.Val); bool need_ATime = (Write_ATime.Def && Write_ATime.Val); bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); if (db) { if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); } UString s; for (UInt32 i = 0; i < numItems; i++) { Int32 newData, newProps; UInt32 indexInArchive; if (!updateCallback) return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); CUpdateItem ui; ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); ui.IndexInArchive = indexInArchive; ui.IndexInClient = i; ui.IsAnti = false; ui.Size = 0; UString name; // bool isAltStream = false; if (ui.IndexInArchive != -1) { if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) return E_INVALIDARG; const CFileItem &fi = db->Files[ui.IndexInArchive]; if (!ui.NewProps) { _db.GetPath(ui.IndexInArchive, name); } ui.IsDir = fi.IsDir; ui.Size = fi.Size; // isAltStream = fi.IsAltStream; ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); if (!ui.NewProps) { ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); } } if (ui.NewProps) { bool folderStatusIsDefined; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); if (prop.vt == VT_EMPTY) ui.AttribDefined = false; else if (prop.vt != VT_UI4) return E_INVALIDARG; else { ui.Attrib = prop.ulVal; ui.AttribDefined = true; } } // we need MTime to sort files. if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); /* if (getRawProps) { const void *data; UInt32 dataSize; UInt32 propType; getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); if (dataSize != 0 && propType != NPropDataType::kRaw) return E_FAIL; ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); } */ { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_EMPTY) { } else if (prop.vt != VT_BSTR) return E_INVALIDARG; else { name = NItemName::MakeLegalName(prop.bstrVal); } } { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)); if (prop.vt == VT_EMPTY) folderStatusIsDefined = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else { ui.IsDir = (prop.boolVal != VARIANT_FALSE); folderStatusIsDefined = true; } } { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)); if (prop.vt == VT_EMPTY) ui.IsAnti = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else ui.IsAnti = (prop.boolVal != VARIANT_FALSE); } /* { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); if (prop.vt == VT_EMPTY) isAltStream = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else isAltStream = (prop.boolVal != VARIANT_FALSE); } */ if (ui.IsAnti) { ui.AttribDefined = false; ui.CTimeDefined = false; ui.ATimeDefined = false; ui.MTimeDefined = false; ui.Size = 0; } if (!folderStatusIsDefined && ui.AttribDefined) ui.SetDirStatusFromAttrib(); } else { /* if (_db.SecureIDs.IsEmpty()) ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); else { int id = _db.SecureIDs[ui.IndexInArchive]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); } */ } /* { int folderIndex = 0; if (_useParents) { int j; s.Empty(); for (j = 0; j < name.Len(); j++) { wchar_t c = name[j]; if (IsCharDirLimiter(c)) { folderIndex = AddFolder(treeFolders, folderIndex, s); s.Empty(); continue; } s += c; } if (isAltStream) { int colonPos = s.Find(':'); if (colonPos < 0) { // isAltStream = false; return E_INVALIDARG; } UString mainName = s.Left(colonPos); int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); if (treeFolders[newFolderIndex].UpdateItemIndex < 0) { for (int j = updateItems.Size() - 1; j >= 0; j--) { CUpdateItem &ui2 = updateItems[j]; if (ui2.ParentFolderIndex == folderIndex && ui2.Name == mainName) { ui2.TreeFolderIndex = newFolderIndex; treeFolders[newFolderIndex].UpdateItemIndex = j; } } } folderIndex = newFolderIndex; s.Delete(0, colonPos + 1); } ui.Name = s; } else ui.Name = name; ui.IsAltStream = isAltStream; ui.ParentFolderIndex = folderIndex; ui.TreeFolderIndex = -1; if (ui.IsDir && !s.IsEmpty()) { ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); } } */ ui.Name = name; if (ui.NewData) { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; ui.Size = (UInt64)prop.uhVal.QuadPart; if (ui.Size != 0 && ui.IsAnti) return E_INVALIDARG; } updateItems.Add(ui); } /* FillSortIndex(treeFolders, 0, 0); for (i = 0; i < (UInt32)updateItems.Size(); i++) { CUpdateItem &ui = updateItems[i]; ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; } */ CCompressionMethodMode methodMode, headerMethod; HRESULT res = SetMainMethod(methodMode, _methods #ifndef _7ZIP_ST , _numThreads #endif ); RINOK(res); methodMode.Binds = _binds; RINOK(SetHeaderMethod(headerMethod)); #ifndef _7ZIP_ST methodMode.NumThreads = _numThreads; headerMethod.NumThreads = 1; #endif CMyComPtr getPassword2; updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); methodMode.PasswordIsDefined = false; methodMode.Password.Empty(); if (getPassword2) { CMyComBSTR password; Int32 passwordIsDefined; RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); if (methodMode.PasswordIsDefined && (BSTR)password) methodMode.Password = password; } bool compressMainHeader = _compressHeaders; // check it bool encryptHeaders = false; if (methodMode.PasswordIsDefined) { if (_encryptHeadersSpecified) encryptHeaders = _encryptHeaders; #ifndef _NO_CRYPTO else encryptHeaders = _passwordIsDefined; #endif compressMainHeader = true; if (encryptHeaders) { headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; headerMethod.Password = methodMode.Password; } } if (numItems < 2) compressMainHeader = false; CUpdateOptions options; options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; int level = GetLevel(); options.UseFilters = level != 0 && _autoFilter; options.MaxFilter = level >= 8; options.HeaderOptions.CompressMainHeader = compressMainHeader; /* options.HeaderOptions.WriteCTime = Write_CTime; options.HeaderOptions.WriteATime = Write_ATime; options.HeaderOptions.WriteMTime = Write_MTime; */ options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; options.RemoveSfxBlock = _removeSfxBlock; options.VolumeMode = _volumeMode; COutArchive archive; CArchiveDatabaseOut newDatabase; CMyComPtr getPassword; updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); /* if (secureBlocks.Sorted.Size() > 1) { secureBlocks.GetReverseMap(); for (int i = 0; i < updateItems.Size(); i++) { int &secureIndex = updateItems[i].SecureIndex; secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; } } */ res = Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume ? volume->Stream: 0, volume ? db : 0, #else _inStream, db, #endif updateItems, // treeFolders, // secureBlocks, archive, newDatabase, outStream, updateCallback, options #ifndef _NO_CRYPTO , getPassword #endif ); RINOK(res); updateItems.ClearAndFree(); return archive.WriteDatabase(EXTERNAL_CODECS_VARS newDatabase, options.HeaderMethod, options.HeaderOptions); COM_TRY_END } static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) { stream = 0; int index = ParseStringToUInt32(srcString, coder); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); if (srcString[0] == 's') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); } return S_OK; } void COutHandler::InitProps() { CMultiMethodProps::Init(); _removeSfxBlock = false; _compressHeaders = true; _encryptHeadersSpecified = false; _encryptHeaders = false; // _useParents = false; Write_CTime.Init(); Write_ATime.Init(); Write_MTime.Init(); _volumeMode = false; InitSolid(); } HRESULT COutHandler::SetSolidFromString(const UString &s) { UString s2 = s; s2.MakeLower_Ascii(); for (unsigned i = 0; i < s2.Len();) { const wchar_t *start = ((const wchar_t *)s2) + i; const wchar_t *end; UInt64 v = ConvertStringToUInt64(start, &end); if (start == end) { if (s2[i++] != 'e') return E_INVALIDARG; _solidExtension = true; continue; } i += (int)(end - start); if (i == s2.Len()) return E_INVALIDARG; wchar_t c = s2[i++]; if (c == 'f') { if (v < 1) v = 1; _numSolidFiles = v; } else { unsigned numBits; switch (c) { case 'b': numBits = 0; break; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; case 't': numBits = 40; break; default: return E_INVALIDARG; } _numSolidBytes = (v << numBits); _numSolidBytesDefined = true; } } return S_OK; } HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) { bool isSolid; switch (value.vt) { case VT_EMPTY: isSolid = true; break; case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; case VT_BSTR: if (StringToBool(value.bstrVal, isSolid)) break; return SetSolidFromString(value.bstrVal); default: return E_INVALIDARG; } if (isSolid) InitSolid(); else _numSolidFiles = 1; return S_OK; } static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) { RINOK(PROPVARIANT_to_bool(prop, dest.Val)); dest.Def = true; return S_OK; } HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; if (name[0] == L's') { name.Delete(0); if (name.IsEmpty()) return SetSolidFromPROPVARIANT(value); if (value.vt != VT_EMPTY) return E_INVALIDARG; return SetSolidFromString(name); } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Ptr(index); if (index == 0) { if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); if (name.IsEqualTo("hcf")) { bool compressHeadersFull = true; RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); return compressHeadersFull ? S_OK: E_INVALIDARG; } if (name.IsEqualTo("he")) { RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); _encryptHeadersSpecified = true; return S_OK; } if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); } return CMultiMethodProps::SetProperty(name, value); } STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN _binds.Clear(); InitProps(); for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; if (name[0] == 'b') { if (value.vt != VT_EMPTY) return E_INVALIDARG; name.Delete(0); CBind bind; RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream)); if (name[0] != ':') return E_INVALIDARG; name.Delete(0); RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream)); if (!name.IsEmpty()) return E_INVALIDARG; _binds.Add(bind); continue; } RINOK(SetProperty(name, value)); } unsigned numEmptyMethods = GetNumEmptyMethods(); if (numEmptyMethods > 0) { unsigned k; for (k = 0; k < _binds.Size(); k++) { const CBind &bind = _binds[k]; if (bind.InCoder < (UInt32)numEmptyMethods || bind.OutCoder < (UInt32)numEmptyMethods) return E_INVALIDARG; } for (k = 0; k < _binds.Size(); k++) { CBind &bind = _binds[k]; bind.InCoder -= (UInt32)numEmptyMethods; bind.OutCoder -= (UInt32)numEmptyMethods; } _methods.DeleteFrontal(numEmptyMethods); } AddDefaultMethod(); if (!_filterMethod.MethodName.IsEmpty()) { FOR_VECTOR (k, _binds) { CBind &bind = _binds[k]; bind.InCoder++; bind.OutCoder++; } _methods.Insert(0, _filterMethod); } FOR_VECTOR (k, _binds) { const CBind &bind = _binds[k]; if (bind.InCoder >= (UInt32)_methods.Size() || bind.OutCoder >= (UInt32)_methods.Size()) return E_INVALIDARG; } return S_OK; COM_TRY_END } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.cpp0100777000000000000000000000074213761647206024110 0ustar00// 7zHeader.cpp #include "StdAfx.h" #include "7zHeader.h" namespace NArchive { namespace N7z { Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; #ifdef _7Z_VOL Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; #endif // We can change signature. So file doesn't contain correct signature. // struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } }; // static SignatureInitializer g_SignatureInitializer; }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.h0100777000000000000000000000272513761647206023560 0ustar00// 7z/7zHeader.h #ifndef __7Z_HEADER_H #define __7Z_HEADER_H #include "../../../Common/MyTypes.h" namespace NArchive { namespace N7z { const unsigned kSignatureSize = 6; extern Byte kSignature[kSignatureSize]; // #define _7Z_VOL // 7z-MultiVolume is not finished yet. // It can work already, but I still do not like some // things of that new multivolume format. // So please keep it commented. #ifdef _7Z_VOL extern Byte kFinishSignature[kSignatureSize]; #endif struct CArchiveVersion { Byte Major; Byte Minor; }; const Byte kMajorVersion = 0; struct CStartHeader { UInt64 NextHeaderOffset; UInt64 NextHeaderSize; UInt32 NextHeaderCRC; }; const UInt32 kStartHeaderSize = 20; #ifdef _7Z_VOL struct CFinishHeader: public CStartHeader { UInt64 ArchiveStartOffset; // data offset from end if that struct UInt64 AdditionalStartBlockSize; // start signature & start header size }; const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; #endif namespace NID { enum EEnum { kEnd, kHeader, kArchiveProperties, kAdditionalStreamsInfo, kMainStreamsInfo, kFilesInfo, kPackInfo, kUnpackInfo, kSubStreamsInfo, kSize, kCRC, kFolder, kCodersUnpackSize, kNumUnpackStream, kEmptyStream, kEmptyFile, kAnti, kName, kCTime, kATime, kMTime, kWinAttrib, kComment, kEncodedHeader, kStartPos, kDummy // kNtSecure, // kParent, // kIsAux }; } }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.cpp0100777000000000000000000012175713761647206023300 0ustar00// 7zIn.cpp #include "StdAfx.h" #ifdef _WIN32 #include #else #include #endif #include "../../../../C/7zCrc.h" #include "../../../../C/CpuArch.h" #include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" #include "7zDecode.h" #include "7zIn.h" #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader #ifndef _SFX #define FORMAT_7Z_RECOVERY #endif using namespace NWindows; using namespace NCOM; namespace NArchive { namespace N7z { static const UInt32 k_LZMA2 = 0x21; static const UInt32 k_LZMA = 0x030101; static void BoolVector_Fill_False(CBoolVector &v, unsigned size) { v.ClearAndSetSize(size); bool *p = &v[0]; for (unsigned i = 0; i < size; i++) p[i] = false; } static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) { if (index >= (UInt32)v.Size()) return true; bool res = v[index]; v[index] = true; return res; } bool CFolder::CheckStructure(unsigned numUnpackSizes) const { const unsigned kNumCodersMax = sizeof(UInt32) * 8; // don't change it const unsigned kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax const unsigned kNumBindsMax = 32; if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) return false; { CBoolVector v; BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); unsigned i; for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) return false; for (i = 0; i < PackStreams.Size(); i++) if (BoolVector_GetAndSet(v, PackStreams[i])) return false; BoolVector_Fill_False(v, numUnpackSizes); for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) return false; } UInt32 mask[kMaskSize]; unsigned i; for (i = 0; i < kMaskSize; i++) mask[i] = 0; { CUIntVector inStreamToCoder, outStreamToCoder; for (i = 0; i < Coders.Size(); i++) { CNum j; const CCoderInfo &coder = Coders[i]; for (j = 0; j < coder.NumInStreams; j++) inStreamToCoder.Add(i); for (j = 0; j < coder.NumOutStreams; j++) outStreamToCoder.Add(i); } for (i = 0; i < BindPairs.Size(); i++) { const CBindPair &bp = BindPairs[i]; mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]); } } for (i = 0; i < kMaskSize; i++) for (unsigned j = 0; j < kMaskSize; j++) if (((1 << j) & mask[i]) != 0) mask[i] |= mask[j]; for (i = 0; i < kMaskSize; i++) if (((1 << i) & mask[i]) != 0) return false; return true; } class CInArchiveException {}; class CUnsupportedFeatureException: public CInArchiveException {}; static void ThrowException() { throw CInArchiveException(); } static inline void ThrowEndOfData() { ThrowException(); } static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } static inline void ThrowIncorrect() { ThrowException(); } class CStreamSwitch { CInArchive *_archive; bool _needRemove; bool _needUpdatePos; public: CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} ~CStreamSwitch() { Remove(); } void Remove(); void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); void Set(CInArchive *archive, const CByteBuffer &byteBuffer); void Set(CInArchive *archive, const CObjectVector *dataVector); }; void CStreamSwitch::Remove() { if (_needRemove) { if (_archive->_inByteBack->GetRem() != 0) _archive->ThereIsHeaderError = true; _archive->DeleteByteStream(_needUpdatePos); _needRemove = false; } } void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) { Remove(); _archive = archive; _archive->AddByteStream(data, size); _needRemove = true; _needUpdatePos = needUpdatePos; } void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) { Set(archive, byteBuffer, byteBuffer.Size(), false); } void CStreamSwitch::Set(CInArchive *archive, const CObjectVector *dataVector) { Remove(); Byte external = archive->ReadByte(); if (external != 0) { CNum dataIndex = archive->ReadNum(); if (dataIndex >= dataVector->Size()) ThrowIncorrect(); Set(archive, (*dataVector)[dataIndex]); } } void CInArchive::AddByteStream(const Byte *buf, size_t size) { if (_numInByteBufs == kNumBufLevelsMax) ThrowIncorrect(); _inByteBack = &_inByteVector[_numInByteBufs++]; _inByteBack->Init(buf, size); } Byte CInByte2::ReadByte() { if (_pos >= _size) ThrowEndOfData(); return _buffer[_pos++]; } void CInByte2::ReadBytes(Byte *data, size_t size) { if (size > _size - _pos) ThrowEndOfData(); memcpy(data, _buffer + _pos, size); _pos += size; } void CInByte2::SkipData(UInt64 size) { if (size > _size - _pos) ThrowEndOfData(); _pos += (size_t)size; } void CInByte2::SkipData() { SkipData(ReadNumber()); } static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) { if (size == 0) { processed = 0; return 0; } Byte firstByte = *p++; size--; if ((firstByte & 0x80) == 0) { processed = 1; return firstByte; } Byte mask = 0x40; if (size == 0) { processed = 0; return 0; } UInt64 value = (UInt64)*p; p++; size--; for (unsigned i = 1; i < 8; i++) { if ((firstByte & mask) == 0) { UInt64 highPart = firstByte & (mask - 1); value += (highPart << (i * 8)); processed = i + 1; return value; } if (size == 0) { processed = 0; return 0; } value |= ((UInt64)*p << (i * 8)); p++; size--; mask >>= 1; } processed = 9; return value; } UInt64 CInByte2::ReadNumber() { size_t processed; UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); if (processed == 0) ThrowEndOfData(); _pos += processed; return res; } CNum CInByte2::ReadNum() { /* if (_pos < _size) { Byte val = _buffer[_pos]; if ((unsigned)val < 0x80) { _pos++; return (unsigned)val; } } */ UInt64 value = ReadNumber(); if (value > kNumMax) ThrowUnsupported(); return (CNum)value; } UInt32 CInByte2::ReadUInt32() { if (_pos + 4 > _size) ThrowEndOfData(); UInt32 res = Get32(_buffer + _pos); _pos += 4; return res; } UInt64 CInByte2::ReadUInt64() { if (_pos + 8 > _size) ThrowEndOfData(); UInt64 res = Get64(_buffer + _pos); _pos += 8; return res; } #define CHECK_SIGNATURE if (p[0] != '7' || p[1] != 'z' || p[2] != 0xBC || p[3] != 0xAF || p[4] != 0x27 || p[5] != 0x1C) return false; static inline bool TestSignature(const Byte *p) { CHECK_SIGNATURE return CrcCalc(p + 12, 20) == Get32(p + 8); } #ifdef FORMAT_7Z_RECOVERY static inline bool TestSignature2(const Byte *p) { CHECK_SIGNATURE; if (CrcCalc(p + 12, 20) == Get32(p + 8)) return true; for (unsigned i = 8; i < kHeaderSize; i++) if (p[i] != 0) return false; return (p[6] != 0 || p[7] != 0); } #else #define TestSignature2(p) TestSignature(p) #endif HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); if (TestSignature2(_header)) return S_OK; if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) return S_FALSE; const UInt32 kBufSize = 1 << 15; CByteArr buf(kBufSize); memcpy(buf, _header, kHeaderSize); UInt64 offset = 0; for (;;) { UInt32 readSize = kBufSize - kHeaderSize; { UInt64 rem = *searchHeaderSizeLimit - offset; if (readSize > rem) readSize = (UInt32)rem; if (readSize == 0) return S_FALSE; } UInt32 processed = 0; RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)); if (processed == 0) return S_FALSE; for (UInt32 pos = 0;;) { const Byte *p = buf + pos + 1; const Byte *lim = buf + processed; for (; p <= lim; p += 4) { if (p[0] == '7') break; if (p[1] == '7') { p += 1; break; } if (p[2] == '7') { p += 2; break; } if (p[3] == '7') { p += 3; break; } }; if (p > lim) break; pos = (UInt32)(p - buf); if (TestSignature(p)) { memcpy(_header, p, kHeaderSize); _arhiveBeginStreamPosition += offset + pos; return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL); } } offset += processed; memmove(buf, buf + processed, kHeaderSize); } } // S_FALSE means that file is not archive HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { HeadersSize = 0; Close(); RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) RINOK(stream->Seek(0, STREAM_SEEK_END, &_fileEndPosition)) RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL)) RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); _stream = stream; return S_OK; } void CInArchive::Close() { _numInByteBufs = 0; _stream.Release(); ThereIsHeaderError = false; } void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) { for (;;) { if (ReadID() == NID::kEnd) break; SkipData(); } } // CFolder &folder can be non empty. So we must set all fields void CInByte2::ParseFolder(CFolder &folder) { CNum numCoders = ReadNum(); folder.Coders.SetSize(numCoders); CNum numInStreams = 0; CNum numOutStreams = 0; CNum i; for (i = 0; i < numCoders; i++) { CCoderInfo &coder = folder.Coders[i]; { Byte mainByte = ReadByte(); if ((mainByte & 0xC0) != 0) ThrowUnsupported(); unsigned idSize = (mainByte & 0xF); if (idSize > 8 || idSize > GetRem()) ThrowUnsupported(); const Byte *longID = GetPtr(); UInt64 id = 0; for (unsigned j = 0; j < idSize; j++) id = ((id << 8) | longID[j]); SkipDataNoCheck(idSize); coder.MethodID = id; if ((mainByte & 0x10) != 0) { coder.NumInStreams = ReadNum(); coder.NumOutStreams = ReadNum(); } else { coder.NumInStreams = 1; coder.NumOutStreams = 1; } if ((mainByte & 0x20) != 0) { CNum propsSize = ReadNum(); coder.Props.Alloc((size_t)propsSize); ReadBytes((Byte *)coder.Props, (size_t)propsSize); } else coder.Props.Free(); } numInStreams += coder.NumInStreams; numOutStreams += coder.NumOutStreams; } CNum numBindPairs = numOutStreams - 1; folder.BindPairs.SetSize(numBindPairs); for (i = 0; i < numBindPairs; i++) { CBindPair &bp = folder.BindPairs[i]; bp.InIndex = ReadNum(); bp.OutIndex = ReadNum(); } if (numInStreams < numBindPairs) ThrowUnsupported(); CNum numPackStreams = numInStreams - numBindPairs; folder.PackStreams.SetSize(numPackStreams); if (numPackStreams == 1) { for (i = 0; i < numInStreams; i++) if (folder.FindBindPairForInStream(i) < 0) { folder.PackStreams[0] = i; break; } if (i == numInStreams) ThrowUnsupported(); } else for (i = 0; i < numPackStreams; i++) folder.PackStreams[i] = ReadNum(); } void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const { size_t startPos = FoCodersDataOffset[folderIndex]; CInByte2 inByte; inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); inByte.ParseFolder(folder); if (inByte.GetRem() != 0) throw 20120424; } void CDatabase::GetPath(unsigned index, UString &path) const { path.Empty(); if (!NameOffsets || !NamesBuf) return; size_t offset = NameOffsets[index]; size_t size = NameOffsets[index + 1] - offset - 1; if (size >= (1 << 20)) return; wchar_t *s = path.GetBuffer((unsigned)size); const Byte *p = ((const Byte *)NamesBuf + offset * 2); #if defined(_WIN32) && defined(MY_CPU_LE) wmemcpy(s, (const wchar_t *)p, size); #else for (size_t i = 0; i < size; i++) { *s = Get16(p); p += 2; s++; } #endif path.ReleaseBuffer((unsigned)size); } HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() { PropVariant_Clear(path); if (!NameOffsets || !NamesBuf) return S_OK; size_t offset = NameOffsets[index]; size_t size = NameOffsets[index + 1] - offset; if (size >= (1 << 14)) return S_OK; RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1)); wchar_t *s = path->bstrVal; const Byte *p = ((const Byte *)NamesBuf + offset * 2); for (size_t i = 0; i < size; i++) { wchar_t c = Get16(p); p += 2; #if WCHAR_PATH_SEPARATOR != L'/' if (c == L'/') c = WCHAR_PATH_SEPARATOR; #endif *s++ = c; } return S_OK; /* unsigned cur = index; unsigned size = 0; for (int i = 0;; i++) { size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; size += (unsigned)len; if (i > 256 || len > (1 << 14) || size > (1 << 14)) return PropVarEm_Set_Str(path, "[TOO-LONG]"); cur = Files[cur].Parent; if (cur < 0) break; } size--; RINOK(PropVarEm_Alloc_Bstr(path, size)); wchar_t *s = path->bstrVal; s += size; *s = 0; cur = index; for (;;) { unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; do { p -= 2; --s; wchar_t c = Get16(p); if (c == '/') c = WCHAR_PATH_SEPARATOR; *s = c; } while (--len); const CFileItem &file = Files[cur]; cur = file.Parent; if (cur < 0) return S_OK; *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); } */ } void CInArchive::WaitId(UInt64 id) { for (;;) { UInt64 type = ReadID(); if (type == id) return; if (type == NID::kEnd) ThrowIncorrect(); SkipData(); } } void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) { ReadBoolVector2(numItems, crcs.Defs); crcs.Vals.ClearAndSetSize(numItems); UInt32 *p = &crcs.Vals[0]; const bool *defs = &crcs.Defs[0]; for (unsigned i = 0; i < numItems; i++) { UInt32 crc = 0; if (defs[i]) crc = ReadUInt32(); p[i] = crc; } } void CInArchive::ReadPackInfo(CFolders &f) { CNum numPackStreams = ReadNum(); WaitId(NID::kSize); f.PackPositions.Alloc(numPackStreams + 1); f.NumPackStreams = numPackStreams; UInt64 sum = 0; for (CNum i = 0; i < numPackStreams; i++) { f.PackPositions[i] = sum; UInt64 packSize = ReadNumber(); sum += packSize; if (sum < packSize) ThrowIncorrect(); } f.PackPositions[numPackStreams] = sum; UInt64 type; for (;;) { type = ReadID(); if (type == NID::kEnd) return; if (type == NID::kCRC) { CUInt32DefVector PackCRCs; ReadHashDigests(numPackStreams, PackCRCs); continue; } SkipData(); } } void CInArchive::ReadUnpackInfo( const CObjectVector *dataVector, CFolders &folders) { WaitId(NID::kFolder); CNum numFolders = ReadNum(); CNum numCodersOutStreams = 0; { CStreamSwitch streamSwitch; streamSwitch.Set(this, dataVector); const Byte *startBufPtr = _inByteBack->GetPtr(); folders.NumFolders = numFolders; folders.FoStartPackStreamIndex.Alloc(numFolders + 1); folders.FoToMainUnpackSizeIndex.Alloc(numFolders); folders.FoCodersDataOffset.Alloc(numFolders + 1); folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); CRecordVector InStreamUsed; CRecordVector OutStreamUsed; CNum packStreamIndex = 0; CNum fo; CInByte2 *inByte = _inByteBack; for (fo = 0; fo < numFolders; fo++) { UInt32 numOutStreams = 0; UInt32 indexOfMainStream = 0; UInt32 numPackStreams = 0; folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; numOutStreams = 0; CNum numInStreams = 0; CNum numCoders = inByte->ReadNum(); for (CNum ci = 0; ci < numCoders; ci++) { Byte mainByte = inByte->ReadByte(); if ((mainByte & 0xC0) != 0) ThrowUnsupported(); unsigned idSize = (mainByte & 0xF); if (idSize > 8) ThrowUnsupported(); if (idSize > inByte->GetRem()) ThrowEndOfData(); const Byte *longID = inByte->GetPtr(); UInt64 id = 0; for (unsigned j = 0; j < idSize; j++) id = ((id << 8) | longID[j]); inByte->SkipDataNoCheck(idSize); if (folders.ParsedMethods.IDs.Size() < 128) folders.ParsedMethods.IDs.AddToUniqueSorted(id); CNum coderInStreams = 1; CNum coderOutStreams = 1; if ((mainByte & 0x10) != 0) { coderInStreams = inByte->ReadNum(); coderOutStreams = inByte->ReadNum(); } numInStreams += coderInStreams; if (numInStreams < coderInStreams) ThrowUnsupported(); numOutStreams += coderOutStreams; if (numOutStreams < coderOutStreams) ThrowUnsupported(); if ((mainByte & 0x20) != 0) { CNum propsSize = inByte->ReadNum(); if (propsSize > inByte->GetRem()) ThrowEndOfData(); if (id == k_LZMA2 && propsSize == 1) { Byte v = *_inByteBack->GetPtr(); if (folders.ParsedMethods.Lzma2Prop < v) folders.ParsedMethods.Lzma2Prop = v; } else if (id == k_LZMA && propsSize == 5) { UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); if (folders.ParsedMethods.LzmaDic < dicSize) folders.ParsedMethods.LzmaDic = dicSize; } inByte->SkipDataNoCheck((size_t)propsSize); } } if (numOutStreams == 1 && numInStreams == 1) { indexOfMainStream = 0; numPackStreams = 1; } else { UInt32 i; if (numOutStreams == 0) ThrowUnsupported(); CNum numBindPairs = numOutStreams - 1; if (numInStreams < numBindPairs) ThrowUnsupported(); if (numInStreams >= 256 || numOutStreams >= 256) ThrowUnsupported(); InStreamUsed.ClearAndSetSize(numInStreams); for (i = 0; i < numInStreams; i++) InStreamUsed[i] = false; OutStreamUsed.ClearAndSetSize(numOutStreams); for (i = 0; i < numOutStreams; i++) OutStreamUsed[i] = false; for (i = 0; i < numBindPairs; i++) { CNum index = ReadNum(); if (index >= numInStreams || InStreamUsed[index]) ThrowUnsupported(); InStreamUsed[index] = true; index = ReadNum(); if (index >= numOutStreams || OutStreamUsed[index]) ThrowUnsupported(); OutStreamUsed[index] = true; } numPackStreams = numInStreams - numBindPairs; if (numPackStreams != 1) for (i = 0; i < numPackStreams; i++) inByte->ReadNum(); // PackStreams for (i = 0; i < numOutStreams; i++) if (!OutStreamUsed[i]) { indexOfMainStream = i; break; } if (i == numOutStreams) ThrowUnsupported(); } folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; numCodersOutStreams += numOutStreams; folders.FoStartPackStreamIndex[fo] = packStreamIndex; packStreamIndex += numPackStreams; folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; } size_t dataSize = _inByteBack->GetPtr() - startBufPtr; folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; folders.FoStartPackStreamIndex[fo] = packStreamIndex; folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; folders.CodersData.CopyFrom(startBufPtr, dataSize); } WaitId(NID::kCodersUnpackSize); folders.CoderUnpackSizes.Alloc(numCodersOutStreams); for (CNum i = 0; i < numCodersOutStreams; i++) folders.CoderUnpackSizes[i] = ReadNumber(); for (;;) { UInt64 type = ReadID(); if (type == NID::kEnd) return; if (type == NID::kCRC) { ReadHashDigests(numFolders, folders.FolderCRCs); continue; } SkipData(); } } void CInArchive::ReadSubStreamsInfo( CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests) { folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); CNum i; for (i = 0; i < folders.NumFolders; i++) folders.NumUnpackStreamsVector[i] = 1; UInt64 type; for (;;) { type = ReadID(); if (type == NID::kNumUnpackStream) { for (i = 0; i < folders.NumFolders; i++) folders.NumUnpackStreamsVector[i] = ReadNum(); continue; } if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) break; SkipData(); } if (type == NID::kSize) { for (i = 0; i < folders.NumFolders; i++) { // v3.13 incorrectly worked with empty folders // v4.07: we check that folder is empty CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 0) continue; UInt64 sum = 0; for (CNum j = 1; j < numSubstreams; j++) { UInt64 size = ReadNumber(); unpackSizes.Add(size); sum += size; if (sum < size) ThrowIncorrect(); } UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); if (folderUnpackSize < sum) ThrowIncorrect(); unpackSizes.Add(folderUnpackSize - sum); } type = ReadID(); } else { for (i = 0; i < folders.NumFolders; i++) { /* v9.26 - v9.29 incorrectly worked: if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ CNum val = folders.NumUnpackStreamsVector[i]; if (val > 1) ThrowIncorrect(); if (val == 1) unpackSizes.Add(folders.GetFolderUnpackSize(i)); } } unsigned numDigests = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) numDigests += numSubstreams; } for (;;) { if (type == NID::kEnd) break; if (type == NID::kCRC) { // CUInt32DefVector digests2; // ReadHashDigests(numDigests, digests2); CBoolVector digests2; ReadBoolVector2(numDigests, digests2); digests.ClearAndSetSize(unpackSizes.Size()); unsigned k = 0; unsigned k2 = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { digests.Defs[k] = true; digests.Vals[k] = folders.FolderCRCs.Vals[i]; k++; } else for (CNum j = 0; j < numSubstreams; j++) { bool defined = digests2[k2++]; digests.Defs[k] = defined; UInt32 crc = 0; if (defined) crc = ReadUInt32(); digests.Vals[k] = crc; k++; } } // if (k != unpackSizes.Size()) throw 1234567; } else SkipData(); type = ReadID(); } if (digests.Defs.Size() != unpackSizes.Size()) { digests.ClearAndSetSize(unpackSizes.Size()); unsigned k = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { digests.Defs[k] = true; digests.Vals[k] = folders.FolderCRCs.Vals[i]; k++; } else for (CNum j = 0; j < numSubstreams; j++) { digests.Defs[k] = false; digests.Vals[k] = 0; k++; } } } } void CInArchive::ReadStreamsInfo( const CObjectVector *dataVector, UInt64 &dataOffset, CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests) { UInt64 type = ReadID(); if (type == NID::kPackInfo) { dataOffset = ReadNumber(); ReadPackInfo(folders); type = ReadID(); } if (type == NID::kUnpackInfo) { ReadUnpackInfo(dataVector, folders); type = ReadID(); } if (folders.NumFolders != 0 && !folders.PackPositions) { // if there are folders, we need PackPositions also folders.PackPositions.Alloc(1); folders.PackPositions[0] = 0; } if (type == NID::kSubStreamsInfo) { ReadSubStreamsInfo(folders, unpackSizes, digests); type = ReadID(); } else { folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); /* If digests.Defs.Size() == 0, it means that there are no crcs. So we don't need to fill digests with values. */ // digests.Vals.ClearAndSetSize(folders.NumFolders); // BoolVector_Fill_False(digests.Defs, folders.NumFolders); for (CNum i = 0; i < folders.NumFolders; i++) { folders.NumUnpackStreamsVector[i] = 1; unpackSizes.Add(folders.GetFolderUnpackSize(i)); // digests.Vals[i] = 0; } } if (type != NID::kEnd) ThrowIncorrect(); } void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) { v.ClearAndSetSize(numItems); Byte b = 0; Byte mask = 0; bool *p = &v[0]; for (unsigned i = 0; i < numItems; i++) { if (mask == 0) { b = ReadByte(); mask = 0x80; } p[i] = ((b & mask) != 0); mask >>= 1; } } void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) { Byte allAreDefined = ReadByte(); if (allAreDefined == 0) { ReadBoolVector(numItems, v); return; } v.ClearAndSetSize(numItems); bool *p = &v[0]; for (unsigned i = 0; i < numItems; i++) p[i] = true; } void CInArchive::ReadUInt64DefVector(const CObjectVector &dataVector, CUInt64DefVector &v, unsigned numItems) { ReadBoolVector2(numItems, v.Defs); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); v.Vals.ClearAndSetSize(numItems); UInt64 *p = &v.Vals[0]; const bool *defs = &v.Defs[0]; for (unsigned i = 0; i < numItems; i++) { UInt64 t = 0; if (defs[i]) t = ReadUInt64(); p[i] = t; } } HRESULT CInArchive::ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector &dataVector _7Z_DECODER_CRYPRO_VARS_DECL ) { CFolders folders; CRecordVector unpackSizes; CUInt32DefVector digests; ReadStreamsInfo(NULL, dataOffset, folders, unpackSizes, digests); CDecoder decoder( #ifdef _ST_MODE false #else true #endif ); for (CNum i = 0; i < folders.NumFolders; i++) { CByteBuffer &data = dataVector.AddNew(); UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); size_t unpackSize = (size_t)unpackSize64; if (unpackSize != unpackSize64) ThrowUnsupported(); data.Alloc(unpackSize); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr outStream = outStreamSpec; outStreamSpec->Init(data, unpackSize); HRESULT result = decoder.Decode( EXTERNAL_CODECS_LOC_VARS _stream, baseOffset + dataOffset, folders, i, outStream, NULL _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , false, 1 #endif ); RINOK(result); if (folders.FolderCRCs.ValidAndDefined(i)) if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) ThrowIncorrect(); } HeadersSize += folders.PackPositions[folders.NumPackStreams]; return S_OK; } HRESULT CInArchive::ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { UInt64 type = ReadID(); if (type == NID::kArchiveProperties) { ReadArchiveProperties(db.ArcInfo); type = ReadID(); } CObjectVector dataVector; if (type == NID::kAdditionalStreamsInfo) { HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS db.ArcInfo.StartPositionAfterHeader, db.ArcInfo.DataStartPosition2, dataVector _7Z_DECODER_CRYPRO_VARS ); RINOK(result); db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } CRecordVector unpackSizes; CUInt32DefVector digests; if (type == NID::kMainStreamsInfo) { ReadStreamsInfo(&dataVector, db.ArcInfo.DataStartPosition, (CFolders &)db, unpackSizes, digests); db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } db.Files.Clear(); if (type == NID::kFilesInfo) { CNum numFiles = ReadNum(); db.Files.ClearAndSetSize(numFiles); CNum i; /* db.Files.Reserve(numFiles); CNum i; for (i = 0; i < numFiles; i++) db.Files.Add(CFileItem()); */ db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); // if (!db.PackSizes.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); if (numFiles > 0 && !digests.Defs.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; for (;;) { UInt64 type = ReadID(); if (type == NID::kEnd) break; UInt64 size = ReadNumber(); if (size > _inByteBack->GetRem()) ThrowIncorrect(); CStreamSwitch switchProp; switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); bool addPropIdToList = true; bool isKnownType = true; if (type > ((UInt32)1 << 30)) isKnownType = false; else switch((UInt32)type) { case NID::kName: { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); size_t rem = _inByteBack->GetRem(); db.NamesBuf.Alloc(rem); ReadBytes(db.NamesBuf, rem); db.NameOffsets.Alloc(db.Files.Size() + 1); size_t pos = 0; unsigned i; for (i = 0; i < db.Files.Size(); i++) { size_t curRem = (rem - pos) / 2; const UInt16 *buf = (const UInt16 *)(db.NamesBuf + pos); size_t j; for (j = 0; j < curRem && buf[j] != 0; j++); if (j == curRem) ThrowEndOfData(); db.NameOffsets[i] = pos / 2; pos += j * 2 + 2; } db.NameOffsets[i] = pos / 2; if (pos != rem) ThereIsHeaderError = true; break; } case NID::kWinAttrib: { CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; file.AttribDefined = boolVector[i]; if (file.AttribDefined) file.Attrib = ReadUInt32(); } break; } /* case NID::kIsAux: { ReadBoolVector(db.Files.Size(), db.IsAux); break; } case NID::kParent: { db.IsTree = true; // CBoolVector boolVector; // ReadBoolVector2(db.Files.Size(), boolVector); // CStreamSwitch streamSwitch; // streamSwitch.Set(this, &dataVector); CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); db.ThereAreAltStreams = false; for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; // file.Parent = -1; // if (boolVector[i]) file.Parent = (int)ReadUInt32(); file.IsAltStream = !boolVector[i]; if (file.IsAltStream) db.ThereAreAltStreams = true; } break; } */ case NID::kEmptyStream: { ReadBoolVector(numFiles, emptyStreamVector); numEmptyStreams = 0; for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) if (emptyStreamVector[i]) numEmptyStreams++; BoolVector_Fill_False(emptyFileVector, numEmptyStreams); BoolVector_Fill_False(antiFileVector, numEmptyStreams); break; } case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; case NID::kDummy: { for (UInt64 j = 0; j < size; j++) if (ReadByte() != 0) ThereIsHeaderError = true; addPropIdToList = false; break; } /* case NID::kNtSecure: { try { { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); UInt32 numDescriptors = ReadUInt32(); size_t offset = 0; db.SecureOffsets.Clear(); for (i = 0; i < numDescriptors; i++) { UInt32 size = ReadUInt32(); db.SecureOffsets.Add(offset); offset += size; } // ThrowIncorrect();; db.SecureOffsets.Add(offset); db.SecureBuf.SetCapacity(offset); for (i = 0; i < numDescriptors; i++) { offset = db.SecureOffsets[i]; ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); } db.SecureIDs.Clear(); for (unsigned i = 0; i < db.Files.Size(); i++) { db.SecureIDs.Add(ReadNum()); // db.SecureIDs.Add(ReadUInt32()); } // ReadUInt32(); if (_inByteBack->GetRem() != 0) ThrowIncorrect();; } } catch(CInArchiveException &) { ThereIsHeaderError = true; addPropIdToList = isKnownType = false; db.ClearSecure(); } break; } */ default: addPropIdToList = isKnownType = false; } if (isKnownType) { if (addPropIdToList) db.ArcInfo.FileInfoPopIDs.Add(type); } else { db.UnsupportedFeatureWarning = true; _inByteBack->SkipRem(); } // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02) if (_inByteBack->GetRem() != 0) ThrowIncorrect(); } type = ReadID(); // Read (NID::kEnd) end of headers CNum emptyFileIndex = 0; CNum sizeIndex = 0; CNum numAntiItems = 0; for (i = 0; i < numEmptyStreams; i++) if (antiFileVector[i]) numAntiItems++; for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; bool isAnti; file.HasStream = !emptyStreamVector[i]; file.Crc = 0; if (file.HasStream) { file.IsDir = false; isAnti = false; file.Size = unpackSizes[sizeIndex]; file.CrcDefined = digests.ValidAndDefined(sizeIndex); if (file.CrcDefined) file.Crc = digests.Vals[sizeIndex]; sizeIndex++; } else { file.IsDir = !emptyFileVector[emptyFileIndex]; isAnti = antiFileVector[emptyFileIndex]; emptyFileIndex++; file.Size = 0; file.CrcDefined = false; } if (numAntiItems != 0) db.IsAnti.Add(isAnti); } } db.FillLinks(); /* if (type != NID::kEnd) ThrowIncorrect(); if (_inByteBack->GetRem() != 0) ThrowIncorrect(); */ return S_OK; } void CDbEx::FillLinks() { FolderStartFileIndex.ClearAndSetSize(NumFolders); FileIndexToFolderIndexMap.ClearAndSetSize(Files.Size()); CNum folderIndex = 0; CNum indexInFolder = 0; unsigned i; for (i = 0; i < Files.Size(); i++) { bool emptyStream = !Files[i].HasStream; if (indexInFolder == 0) { if (emptyStream) { FileIndexToFolderIndexMap[i] = kNumNoIndex; continue; } // v3.13 incorrectly worked with empty folders // v4.07: we skip empty folders for (;;) { if (folderIndex >= NumFolders) ThrowIncorrect(); FolderStartFileIndex[folderIndex] = i; if (NumUnpackStreamsVector[folderIndex] != 0) break; folderIndex++; } } FileIndexToFolderIndexMap[i] = folderIndex; if (emptyStream) continue; if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) { folderIndex++; indexInFolder = 0; } } if (indexInFolder != 0) folderIndex++; /* if (indexInFolder != 0) ThrowIncorrect(); */ for (;;) { if (folderIndex >= NumFolders) return; FolderStartFileIndex[folderIndex] = i; /* if (NumUnpackStreamsVector[folderIndex] != 0) ThrowIncorrect();; */ folderIndex++; } } HRESULT CInArchive::ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { db.Clear(); db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; db.ArcInfo.Version.Major = _header[6]; db.ArcInfo.Version.Minor = _header[7]; if (db.ArcInfo.Version.Major != kMajorVersion) { // db.UnsupportedVersion = true; return S_FALSE; } UInt64 nextHeaderOffset = Get64(_header + 12); UInt64 nextHeaderSize = Get64(_header + 20); UInt32 nextHeaderCRC = Get32(_header + 28); #ifdef FORMAT_7Z_RECOVERY UInt32 crcFromArc = Get32(_header + 8); if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) { UInt64 cur, fileSize; RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); const unsigned kCheckSize = 512; Byte buf[kCheckSize]; RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); UInt64 rem = fileSize - cur; unsigned checkSize = kCheckSize; if (rem < kCheckSize) checkSize = (unsigned)(rem); if (checkSize < 3) return S_FALSE; RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); if (buf[checkSize - 1] != 0) return S_FALSE; unsigned i; for (i = checkSize - 2;; i--) { if (buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo || buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo) break; if (i == 0) return S_FALSE; } nextHeaderSize = checkSize - i; nextHeaderOffset = rem - nextHeaderSize; nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); db.StartHeaderWasRecovered = true; } else #endif { // Crc was tested already at signature check // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); } db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; db.PhySize = kHeaderSize; db.IsArc = false; if ((Int64)nextHeaderOffset < 0 || nextHeaderSize > ((UInt64)1 << 62)) return S_FALSE; if (nextHeaderSize == 0) { if (nextHeaderOffset != 0) return S_FALSE; db.IsArc = true; return S_OK; } if (!db.StartHeaderWasRecovered) db.IsArc = true; HeadersSize += kHeaderSize + nextHeaderSize; db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) { db.UnexpectedEnd = true; return S_FALSE; } RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); size_t nextHeaderSize_t = (size_t)nextHeaderSize; if (nextHeaderSize_t != nextHeaderSize) return E_OUTOFMEMORY; CByteBuffer buffer2(nextHeaderSize_t); RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)); if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) ThrowIncorrect(); if (!db.StartHeaderWasRecovered) db.PhySizeWasConfirmed = true; CStreamSwitch streamSwitch; streamSwitch.Set(this, buffer2); CObjectVector dataVector; UInt64 type = ReadID(); if (type != NID::kHeader) { if (type != NID::kEncodedHeader) ThrowIncorrect(); HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS db.ArcInfo.StartPositionAfterHeader, db.ArcInfo.DataStartPosition2, dataVector _7Z_DECODER_CRYPRO_VARS ); RINOK(result); if (dataVector.Size() == 0) return S_OK; if (dataVector.Size() > 1) ThrowIncorrect(); streamSwitch.Remove(); streamSwitch.Set(this, dataVector.Front()); if (ReadID() != NID::kHeader) ThrowIncorrect(); } db.IsArc = true; db.HeadersSize = HeadersSize; return ReadHeader( EXTERNAL_CODECS_LOC_VARS db _7Z_DECODER_CRYPRO_VARS ); } HRESULT CInArchive::ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { try { HRESULT res = ReadDatabase2( EXTERNAL_CODECS_LOC_VARS db _7Z_DECODER_CRYPRO_VARS ); if (ThereIsHeaderError) db.ThereIsHeaderError = true; if (res == E_NOTIMPL) ThrowUnsupported(); return res; } catch(CUnsupportedFeatureException &) { db.UnsupportedFeatureError = true; return S_FALSE; } catch(CInArchiveException &) { db.ThereIsHeaderError = true; return S_FALSE; } } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.h0100777000000000000000000002320713761647206022734 0ustar00// 7zIn.h #ifndef __7Z_IN_H #define __7Z_IN_H #include "../../../Common/MyCom.h" #include "../../../Windows/PropVariant.h" #include "../../IPassword.h" #include "../../IStream.h" #include "../../Common/CreateCoder.h" #include "../../Common/InBuffer.h" #include "7zItem.h" namespace NArchive { namespace N7z { /* We don't need to init isEncrypted and passwordIsDefined We must upgrade them only */ #ifdef _NO_CRYPTO #define _7Z_DECODER_CRYPRO_VARS_DECL #define _7Z_DECODER_CRYPRO_VARS #else #define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined #define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined #endif struct CParsedMethods { Byte Lzma2Prop; UInt32 LzmaDic; CRecordVector IDs; CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} }; struct CFolders { CNum NumPackStreams; CNum NumFolders; CObjArray PackPositions; // NumPackStreams + 1 // CUInt32DefVector PackCRCs; // we don't use PackCRCs now CUInt32DefVector FolderCRCs; // NumFolders CObjArray NumUnpackStreamsVector; // NumFolders CObjArray CoderUnpackSizes; // including unpack sizes of bind coders CObjArray FoToCoderUnpackSizes; // NumFolders + 1 CObjArray FoStartPackStreamIndex; // NumFolders + 1 CObjArray FoToMainUnpackSizeIndex; // NumFolders CObjArray FoCodersDataOffset; // NumFolders + 1 CByteBuffer CodersData; CParsedMethods ParsedMethods; void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const { return FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]; } UInt64 GetFolderUnpackSize(unsigned folderIndex) const { return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]]; } UInt64 GetStreamPackSize(unsigned index) const { return PackPositions[index + 1] - PackPositions[index]; } void Clear() { NumPackStreams = 0; PackPositions.Free(); // PackCRCs.Clear(); NumFolders = 0; FolderCRCs.Clear(); NumUnpackStreamsVector.Free(); CoderUnpackSizes.Free(); FoToCoderUnpackSizes.Free(); FoStartPackStreamIndex.Free(); FoToMainUnpackSizeIndex.Free(); FoCodersDataOffset.Free(); CodersData.Free(); } }; struct CDatabase: public CFolders { CRecordVector Files; CUInt64DefVector CTime; CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; CRecordVector IsAnti; /* CRecordVector IsAux; CByteBuffer SecureBuf; CRecordVector SecureIDs; */ CByteBuffer NamesBuf; CObjArray NameOffsets; // numFiles + 1, offsets of utf-16 symbols /* void ClearSecure() { SecureBuf.Free(); SecureIDs.Clear(); } */ void Clear() { CFolders::Clear(); // ClearSecure(); NamesBuf.Free(); NameOffsets.Free(); Files.Clear(); CTime.Clear(); ATime.Clear(); MTime.Clear(); StartPos.Clear(); IsAnti.Clear(); // IsAux.Clear(); } bool IsSolid() const { for (CNum i = 0; i < NumFolders; i++) if (NumUnpackStreamsVector[i] > 1) return true; return false; } bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } const void * GetName(unsigned index) const { if (!NameOffsets || !NamesBuf) return NULL; return (const void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); }; void GetPath(unsigned index, UString &path) const; HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw(); }; struct CInArchiveInfo { CArchiveVersion Version; UInt64 StartPosition; UInt64 StartPositionAfterHeader; UInt64 DataStartPosition; UInt64 DataStartPosition2; CRecordVector FileInfoPopIDs; void Clear() { StartPosition = 0; StartPositionAfterHeader = 0; DataStartPosition = 0; DataStartPosition2 = 0; FileInfoPopIDs.Clear(); } }; struct CDbEx: public CDatabase { CInArchiveInfo ArcInfo; CRecordVector FolderStartFileIndex; CRecordVector FileIndexToFolderIndexMap; UInt64 HeadersSize; UInt64 PhySize; /* CRecordVector SecureOffsets; bool IsTree; bool ThereAreAltStreams; */ bool IsArc; bool PhySizeWasConfirmed; bool ThereIsHeaderError; bool UnexpectedEnd; // bool UnsupportedVersion; bool StartHeaderWasRecovered; bool UnsupportedFeatureWarning; bool UnsupportedFeatureError; /* void ClearSecureEx() { ClearSecure(); SecureOffsets.Clear(); } */ void Clear() { IsArc = false; PhySizeWasConfirmed = false; ThereIsHeaderError = false; UnexpectedEnd = false; // UnsupportedVersion = false; StartHeaderWasRecovered = false; UnsupportedFeatureError = false; UnsupportedFeatureWarning = false; /* IsTree = false; ThereAreAltStreams = false; */ CDatabase::Clear(); // SecureOffsets.Clear(); ArcInfo.Clear(); FolderStartFileIndex.Clear(); FileIndexToFolderIndexMap.Clear(); HeadersSize = 0; PhySize = 0; } void FillLinks(); UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const { return ArcInfo.DataStartPosition + PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder]; } UInt64 GetFolderFullPackSize(unsigned folderIndex) const { return PackPositions[FoStartPackStreamIndex[folderIndex + 1]] - PackPositions[FoStartPackStreamIndex[folderIndex]]; } UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const { unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex; return PackPositions[i + 1] - PackPositions[i]; } UInt64 GetFilePackSize(CNum fileIndex) const { CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; if (folderIndex != kNumNoIndex) if (FolderStartFileIndex[folderIndex] == fileIndex) return GetFolderFullPackSize(folderIndex); return 0; } }; const unsigned kNumBufLevelsMax = 4; struct CInByte2 { const Byte *_buffer; public: size_t _size; size_t _pos; size_t GetRem() const { return _size - _pos; } const Byte *GetPtr() const { return _buffer + _pos; } void Init(const Byte *buffer, size_t size) { _buffer = buffer; _size = size; _pos = 0; } Byte ReadByte(); void ReadBytes(Byte *data, size_t size); void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; } void SkipData(UInt64 size); void SkipData(); void SkipRem() { _pos = _size; } UInt64 ReadNumber(); CNum ReadNum(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); void ParseFolder(CFolder &folder); }; class CStreamSwitch; const UInt32 kHeaderSize = 32; class CInArchive { friend class CStreamSwitch; CMyComPtr _stream; unsigned _numInByteBufs; CInByte2 _inByteVector[kNumBufLevelsMax]; CInByte2 *_inByteBack; bool ThereIsHeaderError; UInt64 _arhiveBeginStreamPosition; UInt64 _fileEndPosition; Byte _header[kHeaderSize]; UInt64 HeadersSize; void AddByteStream(const Byte *buffer, size_t size); void DeleteByteStream(bool needUpdatePos) { _numInByteBufs--; if (_numInByteBufs > 0) { _inByteBack = &_inByteVector[_numInByteBufs - 1]; if (needUpdatePos) _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos; } } private: HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } Byte ReadByte() { return _inByteBack->ReadByte(); } UInt64 ReadNumber() { return _inByteBack->ReadNumber(); } CNum ReadNum() { return _inByteBack->ReadNum(); } UInt64 ReadID() { return _inByteBack->ReadNumber(); } UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); } UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } void SkipData(UInt64 size) { _inByteBack->SkipData(size); } void SkipData() { _inByteBack->SkipData(); } void WaitId(UInt64 id); void ReadArchiveProperties(CInArchiveInfo &archiveInfo); void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); void ReadPackInfo(CFolders &f); void ReadUnpackInfo( const CObjectVector *dataVector, CFolders &folders); void ReadSubStreamsInfo( CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests); void ReadStreamsInfo( const CObjectVector *dataVector, UInt64 &dataOffset, CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests); void ReadBoolVector(unsigned numItems, CBoolVector &v); void ReadBoolVector2(unsigned numItems, CBoolVector &v); void ReadUInt64DefVector(const CObjectVector &dataVector, CUInt64DefVector &v, unsigned numItems); HRESULT ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector &dataVector _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); public: CInArchive(): _numInByteBufs(0) { } HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive void Close(); HRESULT ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zItem.h0100777000000000000000000000642013761647206023262 0ustar00// 7zItem.h #ifndef __7Z_ITEM_H #define __7Z_ITEM_H #include "../../../Common/MyBuffer.h" #include "../../../Common/MyString.h" #include "../../Common/MethodId.h" #include "7zHeader.h" namespace NArchive { namespace N7z { const UInt64 k_AES = 0x06F10701; typedef UInt32 CNum; const CNum kNumMax = 0x7FFFFFFF; const CNum kNumNoIndex = 0xFFFFFFFF; struct CCoderInfo { CMethodId MethodID; CByteBuffer Props; CNum NumInStreams; CNum NumOutStreams; bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; struct CBindPair { CNum InIndex; CNum OutIndex; }; struct CFolder { CObjArray2 Coders; CObjArray2 BindPairs; CObjArray2 PackStreams; CNum GetNumOutStreams() const { CNum result = 0; FOR_VECTOR(i, Coders) result += Coders[i].NumOutStreams; return result; } int FindBindPairForInStream(CNum inStreamIndex) const { FOR_VECTOR(i, BindPairs) if (BindPairs[i].InIndex == inStreamIndex) return i; return -1; } int FindBindPairForOutStream(CNum outStreamIndex) const { FOR_VECTOR(i, BindPairs) if (BindPairs[i].OutIndex == outStreamIndex) return i; return -1; } int FindPackStreamArrayIndex(CNum inStreamIndex) const { FOR_VECTOR(i, PackStreams) if (PackStreams[i] == inStreamIndex) return i; return -1; } int GetIndexOfMainOutStream() const { for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--) if (FindBindPairForOutStream(i) < 0) return i; throw 1; } bool IsEncrypted() const { for (int i = Coders.Size() - 1; i >= 0; i--) if (Coders[i].MethodID == k_AES) return true; return false; } bool CheckStructure(unsigned numUnpackSizes) const; }; struct CUInt32DefVector { CBoolVector Defs; CRecordVector Vals; void ClearAndSetSize(unsigned newSize) { Defs.ClearAndSetSize(newSize); Vals.ClearAndSetSize(newSize); } void Clear() { Defs.Clear(); Vals.Clear(); } void ReserveDown() { Defs.ReserveDown(); Vals.ReserveDown(); } bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } }; struct CUInt64DefVector { CBoolVector Defs; CRecordVector Vals; void Clear() { Defs.Clear(); Vals.Clear(); } void ReserveDown() { Defs.ReserveDown(); Vals.ReserveDown(); } bool GetItem(unsigned index, UInt64 &value) const { if (index < Defs.Size() && Defs[index]) { value = Vals[index]; return true; } value = 0; return false; } void SetItem(unsigned index, bool defined, UInt64 value); bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } }; struct CFileItem { UInt64 Size; UInt32 Attrib; UInt32 Crc; /* int Parent; bool IsAltStream; */ bool HasStream; // Test it !!! it means that there is // stream in some folder. It can be empty stream bool IsDir; bool CrcDefined; bool AttribDefined; CFileItem(): /* Parent(-1), IsAltStream(false), */ HasStream(true), IsDir(false), CrcDefined(false), AttribDefined(false) {} void SetAttrib(UInt32 attrib) { AttribDefined = true; Attrib = attrib; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp0100777000000000000000000005325513761647206023476 0ustar00// 7zOut.cpp #include "StdAfx.h" #include "../../../../C/7zCrc.h" #include "../../Common/StreamObjects.h" #include "7zOut.h" namespace NArchive { namespace N7z { HRESULT COutArchive::WriteSignature() { Byte buf[8]; memcpy(buf, kSignature, kSignatureSize); buf[kSignatureSize] = kMajorVersion; buf[kSignatureSize + 1] = 4; return WriteDirect(buf, 8); } #ifdef _7Z_VOL HRESULT COutArchive::WriteFinishSignature() { RINOK(WriteDirect(kFinishSignature, kSignatureSize)); CArchiveVersion av; av.Major = kMajorVersion; av.Minor = 2; RINOK(WriteDirectByte(av.Major)); return WriteDirectByte(av.Minor); } #endif static void SetUInt32(Byte *p, UInt32 d) { for (int i = 0; i < 4; i++, d >>= 8) p[i] = (Byte)d; } static void SetUInt64(Byte *p, UInt64 d) { for (int i = 0; i < 8; i++, d >>= 8) p[i] = (Byte)d; } HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) { Byte buf[24]; SetUInt64(buf + 4, h.NextHeaderOffset); SetUInt64(buf + 12, h.NextHeaderSize); SetUInt32(buf + 20, h.NextHeaderCRC); SetUInt32(buf, CrcCalc(buf + 4, 20)); return WriteDirect(buf, 24); } #ifdef _7Z_VOL HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) { CCRC crc; crc.UpdateUInt64(h.NextHeaderOffset); crc.UpdateUInt64(h.NextHeaderSize); crc.UpdateUInt32(h.NextHeaderCRC); crc.UpdateUInt64(h.ArchiveStartOffset); crc.UpdateUInt64(h.AdditionalStartBlockSize); RINOK(WriteDirectUInt32(crc.GetDigest())); RINOK(WriteDirectUInt64(h.NextHeaderOffset)); RINOK(WriteDirectUInt64(h.NextHeaderSize)); RINOK(WriteDirectUInt32(h.NextHeaderCRC)); RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); return WriteDirectUInt64(h.AdditionalStartBlockSize); } #endif HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker) { Close(); #ifdef _7Z_VOL // endMarker = false; _endMarker = endMarker; #endif SeqStream = stream; if (!endMarker) { SeqStream.QueryInterface(IID_IOutStream, &Stream); if (!Stream) { return E_NOTIMPL; // endMarker = true; } } #ifdef _7Z_VOL if (endMarker) { /* CStartHeader sh; sh.NextHeaderOffset = (UInt32)(Int32)-1; sh.NextHeaderSize = (UInt32)(Int32)-1; sh.NextHeaderCRC = 0; WriteStartHeader(sh); */ } else #endif { if (!Stream) return E_FAIL; RINOK(WriteSignature()); RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos)); } return S_OK; } void COutArchive::Close() { SeqStream.Release(); Stream.Release(); } HRESULT COutArchive::SkipPrefixArchiveHeader() { #ifdef _7Z_VOL if (_endMarker) return S_OK; #endif Byte buf[24]; memset(buf, 0, 24); return WriteDirect(buf, 24); } UInt64 COutArchive::GetPos() const { if (_countMode) return _countSize; if (_writeToStream) return _outByte.GetProcessedSize(); return _outByte2.GetPos(); } void COutArchive::WriteBytes(const void *data, size_t size) { if (_countMode) _countSize += size; else if (_writeToStream) { _outByte.WriteBytes(data, size); _crc = CrcUpdate(_crc, data, size); } else _outByte2.WriteBytes(data, size); } void COutArchive::WriteByte(Byte b) { if (_countMode) _countSize++; else if (_writeToStream) { _outByte.WriteByte(b); _crc = CRC_UPDATE_BYTE(_crc, b); } else _outByte2.WriteByte(b); } void COutArchive::WriteUInt32(UInt32 value) { for (int i = 0; i < 4; i++) { WriteByte((Byte)value); value >>= 8; } } void COutArchive::WriteUInt64(UInt64 value) { for (int i = 0; i < 8; i++) { WriteByte((Byte)value); value >>= 8; } } void COutArchive::WriteNumber(UInt64 value) { Byte firstByte = 0; Byte mask = 0x80; int i; for (i = 0; i < 8; i++) { if (value < ((UInt64(1) << ( 7 * (i + 1))))) { firstByte |= Byte(value >> (8 * i)); break; } firstByte |= mask; mask >>= 1; } WriteByte(firstByte); for (;i > 0; i--) { WriteByte((Byte)value); value >>= 8; } } static UInt32 GetBigNumberSize(UInt64 value) { int i; for (i = 1; i < 9; i++) if (value < (((UInt64)1 << (i * 7)))) break; return i; } #ifdef _7Z_VOL UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) { UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; if (nameLength != 0) { nameLength = (nameLength + 1) * 2; result += nameLength + GetBigNumberSize(nameLength) + 2; } if (props) { result += 20; } if (result >= 128) result++; result += kSignatureSize + 2 + kFinishHeaderSize; return result; } UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) { UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); int testSize; if (volSize > headersSizeBase) testSize = volSize - headersSizeBase; else testSize = 1; UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); UInt64 pureSize = 1; if (volSize > headersSize) pureSize = volSize - headersSize; return pureSize; } #endif void COutArchive::WriteFolder(const CFolder &folder) { WriteNumber(folder.Coders.Size()); unsigned i; for (i = 0; i < folder.Coders.Size(); i++) { const CCoderInfo &coder = folder.Coders[i]; { size_t propsSize = coder.Props.Size(); UInt64 id = coder.MethodID; int idSize; for (idSize = 1; idSize < sizeof(id); idSize++) if ((id >> (8 * idSize)) == 0) break; Byte longID[15]; for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) longID[t] = (Byte)(id & 0xFF); Byte b; b = (Byte)(idSize & 0xF); bool isComplex = !coder.IsSimpleCoder(); b |= (isComplex ? 0x10 : 0); b |= ((propsSize != 0) ? 0x20 : 0 ); WriteByte(b); WriteBytes(longID, idSize); if (isComplex) { WriteNumber(coder.NumInStreams); WriteNumber(coder.NumOutStreams); } if (propsSize == 0) continue; WriteNumber(propsSize); WriteBytes(coder.Props, propsSize); } } for (i = 0; i < folder.BindPairs.Size(); i++) { const CBindPair &bindPair = folder.BindPairs[i]; WriteNumber(bindPair.InIndex); WriteNumber(bindPair.OutIndex); } if (folder.PackStreams.Size() > 1) for (i = 0; i < folder.PackStreams.Size(); i++) { WriteNumber(folder.PackStreams[i]); } } void COutArchive::WriteBoolVector(const CBoolVector &boolVector) { Byte b = 0; Byte mask = 0x80; FOR_VECTOR (i, boolVector) { if (boolVector[i]) b |= mask; mask >>= 1; if (mask == 0) { WriteByte(b); mask = 0x80; b = 0; } } if (mask != 0x80) WriteByte(b); } static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) { WriteByte(id); WriteNumber(Bv_GetSizeInBytes(boolVector)); WriteBoolVector(boolVector); } void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) { unsigned numDefined = 0; unsigned i; for (i = 0; i < digests.Defs.Size(); i++) if (digests.Defs[i]) numDefined++; if (numDefined == 0) return; WriteByte(NID::kCRC); if (numDefined == digests.Defs.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(digests.Defs); } for (i = 0; i < digests.Defs.Size(); i++) if (digests.Defs[i]) WriteUInt32(digests.Vals[i]); } void COutArchive::WritePackInfo( UInt64 dataOffset, const CRecordVector &packSizes, const CUInt32DefVector &packCRCs) { if (packSizes.IsEmpty()) return; WriteByte(NID::kPackInfo); WriteNumber(dataOffset); WriteNumber(packSizes.Size()); WriteByte(NID::kSize); FOR_VECTOR (i, packSizes) WriteNumber(packSizes[i]); WriteHashDigests(packCRCs); WriteByte(NID::kEnd); } void COutArchive::WriteUnpackInfo(const CObjectVector &folders, const COutFolders &outFolders) { if (folders.IsEmpty()) return; WriteByte(NID::kUnpackInfo); WriteByte(NID::kFolder); WriteNumber(folders.Size()); { WriteByte(0); FOR_VECTOR (i, folders) WriteFolder(folders[i]); } WriteByte(NID::kCodersUnpackSize); FOR_VECTOR (i, outFolders.CoderUnpackSizes) WriteNumber(outFolders.CoderUnpackSizes[i]); WriteHashDigests(outFolders.FolderUnpackCRCs); WriteByte(NID::kEnd); } void COutArchive::WriteSubStreamsInfo(const CObjectVector &folders, const COutFolders &outFolders, const CRecordVector &unpackSizes, const CUInt32DefVector &digests) { const CRecordVector &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector; WriteByte(NID::kSubStreamsInfo); unsigned i; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) if (numUnpackStreamsInFolders[i] != 1) { WriteByte(NID::kNumUnpackStream); for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) WriteNumber(numUnpackStreamsInFolders[i]); break; } for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) if (numUnpackStreamsInFolders[i] > 1) { WriteByte(NID::kSize); CNum index = 0; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) { CNum num = numUnpackStreamsInFolders[i]; for (CNum j = 0; j < num; j++) { if (j + 1 != num) WriteNumber(unpackSizes[index]); index++; } } break; } CUInt32DefVector digests2; unsigned digestIndex = 0; for (i = 0; i < folders.Size(); i++) { unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i]; if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i)) digestIndex++; else for (unsigned j = 0; j < numSubStreams; j++, digestIndex++) { digests2.Defs.Add(digests.Defs[digestIndex]); digests2.Vals.Add(digests.Vals[digestIndex]); } } WriteHashDigests(digests2); WriteByte(NID::kEnd); } // 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) { if (!_useAlign) return; pos += (unsigned)GetPos(); pos &= (alignSize - 1); if (pos == 0) return; unsigned skip = alignSize - pos; if (skip < 2) skip += alignSize; skip -= 2; WriteByte(NID::kDummy); WriteByte((Byte)skip); for (unsigned i = 0; i < skip; i++) WriteByte(0); } void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize) { const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize); WriteByte(type); WriteNumber(dataSize); if (numDefined == v.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(v); } WriteByte(0); } void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) { unsigned numDefined = 0; unsigned i; for (i = 0; i < v.Defs.Size(); i++) if (v.Defs[i]) numDefined++; if (numDefined == 0) return; WriteAlignedBoolHeader(v.Defs, numDefined, type, 8); for (i = 0; i < v.Defs.Size(); i++) if (v.Defs[i]) WriteUInt64(v.Vals[i]); } HRESULT COutArchive::EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders) { CBufInStream *streamSpec = new CBufInStream; CMyComPtr stream = streamSpec; streamSpec->Init(data, data.Size()); outFolders.FolderUnpackCRCs.Defs.Add(true); outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); // outFolders.NumUnpackStreamsVector.Add(1); UInt64 dataSize64 = data.Size(); UInt64 unpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS stream, NULL, &dataSize64, folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL)) return S_OK; } void COutArchive::WriteHeader( const CArchiveDatabaseOut &db, // const CHeaderOptions &headerOptions, UInt64 &headerOffset) { /* bool thereIsSecure = (db.SecureBuf.Size() != 0); */ _useAlign = true; unsigned i; UInt64 packedSize = 0; for (i = 0; i < db.PackSizes.Size(); i++) packedSize += db.PackSizes[i]; headerOffset = packedSize; WriteByte(NID::kHeader); // Archive Properties if (db.Folders.Size() > 0) { WriteByte(NID::kMainStreamsInfo); WritePackInfo(0, db.PackSizes, db.PackCRCs); WriteUnpackInfo(db.Folders, (const COutFolders &)db); CRecordVector unpackSizes; CUInt32DefVector digests; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (!file.HasStream) continue; unpackSizes.Add(file.Size); digests.Defs.Add(file.CrcDefined); digests.Vals.Add(file.Crc); } WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests); WriteByte(NID::kEnd); } if (db.Files.IsEmpty()) { WriteByte(NID::kEnd); return; } WriteByte(NID::kFilesInfo); WriteNumber(db.Files.Size()); { /* ---------- Empty Streams ---------- */ CBoolVector emptyStreamVector; emptyStreamVector.ClearAndSetSize(db.Files.Size()); unsigned numEmptyStreams = 0; for (i = 0; i < db.Files.Size(); i++) if (db.Files[i].HasStream) emptyStreamVector[i] = false; else { emptyStreamVector[i] = true; numEmptyStreams++; } if (numEmptyStreams != 0) { WritePropBoolVector(NID::kEmptyStream, emptyStreamVector); CBoolVector emptyFileVector, antiVector; emptyFileVector.ClearAndSetSize(numEmptyStreams); antiVector.ClearAndSetSize(numEmptyStreams); bool thereAreEmptyFiles = false, thereAreAntiItems = false; unsigned cur = 0; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (file.HasStream) continue; emptyFileVector[cur] = !file.IsDir; if (!file.IsDir) thereAreEmptyFiles = true; bool isAnti = db.IsItemAnti(i); antiVector[cur] = isAnti; if (isAnti) thereAreAntiItems = true; cur++; } if (thereAreEmptyFiles) WritePropBoolVector(NID::kEmptyFile, emptyFileVector); if (thereAreAntiItems) WritePropBoolVector(NID::kAnti, antiVector); } } { /* ---------- Names ---------- */ unsigned numDefined = 0; size_t namesDataSize = 0; FOR_VECTOR (i, db.Files) { const UString &name = db.Names[i]; if (!name.IsEmpty()) numDefined++; namesDataSize += (name.Len() + 1) * 2; } if (numDefined > 0) { namesDataSize++; SkipAlign(2 + GetBigNumberSize(namesDataSize), 16); WriteByte(NID::kName); WriteNumber(namesDataSize); WriteByte(0); FOR_VECTOR (i, db.Files) { const UString &name = db.Names[i]; for (unsigned t = 0; t <= name.Len(); t++) { wchar_t c = name[t]; WriteByte((Byte)c); WriteByte((Byte)(c >> 8)); } } } } /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime); /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime); /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime); WriteUInt64DefVector(db.StartPos, NID::kStartPos); { /* ---------- Write Attrib ---------- */ CBoolVector boolVector; boolVector.ClearAndSetSize(db.Files.Size()); unsigned numDefined = 0; for (i = 0; i < db.Files.Size(); i++) { bool defined = db.Files[i].AttribDefined; boolVector[i] = defined; if (defined) numDefined++; } if (numDefined != 0) { WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4); for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (file.AttribDefined) WriteUInt32(file.Attrib); } } } /* { // ---------- Write IsAux ---------- unsigned numAux = 0; const CBoolVector &isAux = db.IsAux; for (i = 0; i < isAux.Size(); i++) if (isAux[i]) numAux++; if (numAux > 0) { const unsigned bvSize = Bv_GetSizeInBytes(isAux); WriteByte(NID::kIsAux); WriteNumber(bvSize); WriteBoolVector(isAux); } } { // ---------- Write Parent ---------- CBoolVector boolVector; boolVector.Reserve(db.Files.Size()); unsigned numIsDir = 0; unsigned numParentLinks = 0; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; bool defined = !file.IsAltStream; boolVector.Add(defined); if (defined) numIsDir++; if (file.Parent >= 0) numParentLinks++; } if (numParentLinks > 0) { // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4); const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector); const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1; SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4); WriteByte(NID::kParent); WriteNumber(dataSize); if (numIsDir == boolVector.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(boolVector); } for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; // if (file.Parent >= 0) WriteUInt32(file.Parent); } } } if (thereIsSecure) { UInt64 secureDataSize = 1 + 4 + db.SecureBuf.Size() + db.SecureSizes.Size() * 4; // secureDataSize += db.SecureIDs.Size() * 4; for (i = 0; i < db.SecureIDs.Size(); i++) secureDataSize += GetBigNumberSize(db.SecureIDs[i]); SkipAlign(2 + GetBigNumberSize(secureDataSize), 4); WriteByte(NID::kNtSecure); WriteNumber(secureDataSize); WriteByte(0); WriteUInt32(db.SecureSizes.Size()); for (i = 0; i < db.SecureSizes.Size(); i++) WriteUInt32(db.SecureSizes[i]); WriteBytes(db.SecureBuf, db.SecureBuf.Size()); for (i = 0; i < db.SecureIDs.Size(); i++) { WriteNumber(db.SecureIDs[i]); // WriteUInt32(db.SecureIDs[i]); } } */ WriteByte(NID::kEnd); // for files WriteByte(NID::kEnd); // for headers } HRESULT COutArchive::WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions) { if (!db.CheckNumFiles()) return E_FAIL; UInt64 headerOffset; UInt32 headerCRC; UInt64 headerSize; if (db.IsEmpty()) { headerSize = 0; headerOffset = 0; headerCRC = CrcCalc(0, 0); } else { bool encodeHeaders = false; if (options != 0) if (options->IsEmpty()) options = 0; if (options != 0) if (options->PasswordIsDefined || headerOptions.CompressMainHeader) encodeHeaders = true; _outByte.SetStream(SeqStream); _outByte.Init(); _crc = CRC_INIT_VAL; _countMode = encodeHeaders; _writeToStream = true; _countSize = 0; WriteHeader(db, /* headerOptions, */ headerOffset); if (encodeHeaders) { CByteBuffer buf(_countSize); _outByte2.Init((Byte *)buf, _countSize); _countMode = false; _writeToStream = false; WriteHeader(db, /* headerOptions, */ headerOffset); if (_countSize != _outByte2.GetPos()) return E_FAIL; CCompressionMethodMode encryptOptions; encryptOptions.PasswordIsDefined = options->PasswordIsDefined; encryptOptions.Password = options->Password; CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); CRecordVector packSizes; CObjectVector folders; COutFolders outFolders; RINOK(EncodeStream( EXTERNAL_CODECS_LOC_VARS encoder, buf, packSizes, folders, outFolders)); _writeToStream = true; if (folders.Size() == 0) throw 1; WriteID(NID::kEncodedHeader); WritePackInfo(headerOffset, packSizes, CUInt32DefVector()); WriteUnpackInfo(folders, outFolders); WriteByte(NID::kEnd); FOR_VECTOR (i, packSizes) headerOffset += packSizes[i]; } RINOK(_outByte.Flush()); headerCRC = CRC_GET_DIGEST(_crc); headerSize = _outByte.GetProcessedSize(); } #ifdef _7Z_VOL if (_endMarker) { CFinishHeader h; h.NextHeaderSize = headerSize; h.NextHeaderCRC = headerCRC; h.NextHeaderOffset = UInt64(0) - (headerSize + 4 + kFinishHeaderSize); h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; h.AdditionalStartBlockSize = 0; RINOK(WriteFinishHeader(h)); return WriteFinishSignature(); } else #endif { CStartHeader h; h.NextHeaderSize = headerSize; h.NextHeaderCRC = headerCRC; h.NextHeaderOffset = headerOffset; RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL)); return WriteStartHeader(h); } } void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) { while (index >= Defs.Size()) Defs.Add(false); Defs[index] = defined; if (!defined) return; while (index >= Vals.Size()) Vals.Add(0); Vals[index] = value; } void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name) { unsigned index = Files.Size(); CTime.SetItem(index, file2.CTimeDefined, file2.CTime); ATime.SetItem(index, file2.ATimeDefined, file2.ATime); MTime.SetItem(index, file2.MTimeDefined, file2.MTime); StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); SetItem_Anti(index, file2.IsAnti); // SetItem_Aux(index, file2.IsAux); Names.Add(name); Files.Add(file); } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.h0100777000000000000000000001560213761647206023135 0ustar00// 7zOut.h #ifndef __7Z_OUT_H #define __7Z_OUT_H #include "7zCompressionMode.h" #include "7zEncode.h" #include "7zHeader.h" #include "7zItem.h" #include "../../Common/OutBuffer.h" #include "../../Common/StreamUtils.h" namespace NArchive { namespace N7z { class CWriteBufferLoc { Byte *_data; size_t _size; size_t _pos; public: CWriteBufferLoc(): _size(0), _pos(0) {} void Init(Byte *data, size_t size) { _data = data; _size = size; _pos = 0; } void WriteBytes(const void *data, size_t size) { if (size > _size - _pos) throw 1; memcpy(_data + _pos, data, size); _pos += size; } void WriteByte(Byte b) { if (_size == _pos) throw 1; _data[_pos++] = b; } size_t GetPos() const { return _pos; } }; struct CHeaderOptions { bool CompressMainHeader; /* bool WriteCTime; bool WriteATime; bool WriteMTime; */ CHeaderOptions(): CompressMainHeader(true) /* , WriteCTime(false) , WriteATime(false) , WriteMTime(true) */ {} }; struct CFileItem2 { UInt64 CTime; UInt64 ATime; UInt64 MTime; UInt64 StartPos; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; bool StartPosDefined; bool IsAnti; // bool IsAux; void Init() { CTimeDefined = false; ATimeDefined = false; MTimeDefined = false; StartPosDefined = false; IsAnti = false; // IsAux = false; } }; struct COutFolders { CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. CRecordVector NumUnpackStreamsVector; CRecordVector CoderUnpackSizes; // including unpack sizes of bind coders void OutFoldersClear() { FolderUnpackCRCs.Clear(); NumUnpackStreamsVector.Clear(); CoderUnpackSizes.Clear(); } void OutFoldersReserveDown() { FolderUnpackCRCs.ReserveDown(); NumUnpackStreamsVector.ReserveDown(); CoderUnpackSizes.ReserveDown(); } }; struct CArchiveDatabaseOut: public COutFolders { CRecordVector PackSizes; CUInt32DefVector PackCRCs; CObjectVector Folders; CRecordVector Files; UStringVector Names; CUInt64DefVector CTime; CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; CRecordVector IsAnti; /* CRecordVector IsAux; CByteBuffer SecureBuf; CRecordVector SecureSizes; CRecordVector SecureIDs; void ClearSecure() { SecureBuf.Free(); SecureSizes.Clear(); SecureIDs.Clear(); } */ void Clear() { OutFoldersClear(); PackSizes.Clear(); PackCRCs.Clear(); Folders.Clear(); Files.Clear(); Names.Clear(); CTime.Clear(); ATime.Clear(); MTime.Clear(); StartPos.Clear(); IsAnti.Clear(); /* IsAux.Clear(); ClearSecure(); */ } void ReserveDown() { OutFoldersReserveDown(); PackSizes.ReserveDown(); PackCRCs.ReserveDown(); Folders.ReserveDown(); Files.ReserveDown(); Names.ReserveDown(); CTime.ReserveDown(); ATime.ReserveDown(); MTime.ReserveDown(); StartPos.ReserveDown(); IsAnti.ReserveDown(); /* IsAux.ReserveDown(); */ } bool IsEmpty() const { return ( PackSizes.IsEmpty() && NumUnpackStreamsVector.IsEmpty() && Folders.IsEmpty() && Files.IsEmpty()); } bool CheckNumFiles() const { unsigned size = Files.Size(); return ( CTime.CheckSize(size) && ATime.CheckSize(size) && MTime.CheckSize(size) && StartPos.CheckSize(size) && (size == IsAnti.Size() || IsAnti.Size() == 0)); } bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } void SetItem_Anti(unsigned index, bool isAnti) { while (index >= IsAnti.Size()) IsAnti.Add(false); IsAnti[index] = isAnti; } /* void SetItem_Aux(unsigned index, bool isAux) { while (index >= IsAux.Size()) IsAux.Add(false); IsAux[index] = isAux; } */ void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); }; class COutArchive { UInt64 _prefixHeaderPos; HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); } UInt64 GetPos() const; void WriteBytes(const void *data, size_t size); void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); } void WriteByte(Byte b); void WriteUInt32(UInt32 value); void WriteUInt64(UInt64 value); void WriteNumber(UInt64 value); void WriteID(UInt64 value) { WriteNumber(value); } void WriteFolder(const CFolder &folder); HRESULT WriteFileHeader(const CFileItem &itemInfo); void WriteBoolVector(const CBoolVector &boolVector); void WritePropBoolVector(Byte id, const CBoolVector &boolVector); void WriteHashDigests(const CUInt32DefVector &digests); void WritePackInfo( UInt64 dataOffset, const CRecordVector &packSizes, const CUInt32DefVector &packCRCs); void WriteUnpackInfo( const CObjectVector &folders, const COutFolders &outFolders); void WriteSubStreamsInfo( const CObjectVector &folders, const COutFolders &outFolders, const CRecordVector &unpackSizes, const CUInt32DefVector &digests); void SkipAlign(unsigned pos, unsigned alignSize); void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize); void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type); HRESULT EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders); void WriteHeader( const CArchiveDatabaseOut &db, // const CHeaderOptions &headerOptions, UInt64 &headerOffset); bool _countMode; bool _writeToStream; size_t _countSize; UInt32 _crc; COutBuffer _outByte; CWriteBufferLoc _outByte2; #ifdef _7Z_VOL bool _endMarker; #endif bool _useAlign; HRESULT WriteSignature(); #ifdef _7Z_VOL HRESULT WriteFinishSignature(); #endif HRESULT WriteStartHeader(const CStartHeader &h); #ifdef _7Z_VOL HRESULT WriteFinishHeader(const CFinishHeader &h); #endif CMyComPtr Stream; public: COutArchive() { _outByte.Create(1 << 16); } CMyComPtr SeqStream; HRESULT Create(ISequentialOutStream *stream, bool endMarker); void Close(); HRESULT SkipPrefixArchiveHeader(); HRESULT WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions); #ifdef _7Z_VOL static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false); static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false); #endif }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.cpp0100777000000000000000000000753613761647206025064 0ustar00// 7zProperties.cpp #include "StdAfx.h" #include "7zProperties.h" #include "7zHeader.h" #include "7zHandler.h" // #define _MULTI_PACK namespace NArchive { namespace N7z { struct CPropMap { UInt64 FilePropID; STATPROPSTG StatPROPSTG; }; static const CPropMap kPropMap[] = { { NID::kName, { NULL, kpidPath, VT_BSTR } }, { NID::kSize, { NULL, kpidSize, VT_UI8 } }, { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } }, #ifdef _MULTI_PACK { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } }, { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } }, { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } }, { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } }, { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } }, #endif { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } }, { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } }, { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, // { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } }, { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } } #ifndef _SFX , { 97, { NULL,kpidEncrypted, VT_BOOL } }, { 98, { NULL,kpidMethod, VT_BSTR } }, { 99, { NULL,kpidBlock, VT_UI4 } } #endif }; static int FindPropInMap(UInt64 filePropID) { for (int i = 0; i < ARRAY_SIZE(kPropMap); i++) if (kPropMap[i].FilePropID == filePropID) return i; return -1; } static void CopyOneItem(CRecordVector &src, CRecordVector &dest, UInt32 item) { FOR_VECTOR (i, src) if (src[i] == item) { dest.Add(item); src.Delete(i); return; } } static void RemoveOneItem(CRecordVector &src, UInt32 item) { FOR_VECTOR (i, src) if (src[i] == item) { src.Delete(i); return; } } static void InsertToHead(CRecordVector &dest, UInt32 item) { FOR_VECTOR (i, dest) if (dest[i] == item) { dest.Delete(i); break; } dest.Insert(0, item); } #define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id); void CHandler::FillPopIDs() { _fileInfoPopIDs.Clear(); #ifdef _7Z_VOL if (_volumes.Size() < 1) return; const CVolume &volume = _volumes.Front(); const CArchiveDatabaseEx &_db = volume.Database; #endif CRecordVector fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs; RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); /* RemoveOneItem(fileInfoPopIDs, NID::kParent); RemoveOneItem(fileInfoPopIDs, NID::kNtSecure); */ COPY_ONE_ITEM(kName); COPY_ONE_ITEM(kAnti); COPY_ONE_ITEM(kSize); COPY_ONE_ITEM(kPackInfo); COPY_ONE_ITEM(kCTime); COPY_ONE_ITEM(kMTime); COPY_ONE_ITEM(kATime); COPY_ONE_ITEM(kWinAttrib); COPY_ONE_ITEM(kCRC); COPY_ONE_ITEM(kComment); _fileInfoPopIDs += fileInfoPopIDs; #ifndef _SFX _fileInfoPopIDs.Add(97); _fileInfoPopIDs.Add(98); _fileInfoPopIDs.Add(99); #endif #ifdef _MULTI_PACK _fileInfoPopIDs.Add(100); _fileInfoPopIDs.Add(101); _fileInfoPopIDs.Add(102); _fileInfoPopIDs.Add(103); _fileInfoPopIDs.Add(104); #endif #ifndef _SFX InsertToHead(_fileInfoPopIDs, NID::kMTime); InsertToHead(_fileInfoPopIDs, NID::kPackInfo); InsertToHead(_fileInfoPopIDs, NID::kSize); InsertToHead(_fileInfoPopIDs, NID::kName); #endif } STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { *numProps = _fileInfoPopIDs.Size(); return S_OK; } STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) { if ((int)index >= _fileInfoPopIDs.Size()) return E_INVALIDARG; int indexInMap = FindPropInMap(_fileInfoPopIDs[index]); if (indexInMap == -1) return E_INVALIDARG; const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG; *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.h0100777000000000000000000000041713761647206024520 0ustar00// 7zProperties.h #ifndef __7Z_PROPERTIES_H #define __7Z_PROPERTIES_H #include "../../PropID.h" namespace NArchive { namespace N7z { enum { kpidPackedSize0 = kpidUserDefined, kpidPackedSize1, kpidPackedSize2, kpidPackedSize3, kpidPackedSize4 }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zRegister.cpp0100777000000000000000000000057613761647206024511 0ustar00// 7zRegister.cpp #include "StdAfx.h" #include "../../Common/RegisterArc.h" #include "7zHandler.h" namespace NArchive { namespace N7z { IMP_CreateArcIn IMP_CreateArcOut static CArcInfo g_ArcInfo = { "7z", "7z", 0, 7, 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}, 0, NArcInfoFlags::kFindSignature, REF_CreateArc_Pair }; REGISTER_ARC_DEC_SIG(7z) // REGISTER_ARC(7z) }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.cpp0100777000000000000000000000110713761647206024762 0ustar00// 7zSpecStream.cpp #include "StdAfx.h" #include "7zSpecStream.h" STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize; HRESULT result = _stream->Read(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return result; } STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value) { if (!_getSubStreamSize) return E_NOTIMPL; return _getSubStreamSize->GetSubStreamSize(subStream, value); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.h0100777000000000000000000000151013761647206024425 0ustar00// 7zSpecStream.h #ifndef __7Z_SPEC_STREAM_H #define __7Z_SPEC_STREAM_H #include "../../IStream.h" #include "../../ICoder.h" #include "../../../Common/MyCom.h" class CSequentialInStreamSizeCount2: public ISequentialInStream, public ICompressGetSubStreamSize, public CMyUnknownImp { CMyComPtr _stream; CMyComPtr _getSubStreamSize; UInt64 _size; public: void Init(ISequentialInStream *stream) { _stream = stream; _getSubStreamSize = 0; _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); _size = 0; } UInt64 GetSize() const { return _size; } MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.cpp0100777000000000000000000011137313761647206024145 0ustar00// 7zUpdate.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Compress/CopyCoder.h" #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" #include "7zDecode.h" #include "7zEncode.h" #include "7zFolderInStream.h" #include "7zHandler.h" #include "7zOut.h" #include "7zUpdate.h" #ifndef WIN32 #include "Windows/FileIO.h" #endif namespace NArchive { namespace N7z { #ifdef MY_CPU_X86_OR_AMD64 #define USE_86_FILTER #endif static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, UInt64 position, UInt64 size, ICompressProgressInfo *progress) { RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0)); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStreamLimited(streamSpec); streamSpec->SetStream(inStream); streamSpec->Init(size); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL); } static int GetReverseSlashPos(const UString &name) { int slashPos = name.ReverseFind(L'/'); #ifdef _WIN32 int slash1Pos = name.ReverseFind(L'\\'); slashPos = MyMax(slashPos, slash1Pos); #endif return slashPos; } int CUpdateItem::GetExtensionPos() const { int slashPos = GetReverseSlashPos(Name); int dotPos = Name.ReverseFind(L'.'); if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) return Name.Len(); return dotPos + 1; } UString CUpdateItem::GetExtension() const { return Name.Ptr(GetExtensionPos()); } #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } #define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) /* static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) { size_t c1 = a1.GetCapacity(); size_t c2 = a2.GetCapacity(); RINOZ_COMP(c1, c2); for (size_t i = 0; i < c1; i++) RINOZ_COMP(a1[i], a2[i]); return 0; } static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) { RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); RINOZ_COMP(c1.MethodID, c2.MethodID); return CompareBuffers(c1.Props, c2.Props); } static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2) { RINOZ_COMP(b1.InIndex, b2.InIndex); return MyCompare(b1.OutIndex, b2.OutIndex); } static int CompareFolders(const CFolder &f1, const CFolder &f2) { int s1 = f1.Coders.Size(); int s2 = f2.Coders.Size(); RINOZ_COMP(s1, s2); int i; for (i = 0; i < s1; i++) RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); s1 = f1.BindPairs.Size(); s2 = f2.BindPairs.Size(); RINOZ_COMP(s1, s2); for (i = 0; i < s1; i++) RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i])); return 0; } */ /* static int CompareFiles(const CFileItem &f1, const CFileItem &f2) { return CompareFileNames(f1.Name, f2.Name); } */ struct CFolderRepack { int FolderIndex; int Group; CNum NumCopyFiles; }; static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */) { RINOZ_COMP(p1->Group, p2->Group); int i1 = p1->FolderIndex; int i2 = p2->FolderIndex; /* // In that version we don't want to parse folders here, so we don't compare folders // probably it must be improved in future const CDbEx &db = *(const CDbEx *)param; RINOZ(CompareFolders( db.Folders[i1], db.Folders[i2])); */ return MyCompare(i1, i2); /* RINOZ_COMP( db.NumUnpackStreamsVector[i1], db.NumUnpackStreamsVector[i2]); if (db.NumUnpackStreamsVector[i1] == 0) return 0; return CompareFiles( db.Files[db.FolderStartFileIndex[i1]], db.Files[db.FolderStartFileIndex[i2]]); */ } /* we sort empty files and dirs in such order: - Dir.NonAnti (name sorted) - File.NonAnti (name sorted) - File.Anti (name sorted) - Dir.Anti (reverse name sorted) */ static int CompareEmptyItems(const int *p1, const int *p2, void *param) { const CObjectVector &updateItems = *(const CObjectVector *)param; const CUpdateItem &u1 = updateItems[*p1]; const CUpdateItem &u2 = updateItems[*p2]; // NonAnti < Anti if (u1.IsAnti != u2.IsAnti) return (u1.IsAnti ? 1 : -1); if (u1.IsDir != u2.IsDir) { // Dir.NonAnti < File < Dir.Anti if (u1.IsDir) return (u1.IsAnti ? 1 : -1); return (u2.IsAnti ? -1 : 1); } int n = CompareFileNames(u1.Name, u2.Name); return (u1.IsDir && u1.IsAnti) ? -n : n; } static const char *g_Exts = " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" " zip jar ear war msi" " 3gp avi mov mpeg mpg mpe wmv" " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" " swf " " chm hxi hxs" " gif jpeg jpg jp2 png tiff bmp ico psd psp" " awg ps eps cgm dxf svg vrml wmf emf ai md" " cad dwg pps key sxi" " max 3ds" " iso bin nrg mdf img pdi tar cpio xpi" " vfd vhd vud vmc vsv" " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" " f77 f f90 f95" " asm sql manifest dep " " mak clw csproj vcproj sln dsp dsw " " class " " bat cmd" " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs" " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" " abw afp cwk lwp wpd wps wpt wrf wri" " abf afm bdf fon mgf otf pcf pfa snf ttf" " dbf mdb nsf ntf wdb db fdb gdb" " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " " pdb pch idb ncb opt"; static int GetExtIndex(const char *ext) { int extIndex = 1; const char *p = g_Exts; for (;;) { char c = *p++; if (c == 0) return extIndex; if (c == ' ') continue; int pos = 0; for (;;) { char c2 = ext[pos++]; if (c2 == 0 && (c == 0 || c == ' ')) return extIndex; if (c != c2) break; c = *p++; } extIndex++; for (;;) { if (c == 0) return extIndex; if (c == ' ') break; c = *p++; } } } struct CRefItem { const CUpdateItem *UpdateItem; UInt32 Index; UInt32 ExtensionPos; UInt32 NamePos; unsigned ExtensionIndex; CRefItem() {}; CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): UpdateItem(&ui), Index(index), ExtensionPos(0), NamePos(0), ExtensionIndex(0) { if (sortByType) { int slashPos = GetReverseSlashPos(ui.Name); NamePos = slashPos + 1; int dotPos = ui.Name.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos) ExtensionPos = ui.Name.Len(); else { ExtensionPos = dotPos + 1; if (ExtensionPos != ui.Name.Len()) { AString s; for (unsigned pos = ExtensionPos;; pos++) { wchar_t c = ui.Name[pos]; if (c >= 0x80) break; if (c == 0) { ExtensionIndex = GetExtIndex(s); break; } s += (char)MyCharLower_Ascii((char)c); } } } } } }; struct CSortParam { // const CObjectVector *TreeFolders; bool SortByType; }; /* we sort files in such order: - Dir.NonAnti (name sorted) - alt streams - Dirs - Dir.Anti (reverse name sorted) */ static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) { const CRefItem &a1 = *p1; const CRefItem &a2 = *p2; const CUpdateItem &u1 = *a1.UpdateItem; const CUpdateItem &u2 = *a2.UpdateItem; /* if (u1.IsAltStream != u2.IsAltStream) return u1.IsAltStream ? 1 : -1; */ // Actually there are no dirs that time. They were stored in other steps // So that code is unused? if (u1.IsDir != u2.IsDir) return u1.IsDir ? 1 : -1; if (u1.IsDir) { if (u1.IsAnti != u2.IsAnti) return (u1.IsAnti ? 1 : -1); int n = CompareFileNames(u1.Name, u2.Name); return -n; } // bool sortByType = *(bool *)param; const CSortParam *sortParam = (const CSortParam *)param; bool sortByType = sortParam->SortByType; if (sortByType) { RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex); RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))); RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))); if (!u1.MTimeDefined && u2.MTimeDefined) return 1; if (u1.MTimeDefined && !u2.MTimeDefined) return -1; if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime); RINOZ_COMP(u1.Size, u2.Size); } /* int par1 = a1.UpdateItem->ParentFolderIndex; int par2 = a2.UpdateItem->ParentFolderIndex; const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; if (b1 < b2) { if (e1 <= b2) return -1; // p2 in p1 int par = par2; for (;;) { const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; par = tf.Parent; if (par == par1) { RINOZ(CompareFileNames(u1.Name, tf.Name)); break; } } } else if (b2 < b1) { if (e2 <= b1) return 1; // p1 in p2 int par = par1; for (;;) { const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; par = tf.Parent; if (par == par2) { RINOZ(CompareFileNames(tf.Name, u2.Name)); break; } } } */ // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); RINOK(CompareFileNames(u1.Name, u2.Name)); RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient); RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive); return 0; } struct CSolidGroup { CRecordVector Indices; }; #ifdef _WIN32 static const wchar_t *g_ExeExts[] = { L"dll" , L"exe" , L"ocx" , L"sfx" , L"sys" }; static bool IsExeExt(const wchar_t *ext) { for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++) if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0) return true; return false; } #else static bool IsExeFile(const CUpdateItem &ui) { if (ui.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) { unsigned short st_mode = ui.Attrib >> 16; if ((st_mode & 00111) && (ui.Size >= 2048)) { // file has the execution flag and it's big enought // try to find if the file is a script NWindows::NFile::NIO::CInFile file; if (file.Open(ui.Name)) { char buffer[512]; UINT32 processedSize; if (file.Read(buffer,sizeof(buffer),processedSize)) { for(UInt32 i = 0; i < processedSize ; i++) { if (buffer[i] == 0) { return true; // this file is not a text (ascii, utf8, ...) ! } } } } } } return false; } #endif static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m) { m.Id = methodID; m.NumInStreams = numInStreams; m.NumOutStreams = 1; } static void AddBcj2Methods(CCompressionMethodMode &mode) { CMethodFull m; GetMethodFull(k_LZMA, 1, m); m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); m.AddProp32(NCoderPropID::kNumFastBytes, 128); m.AddProp32(NCoderPropID::kNumThreads, 1); m.AddProp32(NCoderPropID::kLitPosBits, 2); m.AddProp32(NCoderPropID::kLitContextBits, 0); // m.AddPropString(NCoderPropID::kMatchFinder, L"BT2"); mode.Methods.Add(m); mode.Methods.Add(m); CBind bind; bind.OutCoder = 0; bind.InStream = 0; bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); bind.InCoder = 2; bind.OutStream = 1; mode.Binds.Add(bind); bind.InCoder = 3; bind.OutStream = 2; mode.Binds.Add(bind); } static void MakeExeMethod(CCompressionMethodMode &mode, bool useFilters, bool addFilter, bool bcj2Filter) { if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2) return; if (mode.Methods.Size() == 2) { if (mode.Methods[0].Id == k_BCJ2) AddBcj2Methods(mode); return; } if (!addFilter) return; bcj2Filter = bcj2Filter; #ifdef USE_86_FILTER if (bcj2Filter) { CMethodFull m; GetMethodFull(k_BCJ2, 4, m); mode.Methods.Insert(0, m); AddBcj2Methods(mode); } else { CMethodFull m; GetMethodFull(k_BCJ, 1, m); mode.Methods.Insert(0, m); CBind bind; bind.OutCoder = 0; bind.InStream = 0; bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); } #endif } static void FromUpdateItemToFileItem(const CUpdateItem &ui, CFileItem &file, CFileItem2 &file2) { if (ui.AttribDefined) file.SetAttrib(ui.Attrib); file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; file2.IsAnti = ui.IsAnti; // file2.IsAux = false; file2.StartPosDefined = false; file.Size = ui.Size; file.IsDir = ui.IsDir; file.HasStream = ui.HasStream(); // file.IsAltStream = ui.IsAltStream; } class CFolderOutStream2: public ISequentialOutStream, public CMyUnknownImp { COutStreamWithCRC *_crcStreamSpec; CMyComPtr _crcStream; const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr _outStream; UInt32 _startIndex; unsigned _currentIndex; bool _fileIsOpen; UInt64 _rem; void OpenFile(); void CloseFile(); HRESULT CloseFileAndSetResult(); HRESULT ProcessEmptyFiles(); public: MY_UNKNOWN_IMP CFolderOutStream2() { _crcStreamSpec = new COutStreamWithCRC; _crcStream = _crcStreamSpec; } HRESULT Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream); void ReleaseOutStream(); HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream) { _db = db; _startIndex = startIndex; _extractStatuses = extractStatuses; _outStream = outStream; _currentIndex = 0; _fileIsOpen = false; return ProcessEmptyFiles(); } void CFolderOutStream2::ReleaseOutStream() { _outStream.Release(); _crcStreamSpec->ReleaseStream(); } void CFolderOutStream2::OpenFile() { _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? (ISequentialOutStream *)_outStream : NULL); // FIXED for gcc 2.95 _crcStreamSpec->Init(true); _fileIsOpen = true; _rem = _db->Files[_startIndex + _currentIndex].Size; } void CFolderOutStream2::CloseFile() { _crcStreamSpec->ReleaseStream(); _fileIsOpen = false; _currentIndex++; } HRESULT CFolderOutStream2::CloseFileAndSetResult() { const CFileItem &file = _db->Files[_startIndex + _currentIndex]; CloseFile(); return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE; } HRESULT CFolderOutStream2::ProcessEmptyFiles() { while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) { OpenFile(); RINOK(CloseFileAndSetResult()); } return S_OK; } STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size != 0) { if (_fileIsOpen) { UInt32 cur = size < _rem ? size : (UInt32)_rem; RINOK(_crcStream->Write(data, cur, &cur)); if (cur == 0) break; data = (const Byte *)data + cur; size -= cur; _rem -= cur; if (processedSize != NULL) *processedSize += cur; if (_rem == 0) { RINOK(CloseFileAndSetResult()); RINOK(ProcessEmptyFiles()); continue; } } else { RINOK(ProcessEmptyFiles()); if (_currentIndex == _extractStatuses->Size()) { // we don't support partial extracting return E_FAIL; } OpenFile(); } } return S_OK; } class CThreadDecoder: public CVirtThread { public: HRESULT Result; CMyComPtr InStream; CFolderOutStream2 *FosSpec; CMyComPtr Fos; UInt64 StartPos; const CFolders *Folders; int FolderIndex; #ifndef _NO_CRYPTO CMyComPtr getTextPassword; #endif DECL_EXTERNAL_CODECS_LOC_VARS2; CDecoder Decoder; #ifndef _7ZIP_ST bool MtMode; UInt32 NumThreads; #endif CThreadDecoder(): Decoder(true) { #ifndef _7ZIP_ST MtMode = false; NumThreads = 1; #endif FosSpec = new CFolderOutStream2; Fos = FosSpec; Result = E_FAIL; } ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); } virtual void Execute(); }; void CThreadDecoder::Execute() { try { #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; #endif Result = Decoder.Decode( EXTERNAL_CODECS_LOC_VARS InStream, StartPos, *Folders, FolderIndex, Fos, NULL _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , MtMode, NumThreads #endif ); } catch(...) { Result = E_FAIL; } if (Result == S_OK) Result = FosSpec->CheckFinishedState(); FosSpec->ReleaseOutStream(); } bool static Is86FilteredFolder(const CFolder &f) { FOR_VECTOR(i, f.Coders) { CMethodId m = f.Coders[i].MethodID; if (m == k_BCJ || m == k_BCJ2) return true; } return false; } #ifndef _NO_CRYPTO class CCryptoGetTextPassword: public ICryptoGetTextPassword, public CMyUnknownImp { public: UString Password; MY_UNKNOWN_IMP STDMETHOD(CryptoGetTextPassword)(BSTR *password); }; STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password) { return StringToBstr(Password, password); } #endif static const int kNumGroupsMax = 4; static bool Is86Group(int group) { return (group & 1) != 0; } static bool IsEncryptedGroup(int group) { return (group & 2) != 0; } static int GetGroupIndex(bool encrypted, int bcjFiltered) { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); } static void GetFile(const CDatabase &inDb, int index, CFileItem &file, CFileItem2 &file2) { file = inDb.Files[index]; file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); file2.IsAnti = inDb.IsItemAnti(index); // file2.IsAux = inDb.IsItemAux(index); } HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, const CDbEx *db, const CObjectVector &updateItems, // const CObjectVector &treeFolders, // const CUniqBlocks &secureBlocks, COutArchive &archive, CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getDecoderPassword #endif ) { UInt64 numSolidFiles = options.NumSolidFiles; if (numSolidFiles == 0) numSolidFiles = 1; // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); /* CMyComPtr outStream; RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); if (!outStream) return E_NOTIMPL; */ UInt64 startBlockSize = db != 0 ? db->ArcInfo.StartPosition: 0; if (startBlockSize > 0 && !options.RemoveSfxBlock) { RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL)); } CIntArr fileIndexToUpdateIndexMap; CRecordVector folderRefs; UInt64 complexity = 0; UInt64 inSizeForReduce2 = 0; bool needEncryptedRepack = false; if (db != 0) { fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); unsigned i; for (i = 0; i < db->Files.Size(); i++) fileIndexToUpdateIndexMap[i] = -1; for (i = 0; i < updateItems.Size(); i++) { int index = updateItems[i].IndexInArchive; if (index != -1) fileIndexToUpdateIndexMap[index] = i; } for (i = 0; i < (int)db->NumFolders; i++) { CNum indexInFolder = 0; CNum numCopyItems = 0; CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; UInt64 repackSize = 0; for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) { const CFileItem &file = db->Files[fi]; if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0 && !updateItems[updateIndex].NewData) { numCopyItems++; repackSize += file.Size; } } } if (numCopyItems == 0) continue; CFolderRepack rep; rep.FolderIndex = i; rep.NumCopyFiles = numCopyItems; CFolder f; db->ParseFolderInfo(i, f); bool isEncrypted = f.IsEncrypted(); rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f)); folderRefs.Add(rep); if (numCopyItems == numUnpackStreams) complexity += db->GetFolderFullPackSize(i); else { complexity += repackSize; if (repackSize > inSizeForReduce2) inSizeForReduce2 = repackSize; if (isEncrypted) needEncryptedRepack = true; } } folderRefs.Sort(CompareFolderRepacks, (void *)db); } UInt64 inSizeForReduce = 0; unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { complexity += ui.Size; if (numSolidFiles != 1) inSizeForReduce += ui.Size; else if (ui.Size > inSizeForReduce) inSizeForReduce = ui.Size; } } if (inSizeForReduce2 > inSizeForReduce) inSizeForReduce = inSizeForReduce2; RINOK(updateCallback->SetTotal(complexity)); CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(updateCallback, true); CStreamBinder sb; RINOK(sb.CreateEvents()); CThreadDecoder threadDecoder; if (!folderRefs.IsEmpty()) { #ifdef EXTERNAL_CODECS threadDecoder.__externalCodecs = __externalCodecs; #endif RINOK(threadDecoder.Create()); } CObjectVector groups; for (i = 0; i < kNumGroupsMax; i++) groups.AddNew(); { // ---------- Split files to groups ---------- bool useFilters = options.UseFilters; const CCompressionMethodMode &method = *options.Method; if (method.Methods.Size() != 1 || method.Binds.Size() != 0) useFilters = false; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (!ui.NewData || !ui.HasStream()) continue; bool filteredGroup = false; if (useFilters) { #ifdef _WIN32 int dotPos = ui.Name.ReverseFind(L'.'); if (dotPos >= 0) filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1)); #else filteredGroup = IsExeFile(ui); #endif } groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i); } } #ifndef _NO_CRYPTO CCryptoGetTextPassword *getPasswordSpec = NULL; if (needEncryptedRepack) { getPasswordSpec = new CCryptoGetTextPassword; threadDecoder.getTextPassword = getPasswordSpec; if (options.Method->PasswordIsDefined) getPasswordSpec->Password = options.Method->Password; else { if (!getDecoderPassword) return E_NOTIMPL; CMyComBSTR password; RINOK(getDecoderPassword->CryptoGetTextPassword(&password)); if ((BSTR)password) getPasswordSpec->Password = password; } } #endif // ---------- Compress ---------- RINOK(archive.Create(seqOutStream, false)); RINOK(archive.SkipPrefixArchiveHeader()); /* CIntVector treeFolderToArcIndex; treeFolderToArcIndex.Reserve(treeFolders.Size()); for (i = 0; i < treeFolders.Size(); i++) treeFolderToArcIndex.Add(-1); // ---------- Write Tree (only AUX dirs) ---------- for (i = 1; i < treeFolders.Size(); i++) { const CTreeFolder &treeFolder = treeFolders[i]; CFileItem file; CFileItem2 file2; file2.Init(); int secureID = 0; if (treeFolder.UpdateItemIndex < 0) { // we can store virtual dir item wuthout attrib, but we want all items have attrib. file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); file2.IsAux = true; } else { const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; // if item is not dir, then it's parent for alt streams. // we will write such items later if (!ui.IsDir) continue; secureID = ui.SecureIndex; if (ui.NewProps) FromUpdateItemToFileItem(ui, file, file2); else GetFile(*db, ui.IndexInArchive, file, file2); } file.Size = 0; file.HasStream = false; file.IsDir = true; file.Parent = treeFolder.Parent; treeFolderToArcIndex[i] = newDatabase.Files.Size(); newDatabase.AddFile(file, file2, treeFolder.Name); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(secureID); } */ { /* ---------- Write non-AUX dirs and Empty files ---------- */ CRecordVector emptyRefs; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { if (ui.HasStream()) continue; } else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream) continue; /* if (ui.TreeFolderIndex >= 0) continue; */ emptyRefs.Add(i); } emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); for (i = 0; i < emptyRefs.Size(); i++) { const CUpdateItem &ui = updateItems[emptyRefs[i]]; CFileItem file; CFileItem2 file2; UString name; if (ui.NewProps) { FromUpdateItemToFileItem(ui, file, file2); name = ui.Name; } else { GetFile(*db, ui.IndexInArchive, file, file2); db->GetPath(ui.IndexInArchive, name); } /* if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); file.Parent = ui.ParentFolderIndex; */ newDatabase.AddFile(file, file2, name); } } unsigned folderRefIndex = 0; lps->ProgressOffset = 0; for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++) { const CSolidGroup &group = groups[groupIndex]; CCompressionMethodMode method = *options.Method; MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter); if (IsEncryptedGroup(groupIndex)) { if (!method.PasswordIsDefined) { #ifndef _NO_CRYPTO if (getPasswordSpec) method.Password = getPasswordSpec->Password; #endif method.PasswordIsDefined = true; } } else { method.PasswordIsDefined = false; method.Password.Empty(); } CEncoder encoder(method); for (; folderRefIndex < folderRefs.Size(); folderRefIndex++) { const CFolderRepack &rep = folderRefs[folderRefIndex]; if (rep.Group != groupIndex) break; int folderIndex = rep.FolderIndex; if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex]) { UInt64 packSize = db->GetFolderFullPackSize(folderIndex); RINOK(WriteRange(inStream, archive.SeqStream, db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); lps->ProgressOffset += packSize; CFolder &folder = newDatabase.Folders.AddNew(); db->ParseFolderInfo(folderIndex, folder); CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; for (unsigned j = 0; j < folder.PackStreams.Size(); j++) { newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); } UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex]; UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; for (; indexStart < indexEnd; indexStart++) newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]); } else { CBoolVector extractStatuses; CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { bool needExtract = false; if (db->Files[fi].HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0 && !updateItems[updateIndex].NewData) needExtract = true; } extractStatuses.Add(needExtract); } unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curUnpackSize; { CMyComPtr sbInStream; { CMyComPtr sbOutStream; sb.CreateStreams(&sbInStream, &sbOutStream); sb.ReInit(); RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); } threadDecoder.InStream = inStream; threadDecoder.Folders = (const CFolders *)db; threadDecoder.FolderIndex = folderIndex; threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); threadDecoder.Start(); RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS sbInStream, NULL, &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); threadDecoder.WaitExecuteFinish(); } RINOK(threadDecoder.Result); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; lps->InSize += curUnpackSize; } newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { CFileItem file; CFileItem2 file2; GetFile(*db, fi, file, file2); UString name; db->GetPath(fi, name); if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0) { const CUpdateItem &ui = updateItems[updateIndex]; if (ui.NewData) continue; if (ui.NewProps) { CFileItem uf; FromUpdateItemToFileItem(ui, uf, file2); uf.Size = file.Size; uf.Crc = file.Crc; uf.CrcDefined = file.CrcDefined; uf.HasStream = file.HasStream; file = uf; name = ui.Name; } /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); */ newDatabase.AddFile(file, file2, name); } } } } unsigned numFiles = group.Indices.Size(); if (numFiles == 0) continue; CRecordVector refItems; refItems.ClearAndSetSize(numFiles); bool sortByType = (numSolidFiles > 1); for (i = 0; i < numFiles; i++) refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); CSortParam sortParam; // sortParam.TreeFolders = &treeFolders; sortParam.SortByType = sortByType; refItems.Sort(CompareUpdateItems, (void *)&sortParam); CObjArray indices(numFiles); for (i = 0; i < numFiles; i++) { UInt32 index = refItems[i].Index; indices[i] = index; /* const CUpdateItem &ui = updateItems[index]; CFileItem file; if (ui.NewProps) FromUpdateItemToFileItem(ui, file); else file = db.Files[ui.IndexInArchive]; if (file.IsAnti || file.IsDir) return E_FAIL; newDatabase.Files.Add(file); */ } for (i = 0; i < numFiles;) { UInt64 totalSize = 0; int numSubFiles; UString prevExtension; for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) { const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; totalSize += ui.Size; if (totalSize > options.NumSolidBytes) break; if (options.SolidExtension) { UString ext = ui.GetExtension(); if (numSubFiles == 0) prevExtension = ext; else if (!ext.IsEqualToNoCase(prevExtension)) break; } } if (numSubFiles < 1) numSubFiles = 1; CFolderInStream *inStreamSpec = new CFolderInStream; CMyComPtr solidInStream(inStreamSpec); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curFolderUnpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS solidInStream, NULL, &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; lps->InSize += curFolderUnpackSize; // for () // newDatabase.PackCRCsDefined.Add(false); // newDatabase.PackCRCs.Add(0); CNum numUnpackStreams = 0; for (int subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &ui = updateItems[indices[i + subIndex]]; CFileItem file; CFileItem2 file2; UString name; if (ui.NewProps) { FromUpdateItemToFileItem(ui, file, file2); name = ui.Name; } else { GetFile(*db, ui.IndexInArchive, file, file2); db->GetPath(ui.IndexInArchive, name); } if (file2.IsAnti || file.IsDir) return E_FAIL; /* CFileItem &file = newDatabase.Files[ startFileIndexInDatabase + i + subIndex]; */ if (!inStreamSpec->Processed[subIndex]) { continue; // file.Name += L".locked"; } file.Crc = inStreamSpec->CRCs[subIndex]; file.Size = inStreamSpec->Sizes[subIndex]; if (file.Size != 0) { file.CrcDefined = true; file.HasStream = true; numUnpackStreams++; } else { file.CrcDefined = false; file.HasStream = false; } /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); */ newDatabase.AddFile(file, file2, name); } // numUnpackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); i += numSubFiles; } } if (folderRefIndex != folderRefs.Size()) return E_FAIL; RINOK(lps->SetCur()); /* folderRefs.ClearAndFree(); fileIndexToUpdateIndexMap.ClearAndFree(); groups.ClearAndFree(); */ /* for (i = 0; i < newDatabase.Files.Size(); i++) { CFileItem &file = newDatabase.Files[i]; file.Parent = treeFolderToArcIndex[file.Parent]; } if (totalSecureDataSize != 0) { newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); size_t pos = 0; newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); for (i = 0; i < secureBlocks.Sorted.Size(); i++) { const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; size_t size = buf.GetCapacity(); memcpy(newDatabase.SecureBuf + pos, buf, size); newDatabase.SecureSizes.Add((UInt32)size); pos += size; } } */ newDatabase.ReserveDown(); return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.h0100777000000000000000000000435413761647206023612 0ustar00// 7zUpdate.h #ifndef __7Z_UPDATE_H #define __7Z_UPDATE_H #include "../IArchive.h" // #include "../../Common/UniqBlocks.h" #include "7zCompressionMode.h" #include "7zIn.h" #include "7zOut.h" namespace NArchive { namespace N7z { /* struct CTreeFolder { UString Name; int Parent; CIntVector SubFolders; int UpdateItemIndex; int SortIndex; int SortIndexEnd; CTreeFolder(): UpdateItemIndex(-1) {} }; */ struct CUpdateItem { int IndexInArchive; int IndexInClient; UInt64 CTime; UInt64 ATime; UInt64 MTime; UInt64 Size; UString Name; /* bool IsAltStream; int ParentFolderIndex; int TreeFolderIndex; */ // that code is not used in 9.26 // int ParentSortIndex; // int ParentSortIndexEnd; UInt32 Attrib; bool NewData; bool NewProps; bool IsAnti; bool IsDir; bool AttribDefined; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; // int SecureIndex; // 0 means (no_security) bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } CUpdateItem(): // ParentSortIndex(-1), // IsAltStream(false), IsAnti(false), IsDir(false), AttribDefined(false), CTimeDefined(false), ATimeDefined(false), MTimeDefined(false) // SecureIndex(0) {} void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }; int GetExtensionPos() const; UString GetExtension() const; }; struct CUpdateOptions { const CCompressionMethodMode *Method; const CCompressionMethodMode *HeaderMethod; bool UseFilters; bool MaxFilter; CHeaderOptions HeaderOptions; UInt64 NumSolidFiles; UInt64 NumSolidBytes; bool SolidExtension; bool RemoveSfxBlock; bool VolumeMode; }; HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, const CDbEx *db, const CObjectVector &updateItems, // const CObjectVector &treeFolders, // treeFolders[0] is root // const CUniqBlocks &secureBlocks, COutArchive &archive, CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getDecoderPassword #endif ); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Archive.pri0100777000000000000000000000032113761647206023461 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/IArchive.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/LzmaHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/SplitHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/XzHandler.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/0040777000000000000000000000000013761647206022620 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.cpp0100777000000000000000000000676613761647206025466 0ustar00// CoderMixer2.cpp #include "StdAfx.h" #include "CoderMixer2.h" namespace NCoderMixer { CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): _srcBindInfo(srcBindInfo) { srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); UInt32 j; _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams); DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams); for (j = 0; j < NumSrcInStreams; j++) { _srcInToDestOutMap[j] = 0; DestOutToSrcInMap[j] = 0; } _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams); _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams); for (j = 0; j < _numSrcOutStreams; j++) { _srcOutToDestInMap[j] = 0; _destInToSrcOutMap[j] = 0; } UInt32 destInOffset = 0; UInt32 destOutOffset = 0; UInt32 srcInOffset = NumSrcInStreams; UInt32 srcOutOffset = _numSrcOutStreams; for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--) { const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i]; srcInOffset -= srcCoderInfo.NumInStreams; srcOutOffset -= srcCoderInfo.NumOutStreams; UInt32 j; for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++) { UInt32 index = srcInOffset + j; _srcInToDestOutMap[index] = destOutOffset; DestOutToSrcInMap[destOutOffset] = index; } for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++) { UInt32 index = srcOutOffset + j; _srcOutToDestInMap[index] = destInOffset; _destInToSrcOutMap[destInOffset] = index; } } } void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) { destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size()); destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size()); destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size()); destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size()); unsigned i; for (i = _srcBindInfo.Coders.Size(); i != 0;) { i--; const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; CCoderStreamsInfo destCoderInfo; destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; destBindInfo.Coders.AddInReserved(destCoderInfo); } for (i = _srcBindInfo.BindPairs.Size(); i != 0;) { i--; const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; CBindPair destBindPair; destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; destBindInfo.BindPairs.AddInReserved(destBindPair); } for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); } void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, CRecordVector &sizePointers, UInt32 numItems) { sizes.ClearAndSetSize(numItems); sizePointers.ClearAndSetSize(numItems); for (UInt32 i = 0; i < numItems; i++) { if (!srcSizes || !srcSizes[i]) { sizes[i] = 0; sizePointers[i] = NULL; } else { sizes[i] = *(srcSizes[i]); sizePointers[i] = &sizes[i]; } } } void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.h0100777000000000000000000001020413761647206025111 0ustar00// CoderMixer2.h #ifndef __CODER_MIXER2_H #define __CODER_MIXER2_H #include "../../../Common/MyCom.h" #include "../../../Common/MyVector.h" #include "../../ICoder.h" namespace NCoderMixer { struct CBindPair { UInt32 InIndex; UInt32 OutIndex; }; struct CCoderStreamsInfo { UInt32 NumInStreams; UInt32 NumOutStreams; }; struct CBindInfo { CRecordVector Coders; CRecordVector BindPairs; CRecordVector InStreams; CRecordVector OutStreams; void Clear() { Coders.Clear(); BindPairs.Clear(); InStreams.Clear(); OutStreams.Clear(); } /* UInt32 GetCoderStartOutStream(UInt32 coderIndex) const { UInt32 numOutStreams = 0; for (UInt32 i = 0; i < coderIndex; i++) numOutStreams += Coders[i].NumOutStreams; return numOutStreams; } */ void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const { numInStreams = 0; numOutStreams = 0; FOR_VECTOR (i, Coders) { const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; numInStreams += coderStreamsInfo.NumInStreams; numOutStreams += coderStreamsInfo.NumOutStreams; } } int FindBinderForInStream(UInt32 inStream) const { FOR_VECTOR (i, BindPairs) if (BindPairs[i].InIndex == inStream) return i; return -1; } int FindBinderForOutStream(UInt32 outStream) const { FOR_VECTOR (i, BindPairs) if (BindPairs[i].OutIndex == outStream) return i; return -1; } UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const { UInt32 streamIndex = 0; for (UInt32 i = 0; i < coderIndex; i++) streamIndex += Coders[i].NumInStreams; return streamIndex; } UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const { UInt32 streamIndex = 0; for (UInt32 i = 0; i < coderIndex; i++) streamIndex += Coders[i].NumOutStreams; return streamIndex; } void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const { for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) { UInt32 curSize = Coders[coderIndex].NumInStreams; if (streamIndex < curSize) { coderStreamIndex = streamIndex; return; } streamIndex -= curSize; } throw 1; } void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const { for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) { UInt32 curSize = Coders[coderIndex].NumOutStreams; if (streamIndex < curSize) { coderStreamIndex = streamIndex; return; } streamIndex -= curSize; } throw 1; } }; class CBindReverseConverter { UInt32 _numSrcOutStreams; NCoderMixer::CBindInfo _srcBindInfo; CRecordVector _srcInToDestOutMap; CRecordVector _srcOutToDestInMap; CRecordVector _destInToSrcOutMap; public: UInt32 NumSrcInStreams; CRecordVector DestOutToSrcInMap; CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo); void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo); }; void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, CRecordVector &sizePointers, UInt32 numItems); struct CCoderInfo2 { CMyComPtr Coder; CMyComPtr Coder2; UInt32 NumInStreams; UInt32 NumOutStreams; CRecordVector InSizes; CRecordVector OutSizes; CRecordVector InSizePointers; CRecordVector OutSizePointers; CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): NumInStreams(numInStreams), NumOutStreams(numOutStreams) {} void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); HRESULT QueryInterface(REFGUID iid, void** pp) const { IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; return p->QueryInterface(iid, pp); } }; class CCoderMixer2 { public: virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0; virtual void ReInit() = 0; virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0; }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.cpp0100777000000000000000000001354013761647206025713 0ustar00// CoderMixer2MT.cpp #include "StdAfx.h" #include "CoderMixer2MT.h" namespace NCoderMixer { CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): CCoderInfo2(numInStreams, numOutStreams) { InStreams.ClearAndReserve(NumInStreams); OutStreams.ClearAndReserve(NumOutStreams); } void CCoder2::Execute() { Code(NULL); } void CCoder2::Code(ICompressProgressInfo *progress) { InStreamPointers.ClearAndReserve(NumInStreams); OutStreamPointers.ClearAndReserve(NumOutStreams); UInt32 i; for (i = 0; i < NumInStreams; i++) { if (InSizePointers[i]) InSizePointers[i] = &InSizes[i]; InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); } for (i = 0; i < NumOutStreams; i++) { if (OutSizePointers[i]) OutSizePointers[i] = &OutSizes[i]; OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); } if (Coder) Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], InSizePointers[0], OutSizePointers[0], progress); else Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams, &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress); { unsigned i; for (i = 0; i < InStreams.Size(); i++) InStreams[i].Release(); for (i = 0; i < OutStreams.Size(); i++) OutStreams[i].Release(); } } /* void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); } */ ////////////////////////////////////// // CCoderMixer2MT HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) { _bindInfo = bindInfo; _streamBinders.Clear(); FOR_VECTOR (i, _bindInfo.BindPairs) { RINOK(_streamBinders.AddNew().CreateEvents()); } return S_OK; } void CCoderMixer2MT::AddCoderCommon() { const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()]; CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams); _coders.Add(threadCoderInfo); } void CCoderMixer2MT::AddCoder(ICompressCoder *coder) { AddCoderCommon(); _coders.Back().Coder = coder; } void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) { AddCoderCommon(); _coders.Back().Coder2 = coder; } void CCoderMixer2MT::ReInit() { FOR_VECTOR (i, _streamBinders) _streamBinders[i].ReInit(); } HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams) { /* if (_coders.Size() != _bindInfo.Coders.Size()) throw 0; */ unsigned i; for (i = 0; i < _coders.Size(); i++) { CCoder2 &coderInfo = _coders[i]; const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i]; coderInfo.InStreams.Clear(); UInt32 j; for (j = 0; j < coderStreamsInfo.NumInStreams; j++) coderInfo.InStreams.Add(NULL); coderInfo.OutStreams.Clear(); for (j = 0; j < coderStreamsInfo.NumOutStreams; j++) coderInfo.OutStreams.Add(NULL); } for (i = 0; i < _bindInfo.BindPairs.Size(); i++) { const CBindPair &bindPair = _bindInfo.BindPairs[i]; UInt32 inCoderIndex, inCoderStreamIndex; UInt32 outCoderIndex, outCoderStreamIndex; _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex); _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex); _streamBinders[i].CreateStreams( &_coders[inCoderIndex].InStreams[inCoderStreamIndex], &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]); CMyComPtr inSetSize, outSetSize; _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); if (inSetSize && outSetSize) { const UInt32 kBufSize = 1 << 19; inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); } } for (i = 0; i < _bindInfo.InStreams.Size(); i++) { UInt32 inCoderIndex, inCoderStreamIndex; _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex); _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i]; } for (i = 0; i < _bindInfo.OutStreams.Size(); i++) { UInt32 outCoderIndex, outCoderStreamIndex; _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex); _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i]; } return S_OK; } HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) { FOR_VECTOR (i, _coders) if (_coders[i].Result == code) return code; return S_OK; } STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) return E_INVALIDARG; Init(inStreams, outStreams); unsigned i; for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) { RINOK(_coders[i].Create()); } for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].Start(); _coders[_progressCoderIndex].Code(progress); for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].WaitExecuteFinish(); RINOK(ReturnIfError(E_ABORT)); RINOK(ReturnIfError(E_OUTOFMEMORY)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK && result != E_FAIL && result != S_FALSE) return result; } RINOK(ReturnIfError(S_FALSE)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK) return result; } return S_OK; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.h0100777000000000000000000000417413761647206025363 0ustar00// CoderMixer2MT.h #ifndef __CODER_MIXER2_MT_H #define __CODER_MIXER2_MT_H #include "CoderMixer2.h" #include "../../../Common/MyCom.h" #include "../../Common/StreamBinder.h" #include "../../Common/VirtThread.h" namespace NCoderMixer { struct CCoder2: public CCoderInfo2, public CVirtThread { CRecordVector InStreamPointers; CRecordVector OutStreamPointers; public: HRESULT Result; CObjectVector< CMyComPtr > InStreams; CObjectVector< CMyComPtr > OutStreams; CCoder2(UInt32 numInStreams, UInt32 numOutStreams); ~CCoder2() { CVirtThread::WaitThreadFinish(); } // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); virtual void Execute(); void Code(ICompressProgressInfo *progress); }; /* SetBindInfo() for each coder AddCoder[2]() SetProgressIndex(UInt32 coderIndex); for each file { ReInit() for each coder SetCoderInfo Code } */ class CCoderMixer2MT: public ICompressCoder2, public CCoderMixer2, public CMyUnknownImp { CBindInfo _bindInfo; CObjectVector _streamBinders; unsigned _progressCoderIndex; void AddCoderCommon(); HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams); HRESULT ReturnIfError(HRESULT code); public: CObjectVector _coders; MY_UNKNOWN_IMP STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); HRESULT SetBindInfo(const CBindInfo &bindInfo); void AddCoder(ICompressCoder *coder); void AddCoder2(ICompressCoder2 *coder); void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; } void ReInit(); void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); } UInt64 GetWriteProcessedSize(UInt32 binderIndex) const { return _streamBinders[binderIndex].ProcessedSize; } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/Common.pri0100777000000000000000000000176513761647206024575 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ParseProperties.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.cpp0100777000000000000000000000062213761647206026263 0ustar00// DummyOutStream.cpp #include "StdAfx.h" #include "DummyOutStream.h" STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = size; HRESULT res = S_OK; if (_stream) res = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.h0100777000000000000000000000111113761647206025722 0ustar00// DummyOutStream.h #ifndef __DUMMY_OUT_STREAM_H #define __DUMMY_OUT_STREAM_H #include "../../../Common/MyCom.h" #include "../../IStream.h" class CDummyOutStream: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; public: void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } void ReleaseStream() { _stream.Release(); } void Init() { _size = 0; } MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); UInt64 GetSize() const { return _size; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.cpp0100777000000000000000000000617013761647206025375 0ustar00// HandlerOut.cpp #include "StdAfx.h" #ifndef _7ZIP_ST #include "../../../Windows/System.h" #endif #include "../Common/ParseProperties.h" #include "HandlerOut.h" using namespace NWindows; namespace NArchive { static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value) { if (m.FindProp(propID) < 0) m.AddProp32(propID, value); } void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { UInt32 level = _level; if (level != (UInt32)(Int32)-1) SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); #ifndef _7ZIP_ST SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); #endif } void CMultiMethodProps::Init() { #ifndef _7ZIP_ST _numProcessors = _numThreads = NSystem::GetNumberOfProcessors(); #endif _level = (UInt32)(Int32)-1; _autoFilter = true; _crcSize = 4; _filterMethod.Clear(); _methods.Clear(); } HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; if (name[0] == 'x') { name.Delete(0); _level = 9; return ParsePropToUInt32(name, value, _level); } if (name == L"crc") { name.Delete(0, 3); _crcSize = 4; return ParsePropToUInt32(name, value, _crcSize); } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Ptr(index); if (index == 0) { if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); #endif return S_OK; } if (name.IsEqualTo("f")) { HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); if (res == S_OK) return res; if (value.vt != VT_BSTR) return E_INVALIDARG; return _filterMethod.ParseMethodFromPROPVARIANT(L"", value); } number = 0; } if (number > 64) return E_FAIL; for (int j = _methods.Size(); j <= (int)number; j++) _methods.Add(COneMethodInfo()); return _methods[number].ParseMethodFromPROPVARIANT(realName, value); } void CSingleMethodProps::Init() { Clear(); #ifndef _7ZIP_ST _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); AddNumThreadsProp(_numThreads); #endif _level = (UInt32)(Int32)-1; } HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { Init(); for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; if (name[0] == L'x') { UInt32 a = 9; RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); _level = a; AddLevelProp(a); } else if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); AddNumThreadsProp(_numThreads); #endif } else return ParseMethodFromPROPVARIANT(names[i], value); } return S_OK; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.h0100777000000000000000000000236113761647206025040 0ustar00// HandlerOut.h #ifndef __HANDLER_OUT_H #define __HANDLER_OUT_H #include "../../Common/MethodProps.h" namespace NArchive { class CMultiMethodProps { UInt32 _level; public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; #endif UInt32 _crcSize; CObjectVector _methods; COneMethodInfo _filterMethod; bool _autoFilter; void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); unsigned GetNumEmptyMethods() const { unsigned i; for (i = 0; i < _methods.Size(); i++) if (!_methods[i].IsEmpty()) break; return i; } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } void Init(); CMultiMethodProps() { Init(); } HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); }; class CSingleMethodProps: public COneMethodInfo { UInt32 _level; public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; #endif void Init(); CSingleMethodProps() { Init(); } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.cpp0100777000000000000000000000226113761647206026233 0ustar00// InStreamWithCRC.cpp #include "StdAfx.h" #include "InStreamWithCRC.h" STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessed = 0; HRESULT result = S_OK; if (_stream) result = _stream->Read(data, size, &realProcessed); _size += realProcessed; if (size != 0 && realProcessed == 0) _wasFinished = true; _crc = CrcUpdate(_crc, data, realProcessed); if (processedSize) *processedSize = realProcessed; return result; } STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessed = 0; HRESULT result = S_OK; if (_stream) result = _stream->Read(data, size, &realProcessed); _size += realProcessed; /* if (size != 0 && realProcessed == 0) _wasFinished = true; */ _crc = CrcUpdate(_crc, data, realProcessed); if (processedSize) *processedSize = realProcessed; return result; } STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin != STREAM_SEEK_SET || offset != 0) return E_FAIL; _size = 0; _crc = CRC_INIT_VAL; return _stream->Seek(offset, seekOrigin, newPosition); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.h0100777000000000000000000000301413761647206025675 0ustar00// InStreamWithCRC.h #ifndef __IN_STREAM_WITH_CRC_H #define __IN_STREAM_WITH_CRC_H #include "../../../../C/7zCrc.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" class CSequentialInStreamWithCRC: public ISequentialInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); private: CMyComPtr _stream; UInt64 _size; UInt32 _crc; bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } void Init() { _size = 0; _wasFinished = false; _crc = CRC_INIT_VAL; } void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt64 GetSize() const { return _size; } bool WasFinished() const { return _wasFinished; } }; class CInStreamWithCRC: public IInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); private: CMyComPtr _stream; UInt64 _size; UInt32 _crc; // bool _wasFinished; public: void SetStream(IInStream *stream) { _stream = stream; } void Init() { _size = 0; // _wasFinished = false; _crc = CRC_INIT_VAL; } void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt64 GetSize() const { return _size; } // bool WasFinished() const { return _wasFinished; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.cpp0100777000000000000000000000315413761647206026047 0ustar00// Archive/Common/ItemNameUtils.cpp #include "StdAfx.h" #include "ItemNameUtils.h" namespace NArchive { namespace NItemName { static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR; static const wchar_t kDirDelimiter = L'/'; void ReplaceToOsPathSeparator(wchar_t *s) { #ifdef _WIN32 for (;;) { wchar_t c = *s; if (c == 0) break; if (c == kDirDelimiter) *s = kOSDirDelimiter; s++; } #endif } UString MakeLegalName(const UString &name) { UString zipName = name; zipName.Replace(kOSDirDelimiter, kDirDelimiter); return zipName; } UString GetOSName(const UString &name) { UString newName = name; newName.Replace(kDirDelimiter, kOSDirDelimiter); return newName; } UString GetOSName2(const UString &name) { if (name.IsEmpty()) return UString(); UString newName = GetOSName(name); if (newName.Back() == kOSDirDelimiter) newName.DeleteBack(); return newName; } void ConvertToOSName2(UString &name) { if (!name.IsEmpty()) { name.Replace(kDirDelimiter, kOSDirDelimiter); if (name.Back() == kOSDirDelimiter) name.DeleteBack(); } } bool HasTailSlash(const AString &name, UINT #if defined(_WIN32) && !defined(UNDER_CE) codePage #endif ) { if (name.IsEmpty()) return false; LPCSTR prev = #if defined(_WIN32) && !defined(UNDER_CE) CharPrevExA((WORD)codePage, name, &name[name.Len()], 0); #else (LPCSTR)(name) + (name.Len() - 1); #endif return (*prev == '/'); } #ifndef _WIN32 UString WinNameToOSName(const UString &name) { UString newName = name; newName.Replace(L'\\', kOSDirDelimiter); return newName; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.h0100777000000000000000000000116713761647206025516 0ustar00// Archive/Common/ItemNameUtils.h #ifndef __ARCHIVE_ITEM_NAME_UTILS_H #define __ARCHIVE_ITEM_NAME_UTILS_H #include "../../../Common/MyString.h" namespace NArchive { namespace NItemName { void ReplaceToOsPathSeparator(wchar_t *s); UString MakeLegalName(const UString &name); UString GetOSName(const UString &name); UString GetOSName2(const UString &name); void ConvertToOSName2(UString &name); bool HasTailSlash(const AString &name, UINT codePage); #ifdef _WIN32 inline UString WinNameToOSName(const UString &name) { return name; } #else UString WinNameToOSName(const UString &name); #endif }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.cpp0100777000000000000000000001103213761647206025567 0ustar00// MultiStream.cpp #include "StdAfx.h" #include "MultiStream.h" STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _totalLength) return S_OK; { unsigned left = 0, mid = _streamIndex, right = Streams.Size(); for (;;) { CSubStreamInfo &m = Streams[mid]; if (_pos < m.GlobalOffset) right = mid; else if (_pos >= m.GlobalOffset + m.Size) left = mid + 1; else { _streamIndex = mid; break; } mid = (left + right) / 2; } _streamIndex = mid; } CSubStreamInfo &s = Streams[_streamIndex]; UInt64 localPos = _pos - s.GlobalOffset; if (localPos != s.LocalPos) { RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos)); } UInt64 rem = s.Size - localPos; if (size > rem) size = (UInt32)rem; HRESULT result = s.Stream->Read(data, size, &size); _pos += size; s.LocalPos += size; if (processedSize) *processedSize = size; return result; } STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _totalLength; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } /* class COutVolumeStream: public ISequentialOutStream, public CMyUnknownImp { unsigned _volIndex; UInt64 _volSize; UInt64 _curPos; CMyComPtr _volumeStream; COutArchive _archive; CCRC _crc; public: MY_UNKNOWN_IMP CFileItem _file; CUpdateOptions _options; CMyComPtr VolumeCallback; void Init(IArchiveUpdateCallback2 *volumeCallback, const UString &name) { _file.Name = name; _file.IsStartPosDefined = true; _file.StartPos = 0; VolumeCallback = volumeCallback; _volIndex = 0; _volSize = 0; } HRESULT Flush(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; HRESULT COutVolumeStream::Flush() { if (_volumeStream) { _file.UnPackSize = _curPos; _file.FileCRC = _crc.GetDigest(); RINOK(WriteVolumeHeader(_archive, _file, _options)); _archive.Close(); _volumeStream.Release(); _file.StartPos += _file.UnPackSize; } return S_OK; } */ /* STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_streamIndex >= Streams.Size()) { CSubStreamInfo subStream; RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size)); RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream)); subStream.Pos = 0; Streams.Add(subStream); continue; } CSubStreamInfo &subStream = Streams[_streamIndex]; if (_offsetPos >= subStream.Size) { _offsetPos -= subStream.Size; _streamIndex++; continue; } if (_offsetPos != subStream.Pos) { CMyComPtr outStream; RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)); RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); subStream.Pos = _offsetPos; } UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos); UInt32 realProcessed; RINOK(subStream.Stream->Write(data, curSize, &realProcessed)); data = (void *)((Byte *)data + realProcessed); size -= realProcessed; subStream.Pos += realProcessed; _offsetPos += realProcessed; _absPos += realProcessed; if (_absPos > _length) _length = _absPos; if (processedSize != NULL) *processedSize += realProcessed; if (subStream.Pos == subStream.Size) { _streamIndex++; _offsetPos = 0; } if (realProcessed != curSize && realProcessed == 0) return E_FAIL; } return S_OK; } STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _absPos; break; case STREAM_SEEK_END: offset += _length; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _absPos = offset; _offsetPos = _absPos; _streamIndex = 0; if (newPosition) *newPosition = offset; return S_OK; } */ qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.h0100777000000000000000000000334713761647206025246 0ustar00// MultiStream.h #ifndef __MULTI_STREAM_H #define __MULTI_STREAM_H #include "../../../Common/MyCom.h" #include "../../../Common/MyVector.h" #include "../../IStream.h" class CMultiStream: public IInStream, public CMyUnknownImp { UInt64 _pos; UInt64 _totalLength; unsigned _streamIndex; public: struct CSubStreamInfo { CMyComPtr Stream; UInt64 Size; UInt64 GlobalOffset; UInt64 LocalPos; CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} }; CObjectVector Streams; HRESULT Init() { UInt64 total = 0; FOR_VECTOR (i, Streams) { CSubStreamInfo &s = Streams[i]; s.GlobalOffset = total; total += Streams[i].Size; RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos)); } _totalLength = total; _pos = 0; _streamIndex = 0; return S_OK; } MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; /* class COutMultiStream: public IOutStream, public CMyUnknownImp { unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; struct CSubStreamInfo { CMyComPtr Stream; UInt64 Size; UInt64 Pos; }; CObjectVector Streams; public: CMyComPtr VolumeCallback; void Init() { _streamIndex = 0; _offsetPos = 0; _absPos = 0; _length = 0; } MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; */ #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp0100777000000000000000000000063113761647206026433 0ustar00// OutStreamWithCRC.cpp #include "StdAfx.h" #include "OutStreamWithCRC.h" STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (_stream) result = _stream->Write(data, size, &size); if (_calculate) _crc = CrcUpdate(_crc, data, size); _size += size; if (processedSize != NULL) *processedSize = size; return result; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.h0100777000000000000000000000160413761647206026101 0ustar00// OutStreamWithCRC.h #ifndef __OUT_STREAM_WITH_CRC_H #define __OUT_STREAM_WITH_CRC_H #include "../../../../C/7zCrc.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" class COutStreamWithCRC: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; UInt32 _crc; bool _calculate; public: MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(bool calculate = true) { _size = 0; _calculate = calculate; _crc = CRC_INIT_VAL; } void EnableCalc(bool calculate) { _calculate = calculate; } void InitCRC() { _crc = CRC_INIT_VAL; } UInt64 GetSize() const { return _size; } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.h0100777000000000000000000000013013761647206026112 0ustar00// ParseProperties.h #ifndef __PARSE_PROPERTIES_H #define __PARSE_PROPERTIES_H #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/IArchive.h0100777000000000000000000003507613761647206023246 0ustar00// IArchive.h #ifndef __IARCHIVE_H #define __IARCHIVE_H #include "../IProgress.h" #include "../IStream.h" #include "../PropID.h" #define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x) #define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x) namespace NFileTimeType { enum EEnum { kWindows, kUnix, kDOS }; } namespace NArcInfoFlags { const UInt32 kKeepName = 1 << 0; // keep name of file in archive name const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams const UInt32 kNtSecure = 1 << 2; // the handler supports NT security const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive const UInt32 kMultiSignature = 1 << 4; // there are several signatures const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset const UInt32 kStartOpen = 1 << 6; // call handler for each start position const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links const UInt32 kHardLinks = 1 << 11; // the handler supports hard links } namespace NArchive { namespace NHandlerPropID { enum { kName = 0, // VT_BSTR kClassID, // binary GUID in VT_BSTR kExtension, // VT_BSTR kAddExtension, // VT_BSTR kUpdate, // VT_BOOL kKeepName, // VT_BOOL kSignature, // binary in VT_BSTR kMultiSignature, // binary in VT_BSTR kSignatureOffset, // VT_UI4 kAltStreams, // VT_BOOL kNtSecure, // VT_BOOL kFlags // VT_UI4 // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) }; } namespace NExtract { namespace NAskMode { enum { kExtract = 0, kTest, kSkip }; } namespace NOperationResult { enum { kOK = 0, kUnsupportedMethod, kDataError, kCRCError, kUnavailable, kUnexpectedEnd, kDataAfterEnd, kIsNotArc, kHeadersError }; } } namespace NUpdate { namespace NOperationResult { enum { kOK = 0 , // kError }; } } } #define INTERFACE_IArchiveOpenCallback(x) \ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) { INTERFACE_IArchiveOpenCallback(PURE); }; /* IArchiveExtractCallback::GetStream Result: (*inStream == NULL) - for directories (*inStream == NULL) - if link (hard link or symbolic link) was created */ #define INTERFACE_IArchiveExtractCallback(x) \ INTERFACE_IProgress(x) \ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \ ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) { INTERFACE_IArchiveExtractCallback(PURE) }; #define INTERFACE_IArchiveOpenVolumeCallback(x) \ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \ ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30) { INTERFACE_IArchiveOpenVolumeCallback(PURE); }; ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40) { STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE; }; ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50) { STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE; }; /* IInArchive::Open stream if (kUseGlobalOffset), stream current position can be non 0. if (!kUseGlobalOffset), stream current position is 0. if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream if (*maxCheckStartPosition == 0), the handler must check only current position as archive start IInArchive::Extract: indices must be sorted numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" testMode != 0 means "test files without writing to outStream" IInArchive::GetArchiveProperty: kpidOffset - start offset of archive. VT_EMPTY : means offset = 0. VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed kpidPhySize - size of archive. VT_EMPTY means unknown size. kpidPhySize is allowed to be larger than file size. In that case it must show supposed size. kpidIsDeleted: kpidIsAltStream: kpidIsAux: kpidINode: must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. Notes: Don't call IInArchive functions for same IInArchive object from different threads simultaneously. Some IInArchive handlers will work incorrectly in that case. */ /* MSVC allows the code where there is throw() in declaration of function, but there is no throw() in definition of function. */ #ifdef _MSC_VER #define MY_NO_THROW_DECL_ONLY throw() #else #define MY_NO_THROW_DECL_ONLY #endif #define INTERFACE_IInArchive(x) \ STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; ARCHIVE_INTERFACE(IInArchive, 0x60) { INTERFACE_IInArchive(PURE) }; namespace NParentType { enum { kDir = 0, kAltStream }; }; namespace NPropDataType { const UInt32 kMask_ZeroEnd = 1 << 4; // const UInt32 kMask_BigEndian = 1 << 5; const UInt32 kMask_Utf = 1 << 6; // const UInt32 kMask_Utf8 = kMask_Utf | 0; const UInt32 kMask_Utf16 = kMask_Utf | 1; // const UInt32 kMask_Utf32 = kMask_Utf | 2; const UInt32 kNotDefined = 0; const UInt32 kRaw = 1; const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; }; // UTF string (pointer to wchar_t) with zero end and little-endian. #define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) /* GetRawProp: Result: S_OK - even if property is not set */ #define INTERFACE_IArchiveGetRawProps(x) \ STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \ STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \ STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x; ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70) { INTERFACE_IArchiveGetRawProps(PURE) }; #define INTERFACE_IArchiveGetRootProps(x) \ STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71) { INTERFACE_IArchiveGetRootProps(PURE) }; ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61) { STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE; }; /* OpenForSize Result: S_FALSE - is not archive ? - DATA error */ /* const UInt32 kOpenFlags_RealPhySize = 1 << 0; const UInt32 kOpenFlags_NoSeek = 1 << 1; // const UInt32 kOpenFlags_BeforeExtract = 1 << 2; */ /* Flags: 0 - opens archive with IInStream, if IInStream interface is supported - if phySize is not available, it doesn't try to make full parse to get phySize kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, the handler can return S_OK, but it doesn't check even Signature. So next Extract can be called for that sequential stream. */ /* ARCHIVE_INTERFACE(IArchiveOpen2, 0x62) { STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE; }; */ // ---------- UPDATE ---------- /* GetUpdateItemInfo outs: *newData *newProps 0 0 - Copy data and properties from archive 0 1 - Copy data from archive, request new properties 1 0 - that combination is unused now 1 1 - Request new data and new properties. It can be used even for folders indexInArchive = -1 if there is no item in archive, or if it doesn't matter. GetStream out: Result: S_OK: (*inStream == NULL) - only for directories - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file (*inStream != NULL) - for any file, even for empty file or anti-file S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) (*inStream == NULL) The order of calling for hard links: - GetStream() - GetProperty(kpidHardLink) */ #define INTERFACE_IArchiveUpdateCallback(x) \ INTERFACE_IProgress(x); \ STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \ STDMETHOD(SetOperationResult)(Int32 operationResult) x; \ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80) { INTERFACE_IArchiveUpdateCallback(PURE); }; #define INTERFACE_IArchiveUpdateCallback2(x) \ INTERFACE_IArchiveUpdateCallback(x) \ STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \ STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) { INTERFACE_IArchiveUpdateCallback2(PURE); }; /* UpdateItems() ------------- outStream: output stream. (the handler) MUST support the case when Seek position in outStream is not ZERO. but the caller calls with empty outStream and seek position is ZERO?? archives with stub: If archive is open and the handler and (Offset > 0), then the handler knows about stub size. UpdateItems(): 1) the handler MUST copy that stub to outStream 2) the caller MUST NOT copy the stub to outStream, if "rsfx" property is set with SetProperties the handler must support the case where ISequentialOutStream *outStream */ #define INTERFACE_IOutArchive(x) \ STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \ STDMETHOD(GetFileTimeType)(UInt32 *type) x; ARCHIVE_INTERFACE(IOutArchive, 0xA0) { INTERFACE_IOutArchive(PURE) }; ARCHIVE_INTERFACE(ISetProperties, 0x03) { STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE; }; ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04) { STDMETHOD(KeepModeForNextOpen)() PURE; }; /* Exe handler: the handler for executable format (PE, ELF, Mach-O). SFX archive: executable stub + some tail data. before 9.31: exe handler didn't parse SFX archives as executable format. for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05) { STDMETHOD(AllowTail)(Int32 allowTail) PURE; }; #define IMP_IInArchive_GetProp(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \ #define IMP_IInArchive_GetProp_WITH_NAME(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ const STATPROPSTG &srcItem = k[index]; \ *propID = srcItem.propid; *varType = srcItem.vt; \ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \ #define IMP_IInArchive_Props \ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps) #define IMP_IInArchive_Props_WITH_NAME \ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps) #define IMP_IInArchive_ArcProps \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps) #define IMP_IInArchive_ArcProps_WITH_NAME \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps) #define IMP_IInArchive_ArcProps_NO_Table \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = 0; return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \ { return E_NOTIMPL; } \ #define IMP_IInArchive_ArcProps_NO \ IMP_IInArchive_ArcProps_NO_Table \ STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \ { value->vt = VT_EMPTY; return S_OK; } #define k_IsArc_Res_NO 0 #define k_IsArc_Res_YES 1 #define k_IsArc_Res_NEED_MORE 2 // #define k_IsArc_Res_YES_LOW_PROB 3 #define API_FUNC_IsArc EXTERN_C UInt32 WINAPI #define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI extern "C" { typedef UInt32 (*Func_IsArc)(const Byte *p, size_t size); typedef IOutArchive * (*Func_CreateOutArchive)(); typedef IInArchive * (*Func_CreateInArchive)(); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/LzmaHandler.cpp0100777000000000000000000003332713761647206024305 0ustar00// LzmaHandler.cpp #include "StdAfx.h" #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" #include "../../Windows/PropVariant.h" #include "../Common/CreateCoder.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "../Compress/LzmaDecoder.h" #include "Common/DummyOutStream.h" using namespace NWindows; namespace NArchive { namespace NLzma { static bool CheckDicSize(const Byte *p) { UInt32 dicSize = GetUi32(p); if (dicSize == 1) return true; for (unsigned i = 0; i <= 30; i++) if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) return true; return (dicSize == 0xFFFFFFFF); } static const Byte kProps[] = { kpidSize, kpidPackSize, kpidMethod }; static const Byte kArcProps[] = { kpidNumStreams }; struct CHeader { UInt64 Size; Byte FilterID; Byte LzmaProps[5]; UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); } bool HasSize() const { return (Size != (UInt64)(Int64)-1); } bool Parse(const Byte *buf, bool isThereFilter); }; bool CHeader::Parse(const Byte *buf, bool isThereFilter) { FilterID = 0; if (isThereFilter) FilterID = buf[0]; const Byte *sig = buf + (isThereFilter ? 1 : 0); for (int i = 0; i < 5; i++) LzmaProps[i] = sig[i]; Size = GetUi64(sig + 5); return LzmaProps[0] < 5 * 5 * 9 && FilterID < 2 && (!HasSize() || Size < ((UInt64)1 << 56)) && CheckDicSize(LzmaProps + 1); } class CDecoder { CMyComPtr _lzmaDecoder; CMyComPtr _bcjStream; public: NCompress::NLzma::CDecoder *_lzmaDecoderSpec; ~CDecoder(); HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS bool filtered, ISequentialInStream *inStream); HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress); UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); } void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); } HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize) { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); } }; static const UInt32 k_BCJ = 0x03030103; HRESULT CDecoder::Create( DECL_EXTERNAL_CODECS_LOC_VARS bool filteredMode, ISequentialInStream *inStream) { if (!_lzmaDecoder) { _lzmaDecoderSpec = new NCompress::NLzma::CDecoder; _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } if (filteredMode) { if (!_bcjStream) { CMyComPtr coder; RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false)); if (!coder) return E_NOTIMPL; coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream); if (!_bcjStream) return E_NOTIMPL; } } return _lzmaDecoderSpec->SetInStream(inStream); } CDecoder::~CDecoder() { ReleaseInStream(); } HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { if (header.FilterID > 1) return E_NOTIMPL; { CMyComPtr setDecoderProperties; _lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); if (!setDecoderProperties) return E_NOTIMPL; RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5)); } CMyComPtr setOutStream; bool filteredMode = (header.FilterID == 1); if (filteredMode) { _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream); if (!setOutStream) return E_NOTIMPL; RINOK(setOutStream->SetOutStream(outStream)); outStream = _bcjStream; } const UInt64 *Size = header.HasSize() ? &header.Size : NULL; HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress); if (filteredMode) { CMyComPtr flush; _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush); if (flush) { HRESULT res2 = flush->Flush(); if (res == S_OK) res = res2; } HRESULT res2 = setOutStream->ReleaseOutStream(); if (res == S_OK) res = res2; } RINOK(res); if (header.HasSize()) if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size) return S_FALSE; return S_OK; } class CHandler: public IInArchive, public IArchiveOpenSeq, PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { CHeader _header; bool _lzma86; CMyComPtr _stream; CMyComPtr _seqStream; bool _isArc; bool _needSeekToStart; bool _dataAfterEnd; bool _needMoreInput; bool _packSize_Defined; bool _unpackSize_Defined; bool _numStreams_Defined; bool _unsupported; bool _dataError; UInt64 _packSize; UInt64 _unpackSize; UInt64 _numStreams; DECL_EXTERNAL_CODECS_VARS DECL_ISetCompressCodecsInfo public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq) QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); CHandler(bool lzma86) { _lzma86 = lzma86; } unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } }; IMP_IInArchive_Props IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; case kpidErrorFlags: { UInt32 v = 0; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_dataError) v |= kpv_ErrorFlags_DataError; prop = v; } } prop.Detach(value); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = 1; return S_OK; } static void DictSizeToString(UInt32 value, char *s) { for (int i = 0; i <= 31; i++) if (((UInt32)1 << i) == value) { ::ConvertUInt32ToString(i, s); return; } char c = 'b'; if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; } else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; } ::ConvertUInt32ToString(value, s); s += MyStringLen(s); *s++ = c; *s = 0; } STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; case kpidMethod: if (_stream) { char sz[64]; char *s = sz; if (_header.FilterID != 0) s = MyStpCpy(s, "BCJ "); s = MyStpCpy(s, "LZMA:"); DictSizeToString(_header.GetDicSize(), s); prop = sz; } break; } prop.Detach(value); return S_OK; } API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) { const UInt32 kHeaderSize = 1 + 4 + 8; if (size < kHeaderSize) return k_IsArc_Res_NEED_MORE; if (p[0] >= 5 * 5 * 9) return k_IsArc_Res_NO; UInt64 unpackSize = GetUi64(p + 1 + 4); if (unpackSize != (UInt64)(Int64)-1) { if (size >= ((UInt64)1 << 56)) return k_IsArc_Res_NO; } if (unpackSize != 0) { if (size < kHeaderSize + 2) return k_IsArc_Res_NEED_MORE; if (p[kHeaderSize] != 0) return k_IsArc_Res_NO; if (unpackSize != (UInt64)(Int64)-1) { if ((p[kHeaderSize + 1] & 0x80) != 0) return k_IsArc_Res_NO; } } if (!CheckDicSize(p + 1)) // return k_IsArc_Res_YES_LOW_PROB; return k_IsArc_Res_NO; return k_IsArc_Res_YES; } } API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) { if (size < 1) return k_IsArc_Res_NEED_MORE; Byte filterID = p[0]; if (filterID != 0 && filterID != 1) return k_IsArc_Res_NO; return IsArc_Lzma(p + 1, size - 1); } } STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) { Close(); const UInt32 kBufSize = 1 + 5 + 8 + 2; Byte buf[kBufSize]; RINOK(ReadStream_FALSE(inStream, buf, kBufSize)); if (!_header.Parse(buf, _lzma86)) return S_FALSE; const Byte *start = buf + GetHeaderSize(); if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 return S_FALSE; RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize)); if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0) return S_FALSE; _isArc = true; _stream = inStream; _seqStream = inStream; _needSeekToStart = true; return S_OK; } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); _isArc = true; _seqStream = stream; return S_OK; } STDMETHODIMP CHandler::Close() { _isArc = false; _packSize_Defined = false; _unpackSize_Defined = false; _numStreams_Defined = false; _dataAfterEnd = false; _needMoreInput = false; _unsupported = false; _dataError = false; _packSize = 0; _needSeekToStart = false; _stream.Release(); _seqStream.Release(); return S_OK; } class CCompressProgressInfoImp: public ICompressProgressInfo, public CMyUnknownImp { CMyComPtr Callback; public: UInt64 Offset; MY_UNKNOWN_IMP1(ICompressProgressInfo) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); void Init(IArchiveOpenCallback *callback) { Callback = callback; } }; STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) { if (Callback) { UInt64 files = 0; UInt64 value = Offset + *inSize; return Callback->SetCompleted(&files, &value); } return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; if (_packSize_Defined) extractCallback->SetTotal(_packSize); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); if (!testMode && !realOutStream) return S_OK; extractCallback->PrepareOperation(askMode); CDummyOutStream *outStreamSpec = new CDummyOutStream; CMyComPtr outStream(outStreamSpec); outStreamSpec->SetStream(realOutStream); outStreamSpec->Init(); realOutStream.Release(); CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, true); if (_needSeekToStart) { if (!_stream) return E_FAIL; RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } else _needSeekToStart = true; CDecoder decoder; HRESULT result = decoder.Create( EXTERNAL_CODECS_VARS _lzma86, _seqStream); RINOK(result); bool firstItem = true; UInt64 packSize = 0; UInt64 unpackSize = 0; UInt64 numStreams = 0; bool dataAfterEnd = false; for (;;) { lps->InSize = packSize; lps->OutSize = unpackSize; RINOK(lps->SetCur()); const UInt32 kBufSize = 1 + 5 + 8; Byte buf[kBufSize]; const UInt32 headerSize = GetHeaderSize(); UInt32 processed; RINOK(decoder.ReadInput(buf, headerSize, &processed)); if (processed != headerSize) { if (processed != 0) dataAfterEnd = true; break; } CHeader st; if (!st.Parse(buf, _lzma86)) { dataAfterEnd = true; break; } numStreams++; firstItem = false; result = decoder.Code(st, outStream, progress); packSize = decoder.GetInputProcessedSize(); unpackSize = outStreamSpec->GetSize(); if (result == E_NOTIMPL) { _unsupported = true; result = S_FALSE; break; } if (result == S_FALSE) break; RINOK(result); } if (firstItem) { _isArc = false; result = S_FALSE; } else if (result == S_OK || result == S_FALSE) { if (dataAfterEnd) _dataAfterEnd = true; else if (decoder._lzmaDecoderSpec->NeedMoreInput) _needMoreInput = true; _packSize = packSize; _unpackSize = unpackSize; _numStreams = numStreams; _packSize_Defined = true; _unpackSize_Defined = true; _numStreams_Defined = true; } Int32 opResult = NExtract::NOperationResult::kOK; if (!_isArc) opResult = NExtract::NOperationResult::kIsNotArc; else if (_needMoreInput) opResult = NExtract::NOperationResult::kUnexpectedEnd; else if (_unsupported) opResult = NExtract::NOperationResult::kUnsupportedMethod; else if (_dataAfterEnd) opResult = NExtract::NOperationResult::kDataAfterEnd; else if (result == S_FALSE) opResult = NExtract::NOperationResult::kDataError; else if (result == S_OK) opResult = NExtract::NOperationResult::kOK; else return result; outStream.Release(); return extractCallback->SetOperationResult(opResult); COM_TRY_END } IMPL_ISetCompressCodecsInfo namespace NLzmaAr { IMP_CreateArcIn_2(CHandler(false)) static CArcInfo g_ArcInfo = { "lzma", "lzma", 0, 0xA, 0, { 0 }, // 2, { 0x5D, 0x00 }, 0, NArcInfoFlags::kStartOpen | NArcInfoFlags::kKeepName, CreateArc, NULL, IsArc_Lzma }; REGISTER_ARC(Lzma) } namespace NLzma86Ar { IMP_CreateArcIn_2(CHandler(true)) static CArcInfo g_ArcInfo = { "lzma86", "lzma86", 0, 0xB, 0, { 0 }, 0, NArcInfoFlags::kKeepName, CreateArc, NULL, IsArc_Lzma86 }; REGISTER_ARC(Lzma86) } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/SplitHandler.cpp0100777000000000000000000002041113761647206024463 0ustar00// SplitHandler.cpp #include "StdAfx.h" #include "../../Common/ComTry.h" #include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Compress/CopyCoder.h" #include "Common/MultiStream.h" using namespace NWindows; namespace NArchive { namespace NSplit { static const Byte kProps[] = { kpidPath, kpidSize }; static const Byte kArcProps[] = { kpidNumVolumes, kpidTotalPhySize }; class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { CObjectVector > _streams; CRecordVector _sizes; UString _subName; UInt64 _totalSize; HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; IMP_IInArchive_Props IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidMainSubfile: prop = (UInt32)0; break; case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; case kpidTotalPhySize: prop = _totalSize; break; case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; } prop.Detach(value); return S_OK; } struct CSeqName { UString _unchangedPart; UString _changedPart; bool _splitStyle; UString GetNextName() { UString newName; if (_splitStyle) { int i; int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == 'z') { newName.InsertAtFront('a'); continue; } else if (c == 'Z') { newName.InsertAtFront('A'); continue; } c++; if ((c == 'z' || c == 'Z') && i == 0) { _unchangedPart += c; wchar_t newChar = (c == 'z') ? L'a' : L'A'; newName.Empty(); numLetters++; for (int k = 0; k < numLetters; k++) newName += newChar; break; } newName.InsertAtFront(c); i--; for (; i >= 0; i--) newName.InsertAtFront(_changedPart[i]); break; } } else { int i; int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == '9') { newName.InsertAtFront('0'); if (i == 0) newName.InsertAtFront('1'); continue; } c++; newName.InsertAtFront(c); i--; for (; i >= 0; i--) newName.InsertAtFront(_changedPart[i]); break; } } _changedPart = newName; return _unchangedPart + _changedPart; } }; HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { Close(); if (!callback) return S_FALSE; CMyComPtr volumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); if (!volumeCallback) return S_FALSE; UString name; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidName, &prop)); if (prop.vt != VT_BSTR) return S_FALSE; name = prop.bstrVal; } int dotPos = name.ReverseFind('.'); const UString prefix = name.Left(dotPos + 1); const UString ext = name.Ptr(dotPos + 1); UString ext2 = ext; ext2.MakeLower_Ascii(); CSeqName seqName; unsigned numLetters = 2; bool splitStyle = false; if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) { splitStyle = true; while (numLetters < ext2.Len()) { if (ext2[ext2.Len() - numLetters - 1] != 'a') break; numLetters++; } } else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) { while (numLetters < ext2.Len()) { if (ext2[ext2.Len() - numLetters - 1] != '0') break; numLetters++; } if (numLetters != ext.Len()) return S_FALSE; } else return S_FALSE; seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); seqName._changedPart = ext.RightPtr(numLetters); seqName._splitStyle = splitStyle; if (prefix.Len() < 1) _subName = L"file"; else _subName.SetFrom(prefix, prefix.Len() - 1); UInt64 size; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; } _totalSize += size; _sizes.Add(size); _streams.Add(stream); { UInt64 numFiles = _streams.Size(); RINOK(callback->SetCompleted(&numFiles, NULL)); } for (;;) { const UString fullName = seqName.GetNextName(); CMyComPtr nextStream; HRESULT result = volumeCallback->GetStream(fullName, &nextStream); if (result == S_FALSE) break; if (result != S_OK) return result; if (!stream) break; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; } _totalSize += size; _sizes.Add(size); _streams.Add(nextStream); { UInt64 numFiles = _streams.Size(); RINOK(callback->SetCompleted(&numFiles, NULL)); } } if (_streams.Size() == 1) { if (splitStyle) return S_FALSE; } return S_OK; } STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN HRESULT res = Open2(stream, callback); if (res != S_OK) Close(); return res; COM_TRY_END } STDMETHODIMP CHandler::Close() { _totalSize = 0; _subName.Empty(); _streams.Clear(); _sizes.Clear(); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _streams.IsEmpty() ? 0 : 1; return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidPath: prop = _subName; break; case kpidSize: case kpidPackSize: prop = _totalSize; break; } prop.Detach(value); return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; UInt64 currentTotalSize = 0; RINOK(extractCallback->SetTotal(_totalSize)); CMyComPtr outStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &outStream, askMode)); if (!testMode && !outStream) return S_OK; RINOK(extractCallback->PrepareOperation(askMode)); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); FOR_VECTOR (i, _streams) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); IInStream *inStream = _streams[i]; RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); currentTotalSize += copyCoderSpec->TotalSize; } outStream.Release(); return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN if (index != 0) return E_INVALIDARG; *stream = 0; CMultiStream *streamSpec = new CMultiStream; CMyComPtr streamTemp = streamSpec; FOR_VECTOR (i, _streams) { CMultiStream::CSubStreamInfo subStreamInfo; subStreamInfo.Stream = _streams[i]; subStreamInfo.Size = _sizes[i]; streamSpec->Streams.Add(subStreamInfo); } streamSpec->Init(); *stream = streamTemp.Detach(); return S_OK; COM_TRY_END } IMP_CreateArcIn static CArcInfo g_ArcInfo = { "Split", "001", 0, 0xEA, 0, { 0 }, 0, 0, CreateArc }; REGISTER_ARC(Split) }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Archive/XzHandler.cpp0100777000000000000000000005346413761647206024007 0ustar00// XzHandler.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../../../C/XzCrc64.h" #include "../../../C/XzEnc.h" #include "../../Common/ComTry.h" #include "../../Common/Defs.h" #include "../../Common/IntToString.h" #include "../ICoder.h" #include "../Common/CWrappers.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" #include "IArchive.h" #include "Common/HandlerOut.h" using namespace NWindows; namespace NCompress { namespace NLzma2 { HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); }} static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; namespace NArchive { namespace NXz { struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; static const wchar_t *k_LZMA2_Name = L"LZMA2"; struct CStatInfo { UInt64 InSize; UInt64 OutSize; UInt64 PhySize; UInt64 NumStreams; UInt64 NumBlocks; bool UnpackSize_Defined; bool NumStreams_Defined; bool NumBlocks_Defined; bool IsArc; bool UnexpectedEnd; bool DataAfterEnd; bool Unsupported; bool HeadersError; bool DataError; bool CrcError; CStatInfo() { Clear(); } void Clear() { InSize = 0; OutSize = 0; PhySize = 0; NumStreams = 0; NumBlocks = 0; UnpackSize_Defined = false; NumStreams_Defined = false; NumBlocks_Defined = false; UnexpectedEnd = false; DataAfterEnd = false; Unsupported = false; HeadersError = false; DataError = false; CrcError = false; IsArc = false; } }; struct IDecodeState: public CStatInfo { SRes DecodeRes; IDecodeState(): DecodeRes(SZ_OK) {} virtual HRESULT Progress() = 0; HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream); }; struct CVirtProgress_To_LocalProgress: public IDecodeState { CLocalProgress *lps; CMyComPtr progress; HRESULT Progress(); }; HRESULT CVirtProgress_To_LocalProgress::Progress() { lps->InSize = InSize; lps->OutSize = OutSize; return lps->SetCur(); } class CHandler: public IInArchive, public IArchiveOpenSeq, #ifndef EXTRACT_ONLY public IOutArchive, public ISetProperties, public CMultiMethodProps, #endif public CMyUnknownImp { CStatInfo _stat; bool _isArc; bool _needSeekToStart; bool _phySize_Defined; CMyComPtr _stream; CMyComPtr _seqStream; UInt32 _filterId; AString _methodsString; void Init() { _filterId = 0; CMultiMethodProps::Init(); } HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress) { RINOK(progress.Decode(seqInStream, outStream)); _stat = progress; _phySize_Defined = true; return S_OK; } public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq) #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY(IOutArchive) MY_QUERYINTERFACE_ENTRY(ISetProperties) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif CHandler(); }; CHandler::CHandler() { Init(); } static const Byte kProps[] = { kpidSize, kpidPackSize, kpidMethod }; static const Byte kArcProps[] = { kpidMethod, kpidNumStreams, kpidNumBlocks }; IMP_IInArchive_Props IMP_IInArchive_ArcProps static inline char GetHex(unsigned value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } static inline void AddHexToString(AString &s, Byte value) { s += GetHex(value >> 4); s += GetHex(value & 0xF); } static void AddUInt32ToString(AString &s, UInt32 value) { char temp[16]; ConvertUInt32ToString(value, temp); s += temp; } static void Lzma2PropToString(AString &s, unsigned prop) { char c = 0; UInt32 size; if ((prop & 1) == 0) size = prop / 2 + 12; else { c = 'k'; size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1); if (prop > 17) { size >>= 10; c = 'm'; } } AddUInt32ToString(s, size); if (c != 0) s += c; } struct CMethodNamePair { UInt32 Id; const char *Name; }; static const CMethodNamePair g_NamePairs[] = { { XZ_ID_Subblock, "SB" }, { XZ_ID_Delta, "Delta" }, { XZ_ID_X86, "BCJ" }, { XZ_ID_PPC, "PPC" }, { XZ_ID_IA64, "IA64" }, { XZ_ID_ARM, "ARM" }, { XZ_ID_ARMT, "ARMT" }, { XZ_ID_SPARC, "SPARC" }, { XZ_ID_LZMA2, "LZMA2" } }; static AString GetMethodString(const CXzFilter &f) { const char *p = NULL; for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++) if (g_NamePairs[i].Id == f.id) { p = g_NamePairs[i].Name; break; } char temp[32]; if (!p) { ::ConvertUInt64ToString(f.id, temp); p = temp; } AString s = p; if (f.propsSize > 0) { s += ':'; if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) Lzma2PropToString(s, f.props[0]); else if (f.id == XZ_ID_Delta && f.propsSize == 1) AddUInt32ToString(s, (UInt32)f.props[0] + 1); else { s += '['; for (UInt32 bi = 0; bi < f.propsSize; bi++) AddHexToString(s, f.props[bi]); s += ']'; } } return s; } static void AddString(AString &dest, const AString &src) { if (!dest.IsEmpty()) dest += ' '; dest += src; } static const char *kChecks[] = { "NoCheck" , "CRC32" , NULL , NULL , "CRC64" , NULL , NULL , NULL , NULL , NULL , "SHA256" , NULL , NULL , NULL , NULL , NULL }; static AString GetCheckString(const CXzs &xzs) { size_t i; UInt32 mask = 0; for (i = 0; i < xzs.num; i++) mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags)); AString s; for (i = 0; i <= XZ_CHECK_MASK; i++) if (((mask >> i) & 1) != 0) { AString s2; if (kChecks[i]) s2 = kChecks[i]; else { s2 = "Check-"; AddUInt32ToString(s2, (UInt32)i); } AddString(s, s2); } return s; } STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; switch (propID) { case kpidPhySize: if (_phySize_Defined) prop = _stat.PhySize; break; case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break; case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break; case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; case kpidErrorFlags: { UInt32 v = 0; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError; if (_stat.Unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_stat.DataError) v |= kpv_ErrorFlags_DataError; if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError; prop = v; } } prop.Detach(value); return S_OK; COM_TRY_END } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = 1; return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; switch (propID) { case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; case kpidPackSize: if (_phySize_Defined) prop = _stat.PhySize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; } prop.Detach(value); return S_OK; COM_TRY_END } struct COpenCallbackWrap { ICompressProgress p; IArchiveOpenCallback *OpenCallback; HRESULT Res; COpenCallbackWrap(IArchiveOpenCallback *progress); }; static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */) { COpenCallbackWrap *p = (COpenCallbackWrap *)pp; p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); return (SRes)p->Res; } COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback) { p.Progress = OpenCallbackProgress; OpenCallback = callback; Res = SZ_OK; } struct CXzsCPP { CXzs p; CXzsCPP() { Xzs_Construct(&p); } ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } }; struct CVirtProgress_To_OpenProgress: public IDecodeState { IArchiveOpenCallback *Callback; UInt64 Offset; HRESULT Progress(); }; HRESULT CVirtProgress_To_OpenProgress::Progress() { if (Callback) { UInt64 files = 0; UInt64 value = Offset + InSize; return Callback->SetCompleted(&files, &value); } return S_OK; } static HRESULT SRes_to_Open_HRESULT(SRes res) { switch (res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PROGRESS: return E_ABORT; /* case SZ_ERROR_UNSUPPORTED: case SZ_ERROR_CRC: case SZ_ERROR_DATA: case SZ_ERROR_ARCHIVE: case SZ_ERROR_NO_ARCHIVE: return S_FALSE; */ } return S_FALSE; } HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) { _needSeekToStart = true; { CXzStreamFlags st; CSeqInStreamWrap inStreamWrap(inStream); SRes res = Xz_ReadHeader(&st, &inStreamWrap.p); if (res != SZ_OK) return SRes_to_Open_HRESULT(res); { CXzBlock block; Bool isIndex; UInt32 headerSizeRes; SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes); if (res2 == SZ_OK && !isIndex) { unsigned numFilters = XzBlock_GetNumFilters(&block); for (unsigned i = 0; i < numFilters; i++) AddString(_methodsString, GetMethodString(block.filters[i])); } } } RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize)); RINOK(callback->SetTotal(NULL, &_stat.PhySize)); CSeekInStreamWrap inStreamImp(inStream); CLookToRead lookStream; LookToRead_CreateVTable(&lookStream, True); lookStream.realStream = &inStreamImp.p; LookToRead_Init(&lookStream); COpenCallbackWrap openWrap(callback); CXzsCPP xzs; Int64 startPosition; SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &g_Alloc); if (res == SZ_ERROR_PROGRESS) return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; /* if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) res = SZ_OK; */ if (res == SZ_OK && startPosition == 0) { _phySize_Defined = true; _stat.OutSize = Xzs_GetUnpackSize(&xzs.p); _stat.UnpackSize_Defined = true; _stat.NumStreams = xzs.p.num; _stat.NumStreams_Defined = true; _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p); _stat.NumBlocks_Defined = true; AddString(_methodsString, GetCheckString(xzs.p)); } else { res = SZ_OK; } RINOK(SRes_to_Open_HRESULT(res)); _stream = inStream; _seqStream = inStream; _isArc = true; return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN { Close(); return Open2(inStream, /* 0, */ callback); } COM_TRY_END } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); _seqStream = stream; _isArc = true; _needSeekToStart = false; return S_OK; } STDMETHODIMP CHandler::Close() { _stat.Clear(); _isArc = false; _needSeekToStart = false; _phySize_Defined = false; _methodsString.Empty(); _stream.Release(); _seqStream.Release(); return S_OK; } class CSeekToSeqStream: public IInStream, public CMyUnknownImp { public: CMyComPtr Stream; MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize) { return Stream->Read(data, size, processedSize); } STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; } struct CXzUnpackerCPP { Byte *InBuf; Byte *OutBuf; CXzUnpacker p; CXzUnpackerCPP(): InBuf(0), OutBuf(0) { XzUnpacker_Construct(&p, &g_Alloc); } ~CXzUnpackerCPP() { XzUnpacker_Free(&p); MyFree(InBuf); MyFree(OutBuf); } }; HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream) { const size_t kInBufSize = 1 << 15; const size_t kOutBufSize = 1 << 21; DecodeRes = SZ_OK; CXzUnpackerCPP xzu; XzUnpacker_Init(&xzu.p); xzu.InBuf = (Byte *)MyAlloc(kInBufSize); xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); if (!xzu.InBuf || !xzu.OutBuf) return E_OUTOFMEMORY; UInt32 inSize = 0; SizeT inPos = 0; SizeT outPos = 0; for (;;) { if (inPos == inSize) { inPos = inSize = 0; RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize)); } SizeT inLen = inSize - inPos; SizeT outLen = kOutBufSize - outPos; ECoderStatus status; SRes res = XzUnpacker_Code(&xzu.p, xzu.OutBuf + outPos, &outLen, xzu.InBuf + inPos, &inLen, (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status); inPos += inLen; outPos += outLen; InSize += inLen; OutSize += outLen; DecodeRes = res; bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK); if (outStream) { if (outPos == kOutBufSize || finished) { if (outPos != 0) { RINOK(WriteStream(outStream, xzu.OutBuf, outPos)); outPos = 0; } } } else outPos = 0; RINOK(Progress()); if (finished) { PhySize = InSize; NumStreams = xzu.p.numStartedStreams; if (NumStreams > 0) IsArc = true; NumBlocks = xzu.p.numTotalBlocks; UnpackSize_Defined = true; NumStreams_Defined = true; NumBlocks_Defined = true; UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p); if (res == SZ_OK) { if (status == CODER_STATUS_NEEDS_MORE_INPUT) { extraSize = 0; if (!XzUnpacker_IsStreamWasFinished(&xzu.p)) { // finished at padding bytes, but padding is not aligned for 4 UnexpectedEnd = true; res = SZ_ERROR_DATA; } } else // status == CODER_STATUS_NOT_FINISHED res = SZ_ERROR_DATA; } else if (res == SZ_ERROR_NO_ARCHIVE) { if (InSize == extraSize) IsArc = false; else { if (extraSize != 0 || inPos != inSize) { DataAfterEnd = true; res = SZ_OK; } } } DecodeRes = res; PhySize -= extraSize; switch (res) { case SZ_OK: break; case SZ_ERROR_NO_ARCHIVE: IsArc = false; break; case SZ_ERROR_ARCHIVE: HeadersError = true; break; case SZ_ERROR_UNSUPPORTED: Unsupported = true; break; case SZ_ERROR_CRC: CrcError = true; break; case SZ_ERROR_DATA: DataError = true; break; default: DataError = true; break; } break; } } return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; extractCallback->SetTotal(_stat.PhySize); UInt64 currentTotalPacked = 0; RINOK(extractCallback->SetCompleted(¤tTotalPacked)); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); if (!testMode && !realOutStream) return S_OK; extractCallback->PrepareOperation(askMode); CVirtProgress_To_LocalProgress vp; vp.lps = new CLocalProgress; vp.progress = vp.lps; vp.lps->Init(extractCallback, true); if (_needSeekToStart) { if (!_stream) return E_FAIL; RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } else _needSeekToStart = true; RINOK(Decode2(_seqStream, realOutStream, vp)); Int32 opRes; if (!vp.IsArc) opRes = NExtract::NOperationResult::kIsNotArc; else if (vp.UnexpectedEnd) opRes = NExtract::NOperationResult::kUnexpectedEnd; else if (vp.DataAfterEnd) opRes = NExtract::NOperationResult::kDataAfterEnd; else if (vp.CrcError) opRes = NExtract::NOperationResult::kCRCError; else if (vp.Unsupported) opRes = NExtract::NOperationResult::kUnsupportedMethod; else if (vp.HeadersError) opRes = NExtract::NOperationResult::kDataError; else if (vp.DataError) opRes = NExtract::NOperationResult::kDataError; else if (vp.DecodeRes != SZ_OK) opRes = NExtract::NOperationResult::kDataError; else opRes = NExtract::NOperationResult::kOK; realOutStream.Release(); return extractCallback->SetOperationResult(opRes); COM_TRY_END } #ifndef EXTRACT_ONLY STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { *timeType = NFileTimeType::kUnix; return S_OK; } STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { CSeqOutStreamWrap seqOutStream(outStream); if (numItems == 0) { SRes res = Xz_EncodeEmpty(&seqOutStream.p); return SResToHRESULT(res); } if (numItems != 1) return E_INVALIDARG; Int32 newData, newProps; UInt32 indexInArchive; if (!updateCallback) return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); if (IntToBool(newProps)) { { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); if (prop.vt != VT_EMPTY) if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) return E_INVALIDARG; } } if (IntToBool(newData)) { UInt64 size; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; RINOK(updateCallback->SetTotal(size)); } CLzma2EncProps lzma2Props; Lzma2EncProps_Init(&lzma2Props); lzma2Props.lzmaProps.level = GetLevel(); CMyComPtr fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); CSeqInStreamWrap seqInStream(fileInStream); { NCOM::CPropVariant prop = (UInt64)size; RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props)); } FOR_VECTOR (i, _methods) { COneMethodInfo &m = _methods[i]; SetGlobalLevelAndThreads(m #ifndef _7ZIP_ST , _numThreads #endif ); { FOR_VECTOR (j, m.Props) { const CProp &prop = m.Props[j]; RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props)); } } } #ifndef _7ZIP_ST lzma2Props.numTotalThreads = _numThreads; #endif CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(updateCallback, true); CCompressProgressWrap progressWrap(progress); CXzProps xzProps; CXzFilterProps filter; XzProps_Init(&xzProps); XzFilterProps_Init(&filter); xzProps.lzma2Props = &lzma2Props; xzProps.filterProps = (_filterId != 0 ? &filter : NULL); switch (_crcSize) { case 0: xzProps.checkId = XZ_CHECK_NO; break; case 4: xzProps.checkId = XZ_CHECK_CRC32; break; case 8: xzProps.checkId = XZ_CHECK_CRC64; break; case 32: xzProps.checkId = XZ_CHECK_SHA256; break; default: return E_INVALIDARG; } filter.id = _filterId; if (_filterId == XZ_ID_Delta) { bool deltaDefined = false; FOR_VECTOR (j, _filterMethod.Props) { const CProp &prop = _filterMethod.Props[j]; if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) { UInt32 delta = (UInt32)prop.Value.ulVal; if (delta < 1 || delta > 256) return E_INVALIDARG; filter.delta = delta; deltaDefined = true; } } if (!deltaDefined) return E_INVALIDARG; } SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &xzProps, &progressWrap.p); if (res == SZ_OK) return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); return SResToHRESULT(res); } if (indexInArchive != 0) return E_INVALIDARG; if (_stream) RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); return NCompress::CopyStream(_stream, outStream, NULL); } STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN Init(); for (UInt32 i = 0; i < numProps; i++) { RINOK(SetProperty(names[i], values[i])); } if (!_filterMethod.MethodName.IsEmpty()) { unsigned k; for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++) { const CMethodNamePair &pair = g_NamePairs[k]; if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name)) { _filterId = pair.Id; break; } } if (k == ARRAY_SIZE(g_NamePairs)) return E_INVALIDARG; } _methods.DeleteFrontal(GetNumEmptyMethods()); if (_methods.Size() > 1) return E_INVALIDARG; if (_methods.Size() == 1) { UString &methodName = _methods[0].MethodName; if (methodName.IsEmpty()) methodName = k_LZMA2_Name; else if (!methodName.IsEqualToNoCase(k_LZMA2_Name)) return E_INVALIDARG; } return S_OK; COM_TRY_END } #endif IMP_CreateArcIn IMP_CreateArcOut static CArcInfo g_ArcInfo = { "xz", "xz txz", "* .tar", 0xC, 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 }, 0, NArcInfoFlags::kKeepName, REF_CreateArc_Pair }; REGISTER_ARC(xz) }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/0040777000000000000000000000000013761647206021237 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/Common.pri0100777000000000000000000000353713761647206023213 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Common/CWrappers.h \ $$7ZIP_BASE/CPP/7zip/Common/CreateCoder.h \ $$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.h \ $$7ZIP_BASE/CPP/7zip/Common/FileStreams.h \ $$7ZIP_BASE/CPP/7zip/Common/FilterCoder.h \ $$7ZIP_BASE/CPP/7zip/Common/InBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.h \ $$7ZIP_BASE/CPP/7zip/Common/LockedStream.h \ $$7ZIP_BASE/CPP/7zip/Common/MethodId.h \ $$7ZIP_BASE/CPP/7zip/Common/MethodProps.h \ $$7ZIP_BASE/CPP/7zip/Common/OutBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.h \ $$7ZIP_BASE/CPP/7zip/Common/RegisterArc.h \ $$7ZIP_BASE/CPP/7zip/Common/RegisterCodec.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamBinder.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamObjects.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamUtils.h \ $$7ZIP_BASE/CPP/7zip/Common/UniqBlocks.h \ $$7ZIP_BASE/CPP/7zip/Common/VirtThread.h SOURCES += $$7ZIP_BASE/CPP/7zip/Common/CWrappers.cpp \ $$7ZIP_BASE/CPP/7zip/Common/CreateCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FileStreams.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FilterCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/InBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.cpp \ $$7ZIP_BASE/CPP/7zip/Common/LockedStream.cpp \ $$7ZIP_BASE/CPP/7zip/Common/MethodProps.cpp \ $$7ZIP_BASE/CPP/7zip/Common/OutBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Common/PropId.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamBinder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamObjects.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Common/UniqBlocks.cpp \ $$7ZIP_BASE/CPP/7zip/Common/VirtThread.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.cpp0100777000000000000000000002406713761647206024134 0ustar00// CreateCoder.cpp #include "StdAfx.h" #include "../../Windows/Defs.h" #include "../../Windows/PropVariant.h" #include "CreateCoder.h" #include "FilterCoder.h" #include "RegisterCodec.h" static const unsigned int kNumCodecsMax = 64; unsigned int g_NumCodecs = 0; const CCodecInfo *g_Codecs[kNumCodecsMax]; void RegisterCodec(const CCodecInfo *codecInfo) throw() { if (g_NumCodecs < kNumCodecsMax) g_Codecs[g_NumCodecs++] = codecInfo; } static const unsigned int kNumHashersMax = 16; unsigned int g_NumHashers = 0; const CHasherInfo *g_Hashers[kNumHashersMax]; void RegisterHasher(const CHasherInfo *hashInfo) throw() { if (g_NumHashers < kNumHashersMax) g_Hashers[g_NumHashers++] = hashInfo; } #ifdef EXTERNAL_CODECS static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) { NWindows::NCOM::CPropVariant prop; RINOK(codecsInfo->GetProperty(index, propID, &prop)); if (prop.vt == VT_EMPTY) res = 1; else if (prop.vt == VT_UI4) res = prop.ulVal; else return E_INVALIDARG; return S_OK; } static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) { NWindows::NCOM::CPropVariant prop; RINOK(codecsInfo->GetProperty(index, propID, &prop)); if (prop.vt == VT_EMPTY) res = true; else if (prop.vt == VT_BOOL) res = VARIANT_BOOLToBool(prop.boolVal); else return E_INVALIDARG; return S_OK; } HRESULT CExternalCodecs::LoadCodecs() { if (GetCodecs) { UInt32 num; RINOK(GetCodecs->GetNumberOfMethods(&num)); for (UInt32 i = 0; i < num; i++) { CCodecInfoEx info; NWindows::NCOM::CPropVariant prop; RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)); // if (prop.vt != VT_BSTR) // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal); // memcpy(info.Id.ID, prop.bstrVal, info.Id.IDSize); if (prop.vt != VT_UI8) continue; // old Interface info.Id = prop.uhVal.QuadPart; prop.Clear(); RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)); if (prop.vt == VT_BSTR) info.Name = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_INVALIDARG; RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kInStreams, info.NumInStreams)); RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kOutStreams, info.NumOutStreams)); RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)); RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)); Codecs.Add(info); } } if (GetHashers) { UInt32 num = GetHashers->GetNumHashers(); for (UInt32 i = 0; i < num; i++) { CHasherInfoEx info; NWindows::NCOM::CPropVariant prop; RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) continue; info.Id = prop.uhVal.QuadPart; prop.Clear(); RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)); if (prop.vt == VT_BSTR) info.Name = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_INVALIDARG; Hashers.Add(info); } } return S_OK; } #endif bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (name.IsEqualToNoCase(codec.Name)) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = 1; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (codec.Name.IsEqualToNoCase(name)) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = codec.NumOutStreams; return true; } } #endif return false; } bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (methodId == codec.Id) { name = codec.Name; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (methodId == codec.Id) { name = codec.Name; return true; } } #endif return false; } bool FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId) { UInt32 i; for (i = 0; i < g_NumHashers; i++) { const CHasherInfo &codec = *g_Hashers[i]; if (name.IsEqualToNoCase(codec.Name)) { methodId = codec.Id; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) { const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; if (codec.Name.IsEqualToNoCase(name)) { methodId = codec.Id; return true; } } #endif return false; } void GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector &methods) { methods.ClearAndSetSize(g_NumHashers); UInt32 i; for (i = 0; i < g_NumHashers; i++) methods[i] = (*g_Hashers[i]).Id; #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) methods.Add(__externalCodecs->Hashers[i].Id); #endif } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, CMyComPtr &coder, CMyComPtr &coder2, bool encode, bool onlyCoder) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (codec.Id == methodId) { if (encode) { if (codec.CreateEncoder) { void *p = codec.CreateEncoder(); if (codec.IsFilter) filter = (ICompressFilter *)p; else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; else coder2 = (ICompressCoder2 *)p; break; } } else if (codec.CreateDecoder) { void *p = codec.CreateDecoder(); if (codec.IsFilter) filter = (ICompressFilter *)p; else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; else coder2 = (ICompressCoder2 *)p; break; } } } #ifdef EXTERNAL_CODECS if (!filter && !coder && !coder2 && __externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (codec.Id == methodId) { if (encode) { if (codec.EncoderIsAssigned) { if (codec.IsSimpleCodec()) { HRESULT result = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder); if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) return result; if (!coder) { RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter)); } } else { RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2)); } break; } } else if (codec.DecoderIsAssigned) { if (codec.IsSimpleCodec()) { HRESULT result = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder); if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) return result; if (!coder) { RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter)); } } else { RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2)); } break; } } } #endif if (onlyCoder && filter) { CFilterCoder *coderSpec = new CFilterCoder; coder = coderSpec; coderSpec->Filter = filter; } return S_OK; } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, CMyComPtr &coder2, bool encode) { CMyComPtr filter; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, filter, coder, coder2, encode, true); } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, bool encode) { CMyComPtr filter; CMyComPtr coder2; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, coder, coder2, encode); } HRESULT CreateFilter( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, bool encode) { CMyComPtr coder; CMyComPtr coder2; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, filter, coder, coder2, encode, false); } HRESULT CreateHasher( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name, CMyComPtr &hasher) { UInt32 i; for (i = 0; i < g_NumHashers; i++) { const CHasherInfo &codec = *g_Hashers[i]; if (codec.Id == methodId) { hasher = (IHasher *)codec.CreateHasher(); name = codec.Name; break; } } #ifdef EXTERNAL_CODECS if (!hasher && __externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) { const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; if (codec.Id == methodId) { name = codec.Name; return __externalCodecs->GetHashers->CreateHasher(i, &hasher); } } #endif return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.h0100777000000000000000000000655013761647206023576 0ustar00// CreateCoder.h #ifndef __CREATE_CODER_H #define __CREATE_CODER_H #include "../../Common/MyCom.h" #include "../../Common/MyString.h" #include "../ICoder.h" #include "MethodId.h" #ifdef EXTERNAL_CODECS struct CCodecInfoEx { UString Name; CMethodId Id; UInt32 NumInStreams; UInt32 NumOutStreams; bool EncoderIsAssigned; bool DecoderIsAssigned; bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; } CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {} }; struct CHasherInfoEx { UString Name; CMethodId Id; }; #define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo, #define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo) #define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo); #define IMPL_ISetCompressCodecsInfo2(x) \ STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \ COM_TRY_BEGIN __externalCodecs.GetCodecs = compressCodecsInfo; return __externalCodecs.LoadCodecs(); COM_TRY_END } #define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler) struct CExternalCodecs { CMyComPtr GetCodecs; CMyComPtr GetHashers; CObjectVector Codecs; CObjectVector Hashers; HRESULT LoadCodecs(); }; #define EXTERNAL_CODECS_VARS2 &__externalCodecs #define DECL_EXTERNAL_CODECS_VARS CExternalCodecs __externalCodecs; #define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2, #define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *__externalCodecs #define EXTERNAL_CODECS_LOC_VARS2 __externalCodecs #define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2, #define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2, #else #define PUBLIC_ISetCompressCodecsInfo #define QUERY_ENTRY_ISetCompressCodecsInfo #define DECL_ISetCompressCodecsInfo #define IMPL_ISetCompressCodecsInfo #define EXTERNAL_CODECS_VARS2 #define DECL_EXTERNAL_CODECS_VARS #define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2 #define DECL_EXTERNAL_CODECS_LOC_VARS2 #define EXTERNAL_CODECS_LOC_VARS2 #define DECL_EXTERNAL_CODECS_LOC_VARS #define EXTERNAL_CODECS_LOC_VARS #endif bool FindMethod( DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams); bool FindMethod( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name); bool FindHashMethod( DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId); void GetHashMethods( DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector &methods); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, CMyComPtr &coder, CMyComPtr &coder2, bool encode, bool onlyCoder); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, CMyComPtr &coder2, bool encode); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, bool encode); HRESULT CreateFilter( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, bool encode); HRESULT CreateHasher( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name, CMyComPtr &hacher); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.cpp0100777000000000000000000001173613761647206023661 0ustar00// CWrappers.h #include "StdAfx.h" #include "../../../C/Alloc.h" #include "CWrappers.h" #include "StreamUtils.h" #define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1) #define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x) static SRes CompressProgress(void *pp, UInt64 inSize, UInt64 outSize) throw() { CCompressProgressWrap *p = (CCompressProgressWrap *)pp; p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize)); return (SRes)p->Res; } CCompressProgressWrap::CCompressProgressWrap(ICompressProgressInfo *progress) throw() { p.Progress = CompressProgress; Progress = progress; Res = SZ_OK; } static const UInt32 kStreamStepSize = (UInt32)1 << 31; SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) { switch (res) { case S_OK: return SZ_OK; case E_OUTOFMEMORY: return SZ_ERROR_MEM; case E_INVALIDARG: return SZ_ERROR_PARAM; case E_ABORT: return SZ_ERROR_PROGRESS; case S_FALSE: return SZ_ERROR_DATA; case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED; } return defaultRes; } static SRes MyRead(void *object, void *data, size_t *size) throw() { CSeqInStreamWrap *p = (CSeqInStreamWrap *)object; UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); p->Res = (p->Stream->Read(data, curSize, &curSize)); *size = curSize; p->Processed += curSize; if (p->Res == S_OK) return SZ_OK; return HRESULT_To_SRes(p->Res, SZ_ERROR_READ); } static size_t MyWrite(void *object, const void *data, size_t size) throw() { CSeqOutStreamWrap *p = (CSeqOutStreamWrap *)object; if (p->Stream) { p->Res = WriteStream(p->Stream, data, size); if (p->Res != 0) return 0; } else p->Res = S_OK; p->Processed += size; return size; } CSeqInStreamWrap::CSeqInStreamWrap(ISequentialInStream *stream) throw() { p.Read = MyRead; Stream = stream; Processed = 0; } CSeqOutStreamWrap::CSeqOutStreamWrap(ISequentialOutStream *stream) throw() { p.Write = MyWrite; Stream = stream; Res = SZ_OK; Processed = 0; } HRESULT SResToHRESULT(SRes res) throw() { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; case SZ_ERROR_PROGRESS: return E_ABORT; case SZ_ERROR_DATA: return S_FALSE; case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; } return E_FAIL; } static SRes InStreamWrap_Read(void *pp, void *data, size_t *size) throw() { CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp; UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); p->Res = p->Stream->Read(data, curSize, &curSize); *size = curSize; return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; } static SRes InStreamWrap_Seek(void *pp, Int64 *offset, ESzSeek origin) throw() { CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp; UInt32 moveMethod; switch(origin) { case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break; case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break; case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break; default: return SZ_ERROR_PARAM; } UInt64 newPosition; p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition); *offset = (Int64)newPosition; return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; } CSeekInStreamWrap::CSeekInStreamWrap(IInStream *stream) throw() { Stream = stream; p.Read = InStreamWrap_Read; p.Seek = InStreamWrap_Seek; Res = S_OK; } /* ---------- CByteInBufWrap ---------- */ void CByteInBufWrap::Free() throw() { ::MidFree(Buf); Buf = 0; } bool CByteInBufWrap::Alloc(UInt32 size) throw() { if (Buf == 0 || size != Size) { Free(); Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size); Size = size; } return (Buf != 0); } Byte CByteInBufWrap::ReadByteFromNewBlock() throw() { if (Res == S_OK) { UInt32 avail; Processed += (Cur - Buf); Res = Stream->Read(Buf, Size, &avail); Cur = Buf; Lim = Buf + avail; if (avail != 0) return *Cur++; } Extra = true; return 0; } static Byte Wrap_ReadByte(void *pp) throw() { CByteInBufWrap *p = (CByteInBufWrap *)pp; if (p->Cur != p->Lim) return *p->Cur++; return p->ReadByteFromNewBlock(); } CByteInBufWrap::CByteInBufWrap(): Buf(0) { p.Read = Wrap_ReadByte; } /* ---------- CByteOutBufWrap ---------- */ void CByteOutBufWrap::Free() throw() { ::MidFree(Buf); Buf = 0; } bool CByteOutBufWrap::Alloc(size_t size) throw() { if (Buf == 0 || size != Size) { Free(); Buf = (Byte *)::MidAlloc(size); Size = size; } return (Buf != 0); } HRESULT CByteOutBufWrap::Flush() throw() { if (Res == S_OK) { size_t size = (Cur - Buf); Res = WriteStream(Stream, Buf, size); if (Res == S_OK) Processed += size; Cur = Buf; } return Res; } static void Wrap_WriteByte(void *pp, Byte b) throw() { CByteOutBufWrap *p = (CByteOutBufWrap *)pp; Byte *dest = p->Cur; *dest = b; p->Cur = ++dest; if (dest == p->Lim) p->Flush(); } CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(0) { p.Write = Wrap_WriteByte; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.h0100777000000000000000000000370713761647206023325 0ustar00// CWrappers.h #ifndef __C_WRAPPERS_H #define __C_WRAPPERS_H #include "../ICoder.h" #include "../../Common/MyCom.h" struct CCompressProgressWrap { ICompressProgress p; ICompressProgressInfo *Progress; HRESULT Res; CCompressProgressWrap(ICompressProgressInfo *progress) throw(); }; struct CSeqInStreamWrap { ISeqInStream p; ISequentialInStream *Stream; HRESULT Res; UInt64 Processed; CSeqInStreamWrap(ISequentialInStream *stream) throw(); }; struct CSeekInStreamWrap { ISeekInStream p; IInStream *Stream; HRESULT Res; CSeekInStreamWrap(IInStream *stream) throw(); }; struct CSeqOutStreamWrap { ISeqOutStream p; ISequentialOutStream *Stream; HRESULT Res; UInt64 Processed; CSeqOutStreamWrap(ISequentialOutStream *stream) throw(); }; HRESULT SResToHRESULT(SRes res) throw(); struct CByteInBufWrap { IByteIn p; const Byte *Cur; const Byte *Lim; Byte *Buf; UInt32 Size; ISequentialInStream *Stream; UInt64 Processed; bool Extra; HRESULT Res; CByteInBufWrap(); ~CByteInBufWrap() { Free(); } void Free() throw(); bool Alloc(UInt32 size) throw(); void Init() { Lim = Cur = Buf; Processed = 0; Extra = false; Res = S_OK; } UInt64 GetProcessed() const { return Processed + (Cur - Buf); } Byte ReadByteFromNewBlock() throw(); Byte ReadByte() { if (Cur != Lim) return *Cur++; return ReadByteFromNewBlock(); } }; struct CByteOutBufWrap { IByteOut p; Byte *Cur; const Byte *Lim; Byte *Buf; size_t Size; ISequentialOutStream *Stream; UInt64 Processed; HRESULT Res; CByteOutBufWrap() throw(); ~CByteOutBufWrap() { Free(); } void Free() throw(); bool Alloc(size_t size) throw(); void Init() { Cur = Buf; Lim = Buf + Size; Processed = 0; Res = S_OK; } UInt64 GetProcessed() const { return Processed + (Cur - Buf); } HRESULT Flush() throw(); void WriteByte(Byte b) { *Cur++ = b; if (Cur == Lim) Flush(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.cpp0100777000000000000000000000242713761647206025425 0ustar00// FilePathAutoRename.cpp #include "StdAfx.h" #include "../../Common/Defs.h" #include "../../Common/IntToString.h" #include "../../Windows/FileFind.h" #include "FilePathAutoRename.h" using namespace NWindows; static bool MakeAutoName(const FString &name, const FString &extension, unsigned value, FString &path) { FChar number[16]; ConvertUInt32ToString(value, number); path = name; path += number; path += extension; return NFile::NFind::DoesFileOrDirExist(path); } bool AutoRenamePath(FString &fullProcessedPath) { FString path; int dotPos = fullProcessedPath.ReverseFind(FTEXT('.')); int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); #ifdef _WIN32 int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); slashPos = MyMax(slashPos, slash1Pos); #endif FString name, extension; if (dotPos > slashPos && dotPos > 0) { name.SetFrom(fullProcessedPath, dotPos); extension = fullProcessedPath.Ptr(dotPos); } else name = fullProcessedPath; name += L'_'; unsigned left = 1, right = (1 << 30); while (left != right) { unsigned mid = (left + right) / 2; if (MakeAutoName(name, extension, mid, path)) left = mid + 1; else right = mid; } return !MakeAutoName(name, extension, right, fullProcessedPath); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.h0100777000000000000000000000027313761647206025067 0ustar00// FilePathAutoRename.h #ifndef __FILE_PATH_AUTO_RENAME_H #define __FILE_PATH_AUTO_RENAME_H #include "../../Common/MyString.h" bool AutoRenamePath(FString &fullProcessedPath); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.cpp0100777000000000000000000002351113761647206024163 0ustar00// FileStreams.cpp #include "StdAfx.h" #ifndef _WIN32 #include #include #include #endif #ifdef SUPPORT_DEVICE_FILE #include "../../../C/Alloc.h" #include "../../Common/Defs.h" #endif #include "FileStreams.h" static inline HRESULT ConvertBoolToHRESULT(bool result) { #ifdef _WIN32 if (result) return S_OK; DWORD lastError = ::GetLastError(); if (lastError == 0) return E_FAIL; return HRESULT_FROM_WIN32(lastError); #else return result ? S_OK: E_FAIL; #endif } #ifdef SUPPORT_DEVICE_FILE static const UInt32 kClusterSize = 1 << 18; CInFileStream::CInFileStream(): VirtPos(0), PhyPos(0), Buf(0), BufSize(0), SupportHardLinks(false) { } #endif CInFileStream::~CInFileStream() { #ifdef SUPPORT_DEVICE_FILE MidFree(Buf); #endif } STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef USE_WIN_FILE #ifdef SUPPORT_DEVICE_FILE if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (File.IsDeviceFile) { if (File.SizeDefined) { if (VirtPos >= File.Size) return VirtPos == File.Size ? S_OK : E_FAIL; UInt64 rem = File.Size - VirtPos; if (size > rem) size = (UInt32)rem; } for (;;) { const UInt32 mask = kClusterSize - 1; const UInt64 mask2 = ~(UInt64)mask; UInt64 alignedPos = VirtPos & mask2; if (BufSize > 0 && BufStartPos == alignedPos) { UInt32 pos = (UInt32)VirtPos & mask; if (pos >= BufSize) return S_OK; UInt32 rem = MyMin(BufSize - pos, size); memcpy(data, Buf + pos, rem); VirtPos += rem; if (processedSize) *processedSize += rem; return S_OK; } bool useBuf = false; if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 ) useBuf = true; else { UInt64 end = VirtPos + size; if ((end & mask) != 0) { end &= mask2; if (end <= VirtPos) useBuf = true; else size = (UInt32)(end - VirtPos); } } if (!useBuf) break; if (alignedPos != PhyPos) { UInt64 realNewPosition; bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition); if (!result) return ConvertBoolToHRESULT(result); PhyPos = realNewPosition; } BufStartPos = alignedPos; UInt32 readSize = kClusterSize; if (File.SizeDefined) readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize); if (!Buf) { Buf = (Byte *)MidAlloc(kClusterSize); if (!Buf) return E_OUTOFMEMORY; } bool result = File.Read1(Buf, readSize, BufSize); if (!result) return ConvertBoolToHRESULT(result); if (BufSize == 0) return S_OK; PhyPos += BufSize; } if (VirtPos != PhyPos) { UInt64 realNewPosition; bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition); if (!result) return ConvertBoolToHRESULT(result); PhyPos = VirtPos = realNewPosition; } } #endif UInt32 realProcessedSize; bool result = File.ReadPart(data, size, realProcessedSize); if (processedSize) *processedSize = realProcessedSize; #ifdef SUPPORT_DEVICE_FILE VirtPos += realProcessedSize; PhyPos += realProcessedSize; #endif return ConvertBoolToHRESULT(result); #else if (processedSize) *processedSize = 0; ssize_t res = File.Read(data, (size_t)size); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; #endif } #ifdef UNDER_CE STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { size_t s2 = fread(data, 1, size, stdin); int error = ferror(stdin); if (processedSize) *processedSize = s2; if (s2 <= size && error == 0) return S_OK; return E_FAIL; } #else STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef _WIN32 DWORD realProcessedSize; UInt32 sizeTemp = (1 << 20); if (sizeTemp > size) sizeTemp = size; BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); if (processedSize) *processedSize = realProcessedSize; if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) return S_OK; return ConvertBoolToHRESULT(res != FALSE); #else if (processedSize) *processedSize = 0; ssize_t res; do { res = read(0, data, (size_t)size); } while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; #endif } #endif STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE #ifdef SUPPORT_DEVICE_FILE if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END)) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += VirtPos; break; case STREAM_SEEK_END: offset += File.Size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; VirtPos = offset; if (newPosition) *newPosition = offset; return S_OK; } #endif UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); #ifdef SUPPORT_DEVICE_FILE PhyPos = VirtPos = realNewPosition; #endif if (newPosition) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); #else off_t res = File.Seek((off_t)offset, seekOrigin); if (res == -1) return E_FAIL; if (newPosition) *newPosition = (UInt64)res; return S_OK; #endif } STDMETHODIMP CInFileStream::GetSize(UInt64 *size) { return ConvertBoolToHRESULT(File.GetLength(*size)); } #if 0 // FIXME #ifdef USE_WIN_FILE STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) { BY_HANDLE_FILE_INFORMATION info; if (File.GetFileInformation(&info)) { if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; if (cTime) *cTime = info.ftCreationTime; if (aTime) *aTime = info.ftLastAccessTime; if (mTime) *mTime = info.ftLastWriteTime; if (attrib) *attrib = info.dwFileAttributes; return S_OK; } return GetLastError(); } STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) { BY_HANDLE_FILE_INFORMATION info; if (File.GetFileInformation(&info)) { props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; props->VolID = info.dwVolumeSerialNumber; props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; props->FileID_High = 0; props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; props->Attrib = info.dwFileAttributes; props->CTime = info.ftCreationTime; props->ATime = info.ftLastAccessTime; props->MTime = info.ftLastWriteTime; return S_OK; } return GetLastError(); } #endif ////////////////////////// // COutFileStream HRESULT COutFileStream::Close() { return ConvertBoolToHRESULT(File.Close()); } STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { #ifdef USE_WIN_FILE UInt32 realProcessedSize; bool result = File.WritePart(data, size, realProcessedSize); ProcessedSize += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return ConvertBoolToHRESULT(result); #else if (processedSize) *processedSize = 0; ssize_t res = File.Write(data, (size_t)size); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; ProcessedSize += res; return S_OK; #endif } STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); if (newPosition) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); #else off_t res = File.Seek((off_t)offset, seekOrigin); if (res == -1) return E_FAIL; if (newPosition) *newPosition = (UInt64)res; return S_OK; #endif } STDMETHODIMP COutFileStream::SetSize(UInt64 newSize) { #ifdef USE_WIN_FILE UInt64 currentPos; if (!File.Seek(0, FILE_CURRENT, currentPos)) return E_FAIL; bool result = File.SetLength(newSize); UInt64 currentPos2; result = result && File.Seek(currentPos, currentPos2); return result ? S_OK : E_FAIL; #else return E_FAIL; #endif } #ifdef UNDER_CE STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { size_t s2 = fwrite(data, 1, size, stdout); if (processedSize) *processedSize = s2; return (s2 == size) ? S_OK : E_FAIL; } #else STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; #ifdef _WIN32 UInt32 realProcessedSize; BOOL res = TRUE; if (size > 0) { // Seems that Windows doesn't like big amounts writing to stdout. // So we limit portions by 32KB. UInt32 sizeTemp = (1 << 15); if (sizeTemp > size) sizeTemp = size; res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), data, sizeTemp, (DWORD *)&realProcessedSize, NULL); size -= realProcessedSize; data = (const void *)((const Byte *)data + realProcessedSize); if (processedSize) *processedSize += realProcessedSize; } return ConvertBoolToHRESULT(res != FALSE); #else ssize_t res; do { res = write(1, data, (size_t)size); } while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; return S_OK; #endif } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.h0100777000000000000000000000615013761647206023630 0ustar00// FileStreams.h #ifndef __FILE_STREAMS_H #define __FILE_STREAMS_H #if defined(_WIN32) || defined(ENV_UNIX) #define USE_WIN_FILE #endif #include "../../Common/MyString.h" #ifdef USE_WIN_FILE #include "../../Windows/FileIO.h" #else #include "../../Common/C_FileIO.h" #endif #include "../../Common/MyCom.h" #include "../IStream.h" class CInFileStream: public IInStream, public IStreamGetSize, #if 0 // #ifdef USE_WIN_FILE public IStreamGetProps, public IStreamGetProps2, #endif public CMyUnknownImp { bool _ignoreSymbolicLink; public: #ifdef USE_WIN_FILE NWindows::NFile::NIO::CInFile File; #ifdef SUPPORT_DEVICE_FILE UInt64 VirtPos; UInt64 PhyPos; UInt64 BufStartPos; Byte *Buf; UInt32 BufSize; #endif #else NC::NFile::NIO::CInFile File; #endif bool SupportHardLinks; CInFileStream(bool b=false) { _ignoreSymbolicLink = b; } virtual ~CInFileStream(); bool Open(CFSTR fileName) { return File.Open(fileName,_ignoreSymbolicLink); } bool OpenShared(CFSTR fileName , bool /* shareForWrite */ ) { return File.Open(fileName,_ignoreSymbolicLink); } MY_QUERYINTERFACE_BEGIN2(IInStream) MY_QUERYINTERFACE_ENTRY(IStreamGetSize) #if 0 // #ifdef USE_WIN_FILE MY_QUERYINTERFACE_ENTRY(IStreamGetProps) MY_QUERYINTERFACE_ENTRY(IStreamGetProps2) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(GetSize)(UInt64 *size); #if 0 // #ifdef USE_WIN_FILE STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib); STDMETHOD(GetProps2)(CStreamFileProps *props); #endif }; class CStdInFileStream: public ISequentialInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP virtual ~CStdInFileStream() {} STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; class COutFileStream: public IOutStream, public CMyUnknownImp { public: #ifdef USE_WIN_FILE NWindows::NFile::NIO::COutFile File; #else NC::NFile::NIO::COutFile File; #endif virtual ~COutFileStream() {} bool Create(CFSTR fileName, bool createAlways) { ProcessedSize = 0; return File.Create(fileName, createAlways); } bool Open(CFSTR fileName, DWORD creationDisposition) { ProcessedSize = 0; return File.Open(fileName, creationDisposition); } HRESULT Close(); UInt64 ProcessedSize; #ifdef USE_WIN_FILE bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) { return File.SetTime(cTime, aTime, mTime); } bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); } #endif MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; class CStdOutFileStream: public ISequentialOutStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP virtual ~CStdOutFileStream() {} STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.cpp0100777000000000000000000001455513761647206024157 0ustar00// FilterCoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../../Common/Defs.h" #include "FilterCoder.h" #include "StreamUtils.h" static const UInt32 kBufferSize = 1 << 17; CFilterCoder::CFilterCoder() { _buffer = (Byte *)::MidAlloc(kBufferSize); if (_buffer == 0) throw 1; } CFilterCoder::~CFilterCoder() { ::MidFree(_buffer); } HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size) { if (_outSizeIsDefined) { UInt64 remSize = _outSize - _nowPos64; if (size > remSize) size = (UInt32)remSize; } RINOK(WriteStream(outStream, _buffer, size)); _nowPos64 += size; return S_OK; } STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { RINOK(Init()); UInt32 bufferPos = 0; _outSizeIsDefined = (outSize != 0); if (_outSizeIsDefined) _outSize = *outSize; while (!_outSizeIsDefined || _nowPos64 < _outSize) { size_t processedSize = kBufferSize - bufferPos; // Change it: It can be optimized using ReadPart RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize)); UInt32 endPos = bufferPos + (UInt32)processedSize; bufferPos = Filter->Filter(_buffer, endPos); if (bufferPos > endPos) { for (; endPos < bufferPos; endPos++) _buffer[endPos] = 0; bufferPos = Filter->Filter(_buffer, endPos); } if (bufferPos == 0) { if (endPos == 0) return S_OK; return WriteWithLimit(outStream, endPos); } RINOK(WriteWithLimit(outStream, bufferPos)); if (progress != NULL) { RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64)); } UInt32 i = 0; while (bufferPos < endPos) _buffer[i++] = _buffer[bufferPos++]; bufferPos = i; } return S_OK; } STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) { _bufferPos = 0; _outStream = outStream; return Init(); } STDMETHODIMP CFilterCoder::ReleaseOutStream() { _outStream.Release(); return S_OK; } STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos); memcpy(_buffer + _bufferPos, data, sizeTemp); size -= sizeTemp; if (processedSize != NULL) *processedSize += sizeTemp; data = (const Byte *)data + sizeTemp; UInt32 endPos = _bufferPos + sizeTemp; _bufferPos = Filter->Filter(_buffer, endPos); if (_bufferPos == 0) { _bufferPos = endPos; break; } if (_bufferPos > endPos) { if (size != 0) return E_FAIL; break; } RINOK(WriteWithLimit(_outStream, _bufferPos)); UInt32 i = 0; while (_bufferPos < endPos) _buffer[i++] = _buffer[_bufferPos++]; _bufferPos = i; } return S_OK; } STDMETHODIMP CFilterCoder::Flush() { if (_bufferPos != 0) { // _buffer contains only data refused by previous Filter->Filter call. UInt32 endPos = Filter->Filter(_buffer, _bufferPos); if (endPos > _bufferPos) { for (; _bufferPos < endPos; _bufferPos++) _buffer[_bufferPos] = 0; if (Filter->Filter(_buffer, endPos) != endPos) return E_FAIL; } RINOK(WriteWithLimit(_outStream, _bufferPos)); _bufferPos = 0; } CMyComPtr flush; _outStream.QueryInterface(IID_IOutStreamFlush, &flush); if (flush) return flush->Flush(); return S_OK; } void CFilterCoder::SetInStream_NoSubFilterInit(ISequentialInStream *inStream) { _convertedPosBegin = _convertedPosEnd = _bufferPos = 0; _inStream = inStream; Init2(); } STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) { SetInStream_NoSubFilterInit(inStream); return Init(); } STDMETHODIMP CFilterCoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_convertedPosBegin != _convertedPosEnd) { UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin); memcpy(data, _buffer + _convertedPosBegin, sizeTemp); _convertedPosBegin += sizeTemp; data = (void *)((Byte *)data + sizeTemp); size -= sizeTemp; if (processedSize != NULL) *processedSize += sizeTemp; break; } UInt32 i; for (i = 0; _convertedPosEnd + i < _bufferPos; i++) _buffer[i] = _buffer[_convertedPosEnd + i]; _bufferPos = i; _convertedPosBegin = _convertedPosEnd = 0; size_t processedSizeTemp = kBufferSize - _bufferPos; RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp)); _bufferPos += (UInt32)processedSizeTemp; _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); if (_convertedPosEnd == 0) { if (_bufferPos == 0) break; _convertedPosEnd = _bufferPos; // check it continue; } if (_convertedPosEnd > _bufferPos) { for (; _bufferPos < _convertedPosEnd; _bufferPos++) _buffer[_bufferPos] = 0; _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); } } return S_OK; } #ifndef _NO_CRYPTO STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) { return _setPassword->CryptoSetPassword(data, size); } STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size) { return _cryptoProperties->SetKey(data, size); } STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size) { return _cryptoProperties->SetInitVector(data, size); } #endif #ifndef EXTRACT_ONLY STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *properties, UInt32 numProperties) { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); } STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream) { return _writeCoderProperties->WriteCoderProperties(outStream); } /* STDMETHODIMP CFilterCoder::ResetSalt() { return _CryptoResetSalt->ResetSalt(); } */ STDMETHODIMP CFilterCoder::ResetInitVector() { return _CryptoResetInitVector->ResetInitVector(); } #endif STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) { return _setDecoderProperties->SetDecoderProperties2(data, size); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.h0100777000000000000000000001042213761647206023611 0ustar00// FilterCoder.h #ifndef __FILTER_CODER_H #define __FILTER_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../IPassword.h" #define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \ { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ *outObject = (void *)(i *)this; } class CFilterCoder: public ICompressCoder, public ICompressSetInStream, public ISequentialInStream, public ICompressSetOutStream, public ISequentialOutStream, public IOutStreamFlush, #ifndef _NO_CRYPTO public ICryptoSetPassword, public ICryptoProperties, #endif #ifndef EXTRACT_ONLY public ICompressSetCoderProperties, public ICompressWriteCoderProperties, // public ICryptoResetSalt, public ICryptoResetInitVector, #endif public ICompressSetDecoderProperties2, public CMyUnknownImp { protected: Byte *_buffer; CMyComPtr _inStream; CMyComPtr _outStream; UInt32 _bufferPos; UInt32 _convertedPosBegin; UInt32 _convertedPosEnd; bool _outSizeIsDefined; UInt64 _outSize; UInt64 _nowPos64; void Init2() { _nowPos64 = 0; _outSizeIsDefined = false; } HRESULT Init() { Init2(); return Filter->Init(); } CMyComPtr _setPassword; CMyComPtr _cryptoProperties; #ifndef EXTRACT_ONLY CMyComPtr _SetCoderProperties; CMyComPtr _writeCoderProperties; // CMyComPtr _CryptoResetSalt; CMyComPtr _CryptoResetInitVector; #endif CMyComPtr _setDecoderProperties; public: CMyComPtr Filter; CFilterCoder(); ~CFilterCoder(); HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size); public: MY_QUERYINTERFACE_BEGIN2(ICompressCoder) MY_QUERYINTERFACE_ENTRY(ICompressSetInStream) MY_QUERYINTERFACE_ENTRY(ISequentialInStream) MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream) MY_QUERYINTERFACE_ENTRY(ISequentialOutStream) MY_QUERYINTERFACE_ENTRY(IOutStreamFlush) #ifndef _NO_CRYPTO MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword) MY_QUERYINTERFACE_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties) #endif #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties) MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties) // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt) MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector) #endif MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties) MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(ReleaseInStream)(); STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream); STDMETHOD(ReleaseOutStream)(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Flush)(); #ifndef _NO_CRYPTO STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); STDMETHOD(SetKey)(const Byte *data, UInt32 size); STDMETHOD(SetInitVector)(const Byte *data, UInt32 size); #endif #ifndef EXTRACT_ONLY STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *properties, UInt32 numProperties); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); // STDMETHOD(ResetSalt)(); STDMETHOD(ResetInitVector)(); #endif STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); void SetInStream_NoSubFilterInit(ISequentialInStream *inStream); }; class CInStreamReleaser { public: CFilterCoder *FilterCoder; CInStreamReleaser(): FilterCoder(0) {} ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); } }; class COutStreamReleaser { public: CFilterCoder *FilterCoder; COutStreamReleaser(): FilterCoder(0) {} ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.cpp0100777000000000000000000000461113761647206023445 0ustar00// InBuffer.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "InBuffer.h" CInBufferBase::CInBufferBase() throw(): _buf(0), _bufLim(0), _bufBase(0), _stream(0), _processedSize(0), _bufSize(0), _wasFinished(false), NumExtraBytes(0) {} bool CInBuffer::Create(size_t bufSize) throw() { const unsigned kMinBlockSize = 1; if (bufSize < kMinBlockSize) bufSize = kMinBlockSize; if (_bufBase != 0 && _bufSize == bufSize) return true; Free(); _bufSize = bufSize; _bufBase = (Byte *)::MidAlloc(bufSize); return (_bufBase != 0); } void CInBuffer::Free() throw() { ::MidFree(_bufBase); _bufBase = 0; } void CInBufferBase::Init() throw() { _processedSize = 0; _buf = _bufBase; _bufLim = _buf; _wasFinished = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif NumExtraBytes = 0; } bool CInBufferBase::ReadBlock() { #ifdef _NO_EXCEPTIONS if (ErrorCode != S_OK) return false; #endif if (_wasFinished) return false; _processedSize += (_buf - _bufBase); _buf = _bufBase; _bufLim = _bufBase; UInt32 processed; // FIX_ME: we can improve it to support (_bufSize >= (1 << 32)) HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed); #ifdef _NO_EXCEPTIONS ErrorCode = result; #else if (result != S_OK) throw CInBufferException(result); #endif _bufLim = _buf + processed; _wasFinished = (processed == 0); return !_wasFinished; } bool CInBufferBase::ReadByte_FromNewBlock(Byte &b) { if (!ReadBlock()) { NumExtraBytes++; b = 0xFF; return false; } b = *_buf++; return true; } Byte CInBufferBase::ReadByte_FromNewBlock() { if (!ReadBlock()) { NumExtraBytes++; return 0xFF; } return *_buf++; } size_t CInBufferBase::ReadBytes(Byte *buf, size_t size) { if ((size_t)(_bufLim - _buf) >= size) { const Byte *src = _buf; for (size_t i = 0; i < size; i++) buf[i] = src[i]; _buf += size; return size; } for (size_t i = 0; i < size; i++) { if (_buf >= _bufLim) if (!ReadBlock()) return i; buf[i] = *_buf++; } return size; } size_t CInBufferBase::Skip(size_t size) { size_t processed = 0; for (;;) { size_t rem = (_bufLim - _buf); if (rem >= size) { _buf += size; return processed + size; } _buf += rem; processed += rem; size -= rem; if (!ReadBlock()) return processed; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.h0100777000000000000000000000362313761647206023114 0ustar00// InBuffer.h #ifndef __IN_BUFFER_H #define __IN_BUFFER_H #include "../../Common/MyException.h" #include "../IStream.h" #ifndef _NO_EXCEPTIONS struct CInBufferException: public CSystemException { CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} }; #endif class CInBufferBase { protected: Byte *_buf; Byte *_bufLim; Byte *_bufBase; ISequentialInStream *_stream; UInt64 _processedSize; size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger // only up to 32-bits values now are supported! bool _wasFinished; bool ReadBlock(); bool ReadByte_FromNewBlock(Byte &b); Byte ReadByte_FromNewBlock(); public: #ifdef _NO_EXCEPTIONS HRESULT ErrorCode; #endif UInt32 NumExtraBytes; CInBufferBase() throw(); UInt64 GetStreamSize() const { return _processedSize + (_buf - _bufBase); } UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (_buf - _bufBase); } bool WasFinished() const { return _wasFinished; } void SetStream(ISequentialInStream *stream) { _stream = stream; } void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos) { _bufBase = buf; _bufSize = bufSize; _processedSize = 0; _buf = buf + pos; _bufLim = buf + end; _wasFinished = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif NumExtraBytes = 0; } void Init() throw(); bool ReadByte(Byte &b) { if (_buf >= _bufLim) return ReadByte_FromNewBlock(b); b = *_buf++; return true; } Byte ReadByte() { if (_buf >= _bufLim) return ReadByte_FromNewBlock(); return *_buf++; } size_t ReadBytes(Byte *buf, size_t size); size_t Skip(size_t size); }; class CInBuffer: public CInBufferBase { public: ~CInBuffer() { Free(); } bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported! void Free() throw(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.cpp0100777000000000000000000000473313761647206024770 0ustar00// InOutTempBuffer.cpp #include "StdAfx.h" #include "../../../C/7zCrc.h" #include "../../Common/Defs.h" #include "InOutTempBuffer.h" #include "StreamUtils.h" using namespace NWindows; using namespace NFile; using namespace NDir; static const UInt32 kTempBufSize = (1 << 20); static CFSTR kTempFilePrefixString = FTEXT("7zt"); CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { } void CInOutTempBuffer::Create() { if (!_buf) _buf = new Byte[kTempBufSize]; } CInOutTempBuffer::~CInOutTempBuffer() { delete []_buf; } void CInOutTempBuffer::InitWriting() { _bufPos = 0; _tempFileCreated = false; _size = 0; _crc = CRC_INIT_VAL; } bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size) { if (size == 0) return true; if (!_tempFileCreated) { if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile)) return false; _tempFileCreated = true; } UInt32 processed; if (!_outFile.Write(data, size, processed)) return false; _crc = CrcUpdate(_crc, data, processed); _size += processed; return (processed == size); } bool CInOutTempBuffer::Write(const void *data, UInt32 size) { if (_bufPos < kTempBufSize) { UInt32 cur = MyMin(kTempBufSize - _bufPos, size); memcpy(_buf + _bufPos, data, cur); _crc = CrcUpdate(_crc, data, cur); _bufPos += cur; size -= cur; data = ((const Byte *)data) + cur; _size += cur; } return WriteToFile(data, size); } HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream) { if (!_outFile.Close()) return E_FAIL; UInt64 size = 0; UInt32 crc = CRC_INIT_VAL; if (_bufPos > 0) { RINOK(WriteStream(stream, _buf, _bufPos)); crc = CrcUpdate(crc, _buf, _bufPos); size += _bufPos; } if (_tempFileCreated) { NIO::CInFile inFile; if (!inFile.Open(_tempFile.GetPath())) return E_FAIL; while (size < _size) { UInt32 processed; if (!inFile.ReadPart(_buf, kTempBufSize, processed)) return E_FAIL; if (processed == 0) break; RINOK(WriteStream(stream, _buf, processed)); crc = CrcUpdate(crc, _buf, processed); size += processed; } } return (_crc == crc && size == _size) ? S_OK : E_FAIL; } STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed) { if (!_buf->Write(data, size)) { if (processed != NULL) *processed = 0; return E_FAIL; } if (processed != NULL) *processed = size; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.h0100777000000000000000000000170313761647206024427 0ustar00// InOutTempBuffer.h #ifndef __IN_OUT_TEMP_BUFFER_H #define __IN_OUT_TEMP_BUFFER_H #include "../../Common/MyCom.h" #include "../../Windows/FileDir.h" #include "../IStream.h" class CInOutTempBuffer { NWindows::NFile::NDir::CTempFile _tempFile; NWindows::NFile::NIO::COutFile _outFile; Byte *_buf; UInt32 _bufPos; bool _tempFileCreated; UInt64 _size; UInt32 _crc; bool WriteToFile(const void *data, UInt32 size); public: CInOutTempBuffer(); ~CInOutTempBuffer(); void Create(); void InitWriting(); bool Write(const void *data, UInt32 size); HRESULT WriteToStream(ISequentialOutStream *stream); UInt64 GetDataSize() const { return _size; } }; class CSequentialOutTempBufferImp: public ISequentialOutStream, public CMyUnknownImp { CInOutTempBuffer *_buf; public: void Init(CInOutTempBuffer *buffer) { _buf = buffer; } MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.cpp0100777000000000000000000002146713761647206024703 0ustar00// LimitedStreams.cpp #include "StdAfx.h" #include "LimitedStreams.h" #include "../../Common/Defs.h" STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = 0; UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size); HRESULT result = S_OK; if (sizeToRead > 0) { result = _stream->Read(data, sizeToRead, &realProcessedSize); _pos += realProcessedSize; if (realProcessedSize == 0) _wasFinished = true; } if (processedSize) *processedSize = realProcessedSize; return result; } STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= _size) { // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. return S_OK; // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF } UInt64 rem = _size - _virtPos; if (rem < size) size = (UInt32)rem; UInt64 newPos = _startOffset + _virtPos; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } HRESULT res = _stream->Read(data, size, &size); if (processedSize) *processedSize = size; _physPos += size; _virtPos += size; return res; } STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) { *resStream = 0; CLimitedInStream *streamSpec = new CLimitedInStream; CMyComPtr streamTemp = streamSpec; streamSpec->SetStream(inStream); RINOK(streamSpec->InitAndSeek(pos, size)); streamSpec->SeekToStart(); *resStream = streamTemp.Detach(); return S_OK; } STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= Size) return S_OK; if (_curRem == 0) { UInt32 blockSize = (UInt32)1 << BlockSizeLog; UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); UInt32 phyBlock = Vector[virtBlock]; UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } _curRem = blockSize - offsetInBlock; for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) _curRem += (UInt32)1 << BlockSizeLog; UInt64 rem = Size - _virtPos; if (_curRem > rem) _curRem = (UInt32)rem; } if (size > _curRem) size = _curRem; HRESULT res = Stream->Read(data, size, &size); if (processedSize) *processedSize = size; _physPos += size; _virtPos += size; _curRem -= size; return res; } STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += Size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; if (_virtPos != (UInt64)offset) _curRem = 0; _virtPos = offset; if (newPosition) *newPosition = offset; return S_OK; } STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= Extents.Back().Virt) return S_OK; if (size == 0) return S_OK; unsigned left = 0, right = Extents.Size() - 1; for (;;) { unsigned mid = (left + right) / 2; if (mid == left) break; if (_virtPos < Extents[mid].Virt) right = mid; else left = mid; } const CSeekExtent &extent = Extents[left]; UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); if (_needStartSeek || _phyPos != phyPos) { _needStartSeek = false; _phyPos = phyPos; RINOK(SeekToPhys()); } UInt64 rem = Extents[left + 1].Virt - _virtPos; if (size > rem) size = (UInt32)rem; HRESULT res = Stream->Read(data, size, &size); _phyPos += size; _virtPos += size; if (processedSize) *processedSize = size; return res; } STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += Extents.Back().Virt; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (processedSize) *processedSize = 0; if (size > _size) { if (_size == 0) { _overflow = true; if (!_overflowIsAllowed) return E_FAIL; if (processedSize) *processedSize = size; return S_OK; } size = (UInt32)_size; } if (_stream) result = _stream->Write(data, size, &size); _size -= size; if (processedSize) *processedSize = size; return result; } STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 cur; HRESULT res = Stream->Read(data, size, &cur); if (processedSize) *processedSize = cur; _virtPos += cur; return res; } STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: { UInt64 pos = 0; RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)); if (pos < Offset) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = pos - Offset; if (newPosition) *newPosition = _virtPos; return S_OK; } default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); } STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= _size) { // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. return S_OK; // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF } UInt64 rem = _size - _virtPos; if (rem < size) size = (UInt32)rem; UInt64 newPos = _startOffset + _virtPos; UInt64 offsetInCache = newPos - _cachePhyPos; HRESULT res = S_OK; if (newPos >= _cachePhyPos && offsetInCache <= _cacheSize && size <= _cacheSize - (size_t)offsetInCache) memcpy(data, _cache + (size_t)offsetInCache, size); else { if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } res = _stream->Read(data, size, &size); _physPos += size; } if (processedSize) *processedSize = size; _virtPos += size; return res; } STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 cur; HRESULT res = Stream->Write(data, size, &cur); if (processedSize) *processedSize = cur; _virtPos += cur; if (_virtSize < _virtPos) _virtSize = _virtPos; return res; } STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _virtSize; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); } STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize) { _virtSize = newSize; return Stream->SetSize(Offset + newSize); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.h0100777000000000000000000001327013761647206024341 0ustar00// LimitedStreams.h #ifndef __LIMITED_STREAMS_H #define __LIMITED_STREAMS_H #include "../../Common/MyBuffer.h" #include "../../Common/MyCom.h" #include "../../Common/MyVector.h" #include "../IStream.h" class CLimitedSequentialInStream: public ISequentialInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; UInt64 _pos; bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(UInt64 streamSize) { _size = streamSize; _pos = 0; _wasFinished = false; } MY_UNKNOWN_IMP1(ISequentialInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); UInt64 GetSize() const { return _pos; } bool WasFinished() const { return _wasFinished; } }; class CLimitedInStream: public IInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _virtPos; UInt64 _physPos; UInt64 _size; UInt64 _startOffset; HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } public: void SetStream(IInStream *stream) { _stream = stream; } HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) { _startOffset = startOffset; _physPos = startOffset; _virtPos = 0; _size = size; return SeekToPhys(); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } }; HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream); class CClusterInStream: public IInStream, public CMyUnknownImp { UInt64 _virtPos; UInt64 _physPos; UInt32 _curRem; public: CMyComPtr Stream; UInt64 StartOffset; UInt64 Size; unsigned BlockSizeLog; CRecordVector Vector; HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } HRESULT InitAndSeek() { _curRem = 0; _virtPos = 0; _physPos = StartOffset; if (Vector.Size() > 0) { _physPos = StartOffset + (Vector[0] << BlockSizeLog); return SeekToPhys(); } return S_OK; } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; struct CSeekExtent { UInt64 Phy; UInt64 Virt; }; class CExtentsStream: public IInStream, public CMyUnknownImp { UInt64 _phyPos; UInt64 _virtPos; bool _needStartSeek; HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); } public: CMyComPtr Stream; CRecordVector Extents; MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); void ReleaseStream() { Stream.Release(); } void Init() { _virtPos = 0; _phyPos = 0; _needStartSeek = true; } }; class CLimitedSequentialOutStream: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; bool _overflow; bool _overflowIsAllowed; public: MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(UInt64 size, bool overflowIsAllowed = false) { _size = size; _overflow = false; _overflowIsAllowed = overflowIsAllowed; } bool IsFinishedOK() const { return (_size == 0 && !_overflow); } UInt64 GetRem() const { return _size; } }; class CTailInStream: public IInStream, public CMyUnknownImp { UInt64 _virtPos; public: CMyComPtr Stream; UInt64 Offset; void Init() { _virtPos = 0; } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Stream->Seek(Offset, STREAM_SEEK_SET, NULL); } }; class CLimitedCachedInStream: public IInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _virtPos; UInt64 _physPos; UInt64 _size; UInt64 _startOffset; const Byte *_cache; size_t _cacheSize; size_t _cachePhyPos; HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } public: CByteBuffer Buffer; void SetStream(IInStream *stream) { _stream = stream; } void SetCache(size_t cacheSize, size_t cachePos) { _cache = Buffer; _cacheSize = cacheSize; _cachePhyPos = cachePos; } HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) { _startOffset = startOffset; _physPos = startOffset; _virtPos = 0; _size = size; return SeekToPhys(); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } }; class CTailOutStream: public IOutStream, public CMyUnknownImp { UInt64 _virtPos; UInt64 _virtSize; public: CMyComPtr Stream; UInt64 Offset; virtual ~CTailOutStream() {} MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStream) void Init() { _virtPos = 0; _virtSize = 0; } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.cpp0100777000000000000000000000125113761647206024317 0ustar00// LockedStream.cpp #include "StdAfx.h" #include "LockedStream.h" HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize) { NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL)); return _stream->Read(data, size, processedSize); } STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = 0; HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize); _pos += realProcessedSize; if (processedSize != NULL) *processedSize = realProcessedSize; return result; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.h0100777000000000000000000000146113761647206023767 0ustar00// LockedStream.h #ifndef __LOCKEDSTREAM_H #define __LOCKEDSTREAM_H #include "../../Windows/Synchronization.h" #include "../../Common/MyCom.h" #include "../IStream.h" class CLockedInStream { CMyComPtr _stream; NWindows::NSynchronization::CCriticalSection _criticalSection; public: void Init(IInStream *stream) { _stream = stream; } HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize); }; class CLockedSequentialInStreamImp: public ISequentialInStream, public CMyUnknownImp { CLockedInStream *_lockedInStream; UInt64 _pos; public: void Init(CLockedInStream *lockedInStream, UInt64 startPos) { _lockedInStream = lockedInStream; _pos = startPos; } MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/MethodId.h0100777000000000000000000000020713761647206023104 0ustar00// MethodId.h #ifndef __7Z_METHOD_ID_H #define __7Z_METHOD_ID_H #include "../../Common/MyTypes.h" typedef UInt64 CMethodId; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.cpp0100777000000000000000000002277613761647206024225 0ustar00// MethodProps.cpp #include "StdAfx.h" #include "../../Common/StringToInt.h" #include "MethodProps.h" using namespace NWindows; bool StringToBool(const UString &s, bool &res) { if (s.IsEmpty() || s == L"+" || StringsAreEqualNoCase_Ascii(s, "ON")) { res = true; return true; } if (s == L"-" || StringsAreEqualNoCase_Ascii(s, "OFF")) { res = false; return true; } return false; } HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest) { switch (prop.vt) { case VT_EMPTY: dest = true; return S_OK; case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK; case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG; } return E_INVALIDARG; } unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number) { const wchar_t *start = srcString; const wchar_t *end; number = ConvertStringToUInt32(start, &end); return (unsigned)(end - start); } HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) { // =VT_UI4 // =VT_EMPTY // {stringUInt32}=VT_EMPTY if (prop.vt == VT_UI4) { if (!name.IsEmpty()) return E_INVALIDARG; resValue = prop.ulVal; return S_OK; } if (prop.vt != VT_EMPTY) return E_INVALIDARG; if (name.IsEmpty()) return S_OK; UInt32 v; if (ParseStringToUInt32(name, v) != name.Len()) return E_INVALIDARG; resValue = v; return S_OK; } HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) { if (name.IsEmpty()) { switch (prop.vt) { case VT_UI4: numThreads = prop.ulVal; break; default: { bool val; RINOK(PROPVARIANT_to_bool(prop, val)); numThreads = (val ? defaultNumThreads : 1); break; } } return S_OK; } if (prop.vt != VT_EMPTY) return E_INVALIDARG; return ParsePropToUInt32(name, prop, numThreads); } static HRESULT StringToDictSize(const UString &s, UInt32 &dicSize) { const wchar_t *end; UInt32 number = ConvertStringToUInt32(s, &end); unsigned numDigits = (unsigned)(end - s); if (numDigits == 0 || s.Len() > numDigits + 1) return E_INVALIDARG; const unsigned kLogDictSizeLimit = 32; if (s.Len() == numDigits) { if (number >= kLogDictSizeLimit) return E_INVALIDARG; dicSize = (UInt32)1 << (unsigned)number; return S_OK; } unsigned numBits; switch (MyCharLower_Ascii(s[numDigits])) { case 'b': dicSize = number; return S_OK; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; default: return E_INVALIDARG; } if (number >= ((UInt32)1 << (kLogDictSizeLimit - numBits))) return E_INVALIDARG; dicSize = number << numBits; return S_OK; } static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue) { if (prop.vt == VT_UI4) { UInt32 v = prop.ulVal; if (v >= 32) return E_INVALIDARG; resValue = (UInt32)1 << v; return S_OK; } if (prop.vt == VT_BSTR) return StringToDictSize(prop.bstrVal, resValue); return E_INVALIDARG; } void CProps::AddProp32(PROPID propid, UInt32 level) { CProp prop; prop.IsOptional = true; prop.Id = propid; prop.Value = (UInt32)level; Props.Add(prop); } class CCoderProps { PROPID *_propIDs; NCOM::CPropVariant *_props; unsigned _numProps; unsigned _numPropsMax; public: CCoderProps(unsigned numPropsMax) { _numPropsMax = numPropsMax; _numProps = 0; _propIDs = new PROPID[numPropsMax]; _props = new NCOM::CPropVariant[numPropsMax]; } ~CCoderProps() { delete []_propIDs; delete []_props; } void AddProp(const CProp &prop); HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) { return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); } }; void CCoderProps::AddProp(const CProp &prop) { if (_numProps >= _numPropsMax) throw 1; _propIDs[_numProps] = prop.Id; _props[_numProps] = prop.Value; _numProps++; } HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const { CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0)); FOR_VECTOR (i, Props) coderProps.AddProp(Props[i]); if (dataSizeReduce) { CProp prop; prop.Id = NCoderPropID::kReduceSize; prop.Value = *dataSizeReduce; coderProps.AddProp(prop); } return coderProps.SetProps(scp); } int CMethodProps::FindProp(PROPID id) const { for (int i = Props.Size() - 1; i >= 0; i--) if (Props[i].Id == id) return i; return -1; } int CMethodProps::GetLevel() const { int i = FindProp(NCoderPropID::kLevel); if (i < 0) return 5; if (Props[i].Value.vt != VT_UI4) return 9; UInt32 level = Props[i].Value.ulVal; return level > 9 ? 9 : (int)level; } struct CNameToPropID { VARTYPE VarType; const char *Name; }; static const CNameToPropID g_NameToPropID[] = { { VT_UI4, "" }, { VT_UI4, "d" }, { VT_UI4, "mem" }, { VT_UI4, "o" }, { VT_UI4, "c" }, { VT_UI4, "pb" }, { VT_UI4, "lc" }, { VT_UI4, "lp" }, { VT_UI4, "fb" }, { VT_BSTR, "mf" }, { VT_UI4, "mc" }, { VT_UI4, "pass" }, { VT_UI4, "a" }, { VT_UI4, "mt" }, { VT_BOOL, "eos" }, { VT_UI4, "x" }, { VT_UI4, "reduceSize" } }; static int FindPropIdExact(const UString &name) { for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++) if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) return i; return -1; } static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) { if (varType == srcProp.vt) { destProp = srcProp; return true; } if (varType == VT_BOOL) { bool res; if (PROPVARIANT_to_bool(srcProp, res) != S_OK) return false; destProp = res; return true; } if (srcProp.vt == VT_EMPTY) { destProp = srcProp; return true; } return false; } static void SplitParams(const UString &srcString, UStringVector &subStrings) { subStrings.Clear(); UString s; int len = srcString.Len(); if (len == 0) return; for (int i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L':') { subStrings.Add(s); s.Empty(); } else s += c; } subStrings.Add(s); } static void SplitParam(const UString ¶m, UString &name, UString &value) { int eqPos = param.Find(L'='); if (eqPos >= 0) { name.SetFrom(param, eqPos); value = param.Ptr(eqPos + 1); return; } unsigned i; for (i = 0; i < param.Len(); i++) { wchar_t c = param[i]; if (c >= L'0' && c <= L'9') break; } name.SetFrom(param, i); value = param.Ptr(i); } static bool IsLogSizeProp(PROPID propid) { switch (propid) { case NCoderPropID::kDictionarySize: case NCoderPropID::kUsedMemorySize: case NCoderPropID::kBlockSize: case NCoderPropID::kReduceSize: return true; } return false; } HRESULT CMethodProps::SetParam(const UString &name, const UString &value) { int index = FindPropIdExact(name); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; CProp prop; prop.Id = index; if (IsLogSizeProp(prop.Id)) { UInt32 dicSize; RINOK(StringToDictSize(value, dicSize)); prop.Value = dicSize; } else { NCOM::CPropVariant propValue; if (nameToPropID.VarType == VT_BSTR) propValue = value; else if (nameToPropID.VarType == VT_BOOL) { bool res; if (!StringToBool(value, res)) return E_INVALIDARG; propValue = res; } else if (!value.IsEmpty()) { UInt32 number; if (ParseStringToUInt32(value, number) == value.Len()) propValue = number; else propValue = value; } if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) return E_INVALIDARG; } Props.Add(prop); return S_OK; } HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) { UStringVector params; SplitParams(srcString, params); FOR_VECTOR (i, params) { const UString ¶m = params[i]; UString name, value; SplitParam(param, name, value); RINOK(SetParam(name, value)); } return S_OK; } HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) { if (realName.Len() == 0) { // [empty]=method return E_INVALIDARG; } if (value.vt == VT_EMPTY) { // {realName}=[empty] UString name, value; SplitParam(realName, name, value); return SetParam(name, value); } // {realName}=value int index = FindPropIdExact(realName); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; CProp prop; prop.Id = index; if (IsLogSizeProp(prop.Id)) { UInt32 dicSize; RINOK(PROPVARIANT_to_DictSize(value, dicSize)); prop.Value = dicSize; } else { if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) return E_INVALIDARG; } Props.Add(prop); return S_OK; } HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) { int splitPos = s.Find(':'); MethodName = s; if (splitPos < 0) return S_OK; MethodName.DeleteFrom(splitPos); return ParseParamsFromString(s.Ptr(splitPos + 1)); } HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) { if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) return ParseParamsFromPROPVARIANT(realName, value); // -m{N}=method if (value.vt != VT_BSTR) return E_INVALIDARG; return ParseMethodFromString(value.bstrVal); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.h0100777000000000000000000001063313761647206023657 0ustar00// MethodProps.h #ifndef __7Z_METHOD_PROPS_H #define __7Z_METHOD_PROPS_H #include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" #include "../ICoder.h" bool StringToBool(const UString &s, bool &res); HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest); unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number); HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads); struct CProp { PROPID Id; bool IsOptional; NWindows::NCOM::CPropVariant Value; CProp(): IsOptional(false) {} }; struct CProps { CObjectVector Props; void Clear() { Props.Clear(); } bool AreThereNonOptionalProps() const { FOR_VECTOR (i, Props) if (!Props[i].IsOptional) return true; return false; } void AddProp32(PROPID propid, UInt32 level); void AddPropString(PROPID propid, const wchar_t *s) { CProp prop; prop.IsOptional = true; prop.Id = propid; prop.Value = s; Props.Add(prop); } HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const; }; class CMethodProps: public CProps { HRESULT SetParam(const UString &name, const UString &value); public: int GetLevel() const; int Get_NumThreads() const { int i = FindProp(NCoderPropID::kNumThreads); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return (int)Props[i].Value.ulVal; return -1; } bool Get_DicSize(UInt32 &res) const { res = 0; int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) { res = Props[i].Value.ulVal; return true; } return false; } int FindProp(PROPID id) const; UInt32 Get_Lzma_Algo() const { int i = FindProp(NCoderPropID::kAlgorithm); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; return GetLevel() >= 5 ? 1 : 0; } UInt32 Get_Lzma_DicSize() const { int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; int level = GetLevel(); return level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)); } UInt32 Get_Lzma_NumThreads(bool &fixedNumber) const { fixedNumber = false; int numThreads = Get_NumThreads(); if (numThreads >= 0) { fixedNumber = true; return numThreads < 2 ? 1 : 2; } return Get_Lzma_Algo() == 0 ? 1 : 2; } UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const { fixedNumber = false; int numThreads = Get_NumThreads(); if (numThreads >= 0) { fixedNumber = true; if (numThreads < 1) return 1; if (numThreads > 64) return 64; return numThreads; } return 1; } UInt32 Get_BZip2_BlockSize() const { int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) { UInt32 blockSize = Props[i].Value.ulVal; const UInt32 kDicSizeMin = 100000; const UInt32 kDicSizeMax = 900000; if (blockSize < kDicSizeMin) blockSize = kDicSizeMin; if (blockSize > kDicSizeMax) blockSize = kDicSizeMax; return blockSize; } int level = GetLevel(); return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1)); } UInt32 Get_Ppmd_MemSize() const { int i = FindProp(NCoderPropID::kUsedMemorySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; int level = GetLevel(); return level >= 9 ? (192 << 20) : ((UInt32)1 << (level + 19)); } void AddLevelProp(UInt32 level) { AddProp32(NCoderPropID::kLevel, level); } void AddNumThreadsProp(UInt32 numThreads) { AddProp32(NCoderPropID::kNumThreads, numThreads); } HRESULT ParseParamsFromString(const UString &srcString); HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); }; class COneMethodInfo: public CMethodProps { public: UString MethodName; void Clear() { CMethodProps::Clear(); MethodName.Empty(); } bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); } HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); HRESULT ParseMethodFromString(const UString &s); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.cpp0100777000000000000000000000401113761647206023640 0ustar00// OutBuffer.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "OutBuffer.h" bool COutBuffer::Create(UInt32 bufSize) throw() { const UInt32 kMinBlockSize = 1; if (bufSize < kMinBlockSize) bufSize = kMinBlockSize; if (_buf != 0 && _bufSize == bufSize) return true; Free(); _bufSize = bufSize; _buf = (Byte *)::MidAlloc(bufSize); return (_buf != 0); } void COutBuffer::Free() throw() { ::MidFree(_buf); _buf = 0; } void COutBuffer::Init() throw() { _streamPos = 0; _limitPos = _bufSize; _pos = 0; _processedSize = 0; _overDict = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif } UInt64 COutBuffer::GetProcessedSize() const throw() { UInt64 res = _processedSize + _pos - _streamPos; if (_streamPos > _pos) res += _bufSize; return res; } HRESULT COutBuffer::FlushPart() throw() { // _streamPos < _bufSize UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos); HRESULT result = S_OK; #ifdef _NO_EXCEPTIONS result = ErrorCode; #endif if (_buf2 != 0) { memcpy(_buf2, _buf + _streamPos, size); _buf2 += size; } if (_stream != 0 #ifdef _NO_EXCEPTIONS && (ErrorCode == S_OK) #endif ) { UInt32 processedSize = 0; result = _stream->Write(_buf + _streamPos, size, &processedSize); size = processedSize; } _streamPos += size; if (_streamPos == _bufSize) _streamPos = 0; if (_pos == _bufSize) { _overDict = true; _pos = 0; } _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize; _processedSize += size; return result; } HRESULT COutBuffer::Flush() throw() { #ifdef _NO_EXCEPTIONS if (ErrorCode != S_OK) return ErrorCode; #endif while (_streamPos != _pos) { HRESULT result = FlushPart(); if (result != S_OK) return result; } return S_OK; } void COutBuffer::FlushWithCheck() { HRESULT result = Flush(); #ifdef _NO_EXCEPTIONS ErrorCode = result; #else if (result != S_OK) throw COutBufferException(result); #endif } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.h0100777000000000000000000000236213761647206023314 0ustar00// OutBuffer.h #ifndef __OUT_BUFFER_H #define __OUT_BUFFER_H #include "../IStream.h" #include "../../Common/MyCom.h" #include "../../Common/MyException.h" #ifndef _NO_EXCEPTIONS struct COutBufferException: public CSystemException { COutBufferException(HRESULT errorCode): CSystemException(errorCode) {} }; #endif class COutBuffer { protected: Byte *_buf; UInt32 _pos; UInt32 _limitPos; UInt32 _streamPos; UInt32 _bufSize; ISequentialOutStream *_stream; UInt64 _processedSize; Byte *_buf2; bool _overDict; HRESULT FlushPart() throw(); public: #ifdef _NO_EXCEPTIONS HRESULT ErrorCode; #endif COutBuffer(): _buf(0), _pos(0), _stream(0), _buf2(0) {} ~COutBuffer() { Free(); } bool Create(UInt32 bufSize) throw(); void Free() throw(); void SetMemStream(Byte *buf) { _buf2 = buf; } void SetStream(ISequentialOutStream *stream) { _stream = stream; } void Init() throw(); HRESULT Flush() throw(); void FlushWithCheck(); void WriteByte(Byte b) { _buf[_pos++] = b; if (_pos == _limitPos) FlushWithCheck(); } void WriteBytes(const void *data, size_t size) { for (size_t i = 0; i < size; i++) WriteByte(((const Byte *)data)[i]); } UInt64 GetProcessedSize() const throw(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.cpp0100777000000000000000000000174713761647206024601 0ustar00// ProgressUtils.cpp #include "StdAfx.h" #include "ProgressUtils.h" CLocalProgress::CLocalProgress() { ProgressOffset = InSize = OutSize = 0; SendRatio = SendProgress = true; } void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain) { _ratioProgress.Release(); _progress = progress; _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress); _inSizeIsMain = inSizeIsMain; } STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { UInt64 inSizeNew = InSize, outSizeNew = OutSize; if (inSize) inSizeNew += (*inSize); if (outSize) outSizeNew += (*outSize); if (SendRatio && _ratioProgress) { RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew)); } inSizeNew += ProgressOffset; outSizeNew += ProgressOffset; if (SendProgress) return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew); return S_OK; } HRESULT CLocalProgress::SetCur() { return SetRatioInfo(NULL, NULL); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.h0100777000000000000000000000120513761647206024233 0ustar00// ProgressUtils.h #ifndef __PROGRESSUTILS_H #define __PROGRESSUTILS_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../IProgress.h" class CLocalProgress: public ICompressProgressInfo, public CMyUnknownImp { CMyComPtr _progress; CMyComPtr _ratioProgress; bool _inSizeIsMain; public: UInt64 ProgressOffset; UInt64 InSize; UInt64 OutSize; bool SendRatio; bool SendProgress; CLocalProgress(); void Init(IProgress *progress, bool inSizeIsMain); HRESULT SetCur(); MY_UNKNOWN_IMP STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/PropId.cpp0100777000000000000000000000225713761647206023146 0ustar00// PropId.cpp #include "StdAfx.h" #include "../PropID.h" // VARTYPE Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] = { VT_EMPTY, VT_UI4, VT_UI4, VT_BSTR, VT_BSTR, VT_BSTR, VT_BOOL, VT_UI8, VT_UI8, VT_UI4, VT_FILETIME, VT_FILETIME, VT_FILETIME, VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_UI4, VT_UI4, VT_BSTR, VT_BOOL, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, VT_UI8, VT_BSTR, VT_UI8, VT_BSTR, VT_UI8, VT_UI8, VT_BSTR, // or VT_UI8 kpidUnpackVer VT_UI4, // or VT_UI8 kpidVolume VT_BOOL, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI4, VT_BOOL, VT_BOOL, VT_BSTR, VT_UI8, VT_UI8, VT_UI4, // kpidChecksum VT_BSTR, VT_UI8, VT_BSTR, // or VT_UI8 kpidId VT_BSTR, VT_BSTR, VT_UI4, VT_UI4, VT_BSTR, VT_BSTR, VT_UI8, VT_UI8, VT_UI4, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, // kpidNtSecure VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_BSTR, // SHA-1 VT_BSTR, // SHA-256 VT_BSTR, VT_UI8, VT_UI4, VT_UI4, VT_BSTR, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_BSTR, VT_BSTR, VT_BSTR, VT_BOOL, VT_BOOL, VT_BOOL, VT_UI8, VT_UI8 }; qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h0100777000000000000000000000332713761647206023627 0ustar00// RegisterArc.h #ifndef __REGISTER_ARC_H #define __REGISTER_ARC_H #include "../Archive/IArchive.h" #include struct CArcInfo { const char *Name; const char *Ext; const char *AddExt; Byte ClassId; Byte SignatureSize; Byte Signature[20]; UInt16 SignatureOffset; UInt16 Flags; Func_CreateInArchive CreateInArchive; Func_CreateOutArchive CreateOutArchive; Func_IsArc IsArc; bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } std::once_flag once; }; void RegisterArc(const CArcInfo *arcInfo) throw(); #define REGISTER_ARC_NAME(x) CRegister ## x #define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) \ { \ REGISTER_ARC_NAME(x)() \ { \ std::call_once(g_ArcInfo.once, [] { RegisterArc(&g_ArcInfo); }); \ } \ }; \ static REGISTER_ARC_NAME(x) g_RegisterArc; \ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) \ { \ REGISTER_ARC_NAME(x)() { \ std::call_once(g_ArcInfo.once, [] { \ g_ArcInfo.Signature[0]--; \ RegisterArc(&g_ArcInfo); \ }); \ } \ }; \ static REGISTER_ARC_NAME(x) g_RegisterArc; \ void registerArcDec##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define IMP_CreateArcIn_2(c) \ static IInArchive *CreateArc() { return new c; } #define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler) #ifdef EXTRACT_ONLY #define IMP_CreateArcOut #define REF_CreateArc_Pair CreateArc, NULL #else #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler; } #define REF_CreateArc_Pair CreateArc, CreateArcOut #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h0100777000000000000000000000332413761647206024134 0ustar00// RegisterCodec.h #ifndef __REGISTER_CODEC_H #define __REGISTER_CODEC_H #include "../Common/MethodId.h" #include "../ICoder.h" #include typedef void * (*CreateCodecP)(); struct CCodecInfo { CreateCodecP CreateDecoder; CreateCodecP CreateEncoder; CMethodId Id; const wchar_t *Name; UInt32 NumInStreams; bool IsFilter; std::once_flag once; }; void RegisterCodec(const CCodecInfo *codecInfo) throw(); #define REGISTER_CODEC_NAME(x) CRegisterCodec ## x #define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) \ { \ REGISTER_CODEC_NAME(x)() \ { \ std::call_once(g_CodecInfo.once, [] { RegisterCodec(&g_CodecInfo); }); \ } \ }; \ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; } #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x #define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) \ { \ REGISTER_CODECS_NAME(x)() \ { \ for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ std::call_once(g_CodecsInfo[i].once, [&i] { RegisterCodec(&g_CodecsInfo[i]); }); \ } \ }; \ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; } struct CHasherInfo { IHasher * (*CreateHasher)(); CMethodId Id; const wchar_t *Name; UInt32 DigestSize; }; void RegisterHasher(const CHasherInfo *hasher) throw(); #define REGISTER_HASHER_NAME(x) CRegisterHasher ## x #define REGISTER_HASHER(x) struct REGISTER_HASHER_NAME(x) { \ REGISTER_HASHER_NAME(x)() { RegisterHasher(&g_HasherInfo); }}; \ static REGISTER_HASHER_NAME(x) g_RegisterHasher; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.cpp0100777000000000000000000000646613761647206024336 0ustar00// StreamBinder.cpp #include "StdAfx.h" #include "../../Common/MyCom.h" #include "StreamBinder.h" class CBinderInStream: public ISequentialInStream, public CMyUnknownImp { CStreamBinder *_binder; public: MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); ~CBinderInStream() { _binder->CloseRead(); } CBinderInStream(CStreamBinder *binder): _binder(binder) {} }; STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { return _binder->Read(data, size, processedSize); } class CBinderOutStream: public ISequentialOutStream, public CMyUnknownImp { CStreamBinder *_binder; public: MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); ~CBinderOutStream() { _binder->CloseWrite(); } CBinderOutStream(CStreamBinder *binder): _binder(binder) {} }; STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { return _binder->Write(data, size, processedSize); } WRes CStreamBinder::CreateEvents() { _synchroFor_canWrite_Event_and_readingWasClosed_Event = new NWindows::NSynchronization::CSynchro(); _synchroFor_canWrite_Event_and_readingWasClosed_Event->Create(); RINOK(_canWrite_Event.Create(_synchroFor_canWrite_Event_and_readingWasClosed_Event,true)); // RINOK(_canWrite_Event.Create(true)); RINOK(_canRead_Event.Create()); return _readingWasClosed_Event.Create(_synchroFor_canWrite_Event_and_readingWasClosed_Event); } void CStreamBinder::ReInit() { _waitWrite = true; _canRead_Event.Reset(); _readingWasClosed_Event.Reset(); ProcessedSize = 0; } void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream) { _waitWrite = true; _bufSize = 0; _buf = NULL; ProcessedSize = 0; CBinderInStream *inStreamSpec = new CBinderInStream(this); CMyComPtr inStreamLoc(inStreamSpec); *inStream = inStreamLoc.Detach(); CBinderOutStream *outStreamSpec = new CBinderOutStream(this); CMyComPtr outStreamLoc(outStreamSpec); *outStream = outStreamLoc.Detach(); } // (_canRead_Event && _bufSize == 0) means that stream is finished. HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size != 0) { if (_waitWrite) { RINOK(_canRead_Event.Lock()); _waitWrite = false; } if (size > _bufSize) size = _bufSize; if (size != 0) { memcpy(data, _buf, size); _buf = ((const Byte *)_buf) + size; ProcessedSize += size; if (processedSize) *processedSize = size; _bufSize -= size; if (_bufSize == 0) { _waitWrite = true; _canRead_Event.Reset(); _canWrite_Event.Set(); } } } return S_OK; } HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size != 0) { _buf = data; _bufSize = size; _canWrite_Event.Reset(); _canRead_Event.Set(); HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event }; DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); if (waitResult != WAIT_OBJECT_0 + 0) return S_FALSE; if (processedSize) *processedSize = size; } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.h0100777000000000000000000000171213761647206023770 0ustar00// StreamBinder.h #ifndef __STREAM_BINDER_H #define __STREAM_BINDER_H #include "../../Windows/Synchronization.h" #include "../IStream.h" class CStreamBinder { NWindows::NSynchronization::CManualResetEventWFMO _canWrite_Event; NWindows::NSynchronization::CManualResetEvent _canRead_Event; NWindows::NSynchronization::CManualResetEventWFMO _readingWasClosed_Event; NWindows::NSynchronization::CSynchro * _synchroFor_canWrite_Event_and_readingWasClosed_Event; bool _waitWrite; UInt32 _bufSize; const void *_buf; public: UInt64 ProcessedSize; WRes CreateEvents(); void CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream); void ReInit(); HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize); void CloseRead() { _readingWasClosed_Event.Set(); } void CloseWrite() { // _bufSize must be = 0 _canRead_Event.Set(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.cpp0100777000000000000000000001377513761647206024525 0ustar00// StreamObjects.cpp #include "StdAfx.h" #include #include "../../../C/Alloc.h" #include "StreamObjects.h" STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _size) return S_OK; size_t rem = _size - (size_t)_pos; if (rem > size) rem = (size_t)size; memcpy(data, _data + (size_t)_pos, rem); _pos += rem; if (processedSize) *processedSize = (UInt32)rem; return S_OK; } STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } /* void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream) { CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr streamTemp = inStreamSpec; inStreamSpec->Init((const Byte *)data, size); *stream = streamTemp.Detach(); } */ void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream) { CReferenceBuf *referenceBuf = new CReferenceBuf; CMyComPtr ref = referenceBuf; referenceBuf->Buf.CopyFrom((const Byte *)data, size); CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr streamTemp = inStreamSpec; inStreamSpec->Init(referenceBuf); *stream = streamTemp.Detach(); } void CByteDynBuffer::Free() throw() { free(_buf); _buf = 0; _capacity = 0; } bool CByteDynBuffer::EnsureCapacity(size_t cap) throw() { if (cap <= _capacity) return true; size_t delta; if (_capacity > 64) delta = _capacity / 4; else if (_capacity > 8) delta = 16; else delta = 4; cap = MyMax(_capacity + delta, cap); Byte *buf = (Byte *)realloc(_buf, cap); if (!buf) return false; _buf = buf; _capacity = cap; return true; } Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) { addSize += _size; if (addSize < _size) return NULL; if (!_buffer.EnsureCapacity(addSize)) return NULL; return (Byte *)_buffer + _size; } void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const { dest.CopyFrom((const Byte *)_buffer, _size); } STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; Byte *buf = GetBufPtrForWriting(size); if (!buf) return E_OUTOFMEMORY; memcpy(buf, data, size); UpdateSize(size); if (processedSize) *processedSize = size; return S_OK; } STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { size_t rem = _size - _pos; if (rem > size) rem = (size_t)size; memcpy(_buffer + _pos, data, rem); _pos += rem; if (processedSize) *processedSize = (UInt32)rem; return (rem != 0 || size == 0) ? S_OK : E_FAIL; } STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize; HRESULT result = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return result; } static const UInt64 kEmptyTag = (UInt64)(Int64)-1; void CCachedInStream::Free() throw() { MyFree(_tags); _tags = 0; MidFree(_data); _data = 0; } bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw() { unsigned sizeLog = blockSizeLog + numBlocksLog; if (sizeLog >= sizeof(size_t) * 8) return false; size_t dataSize = (size_t)1 << sizeLog; if (_data == 0 || dataSize != _dataSize) { MidFree(_data); _data = (Byte *)MidAlloc(dataSize); if (_data == 0) return false; _dataSize = dataSize; } if (_tags == 0 || numBlocksLog != _numBlocksLog) { MyFree(_tags); _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); if (_tags == 0) return false; _numBlocksLog = numBlocksLog; } _blockSizeLog = blockSizeLog; return true; } void CCachedInStream::Init(UInt64 size) throw() { _size = size; _pos = 0; size_t numBlocks = (size_t)1 << _numBlocksLog; for (size_t i = 0; i < numBlocks; i++) _tags[i] = kEmptyTag; } STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _size) return S_OK; { UInt64 rem = _size - _pos; if (size > rem) size = (UInt32)rem; } while (size != 0) { UInt64 cacheTag = _pos >> _blockSizeLog; size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); Byte *p = _data + (cacheIndex << _blockSizeLog); if (_tags[cacheIndex] != cacheTag) { UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); size_t blockSize = (size_t)1 << _blockSizeLog; if (blockSize > remInBlock) blockSize = (size_t)remInBlock; RINOK(ReadBlock(cacheTag, p, blockSize)); _tags[cacheIndex] = cacheTag; } size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1); UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size); memcpy(data, p + offset, cur); if (processedSize) *processedSize += cur; data = (void *)((const Byte *)data + cur); _pos += cur; size -= cur; } return S_OK; } STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.h0100777000000000000000000000707413761647206024165 0ustar00// StreamObjects.h #ifndef __STREAM_OBJECTS_H #define __STREAM_OBJECTS_H #include "../../Common/MyBuffer.h" #include "../../Common/MyCom.h" #include "../../Common/MyVector.h" #include "../IStream.h" struct CReferenceBuf: public IUnknown, public CMyUnknownImp { CByteBuffer Buf; MY_UNKNOWN_IMP }; class CBufInStream: public IInStream, public CMyUnknownImp { const Byte *_data; UInt64 _pos; size_t _size; CMyComPtr _ref; public: void Init(const Byte *data, size_t size, IUnknown *ref = 0) { _data = data; _size = size; _pos = 0; _ref = ref; } void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; // void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream); void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream); class CByteDynBuffer { size_t _capacity; Byte *_buf; public: CByteDynBuffer(): _capacity(0), _buf(0) {}; // there is no copy constructor. So don't copy this object. ~CByteDynBuffer() { Free(); } void Free() throw(); size_t GetCapacity() const { return _capacity; } operator Byte*() const { return _buf; }; operator const Byte*() const { return _buf; }; bool EnsureCapacity(size_t capacity) throw(); }; class CDynBufSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { CByteDynBuffer _buffer; size_t _size; public: CDynBufSeqOutStream(): _size(0) {} void Init() { _size = 0; } size_t GetSize() const { return _size; } const Byte *GetBuffer() const { return _buffer; } void CopyToBuffer(CByteBuffer &dest) const; Byte *GetBufPtrForWriting(size_t addSize); void UpdateSize(size_t addSize) { _size += addSize; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CBufPtrSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { Byte *_buffer; size_t _size; size_t _pos; public: void Init(Byte *buffer, size_t size) { _buffer = buffer; _pos = 0; _size = size; } size_t GetPos() const { return _pos; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CSequentialOutStreamSizeCount: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; public: void SetStream(ISequentialOutStream *stream) { _stream = stream; } void Init() { _size = 0; } UInt64 GetSize() const { return _size; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CCachedInStream: public IInStream, public CMyUnknownImp { UInt64 *_tags; Byte *_data; size_t _dataSize; unsigned _blockSizeLog; unsigned _numBlocksLog; UInt64 _size; UInt64 _pos; protected: virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0; public: CCachedInStream(): _tags(0), _data(0) {} virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!! void Free() throw(); bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw(); void Init(UInt64 size) throw(); MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.cpp0100777000000000000000000000305613761647206024223 0ustar00// StreamUtils.cpp #include "StdAfx.h" #include "StreamUtils.h" static const UInt32 kBlockSize = ((UInt32)1 << 31); HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw() { size_t size = *processedSize; *processedSize = 0; while (size != 0) { UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; UInt32 processedSizeLoc; HRESULT res = stream->Read(data, curSize, &processedSizeLoc); *processedSize += processedSizeLoc; data = (void *)((Byte *)data + processedSizeLoc); size -= processedSizeLoc; RINOK(res); if (processedSizeLoc == 0) return S_OK; } return S_OK; } HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw() { size_t processedSize = size; RINOK(ReadStream(stream, data, &processedSize)); return (size == processedSize) ? S_OK : S_FALSE; } HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw() { size_t processedSize = size; RINOK(ReadStream(stream, data, &processedSize)); return (size == processedSize) ? S_OK : E_FAIL; } HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw() { while (size != 0) { UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; UInt32 processedSizeLoc; HRESULT res = stream->Write(data, curSize, &processedSizeLoc); data = (const void *)((const Byte *)data + processedSizeLoc); size -= processedSizeLoc; RINOK(res); if (processedSizeLoc == 0) return E_FAIL; } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.h0100777000000000000000000000070213761647206023663 0ustar00// StreamUtils.h #ifndef __STREAM_UTILS_H #define __STREAM_UTILS_H #include "../IStream.h" HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw(); HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw(); HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw(); HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/UniqBlocks.cpp0100777000000000000000000000220113761647206024010 0ustar00// UniqBlocks.cpp #include "StdAfx.h" #include "UniqBlocks.h" int CUniqBlocks::AddUniq(const Byte *data, size_t size) { unsigned left = 0, right = Sorted.Size(); while (left != right) { unsigned mid = (left + right) / 2; int index = Sorted[mid]; const CByteBuffer &buf = Bufs[index]; size_t sizeMid = buf.Size(); if (size < sizeMid) right = mid; else if (size > sizeMid) left = mid + 1; else { int cmp = memcmp(data, buf, size); if (cmp == 0) return index; if (cmp < 0) right = mid; else left = mid + 1; } } int index = Bufs.Size(); Sorted.Insert(left, index); CByteBuffer &buf = Bufs.AddNew(); buf.CopyFrom(data, size); return index; } UInt64 CUniqBlocks::GetTotalSizeInBytes() const { UInt64 size = 0; FOR_VECTOR (i, Bufs) size += Bufs[i].Size(); return size; } void CUniqBlocks::GetReverseMap() { unsigned num = Sorted.Size(); BufIndexToSortedIndex.ClearAndSetSize(num); int *p = &BufIndexToSortedIndex[0]; unsigned i; for (i = 0; i < num; i++) p[i] = 0; for (i = 0; i < num; i++) p[Sorted[i]] = i; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/UniqBlocks.h0100777000000000000000000000106213761647206023461 0ustar00// UniqBlocks.h #ifndef __UNIQ_BLOCKS_H #define __UNIQ_BLOCKS_H #include "../../Common/MyTypes.h" #include "../../Common/MyBuffer.h" #include "../../Common/MyVector.h" struct CUniqBlocks { CObjectVector Bufs; CIntVector Sorted; CIntVector BufIndexToSortedIndex; int AddUniq(const Byte *data, size_t size); UInt64 GetTotalSizeInBytes() const; void GetReverseMap(); bool IsOnlyEmpty() const { if (Bufs.Size() == 0) return true; if (Bufs.Size() > 1) return false; return Bufs[0].Size() == 0; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.cpp0100777000000000000000000000143213761647206024017 0ustar00// VirtThread.cpp #include "StdAfx.h" #include "VirtThread.h" static THREAD_FUNC_DECL CoderThread(void *p) { for (;;) { CVirtThread *t = (CVirtThread *)p; t->StartEvent.Lock(); if (t->Exit) return 0; t->Execute(); t->FinishedEvent.Set(); } } WRes CVirtThread::Create() { RINOK(StartEvent.CreateIfNotCreated()); RINOK(FinishedEvent.CreateIfNotCreated()); StartEvent.Reset(); FinishedEvent.Reset(); Exit = false; if (Thread.IsCreated()) return S_OK; return Thread.Create(CoderThread, this); } void CVirtThread::Start() { Exit = false; StartEvent.Set(); } void CVirtThread::WaitThreadFinish() { Exit = true; if (StartEvent.IsCreated()) StartEvent.Set(); if (Thread.IsCreated()) { Thread.Wait(); Thread.Close(); } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.h0100777000000000000000000000106313761647206023464 0ustar00// VirtThread.h #ifndef __VIRT_THREAD_H #define __VIRT_THREAD_H #include "../../Windows/Synchronization.h" #include "../../Windows/Thread.h" struct CVirtThread { NWindows::NSynchronization::CAutoResetEvent StartEvent; NWindows::NSynchronization::CAutoResetEvent FinishedEvent; NWindows::CThread Thread; bool Exit; ~CVirtThread() { WaitThreadFinish(); } void WaitThreadFinish(); // call it in destructor of child class ! WRes Create(); void Start(); virtual void Execute() = 0; void WaitExecuteFinish() { FinishedEvent.Lock(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/0040777000000000000000000000000013761647206021602 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp0100777000000000000000000002350413761647206024047 0ustar00// Bcj2Coder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "Bcj2Coder.h" namespace NCompress { namespace NBcj2 { inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); } inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); } inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); } #ifndef EXTRACT_ONLY static const unsigned kBufSize = 1 << 17; #define NUM_BITS 2 #define SIGN_BIT (1 << NUM_BITS) #define MASK_HIGH (0x100 - (1 << (NUM_BITS + 1))) static const UInt32 kDefaultLimit = (1 << (24 + NUM_BITS)); static bool inline Test86MSByte(Byte b) { return (((b) + SIGN_BIT) & MASK_HIGH) == 0; } CEncoder::~CEncoder() { ::MidFree(_buf); } HRESULT CEncoder::Flush() { RINOK(_mainStream.Flush()); RINOK(_callStream.Flush()); RINOK(_jumpStream.Flush()); _rc.FlushData(); return _rc.FlushStream(); } HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != 1 || numOutStreams != 4) return E_INVALIDARG; if (!_mainStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_callStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_jumpStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_rc.Create(1 << 20)) return E_OUTOFMEMORY; if (_buf == 0) { _buf = (Byte *)MidAlloc(kBufSize); if (_buf == 0) return E_OUTOFMEMORY; } bool sizeIsDefined = false; UInt64 inSize = 0; if (inSizes) if (inSizes[0]) { inSize = *inSizes[0]; if (inSize <= kDefaultLimit) sizeIsDefined = true; } ISequentialInStream *inStream = inStreams[0]; _mainStream.SetStream(outStreams[0]); _mainStream.Init(); _callStream.SetStream(outStreams[1]); _callStream.Init(); _jumpStream.SetStream(outStreams[2]); _jumpStream.Init(); _rc.SetStream(outStreams[3]); _rc.Init(); for (unsigned i = 0; i < 256 + 2; i++) _statusEncoder[i].Init(); CMyComPtr getSubStreamSize; { inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); } UInt32 nowPos = 0; UInt64 nowPos64 = 0; UInt32 bufPos = 0; Byte prevByte = 0; UInt64 subStreamIndex = 0; UInt64 subStreamStartPos = 0; UInt64 subStreamEndPos = 0; for (;;) { UInt32 processedSize = 0; for (;;) { UInt32 size = kBufSize - (bufPos + processedSize); UInt32 processedSizeLoc; if (size == 0) break; RINOK(inStream->Read(_buf + bufPos + processedSize, size, &processedSizeLoc)); if (processedSizeLoc == 0) break; processedSize += processedSizeLoc; } UInt32 endPos = bufPos + processedSize; if (endPos < 5) { // change it for (bufPos = 0; bufPos < endPos; bufPos++) { Byte b = _buf[bufPos]; _mainStream.WriteByte(b); UInt32 index; if (b == 0xE8) index = prevByte; else if (b == 0xE9) index = 256; else if (IsJcc(prevByte, b)) index = 257; else { prevByte = b; continue; } _statusEncoder[index].Encode(&_rc, 0); prevByte = b; } return Flush(); } bufPos = 0; UInt32 limit = endPos - 5; while (bufPos <= limit) { Byte b = _buf[bufPos]; _mainStream.WriteByte(b); if (!IsJ(prevByte, b)) { bufPos++; prevByte = b; continue; } Byte nextByte = _buf[bufPos + 4]; UInt32 src = (UInt32(nextByte) << 24) | (UInt32(_buf[bufPos + 3]) << 16) | (UInt32(_buf[bufPos + 2]) << 8) | (_buf[bufPos + 1]); UInt32 dest = (nowPos + bufPos + 5) + src; // if (Test86MSByte(nextByte)) bool convert; if (getSubStreamSize) { UInt64 currentPos = (nowPos64 + bufPos); while (subStreamEndPos < currentPos) { UInt64 subStreamSize; HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); if (result == S_OK) { subStreamStartPos = subStreamEndPos; subStreamEndPos += subStreamSize; subStreamIndex++; } else if (result == S_FALSE || result == E_NOTIMPL) { getSubStreamSize.Release(); subStreamStartPos = 0; subStreamEndPos = subStreamStartPos - 1; } else return result; } if (getSubStreamSize == NULL) { if (sizeIsDefined) convert = (dest < inSize); else convert = Test86MSByte(nextByte); } else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) convert = Test86MSByte(nextByte); else { UInt64 dest64 = (currentPos + 5) + Int64(Int32(src)); convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos); } } else if (sizeIsDefined) convert = (dest < inSize); else convert = Test86MSByte(nextByte); unsigned index = GetIndex(prevByte, b); if (convert) { _statusEncoder[index].Encode(&_rc, 1); bufPos += 5; COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; for (int i = 24; i >= 0; i -= 8) s.WriteByte((Byte)(dest >> i)); prevByte = nextByte; } else { _statusEncoder[index].Encode(&_rc, 0); bufPos++; prevByte = b; } } nowPos += bufPos; nowPos64 += bufPos; if (progress) { /* const UInt64 compressedSize = _mainStream.GetProcessedSize() + _callStream.GetProcessedSize() + _jumpStream.GetProcessedSize() + _rc.GetProcessedSize(); */ RINOK(progress->SetRatioInfo(&nowPos64, NULL)); } UInt32 i = 0; while (bufPos < endPos) _buf[i++] = _buf[bufPos++]; bufPos = i; } } STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) { try { return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); } catch(const COutBufferException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } #endif STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; } STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } CDecoder::CDecoder(): _outBufSize(1 << 16) { _inBufSizes[0] = 1 << 20; _inBufSizes[1] = 1 << 20; _inBufSizes[2] = 1 << 20; _inBufSizes[3] = 1 << 20; } HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != 4 || numOutStreams != 1) return E_INVALIDARG; if (!_mainStream.Create(_inBufSizes[0])) return E_OUTOFMEMORY; if (!_callStream.Create(_inBufSizes[1])) return E_OUTOFMEMORY; if (!_jumpStream.Create(_inBufSizes[2])) return E_OUTOFMEMORY; if (!_rc.Create(_inBufSizes[3])) return E_OUTOFMEMORY; if (!_outStream.Create(_outBufSize)) return E_OUTOFMEMORY; _mainStream.SetStream(inStreams[0]); _callStream.SetStream(inStreams[1]); _jumpStream.SetStream(inStreams[2]); _rc.SetStream(inStreams[3]); _outStream.SetStream(outStreams[0]); _mainStream.Init(); _callStream.Init(); _jumpStream.Init(); _rc.Init(); _outStream.Init(); for (unsigned i = 0; i < 256 + 2; i++) _statusDecoder[i].Init(); Byte prevByte = 0; UInt32 processedBytes = 0; for (;;) { if (processedBytes >= (1 << 20) && progress) { /* const UInt64 compressedSize = _mainStream.GetProcessedSize() + _callStream.GetProcessedSize() + _jumpStream.GetProcessedSize() + _rc.GetProcessedSize(); */ const UInt64 nowPos64 = _outStream.GetProcessedSize(); RINOK(progress->SetRatioInfo(NULL, &nowPos64)); processedBytes = 0; } UInt32 i; Byte b = 0; const UInt32 kBurstSize = (1 << 18); for (i = 0; i < kBurstSize; i++) { if (!_mainStream.ReadByte(b)) return _outStream.Flush(); _outStream.WriteByte(b); if (IsJ(prevByte, b)) break; prevByte = b; } processedBytes += i; if (i == kBurstSize) continue; unsigned index = GetIndex(prevByte, b); if (_statusDecoder[index].Decode(&_rc) == 1) { UInt32 src = 0; CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; for (unsigned i = 0; i < 4; i++) { Byte b0; if (!s.ReadByte(b0)) return S_FALSE; src <<= 8; src |= ((UInt32)b0); } UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ; _outStream.WriteByte((Byte)(dest)); _outStream.WriteByte((Byte)(dest >> 8)); _outStream.WriteByte((Byte)(dest >> 16)); _outStream.WriteByte((Byte)(dest >> 24)); prevByte = (Byte)(dest >> 24); processedBytes += 4; } else prevByte = b; } } STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) { try { return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); } catch(const CInBufferException &e) { return e.ErrorCode; } catch(const COutBufferException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.h0100777000000000000000000000401313761647206023506 0ustar00// Bcj2Coder.h #ifndef __COMPRESS_BCJ2_CODER_H #define __COMPRESS_BCJ2_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "RangeCoderBit.h" namespace NCompress { namespace NBcj2 { const unsigned kNumMoveBits = 5; #ifndef EXTRACT_ONLY class CEncoder: public ICompressCoder2, public CMyUnknownImp { Byte *_buf; COutBuffer _mainStream; COutBuffer _callStream; COutBuffer _jumpStream; NRangeCoder::CEncoder _rc; NRangeCoder::CBitEncoder _statusEncoder[256 + 2]; HRESULT Flush(); public: MY_UNKNOWN_IMP HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); CEncoder(): _buf(0) {}; ~CEncoder(); }; #endif class CDecoder: public ICompressCoder2, public ICompressSetBufSize, public CMyUnknownImp { CInBuffer _mainStream; CInBuffer _callStream; CInBuffer _jumpStream; NRangeCoder::CDecoder _rc; NRangeCoder::CBitDecoder _statusDecoder[256 + 2]; COutBuffer _outStream; UInt32 _inBufSizes[4]; UInt32 _outBufSize; public: MY_UNKNOWN_IMP1(ICompressSetBufSize); HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size); STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size); CDecoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Register.cpp0100777000000000000000000000075213761647206024577 0ustar00// Bcj2Register.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "Bcj2Coder.h" static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); } #ifndef EXTRACT_ONLY static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder()); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false }; REGISTER_CODEC(BCJ2) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.cpp0100777000000000000000000000051413761647206023761 0ustar00// BcjCoder.cpp #include "StdAfx.h" #include "BcjCoder.h" UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size) { return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1); } UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size) { return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.h0100777000000000000000000000047413761647206023433 0ustar00// BcjCoder.h #ifndef __COMPRESS_BCJ_CODER_H #define __COMPRESS_BCJ_CODER_H #include "../../../C/Bra.h" #include "BranchCoder.h" struct CBranch86 { UInt32 _prevMask; void x86Init() { x86_Convert_Init(_prevMask); } }; MyClassB(BCJ_x86, 0x01, 3, CBranch86 , virtual void SubInit() { x86Init(); }) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BcjRegister.cpp0100777000000000000000000000072113761647206024511 0ustar00// BcjRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "BcjCoder.h" static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); } #ifndef EXTRACT_ONLY static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder()); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true }; REGISTER_CODEC(BCJ) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.cpp0100777000000000000000000000051713761647206024463 0ustar00// BranchCoder.cpp #include "StdAfx.h" #include "BranchCoder.h" STDMETHODIMP CBranchConverter::Init() { _bufferPos = 0; SubInit(); return S_OK; } STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size) { UInt32 processedSize = SubFilter(data, size); _bufferPos += processedSize; return processedSize; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.h0100777000000000000000000000250613761647206024130 0ustar00// BranchCoder.h #ifndef __COMPRESS_BRANCH_CODER_H #define __COMPRESS_BRANCH_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" class CBranchConverter: public ICompressFilter, public CMyUnknownImp { protected: UInt32 _bufferPos; virtual void SubInit() {} virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0; public: MY_UNKNOWN_IMP; STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; #define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \ { public: UInt32 SubFilter(Byte *data, UInt32 size); }; #define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \ { public: UInt32 SubFilter(Byte *data, UInt32 size); }; #define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; #define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; #define MyClassA(Name, id, subId) \ MyClassEncoderA(Name ## _Encoder) \ MyClassDecoderA(Name ## _Decoder) #define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \ MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \ MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.cpp0100777000000000000000000000077613761647206024331 0ustar00// BranchMisc.cpp #include "StdAfx.h" #include "../../../C/Bra.h" #include "BranchMisc.h" #define SUB_FILTER_IMP2(name, coderStr, coderNum) \ UInt32 CBC_ ## name ## coderStr::SubFilter(Byte *data, UInt32 size) \ { return (UInt32)::name ## Convert(data, size, _bufferPos, coderNum); } #define SUB_FILTER_IMP(name) \ SUB_FILTER_IMP2(name, Encoder, 1) \ SUB_FILTER_IMP2(name, Decoder, 0) \ SUB_FILTER_IMP(ARM_) SUB_FILTER_IMP(ARMT_) SUB_FILTER_IMP(PPC_) SUB_FILTER_IMP(SPARC_) SUB_FILTER_IMP(IA64_) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.h0100777000000000000000000000040213761647206023760 0ustar00// BranchMisc.h #ifndef __COMPRESS_BRANCH_MISC_H #define __COMPRESS_BRANCH_MISC_H #include "BranchCoder.h" MyClassA(BC_ARM, 0x05, 1) MyClassA(BC_ARMT, 0x07, 1) MyClassA(BC_PPC, 0x02, 5) MyClassA(BC_SPARC, 0x08, 5) MyClassA(BC_IA64, 0x04, 1) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/BranchRegister.cpp0100777000000000000000000000154313761647206025213 0ustar00// BranchRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "BranchMisc.h" #define CREATE_CODEC(x) \ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); } CREATE_CODEC(BC_PPC) CREATE_CODEC(BC_IA64) CREATE_CODEC(BC_ARM) CREATE_CODEC(BC_ARMT) CREATE_CODEC(BC_SPARC) #define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true } static CCodecInfo g_CodecsInfo[] = { METHOD_ITEM(BC_PPC, 0x02, 0x05, L"PPC"), METHOD_ITEM(BC_IA64, 0x04, 1, L"IA64"), METHOD_ITEM(BC_ARM, 0x05, 1, L"ARM"), METHOD_ITEM(BC_ARMT, 0x07, 1, L"ARMT"), METHOD_ITEM(BC_SPARC, 0x08, 0x05, L"SPARC") }; REGISTER_CODECS(Branch) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/ByteSwap.cpp0100777000000000000000000000275013761647206024050 0ustar00// ByteSwap.cpp #include "StdAfx.h" #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../Common/RegisterCodec.h" class CByteSwap2: public ICompressFilter, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; class CByteSwap4: public ICompressFilter, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; STDMETHODIMP CByteSwap2::Init() { return S_OK; } STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size) { const UInt32 kStep = 2; UInt32 i; for (i = 0; i + kStep <= size; i += kStep) { Byte b = data[i]; data[i] = data[i + 1]; data[i + 1] = b; } return i; } STDMETHODIMP CByteSwap4::Init() { return S_OK; } STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size) { const UInt32 kStep = 4; UInt32 i; for (i = 0; i + kStep <= size; i += kStep) { Byte b0 = data[i]; Byte b1 = data[i + 1]; data[i] = data[i + 3]; data[i + 1] = data[i + 2]; data[i + 2] = b1; data[i + 3] = b0; } return i; } static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); } static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); } static CCodecInfo g_CodecsInfo[] = { { CreateCodec2, CreateCodec2, 0x020302, L"Swap2", 1, true }, { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true } }; REGISTER_CODECS(ByteSwap) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Compress.pri0100777000000000000000000000263713761647206024121 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.h \ $$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/RangeCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/RangeCoderBit.h SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Register.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BcjRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/ByteSwap.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/CopyRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/DeltaFilter.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Register.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaRegister.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.cpp0100777000000000000000000000336113761647206024200 0ustar00// Compress/CopyCoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "CopyCoder.h" namespace NCompress { static const UInt32 kBufferSize = 1 << 17; CCopyCoder::~CCopyCoder() { ::MidFree(_buffer); } STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (!_buffer) { _buffer = (Byte *)::MidAlloc(kBufferSize); if (!_buffer) return E_OUTOFMEMORY; } TotalSize = 0; for (;;) { UInt32 size = kBufferSize; if (outSize && size > *outSize - TotalSize) size = (UInt32)(*outSize - TotalSize); RINOK(inStream->Read(_buffer, size, &size)); if (size == 0) break; if (outStream) { RINOK(WriteStream(outStream, _buffer, size)); } TotalSize += size; if (progress) { RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); } } return S_OK; } STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value) { *value = TotalSize; return S_OK; } HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { CMyComPtr copyCoder = new CCopyCoder; return copyCoder->Code(inStream, outStream, NULL, NULL, progress); } HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) { NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)); return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.h0100777000000000000000000000165113761647206023645 0ustar00// Compress/CopyCoder.h #ifndef __COMPRESS_COPY_CODER_H #define __COMPRESS_COPY_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { class CCopyCoder: public ICompressCoder, public ICompressGetInStreamProcessedSize, public CMyUnknownImp { Byte *_buffer; public: UInt64 TotalSize; CCopyCoder(): TotalSize(0), _buffer(0) {}; ~CCopyCoder(); MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); }; HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/CopyRegister.cpp0100777000000000000000000000046313761647206024730 0ustar00// CopyRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "CopyCoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); } static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodec, 0x00, L"Copy", 1, false }; REGISTER_CODEC(Copy) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/DeltaFilter.cpp0100777000000000000000000000571213761647206024512 0ustar00// DeltaFilter.cpp #include "StdAfx.h" #include "../../../C/Delta.h" #include "../Common/RegisterCodec.h" #include "BranchCoder.h" struct CDelta { unsigned _delta; Byte _state[DELTA_STATE_SIZE]; CDelta(): _delta(1) {} void DeltaInit() { Delta_Init(_state); } }; class CDeltaEncoder: public ICompressFilter, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, CDelta, public CMyUnknownImp { public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); }; class CDeltaDecoder: public ICompressFilter, public ICompressSetDecoderProperties2, CDelta, public CMyUnknownImp { public: MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); }; STDMETHODIMP CDeltaEncoder::Init() { DeltaInit(); return S_OK; } STDMETHODIMP_(UInt32) CDeltaEncoder::Filter(Byte *data, UInt32 size) { Delta_Encode(_state, _delta, data, size); return size; } STDMETHODIMP CDeltaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) { UInt32 delta = _delta; for (UInt32 i = 0; i < numProps; i++) { const PROPVARIANT &prop = props[i]; PROPID propID = propIDs[i]; if (propID >= NCoderPropID::kReduceSize) continue; if (prop.vt != VT_UI4) return E_INVALIDARG; switch (propID) { case NCoderPropID::kDefaultProp: delta = (UInt32)prop.ulVal; if (delta < 1 || delta > 256) return E_INVALIDARG; break; case NCoderPropID::kNumThreads: break; case NCoderPropID::kLevel: break; default: return E_INVALIDARG; } } _delta = delta; return S_OK; } STDMETHODIMP CDeltaEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte prop = (Byte)(_delta - 1); return outStream->Write(&prop, 1, NULL); } STDMETHODIMP CDeltaDecoder::Init() { DeltaInit(); return S_OK; } STDMETHODIMP_(UInt32) CDeltaDecoder::Filter(Byte *data, UInt32 size) { Delta_Decode(_state, _delta, data, size); return size; } STDMETHODIMP CDeltaDecoder::SetDecoderProperties2(const Byte *props, UInt32 size) { if (size != 1) return E_INVALIDARG; _delta = (unsigned)props[0] + 1; return S_OK; } #define CREATE_CODEC(x) \ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## Decoder); } \ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## Encoder); } CREATE_CODEC(Delta) #define METHOD_ITEM(x, id, name) { CreateCodec ## x, CreateCodec ## x ## Out, id, name, 1, true } static CCodecInfo g_CodecsInfo[] = { METHOD_ITEM(Delta, 3, L"Delta") }; REGISTER_CODECS(Delta) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.cpp0100777000000000000000000001157613761647206024573 0ustar00// Lzma2Decoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "Lzma2Decoder.h" static HRESULT SResToHRESULT(SRes res) { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; // case SZ_ERROR_PROGRESS: return E_ABORT; case SZ_ERROR_DATA: return S_FALSE; } return E_FAIL; } namespace NCompress { namespace NLzma2 { static const UInt32 kInBufSize = 1 << 20; CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false) { Lzma2Dec_Construct(&_state); } static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CDecoder::~CDecoder() { Lzma2Dec_Free(&_state, &g_Alloc); MyFree(_inBuf); } STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size) { if (size != 1) return SZ_ERROR_UNSUPPORTED; RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc))); if (_inBuf == 0) { _inBuf = (Byte *)MyAlloc(kInBufSize); if (_inBuf == 0) return E_OUTOFMEMORY; } return S_OK; } STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; } STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) { _outSizeDefined = (outSize != NULL); if (_outSizeDefined) _outSize = *outSize; Lzma2Dec_Init(&_state); _inPos = _inSize = 0; _inSizeProcessed = _outSizeProcessed = 0; return S_OK; } STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (_inBuf == 0) return S_FALSE; SetOutStreamSize(outSize); for (;;) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize)); } SizeT dicPos = _state.decoder.dicPos; SizeT curSize = _state.decoder.dicBufSize - dicPos; const UInt32 kStepSize = ((UInt32)1 << 22); if (curSize > kStepSize) curSize = (SizeT)kStepSize; ELzmaFinishMode finishMode = LZMA_FINISH_ANY; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < curSize) { curSize = (SizeT)rem; /* // finishMode = LZMA_FINISH_END; we can't use LZMA_FINISH_END here to allow partial decoding */ } } SizeT inSizeProcessed = _inSize - _inPos; ELzmaStatus status; SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status); _inPos += (UInt32)inSizeProcessed; _inSizeProcessed += inSizeProcessed; SizeT outSizeProcessed = _state.decoder.dicPos - dicPos; _outSizeProcessed += outSizeProcessed; bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0); bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize); if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding) { HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos); if (res != 0) return S_FALSE; RINOK(res2); if (stopDecoding) return S_OK; if (finished) return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE); } if (_state.decoder.dicPos == _state.decoder.dicBufSize) _state.decoder.dicPos = 0; if (progress != NULL) { RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed)); } } } #ifndef NO_READ_FROM_CODER STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; do { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize)); } { SizeT inProcessed = _inSize - _inPos; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < size) size = (UInt32)rem; } SizeT outProcessed = size; ELzmaStatus status; SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status); _inPos += (UInt32)inProcessed; _inSizeProcessed += inProcessed; _outSizeProcessed += outProcessed; size -= (UInt32)outProcessed; data = (Byte *)data + outProcessed; if (processedSize) *processedSize += (UInt32)outProcessed; RINOK(SResToHRESULT(res)); if (inProcessed == 0 && outProcessed == 0) return S_OK; } } while (size != 0); return S_OK; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.h0100777000000000000000000000315513761647206024232 0ustar00// Lzma2Decoder.h #ifndef __LZMA2_DECODER_H #define __LZMA2_DECODER_H #include "../../../C/Lzma2Dec.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma2 { class CDecoder: public ICompressCoder, public ICompressSetDecoderProperties2, public ICompressGetInStreamProcessedSize, #ifndef NO_READ_FROM_CODER public ICompressSetInStream, public ICompressSetOutStreamSize, public ISequentialInStream, #endif public CMyUnknownImp { CMyComPtr _inStream; Byte *_inBuf; UInt32 _inPos; UInt32 _inSize; CLzma2Dec _state; bool _outSizeDefined; UInt64 _outSize; UInt64 _inSizeProcessed; UInt64 _outSizeProcessed; public: #ifndef NO_READ_FROM_CODER MY_UNKNOWN_IMP5( ICompressSetDecoderProperties2, ICompressGetInStreamProcessedSize, ICompressSetInStream, ICompressSetOutStreamSize, ISequentialInStream) #else MY_UNKNOWN_IMP2( ICompressSetDecoderProperties2, ICompressGetInStreamProcessedSize) #endif STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *_inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(ReleaseInStream)(); STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); #ifndef NO_READ_FROM_CODER STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); #endif CDecoder(); virtual ~CDecoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.cpp0100777000000000000000000000506313761647206024577 0ustar00// Lzma2Encoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/CWrappers.h" #include "../Common/StreamUtils.h" #include "Lzma2Encoder.h" namespace NCompress { namespace NLzma { HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); } namespace NLzma2 { static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } static void SzBigFree(void *, void *address) { BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CEncoder::CEncoder() { _encoder = 0; _encoder = Lzma2Enc_Create(&g_Alloc, &g_BigAlloc); if (_encoder == 0) throw 1; } CEncoder::~CEncoder() { if (_encoder != 0) Lzma2Enc_Destroy(_encoder); } HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props) { switch (propID) { case NCoderPropID::kBlockSize: if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; break; case NCoderPropID::kNumThreads: if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break; default: RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)); } return S_OK; } STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { CLzma2EncProps lzma2Props; Lzma2EncProps_Init(&lzma2Props); for (UInt32 i = 0; i < numProps; i++) { RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props)); } return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props)); } STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte prop = Lzma2Enc_WriteProperties(_encoder); return WriteStream(outStream, &prop, 1); } STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { CSeqInStreamWrap inWrap(inStream); CSeqOutStreamWrap outWrap(outStream); CCompressProgressWrap progressWrap(progress); SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL); if (res == SZ_ERROR_READ && inWrap.Res != S_OK) return inWrap.Res; if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) return outWrap.Res; if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) return progressWrap.Res; return SResToHRESULT(res); } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.h0100777000000000000000000000152313761647206024241 0ustar00// Lzma2Encoder.h #ifndef __LZMA2_ENCODER_H #define __LZMA2_ENCODER_H #include "../../../C/Lzma2Enc.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma2 { class CEncoder: public ICompressCoder, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, public CMyUnknownImp { CLzma2EncHandle _encoder; public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); CEncoder(); virtual ~CEncoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Register.cpp0100777000000000000000000000100013761647206024767 0ustar00// Lzma2Register.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "Lzma2Decoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); } #ifndef EXTRACT_ONLY #include "Lzma2Encoder.h" static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CEncoder); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x21, L"LZMA2", 1, false }; REGISTER_CODEC(LZMA2) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.cpp0100777000000000000000000001577013761647206024511 0ustar00// LzmaDecoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "LzmaDecoder.h" static HRESULT SResToHRESULT(SRes res) { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; case SZ_ERROR_DATA: return S_FALSE; } return E_FAIL; } namespace NCompress { namespace NLzma { CDecoder::CDecoder(): _inBuf(0), _propsWereSet(false), _outSizeDefined(false), _inBufSize(1 << 20), _outBufSize(1 << 22), FinishStream(false), NeedMoreInput(false) { _inSizeProcessed = 0; _inPos = _inSize = 0; LzmaDec_Construct(&_state); } static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CDecoder::~CDecoder() { LzmaDec_Free(&_state, &g_Alloc); MyFree(_inBuf); } STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; } STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } HRESULT CDecoder::CreateInputBuffer() { if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated) { MyFree(_inBuf); _inBuf = (Byte *)MyAlloc(_inBufSize); if (_inBuf == 0) return E_OUTOFMEMORY; _inBufSizeAllocated = _inBufSize; } return S_OK; } STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size) { RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc))); _propsWereSet = true; return CreateInputBuffer(); } void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize) { _outSizeDefined = (outSize != NULL); if (_outSizeDefined) _outSize = *outSize; _outSizeProcessed = 0; _wrPos = 0; LzmaDec_Init(&_state); } STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) { _inSizeProcessed = 0; _inPos = _inSize = 0; NeedMoreInput = false; SetOutStreamSizeResume(outSize); return S_OK; } HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { if (_inBuf == 0 || !_propsWereSet) return S_FALSE; UInt64 startInProgress = _inSizeProcessed; SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize); for (;;) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); } SizeT dicPos = _state.dicPos; SizeT curSize = next - dicPos; ELzmaFinishMode finishMode = LZMA_FINISH_ANY; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem <= curSize) { curSize = (SizeT)rem; if (FinishStream) finishMode = LZMA_FINISH_END; } } SizeT inSizeProcessed = _inSize - _inPos; ELzmaStatus status; SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status); _inPos += (UInt32)inSizeProcessed; _inSizeProcessed += inSizeProcessed; SizeT outSizeProcessed = _state.dicPos - dicPos; _outSizeProcessed += outSizeProcessed; bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0); bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize); if (res != 0 || _state.dicPos == next || finished || stopDecoding) { HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos); _wrPos = _state.dicPos; if (_state.dicPos == _state.dicBufSize) { _state.dicPos = 0; _wrPos = 0; } next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize); if (res != 0) return S_FALSE; RINOK(res2); if (stopDecoding) { if (status == LZMA_STATUS_NEEDS_MORE_INPUT) NeedMoreInput = true; if (FinishStream && status != LZMA_STATUS_FINISHED_WITH_MARK && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) return S_FALSE; return S_OK; } if (finished) { if (status == LZMA_STATUS_NEEDS_MORE_INPUT) NeedMoreInput = true; return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE); } } if (progress) { UInt64 inSize = _inSizeProcessed - startInProgress; RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed)); } } } STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (_inBuf == 0) return E_INVALIDARG; SetOutStreamSize(outSize); return CodeSpec(inStream, outStream, progress); } #ifndef NO_READ_FROM_CODER STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; do { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); } { SizeT inProcessed = _inSize - _inPos; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < size) size = (UInt32)rem; } SizeT outProcessed = size; ELzmaStatus status; SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status); _inPos += (UInt32)inProcessed; _inSizeProcessed += inProcessed; _outSizeProcessed += outProcessed; size -= (UInt32)outProcessed; data = (Byte *)data + outProcessed; if (processedSize) *processedSize += (UInt32)outProcessed; RINOK(SResToHRESULT(res)); if (inProcessed == 0 && outProcessed == 0) return S_OK; } } while (size != 0); return S_OK; } HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) { SetOutStreamSizeResume(outSize); return CodeSpec(_inStream, outStream, progress); } HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize) { RINOK(CreateInputBuffer()); if (processedSize) *processedSize = 0; while (size > 0) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); if (_inSize == 0) break; } { UInt32 curSize = _inSize - _inPos; if (curSize > size) curSize = size; memcpy(data, _inBuf + _inPos, curSize); _inPos += curSize; _inSizeProcessed += curSize; size -= curSize; data = (Byte *)data + curSize; if (processedSize) *processedSize += curSize; } } return S_OK; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.h0100777000000000000000000000477313761647206024157 0ustar00// LzmaDecoder.h #ifndef __LZMA_DECODER_H #define __LZMA_DECODER_H #include "../../../C/LzmaDec.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma { class CDecoder: public ICompressCoder, public ICompressSetDecoderProperties2, public ICompressSetBufSize, #ifndef NO_READ_FROM_CODER public ICompressSetInStream, public ICompressSetOutStreamSize, public ISequentialInStream, #endif public CMyUnknownImp { CMyComPtr _inStream; Byte *_inBuf; UInt32 _inPos; UInt32 _inSize; CLzmaDec _state; bool _propsWereSet; bool _outSizeDefined; UInt64 _outSize; UInt64 _inSizeProcessed; UInt64 _outSizeProcessed; UInt32 _inBufSizeAllocated; UInt32 _inBufSize; UInt32 _outBufSize; SizeT _wrPos; HRESULT CreateInputBuffer(); HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); void SetOutStreamSizeResume(const UInt64 *outSize); public: MY_QUERYINTERFACE_BEGIN2(ICompressCoder) MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2) MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize) #ifndef NO_READ_FROM_CODER MY_QUERYINTERFACE_ENTRY(ICompressSetInStream) MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize) MY_QUERYINTERFACE_ENTRY(ISequentialInStream) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size); STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size); #ifndef NO_READ_FROM_CODER STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(ReleaseInStream)(); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize); UInt64 GetInputProcessedSize() const { return _inSizeProcessed; } #endif bool FinishStream; // set it before decoding, if you need to decode full LZMA stream bool NeedMoreInput; // it's set by decoder, if it needs more input data to decode stream CDecoder(); virtual ~CDecoder(); UInt64 GetOutputProcessedSize() const { return _outSizeProcessed; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.cpp0100777000000000000000000001043713761647206024516 0ustar00// LzmaEncoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/CWrappers.h" #include "../Common/StreamUtils.h" #include "LzmaEncoder.h" namespace NCompress { namespace NLzma { static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } static void SzBigFree(void *, void *address) { BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CEncoder::CEncoder() { _encoder = 0; _encoder = LzmaEnc_Create(&g_Alloc); if (_encoder == 0) throw 1; } CEncoder::~CEncoder() { if (_encoder != 0) LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc); } inline wchar_t GetUpperChar(wchar_t c) { if (c >= 'a' && c <= 'z') c -= 0x20; return c; } static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) { wchar_t c = GetUpperChar(*s++); if (c == L'H') { if (GetUpperChar(*s++) != L'C') return 0; int numHashBytesLoc = (int)(*s++ - L'0'); if (numHashBytesLoc < 4 || numHashBytesLoc > 4) return 0; if (*s++ != 0) return 0; *btMode = 0; *numHashBytes = numHashBytesLoc; return 1; } if (c != L'B') return 0; if (GetUpperChar(*s++) != L'T') return 0; int numHashBytesLoc = (int)(*s++ - L'0'); if (numHashBytesLoc < 2 || numHashBytesLoc > 4) return 0; c = GetUpperChar(*s++); if (c != L'\0') return 0; *btMode = 1; *numHashBytes = numHashBytesLoc; return 1; } #define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break; HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) { if (propID == NCoderPropID::kMatchFinder) { if (prop.vt != VT_BSTR) return E_INVALIDARG; return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; } if (propID > NCoderPropID::kReduceSize) return S_OK; if (propID == NCoderPropID::kReduceSize) { if (prop.vt == VT_UI8) ep.reduceSize = prop.uhVal.QuadPart; return S_OK; } if (prop.vt != VT_UI4) return E_INVALIDARG; UInt32 v = prop.ulVal; switch (propID) { case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break; SET_PROP_32(kLevel, level) SET_PROP_32(kNumFastBytes, fb) SET_PROP_32(kMatchFinderCycles, mc) SET_PROP_32(kAlgorithm, algo) SET_PROP_32(kDictionarySize, dictSize) SET_PROP_32(kPosStateBits, pb) SET_PROP_32(kLitPosBits, lp) SET_PROP_32(kLitContextBits, lc) SET_PROP_32(kNumThreads, numThreads) default: return E_INVALIDARG; } return S_OK; } STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { CLzmaEncProps props; LzmaEncProps_Init(&props); for (UInt32 i = 0; i < numProps; i++) { const PROPVARIANT &prop = coderProps[i]; PROPID propID = propIDs[i]; switch (propID) { case NCoderPropID::kEndMarker: if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break; default: RINOK(SetLzmaProp(propID, prop, props)); } } return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); } STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte props[LZMA_PROPS_SIZE]; size_t size = LZMA_PROPS_SIZE; RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)); return WriteStream(outStream, props, size); } STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { CSeqInStreamWrap inWrap(inStream); CSeqOutStreamWrap outWrap(outStream); CCompressProgressWrap progressWrap(progress); SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc); _inputProcessed = inWrap.Processed; if (res == SZ_ERROR_READ && inWrap.Res != S_OK) return inWrap.Res; if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) return outWrap.Res; if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) return progressWrap.Res; return SResToHRESULT(res); } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.h0100777000000000000000000000165213761647206024162 0ustar00// LzmaEncoder.h #ifndef __LZMA_ENCODER_H #define __LZMA_ENCODER_H #include "../../../C/LzmaEnc.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma { class CEncoder: public ICompressCoder, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, public CMyUnknownImp { CLzmaEncHandle _encoder; UInt64 _inputProcessed; public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); CEncoder(); virtual ~CEncoder(); UInt64 GetInputProcessedSize() const { return _inputProcessed; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/LzmaRegister.cpp0100777000000000000000000000077513761647206024727 0ustar00// LzmaRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "LzmaDecoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); } #ifndef EXTRACT_ONLY #include "LzmaEncoder.h" static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CEncoder); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false }; REGISTER_CODEC(LZMA) qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoder.h0100777000000000000000000000736413761647206023776 0ustar00// Compress/RangeCoder.h // 2013-01-10 : Igor Pavlov : Public domain #ifndef __COMPRESS_RANGE_CODER_H #define __COMPRESS_RANGE_CODER_H #include "../Common/InBuffer.h" #include "../Common/OutBuffer.h" namespace NCompress { namespace NRangeCoder { const unsigned kNumTopBits = 24; const UInt32 kTopValue = (1 << kNumTopBits); class CEncoder { UInt32 _cacheSize; Byte _cache; public: UInt64 Low; UInt32 Range; COutBuffer Stream; bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); } void Init() { Stream.Init(); Low = 0; Range = 0xFFFFFFFF; _cacheSize = 1; _cache = 0; } void FlushData() { // Low += 1; for (int i = 0; i < 5; i++) ShiftLow(); } HRESULT FlushStream() { return Stream.Flush(); } void Encode(UInt32 start, UInt32 size, UInt32 total) { Low += start * (Range /= total); Range *= size; while (Range < kTopValue) { Range <<= 8; ShiftLow(); } } void ShiftLow() { if ((UInt32)Low < (UInt32)0xFF000000 || (unsigned)(Low >> 32) != 0) { Byte temp = _cache; do { Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32))); temp = 0xFF; } while (--_cacheSize != 0); _cache = (Byte)((UInt32)Low >> 24); } _cacheSize++; Low = (UInt32)Low << 8; } void EncodeDirectBits(UInt32 value, int numBits) { for (numBits--; numBits >= 0; numBits--) { Range >>= 1; Low += Range & (0 - ((value >> numBits) & 1)); if (Range < kTopValue) { Range <<= 8; ShiftLow(); } } } void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol) { UInt32 newBound = (Range >> numTotalBits) * size0; if (symbol == 0) Range = newBound; else { Low += newBound; Range -= newBound; } while (Range < kTopValue) { Range <<= 8; ShiftLow(); } } UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; } }; class CDecoder { public: CInBuffer Stream; UInt32 Range; UInt32 Code; bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } void Normalize() { while (Range < kTopValue) { Code = (Code << 8) | Stream.ReadByte(); Range <<= 8; } } void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); } void Init() { Stream.Init(); Code = 0; Range = 0xFFFFFFFF; for (int i = 0; i < 5; i++) Code = (Code << 8) | Stream.ReadByte(); } UInt32 GetThreshold(UInt32 total) { return (Code) / (Range /= total); } void Decode(UInt32 start, UInt32 size) { Code -= start * Range; Range *= size; Normalize(); } UInt32 DecodeDirectBits(int numTotalBits) { UInt32 range = Range; UInt32 code = Code; UInt32 result = 0; for (int i = numTotalBits; i != 0; i--) { range >>= 1; /* result <<= 1; if (code >= range) { code -= range; result |= 1; } */ UInt32 t = (code - range) >> 31; code -= range & (t - 1); result = (result << 1) | (1 - t); if (range < kTopValue) { code = (code << 8) | Stream.ReadByte(); range <<= 8; } } Range = range; Code = code; return result; } UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) { UInt32 newBound = (Range >> numTotalBits) * size0; UInt32 symbol; if (Code < newBound) { symbol = 0; Range = newBound; } else { symbol = 1; Code -= newBound; Range -= newBound; } Normalize(); return symbol; } UInt64 GetProcessedSize() { return Stream.GetProcessedSize(); } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoderBit.h0100777000000000000000000000553413761647206024432 0ustar00// Compress/RangeCoderBit.h // 2013-01-10 : Igor Pavlov : Public domain #ifndef __COMPRESS_RANGE_CODER_BIT_H #define __COMPRESS_RANGE_CODER_BIT_H #include "RangeCoder.h" namespace NCompress { namespace NRangeCoder { const unsigned kNumBitModelTotalBits = 11; const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits); const unsigned kNumMoveReducingBits = 4; const unsigned kNumBitPriceShiftBits = 4; const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits; extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; template class CBitModel { public: UInt32 Prob; void UpdateModel(UInt32 symbol) { /* Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits; Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits); */ if (symbol == 0) Prob += (kBitModelTotal - Prob) >> numMoveBits; else Prob -= (Prob) >> numMoveBits; } public: void Init() { Prob = kBitModelTotal / 2; } }; template class CBitEncoder: public CBitModel { public: void Encode(CEncoder *encoder, UInt32 symbol) { /* encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol); this->UpdateModel(symbol); */ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob; if (symbol == 0) { encoder->Range = newBound; this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; } else { encoder->Low += newBound; encoder->Range -= newBound; this->Prob -= (this->Prob) >> numMoveBits; } if (encoder->Range < kTopValue) { encoder->Range <<= 8; encoder->ShiftLow(); } } UInt32 GetPrice(UInt32 symbol) const { return ProbPrices[(this->Prob ^ ((-(int)(Int32)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; } UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; } UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; } }; template class CBitDecoder: public CBitModel { public: UInt32 Decode(CDecoder *decoder) { UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob; if (decoder->Code < newBound) { decoder->Range = newBound; this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; if (decoder->Range < kTopValue) { decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); decoder->Range <<= 8; } return 0; } else { decoder->Range -= newBound; decoder->Code -= newBound; this->Prob -= (this->Prob) >> numMoveBits; if (decoder->Range < kTopValue) { decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); decoder->Range <<= 8; } return 1; } } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/Guid.txt0100777000000000000000000000661213761647206021445 0ustar00{23170F69-40C1-278A-0000-00yy00xx0000} 00 IProgress.h 05 IProgress 01 IFolderArchive.h // 05 IArchiveFolder // old // 06 IInFolderArchive // old 07 IFileExtractCallback.h::IFolderArchiveExtractCallback // 0A IOutFolderArchive 0B IFolderArchiveUpdateCallback 0C Agent.h::IArchiveFolderInternal 0D IArchiveFolder 0E IInFolderArchive 0F IOutFolderArchive 20 IFileExtractCallback.h::IGetProp 30 IFileExtractCallback.h::IFolderExtractToStreamCallback 03 IStream.h 01 ISequentialInStream 02 ISequentialOutStream 03 IInStream 04 IOutStream 06 IStreamGetSize 07 IOutStreamFlush 08 IStreamGetProps 09 IStreamGetProps2 04 ICoder.h 04 ICompressProgressInfo 05 ICompressCoder 18 ICompressCoder2 20 ICompressSetCoderProperties 21 ICompressSetDecoderProperties // 22 ICompressSetDecoderProperties2 23 ICompressWriteCoderProperties 24 ICompressGetInStreamProcessedSize 25 ICompressSetCoderMt 30 ICompressGetSubStreamSize 31 ICompressSetInStream 32 ICompressSetOutStream 33 ICompressSetInStreamSize 34 ICompressSetOutStreamSize 35 ICompressSetBufSize 40 ICompressFilter 60 ICompressCodecsInfo 61 ISetCompressCodecsInfo 80 ICryptoProperties 88 ICryptoResetSalt 8C ICryptoResetInitVector 90 ICryptoSetPassword A0 ICryptoSetCRC C0 IHasher C1 IHashers 05 IPassword.h 10 ICryptoGetTextPassword 11 ICryptoGetTextPassword2 06 IArchive.h 03 ISetProperties 04 IArchiveKeepModeForNextOpen 05 IArchiveAllowTail 10 IArchiveOpenCallback 20 IArchiveExtractCallback 30 IArchiveOpenVolumeCallback 40 IInArchiveGetStream 50 IArchiveOpenSetSubArchiveName 60 IInArchive 61 IArchiveOpenSeq 70 IArchiveGetRawProps 71 IArchiveGetRootProps 80 IArchiveUpdateCallback 82 IArchiveUpdateCallback2 A0 IOutArchive 08 IFolder.h 00 IFolderFolder 01 IEnumProperties 02 IFolderGetTypeID 03 IFolderGetPath 04 IFolderWasChanged 05 // IFolderReload 06 // IFolderOperations old 07 IFolderGetSystemIconIndex 08 IFolderGetItemFullSize 09 IFolderClone 0A IFolderSetFlatMode 0B IFolderOperationsExtractCallback 0C // 0D // 0E IFolderProperties 0F 10 IFolderArcProps 11 IGetFolderArcProps 12 // IFolderOperations 13 IFolderOperations 14 IFolderCalcItemFullSize 15 IFolderCompare 16 IFolderGetItemName 09 IFolder.h :: FOLDER_MANAGER_INTERFACE 00 - 04 // old IFolderManager 05 IFolderManager // 0A PluginInterface.h 00 IInitContextMenu 01 IPluginOptionsCallback 02 IPluginOptions Handler GUIDs: {23170F69-40C1-278A-1000-000110xx0000} 01 Zip 02 BZip2 03 Rar 04 Arj 05 Z 06 Lzh 07 7z 08 Cab 09 Nsis 0A lzma 0B lzma86 0C xz 0D ppmd CD IHex CE Hxs CF TE D0 UEFIc D1 UEFIs D2 SquashFS D3 CramFS D4 APM D5 Mslz D6 Flv D7 Swf D8 Swfc D9 Ntfs DA Fat DB Mbr DC Vhd DD Pe DE Elf DF Mach-O E0 Udf E1 Xar E2 Mub E3 Hfs E4 Dmg E5 Compound E6 Wim E7 Iso E8 E9 Chm EA Split EB Rpm EC Deb ED Cpio EE Tar EF GZip {23170F69-40C1-278A-1000-000100030000} CAgentArchiveHandle {23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu {23170F69-40C1-278B- old codecs clsids {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions {23170F69-40C1-2790-id} Codec Decoders {23170F69-40C1-2791-id} Codec Encoders {23170F69-40C1-2792-id} Hashers qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/ICoder.h0100777000000000000000000001223113761647206021324 0ustar00// ICoder.h #ifndef __ICODER_H #define __ICODER_H #include "IStream.h" #define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x) CODER_INTERFACE(ICompressProgressInfo, 0x04) { STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE; }; CODER_INTERFACE(ICompressCoder, 0x05) { STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) PURE; }; CODER_INTERFACE(ICompressCoder2, 0x18) { STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) PURE; }; namespace NCoderPropID { enum EEnum { kDefaultProp = 0, kDictionarySize, kUsedMemorySize, kOrder, kBlockSize, kPosStateBits, kLitContextBits, kLitPosBits, kNumFastBytes, kMatchFinder, kMatchFinderCycles, kNumPasses, kAlgorithm, kNumThreads, kEndMarker, kLevel, kReduceSize // estimated size of data that will be compressed. Encoder can use this value to reduce dictionary size. }; } CODER_INTERFACE(ICompressSetCoderProperties, 0x20) { STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE; }; /* CODER_INTERFACE(ICompressSetCoderProperties, 0x21) { STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE; }; */ CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22) { STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE; }; CODER_INTERFACE(ICompressWriteCoderProperties, 0x23) { STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE; }; CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24) { STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE; }; CODER_INTERFACE(ICompressSetCoderMt, 0x25) { STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE; }; CODER_INTERFACE(ICompressGetSubStreamSize, 0x30) { STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE; }; CODER_INTERFACE(ICompressSetInStream, 0x31) { STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE; STDMETHOD(ReleaseInStream)() PURE; }; CODER_INTERFACE(ICompressSetOutStream, 0x32) { STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE; STDMETHOD(ReleaseOutStream)() PURE; }; CODER_INTERFACE(ICompressSetInStreamSize, 0x33) { STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE; }; CODER_INTERFACE(ICompressSetOutStreamSize, 0x34) { STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE; }; CODER_INTERFACE(ICompressSetBufSize, 0x35) { STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE; STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE; }; CODER_INTERFACE(ICompressFilter, 0x40) { STDMETHOD(Init)() PURE; STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE; // Filter converts as most as possible bytes // Filter return outSize (UInt32) // if (outSize <= size): Filter have converted outSize bytes // if (outSize > size): Filter have not converted anything. // and it needs at least outSize bytes to convert one block // (it's for crypto block algorithms). }; CODER_INTERFACE(ICompressCodecsInfo, 0x60) { STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods) PURE; STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE; STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE; }; CODER_INTERFACE(ISetCompressCodecsInfo, 0x61) { STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE; }; CODER_INTERFACE(ICryptoProperties, 0x80) { STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE; STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE; }; /* CODER_INTERFACE(ICryptoResetSalt, 0x88) { STDMETHOD(ResetSalt)() PURE; }; */ CODER_INTERFACE(ICryptoResetInitVector, 0x8C) { STDMETHOD(ResetInitVector)() PURE; }; CODER_INTERFACE(ICryptoSetPassword, 0x90) { STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE; }; CODER_INTERFACE(ICryptoSetCRC, 0xA0) { STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE; }; ////////////////////// // It's for DLL file namespace NMethodPropID { enum EEnum { kID, kName, kDecoder, kEncoder, kInStreams, kOutStreams, kDescription, kDecoderIsAssigned, kEncoderIsAssigned, kDigestSize }; } CODER_INTERFACE(IHasher, 0xC0) { STDMETHOD_(void, Init)() PURE; STDMETHOD_(void, Update)(const void *data, UInt32 size) PURE; STDMETHOD_(void, Final)(Byte *digest) PURE; STDMETHOD_(UInt32, GetDigestSize)() PURE; }; CODER_INTERFACE(IHashers, 0xC1) { STDMETHOD_(UInt32, GetNumHashers)() PURE; STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher) PURE; }; extern "C" { typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods); typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/IDecl.h0100777000000000000000000000054013761647206021137 0ustar00// IDecl.h #ifndef __IDECL_H #define __IDECL_H #include "../Common/MyUnknown.h" #define DECL_INTERFACE_SUB(i, base, groupId, subId) \ DEFINE_GUID(IID_ ## i, \ 0x23170F69, 0x40C1, 0x278A, 0, 0, 0, (groupId), 0, (subId), 0, 0); \ struct i: public base #define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/IPassword.h0100777000000000000000000000071713761647206022100 0ustar00// IPassword.h #ifndef __IPASSWORD_H #define __IPASSWORD_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x) PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10) { STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE; }; PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11) { STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/IProgress.h0100777000000000000000000000132413761647206022075 0ustar00// Interface/IProgress.h #ifndef __IPROGRESS_H #define __IPROGRESS_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define INTERFACE_IProgress(x) \ STDMETHOD(SetTotal)(UInt64 total) x; \ STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \ DECL_INTERFACE(IProgress, 0, 5) { INTERFACE_IProgress(PURE) }; /* // {23170F69-40C1-278A-0000-000000050002} DEFINE_GUID(IID_IProgress2, 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02); MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002") IProgress2: public IUnknown { public: STDMETHOD(SetTotal)(const UInt64 *total) PURE; STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; }; */ #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/IStream.h0100777000000000000000000000710613761647206021530 0ustar00// IStream.h #ifndef __ISTREAM_H #define __ISTREAM_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x) #define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x) STREAM_INTERFACE(ISequentialInStream, 0x01) { STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE; /* The requirement for caller: (processedSize != NULL). The callee can allow (processedSize == NULL) for compatibility reasons. if (size == 0), this function returns S_OK and (*processedSize) is set to 0. if (size != 0) { Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size), where (avail_size) is the size of remaining bytes in stream. If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0). You must call Read() in loop, if you need to read exact amount of data. } If seek pointer before Read() call was changed to position past the end of stream: if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0. ERROR CASES: If the function returns error code, then (*processedSize) is size of data written to (data) buffer (it can be data before error or data with errors). The recommended way for callee to work with reading errors: 1) write part of data before error to (data) buffer and return S_OK. 2) return error code for further calls of Read(). */ }; STREAM_INTERFACE(ISequentialOutStream, 0x02) { STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE; /* The requirement for caller: (processedSize != NULL). The callee can allow (processedSize == NULL) for compatibility reasons. if (size != 0) { Partial write is allowed: (*processedSize <= size), but this function must write at least 1 byte: (*processedSize > 0). You must call Write() in loop, if you need to write exact amount of data. } ERROR CASES: If the function returns error code, then (*processedSize) is size of data written from (data) buffer. */ }; #ifdef __HRESULT_FROM_WIN32 #define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) #else #define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) #endif /* Seek() Function If you seek before the beginning of the stream, Seek() function returns error code: Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK). or STG_E_INVALIDFUNCTION It is allowed to seek past the end of the stream. if Seek() returns error, then the value of *newPosition is undefined. */ STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; }; STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; STDMETHOD(SetSize)(UInt64 newSize) PURE; }; STREAM_INTERFACE(IStreamGetSize, 0x06) { STDMETHOD(GetSize)(UInt64 *size) PURE; }; STREAM_INTERFACE(IOutStreamFlush, 0x07) { STDMETHOD(Flush)() PURE; }; STREAM_INTERFACE(IStreamGetProps, 0x08) { STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) PURE; }; struct CStreamFileProps { UInt64 Size; UInt64 VolID; UInt64 FileID_Low; UInt64 FileID_High; UInt32 NumLinks; UInt32 Attrib; FILETIME CTime; FILETIME ATime; FILETIME MTime; }; STREAM_INTERFACE(IStreamGetProps2, 0x09) { STDMETHOD(GetProps2)(CStreamFileProps *props) PURE; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/PropID.h0100777000000000000000000000465513761647206021327 0ustar00// PropID.h #ifndef __7ZIP_PROP_ID_H #define __7ZIP_PROP_ID_H #include "../Common/MyTypes.h" enum { kpidNoProperty = 0, kpidMainSubfile, kpidHandlerItemIndex, kpidPath, kpidName, kpidExtension, kpidIsDir, kpidSize, kpidPackSize, kpidAttrib, kpidCTime, kpidATime, kpidMTime, kpidSolid, kpidCommented, kpidEncrypted, kpidSplitBefore, kpidSplitAfter, kpidDictionarySize, kpidCRC, kpidType, kpidIsAnti, kpidMethod, kpidHostOS, kpidFileSystem, kpidUser, kpidGroup, kpidBlock, kpidComment, kpidPosition, kpidPrefix, kpidNumSubDirs, kpidNumSubFiles, kpidUnpackVer, kpidVolume, kpidIsVolume, kpidOffset, kpidLinks, kpidNumBlocks, kpidNumVolumes, kpidTimeType, kpidBit64, kpidBigEndian, kpidCpu, kpidPhySize, kpidHeadersSize, kpidChecksum, kpidCharacts, kpidVa, kpidId, kpidShortName, kpidCreatorApp, kpidSectorSize, kpidPosixAttrib, kpidSymLink, kpidError, kpidTotalSize, kpidFreeSpace, kpidClusterSize, kpidVolumeName, kpidLocalName, kpidProvider, kpidNtSecure, kpidIsAltStream, kpidIsAux, kpidIsDeleted, kpidIsTree, kpidSha1, kpidSha256, kpidErrorType, kpidNumErrors, kpidErrorFlags, kpidWarningFlags, kpidWarning, kpidNumStreams, kpidNumAltStreams, kpidAltStreamsSize, kpidVirtualSize, kpidUnpackSize, kpidTotalPhySize, kpidVolumeIndex, kpidSubType, kpidShortComment, kpidCodePage, kpidIsNotArcType, kpidPhySizeCantBeDetected, kpidZerosTailIsAllowed, kpidTailSize, kpidEmbeddedStubSize, kpidNtReparse, kpidHardLink, kpidINode, kpidStreamId, kpid_NUM_DEFINED, kpidUserDefined = 0x10000 }; extern Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0; const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1; const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2; const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3; const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4; const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5; const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6; const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7; const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8; const UInt32 kpv_ErrorFlags_DataError = 1 << 9; const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; // const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/0040777000000000000000000000000013761647206020324 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/0040777000000000000000000000000013761647206021554 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp0100777000000000000000000010664613761647206025765 0ustar00// ArchiveCommandLine.cpp #include "StdAfx.h" #undef printf #undef sprintf #ifdef _WIN32 #ifndef UNDER_CE #include #endif #endif #include #include "../../../Common/ListFileUtils.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileName.h" #ifdef _WIN32 #include "../../../Windows/FileMapping.h" #include "../../../Windows/Synchronization.h" #else #include "myPrivate.h" #endif #include "ArchiveCommandLine.h" #include "EnumDirItems.h" #include "SortUtils.h" #include "Update.h" #include "UpdateAction.h" extern bool g_CaseSensitive; #ifdef UNDER_CE #define MY_IS_TERMINAL(x) false; #else #if _MSC_VER >= 1400 #define MY_isatty_fileno(x) _isatty(_fileno(x)) #else #define MY_isatty_fileno(x) isatty(fileno(x)) #endif #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); #endif using namespace NCommandLineParser; using namespace NWindows; using namespace NFile; static bool StringToUInt32(const wchar_t *s, UInt32 &v) { if (*s == 0) return false; const wchar_t *end; v = ConvertStringToUInt32(s, &end); return *end == 0; } static void AddNewLine(UString &s) { s += L'\n'; } CArcCmdLineException::CArcCmdLineException(const char *a, const wchar_t *u) { (*this) += MultiByteToUnicodeString(a); if (u) { AddNewLine(*this); (*this) += u; } } int g_CodePage = -1; namespace NKey { enum Enum { kHelp1 = 0, kHelp2, kHelp3, kDisableHeaders, kDisablePercents, kArchiveType, kYes, #ifndef _NO_CRYPTO kPassword, #endif kProperty, kOutputDir, kWorkingDir, kInclude, kExclude, kArInclude, kArExclude, kNoArName, kUpdate, kVolume, kRecursed, kSfx, kStdIn, kStdOut, kOverwrite, kEmail, kShowDialog, kLargePages, // kListfileCharSet, // kConsoleCharSet, kTechMode, #ifdef _WIN32 kShareForWrite, #endif kUseLStat, kCaseSensitive, kHash, kArcNameMode, kDisableWildcardParsing, kElimDup, kFullPathMode, kHardLinks, kSymLinks, kNtSecurity, kAltStreams, kReplaceColonForAltStream, kWriteToAltStreamIfColon, kDeleteAfterCompressing, kSetArcMTime, kExcludedArcType }; } static const wchar_t kRecursedIDChar = 'r'; static const char *kRecursedPostCharSet = "0-"; static const char *k_ArcNameMode_PostCharSet = "sea"; static inline const EArcNameMode ParseArcNameMode(int postCharIndex) { switch (postCharIndex) { case 1: return k_ArcNameMode_Exact; case 2: return k_ArcNameMode_Add; default: return k_ArcNameMode_Smart; } } namespace NRecursedPostCharIndex { enum EEnum { kWildcardRecursionOnly = 0, kNoRecursion = 1 }; } static const char kImmediateNameID = '!'; static const char kMapNameID = '#'; static const char kFileListID = '@'; static const char kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be static const char *kOverwritePostCharSet = "asut"; NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = { NExtract::NOverwriteMode::kOverwrite, NExtract::NOverwriteMode::kSkip, NExtract::NOverwriteMode::kRename, NExtract::NOverwriteMode::kRenameExisting }; static const CSwitchForm kSwitchForms[] = { { "?" }, { "h" }, { "-help" }, { "ba" }, { "bd" }, { "t", NSwitchType::kString, false, 1 }, { "y" }, #ifndef _NO_CRYPTO { "p", NSwitchType::kString }, #endif { "m", NSwitchType::kString, true, 1 }, { "o", NSwitchType::kString, false, 1 }, { "w", NSwitchType::kString }, { "i", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "x", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "an" }, { "u", NSwitchType::kString, true, 1}, { "v", NSwitchType::kString, true, 1}, { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, { "sfx", NSwitchType::kString }, { "si", NSwitchType::kString }, { "so" }, { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, { "seml", NSwitchType::kString, false, 0}, { "ad" }, { "slp", NSwitchType::kMinus }, // { "scs", NSwitchType::kString }, // { "scc", NSwitchType::kString }, { "slt" }, // { "ssw" }, { "l" }, { "ssc", NSwitchType::kMinus }, { "scrc", NSwitchType::kString, true, 0 }, { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, { "spd" }, { "spe", NSwitchType::kMinus }, { "spf", NSwitchType::kString, false, 0 }, { "snh", NSwitchType::kMinus }, { "snl", NSwitchType::kMinus }, { "sni" }, { "sns", NSwitchType::kMinus }, { "snr" }, { "snc" }, { "sdel" }, { "stl" }, { "stx", NSwitchType::kString, true, 1 } }; static const wchar_t *kUniversalWildcard = L"*"; static const int kMinNonSwitchWords = 1; static const int kCommandIndex = 0; // static const char *kUserErrorMessage = "Incorrect command line"; static const char *kCannotFindListFile = "Cannot find listfile"; static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; static const char *kIncorrectWildcardInListFile = "Incorrect wildcard in listfile"; static const char *kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line"; static const char *kTerminalOutError = "I won't write compressed data to a terminal"; static const char *kSameTerminalError = "I won't write data and program's messages to same terminal"; static const char *kEmptyFilePath = "Empty file path"; static const char *kCannotFindArchive = "Cannot find archive"; bool CArcCommand::IsFromExtractGroup() const { switch (CommandType) { case NCommandType::kTest: case NCommandType::kExtract: case NCommandType::kExtractFull: return true; } return false; } NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const { switch (CommandType) { case NCommandType::kTest: case NCommandType::kExtractFull: return NExtract::NPathMode::kFullPaths; } return NExtract::NPathMode::kNoPaths; } bool CArcCommand::IsFromUpdateGroup() const { switch (CommandType) { case NCommandType::kAdd: case NCommandType::kUpdate: case NCommandType::kDelete: case NCommandType::kRename: return true; } return false; } static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) { switch (index) { case NRecursedPostCharIndex::kWildcardRecursionOnly: return NRecursedType::kWildcardOnlyRecursed; case NRecursedPostCharIndex::kNoRecursion: return NRecursedType::kNonRecursed; default: return NRecursedType::kRecursed; } } static const char *g_Commands = "audtexlbih"; static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) { UString s = commandString; s.MakeLower_Ascii(); if (s.Len() == 1) { if (s[0] > 0x7F) return false; int index = FindCharPosInString(g_Commands, (char)s[0]); if (index < 0) return false; command.CommandType = (NCommandType::EEnum)index; return true; } if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n') { command.CommandType = (NCommandType::kRename); return true; } return false; } // ------------------------------------------------------------------ // filenames functions static void AddNameToCensor(NWildcard::CCensor &censor, const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching) { bool recursed = false; switch (type) { case NRecursedType::kWildcardOnlyRecursed: recursed = DoesNameContainWildcard(name); break; case NRecursedType::kRecursed: recursed = true; break; } censor.AddPreItem(include, name, recursed, wildcardMatching); } static void AddRenamePair(CObjectVector *renamePairs, const UString &oldName, const UString &newName, NRecursedType::EEnum type, bool wildcardMatching) { CRenamePair &pair = renamePairs->AddNew(); pair.OldName = oldName; pair.NewName = newName; pair.RecursedType = type; pair.WildcardParsing = wildcardMatching; if (!pair.Prepare()) { UString val; val += pair.OldName; AddNewLine(val); val += pair.NewName; AddNewLine(val); if (type == NRecursedType::kRecursed) val += L"-r"; else if (type == NRecursedType::kRecursed) val += L"-r0"; throw CArcCmdLineException("Unsupported rename command:", val); } } static void AddToCensorFromListFile( CObjectVector *renamePairs, NWildcard::CCensor &censor, LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage) { UStringVector names; if (!NFind::DoesFileExist(us2fs(fileName))) throw CArcCmdLineException(kCannotFindListFile, fileName); if (!ReadNamesFromListFile(us2fs(fileName), names, codePage)) throw CArcCmdLineException(kIncorrectListFile, fileName); if (renamePairs) { if ((names.Size() & 1) != 0) throw CArcCmdLineException(kIncorrectListFile, fileName); for (unsigned i = 0; i < names.Size(); i += 2) { // change type !!!! AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching); } } else FOR_VECTOR (i, names) AddNameToCensor(censor, names[i], include, type, wildcardMatching); } static void AddToCensorFromNonSwitchesStrings( CObjectVector *renamePairs, unsigned startIndex, NWildcard::CCensor &censor, const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, bool wildcardMatching, bool thereAreSwitchIncludes, Int32 codePage) { if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) AddNameToCensor(censor, kUniversalWildcard, true, type, true // wildcardMatching ); int oldIndex = -1; for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++) { const UString &s = nonSwitchStrings[i]; if (s.IsEmpty()) throw CArcCmdLineException(kEmptyFilePath); if (s[0] == kFileListID) AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage); else if (renamePairs) { if (oldIndex == -1) oldIndex = startIndex; else { // NRecursedType::EEnum type is used for global wildcard (-i! switches) AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching); // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); oldIndex = -1; } } else AddNameToCensor(censor, s, true, type, wildcardMatching); } if (oldIndex != -1) { throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]); } } #ifdef _WIN32 struct CEventSetEnd { UString Name; CEventSetEnd(const wchar_t *name): Name(name) {} ~CEventSetEnd() { NSynchronization::CManualResetEvent event; if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) event.Set(); } }; const char *k_IncorrectMapCommand = "Incorrect Map command"; static const char *ParseMapWithPaths( NWildcard::CCensor &censor, const UString &s2, bool include, NRecursedType::EEnum commonRecursedType, bool wildcardMatching) { UString s = s2; int pos = s.Find(L':'); if (pos < 0) return k_IncorrectMapCommand; int pos2 = s.Find(L':', pos + 1); if (pos2 < 0) return k_IncorrectMapCommand; CEventSetEnd eventSetEnd((const wchar_t *)s + (pos2 + 1)); s.DeleteFrom(pos2); UInt32 size; if (!StringToUInt32(s.Ptr(pos + 1), size) || size < sizeof(wchar_t) || size > ((UInt32)1 << 31) || size % sizeof(wchar_t) != 0) return "Unsupported Map data size"; s.DeleteFrom(pos); CFileMapping map; if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0) return "Can not open mapping"; LPVOID data = map.Map(FILE_MAP_READ, 0, size); if (!data) return "MapViewOfFile error"; CFileUnmapper unmapper(data); UString name; const wchar_t *p = (const wchar_t *)data; if (*p != 0) // data format marker return "Unsupported Map data"; UInt32 numChars = size / sizeof(wchar_t); for (UInt32 i = 1; i < numChars; i++) { wchar_t c = p[i]; if (c == 0) { // MessageBoxW(0, name, L"7-Zip", 0); AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching); name.Empty(); } else name += c; } if (!name.IsEmpty()) return "Map data error"; return NULL; } #endif static void AddSwitchWildcardsToCensor( NWildcard::CCensor &censor, const UStringVector &strings, bool include, NRecursedType::EEnum commonRecursedType, bool wildcardMatching, Int32 codePage) { const char *errorMessage = NULL; unsigned i; for (i = 0; i < strings.Size(); i++) { const UString &name = strings[i]; NRecursedType::EEnum recursedType; unsigned pos = 0; if (name.Len() < kSomeCludePostStringMinSize) { errorMessage = "Too short switch"; break; } if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar) { pos++; wchar_t c = name[pos]; int index = -1; if (c <= 0x7F) index = FindCharPosInString(kRecursedPostCharSet, (char)c); recursedType = GetRecursedTypeFromIndex(index); if (index >= 0) pos++; } else recursedType = commonRecursedType; if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) { errorMessage = "Too short switch"; break; } UString tail = name.Ptr(pos + 1); if (name[pos] == kImmediateNameID) AddNameToCensor(censor, tail, include, recursedType, wildcardMatching); else if (name[pos] == kFileListID) AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage); #ifdef _WIN32 else if (name[pos] == kMapNameID) { errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching); if (errorMessage) break; } #endif else { errorMessage = "Incorrect wildcarc type marker"; break; } } if (i != strings.Size()) throw CArcCmdLineException(errorMessage, strings[i]); } #ifdef _WIN32 // This code converts all short file names to long file names. static void ConvertToLongName(const UString &prefix, UString &name) { if (name.IsEmpty() || DoesNameContainWildcard(name)) return; NFind::CFileInfo fi; const FString path = us2fs(prefix + name); if (NFile::NName::IsDevicePath(path)) return; if (fi.Find(path)) name = fs2us(fi.Name); } static void ConvertToLongNames(const UString &prefix, CObjectVector &items) { FOR_VECTOR (i, items) { NWildcard::CItem &item = items[i]; if (item.Recursive || item.PathParts.Size() != 1) continue; if (prefix.IsEmpty() && item.IsDriveItem()) continue; ConvertToLongName(prefix, item.PathParts.Front()); } } static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) { ConvertToLongNames(prefix, node.IncludeItems); ConvertToLongNames(prefix, node.ExcludeItems); unsigned i; for (i = 0; i < node.SubNodes.Size(); i++) { UString &name = node.SubNodes[i].Name; if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name)) continue; ConvertToLongName(prefix, name); } // mix folders with same name for (i = 0; i < node.SubNodes.Size(); i++) { NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; for (unsigned j = i + 1; j < node.SubNodes.Size();) { const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; if (nextNode1.Name.IsEqualToNoCase(nextNode2.Name)) { nextNode1.IncludeItems += nextNode2.IncludeItems; nextNode1.ExcludeItems += nextNode2.ExcludeItems; node.SubNodes.Delete(j); } else j++; } } for (i = 0; i < node.SubNodes.Size(); i++) { NWildcard::CCensorNode &nextNode = node.SubNodes[i]; ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode); } } void ConvertToLongNames(NWildcard::CCensor &censor) { FOR_VECTOR (i, censor.Pairs) { NWildcard::CPair &pair = censor.Pairs[i]; ConvertToLongNames(pair.Prefix, pair.Head); } } #endif /* static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) { switch (i) { case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore; case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy; case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress; case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti; } throw 98111603; } */ static const wchar_t *kUpdatePairStateIDSet = L"pqrxyzw"; static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; static const unsigned kNumUpdatePairActions = 4; static const char *kUpdateIgnoreItselfPostStringID = "-"; static const wchar_t kUpdateNewArchivePostCharID = '!'; static bool ParseUpdateCommandString2(const UString &command, NUpdateArchive::CActionSet &actionSet, UString &postString) { for (unsigned i = 0; i < command.Len();) { wchar_t c = MyCharLower_Ascii(command[i]); int statePos = FindCharPosInString(kUpdatePairStateIDSet, c); if (statePos < 0) { postString = command.Ptr(i); return true; } i++; if (i >= command.Len()) return false; c = command[i]; if (c < '0' || c >= '0' + kNumUpdatePairActions) return false; int actionPos = c - '0'; actionSet.StateActions[statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos); if (kUpdatePairStateNotSupportedActions[statePos] == actionPos) return false; i++; } postString.Empty(); return true; } static void ParseUpdateCommandString(CUpdateOptions &options, const UStringVector &updatePostStrings, const NUpdateArchive::CActionSet &defaultActionSet) { const char *errorMessage = "incorrect update switch command"; unsigned i; for (i = 0; i < updatePostStrings.Size(); i++) { const UString &updateString = updatePostStrings[i]; if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID)) { if (options.UpdateArchiveItself) { options.UpdateArchiveItself = false; options.Commands.Delete(0); } } else { NUpdateArchive::CActionSet actionSet = defaultActionSet; UString postString; if (!ParseUpdateCommandString2(updateString, actionSet, postString)) break; if (postString.IsEmpty()) { if (options.UpdateArchiveItself) options.Commands[0].ActionSet = actionSet; } else { if (postString[0] != kUpdateNewArchivePostCharID) break; CUpdateArchiveCommand uc; UString archivePath = postString.Ptr(1); if (archivePath.IsEmpty()) break; uc.UserArchivePath = archivePath; uc.ActionSet = actionSet; options.Commands.Add(uc); } } } if (i != updatePostStrings.Size()) throw CArcCmdLineException(errorMessage, updatePostStrings[i]); } bool ParseComplexSize(const wchar_t *s, UInt64 &result); static void SetAddCommandOptions( NCommandType::EEnum commandType, const CParser &parser, CUpdateOptions &options) { NUpdateArchive::CActionSet defaultActionSet; switch (commandType) { case NCommandType::kAdd: defaultActionSet = NUpdateArchive::k_ActionSet_Add; break; case NCommandType::kDelete: defaultActionSet = NUpdateArchive::k_ActionSet_Delete; break; default: defaultActionSet = NUpdateArchive::k_ActionSet_Update; } options.UpdateArchiveItself = true; options.Commands.Clear(); CUpdateArchiveCommand updateMainCommand; updateMainCommand.ActionSet = defaultActionSet; options.Commands.Add(updateMainCommand); if (parser[NKey::kUpdate].ThereIs) ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, defaultActionSet); if (parser[NKey::kWorkingDir].ThereIs) { const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; if (postString.IsEmpty()) NDir::MyGetTempPath(options.WorkingDir); else options.WorkingDir = us2fs(postString); } options.SfxMode = parser[NKey::kSfx].ThereIs; if (options.SfxMode) options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); if (parser[NKey::kVolume].ThereIs) { const UStringVector &sv = parser[NKey::kVolume].PostStrings; FOR_VECTOR (i, sv) { UInt64 size; if (!ParseComplexSize(sv[i], size) || size == 0) throw CArcCmdLineException("Incorrect volume size:", sv[i]); options.VolumesSizes.Add(size); } } } static void SetMethodOptions(const CParser &parser, CObjectVector &properties) { if (parser[NKey::kProperty].ThereIs) { FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) { CProperty prop; prop.Name = parser[NKey::kProperty].PostStrings[i]; int index = prop.Name.Find(L'='); if (index >= 0) { prop.Value = prop.Name.Ptr(index + 1); prop.Name.DeleteFrom(index); } properties.Add(prop); } } } CArcCmdLineParser::CArcCmdLineParser(): parser(ARRAY_SIZE(kSwitchForms)) {} void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options) { if (!parser.ParseStrings(kSwitchForms, commandStrings)) throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); options.IsInTerminal = MY_IS_TERMINAL(stdin); options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); options.StdInMode = parser[NKey::kStdIn].ThereIs; options.StdOutMode = parser[NKey::kStdOut].ThereIs; options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; if (parser[NKey::kCaseSensitive].ThereIs) { g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; options.CaseSensitiveChange = true; options.CaseSensitive = g_CaseSensitive; } #ifdef _7ZIP_LARGE_PAGES options.LargePages = false; if (parser[NKey::kLargePages].ThereIs) { options.LargePages = !parser[NKey::kLargePages].WithMinus; } #endif } struct CCodePagePair { const char *Name; Int32 CodePage; }; static const unsigned kNumByteOnlyCodePages = 3; static CCodePagePair g_CodePagePairs[] = { { "utf-8", CP_UTF8 }, { "win", CP_ACP }, { "dos", CP_OEMCP }, { "utf-16le", MY__CP_UTF16 }, { "utf-16be", MY__CP_UTF16BE } }; static Int32 FindCharset(const NCommandLineParser::CParser &parser, int keyIndex, bool byteOnlyCodePages, Int32 defaultVal) { if (!parser[keyIndex].ThereIs) return defaultVal; UString name = parser[keyIndex].PostStrings.Back(); UInt32 v; if (StringToUInt32(name, v)) if (v < ((UInt32)1 << 16)) return (Int32)v; name.MakeLower_Ascii(); unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs); for (unsigned i = 0;; i++) { if (i == num) // to disable warnings from different compilers throw CArcCmdLineException("Unsupported charset:", name); const CCodePagePair &pair = g_CodePagePairs[i]; if (name.IsEqualTo(pair.Name)) return pair.CodePage; } } void EnumerateDirItemsAndSort( bool storeAltStreams, NWildcard::CCensor &censor, NWildcard::ECensorPathMode censorPathMode, const UString &addPathPrefix, UStringVector &sortedPaths, UStringVector &sortedFullPaths) { UStringVector paths; { CDirItems dirItems; { dirItems.ScanAltStreams = storeAltStreams; HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems, NULL); if (res != S_OK || dirItems.ErrorPaths.Size() > 0) { UString errorPath; if (dirItems.ErrorPaths.Size() > 0) errorPath = fs2us(dirItems.ErrorPaths[0]); throw CArcCmdLineException(kCannotFindArchive, dirItems.ErrorPaths.Size() > 0 ? (const wchar_t *)errorPath : NULL); } } FOR_VECTOR (i, dirItems.Items) { const CDirItem &dirItem = dirItems.Items[i]; if (!dirItem.IsDir()) paths.Add(dirItems.GetPhyPath(i)); } } if (paths.Size() == 0) throw CArcCmdLineException(kCannotFindArchive); UStringVector fullPaths; unsigned i; for (i = 0; i < paths.Size(); i++) { FString fullPath; NFile::NDir::MyGetFullPathName(us2fs(paths[i]), fullPath); fullPaths.Add(fs2us(fullPath)); } CUIntVector indices; SortFileNames(fullPaths, indices); sortedPaths.ClearAndReserve(indices.Size()); sortedFullPaths.ClearAndReserve(indices.Size()); for (i = 0; i < indices.Size(); i++) { unsigned index = indices[i]; sortedPaths.AddInReserved(paths[index]); sortedFullPaths.AddInReserved(fullPaths[index]); if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0) throw CArcCmdLineException("Duplicate archive path:", sortedFullPaths[i]); } } static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) { bp.Def = parser[switchID].ThereIs; if (bp.Def) bp.Val = !parser[switchID].WithMinus; } void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) { const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; int numNonSwitchStrings = nonSwitchStrings.Size(); if (numNonSwitchStrings < kMinNonSwitchWords) throw CArcCmdLineException("The command must be spcified"); if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); options.TechMode = parser[NKey::kTechMode].ThereIs; if (parser[NKey::kHash].ThereIs) options.HashMethods = parser[NKey::kHash].PostStrings; if (parser[NKey::kElimDup].ThereIs) { options.ExtractOptions.ElimDup.Def = true; options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; } NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; if (fullPathMode) { censorPathMode = NWildcard::k_AbsPath; const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; if (!s.IsEmpty()) { if (s == L"2") censorPathMode = NWildcard::k_FullPath; else throw CArcCmdLineException("Unsupported -spf:", s); } } NRecursedType::EEnum recursedType; if (parser[NKey::kRecursed].ThereIs) recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); else recursedType = NRecursedType::kNonRecursed; bool wildcardMatching = true; if (parser[NKey::kDisableWildcardParsing].ThereIs) wildcardMatching = false; Int32 codePage = CP_ACP; bool thereAreSwitchIncludes = false; if (parser[NKey::kInclude].ThereIs) { thereAreSwitchIncludes = true; AddSwitchWildcardsToCensor(options.Censor, parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage); } if (parser[NKey::kExclude].ThereIs) AddSwitchWildcardsToCensor(options.Censor, parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage); int curCommandIndex = kCommandIndex + 1; bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && options.Command.CommandType != NCommandType::kBenchmark && options.Command.CommandType != NCommandType::kInfo && options.Command.CommandType != NCommandType::kHash; bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; bool isRename = options.Command.CommandType == NCommandType::kRename; if ((isExtractOrList || isRename) && options.StdInMode) thereIsArchiveName = false; if (parser[NKey::kArcNameMode].ThereIs) options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); if (thereIsArchiveName) { if (curCommandIndex >= numNonSwitchStrings) throw CArcCmdLineException("Cannot find archive name"); options.ArchiveName = nonSwitchStrings[curCommandIndex++]; if (options.ArchiveName.IsEmpty()) throw CArcCmdLineException("Archive name cannot by empty"); } AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, curCommandIndex, options.Censor, nonSwitchStrings, recursedType, wildcardMatching, thereAreSwitchIncludes, codePage); options.YesToAll = parser[NKey::kYes].ThereIs; #ifndef _NO_CRYPTO options.PasswordEnabled = parser[NKey::kPassword].ThereIs; if (options.PasswordEnabled) options.Password = parser[NKey::kPassword].PostStrings[0]; #endif options.ShowDialog = parser[NKey::kShowDialog].ThereIs; if (parser[NKey::kArchiveType].ThereIs) options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; SetMethodOptions(parser, options.Properties); options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs; if (options.EnablePercents) { if ((options.StdOutMode && !options.IsStdErrTerminal) || (!options.StdOutMode && !options.IsStdOutTerminal)) options.EnablePercents = false; } if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); if (isExtractOrList) { CExtractOptionsBase &eo = options.ExtractOptions; { CExtractNtOptions &nt = eo.NtOptions; nt.NtSecurity = options.NtSecurity; nt.AltStreams = options.AltStreams; if (!options.AltStreams.Def) nt.AltStreams.Val = true; nt.HardLinks = options.HardLinks; if (!options.HardLinks.Def) nt.HardLinks.Val = true; nt.SymLinks = options.SymLinks; if (!options.SymLinks.Def) nt.SymLinks.Val = true; nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; } options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); options.Censor.ExtendExclude(); // are there paths that look as non-relative (!Prefix.IsEmpty()) if (!options.Censor.AllAreRelative()) throw CArcCmdLineException("Cannot use absolute pathnames for this command"); NWildcard::CCensor arcCensor; if (parser[NKey::kArInclude].ThereIs) AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage); if (parser[NKey::kArExclude].ThereIs) AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage); if (thereIsArchiveName) AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching); arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); #ifdef _WIN32 ConvertToLongNames(arcCensor); #endif arcCensor.ExtendExclude(); if (options.StdInMode) { UString arcName = parser[NKey::kStdIn].PostStrings.Front(); options.ArchivePathsSorted.Add(arcName); options.ArchivePathsFullSorted.Add(arcName); } else { EnumerateDirItemsAndSort( false, // scanAltStreams arcCensor, NWildcard::k_RelatPath, UString(), // addPathPrefix options.ArchivePathsSorted, options.ArchivePathsFullSorted); } if (isExtractGroupCommand) { if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal) throw CArcCmdLineException(kSameTerminalError); if (parser[NKey::kOutputDir].ThereIs) { eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); } eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; if (parser[NKey::kOverwrite].ThereIs) { eo.OverwriteMode = k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex]; eo.OverwriteMode_Force = true; } else if (options.YesToAll) { eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; eo.OverwriteMode_Force = true; } } eo.PathMode = options.Command.GetPathMode(); if (censorPathMode == NWildcard::k_AbsPath) { eo.PathMode = NExtract::NPathMode::kAbsPaths; eo.PathMode_Force = true; } else if (censorPathMode == NWildcard::k_FullPath) { eo.PathMode = NExtract::NPathMode::kFullPaths; eo.PathMode_Force = true; } } else if (options.Command.IsFromUpdateGroup()) { if (parser[NKey::kArInclude].ThereIs) throw CArcCmdLineException("-ai switch is not supported for this command"); CUpdateOptions &updateOptions = options.UpdateOptions; SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); updateOptions.MethodMode.Properties = options.Properties; #ifdef _WIN32 if (parser[NKey::kShareForWrite].ThereIs) updateOptions.OpenShareForWrite = true; #endif updateOptions.PathMode = censorPathMode; updateOptions.AltStreams = options.AltStreams; updateOptions.NtSecurity = options.NtSecurity; updateOptions.HardLinks = options.HardLinks; updateOptions.SymLinks = options.SymLinks; updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; if (updateOptions.EMailMode) { updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); if (updateOptions.EMailAddress.Len() > 0) if (updateOptions.EMailAddress[0] == L'.') { updateOptions.EMailRemoveAfter = true; updateOptions.EMailAddress.Delete(0); } } updateOptions.StdOutMode = options.StdOutMode; updateOptions.StdInMode = options.StdInMode; updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; if (updateOptions.StdOutMode && updateOptions.EMailMode) throw CArcCmdLineException("stdout mode and email mode cannot be combined"); if (updateOptions.StdOutMode && options.IsStdOutTerminal) throw CArcCmdLineException(kTerminalOutError); if (updateOptions.StdInMode) updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); if (options.Command.CommandType == NCommandType::kRename) if (updateOptions.Commands.Size() != 1) throw CArcCmdLineException("Only one archive can be created with rename command"); } else if (options.Command.CommandType == NCommandType::kBenchmark) { options.NumIterations = 1; if (curCommandIndex < numNonSwitchStrings) { if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]); curCommandIndex++; } } else if (options.Command.CommandType == NCommandType::kHash) { options.Censor.AddPathsToCensor(censorPathMode); options.Censor.ExtendExclude(); CHashOptions &hashOptions = options.HashOptions; hashOptions.PathMode = censorPathMode; hashOptions.Methods = options.HashMethods; #ifdef _WIN32 if (parser[NKey::kShareForWrite].ThereIs) hashOptions.OpenShareForWrite = true; #endif hashOptions.StdInMode = options.StdInMode; hashOptions.AltStreamsMode = options.AltStreams.Val; } else if (options.Command.CommandType == NCommandType::kInfo) { } else throw 815676711; // FIXME 9815676711; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h0100777000000000000000000000446213761647206025423 0ustar00// ArchiveCommandLine.h #ifndef __ARCHIVE_COMMAND_LINE_H #define __ARCHIVE_COMMAND_LINE_H #include "../../../Common/CommandLineParser.h" #include "../../../Common/Wildcard.h" #include "Extract.h" #include "HashCalc.h" #include "Update.h" struct CArcCmdLineException: public UString { CArcCmdLineException(const char *a, const wchar_t *u = NULL); }; namespace NCommandType { enum EEnum { kAdd = 0, kUpdate, kDelete, kTest, kExtract, kExtractFull, kList, kBenchmark, kInfo, kHash, kRename };} struct CArcCommand { NCommandType::EEnum CommandType; bool IsFromExtractGroup() const; bool IsFromUpdateGroup() const; bool IsTestCommand() const { return CommandType == NCommandType::kTest; } NExtract::NPathMode::EEnum GetPathMode() const; }; struct CArcCmdLineOptions { bool HelpMode; #ifdef _7ZIP_LARGE_PAGES bool LargePages; #endif bool CaseSensitiveChange; bool CaseSensitive; bool IsInTerminal; bool IsStdOutTerminal; bool IsStdErrTerminal; bool StdInMode; bool StdOutMode; bool EnableHeaders; bool YesToAll; bool ShowDialog; NWildcard::CCensor Censor; CArcCommand Command; UString ArchiveName; #ifndef _NO_CRYPTO bool PasswordEnabled; UString Password; #endif bool TechMode; UStringVector HashMethods; bool AppendName; UStringVector ArchivePathsSorted; UStringVector ArchivePathsFullSorted; CObjectVector Properties; CExtractOptionsBase ExtractOptions; CBoolPair NtSecurity; CBoolPair AltStreams; CBoolPair HardLinks; CBoolPair SymLinks; CUpdateOptions UpdateOptions; CHashOptions HashOptions; UString ArcType; UStringVector ExcludedArcTypes; bool EnablePercents; // Benchmark UInt32 NumIterations; CArcCmdLineOptions(): StdInMode(false), StdOutMode(false), CaseSensitiveChange(false), CaseSensitive(false) {}; }; class CArcCmdLineParser { NCommandLineParser::CParser parser; public: CArcCmdLineParser(); void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options); void Parse2(CArcCmdLineOptions &options); }; void EnumerateDirItemsAndSort( bool storeAltStreams, NWildcard::CCensor &censor, NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, UStringVector &sortedPaths, UStringVector &sortedFullPaths); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp0100777000000000000000000007267713761647206026634 0ustar00// ArchiveExtractCallback.cpp #include "StdAfx.h" #undef sprintf #undef printf #include "../../../Common/ComTry.h" #include "../../../Common/StringConvert.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif #include "../../Common/FilePathAutoRename.h" #include "../Common/ExtractingFilePath.h" #include "../Common/PropIDUtils.h" #include "ArchiveExtractCallback.h" using namespace NWindows; using namespace NFile; using namespace NDir; static const char *kCantAutoRename = "Can not create file with auto name"; static const char *kCantRenameFile = "Can not rename existing file"; static const char *kCantDeleteOutputFile = "Can not delete output file"; static const char *kCantDeleteOutputDir = "Can not delete output folder"; #ifndef _SFX STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (_stream) result = _stream->Write(data, size, &size); if (_calculate) _hash->Update(data, size); _size += size; if (processedSize) *processedSize = size; return result; } #endif #ifdef _USE_SECURITY_CODE bool InitLocalPrivileges() { NSecurity::CAccessToken token; if (!token.OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) return false; TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) return false; if (!token.AdjustPrivileges(&tp)) return false; return (GetLastError() == ERROR_SUCCESS); } #endif #ifdef SUPPORT_LINKS int CHardLinkNode::Compare(const CHardLinkNode &a) const { if (StreamId < a.StreamId) return -1; if (StreamId > a.StreamId) return 1; return MyCompare(INode, a.INode); } HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) { h.INode = 0; h.StreamId = (UInt64)(Int64)-1; defined = false; { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidINode, &prop)); if (!ConvertPropVariantToUInt64(prop, h.INode)) return S_OK; } { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidStreamId, &prop)); ConvertPropVariantToUInt64(prop, h.StreamId); } defined = true; return S_OK; } HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector *realIndices) { _hardLinks.Clear(); if (!_arc->Ask_INode) return S_OK; IInArchive *archive = _arc->Archive; CRecordVector &hardIDs = _hardLinks.IDs; { UInt32 numItems; if (realIndices) numItems = realIndices->Size(); else { RINOK(archive->GetNumberOfItems(&numItems)); } for (UInt32 i = 0; i < numItems; i++) { CHardLinkNode h; bool defined; RINOK(Archive_Get_HardLinkNode(archive, realIndices ? (*realIndices)[i] : i, h, defined)); if (defined) hardIDs.Add(h); } } hardIDs.Sort2(); { // wee keep only items that have 2 or more items unsigned k = 0; unsigned numSame = 1; for (unsigned i = 1; i < hardIDs.Size(); i++) { if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) numSame = 1; else if (++numSame == 2) { if (i - 1 != k) hardIDs[k] = hardIDs[i - 1]; k++; } } hardIDs.DeleteFrom(k); } _hardLinks.PrepareLinks(); return S_OK; } #endif CArchiveExtractCallback::CArchiveExtractCallback(): WriteCTime(true), WriteATime(true), WriteMTime(true), _multiArchives(false) { LocalProgressSpec = new CLocalProgress(); _localProgress = LocalProgressSpec; #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } void CArchiveExtractCallback::Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, const CArc *arc, IFolderArchiveExtractCallback *extractCallback2, bool stdOutMode, bool testMode, const FString &directoryPath, const UStringVector &removePathParts, UInt64 packSize) { _extractedFolderPaths.Clear(); _extractedFolderIndices.Clear(); #ifdef SUPPORT_LINKS _hardLinks.Clear(); #endif _ntOptions = ntOptions; _wildcardCensor = wildcardCensor; _stdOutMode = stdOutMode; _testMode = testMode; _unpTotal = 1; _packTotal = packSize; _extractCallback2 = extractCallback2; _compressProgress.Release(); _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); #ifndef _SFX _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); if (ExtractToStreamCallback) { Int32 useStreams = 0; if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) useStreams = 0; if (useStreams == 0) ExtractToStreamCallback.Release(); } #endif LocalProgressSpec->Init(extractCallback2, true); LocalProgressSpec->SendProgress = false; _removePathParts = removePathParts; _baseParentFolder = (UInt32)(Int32)-1; _use_baseParentFolder_mode = false; _arc = arc; _directoryPath = directoryPath; NName::NormalizeDirPathPrefix(_directoryPath); NDir::MyGetFullPathName(directoryPath, _directoryPathFull); } STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) { COM_TRY_BEGIN _unpTotal = size; if (!_multiArchives && _extractCallback2) return _extractCallback2->SetTotal(size); return S_OK; COM_TRY_END } static void NormalizeVals(UInt64 &v1, UInt64 &v2) { const UInt64 kMax = (UInt64)1 << 31; while (v1 > kMax) { v1 >>= 1; v2 >>= 1; } } static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) { NormalizeVals(packTotal, unpTotal); NormalizeVals(unpCur, unpTotal); if (unpTotal == 0) unpTotal = 1; return unpCur * packTotal / unpTotal; } STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) { COM_TRY_BEGIN if (!_extractCallback2) return S_OK; if (_multiArchives) { if (completeValue != NULL) { UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal); return _extractCallback2->SetCompleted(&packCur); } } return _extractCallback2->SetCompleted(completeValue); COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { COM_TRY_BEGIN return _localProgress->SetRatioInfo(inSize, outSize); COM_TRY_END } #define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') static inline bool IsDriveName(const UString &s) { return s.Len() == 2 && s[1] == ':' && IS_LETTER_CHAR(s[0]); } void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) { bool isAbsPath = false; if (!dirPathParts.IsEmpty()) { const UString &s = dirPathParts[0]; if (s.IsEmpty()) isAbsPath = true; #ifdef _WIN32 else { if (dirPathParts.Size() > 1 && IsDriveName(s)) isAbsPath = true; } #endif } if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) fullPath.Empty(); else fullPath = _directoryPath; FOR_VECTOR (i, dirPathParts) { if (i > 0) fullPath += FCHAR_PATH_SEPARATOR; const UString &s = dirPathParts[i]; fullPath += us2fs(s); #ifdef _WIN32 if (_pathMode == NExtract::NPathMode::kAbsPaths) if (i == 0 && IsDriveName(s)) continue; #endif CreateDir(fullPath); } } HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) { filetimeIsDefined = false; NCOM::CPropVariant prop; RINOK(_arc->Archive->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) { filetime = prop.filetime; filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT CArchiveExtractCallback::GetUnpackSize() { return _arc->GetItemSize(_index, _curSize, _curSizeDefined); } HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) { return _extractCallback2->MessageError( UString(L"ERROR: ") + GetUnicodeString(message) + L": " + fs2us(path)); } HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2) { return _extractCallback2->MessageError( UString(L"ERROR: ") + GetUnicodeString(message) + UString(L": ") + fs2us(path1) + UString(L" : ") + fs2us(path2)); } #ifndef _SFX STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value) { if (propID == kpidName) { COM_TRY_BEGIN NCOM::CPropVariant prop = Name.Ptr(); prop.Detach(value); return S_OK; COM_TRY_END } return Arc->Archive->GetProperty(IndexInArc, propID, value); } #endif #ifdef SUPPORT_LINKS static UString GetDirPrefixOf(const UString &src) { UString s = src; if (!s.IsEmpty()) { if (s.Back() == WCHAR_PATH_SEPARATOR) s.DeleteBack(); int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR); s.DeleteFrom(pos + 1); } return s; } static bool IsSafePath(const UString &path) { UStringVector parts; SplitPathToParts(path, parts); int level = 0; FOR_VECTOR(i, parts) { const UString &s = parts[i]; if (s.IsEmpty()) continue; if (s == L".") continue; if (s == L"..") { if (level <= 0) return false; level--; } else level++; } return level > 0; } #endif STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) { COM_TRY_BEGIN *outStream = 0; #ifndef _SFX if (_hashStream) _hashStreamSpec->ReleaseStream(); _hashStreamWasUsed = false; #endif _outFileStream.Release(); _encrypted = false; _isSplit = false; _isAltStream = false; _curSize = 0; _curSizeDefined = false; _index = index; UString fullPath; IInArchive *archive = _arc->Archive; RINOK(_arc->GetItemPath(index, fullPath)); RINOK(Archive_IsItem_Folder(archive, index, _fi.IsDir)); _filePath = fullPath; { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidPosition, &prop)); if (prop.vt != VT_EMPTY) { if (prop.vt != VT_UI8) return E_FAIL; _position = prop.uhVal.QuadPart; _isSplit = true; } } #ifdef SUPPORT_LINKS bool isHardLink = false; bool isJunction = false; bool isRelative = false; UString linkPath; // RINOK(Archive_GetItemBoolProp(archive, index, kpidIsHardLink, isHardLink)); // if (isHardLink) { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidHardLink, &prop)); if (prop.vt == VT_BSTR) { isHardLink = true; linkPath = prop.bstrVal; isRelative = false; // TAR: hard links are from root folder of archive } else if (prop.vt == VT_EMPTY) { // linkPath.Empty(); } else return E_FAIL; } { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidSymLink, &prop)); if (prop.vt == VT_BSTR) { isHardLink = false; linkPath = prop.bstrVal; isRelative = true; // TAR: symbolic links are relative } else if (prop.vt == VT_EMPTY) { // linkPath.Empty(); } else return E_FAIL; } bool isOkReparse = false; if (linkPath.IsEmpty() && _arc->GetRawProps) { const void *data; UInt32 dataSize; UInt32 propType; _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); if (dataSize != 0) { if (propType != NPropDataType::kRaw) return E_FAIL; UString s; CReparseAttr reparse; isOkReparse = reparse.Parse((const Byte *)data, dataSize); if (isOkReparse) { isHardLink = false; linkPath = reparse.GetPath(); isJunction = reparse.IsMountPoint(); isRelative = reparse.IsRelative(); #ifndef _WIN32 linkPath.Replace(WCHAR_PATH_SEPARATOR, '/', ); #endif } } } if (!linkPath.IsEmpty()) { #ifdef _WIN32 linkPath.Replace('/', WCHAR_PATH_SEPARATOR); #endif for (;;) // while (NName::IsAbsolutePath(linkPath)) { unsigned n = NName::GetRootPrefixSize(linkPath); if (n == 0) break; isRelative = false; linkPath.DeleteFrontal(n); } } if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0) { UStringVector pathParts; SplitPathToParts(linkPath, pathParts); bool badPrefix = false; FOR_VECTOR (i, _removePathParts) { if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) { badPrefix = true; break; } } if (!badPrefix) pathParts.DeleteFrontal(_removePathParts.Size()); linkPath = MakePathNameFromParts(pathParts); } #endif RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)); RINOK(GetUnpackSize()); RINOK(Archive_IsItem_AltStream(archive, index, _isAltStream)); if (!_ntOptions.AltStreams.Val && _isAltStream) return S_OK; if (_wildcardCensor) { if (!_wildcardCensor->CheckPath(_isAltStream, fullPath, !_fi.IsDir)) return S_OK; } UStringVector pathParts; if (_use_baseParentFolder_mode) { int baseParent = _baseParentFolder; if (_pathMode == NExtract::NPathMode::kFullPaths || _pathMode == NExtract::NPathMode::kAbsPaths) baseParent = -1; RINOK(_arc->GetItemPathToParent(index, baseParent, pathParts)); if (_pathMode == NExtract::NPathMode::kNoPaths && !pathParts.IsEmpty()) pathParts.DeleteFrontal(pathParts.Size() - 1); } else { SplitPathToParts(fullPath, pathParts); if (pathParts.IsEmpty()) return E_FAIL; unsigned numRemovePathParts = 0; switch (_pathMode) { case NExtract::NPathMode::kCurPaths: { bool badPrefix = false; if (pathParts.Size() <= _removePathParts.Size()) badPrefix = true; else { FOR_VECTOR (i, _removePathParts) { if (!_removePathParts[i].IsEqualToNoCase(pathParts[i])) { badPrefix = true; break; } } } if (badPrefix) { if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) return E_FAIL; } else numRemovePathParts = _removePathParts.Size(); break; } case NExtract::NPathMode::kNoPaths: { numRemovePathParts = pathParts.Size() - 1; break; } /* case NExtract::NPathMode::kFullPaths: case NExtract::NPathMode::kAbsPaths: break; */ } pathParts.DeleteFrontal(numRemovePathParts); } #ifndef _SFX if (ExtractToStreamCallback) { if (!GetProp) { GetProp_Spec = new CGetProp; GetProp = GetProp_Spec; } GetProp_Spec->Arc = _arc; GetProp_Spec->IndexInArc = index; GetProp_Spec->Name = MakePathNameFromParts(pathParts); return ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, _fi.IsDir, outStream, askExtractMode, GetProp); } #endif CMyComPtr outStreamLoc; if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) { if (_stdOutMode) { outStreamLoc = new CStdOutFileStream; } else { { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidAttrib, &prop)); if (prop.vt == VT_UI4) { _fi.Attrib = prop.ulVal; _fi.AttribDefined = true; } else if (prop.vt == VT_EMPTY) _fi.AttribDefined = false; else return E_FAIL; } RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); bool isAnti = false; RINOK(_arc->IsItemAnti(index, isAnti)); bool replace = _isAltStream ? _ntOptions.ReplaceColonForAltStream : !_ntOptions.WriteToAltStreamIfColon; if (_pathMode != NExtract::NPathMode::kAbsPaths) MakeCorrectPath(_directoryPath.IsEmpty(), pathParts, replace); Correct_IfEmptyLastPart(pathParts); UString processedPath = MakePathNameFromParts(pathParts); if (!isAnti) { if (!_fi.IsDir) { if (!pathParts.IsEmpty()) pathParts.DeleteBack(); } if (!pathParts.IsEmpty()) { FString fullPathNew; CreateComplexDirectory(pathParts, fullPathNew); if (_fi.IsDir) { _extractedFolderPaths.Add(fullPathNew); _extractedFolderIndices.Add(index); SetDirTime(fullPathNew, (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); } } } FString fullProcessedPath = us2fs(processedPath); if (_pathMode != NExtract::NPathMode::kAbsPaths || !NName::IsAbsolutePath(processedPath)) fullProcessedPath = _directoryPath + fullProcessedPath; if (_fi.IsDir) { _diskFilePath = fullProcessedPath; if (isAnti) RemoveDir(_diskFilePath); #ifdef SUPPORT_LINKS if (linkPath.IsEmpty()) #endif return S_OK; } else if (!_isSplit) { NFind::CFileInfo fileInfo; if (fileInfo.Find(fullProcessedPath)) { switch (_overwriteMode) { case NExtract::NOverwriteMode::kSkip: return S_OK; case NExtract::NOverwriteMode::kAsk: { int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); #ifdef _WIN32 int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); slashPos = MyMax(slashPos, slash1Pos); #endif FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name; Int32 overwiteResult; RINOK(_extractCallback2->AskOverwrite( fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, fullPath, _fi.MTimeDefined ? &_fi.MTime : NULL, _curSizeDefined ? &_curSize : NULL, &overwiteResult)) switch (overwiteResult) { case NOverwriteAnswer::kCancel: return E_ABORT; case NOverwriteAnswer::kNo: return S_OK; case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; case NOverwriteAnswer::kYes: break; case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break; case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break; default: return E_FAIL; } } } if (_overwriteMode == NExtract::NOverwriteMode::kRename) { if (!AutoRenamePath(fullProcessedPath)) { RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); return E_FAIL; } } else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) { FString existPath = fullProcessedPath; if (!AutoRenamePath(existPath)) { RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); return E_FAIL; } // MyMoveFile can raname folders. So it's OK to use it folders too if (!MyMoveFile(fullProcessedPath, existPath)) { RINOK(SendMessageError(kCantRenameFile, fullProcessedPath)); return E_FAIL; } } else { if (fileInfo.IsDir()) { // do we need to delete all files in folder? if (!RemoveDir(fullProcessedPath)) { RINOK(SendMessageError(kCantDeleteOutputDir, fullProcessedPath)); return S_OK; } } else if (!DeleteFileAlways(fullProcessedPath)) { RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath)); return S_OK; // return E_FAIL; } } } } _diskFilePath = fullProcessedPath; if (!isAnti) { #ifdef SUPPORT_LINKS if (!linkPath.IsEmpty()) { #ifndef UNDER_CE UString relatPath; if (isRelative) relatPath = GetDirPrefixOf(_filePath); relatPath += linkPath; if (!IsSafePath(relatPath)) { RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath))); } else { FString existPath; if (isHardLink || !isRelative) { if (!NName::GetFullPath(_directoryPathFull, us2fs(relatPath), existPath)) { RINOK(SendMessageError("Incorrect path", us2fs(relatPath))); } } else { existPath = us2fs(linkPath); } if (!existPath.IsEmpty()) { if (isHardLink) { if (!MyCreateHardLink(fullProcessedPath, existPath)) { RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath)); // return S_OK; } } else if (_ntOptions.SymLinks.Val) { // bool isSymLink = true; // = false for junction if (_fi.IsDir && !isRelative) { // if it's before Vista we use Junction Point // isJunction = true; // convertToAbs = true; } CByteBuffer data; if (FillLinkData(data, fs2us(existPath), !isJunction)) { CReparseAttr attr; if (!attr.Parse(data, data.Size())) { return E_FAIL; // "Internal conversion error"; } if (!NFile::NIO::SetReparseData(fullProcessedPath, _fi.IsDir, data, (DWORD)data.Size())) { RINOK(SendMessageError("Can not set reparse data", fullProcessedPath)); } } } } } #endif } else #endif // SUPPORT_LINKS { bool needWriteFile = true; #ifdef SUPPORT_LINKS if (!_hardLinks.IDs.IsEmpty()) { CHardLinkNode h; bool defined; RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); if (defined) { { int linkIndex = _hardLinks.IDs.FindInSorted2(h); if (linkIndex >= 0) { FString &hl = _hardLinks.Links[linkIndex]; if (hl.IsEmpty()) hl = fullProcessedPath; else { if (!MyCreateHardLink(fullProcessedPath, hl)) { RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, hl)); return S_OK; } needWriteFile = false; } } } } } #endif if (needWriteFile) { _outFileStreamSpec = new COutFileStream; CMyComPtr outStreamLoc(_outFileStreamSpec); if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS)) { // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) { RINOK(SendMessageError("Can not open output file ", fullProcessedPath)); return S_OK; } } if (_isSplit) { RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); } _outFileStream = outStreamLoc; } } } outStreamLoc = _outFileStream; } } #ifndef _SFX if (_hashStream) { if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || askExtractMode == NArchive::NExtract::NAskMode::kTest) { _hashStreamSpec->SetStream(outStreamLoc); outStreamLoc = _hashStream; _hashStreamSpec->Init(true); _hashStreamWasUsed = true; } } #endif if (outStreamLoc) *outStream = outStreamLoc.Detach(); return S_OK; COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) { COM_TRY_BEGIN #ifndef _SFX if (ExtractToStreamCallback) return ExtractToStreamCallback->PrepareOperation7(askExtractMode); #endif _extractMode = false; switch (askExtractMode) { case NArchive::NExtract::NAskMode::kExtract: if (_testMode) askExtractMode = NArchive::NExtract::NAskMode::kTest; else _extractMode = true; break; }; return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir, askExtractMode, _isSplit ? &_position: 0); COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) { COM_TRY_BEGIN #ifndef _SFX if (ExtractToStreamCallback) return ExtractToStreamCallback->SetOperationResult7(operationResult, _encrypted); #endif #ifndef _SFX if (_hashStreamWasUsed) { _hashStreamSpec->_hash->Final(_fi.IsDir, _isAltStream, _filePath); _curSize = _hashStreamSpec->GetSize(); _curSizeDefined = true; _hashStreamSpec->ReleaseStream(); _hashStreamWasUsed = false; } #endif if (_outFileStream) { _outFileStreamSpec->SetTime( (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); _curSize = _outFileStreamSpec->ProcessedSize; _curSizeDefined = true; RINOK(_outFileStreamSpec->Close()); _outFileStream.Release(); } #ifdef _USE_SECURITY_CODE if (_ntOptions.NtSecurity.Val && _arc->GetRawProps) { const void *data; UInt32 dataSize; UInt32 propType; _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); if (dataSize != 0) { if (propType != NPropDataType::kRaw) return E_FAIL; if (CheckNtSecure((const Byte *)data, dataSize)) { SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; if (_saclEnabled) securInfo |= SACL_SECURITY_INFORMATION; ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data); } } } #endif if (!_curSizeDefined) GetUnpackSize(); if (_curSizeDefined) { if (_isAltStream) AltStreams_UnpackSize += _curSize; else UnpackSize += _curSize; } if (_fi.IsDir) NumFolders++; else if (_isAltStream) NumAltStreams++; else NumFiles++; if (_extractMode && _fi.AttribDefined) SetFileAttrib(_diskFilePath, _fi.Attrib); RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted)); return S_OK; COM_TRY_END } /* STDMETHODIMP CArchiveExtractCallback::GetInStream( const wchar_t *name, ISequentialInStream **inStream) { COM_TRY_BEGIN CInFileStream *inFile = new CInFileStream; CMyComPtr inStreamTemp = inFile; if (!inFile->Open(_srcDirectoryPrefix + name)) return ::GetLastError(); *inStream = inStreamTemp.Detach(); return S_OK; COM_TRY_END } */ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (!_cryptoGetTextPassword) { RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, &_cryptoGetTextPassword)); } return _cryptoGetTextPassword->CryptoGetTextPassword(password); COM_TRY_END } struct CExtrRefSortPair { int Len; int Index; int Compare(const CExtrRefSortPair &a) const; }; #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const { RINOZ(-MyCompare(Len, a.Len)); return MyCompare(Index, a.Index); } static int GetNumSlashes(const FChar *s) { for (int numSlashes = 0;;) { FChar c = *s++; if (c == 0) return numSlashes; if ( #ifdef _WIN32 c == FTEXT('\\') || #endif c == FTEXT('/')) numSlashes++; } } HRESULT CArchiveExtractCallback::SetDirsTimes() { CRecordVector pairs; pairs.ClearAndSetSize(_extractedFolderPaths.Size()); unsigned i; for (i = 0; i < _extractedFolderPaths.Size(); i++) { CExtrRefSortPair &pair = pairs[i]; pair.Index = i; pair.Len = GetNumSlashes(_extractedFolderPaths[i]); } pairs.Sort2(); for (i = 0; i < pairs.Size(); i++) { int pairIndex = pairs[i].Index; int index = _extractedFolderIndices[pairIndex]; FILETIME CTime; FILETIME ATime; FILETIME MTime; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined)); RINOK(GetTime(index, kpidATime, ATime, ATimeDefined)); RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined)); // printf("\n%S", _extractedFolderPaths[pairIndex]); SetDirTime(_extractedFolderPaths[pairIndex], (WriteCTime && CTimeDefined) ? &CTime : NULL, (WriteATime && ATimeDefined) ? &ATime : NULL, (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h0100777000000000000000000001432613761647206026264 0ustar00// ArchiveExtractCallback.h #ifndef __ARCHIVE_EXTRACT_CALLBACK_H #define __ARCHIVE_EXTRACT_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../../Common/Wildcard.h" #include "../../IPassword.h" #include "../../Common/FileStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Archive/IArchive.h" #include "ExtractMode.h" #include "IFileExtractCallback.h" #include "OpenArchive.h" #include "HashCalc.h" #ifndef _SFX class COutStreamWithHash: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; bool _calculate; public: IHashCalc *_hash; MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(bool calculate = true) { InitCRC(); _size = 0; _calculate = calculate; } void EnableCalc(bool calculate) { _calculate = calculate; } void InitCRC() { _hash->InitForNewFile(); } UInt64 GetSize() const { return _size; } }; #endif struct CExtractNtOptions { CBoolPair NtSecurity; CBoolPair SymLinks; CBoolPair HardLinks; CBoolPair AltStreams; bool ReplaceColonForAltStream; bool WriteToAltStreamIfColon; CExtractNtOptions(): ReplaceColonForAltStream(false), WriteToAltStreamIfColon(false) { SymLinks.Val = true; HardLinks.Val = true; AltStreams.Val = true; } }; #ifndef _SFX class CGetProp: public IGetProp, public CMyUnknownImp { public: const CArc *Arc; UInt32 IndexInArc; UString Name; // relative path MY_UNKNOWN_IMP1(IGetProp) INTERFACE_IGetProp(;) }; #endif #ifndef _SFX #ifndef UNDER_CE // FIXME #define SUPPORT_LINKS #endif #endif #ifdef SUPPORT_LINKS struct CHardLinkNode { UInt64 StreamId; UInt64 INode; int Compare(const CHardLinkNode &a) const; }; class CHardLinks { public: CRecordVector IDs; CObjectVector Links; void Clear() { IDs.Clear(); Links.Clear(); } void PrepareLinks() { while (Links.Size() < IDs.Size()) Links.AddNew(); } }; #endif class CArchiveExtractCallback: public IArchiveExtractCallback, // public IArchiveVolumeExtractCallback, public ICryptoGetTextPassword, public ICompressProgressInfo, public CMyUnknownImp { const CArc *_arc; CExtractNtOptions _ntOptions; const NWildcard::CCensorNode *_wildcardCensor; CMyComPtr _extractCallback2; CMyComPtr _compressProgress; CMyComPtr _cryptoGetTextPassword; FString _directoryPath; FString _directoryPathFull; NExtract::NPathMode::EEnum _pathMode; NExtract::NOverwriteMode::EEnum _overwriteMode; #ifndef _SFX CMyComPtr ExtractToStreamCallback; CGetProp *GetProp_Spec; CMyComPtr GetProp; #endif FString _diskFilePath; UString _filePath; UInt64 _position; bool _isSplit; bool _isAltStream; bool _extractMode; bool WriteCTime; bool WriteATime; bool WriteMTime; bool _encrypted; struct CProcessedFileInfo { FILETIME CTime; FILETIME ATime; FILETIME MTime; UInt32 Attrib; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; bool AttribDefined; bool IsDir; } _fi; UInt32 _index; UInt64 _curSize; bool _curSizeDefined; COutFileStream *_outFileStreamSpec; CMyComPtr _outFileStream; #ifndef _SFX COutStreamWithHash *_hashStreamSpec; CMyComPtr _hashStream; bool _hashStreamWasUsed; #endif UStringVector _removePathParts; bool _use_baseParentFolder_mode; UInt32 _baseParentFolder; bool _stdOutMode; bool _testMode; bool _multiArchives; CMyComPtr _localProgress; UInt64 _packTotal; UInt64 _unpTotal; FStringVector _extractedFolderPaths; CRecordVector _extractedFolderIndices; #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) bool _saclEnabled; #endif void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); HRESULT GetUnpackSize(); HRESULT SendMessageError(const char *message, const FString &path); HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2); public: CLocalProgress *LocalProgressSpec; UInt64 NumFolders; UInt64 NumFiles; UInt64 NumAltStreams; UInt64 UnpackSize; UInt64 AltStreams_UnpackSize; MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo) // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback) INTERFACE_IArchiveExtractCallback(;) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); // IArchiveVolumeExtractCallback // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream); STDMETHOD(CryptoGetTextPassword)(BSTR *password); CArchiveExtractCallback(); void InitForMulti(bool multiArchives, NExtract::NPathMode::EEnum pathMode, NExtract::NOverwriteMode::EEnum overwriteMode) { _multiArchives = multiArchives; _pathMode = pathMode; _overwriteMode = overwriteMode; NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; } #ifndef _SFX void SetHashMethods(IHashCalc *hash) { if (!hash) return; _hashStreamSpec = new COutStreamWithHash; _hashStream = _hashStreamSpec; _hashStreamSpec->_hash = hash; } #endif void Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, const CArc *arc, IFolderArchiveExtractCallback *extractCallback2, bool stdOutMode, bool testMode, const FString &directoryPath, const UStringVector &removePathParts, UInt64 packSize); #ifdef SUPPORT_LINKS private: CHardLinks _hardLinks; public: // call PrepareHardLinks() after Init() HRESULT PrepareHardLinks(const CRecordVector *realIndices); // NULL means all items #endif // call it after Init() void SetBaseParentFolderIndex(UInt32 indexInArc) { _use_baseParentFolder_mode = true; _baseParentFolder = indexInArc; } HRESULT SetDirsTimes(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp0100777000000000000000000000627113761647206026106 0ustar00// ArchiveOpenCallback.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../Common/FileStreams.h" #include "ArchiveOpenCallback.h" using namespace NWindows; STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes) { COM_TRY_BEGIN if (ReOpenCallback) return ReOpenCallback->SetTotal(files, bytes); if (!Callback) return S_OK; return Callback->Open_SetTotal(files, bytes); COM_TRY_END } STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes) { COM_TRY_BEGIN if (ReOpenCallback) return ReOpenCallback->SetCompleted(files, bytes); if (!Callback) return S_OK; return Callback->Open_SetCompleted(files, bytes); COM_TRY_END } STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; if (_subArchiveMode) switch(propID) { case kpidName: prop = _subArchiveName; break; } else switch(propID) { case kpidName: prop = _fileInfo.Name; break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; case kpidCTime: prop = _fileInfo.CTime; break; case kpidATime: prop = _fileInfo.ATime; break; case kpidMTime: prop = _fileInfo.MTime; break; } prop.Detach(value); return S_OK; COM_TRY_END } struct CInFileStreamVol: public CInFileStream { int FileNameIndex; COpenCallbackImp *OpenCallbackImp; CMyComPtr OpenCallbackRef; CInFileStreamVol(bool ignoreLink = false) : CInFileStream(ignoreLink) { } ~CInFileStreamVol() { if (OpenCallbackRef) OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false; } }; STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream) { COM_TRY_BEGIN *inStream = NULL; if (_subArchiveMode) return S_FALSE; if (Callback) { RINOK(Callback->Open_CheckBreak()); } FString fullPath; if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), fullPath)) return S_FALSE; if (!_fileInfo.Find(fullPath,true)) return S_FALSE; if (_fileInfo.IsDir()) return S_FALSE; CInFileStreamVol *inFile = new CInFileStreamVol(true); CMyComPtr inStreamTemp = inFile; if (!inFile->Open(fullPath)) return ::GetLastError(); FileSizes.Add(_fileInfo.Size); FileNames.Add(name); inFile->FileNameIndex = FileNames_WasUsed.Add(true); inFile->OpenCallbackImp = this; inFile->OpenCallbackRef = this; // TotalSize += _fileInfo.Size; *inStream = inStreamTemp.Detach(); return S_OK; COM_TRY_END } #ifndef _NO_CRYPTO STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (ReOpenCallback) { CMyComPtr getTextPassword; ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); if (getTextPassword) return getTextPassword->CryptoGetTextPassword(password); } if (!Callback) return E_NOTIMPL; return Callback->Open_CryptoGetTextPassword(password); COM_TRY_END } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h0100777000000000000000000000505313761647206025550 0ustar00// ArchiveOpenCallback.h #ifndef __ARCHIVE_OPEN_CALLBACK_H #define __ARCHIVE_OPEN_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../../Windows/FileFind.h" #ifndef _NO_CRYPTO #include "../../IPassword.h" #endif #include "../../Archive/IArchive.h" #ifdef _NO_CRYPTO #define INTERFACE_IOpenCallbackUI_Crypto(x) #else #define INTERFACE_IOpenCallbackUI_Crypto(x) \ virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \ virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x; \ virtual bool Open_WasPasswordAsked() x; \ virtual void Open_ClearPasswordWasAskedFlag() x; \ #endif #define INTERFACE_IOpenCallbackUI(x) \ virtual HRESULT Open_CheckBreak() x; \ virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \ virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \ INTERFACE_IOpenCallbackUI_Crypto(x) struct IOpenCallbackUI { INTERFACE_IOpenCallbackUI(=0) }; class COpenCallbackImp: public IArchiveOpenCallback, public IArchiveOpenVolumeCallback, public IArchiveOpenSetSubArchiveName, #ifndef _NO_CRYPTO public ICryptoGetTextPassword, #endif public CMyUnknownImp { public: #ifndef _NO_CRYPTO MY_UNKNOWN_IMP3( IArchiveOpenVolumeCallback, ICryptoGetTextPassword, IArchiveOpenSetSubArchiveName ) #else MY_UNKNOWN_IMP2( IArchiveOpenVolumeCallback, IArchiveOpenSetSubArchiveName ) #endif INTERFACE_IArchiveOpenCallback(;) INTERFACE_IArchiveOpenVolumeCallback(;) #ifndef _NO_CRYPTO STDMETHOD(CryptoGetTextPassword)(BSTR *password); #endif STDMETHOD(SetSubArchiveName(const wchar_t *name)) { _subArchiveMode = true; _subArchiveName = name; // TotalSize = 0; return S_OK; } private: FString _folderPrefix; NWindows::NFile::NFind::CFileInfo _fileInfo; bool _subArchiveMode; UString _subArchiveName; public: UStringVector FileNames; CBoolVector FileNames_WasUsed; CRecordVector FileSizes; IOpenCallbackUI *Callback; CMyComPtr ReOpenCallback; // UInt64 TotalSize; COpenCallbackImp(): Callback(NULL) {} void Init(const FString &folderPrefix, const FString &fileName) { _folderPrefix = folderPrefix; if (!_fileInfo.Find(_folderPrefix + fileName,true)) throw 20121118; FileNames.Clear(); FileNames_WasUsed.Clear(); FileSizes.Clear(); _subArchiveMode = false; // TotalSize = 0; } bool SetSecondFileInfo(CFSTR newName) { return _fileInfo.Find(newName) && !_fileInfo.IsDir(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Common.pri0100777000000000000000000000430113761647206023516 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/DirItem.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractMode.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/IFileExtractCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Property.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Update.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.h SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/Update.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp0100777000000000000000000000167413761647206024455 0ustar00// DefaultName.cpp #include "StdAfx.h" #include "DefaultName.h" static UString GetDefaultName3(const UString &fileName, const UString &extension, const UString &addSubExtension) { int extLength = extension.Len(); int fileNameLength = fileName.Len(); if (fileNameLength > extLength + 1) { int dotPos = fileNameLength - (extLength + 1); if (fileName[dotPos] == '.') if (extension.IsEqualToNoCase(fileName.Ptr(dotPos + 1))) return fileName.Left(dotPos) + addSubExtension; } int dotPos = fileName.ReverseFind(L'.'); if (dotPos > 0) return fileName.Left(dotPos) + addSubExtension; if (addSubExtension.IsEmpty()) return fileName + L"~"; else return fileName + addSubExtension; } UString GetDefaultName2(const UString &fileName, const UString &extension, const UString &addSubExtension) { UString name = GetDefaultName3(fileName, extension, addSubExtension); name.TrimRight(); return name; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.h0100777000000000000000000000034413761647206024113 0ustar00// DefaultName.h #ifndef __DEFAULT_NAME_H #define __DEFAULT_NAME_H #include "../../../Common/MyString.h" UString GetDefaultName2(const UString &fileName, const UString &extension, const UString &addSubExtension); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/DirItem.h0100777000000000000000000000520313761647206023262 0ustar00// DirItem.h #ifndef __DIR_ITEM_H #define __DIR_ITEM_H #include "../../../Common/MyString.h" #include "../../../Windows/FileFind.h" #include "../../Common/UniqBlocks.h" #include "../../Archive/IArchive.h" struct CDirItem { UInt64 Size; FILETIME CTime; FILETIME ATime; FILETIME MTime; UString Name; #if defined(_WIN32) && !defined(UNDER_CE) // UString ShortName; CByteBuffer ReparseData; CByteBuffer ReparseData2; // fixed (reduced) absolute links bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } #endif UInt32 Attrib; int PhyParent; int LogParent; int SecureIndex; bool IsAltStream; CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {} bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } }; class CDirItems { UStringVector Prefixes; CIntVector PhyParents; CIntVector LogParents; UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const; void EnumerateDir(int phyParent, int logParent, const FString &phyPrefix); public: CObjectVector Items; bool SymLinks; bool ScanAltStreams; FStringVector ErrorPaths; CRecordVector ErrorCodes; UInt64 TotalSize; #ifndef UNDER_CE void SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi, const FString &phyPrefix); #endif void AddError(const FString &path, DWORD errorCode) { ErrorCodes.Add(errorCode); ErrorPaths.Add(path); } void AddError(const FString &path) { AddError(path, ::GetLastError()); } #if defined(_WIN32) && !defined(UNDER_CE) CUniqBlocks SecureBlocks; CByteBuffer TempSecureBuf; bool _saclEnabled; bool ReadSecure; void AddSecurityItem(const FString &path, int &secureIndex); #endif CDirItems(); int GetNumFolders() const { return Prefixes.Size(); } UString GetPhyPath(unsigned index) const; UString GetLogPath(unsigned index) const; unsigned AddPrefix(int phyParent, int logParent, const UString &prefix); void DeleteLastPrefix(); void EnumerateItems2( const FString &phyPrefix, const UString &logPrefix, const FStringVector &filePaths, FStringVector *requestedPaths); #if defined(_WIN32) && !defined(UNDER_CE) void FillFixedReparse(); #endif void ReserveDown(); }; struct CArcItem { UInt64 Size; FILETIME MTime; UString Name; bool IsDir; bool IsAltStream; bool SizeDefined; bool MTimeDefined; bool Censored; UInt32 IndexInServer; int TimeType; CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp0100777000000000000000000004752513761647206024642 0ustar00// EnumDirItems.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileIO.h" #include "../../../Windows/FileName.h" #if defined(_WIN32) && !defined(UNDER_CE) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif #include "EnumDirItems.h" using namespace NWindows; using namespace NFile; using namespace NName; void AddDirFileInfo(int phyParent, int logParent, int secureIndex, const NFind::CFileInfo &fi, CObjectVector &dirItems) { CDirItem di; di.Size = fi.Size; di.CTime = fi.CTime; di.ATime = fi.ATime; di.MTime = fi.MTime; di.Attrib = fi.Attrib; // FIXME di.IsAltStream = fi.IsAltStream; di.PhyParent = phyParent; di.LogParent = logParent; di.SecureIndex = secureIndex; di.Name = fs2us(fi.Name); #if defined(_WIN32) && !defined(UNDER_CE) // di.ShortName = fs2us(fi.ShortName); #endif dirItems.Add(di); } UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const { UString path; unsigned len = name.Len(); int i; for (i = index; i >= 0; i = parents[i]) len += Prefixes[i].Len(); unsigned totalLen = len; wchar_t *p = path.GetBuffer(len); p[len] = 0; len -= name.Len(); memcpy(p + len, (const wchar_t *)name, name.Len() * sizeof(wchar_t)); for (i = index; i >= 0; i = parents[i]) { const UString &s = Prefixes[i]; len -= s.Len(); memcpy(p + len, (const wchar_t *)s, s.Len() * sizeof(wchar_t)); } path.ReleaseBuffer(totalLen); return path; } UString CDirItems::GetPhyPath(unsigned index) const { const CDirItem &di = Items[index]; return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); } UString CDirItems::GetLogPath(unsigned index) const { const CDirItem &di = Items[index]; return GetPrefixesPath(LogParents, di.LogParent, di.Name); } void CDirItems::ReserveDown() { Prefixes.ReserveDown(); PhyParents.ReserveDown(); LogParents.ReserveDown(); Items.ReserveDown(); } unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) { PhyParents.Add(phyParent); LogParents.Add(logParent); return Prefixes.Add(prefix); } void CDirItems::DeleteLastPrefix() { PhyParents.DeleteBack(); LogParents.DeleteBack(); Prefixes.DeleteBack(); } bool InitLocalPrivileges(); CDirItems::CDirItems(): SymLinks(false), TotalSize(0) #ifdef _USE_SECURITY_CODE , ReadSecure(false) #endif { #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } #ifdef _USE_SECURITY_CODE void CDirItems::AddSecurityItem(const FString &path, int &secureIndex) { secureIndex = -1; SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; if (_saclEnabled) securInfo |= SACL_SECURITY_INFORMATION; DWORD errorCode = 0; DWORD secureSize; BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); if (res) { if (secureSize == 0) return; if (secureSize > TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION; } else { errorCode = GetLastError(); if (errorCode == ERROR_INSUFFICIENT_BUFFER) { if (secureSize <= TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION; else { TempSecureBuf.Alloc(secureSize); res = ::GetFileSecurityW(fs2us(path), securInfo, TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); if (res) { if (secureSize != TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION;; } else errorCode = GetLastError(); } } } if (res) { secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize); return; } if (errorCode == 0) errorCode = ERROR_INVALID_FUNCTION; AddError(path, errorCode); } #endif void CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix) { NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); for (;;) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { AddError(phyPrefix); return; } if (!found) break; int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) AddSecurityItem(phyPrefix + fi.Name, secureIndex); #endif AddDirFileInfo(phyParent, logParent, secureIndex, fi, Items); if (fi.IsDir()) { const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); EnumerateDir(parent, parent, phyPrefix + name2); } } } void CDirItems::EnumerateItems2( const FString &phyPrefix, const UString &logPrefix, const FStringVector &filePaths, FStringVector *requestedPaths) { int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix)); int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix); FOR_VECTOR (i, filePaths) { const FString &filePath = filePaths[i]; NFind::CFileInfo fi; const FString phyPath = phyPrefix + filePath; if (!fi.Find(phyPath)) { AddError(phyPath); continue; } if (requestedPaths) requestedPaths->Add(phyPath); int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR); FString phyPrefixCur; int phyParentCur = phyParent; if (delimiter >= 0) { phyPrefixCur.SetFrom(filePath, delimiter + 1); phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); } int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) AddSecurityItem(phyPath, secureIndex); #endif AddDirFileInfo(phyParentCur, logParent, secureIndex, fi, Items); if (fi.IsDir()) { const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2); } } ReserveDown(); } static HRESULT EnumerateDirItems( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback); static HRESULT EnumerateDirItems_Spec( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &curFolderName, const FString &phyPrefix, const UStringVector &addArchivePrefix, CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); unsigned numItems = dirItems.Items.Size(); HRESULT res = EnumerateDirItems( curNode, parent, parent, phyPrefix + name2, addArchivePrefix, dirItems, enterToSubFolders, callback); if (numItems == dirItems.Items.Size()) dirItems.DeleteLastPrefix(); return res; } #if 0 // #ifndef UNDER_CE static void EnumerateAltStreams( const NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems) { const FString fullPath = phyPrefix + fi.Name; NFind::CStreamEnumerator enumerator(fullPath); for (;;) { NFind::CStreamInfo si; bool found; if (!enumerator.Next(si, found)) { dirItems.AddError(fullPath + FTEXT(":*"), (DWORD)E_FAIL); break; } if (!found) break; if (si.IsMainStream()) continue; UStringVector addArchivePrefixNew = addArchivePrefix; UString reducedName = si.GetReducedName(); addArchivePrefixNew.Back() += reducedName; if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true)) continue; NFind::CFileInfo fi2 = fi; fi2.Name += us2fs(reducedName); fi2.Size = si.Size; fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; fi2.IsAltStream = true; AddDirFileInfo(phyParent, logParent, -1, fi2, dirItems.Items); dirItems.TotalSize += fi2.Size; } } void CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, const FString &phyPrefix) { if (!SymLinks || !fi.HasReparsePoint()) return; const FString path = phyPrefix + fi.Name; CByteBuffer &buf = dirItem.ReparseData; if (NIO::GetReparseData(path, buf)) { CReparseAttr attr; if (attr.Parse(buf, buf.Size())) return; } AddError(path); buf.Free(); } #endif static HRESULT EnumerateForItem( NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { const UString name = fs2us(fi.Name); bool enterToSubFolders2 = enterToSubFolders; UStringVector addArchivePrefixNew = addArchivePrefix; addArchivePrefixNew.Add(name); { UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) return S_OK; } int dirItemIndex = -1; if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (dirItems.ReadSecure) dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex); #endif dirItemIndex = dirItems.Items.Size(); AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); dirItems.TotalSize += fi.Size; if (fi.IsDir()) enterToSubFolders2 = true; } #if 0 // #ifndef UNDER_CE if (dirItems.ScanAltStreams) { EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefixNew, dirItems); } if (dirItemIndex >= 0) { CDirItem &dirItem = dirItems.Items[dirItemIndex]; dirItems.SetLinkInfo(dirItem, fi, phyPrefix); if (dirItem.ReparseData.Size() != 0) return S_OK; } #endif if (!fi.IsDir()) return S_OK; const NWildcard::CCensorNode *nextNode = 0; if (addArchivePrefix.IsEmpty()) { int index = curNode.FindSubNode(name); if (index >= 0) nextNode = &curNode.SubNodes[index]; } if (!enterToSubFolders2 && nextNode == 0) return S_OK; addArchivePrefixNew = addArchivePrefix; if (nextNode == 0) { nextNode = &curNode; addArchivePrefixNew.Add(name); } return EnumerateDirItems_Spec( *nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, enterToSubFolders2, callback); } static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode) { FOR_VECTOR (i, curNode.IncludeItems) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.Recursive || item.PathParts.Size() != 1) return false; const UString &name = item.PathParts.Front(); if (name.IsEmpty()) return false; /* Windows doesn't support file name with wildcard. but if another system supports file name with wildcard, and wildcard mode is disabled, we can ignore wildcard in name */ /* if (!item.WildcardParsing) continue; */ if (DoesNameContainWildcard(name)) return false; } return true; } static HRESULT EnumerateDirItems( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { if (!enterToSubFolders) if (curNode.NeedCheckSubDirs()) enterToSubFolders = true; if (callback) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); // try direct_names case at first if (addArchivePrefix.IsEmpty() && !enterToSubFolders) { if (CanUseFsDirect(curNode)) { // all names are direct (no wildcards) // so we don't need file_system's dir enumerator CRecordVector needEnterVector; unsigned i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; const UString &name = item.PathParts.Front(); const FString fullPath = phyPrefix + us2fs(name); NFind::CFileInfo fi; #ifdef _WIN32 if (phyPrefix.IsEmpty() && item.IsDriveItem()) { fi.SetAsDir(); fi.Name = fullPath; } else #endif if (!fi.Find(fullPath)) { dirItems.AddError(fullPath); continue; } bool isDir = fi.IsDir(); if (isDir && !item.ForDir || !isDir && !item.ForFile) { dirItems.AddError(fullPath, (DWORD)E_FAIL); continue; } { UStringVector pathParts; pathParts.Add(fs2us(fi.Name)); if (curNode.CheckPathToRoot(false, pathParts, !isDir)) continue; } int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (dirItems.ReadSecure) dirItems.AddSecurityItem(fullPath, secureIndex); #endif AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); #if 0 // #ifndef UNDER_CE { CDirItem &dirItem = dirItems.Items.Back(); dirItems.SetLinkInfo(dirItem, fi, phyPrefix); if (dirItem.ReparseData.Size() != 0) continue; } #endif dirItems.TotalSize += fi.Size; #if 0 // #ifndef UNDER_CE if (dirItems.ScanAltStreams) { UStringVector pathParts; pathParts.Add(fs2us(fi.Name)); EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, pathParts, dirItems); } #endif if (!isDir) continue; UStringVector addArchivePrefixNew; const NWildcard::CCensorNode *nextNode = 0; int index = curNode.FindSubNode(name); if (index >= 0) { for (int t = needEnterVector.Size(); t <= index; t++) needEnterVector.Add(true); needEnterVector[index] = false; nextNode = &curNode.SubNodes[index]; } else { nextNode = &curNode; addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support } RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, true, callback)); } for (i = 0; i < curNode.SubNodes.Size(); i++) { if (i < needEnterVector.Size()) if (!needEnterVector[i]) continue; const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; const FString fullPath = phyPrefix + us2fs(nextNode.Name); NFind::CFileInfo fi; #ifdef _WIN32 if (phyPrefix.IsEmpty() && NWildcard::IsDriveColonName(nextNode.Name)) { fi.SetAsDir(); fi.Name = fullPath; } else #endif if (!fi.Find(fullPath,true)) { if (!nextNode.AreThereIncludeItems()) continue; dirItems.AddError(fullPath); continue; } if (!fi.IsDir()) { dirItems.AddError(fullPath, (DWORD)E_FAIL); continue; } RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, UStringVector(), dirItems, false, callback)); } return S_OK; } } #ifdef _WIN32 #ifndef UNDER_CE // scan drives, if wildcard is "*:\" if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0) { unsigned i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.PathParts.Size() < 1) break; const UString &name = item.PathParts.Front(); if (name.Len() != 2 || name[1] != ':') break; if (item.PathParts.Size() == 1) if (item.ForFile || !item.ForDir) break; if (NWildcard::IsDriveColonName(name)) continue; if (name[0] != '*' && name[0] != '?') break; } if (i == curNode.IncludeItems.Size()) { FStringVector driveStrings; NFind::MyGetLogicalDriveStrings(driveStrings); for (i = 0; i < driveStrings.Size(); i++) { FString driveName = driveStrings[i]; if (driveName.Len() < 3 || driveName.Back() != '\\') return E_FAIL; driveName.DeleteBack(); NFind::CFileInfo fi; fi.SetAsDir(); fi.Name = driveName; RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefix, dirItems, enterToSubFolders, callback)); } return S_OK; } } #endif #endif NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); for (unsigned ttt = 0; ; ttt++) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { dirItems.AddError(phyPrefix); break; } if (!found) break; if (callback && (ttt & 0xFF) == 0xFF) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefix, dirItems, enterToSubFolders, callback)); } return S_OK; } HRESULT EnumerateItems( const NWildcard::CCensor &censor, const NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, CDirItems &dirItems, IEnumDirItemCallback *callback) { FOR_VECTOR (i, censor.Pairs) { const NWildcard::CPair &pair = censor.Pairs[i]; int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix); int logParent = -1; if (pathMode == NWildcard::k_AbsPath) logParent = phyParent; else { if (!addPathPrefix.IsEmpty()) logParent = dirItems.AddPrefix(-1, -1, addPathPrefix); } RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(), dirItems, false, // enterToSubFolders callback)); } dirItems.ReserveDown(); #if defined(_WIN32) && !defined(UNDER_CE) dirItems.FillFixedReparse(); #endif return S_OK; } #if defined(_WIN32) && !defined(UNDER_CE) void CDirItems::FillFixedReparse() { /* imagex/WIM reduces absolute pathes in links (raparse data), if we archive non root folder. We do same thing here */ if (!SymLinks) return; FOR_VECTOR(i, Items) { CDirItem &item = Items[i]; if (item.ReparseData.Size() == 0) continue; CReparseAttr attr; if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) continue; if (attr.IsRelative()) continue; const UString &link = attr.GetPath(); if (!IsDrivePath(link)) continue; // maybe we need to support networks paths also ? FString fullPathF; if (!NDir::MyGetFullPathName(us2fs(GetPhyPath(i)), fullPathF)) continue; UString fullPath = fs2us(fullPathF); const UString logPath = GetLogPath(i); if (logPath.Len() >= fullPath.Len()) continue; if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0) continue; const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len()); if (prefix.Back() != WCHAR_PATH_SEPARATOR) continue; unsigned rootPrefixSize = GetRootPrefixSize(prefix); if (rootPrefixSize == 0) continue; if (rootPrefixSize == prefix.Len()) continue; // simple case: paths are from root if (link.Len() <= prefix.Len()) continue; if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) continue; UString newLink = prefix.Left(rootPrefixSize); newLink += link.Ptr(prefix.Len()); CByteBuffer data; if (!FillLinkData(data, newLink, attr.IsSymLink())) continue; item.ReparseData2 = data; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h0100777000000000000000000000126413761647206024275 0ustar00// EnumDirItems.h #ifndef __ENUM_DIR_ITEMS_H #define __ENUM_DIR_ITEMS_H #include "../../../Common/Wildcard.h" #include "../../../Windows/FileFind.h" #include "DirItem.h" void AddDirFileInfo(int phyParent, int logParent, int secureIndex, const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector &dirItems); struct IEnumDirItemCallback { virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) = 0; }; HRESULT EnumerateItems( const NWildcard::CCensor &censor, NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, CDirItems &dirItems, IEnumDirItemCallback *callback); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp0100777000000000000000000003006513761647206023676 0ustar00// Extract.cpp #include "StdAfx.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../Common/ExtractingFilePath.h" #include "Extract.h" #include "SetProperties.h" using namespace NWindows; using namespace NFile; using namespace NDir; static HRESULT DecompressArchive( CCodecs *codecs, const CArchiveLink &arcLink, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, bool calcCrc, IExtractCallbackUI *callback, CArchiveExtractCallback *ecs, UString &errorMessage, UInt64 &stdInProcessed) { const CArc &arc = arcLink.Arcs.Back(); stdInProcessed = 0; IInArchive *archive = arc.Archive; CRecordVector realIndices; UStringVector removePathParts; FString outDir = options.OutputDir; UString replaceName = arc.DefaultName; if (arcLink.Arcs.Size() > 1) { // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". // So it extracts different archives to one folder. // We will use top level archive name const CArc &arc0 = arcLink.Arcs[0]; if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe")) replaceName = arc0.DefaultName; } outDir.Replace(FSTRING_ANY_MASK, us2fs(GetCorrectFsPath(replaceName))); bool elimIsPossible = false; UString elimPrefix; // only pure name without dir delimiter FString outDirReduced = outDir; if (options.ElimDup.Val) { UString dirPrefix; SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); if (!elimPrefix.IsEmpty()) { if (IsCharDirLimiter(elimPrefix.Back())) elimPrefix.DeleteBack(); if (!elimPrefix.IsEmpty()) { outDirReduced = us2fs(dirPrefix); elimIsPossible = true; } } } if (!options.StdInMode) { UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); UString filePath; for (UInt32 i = 0; i < numItems; i++) { RINOK(arc.GetItemPath(i, filePath)); if (elimIsPossible && options.ElimDup.Val) { if (!IsPath1PrefixedByPath2(filePath, elimPrefix)) elimIsPossible = false; else { wchar_t c = filePath[elimPrefix.Len()]; if (c != 0 && !IsCharDirLimiter(c)) elimIsPossible = false; } } bool isFolder; RINOK(Archive_IsItem_Folder(archive, i, isFolder)); bool isAltStream; RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); if (!options.NtOptions.AltStreams.Val && isAltStream) continue; if (!wildcardCensor.CheckPath(isAltStream, filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return callback->ExtractResult(S_OK); } } if (elimIsPossible) outDir = outDirReduced; #ifdef _WIN32 // GetCorrectFullFsPath doesn't like "..". // outDir.TrimRight(); // outDir = GetCorrectFullFsPath(outDir); #endif if (outDir.IsEmpty()) outDir = FString(FTEXT(".")) + FString(FSTRING_PATH_SEPARATOR); else if (!CreateComplexDir(outDir)) { HRESULT res = ::GetLastError(); if (res == S_OK) res = E_FAIL; errorMessage = ((UString)L"Can not create output directory ") + fs2us(outDir); return res; } ecs->Init( options.NtOptions, options.StdInMode ? &wildcardCensor : NULL, &arc, callback, options.StdOutMode, options.TestMode, outDir, removePathParts, packSize); #ifdef SUPPORT_LINKS if (!options.StdInMode && !options.TestMode && options.NtOptions.HardLinks.Val) { RINOK(ecs->PrepareHardLinks(&realIndices)); } #endif HRESULT result; Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; if (options.StdInMode) { result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); NCOM::CPropVariant prop; if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) ConvertPropVariantToUInt64(prop, stdInProcessed); } else result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs); if (result == S_OK && !options.StdInMode) result = ecs->SetDirsTimes(); return callback->ExtractResult(result); } /* v9.31: BUG was fixed: Sorted list for file paths was sorted with case insensitive compare function. But FindInSorted function did binary search via case sensitive compare function */ int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) { unsigned left = 0, right = fileName.Size(); while (left != right) { unsigned mid = (left + right) / 2; const UString &midValue = fileName[mid]; int compare = CompareFileNames(name, midValue); if (compare == 0) return mid; if (compare < 0) right = mid; else left = mid + 1; } return -1; } HRESULT Extract( CCodecs *codecs, const CObjectVector &types, const CIntVector &excludedFormats, UStringVector &arcPaths, UStringVector &arcPathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, #ifndef _SFX IHashCalc *hash, #endif UString &errorMessage, CDecompressStat &stat) { stat.Clear(); UInt64 totalPackSize = 0; CRecordVector arcSizes; unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); unsigned i; for (i = 0; i < numArcs; i++) { NFind::CFileInfo fi; fi.Size = 0; if (!options.StdInMode) { const FString &arcPath = us2fs(arcPaths[i]); if (!fi.Find(arcPath,true)) throw "there is no such archive"; if (fi.IsDir()) throw "can't decompress folder"; } arcSizes.Add(fi.Size); totalPackSize += fi.Size; } CBoolArr skipArcs(numArcs); for (i = 0; i < numArcs; i++) skipArcs[i] = false; CArchiveExtractCallback *ecs = new CArchiveExtractCallback; CMyComPtr ec(ecs); bool multi = (numArcs > 1); ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode); #ifndef _SFX ecs->SetHashMethods(hash); #endif if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } UInt64 totalPackProcessed = 0; bool thereAreNotOpenArcs = false; for (i = 0; i < numArcs; i++) { if (skipArcs[i]) continue; const UString &arcPath = arcPaths[i]; NFind::CFileInfo fi; if (options.StdInMode) { fi.Size = 0; fi.Attrib = 0; } else { if (!fi.Find(us2fs(arcPath),true) || fi.IsDir()) throw "there is no such archive"; } #ifndef _NO_CRYPTO openCallback->Open_ClearPasswordWasAskedFlag(); #endif RINOK(extractCallback->BeforeOpen(arcPath)); CArchiveLink arcLink; CObjectVector types2 = types; /* #ifndef _SFX if (types.IsEmpty()) { int pos = arcPath.ReverseFind(L'.'); if (pos >= 0) { UString s = arcPath.Ptr(pos + 1); int index = codecs->FindFormatForExtension(s); if (index >= 0 && s == L"001") { s = arcPath.Left(pos); pos = s.ReverseFind(L'.'); if (pos >= 0) { int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1)); if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 { types2.Add(index2); types2.Add(index); } } } } } #endif */ COpenOptions op; #ifndef _SFX op.props = &options.Properties; #endif op.codecs = codecs; op.types = &types2; op.excludedFormats = &excludedFormats; op.stdInMode = options.StdInMode; op.stream = NULL; op.filePath = arcPath; HRESULT result = arcLink.Open2(op, openCallback); if (result == E_ABORT) return result; bool crypted = false; #ifndef _NO_CRYPTO crypted = openCallback->Open_WasPasswordAsked(); #endif if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) result = S_FALSE; // arcLink.Set_ErrorsText(); RINOK(extractCallback->OpenResult(arcPath, result, crypted)); { FOR_VECTOR (r, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[r]; const CArcErrorInfo &er = arc.ErrorInfo; if (er.IsThereErrorOrWarning()) { RINOK(extractCallback->SetError(r, arc.Path, er.GetErrorFlags(), er.ErrorMessage, er.GetWarningFlags(), er.WarningMessage)); } } } if (result != S_OK) { thereAreNotOpenArcs = true; if (!options.StdInMode) { NFind::CFileInfo fi; if (fi.Find(us2fs(arcPath))) if (!fi.IsDir()) totalPackProcessed += fi.Size; } continue; } if (!options.StdInMode) { // numVolumes += arcLink.VolumePaths.Size(); // arcLink.VolumesSize; // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); // numArcs = arcPaths.Size(); if (arcLink.VolumePaths.Size() != 0) { Int64 correctionSize = arcLink.VolumesSize; FOR_VECTOR (v, arcLink.VolumePaths) { int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); if (index >= 0) { if ((unsigned)index > i) { skipArcs[index] = true; correctionSize -= arcSizes[index]; } } } if (correctionSize != 0) { Int64 newPackSize = (Int64)totalPackSize + correctionSize; if (newPackSize < 0) newPackSize = 0; totalPackSize = newPackSize; RINOK(extractCallback->SetTotal(totalPackSize)); } } } #ifndef _NO_CRYPTO bool passwordIsDefined; UString password; RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)); if (passwordIsDefined) { RINOK(extractCallback->SetPassword(password)); } #endif FOR_VECTOR (k, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[k]; const CArcErrorInfo &er = arc.ErrorInfo; if (er.ErrorFormatIndex >= 0) { RINOK(extractCallback->OpenTypeWarning(arc.Path, codecs->GetFormatNamePtr(arc.FormatIndex), codecs->GetFormatNamePtr(er.ErrorFormatIndex))) /* UString s = L"Can not open the file as [" + codecs->Formats[arc.ErrorFormatIndex].Name + L"] archive\n"; s += L"The file is open as [" + codecs->Formats[arc.FormatIndex].Name + L"] archive"; RINOK(extractCallback->MessageError(s)); */ } { const UString &s = er.ErrorMessage; if (!s.IsEmpty()) { RINOK(extractCallback->MessageError(s)); } } } CArc &arc = arcLink.Arcs.Back(); arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); arc.MTime = fi.MTime; UInt64 packProcessed; bool calcCrc = #ifndef _SFX (hash != NULL); #else false; #endif RINOK(DecompressArchive( codecs, arcLink, fi.Size + arcLink.VolumesSize, wildcardCensor, options, calcCrc, extractCallback, ecs, errorMessage, packProcessed)); if (!options.StdInMode) packProcessed = fi.Size + arcLink.VolumesSize; totalPackProcessed += packProcessed; ecs->LocalProgressSpec->InSize += packProcessed; ecs->LocalProgressSpec->OutSize = ecs->UnpackSize; if (!errorMessage.IsEmpty()) return E_FAIL; } if (multi || thereAreNotOpenArcs) { RINOK(extractCallback->SetTotal(totalPackSize)); RINOK(extractCallback->SetCompleted(&totalPackProcessed)); } stat.NumFolders = ecs->NumFolders; stat.NumFiles = ecs->NumFiles; stat.NumAltStreams = ecs->NumAltStreams; stat.UnpackSize = ecs->UnpackSize; stat.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; stat.NumArchives = arcPaths.Size(); stat.PackSize = ecs->LocalProgressSpec->InSize; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.h0100777000000000000000000000364113761647206023343 0ustar00// Extract.h #ifndef __EXTRACT_H #define __EXTRACT_H #include "../../../Windows/FileFind.h" #include "../../Archive/IArchive.h" #include "ArchiveExtractCallback.h" #include "ArchiveOpenCallback.h" #include "ExtractMode.h" #include "Property.h" #include "../Common/LoadCodecs.h" struct CExtractOptionsBase { CBoolPair ElimDup; bool PathMode_Force; bool OverwriteMode_Force; NExtract::NPathMode::EEnum PathMode; NExtract::NOverwriteMode::EEnum OverwriteMode; FString OutputDir; CExtractNtOptions NtOptions; CExtractOptionsBase(): PathMode_Force(false), OverwriteMode_Force(false), PathMode(NExtract::NPathMode::kFullPaths), OverwriteMode(NExtract::NOverwriteMode::kAsk) {} }; struct CExtractOptions: public CExtractOptionsBase { bool StdInMode; bool StdOutMode; bool YesToAll; bool TestMode; // bool ShowDialog; // bool PasswordEnabled; // UString Password; #ifndef _SFX CObjectVector Properties; #endif #ifdef EXTERNAL_CODECS CCodecs *Codecs; #endif CExtractOptions(): TestMode(false), StdInMode(false), StdOutMode(false), YesToAll(false) {} }; struct CDecompressStat { UInt64 NumArchives; UInt64 UnpackSize; UInt64 AltStreams_UnpackSize; UInt64 PackSize; UInt64 NumFolders; UInt64 NumFiles; UInt64 NumAltStreams; void Clear() { NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0; } }; HRESULT Extract( CCodecs *codecs, const CObjectVector &types, const CIntVector &excludedFormats, UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, #ifndef _SFX IHashCalc *hash, #endif UString &errorMessage, CDecompressStat &stat); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp0100777000000000000000000000775313761647206026021 0ustar00// ExtractingFilePath.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileName.h" #include "ExtractingFilePath.h" static UString ReplaceIncorrectChars(const UString &s, bool repaceColon) { #ifdef _WIN32 UString res; bool beforeColon = true; { for (unsigned i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if (beforeColon) if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"') c = '_'; if (c == ':') { if (repaceColon) c = '_'; else beforeColon = false; } res += c; } } if (beforeColon) { for (int i = res.Len() - 1; i >= 0; i--) { wchar_t c = res[i]; if (c != '.' && c != ' ') break; res.ReplaceOneCharAtPos(i, '_'); } } return res; #else return s; #endif } #ifdef _WIN32 static const wchar_t *g_ReservedNames[] = { L"CON", L"PRN", L"AUX", L"NUL" }; static bool CheckTail(const UString &name, unsigned len) { int dotPos = name.Find(L'.'); if (dotPos < 0) dotPos = name.Len(); UString s = name.Left(dotPos); s.TrimRight(); return s.Len() != len; } static bool CheckNameNum(const UString &name, const wchar_t *reservedName) { unsigned len = MyStringLen(reservedName); if (name.Len() <= len) return true; if (MyStringCompareNoCase_N(name, reservedName, len) != 0) return true; wchar_t c = name[len]; if (c < L'0' || c > L'9') return true; return CheckTail(name, len + 1); } static bool IsSupportedName(const UString &name) { for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++) { const wchar_t *reservedName = g_ReservedNames[i]; unsigned len = MyStringLen(reservedName); if (name.Len() < len) continue; if (MyStringCompareNoCase_N(name, reservedName, len) != 0) continue; if (!CheckTail(name, len)) return false; } if (!CheckNameNum(name, L"COM")) return false; return CheckNameNum(name, L"LPT"); } #endif static UString GetCorrectFileName(const UString &path, bool repaceColon) { if (path == L".." || path == L".") return UString(); return ReplaceIncorrectChars(path, repaceColon); } void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon) { for (unsigned i = 0; i < pathParts.Size();) { UString &s = pathParts[i]; #ifdef _WIN32 bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1); if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s)) { UString s2 = s[0]; s2 += L'_'; s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon); s = s2; } else s = GetCorrectFileName(s, needReplaceColon); #endif if (s.IsEmpty()) pathParts.Delete(i); else { #ifdef _WIN32 if (!IsSupportedName(s)) s = (UString)L"_" + s; #endif i++; } } } UString MakePathNameFromParts(const UStringVector &parts) { UString result; FOR_VECTOR (i, parts) { if (i != 0) result += WCHAR_PATH_SEPARATOR; result += parts[i]; } return result; } static const wchar_t *k_EmptyReplaceName = L"[]"; void Correct_IfEmptyLastPart(UStringVector &parts) { if (parts.IsEmpty()) parts.Add(k_EmptyReplaceName); else { UString &s = parts.Back(); if (s.IsEmpty()) s = k_EmptyReplaceName; } } UString GetCorrectFsPath(const UString &path) { UString res = GetCorrectFileName(path, true); #ifdef _WIN32 if (!IsSupportedName(res)) res = (UString)L"_" + res; #endif if (res.IsEmpty()) res = k_EmptyReplaceName; return res; } UString GetCorrectFullFsPath(const UString &path) { UStringVector parts; SplitPathToParts(path, parts); FOR_VECTOR (i, parts) { UString &s = parts[i]; #ifdef _WIN32 while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' ')) s.DeleteBack(); if (!IsSupportedName(s)) s.InsertAtFront(L'_'); #endif } return MakePathNameFromParts(parts); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h0100777000000000000000000000120413761647206025447 0ustar00// ExtractingFilePath.h #ifndef __EXTRACTING_FILE_PATH_H #define __EXTRACTING_FILE_PATH_H #include "../../../Common/MyString.h" UString MakePathNameFromParts(const UStringVector &parts); /* for WIN32: if (isRoot == true), and pathParts[0] contains path like "c:name", it thinks that "c:" is drive prefix (it's not ":name alt stream) and the function changes part to c_name */ void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon); UString GetCorrectFsPath(const UString &path); UString GetCorrectFullFsPath(const UString &path); void Correct_IfEmptyLastPart(UStringVector &parts); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h0100777000000000000000000000051113761647206024141 0ustar00// ExtractMode.h #ifndef __EXTRACT_MODE_H #define __EXTRACT_MODE_H namespace NExtract { namespace NPathMode { enum EEnum { kFullPaths, kCurPaths, kNoPaths, kAbsPaths }; } namespace NOverwriteMode { enum EEnum { kAsk, kOverwrite, kSkip, kRename, kRenameExisting }; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/HashCalc.cpp0100777000000000000000000002033713761647206023733 0ustar00// HashCalc.cpp #include "StdAfx.h" #include "../../../../C/Alloc.h" #include "../../../Common/StringToInt.h" #include "../../Common/FileStreams.h" #include "../../Common/StreamUtils.h" #include "EnumDirItems.h" #include "HashCalc.h" using namespace NWindows; class CHashMidBuf { void *_data; public: CHashMidBuf(): _data(0) {} operator void *() { return _data; } bool Alloc(size_t size) { if (_data != 0) return false; _data = ::MidAlloc(size); return _data != 0; } ~CHashMidBuf() { ::MidFree(_data); } }; struct CEnumDirItemCallback_Hash: public IEnumDirItemCallback { IHashCallbackUI *Callback; HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) { return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); } }; static const wchar_t *k_DefaultHashMethod = L"CRC32"; HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods) { UStringVector names = hashMethods; if (names.IsEmpty()) names.Add(k_DefaultHashMethod); CRecordVector ids; CObjectVector methods; unsigned i; for (i = 0; i < names.Size(); i++) { COneMethodInfo m; RINOK(m.ParseMethodFromString(names[i])); if (m.MethodName.IsEmpty()) m.MethodName = k_DefaultHashMethod; if (m.MethodName == L"*") { CRecordVector tempMethods; GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); methods.Clear(); ids.Clear(); FOR_VECTOR (t, tempMethods) { int index = ids.AddToUniqueSorted(tempMethods[t]); if (ids.Size() != methods.Size()) methods.Insert(index, m); } break; } else { // m.MethodName.RemoveChar(L'-'); CMethodId id; if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id)) return E_NOTIMPL; int index = ids.AddToUniqueSorted(id); if (ids.Size() != methods.Size()) methods.Insert(index, m); } } for (i = 0; i < ids.Size(); i++) { CMyComPtr hasher; UString name; RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher)); if (!hasher) throw "Can't create hasher"; const COneMethodInfo &m = methods[i]; { CMyComPtr scp; hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { RINOK(m.SetCoderProps(scp, NULL)); } } UInt32 digestSize = hasher->GetDigestSize(); if (digestSize > k_HashCalc_DigestSize_Max) return E_NOTIMPL; CHasherState &h = Hashers.AddNew(); h.Hasher = hasher; h.Name = name; h.DigestSize = digestSize; for (int i = 0; i < k_HashCalc_NumGroups; i++) memset(h.Digests[i], 0, digestSize); } return S_OK; } void CHashBundle::InitForNewFile() { CurSize = 0; FOR_VECTOR (i, Hashers) { CHasherState &h = Hashers[i]; h.Hasher->Init(); memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize); } } void CHashBundle::Update(const void *data, UInt32 size) { CurSize += size; FOR_VECTOR (i, Hashers) Hashers[i].Hasher->Update(data, size); } void CHashBundle::SetSize(UInt64 size) { CurSize = size; } static void AddDigests(Byte *dest, const Byte *src, UInt32 size) { unsigned next = 0; for (UInt32 i = 0; i < size; i++) { next += (unsigned)dest[i] + (unsigned)src[i]; dest[i] = (Byte)next; next >>= 8; } } void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) { if (isDir) NumDirs++; else if (isAltStream) { NumAltStreams++; AltStreamsSize += CurSize; } else { NumFiles++; FilesSize += CurSize; } Byte pre[16]; memset(pre, 0, sizeof(pre)); if (isDir) pre[0] = 1; FOR_VECTOR (i, Hashers) { CHasherState &h = Hashers[i]; if (!isDir) { h.Hasher->Final(h.Digests[0]); if (!isAltStream) AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize); } h.Hasher->Init(); h.Hasher->Update(pre, sizeof(pre)); h.Hasher->Update(h.Digests[0], h.DigestSize); for (unsigned k = 0; k < path.Len(); k++) { wchar_t c = path[k]; Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; h.Hasher->Update(temp, 2); } Byte tempDigest[k_HashCalc_DigestSize_Max]; h.Hasher->Final(tempDigest); if (!isAltStream) AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize); AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize); } } HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, const CHashOptions &options, UString &errorInfo, IHashCallbackUI *callback) { CDirItems dirItems; UInt64 numErrors = 0; UInt64 totalBytes = 0; if (options.StdInMode) { CDirItem di; di.Size = (UInt64)(Int64)-1; di.Attrib = 0; di.MTime.dwLowDateTime = 0; di.MTime.dwHighDateTime = 0; di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } else { CEnumDirItemCallback_Hash enumCallback; enumCallback.Callback = callback; RINOK(callback->StartScanning()); dirItems.ScanAltStreams = options.AltStreamsMode; HRESULT res = EnumerateItems(censor, options.PathMode, UString(), dirItems, &enumCallback); totalBytes = dirItems.TotalSize; FOR_VECTOR (i, dirItems.ErrorPaths) { RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); } numErrors = dirItems.ErrorPaths.Size(); if (res != S_OK) { if (res != E_ABORT) errorInfo = L"Scanning error"; return res; } RINOK(callback->FinishScanning()); } unsigned i; CHashBundle hb; RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods)); hb.Init(); hb.NumErrors = numErrors; if (options.StdInMode) { RINOK(callback->SetNumFiles(1)); } else { RINOK(callback->SetTotal(totalBytes)); } const UInt32 kBufSize = 1 << 15; CHashMidBuf buf; if (!buf.Alloc(kBufSize)) return E_OUTOFMEMORY; UInt64 completeValue = 0; RINOK(callback->BeforeFirstFile(hb)); for (i = 0; i < dirItems.Items.Size(); i++) { CMyComPtr inStream; UString path; bool isDir = false; bool isAltStream = false; if (options.StdInMode) { inStream = new CStdInFileStream; } else { CInFileStream *inStreamSpec = new CInFileStream; inStream = inStreamSpec; const CDirItem &dirItem = dirItems.Items[i]; isDir = dirItem.IsDir(); isAltStream = dirItem.IsAltStream; path = dirItems.GetLogPath(i); if (!isDir) { UString phyPath = dirItems.GetPhyPath(i); if (!inStreamSpec->OpenShared(us2fs(phyPath), options.OpenShareForWrite)) { HRESULT res = callback->OpenFileError(phyPath, ::GetLastError()); hb.NumErrors++; if (res != S_FALSE) return res; continue; } } } RINOK(callback->GetStream(path, isDir)); UInt64 fileSize = 0; hb.InitForNewFile(); if (!isDir) { for (UInt32 step = 0;; step++) { if ((step & 0xFF) == 0) RINOK(callback->SetCompleted(&completeValue)); UInt32 size; RINOK(inStream->Read(buf, kBufSize, &size)); if (size == 0) break; hb.Update(buf, size); fileSize += size; completeValue += size; } } hb.Final(isDir, isAltStream, path); RINOK(callback->SetOperationResult(fileSize, hb, !isDir)); RINOK(callback->SetCompleted(&completeValue)); } return callback->AfterLastFile(hb); } static inline char GetHex(Byte value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } void AddHashHexToString(char *dest, const Byte *data, UInt32 size) { dest[size * 2] = 0; if (!data) { for (UInt32 i = 0; i < size; i++) { dest[0] = ' '; dest[1] = ' '; dest += 2; } return; } int step = 2; if (size <= 8) { step = -2; dest += size * 2 - 2; } for (UInt32 i = 0; i < size; i++) { Byte b = data[i]; dest[0] = GetHex((Byte)((b >> 4) & 0xF)); dest[1] = GetHex((Byte)(b & 0xF)); dest += step; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/HashCalc.h0100777000000000000000000000547213761647206023403 0ustar00// HashCalc.h #ifndef __HASH_CALC_H #define __HASH_CALC_H #include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" #include "../../Common/MethodProps.h" #include "Property.h" const unsigned k_HashCalc_DigestSize_Max = 64; const unsigned k_HashCalc_NumGroups = 4; enum { k_HashCalc_Index_Current, k_HashCalc_Index_DataSum, k_HashCalc_Index_NamesSum, k_HashCalc_Index_StreamsSum }; struct CHasherState { CMyComPtr Hasher; UString Name; UInt32 DigestSize; Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max]; }; struct IHashCalc { virtual void InitForNewFile() = 0; virtual void Update(const void *data, UInt32 size) = 0; virtual void SetSize(UInt64 size) = 0; virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0; }; struct CHashBundle: public IHashCalc { CObjectVector Hashers; UInt64 NumFiles; UInt64 NumDirs; UInt64 NumAltStreams; UInt64 FilesSize; UInt64 AltStreamsSize; UInt64 NumErrors; UInt64 CurSize; HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods); void Init() { NumFiles = NumDirs = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0; } void InitForNewFile(); void Update(const void *data, UInt32 size); void SetSize(UInt64 size); void Final(bool isDir, bool isAltStream, const UString &path); }; #define INTERFACE_IHashCallbackUI(x) \ virtual HRESULT StartScanning() x; \ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT FinishScanning() x; \ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ virtual HRESULT SetTotal(UInt64 size) x; \ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ virtual HRESULT CheckBreak() x; \ virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x; \ virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x; \ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \ virtual HRESULT AfterLastFile(const CHashBundle &hb) x; \ struct IHashCallbackUI { INTERFACE_IHashCallbackUI(=0) }; struct CHashOptions { UStringVector Methods; bool OpenShareForWrite; bool StdInMode; bool AltStreamsMode; NWildcard::ECensorPathMode PathMode; CHashOptions(): StdInMode(false), OpenShareForWrite(false), AltStreamsMode(false), PathMode(NWildcard::k_RelatPath) {}; }; HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, const CHashOptions &options, UString &errorInfo, IHashCallbackUI *callback); void AddHashHexToString(char *dest, const Byte *data, UInt32 size); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h0100777000000000000000000000424413761647206025671 0ustar00// IFileExtractCallback.h #ifndef __I_FILE_EXTRACT_CALLBACK_H #define __I_FILE_EXTRACT_CALLBACK_H #include "../../../Common/MyString.h" #include "../../IDecl.h" namespace NOverwriteAnswer { enum EEnum { kYes, kYesToAll, kNo, kNoToAll, kAutoRename, kCancel }; } DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07) { public: STDMETHOD(AskOverwrite)( const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, Int32 *answer) PURE; STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE; STDMETHOD(MessageError)(const wchar_t *message) PURE; STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE; }; struct IExtractCallbackUI: IFolderArchiveExtractCallback { virtual HRESULT BeforeOpen(const wchar_t *name) = 0; virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0; virtual HRESULT SetError(int level, const wchar_t *name, UInt32 errorFlags, const wchar_t *errors, UInt32 warningFlags, const wchar_t *warnings) = 0; virtual HRESULT ThereAreNoFiles() = 0; virtual HRESULT ExtractResult(HRESULT result) = 0; virtual HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType) = 0; #ifndef _NO_CRYPTO virtual HRESULT SetPassword(const UString &password) = 0; #endif }; #define INTERFACE_IGetProp(x) \ STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \ DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20) { INTERFACE_IGetProp(PURE) }; #define INTERFACE_IFolderExtractToStreamCallback(x) \ STDMETHOD(UseExtractToStream)(Int32 *res) x; \ STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \ STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \ STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, bool encrypted) x; \ DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30) { INTERFACE_IFolderExtractToStreamCallback(PURE) }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp0100777000000000000000000005321413761647206024265 0ustar00// LoadCodecs.cpp #include "StdAfx.h" #include "../../../../C/7zVersion.h" #include "../../../Common/MyCom.h" #include "../../../Common/StringToInt.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" #include "LoadCodecs.h" using namespace NWindows; #ifdef NEW_FOLDER_INTERFACE #include "../../../Common/StringToInt.h" #endif #include "../../ICoder.h" #include "../../Common/RegisterArc.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/FileFind.h" #include "../../../Windows/DLL.h" #ifdef NEW_FOLDER_INTERFACE #include "../../../Windows/ResourceString.h" static const UINT kIconTypesResId = 100; #endif #ifdef _WIN32 #include "../../../Windows/FileName.h" #include "../../../Windows/Registry.h" #else #include "../../../Common/StringConvert.h" #endif using namespace NFile; #ifdef _WIN32 extern HINSTANCE g_hInstance; #endif #define kCodecsFolderName FTEXT("Codecs") #define kFormatsFolderName FTEXT("Formats") static CFSTR kMainDll = FTEXT("7z.dll"); #ifdef _WIN32 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); static LPCWSTR kProgramPathValue = L"Path"; static LPCWSTR kProgramPath2Value = L"Path" #ifdef _WIN64 L"64"; #else L"32"; #endif static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) { NRegistry::CKey key; if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) { UString pathU; if (key.QueryValue(value, pathU) == ERROR_SUCCESS) { path = us2fs(pathU); NName::NormalizeDirPathPrefix(path); return NFind::DoesFileExist(path + kMainDll); } } return false; } #endif // _WIN32 #endif // EXTERNAL_CODECS static const unsigned kNumArcsMax = 48; static unsigned g_NumArcs = 0; static const CArcInfo *g_Arcs[kNumArcsMax]; void RegisterArc(const CArcInfo *arcInfo) throw() { if (g_NumArcs < kNumArcsMax) { g_Arcs[g_NumArcs] = arcInfo; g_NumArcs++; } } static void SplitString(const UString &srcString, UStringVector &destStrings) { destStrings.Clear(); UString s; unsigned len = srcString.Len(); if (len == 0) return; for (unsigned i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L' ') { if (!s.IsEmpty()) { destStrings.Add(s); s.Empty(); } } else s += c; } if (!s.IsEmpty()) destStrings.Add(s); } int CArcInfoEx::FindExtension(const UString &ext) const { FOR_VECTOR (i, Exts) if (ext.IsEqualToNoCase(Exts[i].Ext)) return i; return -1; } void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) { UStringVector exts, addExts; SplitString(ext, exts); SplitString(addExt, addExts); FOR_VECTOR (i, exts) { CArcExtInfo extInfo; extInfo.Ext = exts[i]; if (i < addExts.Size()) { extInfo.AddExt = addExts[i]; if (extInfo.AddExt == L"*") extInfo.AddExt.Empty(); } Exts.Add(extInfo); } } #ifndef _SFX static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector &signatures) { signatures.Clear(); while (size > 0) { unsigned len = *data++; size--; if (len > size) return false; signatures.AddNew().CopyFrom(data, len); data += len; size -= len; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS static FString GetBaseFolderPrefixFromRegistry() { FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); #ifdef _WIN32 if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) && !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) && !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName)) { FString path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; } #endif return moduleFolderPrefix; } static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, PROPID propId, CLSID &clsId, bool &isAssigned) { NCOM::CPropVariant prop; isAssigned = false; RINOK(getMethodProperty(index, propId, &prop)); if (prop.vt == VT_BSTR) { if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; isAssigned = true; clsId = *(const GUID *)prop.bstrVal; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT CCodecs::LoadCodecs() { CCodecLib &lib = Libs.Back(); lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty"); if (lib.GetMethodProperty) { UInt32 numMethods = 1; Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods"); if (getNumberOfMethodsFunc) { RINOK(getNumberOfMethodsFunc(&numMethods)); } for (UInt32 i = 0; i < numMethods; i++) { CDllCodecInfo info; info.LibIndex = Libs.Size() - 1; info.CodecIndex = i; RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)); RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)); Codecs.Add(info); } } Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers"); if (getHashers) { RINOK(getHashers(&lib.Hashers)); if (lib.Hashers) { UInt32 numMethods = lib.Hashers->GetNumHashers(); for (UInt32 i = 0; i < numMethods; i++) { CDllHasherInfo info; info.LibIndex = Libs.Size() - 1; info.HasherIndex = i; Hashers.Add(info); } } } return S_OK; } static HRESULT GetProp( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, NCOM::CPropVariant &prop) { if (getProp2) return getProp2(index, propID, &prop);; return getProp(propID, &prop); } static HRESULT GetProp_Bool( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, bool &res) { res = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BOOL) res = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_UInt32( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UInt32 &res, bool &defined) { res = 0; defined = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_UI4) { res = prop.ulVal; defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_String( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UString &res) { res.Empty(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) res = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_RawData( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, CByteBuffer &bb) { bb.Free(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) { UINT len = ::SysStringByteLen(prop.bstrVal); bb.CopyFrom((const Byte *)prop.bstrVal, len); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static const UInt32 kArcFlagsPars[] = { NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure }; HRESULT CCodecs::LoadFormats() { const NDLL::CLibrary &lib = Libs.Back().Lib; Func_GetHandlerProperty getProp = NULL; Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2"); Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc"); UInt32 numFormats = 1; if (getProp2) { Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats"); if (getNumberOfFormats) { RINOK(getNumberOfFormats(&numFormats)); } } else { getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty"); if (!getProp) return S_OK; } for (UInt32 i = 0; i < numFormats; i++) { CArcInfoEx item; item.LibIndex = Libs.Size() - 1; item.FormatIndex = i; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)); { NCOM::CPropVariant prop; if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) continue; if (prop.vt != VT_BSTR) continue; if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; item.ClassID = *(const GUID *)prop.bstrVal; prop.Clear(); } UString ext, addExt; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)); RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)); item.AddExts(ext, addExt); GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); bool flags_Defined = false; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)); item.NewInterface = flags_Defined; if (!flags_Defined) // && item.UpdateEnabled { // support for DLL version before 9.31: for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2) { bool val = false; GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); if (val) item.Flags |= kArcFlagsPars[j + 1]; } } CByteBuffer sig; RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); if (sig.Size() != 0) item.Signatures.Add(sig); else { RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)); ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); } bool signatureOffset_Defined; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)); // bool version_Defined; // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); if (getIsArc) getIsArc(i, &item.IsArcFunc); Formats.Add(item); } return S_OK; } #ifdef NEW_FOLDER_INTERFACE void CCodecIcons::LoadIcons(HMODULE m) { #ifdef _WIN32 UString iconTypes; MyLoadString(m, kIconTypesResId, iconTypes); UStringVector pairs; SplitString(iconTypes, pairs); FOR_VECTOR (i, pairs) { const UString &s = pairs[i]; int pos = s.Find(L':'); CIconPair iconPair; iconPair.IconIndex = -1; if (pos < 0) pos = s.Len(); else { UString num = s.Ptr(pos + 1); if (!num.IsEmpty()) { const wchar_t *end; iconPair.IconIndex = ConvertStringToUInt32(num, &end); if (*end != 0) continue; } } iconPair.Ext = s.Left(pos); IconPairs.Add(iconPair); } #endif // #ifdef _WIN32 } bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const { #ifdef _WIN32 iconIndex = -1; FOR_VECTOR (i, IconPairs) { const CIconPair &pair = IconPairs[i]; if (ext.IsEqualToNoCase(pair.Ext)) { iconIndex = pair.IconIndex; return true; } } #endif // #ifdef _WIN32 return false; } #endif // EXTERNAL_CODECS #ifdef _7ZIP_LARGE_PAGES extern "C" { extern size_t g_LargePageSize; } #endif HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll) { #ifdef _WIN32 if (needCheckDll) { NDLL::CLibrary library; if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) return S_OK; } #endif Libs.Add(CCodecLib()); CCodecLib &lib = Libs.Back(); lib.Path = dllPath; bool used = false; HRESULT res = S_OK; if (lib.Lib.Load(dllPath)) { #ifdef NEW_FOLDER_INTERFACE lib.LoadIcons(); #endif #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0) { Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode"); if (setLargePageMode) setLargePageMode(); } #endif if (CaseSensitiveChange) { Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive"); if (setCaseSensitive) setCaseSensitive(CaseSensitive ? 1 : 0); } lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject"); if (lib.CreateObject) { unsigned startSize = Codecs.Size() + Hashers.Size(); res = LoadCodecs(); used = (startSize != Codecs.Size() + Hashers.Size()); if (res == S_OK) { startSize = Formats.Size(); res = LoadFormats(); if (startSize != Formats.Size()) used = true; } } } if (!used) Libs.DeleteBack(); return res; } HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix) { NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK); NFile::NFind::CFileInfo fi; while (enumerator.Next(fi)) { if (fi.IsDir()) continue; RINOK(LoadDll(folderPrefix + fi.Name, true)); } return S_OK; } #endif HRESULT CCodecs::Load() { #ifdef NEW_FOLDER_INTERFACE #ifdef _WIN32 InternalIcons.LoadIcons(g_hInstance); #endif #endif Formats.Clear(); #ifdef EXTERNAL_CODECS Codecs.Clear(); Hashers.Clear(); #endif for (UInt32 i = 0; i < g_NumArcs; i++) { const CArcInfo &arc = *g_Arcs[i]; CArcInfoEx item; item.Name.SetFromAscii(arc.Name); item.CreateInArchive = arc.CreateInArchive; item.IsArcFunc = arc.IsArc; item.Flags = arc.Flags; { UString e, ae; if (arc.Ext) e.SetFromAscii(arc.Ext); if (arc.AddExt) ae.SetFromAscii(arc.AddExt); item.AddExts(e, ae); } #ifndef _SFX item.CreateOutArchive = arc.CreateOutArchive; item.UpdateEnabled = (arc.CreateOutArchive != NULL); item.SignatureOffset = arc.SignatureOffset; // item.Version = MY_VER_MIX; item.NewInterface = true; if (arc.IsMultiSignature()) ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); else item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); #endif Formats.Add(item); } #ifdef EXTERNAL_CODECS const FString baseFolder = GetBaseFolderPrefixFromRegistry(); RINOK(LoadDll(baseFolder + kMainDll, false)); RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR)); RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR)); #endif return S_OK; } #ifndef _SFX int CCodecs::FindFormatForArchiveName(const UString &arcPath) const { int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR); int dotPos = arcPath.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos) return -1; const UString ext = arcPath.Ptr(dotPos + 1); if (ext.IsEmpty()) return -1; if (ext.IsEqualToNoCase(L"exe")) return -1; FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; /* if (!arc.UpdateEnabled) continue; */ if (arc.FindExtension(ext) >= 0) return i; } return -1; } int CCodecs::FindFormatForExtension(const UString &ext) const { if (ext.IsEmpty()) return -1; FOR_VECTOR (i, Formats) if (Formats[i].FindExtension(ext) >= 0) return i; return -1; } int CCodecs::FindFormatForArchiveType(const UString &arcType) const { FOR_VECTOR (i, Formats) if (Formats[i].Name.IsEqualToNoCase(arcType)) return i; return -1; } bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const { formatIndices.Clear(); for (unsigned pos = 0; pos < arcType.Len();) { int pos2 = arcType.Find('.', pos); if (pos2 < 0) pos2 = arcType.Len(); const UString name = arcType.Mid(pos, pos2 - pos); if (name.IsEmpty()) return false; int index = FindFormatForArchiveType(name); if (index < 0 && name != L"*") { formatIndices.Clear(); return false; } formatIndices.Add(index); pos = pos2 + 1; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS // #define EXPORT_CODECS #ifdef EXPORT_CODECS extern unsigned g_NumCodecs; STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject); STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_CODECS g_NumCodecs extern unsigned g_NumHashers; STDAPI CreateHasher(UInt32 index, IHasher **hasher); STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_HASHERS g_NumHashers #else // EXPORT_CODECS #define NUM_EXPORT_CODECS 0 #define NUM_EXPORT_HASHERS 0 #endif // EXPORT_CODECS STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods) { *numMethods = NUM_EXPORT_CODECS #ifdef EXTERNAL_CODECS + Codecs.Size() #endif ; return S_OK; } STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return GetMethodProperty(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (propID == NMethodPropID::kDecoderIsAssigned || propID == NMethodPropID::kEncoderIsAssigned) { NCOM::CPropVariant prop; prop = (propID == NMethodPropID::kDecoderIsAssigned) ? ci.DecoderIsAssigned : ci.EncoderIsAssigned; prop.Detach(value); return S_OK; } return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(false, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.DecoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(true, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.EncoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP_(UInt32) CCodecs::GetNumHashers() { return NUM_EXPORT_HASHERS #ifdef EXTERNAL_CODECS + Hashers.Size() #endif ; } STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return ::GetHasherProp(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->GetHasherProp(ci.HasherIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return CreateHasher(index, hasher); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->CreateHasher(ci.HasherIndex, hasher); #else return E_FAIL; #endif } int CCodecs::GetCodecLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return -1; #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.LibIndex; #else return -1; #endif } int CCodecs::GetHasherLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return -1; #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return ci.LibIndex; #else return -1; #endif } bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) { NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK) if (prop.vt != VT_EMPTY) return true; return false; } #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.EncoderIsAssigned; #else return false; #endif } HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id) { NCOM::CPropVariant prop; RINOK(GetProperty(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; id = prop.uhVal.QuadPart; return S_OK; } UString CCodecs::GetCodecName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt64 CCodecs::GetHasherId(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return 0; return prop.uhVal.QuadPart; } UString CCodecs::GetHasherName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt32 CCodecs::GetHasherDigestSize(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop)); if (prop.vt != VT_UI4) return 0; return prop.ulVal; } #endif // EXTERNAL_CODECS qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h0100777000000000000000000001623213761647206023731 0ustar00// LoadCodecs.h #ifndef __LOAD_CODECS_H #define __LOAD_CODECS_H #include "../../../Common/MyBuffer.h" #include "../../../Common/MyCom.h" #include "../../../Common/MyString.h" #include "../../../Common/ComTry.h" #include "../../ICoder.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/DLL.h" #endif struct CDllCodecInfo { CLSID Encoder; CLSID Decoder; bool EncoderIsAssigned; bool DecoderIsAssigned; int LibIndex; UInt32 CodecIndex; }; struct CDllHasherInfo { int LibIndex; UInt32 HasherIndex; }; #include "../../Archive/IArchive.h" struct CArcExtInfo { UString Ext; UString AddExt; CArcExtInfo() {} CArcExtInfo(const UString &ext): Ext(ext) {} CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} }; struct CArcInfoEx { UInt32 Flags; Func_CreateInArchive CreateInArchive; Func_IsArc IsArcFunc; UString Name; CObjectVector Exts; #ifndef _SFX Func_CreateOutArchive CreateOutArchive; bool UpdateEnabled; bool NewInterface; // UInt32 Version; UInt32 SignatureOffset; CObjectVector Signatures; #ifdef NEW_FOLDER_INTERFACE UStringVector AssociateExts; #endif #endif #ifdef EXTERNAL_CODECS int LibIndex; UInt32 FormatIndex; CLSID ClassID; #endif bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } UString GetMainExt() const { if (Exts.IsEmpty()) return UString(); return Exts[0].Ext; } int FindExtension(const UString &ext) const; /* UString GetAllExtensions() const { UString s; for (int i = 0; i < Exts.Size(); i++) { if (i > 0) s += ' '; s += Exts[i].Ext; } return s; } */ void AddExts(const UString &ext, const UString &addExt); bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); } // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); } CArcInfoEx(): Flags(0), CreateInArchive(NULL), IsArcFunc(NULL) #ifndef _SFX , CreateOutArchive(NULL) , UpdateEnabled(false) , NewInterface(false) // , Version(0) , SignatureOffset(0) #endif #ifdef EXTERNAL_CODECS , LibIndex(-1) #endif {} }; #ifdef EXTERNAL_CODECS #ifdef NEW_FOLDER_INTERFACE struct CCodecIcons { struct CIconPair { UString Ext; int IconIndex; }; CObjectVector IconPairs; void LoadIcons(HMODULE m); bool FindIconIndex(const UString &ext, int &iconIndex) const; }; #endif struct CCodecLib #ifdef NEW_FOLDER_INTERFACE : public CCodecIcons #endif { NWindows::NDLL::CLibrary Lib; FString Path; Func_GetMethodProperty GetMethodProperty; Func_CreateObject CreateObject; CMyComPtr Hashers; #ifdef NEW_FOLDER_INTERFACE void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); } #endif CCodecLib(): GetMethodProperty(NULL) {} }; #endif class CCodecs: #ifdef EXTERNAL_CODECS public ICompressCodecsInfo, public IHashers, #else public IUnknown, #endif public CMyUnknownImp { public: #ifdef EXTERNAL_CODECS CObjectVector Libs; CRecordVector Codecs; CRecordVector Hashers; #ifdef NEW_FOLDER_INTERFACE CCodecIcons InternalIcons; #endif HRESULT LoadCodecs(); HRESULT LoadFormats(); HRESULT LoadDll(const FString &path, bool needCheckDll); HRESULT LoadDllsFromFolder(const FString &folderPrefix); HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const { return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); } #endif public: CObjectVector Formats; bool CaseSensitiveChange; bool CaseSensitive; CCodecs(): CaseSensitiveChange(false), CaseSensitive(false) {} const wchar_t *GetFormatNamePtr(int formatIndex) { return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name; } HRESULT Load(); #ifndef _SFX int FindFormatForArchiveName(const UString &arcPath) const; int FindFormatForExtension(const UString &ext) const; int FindFormatForArchiveType(const UString &arcType) const; bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; #endif #ifdef EXTERNAL_CODECS MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers) STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods); STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder); STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, void **coder); STDMETHOD_(UInt32, GetNumHashers)(); STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher); #else MY_UNKNOWN_IMP #endif // EXTERNAL_CODECS #ifdef EXTERNAL_CODECS int GetCodecLibIndex(UInt32 index); bool GetCodecEncoderIsAssigned(UInt32 index); HRESULT GetCodecId(UInt32 index, UInt64 &id); UString GetCodecName(UInt32 index); int GetHasherLibIndex(UInt32 index); UInt64 GetHasherId(UInt32 index); UString GetHasherName(UInt32 index); UInt32 GetHasherDigestSize(UInt32 index); #endif HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateInArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, (void **)&archive, false); #endif } #ifndef _SFX HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateOutArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, (void **)&archive, true); #endif } int FindOutFormatFromName(const UString &name) const { FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; if (!arc.UpdateEnabled) continue; if (arc.Name.IsEqualToNoCase(name)) return i; } return -1; } #endif // _SFX }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp0100777000000000000000000023773513761647206024504 0ustar00// OpenArchive.cpp #include "StdAfx.h" // #define SHOW_DEBUG_INFO #ifdef SHOW_DEBUG_INFO #include #endif #include "../../../../C/CpuArch.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../Common/FileStreams.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" #include "DefaultName.h" #include "OpenArchive.h" #ifndef _SFX #include "SetProperties.h" #endif #ifdef SHOW_DEBUG_INFO #define PRF(x) x #else #define PRF(x) #endif // increase it, if you need to support larger SFX stubs static const UInt64 kMaxCheckStartPosition = 1 << 22; /* Open: - formatIndex >= 0 (exact Format) 1) Open with main type. Archive handler is allowed to use archive start finder. Warning, if there is tail. - formatIndex = -1 (Parser:0) (default) - same as #1 but doesn't return Parser - formatIndex = -2 (#1) - file has supported extension (like a.7z) Open with that main type (only starting from start of file). - open OK: - if there is no tail - return OK - if there is tail: - archive is not "Self Exe" - return OK with Warning, that there is tail - archive is "Self Exe" ignore "Self Exe" stub, and tries to open tail - tail can be open as archive - shows that archive and stub size property. - tail can't be open as archive - shows Parser ??? - open FAIL: Try to open with all other types from offset 0 only. If some open type is OK and physical archive size is uequal or larger than file size, then return that archive with warning that can not be open as [extension type]. If extension was EXE, it will try to open as unknown_extension case - file has unknown extension (like a.hhh) It tries to open via parser code. - if there is full archive or tail archive and unknown block or "Self Exe" at front, it shows tail archive and stub size property. - in another cases, if there is some archive inside file, it returns parser/ - in another cases, it retuens S_FALSE - formatIndex = -3 (#2) - same as #1, but - stub (EXE) + archive is open in Parser - formatIndex = -4 (#3) - returns only Parser. skip full file archive. And show other sub-archives - formatIndex = -5 (#4) - returns only Parser. skip full file archive. And show other sub-archives for each byte pos */ using namespace NWindows; /* #ifdef _SFX #define OPEN_PROPS_PARAM #else #define OPEN_PROPS_PARAM , props #endif */ /* CArc::~CArc() { GetRawProps.Release(); Archive.Release(); printf("\nCArc::~CArc()\n"); } */ #ifndef _SFX namespace NArchive { namespace NParser { struct CParseItem { UInt64 Offset; UInt64 Size; // UInt64 OkSize; UString Name; UString Extension; FILETIME FileTime; UString Comment; UString ArcType; bool FileTime_Defined; bool UnpackSize_Defined; bool NumSubDirs_Defined; bool NumSubFiles_Defined; bool IsSelfExe; bool IsNotArcType; UInt64 UnpackSize; UInt64 NumSubDirs; UInt64 NumSubFiles; int FormatIndex; bool LenIsUnknown; CParseItem(): LenIsUnknown(false), FileTime_Defined(false), UnpackSize_Defined(false), NumSubFiles_Defined(false), NumSubDirs_Defined(false), IsSelfExe(false), IsNotArcType(false) // OkSize(0) {} /* bool IsEqualTo(const CParseItem &item) const { return Offset == item.Offset && Size == item.Size; } */ void NormalizeOffset() { if ((Int64)Offset < 0) { Size += Offset; // OkSize += Offset; Offset = 0; } } }; class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { public: CObjectVector _items; UInt64 _maxEndOffset; CMyComPtr _stream; MY_UNKNOWN_IMP2( IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); UInt64 GetLastEnd() const { if (_items.IsEmpty()) return 0; const CParseItem &back = _items.Back(); return back.Offset + back.Size; } void AddUnknownItem(UInt64 next); int FindInsertPos(const CParseItem &item); void AddItem(const CParseItem &item); // void Init(); CHandler() { _maxEndOffset = 0; } }; int CHandler::FindInsertPos(const CParseItem &item) { unsigned left = 0, right = _items.Size(); while (left != right) { unsigned mid = (left + right) / 2; const CParseItem & midItem = _items[mid]; if (item.Offset < midItem.Offset) right = mid; else if (item.Offset > midItem.Offset) left = mid + 1; else if (item.Size < midItem.Size) right = mid; else if (item.Size > midItem.Size) left = mid + 1; else { left = mid + 1; // return -1; } } return left; } void CHandler::AddUnknownItem(UInt64 next) { /* UInt64 prevEnd = 0; if (!_items.IsEmpty()) { const CParseItem &back = _items.Back(); prevEnd = back.Offset + back.Size; } */ if (_maxEndOffset < next) { CParseItem item2; item2.Offset = _maxEndOffset; item2.Size = next - _maxEndOffset; _maxEndOffset = next; _items.Add(item2); } else if (_maxEndOffset > next && !_items.IsEmpty()) { CParseItem &back = _items.Back(); if (back.LenIsUnknown) { back.Size = next - back.Offset; _maxEndOffset = next; } } } void CHandler::AddItem(const CParseItem &item) { AddUnknownItem(item.Offset); int pos = FindInsertPos(item); if (pos >= 0) { _items.Insert(pos, item); UInt64 next = item.Offset + item.Size; if (_maxEndOffset < next) _maxEndOffset = next; } } /* static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidSize, VT_UI8}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidType, VT_BSTR}, { NULL, kpidComment, VT_BSTR}, { NULL, kpidOffset, VT_UI8}, { NULL, kpidUnpackSize, VT_UI8}, // { NULL, kpidNumSubDirs, VT_UI8}, }; */ static const Byte kProps[] = { kpidPath, kpidSize, kpidMTime, kpidType, kpidComment, kpidOffset, kpidUnpackSize }; IMP_IInArchive_Props IMP_IInArchive_ArcProps_NO STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */) { COM_TRY_BEGIN { Close(); _stream = stream; } return S_OK; COM_TRY_END } STDMETHODIMP CHandler::Close() { _items.Clear(); _stream.Release(); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _items.Size(); return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; const CParseItem &item = _items[index]; switch (propID) { case kpidPath: { wchar_t sz[32]; ConvertUInt32ToString(index + 1, sz); UString s = sz; if (!item.Name.IsEmpty()) { s += L'.'; s += item.Name; } if (!item.Extension.IsEmpty()) { s += L'.'; s += item.Extension; } prop = s; break; } case kpidSize: case kpidPackSize: prop = item.Size; break; case kpidOffset: prop = item.Offset; break; case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; } prop.Detach(value); return S_OK; COM_TRY_END } HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (_stream && numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) totalSize += _items[allFilesMode ? i : indices[i]].Size; extractCallback->SetTotal(totalSize); totalSize = 0; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStream(streamSpec); streamSpec->SetStream(_stream); CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; CMyComPtr outStream(outStreamSpec); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr copyCoder = copyCoderSpec; for (i = 0; i < numItems; i++) { lps->InSize = totalSize; lps->OutSize = totalSize; RINOK(lps->SetCur()); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; Int32 index = allFilesMode ? i : indices[i]; const CParseItem &item = _items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); UInt64 unpackSize = item.Size; totalSize += unpackSize; bool skipMode = false; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); outStreamSpec->SetStream(realOutStream); realOutStream.Release(); outStreamSpec->Init(skipMode ? 0 : unpackSize, true); Int32 opRes = NExtract::NOperationResult::kOK; RINOK(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(unpackSize); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); if (outStreamSpec->GetRem() != 0) opRes = NExtract::NOperationResult::kDataError; outStreamSpec->ReleaseStream(); RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN const CParseItem &item = _items[index]; return CreateLimitedInStream(_stream, item.Offset, item.Size, stream); COM_TRY_END } }} #endif HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw() { NCOM::CPropVariant prop; result = false; RINOK(arc->GetProperty(index, propID, &prop)); if (prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsDir, result); } HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsAux, result); } HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result); } HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); } static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) { NCOM::CPropVariant prop; result = false; RINOK(arc->GetArchiveProperty(propid, &prop)); if (prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined) { defined = false; NCOM::CPropVariant prop; RINOK(arc->GetArchiveProperty(propid, &prop)); switch (prop.vt) { case VT_UI4: result = prop.ulVal; defined = true; break; case VT_I4: result = prop.lVal; defined = true; break; case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break; case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break; case VT_EMPTY: break; default: return E_FAIL; } return S_OK; } static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined) { defined = false; NCOM::CPropVariant prop; RINOK(arc->GetArchiveProperty(propid, &prop)); switch (prop.vt) { case VT_UI4: result = prop.ulVal; defined = true; break; case VT_I4: result = prop.lVal; defined = true; break; case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break; case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break; case VT_EMPTY: break; default: return E_FAIL; } return S_OK; } HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const { if (!GetRawProps) return E_FAIL; UInt32 curIndex = index; bool prevWasAltStream = false; for (;;) { UString s; #ifdef MY_CPU_LE const void *p; UInt32 size; UInt32 propType; RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)); if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) s = (const wchar_t *)p; else #endif { NCOM::CPropVariant prop; RINOK(Archive->GetProperty(curIndex, kpidName, &prop)); if (prop.vt == VT_BSTR) s = prop.bstrVal; else if (prop.vt == VT_EMPTY) s = L"[Content]"; else return E_FAIL; } if (prevWasAltStream) parts[0] = s + L":" + parts[0]; else parts.Insert(0, s); UInt32 curParent = (UInt32)(Int32)-1; UInt32 parentType = 0; RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)); if (parent == curParent) return S_OK; if (curParent == (UInt32)(Int32)-1) return E_FAIL; prevWasAltStream = (parentType == NParentType::kAltStream); curIndex = curParent; } } HRESULT CArc::GetItemPath(UInt32 index, UString &result) const { #ifdef MY_CPU_LE if (GetRawProps) { const void *p; UInt32 size; UInt32 propType; if (!IsTree) { if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK && propType == NPropDataType::kUtf16z) { unsigned len = size / 2 - 1; wchar_t *s = result.GetBuffer(len); for (unsigned i = 0; i < len; i++) { wchar_t c = GetUi16(p); p = (const void *)((const Byte *)p + 2); #if WCHAR_PATH_SEPARATOR != L'/' if (c == L'/') c = WCHAR_PATH_SEPARATOR; #endif *s++ = c; } result.ReleaseBuffer(len); if (len != 0) return S_OK; } } /* else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK && p && propType == NPropDataType::kUtf16z) { UInt32 totalSize = size; bool isOK = false; { UInt32 index2 = index; for (;;) { UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) break; if (parent == (UInt32)(Int32)-1) { isOK = true; break; } index2 = parent; UInt32 size2; const void *p2; if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) break; totalSize += size2; } } if (isOK) { wchar_t *sz = result.GetBuffer(totalSize / 2); UInt32 pos = totalSize - size; memcpy((Byte *)sz + pos, p, size - 2); UInt32 index2 = index; for (;;) { UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) break; if (parent == (UInt32)(Int32)-1) break; index2 = parent; UInt32 size2; const void *p2; if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) break; pos -= size2; memcpy((Byte *)sz + pos, p2, size2); sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':'; } result.ReleaseBuffer((totalSize - 2) / 2); #ifdef _WIN32 // result.Replace(L'/', WCHAR_PATH_SEPARATOR); #endif return S_OK; } } */ } #endif { NCOM::CPropVariant prop; RINOK(Archive->GetProperty(index, kpidPath, &prop)); if (prop.vt == VT_BSTR) result = prop.bstrVal; else if (prop.vt == VT_EMPTY) result.Empty(); else return E_FAIL; } if (result.IsEmpty()) { result = DefaultName; NCOM::CPropVariant prop; RINOK(Archive->GetProperty(index, kpidExtension, &prop)); if (prop.vt == VT_BSTR) { result += L'.'; result += prop.bstrVal; } else if (prop.vt != VT_EMPTY) return E_FAIL; } return S_OK; } HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const { RINOK(GetItemPath(index, result)); if (Ask_Deleted) { bool isDeleted = false; RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted)); if (isDeleted) result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR); } return S_OK; } #ifndef _SFX static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined) { NCOM::CPropVariant prop; defined = false; size = 0; RINOK(archive->GetProperty(index, kpidSize, &prop)); switch (prop.vt) { case VT_UI1: size = prop.bVal; break; case VT_UI2: size = prop.uiVal; break; case VT_UI4: size = prop.ulVal; break; case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; case VT_EMPTY: return S_OK; default: return E_FAIL; } defined = true; return S_OK; } #endif HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const { NCOM::CPropVariant prop; defined = false; size = 0; RINOK(Archive->GetProperty(index, kpidSize, &prop)); switch (prop.vt) { case VT_UI1: size = prop.bVal; break; case VT_UI2: size = prop.uiVal; break; case VT_UI4: size = prop.ulVal; break; case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; case VT_EMPTY: return S_OK; default: return E_FAIL; } defined = true; return S_OK; } HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const { NCOM::CPropVariant prop; defined = false; ft.dwHighDateTime = ft.dwLowDateTime = 0; RINOK(Archive->GetProperty(index, kpidMTime, &prop)); if (prop.vt == VT_FILETIME) { ft = prop.filetime; defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; else if (MTimeDefined) { ft = MTime; defined = true; } return S_OK; } #ifndef _SFX static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size) { for (size_t i = 0; i < size; i++) if (p1[i] != p2[i]) return false; return true; } static void MakeCheckOrder(CCodecs *codecs, CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, const Byte *data, size_t dataSize) { for (unsigned i = 0; i < numTypes; i++) { int index = orderIndices[i]; if (index < 0) continue; const CArcInfoEx &ai = codecs->Formats[index]; if (ai.SignatureOffset != 0) { orderIndices2.Add(index); orderIndices[i] = -1; continue; } const CObjectVector &sigs = ai.Signatures; FOR_VECTOR (k, sigs) { const CByteBuffer &sig = sigs[k]; if (sig.Size() == 0 && dataSize == 0 || sig.Size() != 0 && sig.Size() <= dataSize && TestSignature(data, sig, sig.Size())) { orderIndices2.Add(index); orderIndices[i] = -1; break; } } } } #endif #ifdef UNDER_CE static const unsigned kNumHashBytes = 1; #define HASH_VAL(buf, pos) ((buf)[pos]) #else static const unsigned kNumHashBytes = 2; #define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8)) #endif #ifndef _SFX static bool IsExeExt(const UString &ext) { return ext.IsEqualToNoCase(L"exe"); } static const char *k_PreArcFormats[] = { "pe" , "elf" , "macho" , "mub" , "te" }; static bool IsNameFromList(const UString &s, const char *names[], size_t num) { for (unsigned i = 0; i < num; i++) if (StringsAreEqualNoCase_Ascii(s, names[i])) return true; return false; } static bool IsPreArcFormat(const CArcInfoEx &ai) { if (ai.Flags_PreArc()) return true; return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats)); } static const char *k_Formats_with_simple_signuature[] = { "7z" , "xz" , "rar" , "bzip2" , "gzip" , "cab" , "wim" , "rpm" , "vhd" , "xar" }; static bool IsNewStyleSignature(const CArcInfoEx &ai) { // if (ai.Version >= 0x91F) if (ai.NewInterface) return true; return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature)); } class CArchiveOpenCallback_Offset: public IArchiveOpenCallback, #ifndef _NO_CRYPTO public ICryptoGetTextPassword, #endif public CMyUnknownImp { public: CMyComPtr Callback; UInt64 Files; UInt64 Offset; #ifndef _NO_CRYPTO CMyComPtr GetTextPassword; MY_UNKNOWN_IMP2( IArchiveOpenCallback, ICryptoGetTextPassword) #else MY_UNKNOWN_IMP1(IArchiveOpenCallback) #endif STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); #ifndef _NO_CRYPTO STDMETHOD(CryptoGetTextPassword)(BSTR *password); #endif }; #ifndef _NO_CRYPTO STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (GetTextPassword) return GetTextPassword->CryptoGetTextPassword(password); return E_NOTIMPL; COM_TRY_END } #endif STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) { return S_OK; } STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 * /* files */, const UInt64 *bytes) { if (!Callback) return S_OK; UInt64 value = Offset; if (bytes) value += *bytes; return Callback->SetCompleted(&Files, &value); } #endif UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) { if (isDefinedProp != NULL) *isDefinedProp = false; switch (prop.vt) { case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; case VT_EMPTY: return 0; default: throw 151199; } } void CArcErrorInfo::ClearErrors() { // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! ThereIsTail = false; UnexpecedEnd = false; IgnoreTail = false; // NonZerosTail = false; ErrorFlags_Defined = false; ErrorFlags = 0; WarningFlags = 0; TailSize = 0; ErrorMessage.Empty(); WarningMessage.Empty(); } HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) { // OkPhySize_Defined = false; PhySizeDefined = false; PhySize = 0; Offset = 0; AvailPhySize = FileSize - startPos; ErrorInfo.ClearErrors(); { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)); ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)); ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidError, &prop)); if (prop.vt != VT_EMPTY) ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidWarning, &prop)); if (prop.vt != VT_EMPTY) ErrorInfo.WarningMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown warning"; } if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) { RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); /* RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); if (!OkPhySize_Defined) { OkPhySize_Defined = PhySizeDefined; OkPhySize = PhySize; } */ bool offsetDefined; RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)); Int64 globalOffset = startPos + Offset; AvailPhySize = FileSize - globalOffset; if (PhySizeDefined) { UInt64 endPos = globalOffset + PhySize; if (endPos < FileSize) { AvailPhySize = PhySize; ErrorInfo.ThereIsTail = true; ErrorInfo.TailSize = FileSize - endPos; } else if (endPos > FileSize) ErrorInfo.UnexpecedEnd = true; } } return S_OK; } /* static PrintNumber(const char *s, int n) { char temp[100]; sprintf(temp, "%s %d", s, n); OutputDebugStringA(temp); } */ HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive) { // OutputDebugStringW(L"a1"); // PrintNumber("formatIndex", formatIndex); RINOK(op.codecs->CreateInArchive(formatIndex, archive)); // OutputDebugStringW(L"a2"); if (!archive) return S_OK; #ifdef EXTERNAL_CODECS { CMyComPtr setCompressCodecsInfo; archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)); } } #endif // OutputDebugStringW(ai.Name); // OutputDebugStringW(L"a3"); #ifndef _SFX const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.Flags_PreArc()) { /* we notify parsers that extract executables, that they don't need to open archive, if there is tail after executable (for SFX cases) */ CMyComPtr allowTail; archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); if (allowTail) allowTail->AllowTail(BoolToInt(true)); } if (op.props) { /* FOR_VECTOR (y, op.props) { const COptionalOpenProperties &optProps = (*op.props)[y]; if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) { RINOK(SetProperties(archive, optProps.Props)); break; } } */ RINOK(SetProperties(archive, *op.props)); } #endif return S_OK; } #ifndef _SFX static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) { pi.Extension = ai.GetMainExt(); pi.FileTime_Defined = false; pi.ArcType = ai.Name; RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); pi.IsSelfExe = ai.Flags_PreArc(); { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidMTime, &prop)); if (prop.vt == VT_FILETIME) { pi.FileTime_Defined = true; pi.FileTime = prop.filetime; } } if (!pi.FileTime_Defined) { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidCTime, &prop)); if (prop.vt == VT_FILETIME) { pi.FileTime_Defined = true; pi.FileTime = prop.filetime; } } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidName, &prop)); if (prop.vt == VT_BSTR) { pi.Name = prop.bstrVal; pi.Extension.Empty(); } else { RINOK(archive->GetArchiveProperty(kpidExtension, &prop)); if (prop.vt == VT_BSTR) pi.Extension = prop.bstrVal; } } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)); if (prop.vt == VT_BSTR) pi.Comment = prop.bstrVal; } UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); // pi.NumSubFiles = numItems; // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); // if (!pi.UnpackSize_Defined) { pi.NumSubFiles = 0; pi.NumSubDirs = 0; pi.UnpackSize = 0; for (UInt32 i = 0; i < numItems; i++) { UInt64 size = 0; bool defined = false; Archive_GetItem_Size(archive, i, size, defined); if (defined) { pi.UnpackSize_Defined = true; pi.UnpackSize += size; } bool isDir = false; Archive_IsItem_Folder(archive, i, isDir); if (isDir) pi.NumSubDirs++; else pi.NumSubFiles++; } if (pi.NumSubDirs != 0) pi.NumSubDirs_Defined = true; pi.NumSubFiles_Defined = true; } return S_OK; } #endif HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) { if (!op.stream) return S_OK; RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL)); const UInt32 kBufSize = 1 << 11; Byte buf[kBufSize]; for (;;) { UInt32 processed = 0; RINOK(op.stream->Read(buf, kBufSize, &processed)); if (processed == 0) { // ErrorInfo.NonZerosTail = false; ErrorInfo.IgnoreTail = true; return S_OK; } for (size_t i = 0; i < processed; i++) { if (buf[i] != 0) { // ErrorInfo.IgnoreTail = false; // ErrorInfo.NonZerosTail = true; return S_OK; } } } } #ifndef _SFX class CExtractCallback_To_OpenCallback: public IArchiveExtractCallback, public ICompressProgressInfo, public CMyUnknownImp { public: CMyComPtr Callback; UInt64 Files; UInt64 Offset; MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo) INTERFACE_IArchiveExtractCallback(;) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); void Init(IArchiveOpenCallback *callback) { Callback = callback; Files = 0; Offset = 0; } }; STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) { if (Callback) { UInt64 value = Offset; if (inSize) value += *inSize; return Callback->SetCompleted(&Files, &value); } return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */) { *outStream = 0; return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */) { return S_OK; } static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback, IArchiveExtractCallback *extractCallback) { /* if (needPhySize) { CMyComPtr open2; archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2); if (open2) return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); } */ RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)); if (needPhySize) { bool phySize_Defined = false; UInt64 phySize = 0; RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)); if (phySize_Defined) return S_OK; bool phySizeCantBeDetected = false;; RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); if (!phySizeCantBeDetected) { RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)); } } return S_OK; } static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) { FOR_VECTOR (i, orderIndices) if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name)) return i; return -1; } #endif HRESULT CArc::OpenStream2(const COpenOptions &op) { // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); Archive.Release(); GetRawProps.Release(); GetRootProps.Release(); ErrorInfo.ClearErrors(); ErrorInfo.ErrorFormatIndex = -1; IsParseArc = false; ArcStreamOffset = 0; // OutputDebugStringW(L"1"); // OutputDebugStringW(Path); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Ptr(dotPos + 1); } CIntVector orderIndices; bool searchMarkerInHandler = false; #ifdef _SFX searchMarkerInHandler = true; #endif CBoolArr isMainFormatArr(op.codecs->Formats.Size()); { FOR_VECTOR(i, op.codecs->Formats) isMainFormatArr[i] = false; } UInt64 maxStartOffset = op.openType.MaxStartOffset_Defined ? op.openType.MaxStartOffset : kMaxCheckStartPosition; #ifndef _SFX bool isUnknownExt = false; #endif bool isForced = false; unsigned numMainTypes = 0; int formatIndex = op.openType.FormatIndex; if (formatIndex >= 0) { isForced = true; orderIndices.Add(formatIndex); numMainTypes = 1; isMainFormatArr[formatIndex] = true; searchMarkerInHandler = true; } else { unsigned numFinded = 0; #ifndef _SFX bool isPrearcExt = false; #endif { FOR_VECTOR (i, op.codecs->Formats) { const CArcInfoEx &ai = op.codecs->Formats[i]; if (IgnoreSplit || !op.openType.CanReturnArc) if (ai.IsSplit()) continue; if (op.excludedFormats->FindInSorted(i) >= 0) continue; #ifndef _SFX if (IsPreArcFormat(ai)) isPrearcExt = true; #endif if (ai.FindExtension(extension) >= 0) { // PrintNumber("orderIndices.Insert", i); orderIndices.Insert(numFinded++, i); isMainFormatArr[i] = true; } else orderIndices.Add(i); } } if (!op.stream) { if (numFinded != 1) return E_NOTIMPL; orderIndices.DeleteFrom(1); } // PrintNumber("numFinded", numFinded ); /* if (op.openOnlySpecifiedByExtension) { if (numFinded != 0 && !IsExeExt(extension)) orderIndices.DeleteFrom(numFinded); } */ #ifndef _SFX if (op.stream && orderIndices.Size() >= 2) { RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CByteBuffer byteBuffer; CIntVector orderIndices2; if (numFinded == 0 || IsExeExt(extension)) { // signature search was here } else if (extension == L"000" || extension == L"001") { int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); if (i >= 0) { const size_t kBufSize = (1 << 10); byteBuffer.Alloc(kBufSize); size_t processedSize = kBufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize >= 16) { const Byte *buf = byteBuffer; const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) { orderIndices2.Add(orderIndices[i]); orderIndices[i] = -1; if (i >= (int)numFinded) numFinded++; } } } } else { const size_t kBufSize = (1 << 10); byteBuffer.Alloc(kBufSize); size_t processedSize = kBufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize == 0) return S_FALSE; /* check type order: 1) matched extension, no signuature 2) matched extension, matched signuature // 3) no signuature // 4) matched signuature */ MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); } FOR_VECTOR (i, orderIndices) { int val = orderIndices[i]; if (val != -1) orderIndices2.Add(val); } orderIndices = orderIndices2; } if (orderIndices.Size() >= 2) { int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); if (iUdf > iIso && iIso >= 0) { int isoIndex = orderIndices[iIso]; int udfIndex = orderIndices[iUdf]; orderIndices[iUdf] = isoIndex; orderIndices[iIso] = udfIndex; } } numMainTypes = numFinded; isUnknownExt = (numMainTypes == 0) || isPrearcExt; #else // _SFX numMainTypes = orderIndices.Size(); #endif } UInt64 fileSize = 0; if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } FileSize = fileSize; #ifndef _SFX CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); { FOR_VECTOR(i, op.codecs->Formats) skipFrontalFormat[i] = false; } #endif const COpenType &mode = op.openType; if (mode.CanReturnArc) { // ---------- OPEN main type by extenssion ---------- unsigned numCheckTypes = orderIndices.Size(); if (formatIndex >= 0) numCheckTypes = numMainTypes; for (unsigned i = 0; i < numCheckTypes; i++) { FormatIndex = orderIndices[i]; const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; // OutputDebugStringW(ai.Name); bool exactOnly = false; if (i >= numMainTypes) { if (!ai.Flags_BackwardOpen() // && !ai.Flags_PureStartOpen() ) continue; exactOnly = true; } // Some handlers do not set total bytes. So we set it here RINOK(op.callback->SetTotal(NULL, &fileSize)); if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } CMyComPtr archive; RINOK(PrepareToOpen(op, FormatIndex, archive)); if (!archive) continue; HRESULT result; if (op.stream) { UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; result = archive->Open(op.stream, &searchLimit, op.callback); } else { CMyComPtr openSeq; archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); if (!openSeq) return E_NOTIMPL; result = openSeq->OpenSeq(op.seqStream); } RINOK(ReadBasicProps(archive, 0, result)); if (result == S_FALSE) { bool isArc = ErrorInfo.IsArc_After_NonOpen(); #ifndef _SFX // if it's archive, we allow another open attempt for parser if (!mode.CanReturnParser || !isArc) skipFrontalFormat[FormatIndex] = true; #endif if (exactOnly) continue; if (i == 0 && numMainTypes == 1) { // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). ErrorInfo.ErrorFormatIndex = FormatIndex; NonOpen_ErrorInfo = ErrorInfo; if (!mode.CanReturnParser && isArc) { // if (formatIndex < 0 && !searchMarkerInHandler) { // if bad archive was detected, we don't need additional open attempts #ifndef _SFX if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) #endif return S_FALSE; } } } /* #ifndef _SFX if (IsExeExt(extension) || ai.Flags_PreArc()) { // openOnlyFullArc = false; // canReturnTailArc = true; // limitSignatureSearch = true; } #endif */ continue; } RINOK(result); #ifndef _SFX bool isMainFormat = isMainFormatArr[FormatIndex]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); bool thereIsTail = ErrorInfo.ThereIsTail; if (thereIsTail && mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, Offset + PhySize)); if (ErrorInfo.IgnoreTail) thereIsTail = false; } if (Offset > 0) { if (exactOnly || !searchMarkerInHandler || !specFlags.CanReturn_NonStart() || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) continue; } if (thereIsTail) { if (Offset > 0) { if (!specFlags.CanReturnMid) continue; } else if (!specFlags.CanReturnFrontal) continue; } if (Offset > 0 || thereIsTail) { if (formatIndex < 0) { if (IsPreArcFormat(ai)) { // openOnlyFullArc = false; // canReturnTailArc = true; /* if (mode.SkipSfxStub) limitSignatureSearch = true; */ // if (mode.SkipSfxStub) { // skipFrontalFormat[FormatIndex] = true; continue; } } } } #endif Archive = archive; return S_OK; } } #ifndef _SFX if (!op.stream) return S_FALSE; if (formatIndex >= 0 && !mode.CanReturnParser) { if (mode.MaxStartOffset_Defined) { if (mode.MaxStartOffset == 0) return S_FALSE; } else { const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.FindExtension(extension) >= 0) { const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.Flags_FindSignature() && searchMarkerInHandler) return S_FALSE; } } } NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; CMyComPtr handler = handlerSpec; CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; CMyComPtr extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; extractCallback_To_OpenCallback_Spec->Init(op.callback); { // ---------- Check all possible START archives ---------- // this code is better for full file archives than Parser's code. CByteBuffer byteBuffer; bool endOfFile = false; size_t processedSize; { size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) if (bufSize > fileSize) { bufSize = (size_t)fileSize; endOfFile = true; } byteBuffer.Alloc(bufSize); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); processedSize = bufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize == 0) return S_FALSE; if (processedSize < bufSize) endOfFile = true; } CUIntVector sortedFormats; unsigned i; int splitIndex = -1; for (i = 0; i < orderIndices.Size(); i++) { unsigned form = orderIndices[i]; if (skipFrontalFormat[form]) continue; const CArcInfoEx &ai = op.codecs->Formats[form]; if (ai.IsSplit()) { splitIndex = form; continue; } if (ai.IsArcFunc) { UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); if (isArcRes == k_IsArc_Res_NO) continue; if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) continue; // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; sortedFormats.Insert(0, form); continue; } bool isNewStyleSignature = IsNewStyleSignature(ai); bool needCheck = !isNewStyleSignature || ai.Signatures.IsEmpty() || ai.Flags_PureStartOpen() || ai.Flags_StartOpen() || ai.Flags_BackwardOpen(); if (isNewStyleSignature && !ai.Signatures.IsEmpty()) { unsigned k; for (k = 0; k < ai.Signatures.Size(); k++) { const CByteBuffer &sig = ai.Signatures[k]; UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); if (processedSize < signatureEnd) { if (!endOfFile) needCheck = true; } else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0) break; } if (k != ai.Signatures.Size()) { sortedFormats.Insert(0, form); continue; } } if (needCheck) sortedFormats.Add(form); } if (splitIndex >= 0) sortedFormats.Insert(0, splitIndex); for (i = 0; i < sortedFormats.Size(); i++) { FormatIndex = sortedFormats[i]; const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; RINOK(op.callback->SetTotal(NULL, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CMyComPtr archive; RINOK(PrepareToOpen(op, FormatIndex, archive)); if (!archive) continue; PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); HRESULT result; { UInt64 searchLimit = 0; /* if (mode.CanReturnArc) result = archive->Open(op.stream, &searchLimit, op.callback); else */ result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); } if (result == S_FALSE) { skipFrontalFormat[FormatIndex] = true; // FIXME: maybe we must use LenIsUnknown. // printf(" OpenForSize Error"); continue; } RINOK(result); RINOK(ReadBasicProps(archive, 0, result)); if (Offset > 0) { continue; // good handler doesn't return such Offset > 0 // but there are some cases like false prefixed PK00 archive, when // we can support it? } NArchive::NParser::CParseItem pi; pi.Offset = Offset; pi.Size = AvailPhySize; // bool needScan = false; if (!PhySizeDefined) { // it's for Z format pi.LenIsUnknown = true; // needScan = true; // phySize = arcRem; // nextNeedCheckStartOpen = false; } /* if (OkPhySize_Defined) pi.OkSize = pi.OkPhySize; else pi.OkSize = pi.Size; */ pi.NormalizeOffset(); // printf(" phySize = %8d", (unsigned)phySize); if (mode.CanReturnArc) { bool isMainFormat = isMainFormatArr[FormatIndex]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); bool openCur = false; if (!ErrorInfo.ThereIsTail) openCur = true; else { if (mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, Offset + PhySize)); if (ErrorInfo.IgnoreTail) openCur = true; } if (!openCur) { openCur = specFlags.CanReturnFrontal; if (formatIndex < 0) // format is not forced { if (IsPreArcFormat(ai)) { // if (mode.SkipSfxStub) { openCur = false; } } } } } if (openCur) { InStream = op.stream; Archive = archive; return S_OK; } } skipFrontalFormat[FormatIndex] = true; // if (!mode.CanReturnArc) /* if (!ErrorInfo.ThereIsTail) continue; */ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) continue; // printf("\nAdd offset = %d", (int)pi.Offset); RINOK(ReadParseItemProps(archive, ai, pi)); handlerSpec->AddItem(pi); } } // ---------- PARSER ---------- CUIntVector arc2sig; // formatIndex to signatureIndex CUIntVector sig2arc; // signatureIndex to formatIndex; { unsigned sum = 0; FOR_VECTOR (i, op.codecs->Formats) { arc2sig.Add(sum); const CObjectVector &sigs = op.codecs->Formats[i].Signatures; sum += sigs.Size(); FOR_VECTOR (k, sigs) sig2arc.Add(i); } } { CArchiveOpenCallback_Offset *openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; CMyComPtr openCallback_Offset = openCallback_Offset_Spec; const size_t kBeforeSize = 1 << 16; const size_t kAfterSize = 1 << 20; const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); CByteArr hashBuffer(kNumVals); Byte *hash = hashBuffer; memset(hash, 0xFF, kNumVals); Byte prevs[256]; memset(prevs, 0xFF, sizeof(prevs)); if (sig2arc.Size() >= 0xFF) return S_FALSE; CUIntVector difficultFormats; CBoolArr difficultBools(256); { for (unsigned i = 0; i < 256; i++) difficultBools[i] = false; } bool thereAreHandlersForSearch = false; // UInt32 maxSignatureEnd = 0; FOR_VECTOR (i, orderIndices) { int index = orderIndices[i]; if (index < 0) continue; const CArcInfoEx &ai = op.codecs->Formats[index]; bool isDifficult = false; // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) if (!ai.NewInterface) isDifficult = true; else { if (ai.Flags_StartOpen()) isDifficult = true; FOR_VECTOR (k, ai.Signatures) { const CByteBuffer &sig = ai.Signatures[k]; /* UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); if (maxSignatureEnd < signatureEnd) maxSignatureEnd = signatureEnd; */ if (sig.Size() < kNumHashBytes) { isDifficult = true; continue; } thereAreHandlersForSearch = true; UInt32 v = HASH_VAL(sig, 0); unsigned sigIndex = arc2sig[index] + k; prevs[sigIndex] = hash[v]; hash[v] = (Byte)sigIndex; } } if (isDifficult) { difficultFormats.Add(index); difficultBools[index] = true; } } if (!thereAreHandlersForSearch) { // openOnlyFullArc = true; // canReturnTailArc = true; } RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; CMyComPtr limitedStream = limitedStreamSpec; limitedStreamSpec->SetStream(op.stream); openCallback_Offset_Spec->Callback = op.callback; #ifndef _NO_CRYPTO if (op.callback) { openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); } #endif RINOK(op.callback->SetTotal(NULL, &fileSize)); CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; byteBuffer.Alloc(kBufSize); UInt64 callbackPrev = 0; bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. bool endOfFile = false; UInt64 bufPhyPos = 0; size_t bytesInBuf = 0; // UInt64 prevPos = 0; // ---------- Main Scan Loop ---------- UInt64 pos = 0; if (!mode.EachPos && handlerSpec->_items.Size() == 1) { NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; if (!pi.LenIsUnknown && pi.Offset == 0) pos = pi.Size; } for (;;) { // printf("\nPos = %d", (int)pos); UInt64 posInBuf = pos - bufPhyPos; // if (pos > ((UInt64)1 << 35)) break; if (!endOfFile) { if (bytesInBuf < kBufSize) { size_t processedSize = kBufSize - bytesInBuf; // printf("\nRead ask = %d", (unsigned)processedSize); UInt64 seekPos = bufPhyPos + bytesInBuf; RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL)); RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize)); // printf(" processed = %d", (unsigned)processedSize); if (processedSize == 0) { fileSize = seekPos; endOfFile = true; } else { bytesInBuf += processedSize; limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); } continue; } if (bytesInBuf < posInBuf) { UInt64 skipSize = posInBuf - bytesInBuf; if (skipSize <= kBeforeSize) { size_t keepSize = (size_t)(kBeforeSize - skipSize); // printf("\nmemmove skip = %d", (int)keepSize); memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize); bytesInBuf = keepSize; bufPhyPos = pos - keepSize; continue; } // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); bytesInBuf = 0; bufPhyPos = pos - kBeforeSize; continue; } if (bytesInBuf - posInBuf < kAfterSize) { size_t beg = (size_t)posInBuf - kBeforeSize; // printf("\nmemmove for after beg = %d", (int)beg); memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg); bufPhyPos += beg; bytesInBuf -= beg; continue; } } if (pos >= callbackPrev + (1 << 23)) { openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); openCallback_Offset_Spec->Offset = pos; RINOK(openCallback_Offset->SetCompleted(NULL, NULL)); callbackPrev = pos; } { UInt64 endPos = bufPhyPos + bytesInBuf; if (fileSize < endPos) { FileSize = fileSize; // why ???? fileSize = endPos; } } size_t availSize = bytesInBuf - (size_t)posInBuf; if (availSize < kNumHashBytes) break; size_t scanSize = availSize - ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); { /* UInt64 scanLimit = openOnlyFullArc ? maxSignatureEnd : op.openType.ScanSize + maxSignatureEnd; */ if (!mode.CanReturnParser) { if (pos > maxStartOffset) break; UInt64 remScan = maxStartOffset - pos; if (scanSize > remScan) scanSize = (size_t)remScan; } } scanSize++; const Byte *buf = byteBuffer + (size_t)posInBuf; size_t ppp = 0; if (!needCheckStartOpen) { for (; ppp < scanSize && hash[HASH_VAL(buf, ppp)] == 0xFF; ppp++); pos += ppp; if (ppp == scanSize) continue; } UInt32 v = HASH_VAL(buf, ppp); bool nextNeedCheckStartOpen = true; unsigned i = hash[v]; unsigned indexOfDifficult = 0; // ---------- Open Loop for Current Pos ---------- bool wasOpen = false; for (;;) { unsigned index; bool isDifficult; if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) { index = difficultFormats[indexOfDifficult++]; isDifficult = true; } else { if (i == 0xFF) break; index = sig2arc[i]; unsigned sigIndex = i - arc2sig[index]; i = prevs[i]; if (needCheckStartOpen && difficultBools[index]) continue; const CArcInfoEx &ai = op.codecs->Formats[index]; if (pos < ai.SignatureOffset) continue; /* if (openOnlyFullArc) if (pos != ai.SignatureOffset) continue; */ const CByteBuffer &sig = ai.Signatures[sigIndex]; if (ppp + sig.Size() > availSize || !TestSignature(buf + ppp, sig, sig.Size())) continue; // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); // prevPos = pos; isDifficult = false; } const CArcInfoEx &ai = op.codecs->Formats[index]; if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) { // we don't check same archive second time */ if (skipFrontalFormat[index]) continue; } UInt64 startArcPos = pos; if (!isDifficult) { if (pos < ai.SignatureOffset) continue; startArcPos = pos - ai.SignatureOffset; /* // we don't need the check for Z files if (startArcPos < handlerSpec->GetLastEnd()) continue; */ } if (ai.IsArcFunc && startArcPos >= bufPhyPos) { size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); if (offsetInBuf < bytesInBuf) { UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf); if (isArcRes == k_IsArc_Res_NO) continue; if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) continue; /* if (isArcRes == k_IsArc_Res_YES_LOW_PROB) { // if (pos != ai.SignatureOffset) continue; } */ } // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); } /* if (pos == 67109888) pos = pos; */ PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); bool isMainFormat = isMainFormatArr[index]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); CMyComPtr archive; RINOK(PrepareToOpen(op, index, archive)); if (!archive) return E_FAIL; // OutputDebugStringW(ai.Name); UInt64 rem = fileSize - startArcPos; UInt64 arcStreamOffset = 0; if (ai.Flags_UseGlobalOffset()) { limitedStreamSpec->InitAndSeek(0, fileSize); limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL); } else { limitedStreamSpec->InitAndSeek(startArcPos, rem); arcStreamOffset = startArcPos; } UInt64 maxCheckStartPosition = 0; openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); openCallback_Offset_Spec->Offset = startArcPos; // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); extractCallback_To_OpenCallback_Spec->Files = 0; extractCallback_To_OpenCallback_Spec->Offset = startArcPos; HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition, openCallback_Offset, extractCallback_To_OpenCallback); RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)); bool isOpen = false; if (result == S_FALSE) { if (!mode.CanReturnParser) { if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) { ErrorInfo.ErrorFormatIndex = index; NonOpen_ErrorInfo = ErrorInfo; // if archive was detected, we don't need additional open attempts return S_FALSE; } continue; } if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) continue; } else { isOpen = true; RINOK(result); PRF(printf(" OK ")); } // fprintf(stderr, "\n %8X %S", startArcPos, Path); // printf("\nOpen OK: %S", ai.Name); NArchive::NParser::CParseItem pi; pi.Offset = startArcPos; if (ai.Flags_UseGlobalOffset()) pi.Offset = Offset; else if (Offset != 0) return E_FAIL; UInt64 arcRem = FileSize - pi.Offset; UInt64 phySize = arcRem; bool phySizeDefined = PhySizeDefined; if (phySizeDefined) { if (pi.Offset + PhySize > FileSize) { // ErrorInfo.ThereIsTail = true; PhySize = FileSize - pi.Offset; } phySize = PhySize; } if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) return E_FAIL; /* if (!ai.UseGlobalOffset) { if (phySize > arcRem) { ThereIsTail = true; phySize = arcRem; } } */ bool needScan = false; if (isOpen && !phySizeDefined) { // it's for Z format pi.LenIsUnknown = true; needScan = true; phySize = arcRem; nextNeedCheckStartOpen = false; } pi.Size = phySize; /* if (OkPhySize_Defined) pi.OkSize = OkPhySize; */ pi.NormalizeOffset(); // printf(" phySize = %8d", (unsigned)phySize); /* if (needSkipFullArc) if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) continue; */ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) { // it's possible for dmg archives if (!mode.CanReturnArc) continue; } if (mode.EachPos) pos++; else if (needScan) { pos++; /* if (!OkPhySize_Defined) pos++; else pos = pi.Offset + pi.OkSize; */ } else pos = pi.Offset + pi.Size; RINOK(ReadParseItemProps(archive, ai, pi)); if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) { /* It's for DMG format. This code deletes all previous items that are included to current item */ while (!handlerSpec->_items.IsEmpty()) { { const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); if (back.Offset < pi.Offset) break; if (back.Offset + back.Size > pi.Offset + pi.Size) break; } handlerSpec->_items.DeleteBack(); } } if (isOpen && mode.CanReturnArc && phySizeDefined) { // if (pi.Offset + pi.Size >= fileSize) bool openCur = false; bool thereIsTail = ErrorInfo.ThereIsTail; if (thereIsTail && mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize)); if (ErrorInfo.IgnoreTail) thereIsTail = false; } if (pi.Offset != 0) { if (!pi.IsNotArcType) if (thereIsTail) openCur = specFlags.CanReturnMid; else openCur = specFlags.CanReturnTail; } else { if (!thereIsTail) openCur = true; else openCur = specFlags.CanReturnFrontal; if (formatIndex >= -2) openCur = true; } if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) openCur = false; // We open file as SFX, if there is front archive or first archive is "Self Executable" if (!openCur && !pi.IsSelfExe && !thereIsTail && (!pi.IsNotArcType || pi.Offset == 0)) { if (handlerSpec->_items.IsEmpty()) { if (specFlags.CanReturnTail) openCur = true; } else if (handlerSpec->_items.Size() == 1) { if (handlerSpec->_items[0].IsSelfExe) { if (mode.SpecUnknownExt.CanReturnTail) openCur = true; } } } if (openCur) { InStream = op.stream; Archive = archive; FormatIndex = index; ArcStreamOffset = arcStreamOffset; return S_OK; } } /* if (openOnlyFullArc) { ErrorInfo.ClearErrors(); return S_FALSE; } */ pi.FormatIndex = index; // printf("\nAdd offset = %d", (int)pi.Offset); handlerSpec->AddItem(pi); wasOpen = true; break; } // ---------- End of Open Loop for Current Pos ---------- if (!wasOpen) pos++; needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); } // ---------- End of Main Scan Loop ---------- /* if (handlerSpec->_items.Size() == 1) { const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; if (pi.Size == fileSize && pi.Offset == 0) { Archive = archive; FormatIndex2 = pi.FormatIndex; return S_OK; } } */ if (mode.CanReturnParser) { bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing handlerSpec->AddUnknownItem(fileSize); if (handlerSpec->_items.Size() == 0) return S_FALSE; if (returnParser || handlerSpec->_items.Size() != 1) { // return S_FALSE; handlerSpec->_stream = op.stream; Archive = handler; ErrorInfo.ClearErrors(); IsParseArc = true; FormatIndex = -1; // It's parser Offset = 0; return S_OK; } } } #endif if (!Archive) return S_FALSE; return S_OK; } HRESULT CArc::OpenStream(const COpenOptions &op) { RINOK(OpenStream2(op)); // PrintNumber("op.formatIndex 3", op.formatIndex); if (Archive) { GetRawProps.Release(); GetRootProps.Release(); Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Ptr(dotPos + 1); } DefaultName.Empty(); if (FormatIndex >= 0) { const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; if (ai.Exts.Size() == 0) DefaultName = GetDefaultName2(fileName, L"", L""); else { int subExtIndex = ai.FindExtension(extension); if (subExtIndex < 0) subExtIndex = 0; const CArcExtInfo &extInfo = ai.Exts[subExtIndex]; DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); } } } return S_OK; } #ifdef _SFX #ifdef _WIN32 static const wchar_t *k_ExeExt = L".exe"; static const unsigned k_ExeExt_Len = 4; #else static const wchar_t *k_ExeExt = L""; static const unsigned k_ExeExt_Len = 0; #endif #endif HRESULT CArc::OpenStreamOrFile(COpenOptions &op) { CMyComPtr fileStream; CMyComPtr seqStream; CInFileStream *fileStreamSpec = NULL; if (op.stdInMode) { seqStream = new CStdInFileStream; op.seqStream = seqStream; } else if (!op.stream) { fileStreamSpec = new CInFileStream(true); fileStream = fileStreamSpec; Path = filePath; if (!fileStreamSpec->Open(us2fs(Path))) { return GetLastError(); } op.stream = fileStream; #ifdef _SFX IgnoreSplit = true; #endif } /* if (callback) { UInt64 fileSize; RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.callback->SetTotal(NULL, &fileSize)) } */ HRESULT res = OpenStream(op); IgnoreSplit = false; #ifdef _SFX if (res != S_FALSE || !fileStreamSpec || !op.callbackSpec || NonOpen_ErrorInfo.IsArc_After_NonOpen()) return res; { if (filePath.Len() > k_ExeExt_Len && MyStringCompareNoCase(filePath.RightPtr(k_ExeExt_Len), k_ExeExt) == 0) { const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); FOR_VECTOR (i, op.codecs->Formats) { const CArcInfoEx &ai = op.codecs->Formats[i]; if (ai.IsSplit()) continue; UString path3 = path2; path3 += L"."; path3 += ai.GetMainExt(); // "7z" for SFX. Path = path3 + L".001"; bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); if (!isOk) { Path = path3; isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); } if (isOk) { if (fileStreamSpec->Open(us2fs(Path))) { op.stream = fileStream; NonOpen_ErrorInfo.ClearErrors_Full(); if (OpenStream(op) == S_OK) return S_OK; } } } } } #endif return res; } void CArchiveLink::KeepModeForNextOpen() { for (int i = Arcs.Size() - 1; i >= 0; i--) { CMyComPtr keep; Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); if (keep) keep->KeepModeForNextOpen(); } } HRESULT CArchiveLink::Close() { for (int i = Arcs.Size() - 1; i >= 0; i--) { RINOK(Arcs[i].Close()); } IsOpen = false; // ErrorsText.Empty(); return S_OK; } void CArchiveLink::Release() { // NonOpenErrorFormatIndex = -1; NonOpen_ErrorInfo.ClearErrors(); NonOpen_ArcPath.Empty(); while (!Arcs.IsEmpty()) Arcs.DeleteBack(); } /* void CArchiveLink::Set_ErrorsText() { FOR_VECTOR(i, Arcs) { const CArc &arc = Arcs[i]; if (!arc.ErrorFlagsText.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += GetUnicodeString(arc.ErrorFlagsText); } if (!arc.ErrorMessage.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += arc.ErrorMessage; } if (!arc.WarningMessage.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += arc.WarningMessage; } } } */ HRESULT CArchiveLink::Open(COpenOptions &op) { Release(); if (op.types->Size() >= 32) return E_NOTIMPL; HRESULT resSpec; for (;;) { resSpec = S_OK; op.openType = COpenType(); if (op.types->Size() >= 1) { COpenType latest; if (Arcs.Size() < op.types->Size()) latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; else { latest = (*op.types)[0]; if (!latest.Recursive) break; } op.openType = latest; } else if (Arcs.Size() >= 32) break; /* op.formatIndex = -1; if (op.types->Size() >= 1) { int latest; if (Arcs.Size() < op.types->Size()) latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; else { latest = (*op.types)[0]; if (latest != -2 && latest != -3) break; } if (latest >= 0) op.formatIndex = latest; else if (latest == -1 || latest == -2) { // default } else if (latest == -3) op.formatIndex = -2; else op.formatIndex = latest + 2; } else if (Arcs.Size() >= 32) break; */ if (Arcs.IsEmpty()) { CArc arc; arc.filePath = op.filePath; arc.Path = op.filePath; arc.SubfileIndex = (UInt32)(Int32)-1; HRESULT result = arc.OpenStreamOrFile(op); if (result != S_OK) { if (result == S_FALSE) { NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; NonOpen_ArcPath = arc.Path; } return result; } Arcs.Add(arc); continue; } // PrintNumber("op.formatIndex 11", op.formatIndex); const CArc &arc = Arcs.Back(); if (op.types->Size() > Arcs.Size()) resSpec = E_NOTIMPL; UInt32 mainSubfile; { NCOM::CPropVariant prop; RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)); if (prop.vt == VT_UI4) mainSubfile = prop.ulVal; else break; UInt32 numItems; RINOK(arc.Archive->GetNumberOfItems(&numItems)); if (mainSubfile >= numItems) break; } CMyComPtr getStream; if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) break; CMyComPtr subSeqStream; if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) break; CMyComPtr subStream; if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) break; CArc arc2; RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); bool zerosTailIsAllowed; RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); CMyComPtr setSubArchiveName; op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); if (setSubArchiveName) setSubArchiveName->SetSubArchiveName(arc2.Path); arc2.SubfileIndex = mainSubfile; // CIntVector incl; CIntVector excl; COpenOptions op2; #ifndef _SFX op2.props = op.props; #endif op2.codecs = op.codecs; // op2.types = &incl; op2.openType = op.openType; op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; op2.excludedFormats = ! op2.stdInMode = false; op2.stream = subStream; op2.filePath = arc2.Path; op2.callback = op.callback; op2.callbackSpec = op.callbackSpec; HRESULT result = arc2.OpenStream(op2); resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); if (result == S_FALSE) { NonOpen_ErrorInfo = arc2.ErrorInfo; NonOpen_ArcPath = arc2.Path; break; } RINOK(result); RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); Arcs.Add(arc2); } IsOpen = !Arcs.IsEmpty(); return resSpec; } static void SetCallback(const FString &filePath, IOpenCallbackUI *callbackUI, IArchiveOpenCallback *reOpenCallback, CMyComPtr &callback) { COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; callback = openCallbackSpec; openCallbackSpec->Callback = callbackUI; openCallbackSpec->ReOpenCallback = reOpenCallback; FString dirPrefix, fileName; NFile::NDir::GetFullPathAndSplit(filePath, dirPrefix, fileName); openCallbackSpec->Init(dirPrefix, fileName); } HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) { VolumesSize = 0; COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; CMyComPtr callback = openCallbackSpec; openCallbackSpec->Callback = callbackUI; FString prefix, name; if (!op.stream && !op.stdInMode) { NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); openCallbackSpec->Init(prefix, name); } else { openCallbackSpec->SetSubArchiveName(op.filePath); } op.callback = callback; op.callbackSpec = openCallbackSpec; RINOK(Open(op)); // VolumePaths.Add(fs2us(prefix + name)); FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) { if (openCallbackSpec->FileNames_WasUsed[i]) { VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); VolumesSize += openCallbackSpec->FileSizes[i]; } } // VolumesSize = openCallbackSpec->TotalSize; return S_OK; } HRESULT CArc::ReOpen(const COpenOptions &op) { ErrorInfo.ClearErrors(); ErrorInfo.ErrorFormatIndex = -1; UInt64 fileSize = 0; if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } FileSize = fileSize; CMyComPtr stream2; Int64 globalOffset = GetGlobalOffset(); if (globalOffset <= 0) stream2 = op.stream; else { CTailInStream *tailStreamSpec = new CTailInStream; stream2 = tailStreamSpec; tailStreamSpec->Stream = op.stream; tailStreamSpec->Offset = globalOffset; tailStreamSpec->Init(); RINOK(tailStreamSpec->SeekToStart()); } // There are archives with embedded STUBs (like ZIP), so we must support signature scanning // But for another archives we can use 0 here. So the code can be fixed !!! UInt64 maxStartPosition = kMaxCheckStartPosition; HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback); if (res == S_OK) { RINOK(ReadBasicProps(Archive, globalOffset, res)); ArcStreamOffset = globalOffset; if (ArcStreamOffset != 0) InStream = op.stream; } return res; } HRESULT CArchiveLink::ReOpen(COpenOptions &op) { if (Arcs.Size() > 1) return E_NOTIMPL; CObjectVector inc; CIntVector excl; op.types = &inc; op.excludedFormats = ! op.stdInMode = false; op.stream = NULL; if (Arcs.Size() == 0) // ??? return Open2(op, NULL); CMyComPtr openCallbackNew; SetCallback(us2fs(op.filePath), NULL, op.callback, openCallbackNew); CInFileStream *fileStreamSpec = new CInFileStream(true); CMyComPtr stream(fileStreamSpec); if (!fileStreamSpec->Open(us2fs(op.filePath))) return GetLastError(); op.stream = stream; CArc &arc = Arcs[0]; HRESULT res = arc.ReOpen(op); IsOpen = (res == S_OK); return res; } #ifndef _SFX bool ParseComplexSize(const wchar_t *s, UInt64 &result) { result = 0; const wchar_t *end; UInt64 number = ConvertStringToUInt64(s, &end); if (end == s) return false; if (*end == 0) { result = number; return true; } if (end[1] != 0) return false; unsigned numBits; switch (MyCharLower_Ascii(*end)) { case 'b': result = number; return true; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; case 't': numBits = 40; break; default: return false; } if (number >= ((UInt64)1 << (64 - numBits))) return false; result = number << numBits; return true; } static bool ParseTypeParams(const UString &s, COpenType &type) { if (s[0] == 0) return true; if (s[1] == 0) { switch ((unsigned)(Byte)s[0]) { case 'e': type.EachPos = true; return true; case 'a': type.CanReturnArc = true; return true; case 'r': type.Recursive = true; return true; } return false; } if (s[0] == 's') { UInt64 result; if (!ParseComplexSize(s.Ptr(1), result)) return false; type.MaxStartOffset = result; type.MaxStartOffset_Defined = true; return true; } return false; } bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) { int pos2 = s.Find(':'); UString name; if (pos2 < 0) { name = s; pos2 = s.Len(); } else { name = s.Left(pos2); pos2++; } int index = codecs.FindFormatForArchiveType(name); type.Recursive = false; if (index < 0) { if (name[0] == '*') { if (name[1] != 0) return false; } else if (name[0] == '#') { if (name[1] != 0) return false; type.CanReturnArc = false; type.CanReturnParser = true; } else return false; } type.FormatIndex = index; for (unsigned i = pos2; i < s.Len();) { int next = s.Find(':', i); if (next < 0) next = s.Len(); UString name = s.Mid(i, next - i); if (name.IsEmpty()) return false; if (!ParseTypeParams(name, type)) return false; i = next + 1; } return true; } bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types) { types.Clear(); for (unsigned pos = 0; pos < s.Len();) { int pos2 = s.Find('.', pos); if (pos2 < 0) pos2 = s.Len(); UString name = s.Mid(pos, pos2 - pos); if (name.IsEmpty()) return false; COpenType type; if (!ParseType(codecs, name, type)) return false; types.Add(type); pos = pos2 + 1; } return true; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h0100777000000000000000000002134713761647206024137 0ustar00// OpenArchive.h #ifndef __OPEN_ARCHIVE_H #define __OPEN_ARCHIVE_H #include "../../../Windows/PropVariant.h" #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "Property.h" HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); HRESULT Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); /* struct COptionalOpenProperties { UString FormatName; CObjectVector Props; }; */ #ifdef _SFX #define OPEN_PROPS_DECL #else #define OPEN_PROPS_DECL const CObjectVector *props; // #define OPEN_PROPS_DECL , const CObjectVector *props #endif struct COpenSpecFlags { // bool CanReturnFull; bool CanReturnFrontal; bool CanReturnTail; bool CanReturnMid; bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } COpenSpecFlags(): // CanReturnFull(true), CanReturnFrontal(false), CanReturnTail(false), CanReturnMid(false) {} }; struct COpenType { int FormatIndex; COpenSpecFlags SpecForcedType; COpenSpecFlags SpecMainType; COpenSpecFlags SpecWrongExt; COpenSpecFlags SpecUnknownExt; bool Recursive; bool CanReturnArc; bool CanReturnParser; bool EachPos; // bool SkipSfxStub; // bool ExeAsUnknown; bool ZerosTailIsAllowed; bool MaxStartOffset_Defined; UInt64 MaxStartOffset; const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const { return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); } COpenType(): FormatIndex(-1), Recursive(true), CanReturnArc(true), CanReturnParser(false), EachPos(false), // SkipSfxStub(true), // ExeAsUnknown(true), ZerosTailIsAllowed(false), MaxStartOffset_Defined(false), MaxStartOffset(0) { SpecForcedType.CanReturnFrontal = true; SpecForcedType.CanReturnTail = true; SpecForcedType.CanReturnMid = true; SpecMainType.CanReturnFrontal = true; SpecUnknownExt.CanReturnTail = true; // for sfx SpecUnknownExt.CanReturnMid = true; SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad // ZerosTailIsAllowed = true; } }; struct COpenOptions { CCodecs *codecs; COpenType openType; const CObjectVector *types; const CIntVector *excludedFormats; IInStream *stream; ISequentialInStream *seqStream; IArchiveOpenCallback *callback; COpenCallbackImp *callbackSpec; OPEN_PROPS_DECL // bool openOnlySpecifiedByExtension, bool stdInMode; UString filePath; COpenOptions(): codecs(NULL), types(NULL), excludedFormats(NULL), stream(NULL), seqStream(NULL), callback(NULL), callbackSpec(NULL), stdInMode(false) {} }; UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); struct CArcErrorInfo { bool ThereIsTail; bool UnexpecedEnd; bool IgnoreTail; // all are zeros // bool NonZerosTail; bool ErrorFlags_Defined; UInt32 ErrorFlags; UInt32 WarningFlags; int ErrorFormatIndex; // - 1 means no Error. // if FormatIndex == ErrorFormatIndex, the archive is open with offset UInt64 TailSize; /* if CArc is Open OK with some format: - ErrorFormatIndex shows error format index, if extension is incorrect - other variables show message and warnings of archive that is open */ UString ErrorMessage; UString WarningMessage; // call IsArc_After_NonOpen only if Open returns S_FALSE bool IsArc_After_NonOpen() const { return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); } CArcErrorInfo(): ThereIsTail(false), UnexpecedEnd(false), IgnoreTail(false), // NonZerosTail(false), ErrorFlags_Defined(false), ErrorFlags(0), WarningFlags(0), ErrorFormatIndex(-1), TailSize(0) {} void ClearErrors(); void ClearErrors_Full() { ErrorFormatIndex = -1; ClearErrors(); } bool IsThereErrorOrWarning() const { return ErrorFlags != 0 || WarningFlags != 0 || NeedTailWarning() || UnexpecedEnd || !ErrorMessage.IsEmpty() || !WarningMessage.IsEmpty(); } bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } UInt32 GetWarningFlags() const { UInt32 a = WarningFlags; if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) a |= kpv_ErrorFlags_DataAfterEnd; return a; } UInt32 GetErrorFlags() const { UInt32 a = ErrorFlags; if (UnexpecedEnd) a |= kpv_ErrorFlags_UnexpectedEnd; return a; } }; class CArc { HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); HRESULT OpenStream2(const COpenOptions &options); public: CMyComPtr Archive; CMyComPtr InStream; // we use InStream in 2 cases (ArcStreamOffset != 0): // 1) if we use additional cache stream // 2) we reopen sfx archive with CTailInStream CMyComPtr GetRawProps; CMyComPtr GetRootProps; CArcErrorInfo ErrorInfo; // for OK archives CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) UString Path; UString filePath; UString DefaultName; int FormatIndex; // - 1 means Parser. int SubfileIndex; FILETIME MTime; bool MTimeDefined; Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler UInt64 PhySize; // UInt64 OkPhySize; bool PhySizeDefined; // bool OkPhySize_Defined; UInt64 FileSize; UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file // bool offsetDefined; UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive // AString ErrorFlagsText; bool IsParseArc; bool IsTree; bool Ask_Deleted; bool Ask_AltStream; bool Ask_Aux; bool Ask_INode; bool IgnoreSplit; // don't try split handler // void Set_ErrorFlagsText(); CArc(): MTimeDefined(false), IsTree(false), Ask_Deleted(false), Ask_AltStream(false), Ask_Aux(false), Ask_INode(false), IgnoreSplit(false) {} HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); // ~CArc(); HRESULT Close() { InStream.Release(); return Archive->Close(); } // AltStream's name is concatenated with base file name in one string in parts.Back() HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; HRESULT GetItemPath(UInt32 index, UString &result) const; // GetItemPath2 adds [DELETED] dir prefix for deleted items. HRESULT GetItemPath2(UInt32 index, UString &result) const; HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; HRESULT IsItemAnti(UInt32 index, bool &result) const { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } HRESULT OpenStream(const COpenOptions &options); HRESULT OpenStreamOrFile(COpenOptions &options); HRESULT ReOpen(const COpenOptions &options); HRESULT CreateNewTailStream(CMyComPtr &stream); }; struct CArchiveLink { CObjectVector Arcs; UStringVector VolumePaths; UInt64 VolumesSize; bool IsOpen; // int NonOpenErrorFormatIndex; // - 1 means no Error. UString NonOpen_ArcPath; CArcErrorInfo NonOpen_ErrorInfo; // UString ErrorsText; // void Set_ErrorsText(); CArchiveLink(): VolumesSize(0), IsOpen(false) {} void KeepModeForNextOpen(); HRESULT Close(); void Release(); ~CArchiveLink() { Release(); } const CArc *GetArc() const { return &Arcs.Back(); } IInArchive *GetArchive() const { return Arcs.Back().Archive; } IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } HRESULT Open(COpenOptions &options); HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); HRESULT ReOpen(COpenOptions &options); }; bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Property.h0100777000000000000000000000024613761647206023553 0ustar00// Property.h #ifndef __7Z_PROPERTY_H #define __7Z_PROPERTY_H #include "../../../Common/MyString.h" struct CProperty { UString Name; UString Value; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp0100777000000000000000000002765513761647206024455 0ustar00// PropIDUtils.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileIO.h" #include "../../../Windows/PropVariantConv.h" #include "../../PropID.h" #include "PropIDUtils.h" #define Get16(x) GetUi16(x) #define Get32(x) GetUi32(x) using namespace NWindows; static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_"; /* 0 READONLY 1 HIDDEN 2 SYSTEM 4 DIRECTORY 5 ARCHIVE 6 DEVICE 7 NORMAL 8 TEMPORARY 9 SPARSE_FILE 10 REPARSE_POINT 11 COMPRESSED 12 OFFLINE 13 NOT_CONTENT_INDEXED 14 ENCRYPTED 16 VIRTUAL */ void ConvertWinAttribToString(char *s, UInt32 wa) { for (int i = 0; i < 16; i++) if ((wa & (1 << i)) && i != 7) *s++ = g_WinAttribChars[i]; *s = 0; } static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; #define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-'; void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw() { *dest = 0; if (prop.vt == VT_FILETIME) { FILETIME localFileTime; if ((prop.filetime.dwHighDateTime == 0 && prop.filetime.dwLowDateTime == 0) || !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime)) return; ConvertFileTimeToString(localFileTime, dest, true, full); return; } switch (propID) { case kpidCRC: { if (prop.vt != VT_UI4) break; ConvertUInt32ToHex8Digits(prop.ulVal, dest); return; } case kpidAttrib: { if (prop.vt != VT_UI4) break; ConvertWinAttribToString(dest, prop.ulVal); return; } case kpidPosixAttrib: { if (prop.vt != VT_UI4) break; UString res; UInt32 a = prop.ulVal; dest[0] = kPosixTypes[(a >> 12) & 0xF]; for (int i = 6; i >= 0; i -= 3) { dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); } if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S'); if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S'); if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T'); dest[10] = 0; a &= ~(UInt32)0xFFFF; if (a != 0) { dest[10] = ' '; ConvertUInt32ToHex8Digits(a, dest + 11); } return; } case kpidINode: { if (prop.vt != VT_UI8) break; ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); dest += strlen(dest); *dest++ = '-'; UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); ConvertUInt64ToString(low, dest); return; } case kpidVa: { UInt64 v = 0; if (ConvertPropVariantToUInt64(prop, v)) { dest[0] = '0'; dest[1] = 'x'; ConvertUInt64ToHex(prop.ulVal, dest + 2); return; } break; } } ConvertPropVariantToShortString(prop, dest); } void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full) { if (prop.vt == VT_BSTR) { dest = prop.bstrVal; return; } char temp[64]; ConvertPropertyToShortString(temp, prop, propID, full); int len = MyStringLen(temp); wchar_t *str = dest.GetBuffer(len); for (int i = 0; i < len; i++) str[i] = temp[i]; dest.ReleaseBuffer(len); } static inline char GetHex(Byte value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } #ifndef _SFX static inline void AddHexToString(AString &res, Byte value) { res += GetHex((Byte)(value >> 4)); res += GetHex((Byte)(value & 0xF)); res += ' '; } /* static AString Data_To_Hex(const Byte *data, size_t size) { AString s; for (size_t i = 0; i < size; i++) AddHexToString(s, data[i]); return s; } */ static const char *sidNames[] = { "0", "Dialup", "Network", "Batch", "Interactive", "Logon", // S-1-5-5-X-Y "Service", "Anonymous", "Proxy", "EnterpriseDC", "Self", "AuthenticatedUsers", "RestrictedCode", "TerminalServer", "RemoteInteractiveLogon", "ThisOrganization", "16", "IUserIIS", "LocalSystem", "LocalService", "NetworkService", "Domains" }; struct CSecID2Name { UInt32 n; const char *sz; }; const CSecID2Name sid_32_Names[] = { { 544, "Administrators" }, { 545, "Users" }, { 546, "Guests" }, { 547, "PowerUsers" }, { 548, "AccountOperators" }, { 549, "ServerOperators" }, { 550, "PrintOperators" }, { 551, "BackupOperators" }, { 552, "Replicators" }, { 553, "Backup Operators" }, { 554, "PreWindows2000CompatibleAccess" }, { 555, "RemoteDesktopUsers" }, { 556, "NetworkConfigurationOperators" }, { 557, "IncomingForestTrustBuilders" }, { 558, "PerformanceMonitorUsers" }, { 559, "PerformanceLogUsers" }, { 560, "WindowsAuthorizationAccessGroup" }, { 561, "TerminalServerLicenseServers" }, { 562, "DistributedCOMUsers" }, { 569, "CryptographicOperators" }, { 573, "EventLogReaders" }, { 574, "CertificateServiceDCOMAccess" } }; static const CSecID2Name sid_21_Names[] = { { 500, "Administrator" }, { 501, "Guest" }, { 502, "KRBTGT" }, { 512, "DomainAdmins" }, { 513, "DomainUsers" }, { 515, "DomainComputers" }, { 516, "DomainControllers" }, { 517, "CertPublishers" }, { 518, "SchemaAdmins" }, { 519, "EnterpriseAdmins" }, { 520, "GroupPolicyCreatorOwners" }, { 553, "RASandIASServers" }, { 553, "RASandIASServers" }, { 571, "AllowedRODCPasswordReplicationGroup" }, { 572, "DeniedRODCPasswordReplicationGroup" } }; struct CServicesToName { UInt32 n[5]; const char *sz; }; static const CServicesToName services_to_name[] = { { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } }; static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize) { sidSize = 0; if (lim < 8) { s += "ERROR"; return; } UInt32 rev = p[0]; if (rev != 1) { s += "UNSUPPORTED"; return; } UInt32 num = p[1]; if (8 + num * 4 > lim) { s += "ERROR"; return; } sidSize = 8 + num * 4; UInt32 authority = GetBe32(p + 4); if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) { UInt32 v0 = Get32(p + 8); if (v0 < ARRAY_SIZE(sidNames)) { s += sidNames[v0]; return; } if (v0 == 32 && num == 2) { UInt32 v1 = Get32(p + 12); for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++) if (sid_32_Names[i].n == v1) { s += sid_32_Names[i].sz; return; } } if (v0 == 21 && num == 5) { UInt32 v4 = Get32(p + 8 + 4 * 4); for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++) if (sid_21_Names[i].n == v4) { s += sid_21_Names[i].sz; return; } } if (v0 == 80 && num == 6) { for (int i = 0; i < ARRAY_SIZE(services_to_name); i++) { const CServicesToName &sn = services_to_name[i]; int j; for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); if (j == 5) { s += sn.sz; return; } } } } char sz[16]; s += "S-1-"; if (p[2] == 0 && p[3] == 0) { ConvertUInt32ToString(authority, sz); s += sz; } else { s += "0x"; for (int i = 2; i < 8; i++) AddHexToString(s, p[i]); } for (UInt32 i = 0; i < num; i++) { s += '-'; ConvertUInt32ToString(Get32(p + 8 + i * 4), sz); s += sz; } } static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos) { if (pos > size) { s += "ERROR"; return; } UInt32 sidSize = 0; ParseSid(s, p + pos, size - pos, sidSize); } static void AddUInt32ToString(AString &s, UInt32 val) { char sz[16]; ConvertUInt32ToString(val, sz); s += sz; } static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset) { UInt32 control = Get16(p + 2); if ((flags & control) == 0) return; UInt32 pos = Get32(p + offset); s += ' '; s += strName; if (pos >= size) return; p += pos; size -= pos; if (size < 8) return; if (Get16(p) != 2) // revision return; // UInt32 aclSize = Get16(p + 2); UInt32 num = Get32(p + 4); AddUInt32ToString(s, num); /* if (num >= (1 << 16)) return; if (aclSize > size) return; size = aclSize; size -= 8; p += 8; for (UInt32 i = 0 ; i < num; i++) { if (size <= 8) return; // Byte type = p[0]; // Byte flags = p[1]; // UInt32 aceSize = Get16(p + 2); // UInt32 mask = Get32(p + 4); p += 8; size -= 8; UInt32 sidSize = 0; s += ' '; s += ParseSid(p, size, sidSize); if (sidSize == 0) return; p += sidSize; size -= sidSize; } if (size != 0) s += " ERROR"; */ } #define MY_SE_OWNER_DEFAULTED (0x0001) #define MY_SE_GROUP_DEFAULTED (0x0002) #define MY_SE_DACL_PRESENT (0x0004) #define MY_SE_DACL_DEFAULTED (0x0008) #define MY_SE_SACL_PRESENT (0x0010) #define MY_SE_SACL_DEFAULTED (0x0020) #define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) #define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) #define MY_SE_DACL_AUTO_INHERITED (0x0400) #define MY_SE_SACL_AUTO_INHERITED (0x0800) #define MY_SE_DACL_PROTECTED (0x1000) #define MY_SE_SACL_PROTECTED (0x2000) #define MY_SE_RM_CONTROL_VALID (0x4000) #define MY_SE_SELF_RELATIVE (0x8000) void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s) { s.Empty(); if (size < 20 || size > (1 << 18)) { s += "ERROR"; return; } if (Get16(data) != 1) // revision { s += "UNSUPPORTED"; return; } ParseOwner(s, data, size, Get32(data + 4)); s += ' '; ParseOwner(s, data, size, Get32(data + 8)); ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); s += ' '; AddUInt32ToString(s, size); // s += '\n'; // s += Data_To_Hex(data, size); } #ifdef _WIN32 static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) { if (pos >= size) return false; size -= pos; if (size < 8) return false; UInt32 rev = data[pos]; if (rev != 1) return false; UInt32 num = data[pos + 1]; return (8 + num * 4 <= size); } static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) { UInt32 control = Get16(p + 2); if ((flags & control) == 0) return true; UInt32 pos = Get32(p + offset); if (pos >= size) return false; p += pos; size -= pos; if (size < 8) return false; UInt32 aclSize = Get16(p + 2); return (aclSize <= size); } bool CheckNtSecure(const Byte *data, UInt32 size) { if (size < 20) return false; if (Get16(data) != 1) // revision return true; // windows function can handle such error, so we allow it if (size > (1 << 18)) return false; if (!CheckSid(data, size, Get32(data + 4))) return false; if (!CheckSid(data, size, Get32(data + 8))) return false; if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; return true; } #endif #ifdef _WIN32 bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) { s.Empty(); NFile::CReparseAttr attr; if (attr.Parse(data, size)) { if (!attr.IsSymLink()) s += L"Junction: "; s += attr.GetPath(); if (!attr.IsOkNamePair()) { s += L" : "; s += attr.PrintName; } return true; } if (size < 8) return false; UInt32 tag = Get32(data); UInt32 len = Get16(data + 4); if (len + 8 > size) return false; if (Get16(data + 6) != 0) // padding return false; char hex[16]; ConvertUInt32ToHex8Digits(tag, hex); s.AddAsciiStr(hex); s += L' '; data += 8; for (UInt32 i = 0; i < len; i++) { Byte b = ((const Byte *)data)[i]; s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF)); s += (wchar_t)GetHex((Byte)(b & 0xF)); } return true; } #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h0100777000000000000000000000121713761647206024104 0ustar00// PropIDUtils.h #ifndef __PROPID_UTILS_H #define __PROPID_UTILS_H #include "../../../Common/MyString.h" // provide at least 64 bytes for buffer including zero-end void ConvertPropertyToShortString(char *dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true) throw(); void ConvertPropertyToString(UString &dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true); bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s); void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s); bool CheckNtSecure(const Byte *data, UInt32 size); void ConvertWinAttribToString(char *s, UInt32 wa); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp0100777000000000000000000000363313761647206025075 0ustar00// SetProperties.cpp #include "StdAfx.h" #include "../../../Common/MyCom.h" #include "../../../Common/MyString.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/PropVariant.h" #include "../../Archive/IArchive.h" #include "SetProperties.h" using namespace NWindows; using namespace NCOM; static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) { const wchar_t *end; UInt64 result = ConvertStringToUInt64(s, &end); if (*end != 0 || s.IsEmpty()) prop = s; else if (result <= (UInt32)0xFFFFFFFF) prop = (UInt32)result; else prop = result; } HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties) { if (properties.IsEmpty()) return S_OK; CMyComPtr setProperties; unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties); if (!setProperties) return S_OK; UStringVector realNames; CPropVariant *values = new CPropVariant[properties.Size()]; try { unsigned i; for (i = 0; i < properties.Size(); i++) { const CProperty &property = properties[i]; NCOM::CPropVariant propVariant; UString name = property.Name; if (property.Value.IsEmpty()) { if (!name.IsEmpty()) { wchar_t c = name.Back(); if (c == L'-') propVariant = false; else if (c == L'+') propVariant = true; if (propVariant.vt != VT_EMPTY) name.DeleteBack(); } } else ParseNumberString(property.Value, propVariant); realNames.Add(name); values[i] = propVariant; } CRecordVector names; for (i = 0; i < realNames.Size(); i++) names.Add((const wchar_t *)realNames[i]); RINOK(setProperties->SetProperties(&names.Front(), values, names.Size())); } catch(...) { delete []values; throw; } delete []values; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.h0100777000000000000000000000027613761647206024542 0ustar00// SetProperties.h #ifndef __SETPROPERTIES_H #define __SETPROPERTIES_H #include "Property.h" HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp0100777000000000000000000000112413761647206024226 0ustar00// SortUtils.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "SortUtils.h" static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param) { const UStringVector &strings = *(const UStringVector *)param; return CompareFileNames(strings[*p1], strings[*p2]); } void SortFileNames(const UStringVector &strings, CUIntVector &indices) { unsigned numItems = strings.Size(); indices.ClearAndSetSize(numItems); unsigned *vals = &indices[0]; for (unsigned i = 0; i < numItems; i++) vals[i] = i; indices.Sort(CompareStrings, (void *)&strings); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.h0100777000000000000000000000026413761647206023677 0ustar00// SortUtils.h #ifndef __SORT_UTLS_H #define __SORT_UTLS_H #include "../../../Common/MyString.h" void SortFileNames(const UStringVector &strings, CUIntVector &indices); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp0100777000000000000000000000043413761647206024151 0ustar00// TempFiles.cpp #include "StdAfx.h" #include "../../../Windows/FileDir.h" #include "TempFiles.h" using namespace NWindows; using namespace NFile; void CTempFiles::Clear() { while (!Paths.IsEmpty()) { NDir::DeleteFileAlways(Paths.Back()); Paths.DeleteBack(); } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.h0100777000000000000000000000032013761647206023610 0ustar00// TempFiles.h #ifndef __TEMP_FILES_H #define __TEMP_FILES_H #include "../../../Common/MyString.h" class CTempFiles { void Clear(); public: FStringVector Paths; ~CTempFiles() { Clear(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.cpp0100777000000000000000000011342613761647206023511 0ustar00// Update.cpp #include "StdAfx.h" #include "Update.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/DLL.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../../../Windows/TimeUtils.h" #include "../../Common/FileStreams.h" #include "../../Common/LimitedStreams.h" #include "../../Compress/CopyCoder.h" #include "../Common/DirItem.h" #include "../Common/EnumDirItems.h" #include "../Common/OpenArchive.h" #include "../Common/UpdateProduce.h" #include "EnumDirItems.h" #include "SetProperties.h" #include "TempFiles.h" #include "UpdateCallback.h" static const char *kUpdateIsNotSupoorted = "update operations are not supported for this archive"; using namespace NWindows; using namespace NCOM; using namespace NFile; using namespace NDir; using namespace NName; static CFSTR kTempFolderPrefix = FTEXT("7zE"); #ifdef ENV_UNIX FString GetModuleDirPrefix() { FString s; const char *p7zip_home_dir = getenv("P7ZIP_HOME_DIR"); if (p7zip_home_dir) { return MultiByteToUnicodeString(p7zip_home_dir,CP_ACP); } return FTEXT(".") FSTRING_PATH_SEPARATOR; } #endif static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) { NFind::CFileInfo fileInfo; FString pathPrefix = path + FCHAR_PATH_SEPARATOR; { NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); while (enumerator.Next(fileInfo)) { if (fileInfo.IsDir()) if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) return false; } } /* // we don't need clear read-only for folders if (!MySetFileAttributes(path, 0)) return false; */ return RemoveDir(path); } using namespace NUpdateArchive; class COutMultiVolStream: public IOutStream, public CMyUnknownImp { unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; struct CAltStreamInfo { COutFileStream *StreamSpec; CMyComPtr Stream; FString Name; UInt64 Pos; UInt64 RealSize; }; CObjectVector Streams; public: // CMyComPtr VolumeCallback; CRecordVector Sizes; FString Prefix; CTempFiles *TempFiles; void Init() { _streamIndex = 0; _offsetPos = 0; _absPos = 0; _length = 0; } bool SetMTime(const FILETIME *mTime); HRESULT Close(); MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; // static NSynchronization::CCriticalSection g_TempPathsCS; HRESULT COutMultiVolStream::Close() { HRESULT res = S_OK; FOR_VECTOR (i, Streams) { COutFileStream *s = Streams[i].StreamSpec; if (s) { HRESULT res2 = s->Close(); if (res2 != S_OK) res = res2; } } return res; } bool COutMultiVolStream::SetMTime(const FILETIME *mTime) { bool res = true; FOR_VECTOR (i, Streams) { COutFileStream *s = Streams[i].StreamSpec; if (s) if (!s->SetMTime(mTime)) res = false; } return res; } STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_streamIndex >= Streams.Size()) { CAltStreamInfo altStream; FChar temp[16]; ConvertUInt32ToString(_streamIndex + 1, temp); FString res = temp; while (res.Len() < 3) res = FString(FTEXT('0')) + res; FString name = Prefix + res; altStream.StreamSpec = new COutFileStream; altStream.Stream = altStream.StreamSpec; if (!altStream.StreamSpec->Create(name, false)) return ::GetLastError(); { // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); TempFiles->Paths.Add(name); } altStream.Pos = 0; altStream.RealSize = 0; altStream.Name = name; Streams.Add(altStream); continue; } CAltStreamInfo &altStream = Streams[_streamIndex]; unsigned index = _streamIndex; if (index >= Sizes.Size()) index = Sizes.Size() - 1; UInt64 volSize = Sizes[index]; if (_offsetPos >= volSize) { _offsetPos -= volSize; _streamIndex++; continue; } if (_offsetPos != altStream.Pos) { // CMyComPtr outStream; // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream)); RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); altStream.Pos = _offsetPos; } UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos); UInt32 realProcessed; RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); data = (void *)((Byte *)data + realProcessed); size -= realProcessed; altStream.Pos += realProcessed; _offsetPos += realProcessed; _absPos += realProcessed; if (_absPos > _length) _length = _absPos; if (_offsetPos > altStream.RealSize) altStream.RealSize = _offsetPos; if (processedSize != NULL) *processedSize += realProcessed; if (altStream.Pos == volSize) { _streamIndex++; _offsetPos = 0; } if (realProcessed == 0 && curSize != 0) return E_FAIL; break; } return S_OK; } STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; switch (seekOrigin) { case STREAM_SEEK_SET: _absPos = offset; break; case STREAM_SEEK_CUR: _absPos += offset; break; case STREAM_SEEK_END: _absPos = _length + offset; break; } _offsetPos = _absPos; if (newPosition != NULL) *newPosition = _absPos; _streamIndex = 0; return S_OK; } STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) { if (newSize < 0) return E_INVALIDARG; unsigned i = 0; while (i < Streams.Size()) { CAltStreamInfo &altStream = Streams[i++]; if ((UInt64)newSize < altStream.RealSize) { RINOK(altStream.Stream->SetSize(newSize)); altStream.RealSize = newSize; break; } newSize -= altStream.RealSize; } while (i < Streams.Size()) { { CAltStreamInfo &altStream = Streams.Back(); altStream.Stream.Release(); DeleteFileAlways(altStream.Name); } Streams.DeleteBack(); } _offsetPos = _absPos; _streamIndex = 0; _length = newSize; return S_OK; } void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) { OriginalPath = path; SplitPathToParts_2(path, Prefix, Name); if (mode == k_ArcNameMode_Add) return; if (mode == k_ArcNameMode_Exact) { BaseExtension.Empty(); return; } int dotPos = Name.ReverseFind(L'.'); if (dotPos < 0) return; if ((unsigned)dotPos == Name.Len() - 1) { Name.DeleteBack(); BaseExtension.Empty(); return; } const UString ext = Name.Ptr(dotPos + 1); if (BaseExtension.IsEqualToNoCase(ext)) { BaseExtension = ext; Name.DeleteFrom(dotPos); } else BaseExtension.Empty(); } UString CArchivePath::GetFinalPath() const { UString path = GetPathWithoutExt(); if (!BaseExtension.IsEmpty()) path += UString(L'.') + BaseExtension; return path; } UString CArchivePath::GetFinalVolPath() const { UString path = GetPathWithoutExt(); if (!BaseExtension.IsEmpty()) path += UString(L'.') + VolExtension; return path; } FString CArchivePath::GetTempPath() const { FString path = TempPrefix + us2fs(Name); if (!BaseExtension.IsEmpty()) path += FString(FTEXT('.')) + us2fs(BaseExtension); path += FTEXT(".tmp"); path += TempPostfix; return path; } static const wchar_t *kDefaultArcType = L"7z"; static const wchar_t *kDefaultArcExt = L"7z"; static const wchar_t *kSFXExtension = #ifdef _WIN32 L"exe"; #else L""; #endif bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath) { if (types.Size() > 1) return false; // int arcTypeIndex = -1; if (types.Size() != 0) { MethodMode.Type = types[0]; MethodMode.Type_Defined = true; } if (MethodMode.Type.FormatIndex < 0) { // MethodMode.Type = -1; MethodMode.Type = COpenType(); if (ArcNameMode != k_ArcNameMode_Add) { MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); if (MethodMode.Type.FormatIndex >= 0) MethodMode.Type_Defined = true; } } return true; } bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) { UString typeExt; int formatIndex = MethodMode.Type.FormatIndex; if (formatIndex < 0) { typeExt = kDefaultArcExt; } else { const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; if (!arcInfo.UpdateEnabled) return false; typeExt = arcInfo.GetMainExt(); } UString ext = typeExt; if (SfxMode) ext = kSFXExtension; ArchivePath.BaseExtension = ext; ArchivePath.VolExtension = typeExt; ArchivePath.ParseFromPath(arcPath, ArcNameMode); FOR_VECTOR (i, Commands) { CUpdateArchiveCommand &uc = Commands[i]; uc.ArchivePath.BaseExtension = ext; uc.ArchivePath.VolExtension = typeExt; uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); } return true; } /* struct CUpdateProduceCallbackImp: public IUpdateProduceCallback { const CObjectVector *_arcItems; IUpdateCallbackUI *_callback; CUpdateProduceCallbackImp(const CObjectVector *a, IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} virtual HRESULT ShowDeleteFile(int arcIndex); }; HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) { return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); } */ bool CRenamePair::Prepare() { if (RecursedType != NRecursedType::kNonRecursed) return false; if (!WildcardParsing) return true; return !DoesNameContainWildcard(OldName); } extern bool g_CaseSensitive; static int CompareTwoNames(const wchar_t *s1, const wchar_t *s2) { for (int i = 0;; i++) { wchar_t c1 = s1[i]; wchar_t c2 = s2[i]; if (c1 == 0 || c2 == 0) return i; if (c1 == c2) continue; if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) continue; if (IsCharDirLimiter(c1) && IsCharDirLimiter(c2)) continue; return i; } } bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const { int num = CompareTwoNames(OldName, src); if (OldName[num] == 0) { if (src[num] != 0 && !IsCharDirLimiter(src[num]) && num != 0 && !IsCharDirLimiter(src[num - 1])) return false; } else { // OldName[num] != 0 // OldName = "1\1a.txt" // src = "1" if (!isFolder || src[num] != 0 || !IsCharDirLimiter(OldName[num]) || OldName[num + 1] != 0) return false; } dest = NewName + src.Ptr(num); return true; } static int GetReverseSlashPos(const UString &name) { int slashPos = name.ReverseFind(L'/'); #ifdef _WIN32 int slash1Pos = name.ReverseFind(L'\\'); slashPos = MyMax(slashPos, slash1Pos); #endif return slashPos; } static HRESULT Compress( const CUpdateOptions &options, CCodecs *codecs, const CActionSet &actionSet, const CArc *arc, CArchivePath &archivePath, const CObjectVector &arcItems, Byte *processedItemsStatuses, const CDirItems &dirItems, const CDirItem *parentDirItem, CTempFiles &tempFiles, CUpdateErrorInfo &errorInfo, IUpdateCallbackUI *callback) { CMyComPtr outArchive; int formatIndex = options.MethodMode.Type.FormatIndex; if (arc) { formatIndex = arc->FormatIndex; if (formatIndex < 0) return E_NOTIMPL; CMyComPtr archive2 = arc->Archive; HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); if (result != S_OK) throw kUpdateIsNotSupoorted; } else { RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); #ifdef EXTERNAL_CODECS { CMyComPtr setCompressCodecsInfo; outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); } } #endif } if (outArchive == 0) throw kUpdateIsNotSupoorted; NFileTimeType::EEnum fileTimeType; UInt32 value; RINOK(outArchive->GetFileTimeType(&value)); switch (value) { case NFileTimeType::kWindows: case NFileTimeType::kUnix: case NFileTimeType::kDOS: fileTimeType = (NFileTimeType::EEnum)value; break; default: return E_FAIL; } { const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) return E_NOTIMPL; if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) return E_NOTIMPL; } CRecordVector updatePairs2; UStringVector newNames; if (options.RenamePairs.Size() != 0) { FOR_VECTOR (i, arcItems) { const CArcItem &ai = arcItems[i]; bool needRename = false; UString dest; if (ai.Censored) { FOR_VECTOR (j, options.RenamePairs) { const CRenamePair &rp = options.RenamePairs[j]; if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) { needRename = true; break; } if (ai.IsAltStream) { int colonPos = ai.Name.ReverseFind(':'); int slashPosPos = GetReverseSlashPos(ai.Name); if (colonPos > slashPosPos) { UString mainName = ai.Name.Left(colonPos); /* actually we must improve that code to support cases with folder renaming like: rn arc dir1\ dir2\ */ if (rp.GetNewPath(false, mainName, dest)) { needRename = true; dest += ':'; dest += ai.Name.Ptr(colonPos + 1); break; } } } } } CUpdatePair2 up2; up2.SetAs_NoChangeArcItem(ai.IndexInServer); if (needRename) { up2.NewProps = true; RINOK(arc->IsItemAnti(i, up2.IsAnti)); up2.NewNameIndex = newNames.Add(dest); } updatePairs2.Add(up2); } } else { CRecordVector updatePairs; GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! // CUpdateProduceCallbackImp upCallback(&arcItems, callback); UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */); } UInt32 numFiles = 0; FOR_VECTOR (i, updatePairs2) if (updatePairs2[i].NewData) numFiles++; RINOK(callback->SetNumFiles(numFiles)); CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; CMyComPtr updateCallback(updateCallbackSpec); updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; updateCallbackSpec->StdInMode = options.StdInMode; updateCallbackSpec->Callback = callback; if (arc) { // we set Archive to allow to transfer GetProperty requests back to DLL. updateCallbackSpec->Archive = arc->Archive; updateCallbackSpec->GetRawProps = arc->GetRawProps; updateCallbackSpec->GetRootProps = arc->GetRootProps; } updateCallbackSpec->DirItems = &dirItems; updateCallbackSpec->ParentDirItem = parentDirItem; updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; updateCallbackSpec->ArcItems = &arcItems; updateCallbackSpec->UpdatePairs = &updatePairs2; updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; if (options.RenamePairs.Size() != 0) updateCallbackSpec->NewNames = &newNames; CMyComPtr outSeekStream; CMyComPtr outStream; if (!options.StdOutMode) { FString dirPrefix; if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) throw 1417161; CreateComplexDir(dirPrefix); } COutFileStream *outStreamSpec = NULL; COutMultiVolStream *volStreamSpec = NULL; if (options.VolumesSizes.Size() == 0) { if (options.StdOutMode) outStream = new CStdOutFileStream; else { outStreamSpec = new COutFileStream; outSeekStream = outStreamSpec; outStream = outSeekStream; bool isOK = false; FString realPath; for (int i = 0; i < (1 << 16); i++) { if (archivePath.Temp) { if (i > 0) { FChar s[16]; ConvertUInt32ToString(i, s); archivePath.TempPostfix = s; } realPath = archivePath.GetTempPath(); } else realPath = us2fs(archivePath.GetFinalPath()); if (outStreamSpec->Create(realPath, false)) { tempFiles.Paths.Add(realPath); isOK = true; break; } if (::GetLastError() != ERROR_FILE_EXISTS) break; if (!archivePath.Temp) break; } if (!isOK) { errorInfo.SystemError = ::GetLastError(); errorInfo.FileName = realPath; errorInfo.Message = L"7-Zip cannot open file"; return E_FAIL; } } } else { if (options.StdOutMode) return E_FAIL; if (arc && arc->GetGlobalOffset() > 0) return E_NOTIMPL; volStreamSpec = new COutMultiVolStream; outSeekStream = volStreamSpec; outStream = outSeekStream; volStreamSpec->Sizes = options.VolumesSizes; volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath() + L"."); volStreamSpec->TempFiles = &tempFiles; volStreamSpec->Init(); /* updateCallbackSpec->VolumesSizes = volumesSizes; updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; if (!archivePath.VolExtension.IsEmpty()) updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension; */ } RINOK(SetProperties(outArchive, options.MethodMode.Properties)); if (options.SfxMode) { CInFileStream *sfxStreamSpec = new CInFileStream; CMyComPtr sfxStream(sfxStreamSpec); if (!sfxStreamSpec->Open(options.SfxModule)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot open SFX module"; errorInfo.FileName = options.SfxModule; return E_FAIL; } CMyComPtr sfxOutStream; COutFileStream *outStreamSpec = NULL; if (options.VolumesSizes.Size() == 0) sfxOutStream = outStream; else { outStreamSpec = new COutFileStream; sfxOutStream = outStreamSpec; FString realPath = us2fs(archivePath.GetFinalPath()); if (!outStreamSpec->Create(realPath, false)) { errorInfo.SystemError = ::GetLastError(); errorInfo.FileName = realPath; errorInfo.Message = L"7-Zip cannot open file"; return E_FAIL; } } RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); if (outStreamSpec) { RINOK(outStreamSpec->Close()); } } CMyComPtr tailStream; if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) tailStream = outStream; else { // Int64 globalOffset = arc->GetGlobalOffset(); RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); if (options.StdOutMode) tailStream = outStream; else { CTailOutStream *tailStreamSpec = new CTailOutStream; tailStream = tailStreamSpec; tailStreamSpec->Stream = outSeekStream; tailStreamSpec->Offset = arc->ArcStreamOffset; tailStreamSpec->Init(); } } HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); callback->Finilize(); RINOK(result); if (options.SetArcMTime) { FILETIME ft; ft.dwLowDateTime = 0; ft.dwHighDateTime = 0; FOR_VECTOR (i, updatePairs2) { CUpdatePair2 &pair2 = updatePairs2[i]; const FILETIME *ft2 = NULL; if (pair2.NewProps && pair2.DirIndex >= 0) ft2 = &dirItems.Items[pair2.DirIndex].MTime; else if (pair2.UseArcProps && pair2.ArcIndex >= 0) ft2 = &arcItems[pair2.ArcIndex].MTime; if (ft2) { if (::CompareFileTime(&ft, ft2) < 0) ft = *ft2; } } if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) { if (outStreamSpec) outStreamSpec->SetMTime(&ft); else if (volStreamSpec) volStreamSpec->SetMTime(&ft);; } } if (outStreamSpec) result = outStreamSpec->Close(); else if (volStreamSpec) result = volStreamSpec->Close(); return result; } static HRESULT EnumerateInArchiveItems( // bool storeStreamsMode, const NWildcard::CCensor &censor, const CArc &arc, CObjectVector &arcItems) { arcItems.Clear(); UInt32 numItems; IInArchive *archive = arc.Archive; RINOK(archive->GetNumberOfItems(&numItems)); arcItems.ClearAndReserve(numItems); for (UInt32 i = 0; i < numItems; i++) { CArcItem ai; RINOK(arc.GetItemPath(i, ai.Name)); RINOK(Archive_IsItem_Folder(archive, i, ai.IsDir)); RINOK(Archive_IsItem_AltStream(archive, i, ai.IsAltStream)); /* if (!storeStreamsMode && ai.IsAltStream) continue; */ ai.Censored = censor.CheckPath(ai.IsAltStream, ai.Name, !ai.IsDir); RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); { CPropVariant prop; RINOK(archive->GetProperty(i, kpidTimeType, &prop)); if (prop.vt == VT_UI4) { ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; switch (ai.TimeType) { case NFileTimeType::kWindows: case NFileTimeType::kUnix: case NFileTimeType::kDOS: break; default: return E_FAIL; } } } ai.IndexInServer = i; arcItems.AddInReserved(ai); } return S_OK; } struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback { IUpdateCallbackUI2 *Callback; HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) { return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); } }; #if defined(_WIN32) && !defined(UNDER_CE) #include #endif struct CRefSortPair { int Len; int Index; }; #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *) { RINOZ(-MyCompare(a1->Len, a2->Len)); return MyCompare(a1->Index, a2->Index); } static int GetNumSlashes(const FChar *s) { for (int numSlashes = 0;;) { FChar c = *s++; if (c == 0) return numSlashes; if ( #ifdef _WIN32 c == FTEXT('\\') || #endif c == FTEXT('/')) numSlashes++; } } #ifdef _WIN32 void ConvertToLongNames(NWildcard::CCensor &censor); #endif HRESULT UpdateArchive( CCodecs *codecs, const CObjectVector &types, const UString &cmdArcPath2, NWildcard::CCensor &censor, CUpdateOptions &options, CUpdateErrorInfo &errorInfo, IOpenCallbackUI *openCallback, IUpdateCallbackUI2 *callback, bool needSetPath) { if (options.StdOutMode && options.EMailMode) return E_FAIL; if (types.Size() > 1) return E_NOTIMPL; bool renameMode = !options.RenamePairs.IsEmpty(); if (renameMode) { if (options.Commands.Size() != 1) return E_FAIL; } if (options.DeleteAfterCompressing) { if (options.Commands.Size() != 1) return E_NOTIMPL; const CActionSet &as = options.Commands[0].ActionSet; for (int i = 2; i < NPairState::kNumValues; i++) if (as.StateActions[i] != NPairAction::kCompress) return E_NOTIMPL; } censor.AddPathsToCensor(options.PathMode); #ifdef _WIN32 ConvertToLongNames(censor); #endif censor.ExtendExclude(); if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) return E_NOTIMPL; if (options.SfxMode) { CProperty property; property.Name = L"rsfx"; property.Value = L"on"; options.MethodMode.Properties.Add(property); if (options.SfxModule.IsEmpty()) { errorInfo.Message = L"SFX file is not specified"; return E_FAIL; } bool found = false; if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) { const FString fullName = ::GetModuleDirPrefix() + options.SfxModule; if (NFind::DoesFileExist(fullName)) { options.SfxModule = fullName; found = true; } } if (!found) { if (!NFind::DoesFileExist(options.SfxModule)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find specified SFX module"; errorInfo.FileName = options.SfxModule; return E_FAIL; } } } CArchiveLink arcLink; if (needSetPath) { if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || !options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } UString arcPath = options.ArchivePath.GetFinalPath(); if (cmdArcPath2.IsEmpty()) { if (options.MethodMode.Type.FormatIndex < 0) throw "type of archive is not specified"; } else { NFind::CFileInfo fi; if (!fi.Find(us2fs(arcPath))) { if (renameMode) throw "can't find archive";; if (options.MethodMode.Type.FormatIndex < 0) { if (!options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } } else { if (fi.IsDir()) throw "there is no such archive"; if (fi.IsDevice) return E_NOTIMPL; if (options.VolumesSizes.Size() > 0) return E_NOTIMPL; CObjectVector types; // change it. if (options.MethodMode.Type_Defined) types.Add(options.MethodMode.Type); // We need to set Properties to open archive only in some cases (WIM archives). CIntVector excl; COpenOptions op; #ifndef _SFX op.props = &options.MethodMode.Properties; #endif op.codecs = codecs; op.types = &types; op.excludedFormats = ! op.stdInMode = false; op.stream = NULL; op.filePath = arcPath; HRESULT result = arcLink.Open2(op, openCallback); if (result == E_ABORT) return result; const wchar_t *errorArcType = NULL; if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex > 0) errorArcType = codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name; RINOK(callback->OpenResult(arcPath, result, errorArcType)); /* if (result == S_FALSE) return E_FAIL; */ RINOK(result); if (arcLink.VolumePaths.Size() > 1) { errorInfo.SystemError = (DWORD)E_NOTIMPL; errorInfo.Message = L"Updating for multivolume archives is not implemented"; return E_NOTIMPL; } CArc &arc = arcLink.Arcs.Back(); arc.MTimeDefined = !fi.IsDevice; arc.MTime = fi.MTime; if (arc.ErrorInfo.ThereIsTail) { errorInfo.SystemError = (DWORD)E_NOTIMPL; errorInfo.Message = L"There is some data block after the end of the archive"; return E_NOTIMPL; } if (options.MethodMode.Type.FormatIndex < 0) { options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; if (!options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } } } if (options.MethodMode.Type.FormatIndex < 0) { options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArcType); if (options.MethodMode.Type.FormatIndex < 0) return E_NOTIMPL; } bool thereIsInArchive = arcLink.IsOpen; if (!thereIsInArchive && renameMode) return E_FAIL; CDirItems dirItems; CDirItem parentDirItem; CDirItem *parentDirItem_Ptr = NULL; /* FStringVector requestedPaths; FStringVector *requestedPaths_Ptr = NULL; if (options.DeleteAfterCompressing) requestedPaths_Ptr = &requestedPaths; */ if (options.StdInMode) { CDirItem di; di.Name = options.StdInFileName; di.Size = (UInt64)(Int64)-1; di.Attrib = 0; NTime::GetCurUtcFileTime(di.MTime); di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } else { bool needScanning = false; if (!renameMode) FOR_VECTOR (i, options.Commands) if (options.Commands[i].ActionSet.NeedScanning()) needScanning = true; if (needScanning) { CEnumDirItemUpdateCallback enumCallback; enumCallback.Callback = callback; RINOK(callback->StartScanning()); dirItems.SymLinks = options.SymLinks.Val; #if defined(_WIN32) && !defined(UNDER_CE) dirItems.ReadSecure = options.NtSecurity.Val; #endif dirItems.ScanAltStreams = options.AltStreams.Val; HRESULT res = EnumerateItems(censor, options.PathMode, options.AddPathPrefix, dirItems, &enumCallback); FOR_VECTOR (i, dirItems.ErrorPaths) { RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); } if (res != S_OK) { if (res != E_ABORT) errorInfo.Message = L"Scanning error"; return res; } RINOK(callback->FinishScanning()); if (censor.Pairs.Size() == 1) { NFind::CFileInfo fi; FString prefix = us2fs(censor.Pairs[0].Prefix) + FTEXT("."); // UString prefix = censor.Pairs[0].Prefix; /* if (prefix.Back() == WCHAR_PATH_SEPARATOR) { prefix.DeleteBack(); } */ if (fi.Find(prefix)) if (fi.IsDir()) { parentDirItem.Size = fi.Size; parentDirItem.CTime = fi.CTime; parentDirItem.ATime = fi.ATime; parentDirItem.MTime = fi.MTime; parentDirItem.Attrib = fi.Attrib; parentDirItem_Ptr = &parentDirItem; int secureIndex = -1; #if defined(_WIN32) && !defined(UNDER_CE) if (options.NtSecurity.Val) dirItems.AddSecurityItem(prefix, secureIndex); #endif parentDirItem.SecureIndex = secureIndex; parentDirItem_Ptr = &parentDirItem; } } } } FString tempDirPrefix; bool usesTempDir = false; #ifdef _WIN32 CTempDir tempDirectory; if (options.EMailMode && options.EMailRemoveAfter) { tempDirectory.Create(kTempFolderPrefix); tempDirPrefix = tempDirectory.GetPath(); NormalizeDirPathPrefix(tempDirPrefix); usesTempDir = true; } #endif CTempFiles tempFiles; bool createTempFile = false; if (!options.StdOutMode && options.UpdateArchiveItself) { CArchivePath &ap = options.Commands[0].ArchivePath; ap = options.ArchivePath; // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) { createTempFile = true; ap.Temp = true; if (!options.WorkingDir.IsEmpty()) ap.TempPrefix = options.WorkingDir; else ap.TempPrefix = us2fs(ap.Prefix); NormalizeDirPathPrefix(ap.TempPrefix); } } unsigned i; for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; if (usesTempDir) { // Check it ap.Prefix = fs2us(tempDirPrefix); // ap.Temp = true; // ap.TempPrefix = tempDirPrefix; } if (!options.StdOutMode && (i > 0 || !createTempFile)) { const FString path = us2fs(ap.GetFinalPath()); if (NFind::DoesFileOrDirExist(path)) { errorInfo.SystemError = 0; errorInfo.Message = L"The file already exists"; errorInfo.FileName = path; return E_FAIL; } } } CObjectVector arcItems; if (thereIsInArchive) { RINOK(EnumerateInArchiveItems( // options.StoreAltStreams, censor, arcLink.Arcs.Back(), arcItems)); } /* FStringVector processedFilePaths; FStringVector *processedFilePaths_Ptr = NULL; if (options.DeleteAfterCompressing) processedFilePaths_Ptr = &processedFilePaths; */ CByteBuffer processedItems; if (options.DeleteAfterCompressing) { unsigned num = dirItems.Items.Size(); processedItems.Alloc(num); for (i = 0; i < num; i++) processedItems[i] = 0; } for (i = 0; i < options.Commands.Size(); i++) { const CArc *arc = thereIsInArchive ? arcLink.GetArc() : 0; // IInArchiveExtra *archiveExtra = thereIsInArchive ? arcLink.GetArchiveExtra() : 0; // IArchiveGetRootProps *archiveGetRootProps = thereIsInArchive ? arcLink.GetArchiveGetRootProps() : 0; CUpdateArchiveCommand &command = options.Commands[i]; UString name; bool isUpdating; if (options.StdOutMode) { name = L"stdout"; isUpdating = arc != 0; } else { name = command.ArchivePath.GetFinalPath(); isUpdating = (i == 0 && options.UpdateArchiveItself && arc != 0); } RINOK(callback->StartArchive(name, isUpdating)) RINOK(Compress(options, codecs, command.ActionSet, arc, command.ArchivePath, arcItems, options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, dirItems, parentDirItem_Ptr, tempFiles, errorInfo, callback)); RINOK(callback->FinishArchive()); } if (thereIsInArchive) { RINOK(arcLink.Close()); arcLink.Release(); } tempFiles.Paths.Clear(); if (createTempFile) { try { CArchivePath &ap = options.Commands[0].ArchivePath; const FString &tempPath = ap.GetTempPath(); if (thereIsInArchive) if (!DeleteFileAlways(us2fs(arcPath))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot delete the file"; errorInfo.FileName = us2fs(arcPath); return E_FAIL; } if (!MyMoveFile(tempPath, us2fs(arcPath))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot move the file"; errorInfo.FileName = tempPath; errorInfo.FileName2 = us2fs(arcPath); return E_FAIL; } } catch(...) { throw; } } #if defined(_WIN32) && !defined(UNDER_CE) if (options.EMailMode) { NDLL::CLibrary mapiLib; if (!mapiLib.Load(FTEXT("Mapi32.dll"))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot load Mapi32.dll"; return E_FAIL; } /* LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); if (fnSend == 0) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function"; return E_FAIL; } */ LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); if (sendMail == 0) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find MAPISendMail function"; return E_FAIL; } FStringVector fullPaths; unsigned i; for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; FString arcPath; if (!MyGetFullPathName(us2fs(ap.GetFinalPath()), arcPath)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"GetFullPathName error"; return E_FAIL; } fullPaths.Add(arcPath); } CCurrentDirRestorer curDirRestorer; for (i = 0; i < fullPaths.Size(); i++) { UString arcPath = fs2us(fullPaths[i]); UString fileName = ExtractFileNameFromPath(arcPath); AString path = GetAnsiString(arcPath); AString name = GetAnsiString(fileName); // Warning!!! MAPISendDocuments function changes Current directory // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); MapiFileDesc f; memset(&f, 0, sizeof(f)); f.nPosition = 0xFFFFFFFF; f.lpszPathName = (char *)(const char *)path; f.lpszFileName = (char *)(const char *)name; MapiMessage m; memset(&m, 0, sizeof(m)); m.nFileCount = 1; m.lpFiles = &f; const AString addr = GetAnsiString(options.EMailAddress); MapiRecipDesc rec; if (!addr.IsEmpty()) { memset(&rec, 0, sizeof(rec)); rec.ulRecipClass = MAPI_TO; rec.lpszAddress = (char *)(const char *)addr; m.nRecipCount = 1; m.lpRecips = &rec; } sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); } } #endif if (options.DeleteAfterCompressing) { CRecordVector pairs; FStringVector foldersNames; for (i = 0; i < dirItems.Items.Size(); i++) { const CDirItem &dirItem = dirItems.Items[i]; FString phyPath = us2fs(dirItems.GetPhyPath(i)); if (dirItem.IsDir()) { CRefSortPair pair; pair.Index = i; pair.Len = GetNumSlashes(phyPath); pairs.Add(pair); } else { if (processedItems[i] != 0 || dirItem.Size == 0) { DeleteFileAlways(phyPath); } else { // file was skipped /* errorInfo.SystemError = 0; errorInfo.Message = L"file was not processed"; errorInfo.FileName = phyPath; return E_FAIL; */ } } } pairs.Sort(CompareRefSortPair, NULL); for (i = 0; i < pairs.Size(); i++) { FString phyPath = us2fs(dirItems.GetPhyPath(pairs[i].Index)); if (NFind::DoesDirExist(phyPath)) { // printf("delete %S\n", phyPath); RemoveDir(phyPath); } } } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.h0100777000000000000000000001032013761647206023143 0ustar00// Update.h #ifndef __COMMON_UPDATE_H #define __COMMON_UPDATE_H #include "../../../Common/Wildcard.h" #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "OpenArchive.h" #include "Property.h" #include "UpdateAction.h" #include "UpdateCallback.h" enum EArcNameMode { k_ArcNameMode_Smart, k_ArcNameMode_Exact, k_ArcNameMode_Add, }; struct CArchivePath { UString OriginalPath; UString Prefix; // path(folder) prefix including slash UString Name; // base name UString BaseExtension; // archive type extension or "exe" extension UString VolExtension; // archive type extension for volumes bool Temp; FString TempPrefix; // path(folder) for temp location FString TempPostfix; CArchivePath(): Temp(false) {}; void ParseFromPath(const UString &path, EArcNameMode mode); UString GetPathWithoutExt() const { return Prefix + Name; } UString GetFinalPath() const; UString GetFinalVolPath() const; FString GetTempPath() const; }; struct CUpdateArchiveCommand { UString UserArchivePath; CArchivePath ArchivePath; NUpdateArchive::CActionSet ActionSet; }; struct CCompressionMethodMode { bool Type_Defined; COpenType Type; CObjectVector Properties; CCompressionMethodMode(): Type_Defined(false) {} }; namespace NRecursedType { enum EEnum { kRecursed, kWildcardOnlyRecursed, kNonRecursed };} struct CRenamePair { UString OldName; UString NewName; bool WildcardParsing; NRecursedType::EEnum RecursedType; CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {} bool Prepare(); bool GetNewPath(bool isFolder, const UString &src, UString &dest) const; }; struct CUpdateOptions { CCompressionMethodMode MethodMode; CObjectVector Commands; bool UpdateArchiveItself; CArchivePath ArchivePath; EArcNameMode ArcNameMode; bool SfxMode; FString SfxModule; bool OpenShareForWrite; bool StdInMode; UString StdInFileName; bool StdOutMode; bool EMailMode; bool EMailRemoveAfter; UString EMailAddress; FString WorkingDir; NWildcard::ECensorPathMode PathMode; UString AddPathPrefix; CBoolPair NtSecurity; CBoolPair AltStreams; CBoolPair HardLinks; CBoolPair SymLinks; bool DeleteAfterCompressing; bool SetArcMTime; CObjectVector RenamePairs; bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath); bool SetArcPath(const CCodecs *codecs, const UString &arcPath); CUpdateOptions(): UpdateArchiveItself(true), ArcNameMode(k_ArcNameMode_Smart), SfxMode(false), OpenShareForWrite(false), StdInMode(false), StdOutMode(false), EMailMode(false), EMailRemoveAfter(false), PathMode(NWildcard::k_RelatPath), DeleteAfterCompressing(false), SetArcMTime(false) {}; void SetActionCommand_Add() { Commands.Clear(); CUpdateArchiveCommand c; c.ActionSet = NUpdateArchive::k_ActionSet_Add; Commands.Add(c); } CRecordVector VolumesSizes; }; struct CErrorInfo { DWORD SystemError; FString FileName; FString FileName2; UString Message; // UStringVector ErrorPaths; // CRecordVector ErrorCodes; CErrorInfo(): SystemError(0) {}; }; struct CUpdateErrorInfo: public CErrorInfo { }; #define INTERFACE_IUpdateCallbackUI2(x) \ INTERFACE_IUpdateCallbackUI(x) \ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, const wchar_t *errorArcType) x; \ virtual HRESULT StartScanning() x; \ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT FinishScanning() x; \ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \ virtual HRESULT FinishArchive() x; \ struct IUpdateCallbackUI2: public IUpdateCallbackUI { INTERFACE_IUpdateCallbackUI2(=0) }; HRESULT UpdateArchive( CCodecs *codecs, const CObjectVector &types, const UString &cmdArcPath2, NWildcard::CCensor &censor, CUpdateOptions &options, CUpdateErrorInfo &errorInfo, IOpenCallbackUI *openCallback, IUpdateCallbackUI2 *callback, bool needSetPath); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp0100777000000000000000000000220513761647206024637 0ustar00// UpdateAction.cpp #include "StdAfx.h" #include "UpdateAction.h" namespace NUpdateArchive { const CActionSet k_ActionSet_Add = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress }}; const CActionSet k_ActionSet_Update = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress }}; const CActionSet k_ActionSet_Fresh = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress }}; const CActionSet k_ActionSet_Sync = {{ NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, }}; const CActionSet k_ActionSet_Delete = {{ NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore }}; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h0100777000000000000000000000250413761647206024306 0ustar00// UpdateAction.h #ifndef __UPDATE_ACTION_H #define __UPDATE_ACTION_H namespace NUpdateArchive { namespace NPairState { const unsigned kNumValues = 7; enum EEnum { kNotMasked = 0, kOnlyInArchive, kOnlyOnDisk, kNewInArchive, kOldInArchive, kSameFiles, kUnknowNewerFiles }; } namespace NPairAction { enum EEnum { kIgnore = 0, kCopy, kCompress, kCompressAsAnti }; } struct CActionSet { NPairAction::EEnum StateActions[NPairState::kNumValues]; bool IsEqualTo(const CActionSet &a) const { for (unsigned i = 0; i < NPairState::kNumValues; i++) if (StateActions[i] != a.StateActions[i]) return false; return true; } bool NeedScanning() const { unsigned i; for (i = 0; i < NPairState::kNumValues; i++) if (StateActions[i] == NPairAction::kCompress) return true; for (i = 1; i < NPairState::kNumValues; i++) if (StateActions[i] != NPairAction::kIgnore) return true; return false; } }; extern const CActionSet k_ActionSet_Add; extern const CActionSet k_ActionSet_Update; extern const CActionSet k_ActionSet_Fresh; extern const CActionSet k_ActionSet_Sync; extern const CActionSet k_ActionSet_Delete; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp0100777000000000000000000003421313761647206025122 0ustar00// UpdateCallback.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/Synchronization.h" #include "../../Common/FileStreams.h" #include "../../Common/StreamObjects.h" #include "UpdateCallback.h" #if defined(_WIN32) && !defined(UNDER_CE) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif using namespace NWindows; using namespace NFile; #ifdef _USE_SECURITY_CODE bool InitLocalPrivileges(); #endif CArchiveUpdateCallback::CArchiveUpdateCallback(): Callback(0), ShareForWrite(false), StdInMode(false), DirItems(0), ArcItems(0), UpdatePairs(0), NewNames(0), KeepOriginalItemNames(false), ProcessedItemsStatuses(NULL), ParentDirItem(NULL), StoreNtSecurity(false), StoreHardLinks(false), StoreSymLinks(false), _hardIndex_From((UInt32)(Int32)-1) { #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size) { COM_TRY_BEGIN return Callback->SetTotal(size); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue) { COM_TRY_BEGIN return Callback->SetCompleted(completeValue); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { COM_TRY_BEGIN return Callback->SetRatioInfo(inSize, outSize); COM_TRY_END } /* static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, { NULL, kpidSize, VT_UI8}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidAttrib, VT_UI4}, { NULL, kpidIsAnti, VT_BOOL} }; STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) { return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator); } */ STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) { COM_TRY_BEGIN RINOK(Callback->CheckBreak()); const CUpdatePair2 &up = (*UpdatePairs)[index]; if (newData) *newData = BoolToInt(up.NewData); if (newProps) *newProps = BoolToInt(up.NewProps); if (indexInArchive) { *indexInArchive = (UInt32)(Int32)-1; if (up.ExistInArchive()) *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer; } return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidIsDir: prop = true; break; case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; } prop.Detach(value); return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) { *parentType = NParentType::kDir; *parent = (UInt32)(Int32)-1; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps) { *numProps = 0; if (StoreNtSecurity) *numProps = 1; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) { *name = NULL; *propID = kpidNtSecure; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID #ifdef _USE_SECURITY_CODE propID #endif , const void **data, UInt32 *dataSize, UInt32 *propType) { *data = 0; *dataSize = 0; *propType = 0; if (!StoreNtSecurity) return S_OK; #ifdef _USE_SECURITY_CODE if (propID == kpidNtSecure) { if (StdInMode) return S_OK; if (ParentDirItem) { if (ParentDirItem->SecureIndex < 0) return S_OK; const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex]; *data = buf; *dataSize = (UInt32)buf.Size(); *propType = NPropDataType::kRaw; return S_OK; } if (GetRootProps) return GetRootProps->GetRootRawProp(propID, data, dataSize, propType); } #endif return S_OK; } // #ifdef _USE_SECURITY_CODE // #endif STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) { *data = 0; *dataSize = 0; *propType = 0; if (propID == kpidNtSecure || propID == kpidNtReparse) { if (StdInMode) return S_OK; const CUpdatePair2 &up = (*UpdatePairs)[index]; if (up.UseArcProps && up.ExistInArchive() && GetRawProps) return GetRawProps->GetRawProp( ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, data, dataSize, propType); { const CUpdatePair2 &up = (*UpdatePairs)[index]; /* if (!up.NewData) return E_FAIL; */ if (up.IsAnti) return S_OK; #ifndef UNDER_CE const CDirItem &di = DirItems->Items[up.DirIndex]; #endif #ifdef _USE_SECURITY_CODE if (propID == kpidNtSecure) { if (!StoreNtSecurity) return S_OK; if (di.SecureIndex < 0) return S_OK; const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex]; *data = buf; *dataSize = (UInt32)buf.Size(); *propType = NPropDataType::kRaw; } else #endif { // propID == kpidNtReparse if (!StoreSymLinks) return S_OK; #if 0 // #ifndef UNDER_CE const CByteBuffer *buf = &di.ReparseData2; if (buf->Size() == 0) buf = &di.ReparseData; if (buf->Size() != 0) { *data = *buf; *dataSize = (UInt32)buf->Size(); *propType = NPropDataType::kRaw; } #endif } return S_OK; } } return S_OK; } #ifndef UNDER_CE static UString GetRelativePath(const UString &to, const UString &from) { UStringVector partsTo, partsFrom; SplitPathToParts(to, partsTo); SplitPathToParts(from, partsFrom); unsigned i; for (i = 0;; i++) { if (i + 1 >= partsFrom.Size() || i + 1 >= partsTo.Size()) break; if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) break; } if (i == 0) { #ifdef _WIN32 if (NName::IsDrivePath(to) || NName::IsDrivePath(from)) return to; #endif } UString s; unsigned k; for (k = i + 1; k < partsFrom.Size(); k++) s += L".." WSTRING_PATH_SEPARATOR; for (k = i; k < partsTo.Size(); k++) { if (k != i) s += WCHAR_PATH_SEPARATOR; s += partsTo[k]; } return s; } #endif STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN const CUpdatePair2 &up = (*UpdatePairs)[index]; NCOM::CPropVariant prop; if (up.NewData) { /* if (propID == kpidIsHardLink) { prop = _isHardLink; prop.Detach(value); return S_OK; } */ if (propID == kpidSymLink) { if (index == _hardIndex_From) { prop.Detach(value); return S_OK; } if (up.DirIndex >= 0) { #if 0 // #ifndef UNDER_CE const CDirItem &di = DirItems->Items[up.DirIndex]; // if (di.IsDir()) { CReparseAttr attr; if (attr.Parse(di.ReparseData, di.ReparseData.Size())) { UString simpleName = attr.GetPath(); if (attr.IsRelative()) prop = simpleName; else { const UString phyPath = DirItems->GetPhyPath(up.DirIndex); FString fullPath; if (NDir::MyGetFullPathName(us2fs(phyPath), fullPath)) { prop = GetRelativePath(simpleName, fs2us(fullPath)); } } prop.Detach(value); return S_OK; } } #endif } } else if (propID == kpidHardLink) { if (index == _hardIndex_From) { const CKeyKeyValPair &pair = _map[_hardIndex_To]; const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; prop = DirItems->GetLogPath(up2.DirIndex); prop.Detach(value); return S_OK; } if (up.DirIndex >= 0) { prop.Detach(value); return S_OK; } } } if (up.IsAnti && propID != kpidIsDir && propID != kpidPath && propID != kpidIsAltStream) { switch (propID) { case kpidSize: prop = (UInt64)0; break; case kpidIsAnti: prop = true; break; } } else if (propID == kpidPath && up.NewNameIndex >= 0) prop = (*NewNames)[up.NewNameIndex]; else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) { // we can generate new ShortName here; } else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) && up.ExistInArchive() && Archive) return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value); else if (up.ExistOnDisk()) { const CDirItem &di = DirItems->Items[up.DirIndex]; switch (propID) { case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break; case kpidIsDir: prop = di.IsDir(); break; case kpidSize: prop = di.Size; break; case kpidAttrib: prop = di.Attrib; break; case kpidCTime: prop = di.CTime; break; case kpidATime: prop = di.ATime; break; case kpidMTime: prop = di.MTime; break; case kpidIsAltStream: prop = di.IsAltStream; break; #if defined(_WIN32) && !defined(UNDER_CE) // case kpidShortName: prop = di.ShortName; break; #endif } } prop.Detach(value); return S_OK; COM_TRY_END } static NSynchronization::CCriticalSection CS; STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) { COM_TRY_BEGIN *inStream = NULL; const CUpdatePair2 &up = (*UpdatePairs)[index]; if (!up.NewData) return E_FAIL; RINOK(Callback->CheckBreak()); RINOK(Callback->Finilize()); bool isDir = IsDir(up); if (up.IsAnti) { UString name; if (up.ArcIndex >= 0) name = (*ArcItems)[up.ArcIndex].Name; else if (up.DirIndex >= 0) name = DirItems->GetLogPath(up.DirIndex); RINOK(Callback->GetStream(name, true)); /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. so we return empty stream */ if (!isDir) { CBufInStream *inStreamSpec = new CBufInStream(); CMyComPtr inStreamLoc = inStreamSpec; inStreamSpec->Init(NULL, 0); *inStream = inStreamLoc.Detach(); } return S_OK; } RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false)); if (isDir) return S_OK; if (StdInMode) { CStdInFileStream *inStreamSpec = new CStdInFileStream; CMyComPtr inStreamLoc(inStreamSpec); *inStream = inStreamLoc.Detach(); } else { CInFileStream *inStreamSpec = new CInFileStream; CMyComPtr inStreamLoc(inStreamSpec); inStreamSpec->SupportHardLinks = StoreHardLinks; const UString path = DirItems->GetPhyPath(up.DirIndex); #if defined(_WIN32) && !defined(UNDER_CE) if (DirItems->Items[up.DirIndex].AreReparseData()) { if (!inStreamSpec->File.OpenReparse(us2fs(path))) { return Callback->OpenFileError(path, ::GetLastError()); } } else #endif if (!inStreamSpec->OpenShared(us2fs(path), ShareForWrite)) { return Callback->OpenFileError(path, ::GetLastError()); } #if 0 // FIXME if (StoreHardLinks) { CStreamFileProps props; if (inStreamSpec->GetProps2(&props) == S_OK) { if (props.NumLinks > 1) { CKeyKeyValPair pair; pair.Key1 = props.VolID; pair.Key2 = props.FileID_Low; pair.Value = index; unsigned numItems = _map.Size(); unsigned pairIndex = _map.AddToUniqueSorted2(pair); if (numItems == _map.Size()) { // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; _hardIndex_From = index; _hardIndex_To = pairIndex; // we could return NULL as stream, but it's better to return real stream // return S_OK; } } } } #endif if (ProcessedItemsStatuses) { NSynchronization::CCriticalSectionLock lock(CS); ProcessedItemsStatuses[up.DirIndex] = 1; } *inStream = inStreamLoc.Detach(); } return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult) { COM_TRY_BEGIN return Callback->SetOperationResult(operationResult); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) { if (VolumesSizes.Size() == 0) return S_FALSE; if (index >= (UInt32)VolumesSizes.Size()) index = VolumesSizes.Size() - 1; *size = VolumesSizes[index]; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream) { COM_TRY_BEGIN FChar temp[16]; ConvertUInt32ToString(index + 1, temp); FString res = temp; while (res.Len() < 2) res.InsertAtFront(FTEXT('0')); FString fileName = VolName; fileName += L'.'; fileName += res; fileName += VolExt; COutFileStream *streamSpec = new COutFileStream; CMyComPtr streamLoc(streamSpec); if (!streamSpec->Create(fileName, false)) return ::GetLastError(); *volumeStream = streamLoc.Detach(); return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) { COM_TRY_BEGIN return Callback->CryptoGetTextPassword2(passwordIsDefined, password); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN return Callback->CryptoGetTextPassword(password); COM_TRY_END } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h0100777000000000000000000000614313761647206024570 0ustar00// UpdateCallback.h #ifndef __UPDATE_CALLBACK_H #define __UPDATE_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../IPassword.h" #include "../../ICoder.h" #include "../Common/UpdatePair.h" #include "../Common/UpdateProduce.h" #define INTERFACE_IUpdateCallbackUI(x) \ virtual HRESULT SetTotal(UInt64 size) x; \ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \ virtual HRESULT CheckBreak() x; \ virtual HRESULT Finilize() x; \ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT SetOperationResult(Int32 operationResult) x; \ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ /* virtual HRESULT ShowDeleteFile(const wchar_t *name) x; */ \ /* virtual HRESULT CloseProgress() { return S_OK; }; */ struct IUpdateCallbackUI { INTERFACE_IUpdateCallbackUI(=0) }; struct CKeyKeyValPair { UInt64 Key1; UInt64 Key2; unsigned Value; int Compare(const CKeyKeyValPair &a) const { if (Key1 < a.Key1) return -1; if (Key1 > a.Key1) return 1; return MyCompare(Key2, a.Key2); } }; class CArchiveUpdateCallback: public IArchiveUpdateCallback2, public IArchiveGetRawProps, public IArchiveGetRootProps, public ICryptoGetTextPassword2, public ICryptoGetTextPassword, public ICompressProgressInfo, public CMyUnknownImp { #if defined(_WIN32) && !defined(UNDER_CE) bool _saclEnabled; #endif CRecordVector _map; UInt32 _hardIndex_From; UInt32 _hardIndex_To; public: MY_UNKNOWN_IMP6( IArchiveUpdateCallback2, IArchiveGetRawProps, IArchiveGetRootProps, ICryptoGetTextPassword2, ICryptoGetTextPassword, ICompressProgressInfo) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); INTERFACE_IArchiveUpdateCallback2(;) INTERFACE_IArchiveGetRawProps(;) INTERFACE_IArchiveGetRootProps(;) STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); STDMETHOD(CryptoGetTextPassword)(BSTR *password); CRecordVector VolumesSizes; FString VolName; FString VolExt; IUpdateCallbackUI *Callback; bool ShareForWrite; bool StdInMode; const CDirItems *DirItems; const CDirItem *ParentDirItem; const CObjectVector *ArcItems; const CRecordVector *UpdatePairs; const UStringVector *NewNames; CMyComPtr Archive; CMyComPtr GetRawProps; CMyComPtr GetRootProps; bool KeepOriginalItemNames; bool StoreNtSecurity; bool StoreHardLinks; bool StoreSymLinks; Byte *ProcessedItemsStatuses; CArchiveUpdateCallback(); bool IsDir(const CUpdatePair2 &up) const { if (up.DirIndex >= 0) return DirItems->Items[up.DirIndex].IsDir(); else if (up.ArcIndex >= 0) return (*ArcItems)[up.ArcIndex].IsDir; return false; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp0100777000000000000000000001407113761647206024321 0ustar00// UpdatePair.cpp #include "StdAfx.h" #include #include "../../../Common/Wildcard.h" #include "../../../Windows/TimeUtils.h" #include "SortUtils.h" #include "UpdatePair.h" using namespace NWindows; using namespace NTime; static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2) { switch (fileTimeType) { case NFileTimeType::kWindows: return ::CompareFileTime(&time1, &time2); case NFileTimeType::kUnix: { UInt32 unixTime1, unixTime2; FileTimeToUnixTime(time1, unixTime1); FileTimeToUnixTime(time2, unixTime2); return MyCompare(unixTime1, unixTime2); } case NFileTimeType::kDOS: { UInt32 dosTime1, dosTime2; FileTimeToDosTime(time1, dosTime1); FileTimeToDosTime(time2, dosTime2); return MyCompare(dosTime1, dosTime2); } } throw 4191618; } static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:"; static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:"; static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; static void ThrowError(const char *message, const UString &s1, const UString &s2) { UString m; m.SetFromAscii(message); m += L'\n'; m += s1; m += L'\n'; m += s2; throw m; } static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) { int res = CompareFileNames(ai1.Name, ai2.Name); if (res != 0) return res; if (ai1.IsDir != ai2.IsDir) return ai1.IsDir ? -1 : 1; return 0; } static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) { unsigned i1 = *p1; unsigned i2 = *p2; const CObjectVector &arcItems = *(const CObjectVector *)param; int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); if (res != 0) return res; return MyCompare(i1, i2); } void GetUpdatePairInfoList( const CDirItems &dirItems, const CObjectVector &arcItems, NFileTimeType::EEnum fileTimeType, CRecordVector &updatePairs) { CUIntVector dirIndices, arcIndices; unsigned numDirItems = dirItems.Items.Size(); unsigned numArcItems = arcItems.Size(); CIntArr duplicatedArcItem(numArcItems); { int *vals = &duplicatedArcItem[0]; for (unsigned i = 0; i < numArcItems; i++) vals[i] = 0; } { arcIndices.ClearAndSetSize(numArcItems); { unsigned *vals = &arcIndices[0]; for (unsigned i = 0; i < numArcItems; i++) vals[i] = i; } arcIndices.Sort(CompareArcItems, (void *)&arcItems); for (unsigned i = 0; i + 1 < numArcItems; i++) if (CompareArcItemsBase( arcItems[arcIndices[i]], arcItems[arcIndices[i + 1]]) == 0) { duplicatedArcItem[i] = 1; duplicatedArcItem[i + 1] = -1; } } UStringVector dirNames; { dirNames.ClearAndReserve(numDirItems); unsigned i; for (i = 0; i < numDirItems; i++) dirNames.AddInReserved(dirItems.GetLogPath(i)); SortFileNames(dirNames, dirIndices); for (i = 0; i + 1 < numDirItems; i++) { const UString &s1 = dirNames[dirIndices[i]]; const UString &s2 = dirNames[dirIndices[i + 1]]; if (CompareFileNames(s1, s2) == 0) ThrowError(k_Duplicate_inDir_Message, s1, s2); } } unsigned dirIndex = 0; unsigned arcIndex = 0; int prevHostFile = -1; const UString *prevHostName = NULL; while (dirIndex < numDirItems || arcIndex < numArcItems) { CUpdatePair pair; int dirIndex2 = -1; int arcIndex2 = -1; const CDirItem *di = NULL; const CArcItem *ai = NULL; int compareResult = -1; const UString *name = NULL; if (dirIndex < numDirItems) { dirIndex2 = dirIndices[dirIndex]; di = &dirItems.Items[dirIndex2]; } if (arcIndex < numArcItems) { arcIndex2 = arcIndices[arcIndex]; ai = &arcItems[arcIndex2]; compareResult = 1; if (dirIndex < numDirItems) { compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name); if (compareResult == 0) { if (di->IsDir() != ai->IsDir) compareResult = (ai->IsDir ? 1 : -1); } } } if (compareResult < 0) { name = &dirNames[dirIndex2]; pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; pair.DirIndex = dirIndex2; dirIndex++; } else if (compareResult > 0) { name = &ai->Name; pair.State = ai->Censored ? NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked; pair.ArcIndex = arcIndex2; arcIndex++; } else { int dupl = duplicatedArcItem[arcIndex]; if (dupl != 0) ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name); name = &dirNames[dirIndex2]; if (!ai->Censored) ThrowError(k_NotCensoredCollision_Message, *name, ai->Name); pair.DirIndex = dirIndex2; pair.ArcIndex = arcIndex2; switch (ai->MTimeDefined ? MyCompareTime( ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType, di->MTime, ai->MTime): 0) { case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; default: pair.State = (ai->SizeDefined && di->Size == ai->Size) ? NUpdateArchive::NPairState::kSameFiles : NUpdateArchive::NPairState::kUnknowNewerFiles; } dirIndex++; arcIndex++; } if ((di && di->IsAltStream) || (ai && ai->IsAltStream)) { if (prevHostName) { unsigned hostLen = prevHostName->Len(); if (name->Len() > hostLen) if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) pair.HostIndex = prevHostFile; } } else { prevHostFile = updatePairs.Size(); prevHostName = name; } updatePairs.Add(pair); } updatePairs.ReserveDown(); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h0100777000000000000000000000111213761647206023756 0ustar00// UpdatePair.h #ifndef __UPDATE_PAIR_H #define __UPDATE_PAIR_H #include "DirItem.h" #include "UpdateAction.h" #include "../../Archive/IArchive.h" struct CUpdatePair { NUpdateArchive::NPairState::EEnum State; int ArcIndex; int DirIndex; int HostIndex; // >= 0 for alt streams only, contains index of host pair CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {} }; void GetUpdatePairInfoList( const CDirItems &dirItems, const CObjectVector &arcItems, NFileTimeType::EEnum fileTimeType, CRecordVector &updatePairs); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp0100777000000000000000000000365513761647206025035 0ustar00// UpdateProduce.cpp #include "StdAfx.h" #include "UpdateProduce.h" using namespace NUpdateArchive; static const char *kUpdateActionSetCollision = "Internal collision in update action set"; void UpdateProduce( const CRecordVector &updatePairs, const CActionSet &actionSet, CRecordVector &operationChain, IUpdateProduceCallback *callback) { FOR_VECTOR (i, updatePairs) { const CUpdatePair &pair = updatePairs[i]; CUpdatePair2 up2; up2.DirIndex = pair.DirIndex; up2.ArcIndex = pair.ArcIndex; up2.NewData = up2.NewProps = true; up2.UseArcProps = false; switch (actionSet.StateActions[pair.State]) { case NPairAction::kIgnore: /* if (pair.State != NPairState::kOnlyOnDisk) IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]); // cout << "deleting"; */ if (callback) callback->ShowDeleteFile(pair.ArcIndex); continue; case NPairAction::kCopy: if (pair.State == NPairState::kOnlyOnDisk) throw kUpdateActionSetCollision; if (pair.State == NPairState::kOnlyInArchive) { if (pair.HostIndex >= 0) { /* ignore alt stream if 1) no such alt stream in Disk 2) there is Host file in disk */ if (updatePairs[pair.HostIndex].DirIndex >= 0) continue; } } up2.NewData = up2.NewProps = false; up2.UseArcProps = true; break; case NPairAction::kCompress: if (pair.State == NPairState::kOnlyInArchive || pair.State == NPairState::kNotMasked) throw kUpdateActionSetCollision; break; case NPairAction::kCompressAsAnti: up2.IsAnti = true; up2.UseArcProps = (pair.ArcIndex >= 0); break; } operationChain.Add(up2); } operationChain.ReserveDown(); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h0100777000000000000000000000224113761647206024470 0ustar00// UpdateProduce.h #ifndef __UPDATE_PRODUCE_H #define __UPDATE_PRODUCE_H #include "UpdatePair.h" struct CUpdatePair2 { bool NewData; bool NewProps; bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties. bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status int DirIndex; int ArcIndex; int NewNameIndex; bool IsMainRenameItem; void SetAs_NoChangeArcItem(int arcIndex) { NewData = NewProps = false; UseArcProps = true; IsAnti = false; ArcIndex = arcIndex; } bool ExistOnDisk() const { return DirIndex != -1; } bool ExistInArchive() const { return ArcIndex != -1; } CUpdatePair2(): NewData(false), NewProps(false), UseArcProps(false), IsAnti(false), DirIndex(-1), ArcIndex(-1), NewNameIndex(-1), IsMainRenameItem(false) {} }; struct IUpdateProduceCallback { virtual HRESULT ShowDeleteFile(int arcIndex) = 0; }; void UpdateProduce( const CRecordVector &updatePairs, const NUpdateArchive::CActionSet &actionSet, CRecordVector &operationChain, IUpdateProduceCallback *callback); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Console/0040777000000000000000000000000013761647206021726 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Console/Console.pri0100777000000000000000000000017213761647206024044 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.h SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.cpp0100777000000000000000000000411313761647206025375 0ustar00// PercentPrinter.cpp #include "StdAfx.h" #include "../../../Common/Defs.h" #include "../../../Common/IntToString.h" #include "PercentPrinter.h" static const unsigned kPaddingSize = 2; static const unsigned kPercentsSize = 4; static const unsigned kMaxExtraSize = kPaddingSize + 32 + kPercentsSize; static void ClearPrev(char *p, unsigned num) { unsigned i; for (i = 0; i < num; i++) *p++ = '\b'; for (i = 0; i < num; i++) *p++ = ' '; for (i = 0; i < num; i++) *p++ = '\b'; *p = '\0'; } void CPercentPrinter::ClosePrint() { if (m_NumExtraChars == 0) return; char s[kMaxExtraSize * 3 + 1]; ClearPrev(s, m_NumExtraChars); (*OutStream) << s; m_NumExtraChars = 0; } void CPercentPrinter::PrintString(const char *s) { ClosePrint(); (*OutStream) << s; } void CPercentPrinter::PrintString(const wchar_t *s) { ClosePrint(); (*OutStream) << s; } void CPercentPrinter::PrintNewLine() { ClosePrint(); (*OutStream) << "\n"; } void CPercentPrinter::RePrintRatio() { char s[32]; unsigned size; { char c = '%'; UInt64 value = 0; if (m_Total == (UInt64)(Int64)-1) { value = m_CurValue >> 20; c = 'M'; } else if (m_Total != 0) value = m_CurValue * 100 / m_Total; ConvertUInt64ToString(value, s); size = (unsigned)strlen(s); s[size++] = c; s[size] = '\0'; } unsigned extraSize = kPaddingSize + MyMax(size, kPercentsSize); if (extraSize < m_NumExtraChars) extraSize = m_NumExtraChars; char fullString[kMaxExtraSize * 3]; char *p = fullString; unsigned i; if (m_NumExtraChars == 0) { for (i = 0; i < extraSize; i++) *p++ = ' '; m_NumExtraChars = extraSize; } for (i = 0; i < m_NumExtraChars; i++) *p++ = '\b'; m_NumExtraChars = extraSize; for (; size < extraSize; size++) *p++ = ' '; MyStringCopy(p, s); (*OutStream) << fullString; OutStream->Flush(); m_PrevValue = m_CurValue; } void CPercentPrinter::PrintRatio() { if (m_CurValue < m_PrevValue + m_MinStepSize && m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0) return; RePrintRatio(); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.h0100777000000000000000000000136313761647206025046 0ustar00// PercentPrinter.h #ifndef __PERCENT_PRINTER_H #define __PERCENT_PRINTER_H #include "../../../Common/StdOutStream.h" class CPercentPrinter { UInt64 m_MinStepSize; UInt64 m_PrevValue; UInt64 m_CurValue; UInt64 m_Total; unsigned m_NumExtraChars; public: CStdOutStream *OutStream; CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize), m_PrevValue(0), m_CurValue(0), m_Total((UInt64)(Int64)-1), m_NumExtraChars(0) {} void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; } void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; } void PrintString(const char *s); void PrintString(const wchar_t *s); void PrintNewLine(); void ClosePrint(); void RePrintRatio(); void PrintRatio(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/0040777000000000000000000000000013761647206020346 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/CommandLineParser.cpp0100777000000000000000000000734613761647206024427 0ustar00// CommandLineParser.cpp #include "StdAfx.h" #include "CommandLineParser.h" static bool IsString1PrefixedByString2_NoCase(const wchar_t *u, const char *a) { for (;;) { char c = *a; if (c == 0) return true; if (MyCharLower_Ascii(c) != MyCharLower_Ascii(*u)) return false; a++; u++; } } namespace NCommandLineParser { #ifdef _WIN32 bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) { dest1.Empty(); dest2.Empty(); bool quoteMode = false; unsigned i; for (i = 0; i < src.Len(); i++) { wchar_t c = src[i]; if ((c == L' ' || c == L'\t') && !quoteMode) { dest2 = src.Ptr(i + 1); return i != 0; } if (c == L'\"') quoteMode = !quoteMode; else dest1 += c; } return i != 0; } void SplitCommandLine(const UString &s, UStringVector &parts) { UString sTemp = s; sTemp.Trim(); parts.Clear(); for (;;) { UString s1, s2; if (SplitCommandLine(sTemp, s1, s2)) parts.Add(s1); if (s2.IsEmpty()) break; sTemp = s2; } } #endif static const char *kStopSwitchParsing = "--"; static bool inline IsItSwitchChar(wchar_t c) { return (c == '-'); } CParser::CParser(unsigned numSwitches): _numSwitches(numSwitches), _switches(0) { _switches = new CSwitchResult[numSwitches]; } CParser::~CParser() { delete []_switches; } // if (s) contains switch then function updates switch structures // out: true, if (s) is a switch bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms) { if (s.IsEmpty() || !IsItSwitchChar(s[0])) return false; unsigned pos = 1; unsigned switchIndex = 0; int maxLen = -1; for (unsigned i = 0; i < _numSwitches; i++) { const char *key = switchForms[i].Key; unsigned switchLen = MyStringLen(key); if ((int)switchLen <= maxLen || pos + switchLen > s.Len()) continue; if (IsString1PrefixedByString2_NoCase((const wchar_t *)s + pos, key)) { switchIndex = i; maxLen = switchLen; } } if (maxLen < 0) { ErrorMessage = "Unknown switch:"; return false; } pos += maxLen; CSwitchResult &sw = _switches[switchIndex]; const CSwitchForm &form = switchForms[switchIndex]; if (!form.Multi && sw.ThereIs) { ErrorMessage = "Multiple instances for switch:"; return false; } sw.ThereIs = true; int rem = s.Len() - pos; if (rem < form.MinLen) { ErrorMessage = "Too short switch:"; return false; } sw.WithMinus = false; sw.PostCharIndex = -1; switch (form.Type) { case NSwitchType::kMinus: if (rem != 0) { sw.WithMinus = (s[pos] == '-'); if (sw.WithMinus) pos++; } break; case NSwitchType::kChar: if (rem != 0) { wchar_t c = s[pos]; if (c <= 0x7F) { sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c); if (sw.PostCharIndex >= 0) pos++; } } break; case NSwitchType::kString: sw.PostStrings.Add((const wchar_t *)s + pos); return true; } if (pos != s.Len()) { ErrorMessage = "Too long switch:"; return false; } return true; } bool CParser::ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings) { ErrorLine.Empty(); bool stopSwitch = false; FOR_VECTOR (i, commandStrings) { const UString &s = commandStrings[i]; if (!stopSwitch) { if (s.IsEqualTo(kStopSwitchParsing)) { stopSwitch = true; continue; } if (!s.IsEmpty() && IsItSwitchChar(s[0])) { if (ParseString(s, switchForms)) continue; ErrorLine = s; return false; } } NonSwitchStrings.Add(s); } return true; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/CommandLineParser.h0100777000000000000000000000216713761647206024070 0ustar00// Common/CommandLineParser.h #ifndef __COMMON_COMMAND_LINE_PARSER_H #define __COMMON_COMMAND_LINE_PARSER_H #include "MyString.h" namespace NCommandLineParser { bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2); void SplitCommandLine(const UString &s, UStringVector &parts); namespace NSwitchType { enum EEnum { kSimple, kMinus, kString, kChar }; } struct CSwitchForm { const char *Key; Byte Type; bool Multi; Byte MinLen; // int MaxLen; const char *PostCharSet; }; struct CSwitchResult { bool ThereIs; bool WithMinus; int PostCharIndex; UStringVector PostStrings; CSwitchResult(): ThereIs(false) {}; }; class CParser { unsigned _numSwitches; CSwitchResult *_switches; bool ParseString(const UString &s, const CSwitchForm *switchForms); public: UStringVector NonSwitchStrings; AString ErrorMessage; UString ErrorLine; CParser(unsigned numSwitches); ~CParser(); bool ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings); const CSwitchResult& operator[](size_t index) const { return _switches[index]; } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/Common.h0100777000000000000000000000031413761647206021745 0ustar00// Common.h #ifndef __COMMON_COMMON_H #define __COMMON_COMMON_H #include "../../C/Compiler.h" #include "MyWindows.h" #include "NewHandler.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[1])) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/Common.pri0100777000000000000000000000261013761647206022311 0ustar00HEADERS += $$7ZIP_BASE/CPP/Common/CommandLineParser.h \ $$7ZIP_BASE/CPP/Common/ComTry.h \ $$7ZIP_BASE/CPP/Common/Common.h \ $$7ZIP_BASE/CPP/Common/Defs.h \ $$7ZIP_BASE/CPP/Common/IntToString.h \ $$7ZIP_BASE/CPP/Common/ListFileUtils.h \ $$7ZIP_BASE/CPP/Common/MyBuffer.h \ $$7ZIP_BASE/CPP/Common/MyCom.h \ $$7ZIP_BASE/CPP/Common/MyException.h \ $$7ZIP_BASE/CPP/Common/MyGuidDef.h \ $$7ZIP_BASE/CPP/Common/MyInitGuid.h \ $$7ZIP_BASE/CPP/Common/MyString.h \ $$7ZIP_BASE/CPP/Common/MyTypes.h \ $$7ZIP_BASE/CPP/Common/MyUnknown.h \ $$7ZIP_BASE/CPP/Common/MyVector.h \ $$7ZIP_BASE/CPP/Common/MyWindows.h \ $$7ZIP_BASE/CPP/Common/NewHandler.h \ $$7ZIP_BASE/CPP/Common/StdOutStream.h \ $$7ZIP_BASE/CPP/Common/StringConvert.h \ $$7ZIP_BASE/CPP/Common/StringToInt.h \ $$7ZIP_BASE/CPP/Common/UTFConvert.h \ $$7ZIP_BASE/CPP/Common/Wildcard.h SOURCES += $$7ZIP_BASE/CPP/Common/CommandLineParser.cpp \ $$7ZIP_BASE/CPP/Common/IntToString.cpp \ $$7ZIP_BASE/CPP/Common/ListFileUtils.cpp \ $$7ZIP_BASE/CPP/Common/MyString.cpp \ $$7ZIP_BASE/CPP/Common/MyWindows.cpp \ $$7ZIP_BASE/CPP/Common/NewHandler.cpp \ $$7ZIP_BASE/CPP/Common/StdOutStream.cpp \ $$7ZIP_BASE/CPP/Common/StringConvert.cpp \ $$7ZIP_BASE/CPP/Common/StringToInt.cpp \ $$7ZIP_BASE/CPP/Common/UTFConvert.cpp \ $$7ZIP_BASE/CPP/Common/Wildcard.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/ComTry.h0100777000000000000000000000065013761647206021735 0ustar00// ComTry.h #ifndef __COM_TRY_H #define __COM_TRY_H #include "MyWindows.h" // #include "Exception.h" // #include "NewHandler.h" #define COM_TRY_BEGIN try { #define COM_TRY_END } catch(const char * s) { throw s ; } \ catch(...) { return E_OUTOFMEMORY; } // catch(const CNewException &) { return E_OUTOFMEMORY; } // catch(const CSystemException &e) { return e.ErrorCode; } // catch(...) { return E_FAIL; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/Defs.h0100777000000000000000000000067113761647206021404 0ustar00// Common/Defs.h #ifndef __COMMON_DEFS_H #define __COMMON_DEFS_H template inline T MyMin(T a, T b) { return a < b ? a : b; } template inline T MyMax(T a, T b) { return a > b ? a : b; } template inline int MyCompare(T a, T b) { return a < b ? -1 : (a == b ? 0 : 1); } inline int BoolToInt(bool value) { return (value ? 1: 0); } inline bool IntToBool(int value) { return (value != 0); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/IntToString.cpp0100777000000000000000000000505213761647206023300 0ustar00// Common/IntToString.cpp #include "StdAfx.h" #include "IntToString.h" #define CONVERT_INT_TO_STR(charType, tempSize) \ unsigned char temp[tempSize]; unsigned i = 0; \ while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ *s++ = (charType)('0' + (unsigned)val); \ while (i != 0) { i--; *s++ = temp[i]; } \ *s = 0; void ConvertUInt32ToString(UInt32 val, char *s) throw() { CONVERT_INT_TO_STR(char, 16); } void ConvertUInt64ToString(UInt64 val, char *s) throw() { if (val <= (UInt32)0xFFFFFFFF) { ConvertUInt32ToString((UInt32)val, s); return; } CONVERT_INT_TO_STR(char, 24); } void ConvertUInt64ToOct(UInt64 val, char *s) throw() { UInt64 v = val; unsigned i; for (i = 1;; i++) { v >>= 3; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)(val & 0x7); val >>= 3; s[--i] = (char)('0' + t); } while (i); } void ConvertUInt32ToHex(UInt32 val, char *s) throw() { UInt32 v = val; unsigned i; for (i = 1;; i++) { v >>= 4; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)((val & 0xF)); val >>= 4; s[--i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } while (i); } void ConvertUInt64ToHex(UInt64 val, char *s) throw() { UInt64 v = val; unsigned i; for (i = 1;; i++) { v >>= 4; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)((val & 0xF)); val >>= 4; s[--i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } while (i); } void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw() { s[8] = 0; for (int i = 7; i >= 0; i--) { unsigned t = val & 0xF; val >>= 4; s[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } } /* void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s) { s[8] = 0; for (int i = 7; i >= 0; i--) { unsigned t = val & 0xF; val >>= 4; s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } } */ void ConvertUInt32ToString(UInt32 val, wchar_t *s) throw() { CONVERT_INT_TO_STR(wchar_t, 16); } void ConvertUInt64ToString(UInt64 val, wchar_t *s) throw() { if (val <= (UInt32)0xFFFFFFFF) { ConvertUInt32ToString((UInt32)val, s); return; } CONVERT_INT_TO_STR(wchar_t, 24); } void ConvertInt64ToString(Int64 val, char *s) throw() { if (val < 0) { *s++ = '-'; val = -val; } ConvertUInt64ToString(val, s); } void ConvertInt64ToString(Int64 val, wchar_t *s) throw() { if (val < 0) { *s++ = L'-'; val = -val; } ConvertUInt64ToString(val, s); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/IntToString.h0100777000000000000000000000142113761647206022741 0ustar00// Common/IntToString.h #ifndef __COMMON_INT_TO_STRING_H #define __COMMON_INT_TO_STRING_H #include "MyTypes.h" void ConvertUInt32ToString(UInt32 value, char *s) throw(); void ConvertUInt64ToString(UInt64 value, char *s) throw(); void ConvertUInt32ToString(UInt32 value, wchar_t *s) throw(); void ConvertUInt64ToString(UInt64 value, wchar_t *s) throw(); void ConvertUInt64ToOct(UInt64 value, char *s) throw(); void ConvertUInt32ToHex(UInt32 value, char *s) throw(); void ConvertUInt64ToHex(UInt64 value, char *s) throw(); void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw(); // void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw(); void ConvertInt64ToString(Int64 value, char *s) throw(); void ConvertInt64ToString(Int64 value, wchar_t *s) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/ListFileUtils.cpp0100777000000000000000000000501513761647206023607 0ustar00// Common/ListFileUtils.cpp #include "StdAfx.h" #include "../../C/CpuArch.h" #include "../Windows/FileIO.h" #include "ListFileUtils.h" #include "MyBuffer.h" #include "StringConvert.h" #include "UTFConvert.h" static const char kQuoteChar = '\"'; static void AddName(UStringVector &strings, UString &s) { s.Trim(); if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar) { s.DeleteBack(); s.Delete(0); } if (!s.IsEmpty()) strings.Add(s); } bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage) { NWindows::NFile::NIO::CInFile file; if (!file.Open(fileName,true)) /* follow the symbolic link */ return false; UInt64 fileSize; if (!file.GetLength(fileSize)) return false; if (fileSize >= ((UInt32)1 << 31) - 32) return false; UString u; if (codePage == MY__CP_UTF16 || codePage == MY__CP_UTF16BE) { if ((fileSize & 1) != 0) return false; CByteArr buf((size_t)fileSize); UInt32 processed; if (!file.Read(buf, (UInt32)fileSize, processed)) return false; if (processed != fileSize) return false; file.Close(); unsigned num = (unsigned)fileSize / 2; wchar_t *p = u.GetBuffer(num); if (codePage == MY__CP_UTF16) for (unsigned i = 0; i < num; i++) { wchar_t c = GetUi16(buf + i * 2); if (c == 0) return false; p[i] = c; } else for (unsigned i = 0; i < num; i++) { wchar_t c = (wchar_t)GetBe16(buf + i * 2); if (c == 0) return false; p[i] = c; } u.ReleaseBuffer(num); } else { AString s; char *p = s.GetBuffer((unsigned)fileSize); UInt32 processed; if (!file.Read(p, (UInt32)fileSize, processed)) return false; if (processed != fileSize) return false; file.Close(); p[processed] = 0; s.ReleaseBuffer(); if (s.Len() != processed) return false; // #ifdef CP_UTF8 if (codePage == CP_UTF8) { if (!ConvertUTF8ToUnicode(s, u)) return false; } else // #endif MultiByteToUnicodeString2(u, s, codePage); } const wchar_t kGoodBOM = 0xFEFF; const wchar_t kBadBOM = 0xFFFE; UString s; unsigned i = 0; for (; i < u.Len() && u[i] == kGoodBOM; i++); for (; i < u.Len(); i++) { wchar_t c = u[i]; if (c == kGoodBOM || c == kBadBOM) return false; if (c == L'\n' || c == 0xD) { AddName(strings, s); s.Empty(); } else s += c; } AddName(strings, s); return true; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/ListFileUtils.h0100777000000000000000000000045513761647206023257 0ustar00// Common/ListFileUtils.h #ifndef __COMMON_LIST_FILE_UTILS_H #define __COMMON_LIST_FILE_UTILS_H #include "MyString.h" #include "MyTypes.h" #define MY__CP_UTF16 1200 #define MY__CP_UTF16BE 1201 bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyBuffer.h0100777000000000000000000001115613761647206022242 0ustar00// Common/MyBuffer.h #ifndef __COMMON_MY_BUFFER_H #define __COMMON_MY_BUFFER_H #include "Defs.h" template class CBuffer { T *_items; size_t _size; void CopyToEmpty(const CBuffer &buffer) { if (buffer._size > 0) { _items = new T[buffer._size]; memcpy(_items, buffer._items, buffer._size * sizeof(T)); _size = buffer._size; } } public: void Free() { if (_items) { delete []_items; _items = 0; } _size = 0; } CBuffer(): _items(0), _size(0) {}; CBuffer(size_t size): _items(0), _size(0) { _items = new T[size]; _size = size; } CBuffer(const CBuffer &buffer): _items(0), _size(0) { CopyToEmpty(buffer); } ~CBuffer() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; size_t Size() const { return _size; } void Alloc(size_t size) { if (size != _size) { Free(); if (size != 0) { _items = new T[size]; _size = size; } } } void AllocAtLeast(size_t size) { if (size > _size) { Free(); _items = new T[size]; _size = size; } } void CopyFrom(const T *data, size_t size) { Alloc(size); memcpy(_items, data, size * sizeof(T)); } void ChangeSize_KeepData(size_t newSize, size_t keepSize) { if (newSize == _size) return; T *newBuffer = NULL; if (newSize > 0) { newBuffer = new T[newSize]; if (_size > 0) memcpy(newBuffer, _items, MyMin(MyMin(_size, keepSize), newSize) * sizeof(T)); } delete []_items; _items = newBuffer; _size = newSize; } CBuffer& operator=(const CBuffer &buffer) { Free(); CopyToEmpty(buffer); return *this; } }; template bool operator==(const CBuffer& b1, const CBuffer& b2) { size_t size1 = b1.Size(); if (size1 != b2.Size()) return false; return memcmp(b1, b2, size1 * sizeof(T)) == 0; } template bool operator!=(const CBuffer& b1, const CBuffer& b2) { size_t size1 = b1.Size(); if (size1 == b2.Size()) return false; return memcmp(b1, b2, size1 * sizeof(T)) != 0; } typedef CBuffer CCharBuffer; typedef CBuffer CWCharBuffer; typedef CBuffer CByteBuffer; template class CObjArray { protected: T *_items; private: // we disable constructors CObjArray(const CObjArray &buffer); void operator=(const CObjArray &buffer); public: void Free() { delete []_items; _items = 0; } CObjArray(size_t size): _items(0) { if (size != 0) _items = new T[size]; } CObjArray(): _items(0) {}; ~CObjArray() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; void Alloc(size_t newSize) { delete []_items; _items = 0; _items = new T[newSize]; } }; typedef CObjArray CByteArr; typedef CObjArray CBoolArr; typedef CObjArray CIntArr; // #define CRecArray CObjArray template class CObjArray2 { // protected: T *_items; unsigned _size; CObjArray2(const CObjArray2 &buffer); void operator=(const CObjArray2 &buffer); public: void Free() { delete []_items; _items = 0; _size = 0; } CObjArray2(): _items(0), _size(0) {}; /* CObjArray2(const CObjArray2 &buffer): _items(0), _size(0) { size_t newSize = buffer._size; if (newSize > 0) { T *newBuffer = new T[newSize];; _items = newBuffer; _size = newSize; const T *src = buffer; for (size_t i = 0; i < newSize; i++) newBuffer[i] = src[i]; } } */ /* CObjArray2(size_t size): _items(0), _size(0) { if (size != 0) { _items = new T[size]; _size = size; } } */ ~CObjArray2() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; unsigned Size() const { return (unsigned)_size; } bool IsEmpty() const { return _size == 0; } // SetSize doesn't keep old items. It allocates new array if size is not equal void SetSize(unsigned size) { if (size == _size) return; T *newBuffer = NULL; if (size > 0) newBuffer = new T[size]; delete []_items; _items = newBuffer; _size = size; } /* CObjArray2& operator=(const CObjArray2 &buffer) { Free(); size_t newSize = buffer._size; if (newSize > 0) { T *newBuffer = new T[newSize];; _items = newBuffer; _size = newSize; const T *src = buffer; for (size_t i = 0; i < newSize; i++) newBuffer[i] = src[i]; } return *this; } */ }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyCom.h0100777000000000000000000001427713761647206021556 0ustar00// MyCom.h #ifndef __MY_COM_H #define __MY_COM_H #include "MyWindows.h" #include "NewHandler.h" #ifndef RINOK #define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; } #endif template class CMyComPtr { T* _p; public: CMyComPtr(): _p(NULL) {} CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } CMyComPtr(const CMyComPtr& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); } ~CMyComPtr() { if (_p) _p->Release(); } void Release() { if (_p) { _p->Release(); _p = NULL; } } operator T*() const { return (T*)_p; } // T& operator*() const { return *_p; } T** operator&() { return &_p; } T* operator->() const { return _p; } T* operator=(T* p) { if (p) p->AddRef(); if (_p) _p->Release(); _p = p; return p; } T* operator=(const CMyComPtr& lp) { return (*this = lp._p); } bool operator!() const { return (_p == NULL); } // bool operator==(T* pT) const { return _p == pT; } void Attach(T* p2) { Release(); _p = p2; } T* Detach() { T* pt = _p; _p = NULL; return pt; } #ifdef _WIN32 HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) { return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); } #endif /* HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) { CLSID clsid; HRESULT hr = CLSIDFromProgID(szProgID, &clsid); ATLASSERT(_p == NULL); if (SUCCEEDED(hr)) hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); return hr; } */ template HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() { return _p->QueryInterface(iid, (void**)pp); } }; ////////////////////////////////////////////////////////// inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr) { *bstr = ::SysAllocString(src); return (*bstr != NULL) ? S_OK : E_OUTOFMEMORY; } class CMyComBSTR { BSTR m_str; public: CMyComBSTR(): m_str(NULL) {} CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); } // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } /* CMyComBSTR(REFGUID src) { LPOLESTR szGuid; StringFromCLSID(src, &szGuid); m_str = ::SysAllocString(szGuid); CoTaskMemFree(szGuid); } */ ~CMyComBSTR() { ::SysFreeString(m_str); } CMyComBSTR& operator=(const CMyComBSTR& src) { if (m_str != src.m_str) { if (m_str) ::SysFreeString(m_str); m_str = src.MyCopy(); } return *this; } CMyComBSTR& operator=(LPCOLESTR src) { ::SysFreeString(m_str); m_str = ::SysAllocString(src); return *this; } // unsigned Len() const { return ::SysStringLen(m_str); } operator BSTR() const { return m_str; } BSTR* operator&() { return &m_str; } BSTR MyCopy() const { int byteLen = ::SysStringByteLen(m_str); BSTR res = ::SysAllocStringByteLen(NULL, byteLen); memcpy(res, m_str, byteLen); return res; } /* void Attach(BSTR src) { m_str = src; } BSTR Detach() { BSTR s = m_str; m_str = NULL; return s; } */ void Empty() { ::SysFreeString(m_str); m_str = NULL; } bool operator!() const { return (m_str == NULL); } }; ////////////////////////////////////////////////////////// class CMyUnknownImp { public: ULONG __m_RefCount; CMyUnknownImp(): __m_RefCount(0) {} }; #define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \ (REFGUID iid, void **outObject) throw() { *outObject = NULL; #define MY_QUERYINTERFACE_ENTRY(i) else if (iid == IID_ ## i) \ { *outObject = (void *)(i *)this; } #define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \ { *outObject = (void *)(IUnknown *)(i *)this; } #define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ MY_QUERYINTERFACE_ENTRY(i) #define MY_QUERYINTERFACE_END else return E_NOINTERFACE; AddRef(); return S_OK; } #define MY_ADDREF_RELEASE \ STDMETHOD_(ULONG, AddRef)() throw() { return ++__m_RefCount; } \ STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \ return __m_RefCount; delete this; return 0; } #define MY_UNKNOWN_IMP_SPEC(i) \ MY_QUERYINTERFACE_BEGIN \ i \ MY_QUERYINTERFACE_END \ MY_ADDREF_RELEASE #define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \ MY_QUERYINTERFACE_END \ MY_ADDREF_RELEASE #define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ MY_QUERYINTERFACE_ENTRY(i) \ ) #define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ ) #define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ ) #define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ ) #define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ ) #define MY_UNKNOWN_IMP6(i1, i2, i3, i4, i5, i6) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ MY_QUERYINTERFACE_ENTRY(i6) \ ) #define MY_UNKNOWN_IMP7(i1, i2, i3, i4, i5, i6, i7) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ MY_QUERYINTERFACE_ENTRY(i6) \ MY_QUERYINTERFACE_ENTRY(i7) \ ) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyException.h0100777000000000000000000000034313761647206022763 0ustar00// Common/Exception.h #ifndef __COMMON_EXCEPTION_H #define __COMMON_EXCEPTION_H #include "MyWindows.h" struct CSystemException { HRESULT ErrorCode; CSystemException(HRESULT errorCode): ErrorCode(errorCode) {} }; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyGuidDef.h0100777000000000000000000000203413761647206022333 0ustar00// Common/MyGuidDef.h #ifndef GUID_DEFINED #define GUID_DEFINED #include "MyTypes.h" typedef struct { UInt32 Data1; UInt16 Data2; UInt16 Data3; unsigned char Data4[8]; } GUID; #ifdef __cplusplus #define REFGUID const GUID & #else #define REFGUID const GUID * #endif #define REFCLSID REFGUID #define REFIID REFGUID #ifdef __cplusplus inline int operator==(REFGUID g1, REFGUID g2) { for (int i = 0; i < (int)sizeof(g1); i++) if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i]) return 0; return 1; } inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } #endif #ifdef __cplusplus #define MY_EXTERN_C extern "C" #else #define MY_EXTERN_C extern #endif #endif #ifdef DEFINE_GUID #undef DEFINE_GUID #endif #ifdef INITGUID #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } #else #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ MY_EXTERN_C const GUID name #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyInitGuid.h0100777000000000000000000000227013761647206022542 0ustar00// Common/MyInitGuid.h #ifndef __COMMON_MY_INITGUID_H #define __COMMON_MY_INITGUID_H /* This file must be included only to one C++ file in project before declarations of COM interfaces with DEFINE_GUID macro. Each GUID must be initialized exactly once in project. There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h): - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name. - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID. Also we need IID_IUnknown that is initialized in some file for linking: MSVC: by default the linker uses some lib file that contains IID_IUnknown MinGW: add -luuid switch for linker WinCE: we define IID_IUnknown in this file Other: we define IID_IUnknown in this file */ #ifdef _WIN32 #ifdef UNDER_CE #include #endif #include #ifdef UNDER_CE DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); #endif #else #define INITGUID #include "MyGuidDef.h" DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyString.cpp0100777000000000000000000005522513761647206022637 0ustar00// Common/MyString.cpp #include "StdAfx.h" #ifdef _WIN32 #include #include #else #include #endif #if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) #include "StringConvert.h" #endif #include "MyString.h" #define MY_STRING_NEW(_T_, _size_) new _T_[_size_] // #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) /* inline const char* MyStringGetNextCharPointer(const char *p) throw() { #if defined(_WIN32) && !defined(UNDER_CE) return CharNextA(p); #else return p + 1; #endif } */ int FindCharPosInString(const char *s, char c) throw() { for (const char *p = s;; p++) { if (*p == c) return (int)(p - s); if (*p == 0) return -1; // MyStringGetNextCharPointer(p); } } int FindCharPosInString(const wchar_t *s, wchar_t c) throw() { for (const wchar_t *p = s;; p++) { if (*p == c) return (int)(p - s); if (*p == 0) return -1; } } /* void MyStringUpper_Ascii(wchar_t *s) { for (;;) { wchar_t c = *s; if (c == 0) return; *s++ = MyCharUpper_Ascii(c); } } */ void MyStringLower_Ascii(wchar_t *s) throw() { for (;;) { wchar_t c = *s; if (c == 0) return; *s++ = MyCharLower_Ascii(c); } } #ifdef _WIN32 #ifdef _UNICODE // wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } // wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } // for WinCE - FString - char // const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } #else // const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } // char * MyStringUpper(char *s) { return CharUpperA(s); } // char * MyStringLower(char *s) { return CharLowerA(s); } wchar_t MyCharUpper_WIN(wchar_t c) throw() { wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return (wchar_t)(unsigned)(UINT_PTR)res; const int kBufSize = 4; char s[kBufSize + 1]; int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); if (numChars == 0 || numChars > kBufSize) return c; s[numChars] = 0; ::CharUpperA(s); ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); return c; } /* wchar_t MyCharLower_WIN(wchar_t c) { wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return (wchar_t)(unsigned)(UINT_PTR)res; const int kBufSize = 4; char s[kBufSize + 1]; int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); if (numChars == 0 || numChars > kBufSize) return c; s[numChars] = 0; ::CharLowerA(s); ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); return c; } */ /* wchar_t * MyStringUpper(wchar_t *s) { if (s == 0) return 0; wchar_t *res = CharUpperW(s); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return res; AString a = UnicodeStringToMultiByte(s); a.MakeUpper(); MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); return s; } */ /* wchar_t * MyStringLower(wchar_t *s) { if (s == 0) return 0; wchar_t *res = CharLowerW(s); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return res; AString a = UnicodeStringToMultiByte(s); a.MakeLower(); MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); return s; } */ #endif #endif bool IsString1PrefixedByString2(const char *s1, const char *s2) throw() { for (;;) { unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; } } bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; if (c1 == 0) return true; } } // ---------- ASCII ---------- bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() { const char *s1 = _chars; for (;;) { char c2 = *s++; if (c2 == 0) return true; char c1 = *s1++; if (MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; } } bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() { const wchar_t *s1 = _chars; for (;;) { char c2 = *s++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) return false; } } bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw() { for (;;) { unsigned char c = *a; if (c != *u) return false; if (c == 0) return true; a++; u++; } } bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw() { for (;;) { char c1 = *s1++; char c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) return true; } } bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) return true; } } bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw() { for (;;) { wchar_t c1 = *s1++; char c2 = *s2++; if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) return false; if (c1 == 0) return true; } } bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (c1 != c2) return false; } } // NTFS order: uses upper case int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2) { wchar_t u1 = MyCharUpper(c1); wchar_t u2 = MyCharUpper(c2); if (u1 < u2) return -1; if (u1 > u2) return 1; } if (c1 == 0) return 0; } } int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw() { for (; num != 0; num--) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2) { wchar_t u1 = MyCharUpper(c1); wchar_t u2 = MyCharUpper(c2); if (u1 < u2) return -1; if (u1 > u2) return 1; } if (c1 == 0) return 0; } return 0; } // ---------- AString ---------- void AString::InsertSpace(unsigned &index, unsigned size) { Grow(size); MoveItems(index + size, index); } void AString::ReAlloc(unsigned newLimit) { if (newLimit < _len || newLimit >= 0x20000000) throw 20130220; // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); char *newBuf = MY_STRING_NEW(char, newLimit + 1); memcpy(newBuf, _chars, (size_t)(_len + 1)); \ MY_STRING_DELETE(_chars); _chars = newBuf; _limit = newLimit; } void AString::SetStartLen(unsigned len) { _chars = 0; _chars = MY_STRING_NEW(char, len + 1); _len = len; _limit = len; } void AString::Grow_1() { unsigned next = _len; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } void AString::Grow(unsigned n) { unsigned freeSize = _limit - _len; if (n <= freeSize) return; unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } /* AString::AString(unsigned num, const char *s) { unsigned len = MyStringLen(s); if (num > len) num = len; SetStartLen(num); memcpy(_chars, s, num); _chars[num] = 0; } */ AString::AString(unsigned num, const AString &s) { if (num > s._len) num = s._len; SetStartLen(num); memcpy(_chars, s._chars, num); _chars[num] = 0; } AString::AString(const AString &s, char c) { SetStartLen(s.Len() + 1); char *chars = _chars; unsigned len = s.Len(); memcpy(chars, s, len); chars[len] = c; chars[len + 1] = 0; } AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2) { SetStartLen(num1 + num2); char *chars = _chars; memcpy(chars, s1, num1); memcpy(chars + num1, s2, num2 + 1); } AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); } AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); } AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); } AString::AString() { _chars = 0; _chars = MY_STRING_NEW(char, 4); _len = 0; _limit = 4 - 1; _chars[0] = 0; } AString::AString(char c) { SetStartLen(1); _chars[0] = c; _chars[1] = 0; } AString::AString(const char *s) { SetStartLen(MyStringLen(s)); MyStringCopy(_chars, s); } AString::AString(const AString &s) { SetStartLen(s._len); MyStringCopy(_chars, s._chars); } AString &AString::operator=(char c) { if (1 > _limit) { char *newBuf = MY_STRING_NEW(char, 1 + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = 1; } _len = 1; _chars[0] = c; _chars[1] = 0; return *this; } AString &AString::operator=(const char *s) { unsigned len = MyStringLen(s); if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s); return *this; } AString &AString::operator=(const AString &s) { if (&s == this) return *this; unsigned len = s._len; if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s._chars); return *this; } AString &AString::operator+=(const char *s) { unsigned len = MyStringLen(s); Grow(len); MyStringCopy(_chars + _len, s); _len += len; return *this; } AString &AString::operator+=(const AString &s) { Grow(s._len); MyStringCopy(_chars + _len, s._chars); _len += s._len; return *this; } void AString::SetFrom(const char *s, unsigned len) // no check { if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } memcpy(_chars, s, len); _chars[len] = 0; _len = len; } int AString::Find(const AString &s, unsigned startIndex) const throw() { if (s.IsEmpty()) return startIndex; for (; startIndex < _len; startIndex++) { unsigned j; for (j = 0; j < s._len && startIndex + j < _len; j++) if (_chars[startIndex + j] != s._chars[j]) break; if (j == s._len) return (int)startIndex; } return -1; } int AString::ReverseFind(char c) const throw() { if (_len == 0) return -1; const char *p = _chars + _len - 1; for (;;) { if (*p == c) return (int)(p - _chars); if (p == _chars) return -1; p--; // p = GetPrevCharPointer(_chars, p); } } void AString::TrimLeft() throw() { const char *p = _chars; for (;; p++) { char c = *p; if (c != ' ' && c != '\n' && c != '\t') break; } unsigned pos = (unsigned)(p - _chars); if (pos != 0) { MoveItems(0, pos); _len -= pos; } } void AString::TrimRight() throw() { const char *p = _chars; int i; for (i = _len - 1; i >= 0; i--) { char c = p[i]; if (c != ' ' && c != '\n' && c != '\t') break; } i++; if ((unsigned)i != _len) { _chars[i] = 0; _len = i; } } void AString::InsertAtFront(char c) { if (_limit == _len) Grow_1(); MoveItems(1, 0); _chars[0] = c; _len++; } /* void AString::Insert(unsigned index, char c) { InsertSpace(index, 1); _chars[index] = c; _len++; } */ void AString::Insert(unsigned index, const char *s) { unsigned num = MyStringLen(s); if (num != 0) { InsertSpace(index, num); memcpy(_chars + index, s, num); _len += num; } } void AString::Insert(unsigned index, const AString &s) { unsigned num = s.Len(); if (num != 0) { InsertSpace(index, num); memcpy(_chars + index, s, num); _len += num; } } void AString::RemoveChar(char ch) throw() { int pos = Find(ch); if (pos < 0) return; const char *src = _chars; char *dest = _chars + pos; pos++; unsigned len = _len; for (; (unsigned)pos < len; pos++) { char c = src[(unsigned)pos]; if (c != ch) *dest++ = c; } *dest = 0; _len = (unsigned)(dest - _chars); } // !!!!!!!!!!!!!!! test it if newChar = '\0' void AString::Replace(char oldChar, char newChar) throw() { if (oldChar == newChar) return; // 0; // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldChar, pos); if (pos < 0) break; _chars[pos] = newChar; pos++; // number++; } return; // number; } void AString::Replace(const AString &oldString, const AString &newString) { if (oldString.IsEmpty()) return; // 0; if (oldString == newString) return; // 0; unsigned oldLen = oldString.Len(); unsigned newLen = newString.Len(); // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldString, pos); if (pos < 0) break; Delete(pos, oldLen); Insert(pos, newString); pos += newLen; // number++; } // return number; } void AString::Delete(unsigned index) throw() { MoveItems(index, index + 1); _len--; } void AString::Delete(unsigned index, unsigned count) throw() { if (index + count > _len) count = _len - index; if (count > 0) { MoveItems(index, index + count); _len -= count; } } void AString::DeleteFrontal(unsigned num) throw() { if (num != 0) { MoveItems(0, num); _len -= num; } } /* AString operator+(const AString &s1, const AString &s2) { AString result(s1); result += s2; return result; } AString operator+(const AString &s, const char *chars) { AString result(s); result += chars; return result; } AString operator+(const char *chars, const AString &s) { AString result(chars); result += s; return result; } AString operator+(const AString &s, char c) { AString result(s); result += c; return result; } */ /* AString operator+(char c, const AString &s) { AString result(c); result += s; return result; } */ // ---------- UString ---------- void UString::InsertSpace(unsigned index, unsigned size) { Grow(size); MoveItems(index + size, index); } void UString::ReAlloc(unsigned newLimit) { if (newLimit < _len || newLimit >= 0x20000000) throw 20130221; // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1); wmemcpy(newBuf, _chars, _len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = newLimit; } void UString::SetStartLen(unsigned len) { _chars = 0; _chars = MY_STRING_NEW(wchar_t, len + 1); _len = len; _limit = len; } void UString::Grow_1() { unsigned next = _len; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } void UString::Grow(unsigned n) { unsigned freeSize = _limit - _len; if (n <= freeSize) return; unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } UString::UString(unsigned num, const wchar_t *s) { unsigned len = MyStringLen(s); if (num > len) num = len; SetStartLen(num); wmemcpy(_chars, s, num); _chars[num] = 0; } UString::UString(unsigned num, const UString &s) { if (num > s._len) num = s._len; SetStartLen(num); wmemcpy(_chars, s._chars, num); _chars[num] = 0; } UString::UString(const UString &s, wchar_t c) { SetStartLen(s.Len() + 1); wchar_t *chars = _chars; unsigned len = s.Len(); wmemcpy(chars, s, len); chars[len] = c; chars[len + 1] = 0; } UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2) { SetStartLen(num1 + num2); wchar_t *chars = _chars; wmemcpy(chars, s1, num1); wmemcpy(chars + num1, s2, num2 + 1); } UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); } UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); } UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); } UString::UString() { _chars = 0; _chars = MY_STRING_NEW(wchar_t, 4); _len = 0; _limit = 4 - 1; _chars[0] = 0; } UString::UString(wchar_t c) { SetStartLen(1); _chars[0] = c; _chars[1] = 0; } UString::UString(const wchar_t *s) { SetStartLen(MyStringLen(s)); MyStringCopy(_chars, s); } UString::UString(const UString &s) { SetStartLen(s._len); MyStringCopy(_chars, s._chars); } UString &UString::operator=(wchar_t c) { if (1 > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = 1; } _len = 1; _chars[0] = c; _chars[1] = 0; return *this; } UString &UString::operator=(const wchar_t *s) { unsigned len = MyStringLen(s); if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s); return *this; } UString &UString::operator=(const UString &s) { if (&s == this) return *this; unsigned len = s._len; if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s._chars); return *this; } UString &UString::operator+=(const wchar_t *s) { unsigned len = MyStringLen(s); Grow(len); MyStringCopy(_chars + _len, s); _len += len; return *this; } UString &UString::operator+=(const UString &s) { Grow(s._len); MyStringCopy(_chars + _len, s._chars); _len += s._len; return *this; } void UString::SetFrom(const wchar_t *s, unsigned len) // no check { if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } wmemcpy(_chars, s, len); _chars[len] = 0; _len = len; } void UString::SetFromAscii(const char *s) { unsigned len = MyStringLen(s); if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } wchar_t *chars = _chars; for (unsigned i = 0; i < len; i++) chars[i] = s[i]; chars[len] = 0; _len = len; } void UString::AddAsciiStr(const char *s) { unsigned len = MyStringLen(s); Grow(len); wchar_t *chars = _chars + _len; for (unsigned i = 0; i < len; i++) chars[i] = s[i]; chars[len] = 0; _len += len; } int UString::Find(const UString &s, unsigned startIndex) const throw() { if (s.IsEmpty()) return startIndex; for (; startIndex < _len; startIndex++) { unsigned j; for (j = 0; j < s._len && startIndex + j < _len; j++) if (_chars[startIndex + j] != s._chars[j]) break; if (j == s._len) return (int)startIndex; } return -1; } int UString::ReverseFind(wchar_t c) const throw() { if (_len == 0) return -1; const wchar_t *p = _chars + _len - 1; for (;;) { if (*p == c) return (int)(p - _chars); if (p == _chars) return -1; p--; } } void UString::TrimLeft() throw() { const wchar_t *p = _chars; for (;; p++) { wchar_t c = *p; if (c != ' ' && c != '\n' && c != '\t') break; } unsigned pos = (unsigned)(p - _chars); if (pos != 0) { MoveItems(0, pos); _len -= pos; } } void UString::TrimRight() throw() { const wchar_t *p = _chars; int i; for (i = _len - 1; i >= 0; i--) { wchar_t c = p[i]; if (c != ' ' && c != '\n' && c != '\t') break; } i++; if ((unsigned)i != _len) { _chars[i] = 0; _len = i; } } void UString::InsertAtFront(wchar_t c) { if (_limit == _len) Grow_1(); MoveItems(1, 0); _chars[0] = c; _len++; } /* void UString::Insert(unsigned index, wchar_t c) { InsertSpace(index, 1); _chars[index] = c; _len++; } */ void UString::Insert(unsigned index, const wchar_t *s) { unsigned num = MyStringLen(s); if (num != 0) { InsertSpace(index, num); wmemcpy(_chars + index, s, num); _len += num; } } void UString::Insert(unsigned index, const UString &s) { unsigned num = s.Len(); if (num != 0) { InsertSpace(index, num); wmemcpy(_chars + index, s, num); _len += num; } } void UString::RemoveChar(wchar_t ch) throw() { int pos = Find(ch); if (pos < 0) return; const wchar_t *src = _chars; wchar_t *dest = _chars + pos; pos++; unsigned len = _len; for (; (unsigned)pos < len; pos++) { wchar_t c = src[(unsigned)pos]; if (c != ch) *dest++ = c; } *dest = 0; _len = (unsigned)(dest - _chars); } // !!!!!!!!!!!!!!! test it if newChar = '\0' void UString::Replace(wchar_t oldChar, wchar_t newChar) throw() { if (oldChar == newChar) return; // 0; // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldChar, pos); if (pos < 0) break; _chars[pos] = newChar; pos++; // number++; } return; // number; } void UString::Replace(const UString &oldString, const UString &newString) { if (oldString.IsEmpty()) return; // 0; if (oldString == newString) return; // 0; unsigned oldLen = oldString.Len(); unsigned newLen = newString.Len(); // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldString, pos); if (pos < 0) break; Delete(pos, oldLen); Insert(pos, newString); pos += newLen; // number++; } // return number; } void UString::Delete(unsigned index) throw() { MoveItems(index, index + 1); _len--; } void UString::Delete(unsigned index, unsigned count) throw() { if (index + count > _len) count = _len - index; if (count > 0) { MoveItems(index, index + count); _len -= count; } } void UString::DeleteFrontal(unsigned num) throw() { if (num != 0) { MoveItems(0, num); _len -= num; } } // ---------------------------------------- /* int MyStringCompareNoCase(const char *s1, const char *s2) { return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); } */ static inline UINT GetCurrentCodePage() { #if defined(UNDER_CE) || !defined(_WIN32) return CP_ACP; #else return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; #endif } #ifdef USE_UNICODE_FSTRING #ifndef _UNICODE AString fs2fas(CFSTR s) { return UnicodeStringToMultiByte(s, GetCurrentCodePage()); } FString fas2fs(const AString &s) { return MultiByteToUnicodeString(s, GetCurrentCodePage()); } #endif #else UString fs2us(const FString &s) { return MultiByteToUnicodeString((AString)s, GetCurrentCodePage()); } FString us2fs(const wchar_t *s) { return UnicodeStringToMultiByte(s, GetCurrentCodePage()); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyString.h0100777000000000000000000003633313761647206022303 0ustar00// Common/String.h #ifndef __COMMON_STRING_H #define __COMMON_STRING_H #include #ifndef _WIN32 #include #include #endif #include "MyTypes.h" #include "MyVector.h" inline unsigned MyStringLen(const char *s) { unsigned i; for (i = 0; s[i] != 0; i++); return i; } inline void MyStringCopy(char *dest, const char *src) { while ((*dest++ = *src++) != 0); } inline char *MyStpCpy(char *dest, const char *src) { for (;;) { char c = *src; *dest = c; if (c == 0) return dest; src++; dest++; } } inline unsigned MyStringLen(const wchar_t *s) { unsigned i; for (i = 0; s[i] != 0; i++); return i; } inline void MyStringCopy(wchar_t *dest, const wchar_t *src) { while ((*dest++ = *src++) != 0); } int FindCharPosInString(const char *s, char c) throw(); int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); #ifdef _WIN32 #ifndef _UNICODE #define STRING_UNICODE_THROW #endif #endif #ifndef STRING_UNICODE_THROW #define STRING_UNICODE_THROW throw() #endif /* inline char MyCharUpper_Ascii(char c) { if (c >= 'a' && c <= 'z') return (char)(c - 0x20); return c; } inline wchar_t MyCharUpper_Ascii(wchar_t c) { if (c >= 'a' && c <= 'z') return (wchar_t)(c - 0x20); return c; } */ inline char MyCharLower_Ascii(char c) { if (c >= 'A' && c <= 'Z') return (char)(c + 0x20); return c; } inline wchar_t MyCharLower_Ascii(wchar_t c) { if (c >= 'A' && c <= 'Z') return (wchar_t)(c + 0x20); return c; } wchar_t MyCharUpper_WIN(wchar_t c) throw(); inline wchar_t MyCharUpper(wchar_t c) throw() { if (c < 'a') return c; if (c <= 'z') return (wchar_t)(c - 0x20); if (c <= 0x7F) return c; #ifdef _WIN32 #ifdef _UNICODE return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); #else return (wchar_t)MyCharUpper_WIN(c); #endif #else return (wchar_t)towupper(c); #endif } /* wchar_t MyCharLower_WIN(wchar_t c) throw(); inline wchar_t MyCharLower(wchar_t c) throw() { if (c < 'A') return c; if (c <= 'Z') return (wchar_t)(c + 0x20); if (c <= 0x7F) return c; #ifdef _WIN32 #ifdef _UNICODE return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); #else return (wchar_t)MyCharLower_WIN(c); #endif #else return (wchar_t)tolower(c); #endif } */ // char *MyStringUpper(char *s) throw(); // char *MyStringLower(char *s) throw(); // void MyStringUpper_Ascii(wchar_t *s) throw(); void MyStringLower_Ascii(wchar_t *s) throw(); // wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; // wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); // ---------- ASCII ---------- // char values in ASCII strings must be less then 128 bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); #define MY_STRING_DELETE(_p_) delete []_p_; // #define MY_STRING_DELETE(_p_) my_delete(_p_); class AString { char *_chars; unsigned _len; unsigned _limit; void MoveItems(unsigned dest, unsigned src) { memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); } void InsertSpace(unsigned &index, unsigned size); void ReAlloc(unsigned newLimit); void SetStartLen(unsigned len); void Grow_1(); void Grow(unsigned n); // AString(unsigned num, const char *s); AString(unsigned num, const AString &s); AString(const AString &s, char c); // it's for String + char AString(const char *s1, unsigned num1, const char *s2, unsigned num2); friend AString operator+(const AString &s, char c) { return AString(s, c); } ; // friend AString operator+(char c, const AString &s); // is not supported friend AString operator+(const AString &s1, const AString &s2); friend AString operator+(const AString &s1, const char *s2); friend AString operator+(const char *s1, const AString &s2); public: AString(); AString(char c); AString(const char *s); AString(const AString &s); ~AString() { MY_STRING_DELETE(_chars); } unsigned Len() const { return _len; } bool IsEmpty() const { return _len == 0; } void Empty() { _len = 0; _chars[0] = 0; } operator const char *() const { return _chars; } const char *Ptr() const { return _chars; } const char *Ptr(unsigned pos) const { return _chars + pos; } const char *RightPtr(unsigned num) const { return _chars + _len - num; } char Back() const { return _chars[_len - 1]; } void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } // The minimum size of the character buffer in characters. // This value does not include space for a null terminator. char *GetBuffer(unsigned minBufLen) { if (minBufLen > _limit) ReAlloc(minBufLen); return _chars; } void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); } void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } AString &operator=(char c); AString &operator=(const char *s); AString &operator=(const AString &s); AString &operator+=(char c) { if (_limit == _len) Grow_1(); unsigned len = _len; char *chars = _chars; chars[len++] = c; chars[len] = 0; _len = len; return *this; } AString &operator+=(const char *s); AString &operator+=(const AString &s); void SetFrom(const char *s, unsigned len); // no check // AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } AString Left(unsigned count) const { return AString(count, *this); } // void MakeUpper() { MyStringUpper(_chars); } // void MakeLower() { MyStringLower(_chars); } // int Compare(const char *s) const { return MyStringCompare(_chars, s); } // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); int Find(char c) const { return FindCharPosInString(_chars, c); } int Find(char c, unsigned startIndex) const { int pos = FindCharPosInString(_chars + startIndex, c); return pos < 0 ? -1 : (int)startIndex + pos; } int ReverseFind(char c) const throw(); int Find(const AString &s) const { return Find(s, 0); } int Find(const AString &s, unsigned startIndex) const throw(); void TrimLeft() throw(); void TrimRight() throw(); void Trim() { TrimRight(); TrimLeft(); } void InsertAtFront(char c); // void Insert(unsigned index, char c); void Insert(unsigned index, const char *s); void Insert(unsigned index, const AString &s); void RemoveChar(char ch) throw(); void Replace(char oldChar, char newChar) throw(); void Replace(const AString &oldString, const AString &newString); void Delete(unsigned index) throw(); void Delete(unsigned index, unsigned count) throw(); void DeleteFrontal(unsigned num) throw(); void DeleteBack() { _chars[--_len] = 0; } void DeleteFrom(unsigned index) { if (index < _len) { _len = index; _chars[index] = 0; } } }; bool operator<(const AString &s1, const AString &s2); bool operator>(const AString &s1, const AString &s2); /* bool operator==(const AString &s1, const AString &s2); bool operator==(const AString &s1, const char *s2); bool operator==(const char *s1, const AString &s2); bool operator!=(const AString &s1, const AString &s2); bool operator!=(const AString &s1, const char *s2); bool operator!=(const char *s1, const AString &s2); */ inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } class UString { wchar_t *_chars; unsigned _len; unsigned _limit; void MoveItems(unsigned dest, unsigned src) { memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); } void InsertSpace(unsigned index, unsigned size); void ReAlloc(unsigned newLimit); void SetStartLen(unsigned len); void Grow_1(); void Grow(unsigned n); UString(unsigned num, const wchar_t *s); // for Mid UString(unsigned num, const UString &s); // for Left UString(const UString &s, wchar_t c); // it's for String + char UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } ; // friend UString operator+(wchar_t c, const UString &s); // is not supported friend UString operator+(const UString &s1, const UString &s2); friend UString operator+(const UString &s1, const wchar_t *s2); friend UString operator+(const wchar_t *s1, const UString &s2); public: UString(); UString(wchar_t c); UString(const wchar_t *s); UString(const UString &s); ~UString() { MY_STRING_DELETE(_chars); } unsigned Len() const { return _len; } bool IsEmpty() const { return _len == 0; } void Empty() { _len = 0; _chars[0] = 0; } operator const wchar_t *() const { return _chars; } const wchar_t *Ptr() const { return _chars; } const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } wchar_t Back() const { return _chars[_len - 1]; } void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } // The minimum size of the character buffer in characters. // This value does not include space for a null terminator. wchar_t *GetBuffer(unsigned minBufLen) { if (minBufLen > _limit) ReAlloc(minBufLen); return _chars; } void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); } void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } UString &operator=(wchar_t c); UString &operator=(const wchar_t *s); UString &operator=(const UString &s); UString &operator+=(wchar_t c) { if (_limit == _len) Grow_1(); unsigned len = _len; wchar_t *chars = _chars; chars[len++] = c; chars[len] = 0; _len = len; return *this; } UString &operator+=(const wchar_t *s); UString &operator+=(const UString &s); void SetFrom(const wchar_t *s, unsigned len); // no check void SetFromAscii(const char *s); void AddAsciiStr(const char *s); UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } UString Left(unsigned count) const { return UString(count, *this); } // void MakeUpper() { MyStringUpper(_chars); } // void MakeUpper() { MyStringUpper_Ascii(_chars); } // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } bool IsEqualToNoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }; bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } int Find(wchar_t c, unsigned startIndex) const { int pos = FindCharPosInString(_chars + startIndex, c); return pos < 0 ? -1 : (int)startIndex + pos; } int Find(const UString &s) const { return Find(s, 0); } int Find(const UString &s, unsigned startIndex) const throw(); int ReverseFind(wchar_t c) const throw(); void TrimLeft() throw(); void TrimRight() throw(); void Trim() { TrimRight(); TrimLeft(); } void InsertAtFront(wchar_t c); // void Insert(unsigned index, wchar_t c); void Insert(unsigned index, const wchar_t *s); void Insert(unsigned index, const UString &s); void RemoveChar(wchar_t ch) throw(); void Replace(wchar_t oldChar, wchar_t newChar) throw(); void Replace(const UString &oldString, const UString &newString); void Delete(unsigned index) throw(); void Delete(unsigned index, unsigned count) throw(); void DeleteFrontal(unsigned num) throw(); void DeleteBack() { _chars[--_len] = 0; } void DeleteFrom(unsigned index) { if (index < _len) { _len = index; _chars[index] = 0; } } }; bool operator<(const UString &s1, const UString &s2); bool operator>(const UString &s1, const UString &s2); inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } typedef CObjectVector AStringVector; typedef CObjectVector UStringVector; #ifdef _UNICODE typedef UString CSysString; #else typedef AString CSysString; #endif typedef CObjectVector CSysStringVector; // ---------- FString ---------- // #ifdef _WIN32 #define USE_UNICODE_FSTRING // #endif #ifdef USE_UNICODE_FSTRING #define __FTEXT(quote) L##quote typedef wchar_t FChar; typedef UString FString; #define fs2us(_x_) (_x_) #define us2fs(_x_) (_x_) FString fas2fs(const AString &s); AString fs2fas(const FChar *s); #else #define __FTEXT(quote) quote typedef char FChar; typedef AString FString; UString fs2us(const FString &s); FString us2fs(const wchar_t *s); #define fas2fs(_x_) (_x_) #define fs2fas(_x_) (_x_) #endif #define FTEXT(quote) __FTEXT(quote) #define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) #define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) #define FCHAR_ANY_MASK FTEXT('*') #define FSTRING_ANY_MASK FTEXT("*") typedef const FChar *CFSTR; typedef CObjectVector FStringVector; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyTypes.h0100777000000000000000000000056013761647206022132 0ustar00// Common/MyTypes.h #ifndef __COMMON_MY_TYPES_H #define __COMMON_MY_TYPES_H #include "../../C/7zTypes.h" typedef int HRes; #ifdef __cplusplus struct CBoolPair { bool Val; bool Def; CBoolPair(): Val(false), Def(false) {} void Init() { Val = false; Def = false; } void SetTrueTrue() { Val = true; Def = true; } }; #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyUnknown.h0100777000000000000000000000024313761647206022463 0ustar00// MyUnknown.h #ifndef __MY_UNKNOWN_H #define __MY_UNKNOWN_H #ifdef _WIN32 #include #include #else #include "MyWindows.h" #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyVector.h0100777000000000000000000003067113761647206022276 0ustar00// Common/MyVector.h #ifndef __COMMON_MY_VECTOR_H #define __COMMON_MY_VECTOR_H template class CRecordVector { T *_items; unsigned _size; unsigned _capacity; void MoveItems(unsigned destIndex, unsigned srcIndex) { memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * (size_t)sizeof(T)); } void ReserveOnePosition() { if (_size == _capacity) { unsigned newCapacity = _capacity + (_capacity >> 2) + 1; T *p = new T[newCapacity]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newCapacity; } } public: CRecordVector(): _items(0), _size(0), _capacity(0) {} CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0) { unsigned size = v.Size(); if (size != 0) { _items = new T[size]; _size = size; _capacity = size; memcpy(_items, v._items, (size_t)size * (size_t)sizeof(T)); } } unsigned Size() const { return _size; } bool IsEmpty() const { return _size == 0; } void ConstructReserve(unsigned size) { if (size != 0) { _items = new T[size]; _capacity = size; } } void Reserve(unsigned newCapacity) { if (newCapacity > _capacity) { T *p = new T[newCapacity]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newCapacity; } } void ClearAndReserve(unsigned newCapacity) { Clear(); if (newCapacity > _capacity) { delete []_items; _items = NULL; _capacity = 0; _items = new T[newCapacity]; _capacity = newCapacity; } } void ClearAndSetSize(unsigned newSize) { ClearAndReserve(newSize); _size = newSize; } void ChangeSize_KeepData(unsigned newSize) { if (newSize > _capacity) { T *p = new T[newSize]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newSize; } _size = newSize; } void ReserveDown() { if (_size == _capacity) return; T *p = NULL; if (_size != 0) { p = new T[_size]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); } delete []_items; _items = p; _capacity = _size; } ~CRecordVector() { delete []_items; } void ClearAndFree() { delete []_items; _items = NULL; _size = 0; _capacity = 0; } void Clear() { _size = 0; } void DeleteBack() { _size--; } void DeleteFrom(unsigned index) { // if (index <= _size) _size = index; } void DeleteFrontal(unsigned num) { if (num != 0) { MoveItems(0, num); _size -= num; } } void Delete(unsigned index) { MoveItems(index, index + 1); _size -= 1; } /* void Delete(unsigned index, unsigned num) { if (num > 0) { MoveItems(index, index + num); _size -= num; } } */ CRecordVector& operator=(const CRecordVector &v) { unsigned size = v.Size(); if (size > _capacity) { delete []_items; _capacity = 0; _size = 0; _items = NULL; _items = new T[size]; _capacity = size; } _size = size; memcpy(_items, v._items, (size_t)size * (size_t)sizeof(T)); return *this; } CRecordVector& operator+=(const CRecordVector &v) { unsigned size = v.Size(); Reserve(_size + size); memcpy(_items + _size, v._items, (size_t)size * (size_t)sizeof(T)); _size += size; return *this; } unsigned Add(const T item) { ReserveOnePosition(); _items[_size] = item; return _size++; } void AddInReserved(const T item) { _items[_size++] = item; } void Insert(unsigned index, const T item) { ReserveOnePosition(); MoveItems(index + 1, index); _items[index] = item; _size++; } void MoveToFront(unsigned index) { if (index != 0) { T temp = _items[index]; memmove(_items + 1, _items, (size_t)index * (size_t)sizeof(T)); _items[0] = temp; } } const T& operator[](unsigned index) const { return _items[index]; } T& operator[](unsigned index) { return _items[index]; } const T& Front() const { return _items[0]; } T& Front() { return _items[0]; } const T& Back() const { return _items[_size - 1]; } T& Back() { return _items[_size - 1]; } /* void Swap(unsigned i, unsigned j) { T temp = _items[i]; _items[i] = _items[j]; _items[j] = temp; } */ int FindInSorted(const T item, unsigned left, unsigned right) const { while (left != right) { unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return mid; if (item < midVal) right = mid; else left = mid + 1; } return -1; } int FindInSorted2(const T &item, unsigned left, unsigned right) const { while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } return -1; } int FindInSorted(const T item) const { return FindInSorted(item, 0, _size); } int FindInSorted2(const T &item) const { return FindInSorted2(item, 0, _size); } unsigned AddToUniqueSorted(const T item) { unsigned left = 0, right = _size; while (left != right) { unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return mid; if (item < midVal) right = mid; else left = mid + 1; } Insert(right, item); return right; } unsigned AddToUniqueSorted2(const T &item) { unsigned left = 0, right = _size; while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param) { T temp = p[k]; for (;;) { unsigned s = (k << 1); if (s > size) break; if (s < size && compare(p + s + 1, p + s, param) > 0) s++; if (compare(&temp, p + s, param) >= 0) break; p[k] = p[s]; k = s; } p[k] = temp; } void Sort(int (*compare)(const T*, const T*, void *), void *param) { unsigned size = _size; if (size <= 1) return; T* p = (&Front()) - 1; { unsigned i = size >> 1; do SortRefDown(p, i, size, compare, param); while (--i != 0); } do { T temp = p[size]; p[size--] = p[1]; p[1] = temp; SortRefDown(p, 1, size, compare, param); } while (size > 1); } static void SortRefDown2(T* p, unsigned k, unsigned size) { T temp = p[k]; for (;;) { unsigned s = (k << 1); if (s > size) break; if (s < size && p[s + 1].Compare(p[s]) > 0) s++; if (temp.Compare(p[s]) >= 0) break; p[k] = p[s]; k = s; } p[k] = temp; } void Sort2() { unsigned size = _size; if (size <= 1) return; T* p = (&Front()) - 1; { unsigned i = size >> 1; do SortRefDown2(p, i, size); while (--i != 0); } do { T temp = p[size]; p[size--] = p[1]; p[1] = temp; SortRefDown2(p, 1, size); } while (size > 1); } }; typedef CRecordVector CIntVector; typedef CRecordVector CUIntVector; typedef CRecordVector CBoolVector; typedef CRecordVector CByteVector; typedef CRecordVector CPointerVector; template class CObjectVector { CPointerVector _v; public: unsigned Size() const { return _v.Size(); } bool IsEmpty() const { return _v.IsEmpty(); } void ReserveDown() { _v.ReserveDown(); } // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); } void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); } CObjectVector() {}; CObjectVector(const CObjectVector &v) { unsigned size = v.Size(); _v.ConstructReserve(size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); } CObjectVector& operator=(const CObjectVector &v) { Clear(); unsigned size = v.Size(); _v.Reserve(size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); return *this; } CObjectVector& operator+=(const CObjectVector &v) { unsigned size = v.Size(); _v.Reserve(Size() + size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); return *this; } const T& operator[](unsigned index) const { return *((T *)_v[index]); } T& operator[](unsigned index) { return *((T *)_v[index]); } const T& Front() const { return operator[](0); } T& Front() { return operator[](0); } const T& Back() const { return operator[](_v.Size() - 1); } T& Back() { return operator[](_v.Size() - 1); } void MoveToFront(unsigned index) { _v.MoveToFront(index); } unsigned Add(const T& item) { return _v.Add(new T(item)); } void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); } T& AddNew() { T *p = new T; _v.Add(p); return *p; } T& AddNewInReserved() { T *p = new T; _v.AddInReserved(p); return *p; } void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); } T& InsertNew(unsigned index) { T *p = new T; _v.Insert(index, p); return *p; } ~CObjectVector() { for (unsigned i = _v.Size(); i != 0;) delete (T *)_v[--i]; } void ClearAndFree() { Clear(); _v.ClearAndFree(); } void Clear() { for (unsigned i = _v.Size(); i != 0;) delete (T *)_v[--i]; _v.Clear(); } void DeleteFrom(unsigned index) { unsigned size = _v.Size(); for (unsigned i = index; i < size; i++) delete (T *)_v[i]; _v.DeleteFrom(index); } void DeleteFrontal(unsigned num) { for (unsigned i = 0; i < num; i++) delete (T *)_v[i]; _v.DeleteFrontal(num); } void DeleteBack() { delete (T *)_v[_v.Size() - 1]; _v.DeleteBack(); } void Delete(unsigned index) { delete (T *)_v[index]; _v.Delete(index); } /* void Delete(unsigned index, unsigned num) { for (unsigned i = 0; i < num; i++) delete (T *)_v[index + i]; _v.Delete(index, num); } */ /* int Find(const T& item) const { unsigned size = Size(); for (unsigned i = 0; i < size; i++) if (item == (*this)[i]) return i; return -1; } */ int FindInSorted(const T& item) const { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } return -1; } unsigned AddToUniqueSorted(const T& item) { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } /* unsigned AddToSorted(const T& item) { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) { right = mid + 1; break; } if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } */ void Sort(int (*compare)(void *const *, void *const *, void *), void *param) { _v.Sort(compare, param); } static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */) { return (*(*((const T **)a1))).Compare(*(*((const T **)a2))); } void Sort() { _v.Sort(CompareObjectItems, 0); } }; #define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++) #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyWindows.cpp0100777000000000000000000000573713761647206023026 0ustar00// MyWindows.cpp #include "StdAfx.h" #ifndef _WIN32 #include "MyWindows.h" #include "MyTypes.h" #include /* FIXED */ static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } static inline void FreeForBSTR(void *pv) { ::free(pv);} static UINT MyStringLen(const wchar_t *s) { UINT i; for (i = 0; s[i] != '\0'; i++); return i; } BSTR SysAllocStringByteLen(LPCSTR psz, UINT len) { // FIXED int realLen = len + sizeof(UINT) + 3; const int LEN_ADDON = sizeof(wchar_t) - 1; int realLen = len + sizeof(UINT) + sizeof(wchar_t) + LEN_ADDON; void *p = AllocateForBSTR(realLen); if (p == 0) return 0; *(UINT *)p = len; // "void *" instead of "BSTR" to avoid unaligned copy of "wchar_t" because of optimizer on Solaris void * bstr = (void *)((UINT *)p + 1); if (psz) memmove(bstr, psz, len); // psz does not always have "wchar_t" alignment. void *pb = (void *)(((Byte *)bstr) + len); memset(pb,0,sizeof(wchar_t) + LEN_ADDON); return (BSTR)bstr; } BSTR WINAPI SysAllocStringLen(const OLECHAR *sz, unsigned int numChars) // FIXME - code { UINT len = (numChars + 1) * sizeof(OLECHAR); void *p = AllocateForBSTR(len + sizeof(UINT)); if (p == 0) return 0; memset(p,0,len + sizeof(UINT)); *(UINT *)p = numChars * sizeof(OLECHAR); // FIXED void * bstr = (void *)((UINT *)p + 1); if (sz) memmove(bstr, sz, numChars * sizeof(OLECHAR)); // sz does not always have "wchar_t" alignment. return (BSTR)bstr; } BSTR SysAllocString(const OLECHAR *sz) { if (sz == 0) return 0; UINT strLen = MyStringLen(sz); UINT len = (strLen + 1) * sizeof(OLECHAR); void *p = AllocateForBSTR(len + sizeof(UINT)); if (p == 0) return 0; *(UINT *)p = strLen * sizeof(OLECHAR); // FIXED void * bstr = (void *)((UINT *)p + 1); memmove(bstr, sz, len); // sz does not always have "wchar_t" alignment. return (BSTR)bstr; } void SysFreeString(BSTR bstr) { if (bstr != 0) FreeForBSTR((UINT *)bstr - 1); } UINT SysStringByteLen(BSTR bstr) { if (bstr == 0) return 0; return *((UINT *)bstr - 1); } UINT SysStringLen(BSTR bstr) { return SysStringByteLen(bstr) / sizeof(OLECHAR); } HRESULT VariantClear(VARIANTARG *prop) { if (prop->vt == VT_BSTR) SysFreeString(prop->bstrVal); prop->vt = VT_EMPTY; return S_OK; } HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src) { HRESULT res = ::VariantClear(dest); if (res != S_OK) return res; if (src->vt == VT_BSTR) { dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, SysStringByteLen(src->bstrVal)); if (dest->bstrVal == 0) return E_OUTOFMEMORY; dest->vt = VT_BSTR; } else *dest = *src; return S_OK; } LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) { if(ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; if(ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; if(ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; if(ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; return 0; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/MyWindows.h0100777000000000000000000001106113761647206022456 0ustar00// MyWindows.h #ifndef __MYWINDOWS_H #define __MYWINDOWS_H #ifdef _WIN32 #include #else #include // for wchar_t #include #include "MyGuidDef.h" typedef char CHAR; typedef unsigned char UCHAR; #undef BYTE typedef unsigned char BYTE; typedef short SHORT; typedef unsigned short USHORT; #undef WORD typedef unsigned short WORD; typedef short VARIANT_BOOL; typedef int INT; typedef Int32 INT32; typedef unsigned int UINT; typedef UInt32 UINT32; typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit typedef UINT32 ULONG; #undef DWORD typedef UINT32 DWORD; typedef Int64 LONGLONG; typedef UInt64 ULONGLONG; typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; }; struct { DWORD LowPart; LONG HighPart; } u; LONGLONG QuadPart; } LARGE_INTEGER; typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER; typedef const CHAR *LPCSTR; typedef wchar_t WCHAR; #ifdef _UNICODE typedef WCHAR TCHAR; #define lstrcpy wcscpy #define lstrcat wcscat #define lstrlen wcslen #else typedef CHAR TCHAR; #define lstrcpy strcpy #define lstrcat strcat #define lstrlen strlen #endif #define _wcsicmp(str1,str2) MyStringCompareNoCase(str1,str2) typedef const TCHAR *LPCTSTR; typedef WCHAR OLECHAR; typedef const WCHAR *LPCWSTR; typedef OLECHAR *BSTR; typedef const OLECHAR *LPCOLESTR; typedef OLECHAR *LPOLESTR; typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; }FILETIME; #define HRESULT LONG #define FAILED(Status) ((HRESULT)(Status)<0) typedef ULONG PROPID; typedef LONG SCODE; #define S_OK ((HRESULT)0x00000000L) #define S_FALSE ((HRESULT)0x00000001L) #define E_NOTIMPL ((HRESULT)0x80004001L) #define E_NOINTERFACE ((HRESULT)0x80004002L) #define E_ABORT ((HRESULT)0x80004004L) #define E_FAIL ((HRESULT)0x80004005L) #define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) #define E_OUTOFMEMORY ((HRESULT)0x8007000EL) #define E_INVALIDARG ((HRESULT)0x80070057L) #ifdef _MSC_VER #define STDMETHODCALLTYPE __stdcall #else #define STDMETHODCALLTYPE #endif #define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f #define STDMETHOD(f) STDMETHOD_(HRESULT, f) #define STDMETHODIMP_(type) type STDMETHODCALLTYPE #define STDMETHODIMP STDMETHODIMP_(HRESULT) #define PURE = 0 #define MIDL_INTERFACE(x) struct #ifdef __cplusplus DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); struct IUnknown { STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE; STDMETHOD_(ULONG, AddRef)() PURE; STDMETHOD_(ULONG, Release)() PURE; #ifndef _WIN32 virtual ~IUnknown() {} #endif }; typedef IUnknown *LPUNKNOWN; #endif #define VARIANT_TRUE ((VARIANT_BOOL)-1) #define VARIANT_FALSE ((VARIANT_BOOL)0) enum VARENUM { VT_EMPTY = 0, VT_NULL = 1, VT_I2 = 2, VT_I4 = 3, VT_R4 = 4, VT_R8 = 5, VT_CY = 6, VT_DATE = 7, VT_BSTR = 8, VT_DISPATCH = 9, VT_ERROR = 10, VT_BOOL = 11, VT_VARIANT = 12, VT_UNKNOWN = 13, VT_DECIMAL = 14, VT_I1 = 16, VT_UI1 = 17, VT_UI2 = 18, VT_UI4 = 19, VT_I8 = 20, VT_UI8 = 21, VT_INT = 22, VT_UINT = 23, VT_VOID = 24, VT_HRESULT = 25, VT_FILETIME = 64 }; typedef unsigned short VARTYPE; typedef WORD PROPVAR_PAD1; typedef WORD PROPVAR_PAD2; typedef WORD PROPVAR_PAD3; #ifdef __cplusplus typedef struct tagPROPVARIANT { VARTYPE vt; PROPVAR_PAD1 wReserved1; PROPVAR_PAD2 wReserved2; PROPVAR_PAD3 wReserved3; union { CHAR cVal; UCHAR bVal; SHORT iVal; USHORT uiVal; LONG lVal; ULONG ulVal; INT intVal; UINT uintVal; LARGE_INTEGER hVal; ULARGE_INTEGER uhVal; VARIANT_BOOL boolVal; SCODE scode; FILETIME filetime; BSTR bstrVal; }; } PROPVARIANT; typedef PROPVARIANT tagVARIANT; typedef tagVARIANT VARIANT; typedef VARIANT VARIANTARG; #define MY_EXTERN_C extern "C" MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop); MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src); #else #define MY_EXTERN_C extern #endif MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); MY_EXTERN_C BSTR SysAllocStringLen(const OLECHAR*,UINT); MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz); MY_EXTERN_C void SysFreeString(BSTR bstr); MY_EXTERN_C UINT SysStringByteLen(BSTR bstr); MY_EXTERN_C UINT SysStringLen(BSTR bstr); /* MY_EXTERN_C DWORD GetLastError(); */ MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); #define CP_ACP 0 #define CP_OEMCP 1 typedef enum tagSTREAM_SEEK { STREAM_SEEK_SET = 0, STREAM_SEEK_CUR = 1, STREAM_SEEK_END = 2 } STREAM_SEEK; #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/NewHandler.cpp0100777000000000000000000000075213761647206023105 0ustar00// NewHandler.cpp #include "StdAfx.h" #include "../../C/Alloc.h" /* An overload function for the C++ new */ void * operator new(size_t size) { return MyAlloc(size); } /* An overload function for the C++ new[] */ void * operator new[](size_t size) { return MyAlloc(size); } /* An overload function for the C++ delete */ void operator delete(void *pnt) { MyFree(pnt); } /* An overload function for the C++ delete[] */ void operator delete[](void *pnt) { MyFree(pnt); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/NewHandler.h0100777000000000000000000000304013761647206022543 0ustar00// Common/NewHandler.h #ifndef __COMMON_NEW_HANDLER_H #define __COMMON_NEW_HANDLER_H /* This file must be included before any code that uses operators "delete" or "new". Also you must compile and link "NewHandler.cpp", if you use MSVC 6.0. The operator "new" in MSVC 6.0 doesn't throw exception "bad_alloc". So we define another version of operator "new" that throws "CNewException" on failure. If you use compiler that throws exception in "new" operator (GCC or new version of MSVC), you can compile without "NewHandler.cpp". So standard exception "bad_alloc" will be used. It's still allowed to use redefined version of operator "new" from "NewHandler.cpp" with any compiler. 7-Zip's code can work with "bad_alloc" and "CNewException" exceptions. But if you use some additional code (outside of 7-Zip's code), you must check that redefined version of operator "new" (that throws CNewException) is not problem for your code. Also we declare delete(void *p) throw() that creates smaller code. */ class CNewException {}; #ifdef WIN32 // We can compile my_new and my_delete with _fastcall /* void * my_new(size_t size); void my_delete(void *p) throw(); // void * my_Realloc(void *p, size_t newSize, size_t oldSize); */ #endif #ifdef _WIN32 void * #ifdef _MSC_VER __cdecl #endif operator new(size_t size); void #ifdef _MSC_VER __cdecl #endif operator delete(void *p) throw(); #endif /* #ifdef _WIN32 void * #ifdef _MSC_VER __cdecl #endif operator new[](size_t size); void #ifdef _MSC_VER __cdecl #endif operator delete[](void *p) throw(); #endif */ #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StdOutStream.cpp0100777000000000000000000000421513761647206023452 0ustar00// Common/StdOutStream.cpp #include "StdAfx.h" #include #include "IntToString.h" #include "StdOutStream.h" #include "StringConvert.h" #include "UTFConvert.h" static const char kNewLineChar = '\n'; static const char *kFileOpenMode = "wt"; extern int g_CodePage; CStdOutStream g_StdOut(stdout); CStdOutStream g_StdErr(stderr); bool CStdOutStream::Open(const char *fileName) throw() { Close(); _stream = fopen(fileName, kFileOpenMode); _streamIsOpen = (_stream != 0); return _streamIsOpen; } bool CStdOutStream::Close() throw() { if (!_streamIsOpen) return true; if (fclose(_stream) != 0) return false; _stream = 0; _streamIsOpen = false; return true; } bool CStdOutStream::Flush() throw() { return (fflush(_stream) == 0); } CStdOutStream & endl(CStdOutStream & outStream) throw() { return outStream << kNewLineChar; } CStdOutStream & CStdOutStream::operator<<(const wchar_t *s) { int codePage = g_CodePage; if (codePage == -1) codePage = CP_OEMCP; AString dest; if (codePage == CP_UTF8) ConvertUnicodeToUTF8(s, dest); else UnicodeStringToMultiByte2(dest, s, (UINT)codePage); return operator<<((const char *)dest); } void StdOut_Convert_UString_to_AString(const UString &s, AString &temp) { int codePage = g_CodePage; if (codePage == -1) codePage = CP_OEMCP; if (codePage == CP_UTF8) ConvertUnicodeToUTF8(s, temp); else UnicodeStringToMultiByte2(temp, s, (UINT)codePage); } void CStdOutStream::PrintUString(const UString &s, AString &temp) { StdOut_Convert_UString_to_AString(s, temp); *this << (const char *)temp; } CStdOutStream & CStdOutStream::operator<<(Int32 number) throw() { char s[32]; ConvertInt64ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(Int64 number) throw() { char s[32]; ConvertInt64ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw() { char s[16]; ConvertUInt32ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw() { char s[32]; ConvertUInt64ToString(number, s); return operator<<(s); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StdOutStream.h0100777000000000000000000000273613761647206023125 0ustar00// Common/StdOutStream.h #ifndef __COMMON_STD_OUT_STREAM_H #define __COMMON_STD_OUT_STREAM_H #include #include "MyString.h" #include "MyTypes.h" class CStdOutStream { FILE *_stream; bool _streamIsOpen; public: CStdOutStream(): _stream(0), _streamIsOpen(false) {}; CStdOutStream(FILE *stream): _stream(stream), _streamIsOpen(false) {}; ~CStdOutStream() { Close(); } // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; } // bool IsDefined() const { return _stream != NULL; } operator FILE *() { return _stream; } bool Open(const char *fileName) throw(); bool Close() throw(); bool Flush() throw(); CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &)) { (*func)(*this); return *this; } CStdOutStream & operator<<(const char *s) throw() { fputs(s, _stream); return *this; } CStdOutStream & operator<<(char c) throw() { fputc(c, _stream); return *this; } CStdOutStream & operator<<(Int32 number) throw(); CStdOutStream & operator<<(Int64 number) throw(); CStdOutStream & operator<<(UInt32 number) throw(); CStdOutStream & operator<<(UInt64 number) throw(); CStdOutStream & operator<<(const wchar_t *s); void PrintUString(const UString &s, AString &temp); }; CStdOutStream & endl(CStdOutStream & outStream) throw(); extern CStdOutStream g_StdOut; extern CStdOutStream g_StdErr; void StdOut_Convert_UString_to_AString(const UString &s, AString &temp); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StringConvert.cpp0100777000000000000000000001241513761647206023664 0ustar00// Common/StringConvert.cpp #include "StdAfx.h" #include "StringConvert.h" extern "C" { int global_use_utf16_conversion = 0; } #ifdef LOCALE_IS_UTF8 #ifdef __APPLE_CC__ #define UInt32 macUIn32 #include #undef UInt32 UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) { if (!srcString.IsEmpty()) { UString resultString; const char * path = &srcString[0]; // FIXME size_t n = strlen(path); CFStringRef cfpath = CFStringCreateWithCString(NULL,path,kCFStringEncodingUTF8); if (cfpath) { CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath); CFRelease(cfpath); CFStringNormalize(cfpath2,kCFStringNormalizationFormC); size_t n = CFStringGetLength(cfpath2); for(size_t i = 0 ; i< n ;i++) { resultString += CFStringGetCharacterAtIndex(cfpath2,i); } CFRelease(cfpath2); return resultString; } } UString resultString; for (int i = 0; i < srcString.Len(); i++) resultString += wchar_t(srcString[i] & 255); return resultString; } AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) { if (!srcString.IsEmpty()) { const wchar_t * wcs = &srcString[0]; char utf8[4096]; UniChar unipath[4096]; size_t n = wcslen(wcs); for(size_t i = 0 ; i<= n ;i++) { unipath[i] = wcs[i]; } CFStringRef cfpath = CFStringCreateWithCharacters(NULL,unipath,n); CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath); CFRelease(cfpath); CFStringNormalize(cfpath2,kCFStringNormalizationFormD); CFStringGetCString(cfpath2,(char *)utf8,4096,kCFStringEncodingUTF8); CFRelease(cfpath2); return AString(utf8); } AString resultString; for (int i = 0; i < srcString.Len(); i++) { if (srcString[i] >= 256) resultString += '?'; else resultString += char(srcString[i]); } return resultString; } #else /* __APPLE_CC__ */ #include "UTFConvert.h" UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) { if ((global_use_utf16_conversion) && (!srcString.IsEmpty())) { UString resultString; bool bret = ConvertUTF8ToUnicode(srcString,resultString); if (bret) return resultString; } UString resultString; for (int i = 0; i < srcString.Len(); i++) resultString += wchar_t(srcString[i] & 255); return resultString; } AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) { if ((global_use_utf16_conversion) && (!srcString.IsEmpty())) { AString resultString; bool bret = ConvertUnicodeToUTF8(srcString,resultString); if (bret) return resultString; } AString resultString; for (int i = 0; i < srcString.Len(); i++) { if (srcString[i] >= 256) resultString += '?'; else resultString += char(srcString[i]); } return resultString; } #endif /* __APPLE_CC__ */ #else /* LOCALE_IS_UTF8 */ UString MultiByteToUnicodeString(const AString &srcString, UINT /* codePage */ ) { #ifdef ENV_HAVE_MBSTOWCS if ((global_use_utf16_conversion) && (!srcString.IsEmpty())) { UString resultString; int numChars = mbstowcs(resultString.GetBuffer(srcString.Len()),srcString,srcString.Len()+1); if (numChars >= 0) { resultString.ReleaseBuffer(numChars); #if WCHAR_MAX > 0xffff for (int i = numChars; i >= 0; i--) { if (resultString[i] > 0xffff) { wchar_t c = resultString[i] - 0x10000; resultString.Delete(i); resultString.Insert(i, ((c >> 10) & 0x3ff) + 0xd800); resultString.Insert(i + 1, (c & 0x3ff) + 0xdc00); numChars++; } } #endif return resultString; } } #endif UString resultString; for (int i = 0; i < srcString.Len(); i++) resultString += wchar_t(srcString[i] & 255); return resultString; } AString UnicodeStringToMultiByte(const UString &src, UINT /* codePage */ ) { #ifdef ENV_HAVE_WCSTOMBS #if WCHAR_MAX > 0xffff UString srcString(src); for (int i = 0; i < srcString.Len(); i++) { if ((0xd800 <= srcString[i] && srcString[i] <= 0xdbff) && ((i + 1) < srcString.Len()) && (0xdc00 <= srcString[i + 1] && srcString[i + 1] <= 0xdf00)) { wchar_t c = (((srcString[i] - 0xd800) << 10) | (srcString[i + 1] - 0xdc00)) + 0x10000; srcString.Delete(i, 2); srcString.Insert(i, c); } } #else UString &srcString = src; #endif if ((global_use_utf16_conversion) && (!srcString.IsEmpty())) { AString resultString; int numRequiredBytes = srcString.Len() * 6+1; int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes),srcString,numRequiredBytes); if (numChars >= 0) { resultString.ReleaseBuffer(numChars); return resultString; } } #endif AString resultString; for (int i = 0; i < srcString.Len(); i++) { if (srcString[i] >= 256) resultString += '?'; else resultString += char(srcString[i]); } return resultString; } #endif /* LOCALE_IS_UTF8 */ void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage) { dest = MultiByteToUnicodeString(srcString,codePage); } void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage) { dest = UnicodeStringToMultiByte(srcString,codePage); } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StringConvert.h0100777000000000000000000000653713761647206023341 0ustar00// Common/StringConvert.h #ifndef __COMMON_STRING_CONVERT_H #define __COMMON_STRING_CONVERT_H #include "MyString.h" #include "MyWindows.h" UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP); // optimized versions that work faster for ASCII strings void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage = CP_ACP); void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed); void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage); AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage, char defaultChar, bool &defaultCharWasUsed); AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP); inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString) { return unicodeString; } inline const UString& GetUnicodeString(const UString &unicodeString) { return unicodeString; } inline UString GetUnicodeString(const AString &ansiString) { return MultiByteToUnicodeString(ansiString); } inline UString GetUnicodeString(const AString &multiByteString, UINT codePage) { return MultiByteToUnicodeString(multiByteString, codePage); } inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT) { return unicodeString; } inline const UString& GetUnicodeString(const UString &unicodeString, UINT) { return unicodeString; } inline const char* GetAnsiString(const char* ansiString) { return ansiString; } inline const AString& GetAnsiString(const AString &ansiString) { return ansiString; } inline AString GetAnsiString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString); } inline const char* GetOemString(const char* oemString) { return oemString; } inline const AString& GetOemString(const AString &oemString) { return oemString; } inline AString GetOemString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); } #ifdef _UNICODE inline const wchar_t* GetSystemString(const wchar_t* unicodeString) { return unicodeString;} inline const UString& GetSystemString(const UString &unicodeString) { return unicodeString;} inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */) { return unicodeString;} inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */) { return unicodeString;} inline UString GetSystemString(const AString &multiByteString, UINT codePage) { return MultiByteToUnicodeString(multiByteString, codePage);} inline UString GetSystemString(const AString &multiByteString) { return MultiByteToUnicodeString(multiByteString);} #else inline const char* GetSystemString(const char *ansiString) { return ansiString; } inline const AString& GetSystemString(const AString &multiByteString, UINT) { return multiByteString; } inline const char * GetSystemString(const char *multiByteString, UINT) { return multiByteString; } inline AString GetSystemString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString); } inline AString GetSystemString(const UString &unicodeString, UINT codePage) { return UnicodeStringToMultiByte(unicodeString, codePage); } #endif #ifndef UNDER_CE AString SystemStringToOemString(const CSysString &srcString); #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StringToInt.cpp0100777000000000000000000000606113761647206023301 0ustar00// Common/StringToInt.cpp #include "StdAfx.h" #include "StringToInt.h" static const UInt32 k_UInt32_max = 0xFFFFFFFF; static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF); // static const UInt64 k_UInt64_max = (UInt64)(Int64)-1; #define CONVERT_STRING_TO_UINT_FUNC(uintType, charType) \ uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ if (end) *end = s; \ uintType res = 0; \ for (;; s++) { \ charType c = *s; \ if (c < '0' || c > '9') { if (end) *end = s; return res; } \ if (res > (k_ ## uintType ## _max) / 10) return 0; \ res *= 10; \ unsigned v = (c - '0'); \ if (res > (k_ ## uintType ## _max) - v) return 0; \ res += v; }} CONVERT_STRING_TO_UINT_FUNC(UInt32, char) CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t) CONVERT_STRING_TO_UINT_FUNC(UInt64, char) CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t) Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() { if (end) *end = s; const wchar_t *s2 = s; if (*s == '-') s2++; if (*s2 == 0) return 0; const wchar_t *end2; UInt32 res = ConvertStringToUInt32(s2, &end2); if (*s == '-') { if (res > ((UInt32)1 << (32 - 1))) return 0; } else if ((res & ((UInt32)1 << (32 - 1))) != 0) return 0; if (end) *end = end2; if (*s == '-') return -(Int32)res; return (Int32)res; } UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw() { if (end) *end = s; UInt32 res = 0; for (;; s++) { char c = *s; if (c < '0' || c > '7') { if (end) *end = s; return res; } if ((res & (UInt32)7 << (32 - 3)) != 0) return 0; res <<= 3; res |= (unsigned)(c - '0'); } } UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw() { if (end) *end = s; UInt64 res = 0; for (;; s++) { char c = *s; if (c < '0' || c > '7') { if (end) *end = s; return res; } if ((res & (UInt64)7 << (64 - 3)) != 0) return 0; res <<= 3; res |= (unsigned)(c - '0'); } } UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw() { if (end) *end = s; UInt32 res = 0; for (;; s++) { char c = *s; unsigned v; if (c >= '0' && c <= '9') v = (c - '0'); else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); else { if (end) *end = s; return res; } if ((res & (UInt32)0xF << (32 - 4)) != 0) return 0; res <<= 4; res |= v; } } UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw() { if (end) *end = s; UInt64 res = 0; for (;; s++) { char c = *s; unsigned v; if (c >= '0' && c <= '9') v = (c - '0'); else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); else { if (end) *end = s; return res; } if ((res & (UInt64)0xF << (64 - 4)) != 0) return 0; res <<= 4; res |= v; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/StringToInt.h0100777000000000000000000000143013761647206022741 0ustar00// Common/StringToInt.h #ifndef __COMMON_STRING_TO_INT_H #define __COMMON_STRING_TO_INT_H #include "MyTypes.h" UInt32 ConvertStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertStringToUInt64(const char *s, const char **end) throw(); UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw(); UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/UTFConvert.cpp0100777000000000000000000000724413761647206023060 0ustar00// UTFConvert.cpp #include "StdAfx.h" #include "MyTypes.h" #include "UTFConvert.h" static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; bool CheckUTF8(const char *src) throw() { for (;;) { Byte c; unsigned numAdds; c = *src++; if (c == 0) return true; if (c < 0x80) continue; if (c < 0xC0) return false; for (numAdds = 1; numAdds < 5; numAdds++) if (c < kUtf8Limits[numAdds]) break; UInt32 value = (c - kUtf8Limits[numAdds - 1]); do { Byte c2 = *src++; if (c2 < 0x80 || c2 >= 0xC0) return false; value <<= 6; value |= (c2 - 0x80); } while (--numAdds); if (value >= 0x110000) return false; } } static Bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, size_t srcLen) throw() { size_t destPos = 0, srcPos = 0; for (;;) { Byte c; unsigned numAdds; if (srcPos == srcLen) { *destLen = destPos; return True; } c = (Byte)src[srcPos++]; if (c < 0x80) { if (dest) dest[destPos] = (wchar_t)c; destPos++; continue; } if (c < 0xC0) break; for (numAdds = 1; numAdds < 5; numAdds++) if (c < kUtf8Limits[numAdds]) break; UInt32 value = (c - kUtf8Limits[numAdds - 1]); do { Byte c2; if (srcPos == srcLen) break; c2 = (Byte)src[srcPos++]; if (c2 < 0x80 || c2 >= 0xC0) break; value <<= 6; value |= (c2 - 0x80); } while (--numAdds); if (value < 0x10000) { if (dest) dest[destPos] = (wchar_t)value; destPos++; } else { value -= 0x10000; if (value >= 0x100000) break; if (dest) { dest[destPos + 0] = (wchar_t)(0xD800 + (value >> 10)); dest[destPos + 1] = (wchar_t)(0xDC00 + (value & 0x3FF)); } destPos += 2; } } *destLen = destPos; return False; } static Bool Utf16_To_Utf8(char *dest, size_t *destLen, const wchar_t *src, size_t srcLen) { size_t destPos = 0, srcPos = 0; for (;;) { unsigned numAdds; UInt32 value; if (srcPos == srcLen) { *destLen = destPos; return True; } value = src[srcPos++]; if (value < 0x80) { if (dest) dest[destPos] = (char)value; destPos++; continue; } if (value >= 0xD800 && value < 0xE000) { UInt32 c2; if (value >= 0xDC00 || srcPos == srcLen) break; c2 = src[srcPos++]; if (c2 < 0xDC00 || c2 >= 0xE000) break; value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; } for (numAdds = 1; numAdds < 5; numAdds++) if (value < (((UInt32)1) << (numAdds * 5 + 6))) break; if (dest) dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); destPos++; do { numAdds--; if (dest) dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); destPos++; } while (numAdds != 0); } *destLen = destPos; return False; } bool ConvertUTF8ToUnicode(const AString &src, UString &dest) { dest.Empty(); size_t destLen = 0; Utf8_To_Utf16(NULL, &destLen, src, src.Len()); Bool res = Utf8_To_Utf16(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len()); dest.ReleaseBuffer((unsigned)destLen); return res ? true : false; } bool ConvertUnicodeToUTF8(const UString &src, AString &dest) { dest.Empty(); size_t destLen = 0; Utf16_To_Utf8(NULL, &destLen, src, src.Len()); Bool res = Utf16_To_Utf8(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len()); dest.ReleaseBuffer((unsigned)destLen); return res ? true : false; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/UTFConvert.h0100777000000000000000000000047313761647206022522 0ustar00// Common/UTFConvert.h #ifndef __COMMON_UTF_CONVERT_H #define __COMMON_UTF_CONVERT_H #include "MyString.h" bool CheckUTF8(const char *src) throw(); bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString); bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString); #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/Wildcard.cpp0100777000000000000000000003312313761647206022605 0ustar00// Common/Wildcard.cpp #include "StdAfx.h" #include "Wildcard.h" bool g_CaseSensitive = #ifdef _WIN32 false; #else true; #endif bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) { if (g_CaseSensitive) { for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (MyCharUpper(c1) != MyCharUpper(c2)) return false; } } for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (c1 != c2) return false; } } int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW { if (g_CaseSensitive) return wcscmp(s1, s2); return MyStringCompareNoCase(s1, s2); } #ifndef USE_UNICODE_FSTRING int CompareFileNames(const char *s1, const char *s2) { if (g_CaseSensitive) return wcscmp(fs2us(s1), fs2us(s2)); return MyStringCompareNoCase(fs2us(s1), fs2us(s2)); } #endif // ----------------------------------------- // this function compares name with mask // ? - any char // * - any char or empty static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) { for (;;) { wchar_t m = *mask; wchar_t c = *name; if (m == 0) return (c == 0); if (m == '*') { if (EnhancedMaskTest(mask + 1, name)) return true; if (c == 0) return false; } else { if (m == '?') { if (c == 0) return false; } else if (m != c) if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) return false; mask++; } name++; } } // -------------------------------------------------- // Splits path to strings void SplitPathToParts(const UString &path, UStringVector &pathParts) { pathParts.Clear(); unsigned len = path.Len(); if (len == 0) return; UString name; unsigned prev = 0; for (unsigned i = 0; i < len; i++) if (IsCharDirLimiter(path[i])) { name.SetFrom(path.Ptr(prev), i - prev); pathParts.Add(name); prev = i + 1; } name.SetFrom(path.Ptr(prev), len - prev); pathParts.Add(name); } void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; dirPrefix.SetFrom(path, (unsigned)(p - start)); name = p; } void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); if (p != start) { if (IsCharDirLimiter(*(p - 1))) p--; for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; } dirPrefix.SetFrom(path, (unsigned)(p - start)); name = p; } UString ExtractDirPrefixFromPath(const UString &path) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; return path.Left((unsigned)(p - start)); } UString ExtractFileNameFromPath(const UString &path) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; return p; } bool DoesWildcardMatchName(const UString &mask, const UString &name) { return EnhancedMaskTest(mask, name); } bool DoesNameContainWildcard(const UString &path) { for (unsigned i = 0; i < path.Len(); i++) { wchar_t c = path[i]; if (c == '*' || c == '?') return true; } return false; } // ----------------------------------------------------------' // NWildcard namespace NWildcard { #ifdef _WIN32 bool IsDriveColonName(const wchar_t *s) { wchar_t c = s[0]; return c != 0 && s[1] == ':' && s[2] == 0 && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); } #endif /* M = MaskParts.Size(); N = TestNameParts.Size(); File Dir ForFile rec M<=N [N-M, N) - !ForDir nonrec M=N [0, M) - ForDir rec M 1) return true; } return false; } bool CCensorNode::AreThereIncludeItems() const { if (IncludeItems.Size() > 0) return true; FOR_VECTOR (i, SubNodes) if (SubNodes[i].AreThereIncludeItems()) return true; return false; } bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const { const CObjectVector &items = include ? IncludeItems : ExcludeItems; FOR_VECTOR (i, items) if (items[i].CheckPath(pathParts, isFile)) return true; return false; } bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const { if (CheckPathCurrent(false, pathParts, isFile)) { include = false; return true; } include = true; bool finded = CheckPathCurrent(true, pathParts, isFile); if (pathParts.Size() <= 1) return finded; int index = FindSubNode(pathParts.Front()); if (index >= 0) { UStringVector pathParts2 = pathParts; pathParts2.Delete(0); if (SubNodes[index].CheckPathVect(pathParts2, isFile, include)) return true; } return finded; } bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const { UStringVector pathParts; SplitPathToParts(path, pathParts); if (CheckPathVect(pathParts, isFile, include)) { if (!include || !isAltStream) return true; } if (isAltStream && !pathParts.IsEmpty()) { UString &back = pathParts.Back(); int pos = back.Find(L':'); if (pos > 0) { back.DeleteFrom(pos); return CheckPathVect(pathParts, isFile, include); } } return false; } bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const { bool include; if (CheckPath2(isAltStream, path, isFile, include)) return include; return false; } bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const { if (CheckPathCurrent(include, pathParts, isFile)) return true; if (Parent == 0) return false; pathParts.Insert(0, Name); return Parent->CheckPathToRoot(include, pathParts, isFile); } /* bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const { UStringVector pathParts; SplitPathToParts(path, pathParts); return CheckPathToRoot(include, pathParts, isFile); } */ void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching) { if (path.IsEmpty()) return; bool forFile = true; bool forFolder = true; UString path2 = path; if (IsCharDirLimiter(path.Back())) { path2.DeleteBack(); forFile = false; } AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching); } void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) { ExcludeItems += fromNodes.ExcludeItems; FOR_VECTOR (i, fromNodes.SubNodes) { const CCensorNode &node = fromNodes.SubNodes[i]; int subNodeIndex = FindSubNode(node.Name); if (subNodeIndex < 0) subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this)); SubNodes[subNodeIndex].ExtendExclude(node); } } int CCensor::FindPrefix(const UString &prefix) const { FOR_VECTOR (i, Pairs) if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) return i; return -1; } void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching) { UStringVector pathParts; if (path.IsEmpty()) throw "Empty file path"; SplitPathToParts(path, pathParts); bool forFile = true; if (pathParts.Back().IsEmpty()) { forFile = false; pathParts.DeleteBack(); } UString prefix; if (pathMode != k_AbsPath) { const UString &front = pathParts.Front(); bool isAbs = false; if (front.IsEmpty()) isAbs = true; else { #ifdef _WIN32 if (IsDriveColonName(front)) isAbs = true; else #endif FOR_VECTOR (i, pathParts) { const UString &part = pathParts[i]; if (part == L".." || part == L".") { isAbs = true; break; } } } unsigned numAbsParts = 0; if (isAbs) if (pathParts.Size() > 1) numAbsParts = pathParts.Size() - 1; else numAbsParts = 1; #ifdef _WIN32 // \\?\ case if (numAbsParts >= 3) { if (pathParts[0].IsEmpty() && pathParts[1].IsEmpty() && pathParts[2] == L"?") { prefix = WSTRING_PATH_SEPARATOR WSTRING_PATH_SEPARATOR L"?" WSTRING_PATH_SEPARATOR; numAbsParts -= 3; pathParts.DeleteFrontal(3); } } #endif if (numAbsParts > 1 && pathMode == k_FullPath) numAbsParts = 1; // We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name // if (wildcardMatching) for (unsigned i = 0; i < numAbsParts; i++) { { const UString &front = pathParts.Front(); if (DoesNameContainWildcard(front)) break; prefix += front; prefix += WCHAR_PATH_SEPARATOR; } pathParts.Delete(0); } } int index = FindPrefix(prefix); if (index < 0) index = Pairs.Add(CPair(prefix)); CItem item; item.PathParts = pathParts; item.ForDir = true; item.ForFile = forFile; item.Recursive = recursive; item.WildcardMatching = wildcardMatching; Pairs[index].Head.AddItem(include, item); } bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const { bool finded = false; FOR_VECTOR (i, Pairs) { bool include; if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) { if (!include) return false; finded = true; } } return finded; } void CCensor::ExtendExclude() { unsigned i; for (i = 0; i < Pairs.Size(); i++) if (Pairs[i].Prefix.IsEmpty()) break; if (i == Pairs.Size()) return; unsigned index = i; for (i = 0; i < Pairs.Size(); i++) if (index != i) Pairs[i].Head.ExtendExclude(Pairs[index].Head); } void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) { FOR_VECTOR(i, CensorPaths) { const CCensorPath &cp = CensorPaths[i]; AddItem(censorPathMode, cp.Include, cp.Path, cp.Recursive, cp.WildcardMatching); } CensorPaths.Clear(); } void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching) { CCensorPath &cp = CensorPaths.AddNew(); cp.Path = path; cp.Include = include; cp.Recursive = recursive; cp.WildcardMatching = wildcardMatching; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Common/Wildcard.h0100777000000000000000000001015613761647206022253 0ustar00// Common/Wildcard.h #ifndef __COMMON_WILDCARD_H #define __COMMON_WILDCARD_H #include "MyString.h" int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW; #ifndef USE_UNICODE_FSTRING int CompareFileNames(const char *s1, const char *s2); #endif bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2); inline bool IsCharDirLimiter(wchar_t c) { return c == WCHAR_PATH_SEPARATOR #ifdef _WIN32 || c == L'/' #endif ; } void SplitPathToParts(const UString &path, UStringVector &pathParts); void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name); void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path) UString ExtractDirPrefixFromPath(const UString &path); UString ExtractFileNameFromPath(const UString &path); bool DoesNameContainWildcard(const UString &path); bool DoesWildcardMatchName(const UString &mask, const UString &name); namespace NWildcard { #ifdef _WIN32 // returns true, if name is like "a:", "c:", ... bool IsDriveColonName(const wchar_t *s); #endif struct CItem { UStringVector PathParts; bool Recursive; bool ForFile; bool ForDir; bool WildcardMatching; #ifdef _WIN32 bool IsDriveItem() const { return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]); } #endif // CItem(): WildcardMatching(true) {} bool AreAllAllowed() const; bool CheckPath(const UStringVector &pathParts, bool isFile) const; }; class CCensorNode { CCensorNode *Parent; bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; void AddItemSimple(bool include, CItem &item); bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const; public: CCensorNode(): Parent(0) { }; CCensorNode(const UString &name, CCensorNode *parent): Parent(parent), Name(name) { }; UString Name; // wildcard is not allowed here CObjectVector SubNodes; CObjectVector IncludeItems; CObjectVector ExcludeItems; bool AreAllAllowed() const; int FindSubNode(const UString &path) const; void AddItem(bool include, CItem &item); void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching); void AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching); bool NeedCheckSubDirs() const; bool AreThereIncludeItems() const; bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const; bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const; // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; void ExtendExclude(const CCensorNode &fromNodes); }; struct CPair { UString Prefix; CCensorNode Head; CPair(const UString &prefix): Prefix(prefix) { }; }; enum ECensorPathMode { k_RelatPath, // absolute prefix as Prefix, remain path in Tree k_FullPath, // drive prefix as Prefix, remain path in Tree k_AbsPath // full path in Tree }; struct CCensorPath { UString Path; bool Include; bool Recursive; bool WildcardMatching; CCensorPath(): Include(true), Recursive(false), WildcardMatching(true) {} }; class CCensor { int FindPrefix(const UString &prefix) const; public: CObjectVector Pairs; CObjectVector CensorPaths; bool AllAreRelative() const { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } void AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching); bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; void ExtendExclude(); void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); void AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching); void AddPreItem(const UString &path) { AddPreItem(true, path, false, false); } void AddPreItem_Wildcard() { AddPreItem(true, L"*", false, true); } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/include_windows/0040777000000000000000000000000013761647206022313 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/include_windows/basetyps.h0100777000000000000000000000054013761647206024315 0ustar00#ifndef _BASETYPS_H #define _BASETYPS_H #ifdef ENV_HAVE_GCCVISIBILITYPATCH #define DLLEXPORT __attribute__ ((visibility("default"))) #else #define DLLEXPORT #endif #ifdef __cplusplus #define STDAPI extern "C" DLLEXPORT HRESULT #else #define STDAPI extern DLLEXPORT HRESULT #endif /* __cplusplus */ typedef GUID IID; typedef GUID CLSID; #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/include_windows/include_windows.pri0100777000000000000000000000022413761647206026222 0ustar00HEADERS += $$7ZIP_BASE/CPP/include_windows/basetyps.h \ $$7ZIP_BASE/CPP/include_windows/tchar.h \ $$7ZIP_BASE/CPP/include_windows/windows.h qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/include_windows/tchar.h0100777000000000000000000000427213761647206023572 0ustar00/* * tchar.h * * Unicode mapping layer for the standard C library. By including this * file and using the 't' names for string functions * (eg. _tprintf) you can make code which can be easily adapted to both * Unicode and non-unicode environments. In a unicode enabled compile define * _UNICODE before including tchar.h, otherwise the standard non-unicode * library functions will be used. * * Note that you still need to include string.h or stdlib.h etc. to define * the appropriate functions. Also note that there are several defines * included for non-ANSI functions which are commonly available (but using * the convention of prepending an underscore to non-ANSI library function * names). * * This file is part of the Mingw32 package. * * Contributors: * Created by Colin Peters * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * $Revision: 1.11 $ * $Author: earnie $ * $Date: 2003/05/03 13:48:46 $ * */ #ifndef _TCHAR_H_ #define _TCHAR_H_ /* All the headers include this file. */ #ifndef __int64 #define __int64 long long #endif #ifndef __cdecl #define __cdecl /* */ #endif /* * NOTE: This tests _UNICODE, which is different from the UNICODE define * used to differentiate Win32 API calls. */ #ifdef _UNICODE /* * Use TCHAR instead of char or wchar_t. It will be appropriately translated * if _UNICODE is correctly defined (or not). */ #ifndef _TCHAR_DEFINED typedef wchar_t TCHAR; #define _TCHAR_DEFINED #endif /* * Unicode functions */ /* #define _tfopen _wfopen FILE *_wfopen( const wchar_t *filename, const wchar_t *mode ); */ #else /* Not _UNICODE */ #define _tfopen fopen /* * TCHAR, the type you should use instead of char. */ #ifndef _TCHAR_DEFINED typedef char TCHAR; #define _TCHAR_DEFINED #endif #endif /* Not _UNICODE */ #endif /* Not _TCHAR_H_ */ qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/include_windows/windows.h0100777000000000000000000001212013761647206024152 0ustar00/* windows.h - main header file for the Win32 API Written by Anders Norlander This file is part of a free library for the Win32 API. 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. */ #ifndef _WINDOWS_H #define _WINDOWS_H #include /* BEGIN #include */ #include "Common/MyWindows.h" // FIXED #ifndef CONST #define CONST const #endif #undef MAX_PATH #define MAX_PATH 4096 /* Linux : 4096 - Windows : 260 */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define WINAPI #undef BOOL typedef int BOOL; #define CREATE_NEW 1 #define CREATE_ALWAYS 2 #define OPEN_EXISTING 3 #define OPEN_ALWAYS 4 /* #define TRUNCATE_EXISTING 5 */ /* BEGIN #include */ /* BEGIN */ #define NO_ERROR 0L #define ERROR_ALREADY_EXISTS EEXIST #define ERROR_FILE_EXISTS EEXIST #define ERROR_INVALID_HANDLE EBADF #define ERROR_PATH_NOT_FOUND ENOENT #define ERROR_DISK_FULL ENOSPC #define ERROR_NO_MORE_FILES 0x100018 // FIXME #define ERROR_DIRECTORY 267 // FIXME // #define ERROR_NEGATIVE_SEEK 0x100131 // FIXME /* see Common/WyWindows.h #define S_OK ((HRESULT)0x00000000L) #define S_FALSE ((HRESULT)0x00000001L) #define E_INVALIDARG ((HRESULT)0x80070057L) #define E_NOTIMPL ((HRESULT)0x80004001L) #define E_NOINTERFACE ((HRESULT)0x80004002L) #define E_ABORT ((HRESULT)0x80004004L) #define E_FAIL ((HRESULT)0x80004005L) #define E_OUTOFMEMORY ((HRESULT)0x8007000EL) #define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) #define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) #define FAILED(Status) ((HRESULT)(Status)<0) */ #ifndef VOID #define VOID void #endif typedef void *PVOID,*LPVOID; typedef WCHAR *LPWSTR; typedef CHAR *LPSTR; typedef TCHAR *LPTSTR; #ifdef UNICODE /* * P7ZIP_TEXT is a private macro whose specific use is to force the expansion of a * macro passed as an argument to the macro TEXT. DO NOT use this * macro within your programs. It's name and function could change without * notice. */ #define P7ZIP_TEXT(q) L##q #else #define P7ZIP_TEXT(q) q #endif /* * UNICODE a constant string when UNICODE is defined, else returns the string * unmodified. * The corresponding macros _TEXT() and _T() for mapping _UNICODE strings * passed to C runtime functions are defined in mingw/tchar.h */ #define TEXT(q) P7ZIP_TEXT(q) typedef BYTE BOOLEAN; /* BEGIN #include */ #ifndef __int64 #define __int64 long long #endif typedef unsigned __int64 UINT64; typedef __int64 INT64; /* END #include */ #define FILE_ATTRIBUTE_READONLY 1 #define FILE_ATTRIBUTE_HIDDEN 2 #define FILE_ATTRIBUTE_SYSTEM 4 #define FILE_ATTRIBUTE_DIRECTORY 16 #define FILE_ATTRIBUTE_ARCHIVE 32 #define FILE_ATTRIBUTE_DEVICE 64 #define FILE_ATTRIBUTE_NORMAL 128 #define FILE_ATTRIBUTE_TEMPORARY 256 #define FILE_ATTRIBUTE_SPARSE_FILE 512 #define FILE_ATTRIBUTE_REPARSE_POINT 1024 #define FILE_ATTRIBUTE_COMPRESSED 2048 #define FILE_ATTRIBUTE_OFFLINE 0x1000 #define FILE_ATTRIBUTE_ENCRYPTED 0x4000 #define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ /* END */ #include #include /* END #include */ /* END #include */ /* BEGIN #include */ #define WAIT_OBJECT_0 0 #define INFINITE 0xFFFFFFFF typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME; #ifdef __cplusplus extern "C" { #endif BOOL WINAPI DosDateTimeToFileTime(WORD,WORD,FILETIME *); BOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *,WORD *, WORD *); BOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *,FILETIME *); BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *,SYSTEMTIME *); BOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *,FILETIME *); VOID WINAPI GetSystemTime(SYSTEMTIME *); BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME*,FILETIME *); VOID WINAPI GetSystemTimeAsFileTime(FILETIME * time); DWORD WINAPI GetTickCount(VOID); #ifdef __cplusplus } #endif /* END #include */ /* BEGIN #include */ #define CP_ACP 0 #define CP_OEMCP 1 #define CP_UTF8 65001 /* #include */ #include "basetyps.h" struct IEnumSTATPROPSTG; typedef struct tagSTATPROPSTG { const OLECHAR * lpwstrName; /* to avoid some warnings : LPOLESTR lpwstrName; */ PROPID propid; VARTYPE vt; } STATPROPSTG; #ifdef __cplusplus extern "C" const IID IID_ISequentialStream; struct ISequentialStream : public IUnknown { STDMETHOD(QueryInterface)(REFIID,PVOID*) PURE; STDMETHOD_(ULONG,AddRef)(void) PURE; STDMETHOD_(ULONG,Release)(void) PURE; STDMETHOD(Read)(void*,ULONG,ULONG*) PURE; STDMETHOD(Write)(void const*,ULONG,ULONG*) PURE; }; #else extern const IID IID_ISequentialStream; #endif /* __cplusplus */ /* END #include */ #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/0040777000000000000000000000000013761647206021116 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/config.h0100777000000000000000000000232113761647206022532 0ustar00 #if !defined(__DJGPP__) #ifndef __CYGWIN__ #define FILESYSTEM_IS_CASE_SENSITIVE 1 #endif #if !defined(ENV_MACOSX) && !defined(ENV_BEOS) /* */ /* ENV_HAVE_WCHAR__H and not ENV_HAVE_WCHAR_H to avoid warning with wxWidgets */ #define ENV_HAVE_WCHAR__H /* */ #define ENV_HAVE_WCTYPE_H /* mbrtowc */ /* #ifndef __hpux */ /* #define ENV_HAVE_MBRTOWC */ /* #endif */ /* towupper */ #define ENV_HAVE_TOWUPPER #endif /* !ENV_MACOSX && !ENV_BEOS */ #if !defined(ENV_BEOS) && !defined(ANDROID_NDK) #define ENV_HAVE_GETPASS #if !defined(sun) #define ENV_HAVE_TIMEGM #endif #endif /* lstat, readlink and S_ISLNK */ #define ENV_HAVE_LSTAT /* */ #define ENV_HAVE_LOCALE /* mbstowcs */ #define ENV_HAVE_MBSTOWCS /* wcstombs */ #define ENV_HAVE_WCSTOMBS #endif /* !__DJGPP__ */ #ifndef ENV_BEOS #define ENV_HAVE_PTHREAD #endif /* ANDROID don't have wcstombs or mbstowcs ? */ #if defined(ENV_MACOSX) || defined(ANDROID_NDK) #define LOCALE_IS_UTF8 #endif #ifdef LOCALE_IS_UTF8 #undef ENV_HAVE_LOCALE #undef ENV_HAVE_MBSTOWCS #undef ENV_HAVE_WCSTOMBS /* #undef ENV_HAVE_MBRTOWC */ #endif #define MAX_PATHNAME_LEN 1024 qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/initguid.h0100777000000000000000000000005713761647206023105 0ustar00// initguid.h #include "Common/MyInitGuid.h" qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/myCommandLineParser.cpp0100777000000000000000000000400213761647206025527 0ustar00/************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../CPP/Common/MyString.h" #include namespace NCommandLineParser { void SplitCommandLine(const UString &s, UStringVector &parts) { parts.Clear(); const QString cmdLine = QString::fromStdWString(static_cast(s)); const QStringList args = cmdLine.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); foreach (const QString &arg, args) parts.Add(arg.toStdWString().c_str()); } } // namespace NCommandLineParser qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp0100777000000000000000000001451413761647206024314 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "windows.h" #include #include /* MSDN description about FILETIME structure: The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). The DeltaToEpochInMsec can be calculated like this: \code quint64 delta = quint64(QDateTime(QDate(1601, 1, 1)).msecsTo(QDateTime(QDate(1970, 1, 1)))) * 10000ULL; \endcode But since the value is static, we use a precalculated number here. */ static const ULONGLONG DeltaToEpochInMsec = 116444736000000000ULL; inline void LocalDateTimeToFileTime(const QDateTime &dt, ULONGLONG utcOffsetInMsec, FILETIME *ft) { const ULONGLONG msec = dt.toMSecsSinceEpoch() + utcOffsetInMsec; const ULONGLONG nano100 = (msec * 10000ULL) + DeltaToEpochInMsec; ft->dwLowDateTime = nano100; ft->dwHighDateTime = nano100 >> 32; } inline void UTCDateTimeToSystemTime(const QDateTime &dt, SYSTEMTIME *st) { const QDate date = dt.date(); const QTime time = dt.time(); st->wYear = date.year(); st->wMonth = date.month(); st->wDayOfWeek = date.dayOfWeek(); st->wDay = date.day(); st->wHour = time.hour(); st->wMinute = time.minute(); st->wSecond = time.second(); st->wMilliseconds = time.msec(); } // -- WINAPI BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *source,SYSTEMTIME *target) { const QDateTime dt = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 1), Qt::UTC).addMSecs ((ULONGLONG(source->dwLowDateTime) + (ULONGLONG(source->dwHighDateTime) << 32)) / 10000ULL); UTCDateTimeToSystemTime(dt.toUTC(), target); return TRUE; } BOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *source,FILETIME *target) { const QDateTime dt = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 1), Qt::UTC).addMSecs ((ULONGLONG(source->dwLowDateTime) + (ULONGLONG(source->dwHighDateTime) << 32)) / 10000ULL); LocalDateTimeToFileTime(dt.toLocalTime(), ULONGLONG(QDateTime::currentDateTime() .offsetFromUtc()) * 1000ULL, target); return TRUE; } BOOLEAN WINAPI RtlTimeToSecondsSince1970(const LARGE_INTEGER *Time, DWORD *Seconds) { /* MSDN suggests to implement the function like this: 1. Call SystemTimeToFileTime to copy the system time to a FILETIME structure. Call GetSystemTime to get the current system time to pass to SystemTimeToFileTime. 2. Copy the contents of the FILETIME structure to a ULARGE_INTEGER structure. 3. Initialize a SYSTEMTIME structure with the date and time of the first second of January 1, 1970. 4. Call SystemTimeToFileTime, passing the SYSTEMTIME structure initialized in Step 3 to the call. 5. Copy the contents of the FILETIME structure returned by SystemTimeToFileTime in Step 4 to a second ULARGE_INTEGER. The copied value should be less than or equal to the value copied in Step 2. 6. Subtract the 64-bit value in the ULARGE_INTEGER structure initialized in Step 5 (January 1, 1970) from the 64-bit value of the ULARGE_INTEGER structure initialized in Step 2 (the current system time). This produces a value in 100-nanosecond intervals since January 1, 1970. To convert this value to seconds, divide by 10,000,000. We can omit step 1 and 2, cause we get the LARGE_INTEGER passed as function argument. */ SYSTEMTIME stFirstSecondOf1979; stFirstSecondOf1979.wSecond = 1; stFirstSecondOf1979.wMinute = 0; stFirstSecondOf1979.wHour = 0; stFirstSecondOf1979.wDay = 1; stFirstSecondOf1979.wMonth = 1; stFirstSecondOf1979.wYear = 1970; stFirstSecondOf1979.wDayOfWeek = 4; FILETIME ftFirstSecondOf1979; SystemTimeToFileTime(&stFirstSecondOf1979, &ftFirstSecondOf1979); LARGE_INTEGER liFirstSecondOf1979; liFirstSecondOf1979.LowPart = ftFirstSecondOf1979.dwLowDateTime; liFirstSecondOf1979.HighPart = ftFirstSecondOf1979.dwHighDateTime; const ULONGLONG diffNano100 = Time->QuadPart - liFirstSecondOf1979.QuadPart; *Seconds = diffNano100 / 10000000ULL; return TRUE; } void WINAPI RtlSecondsSince1970ToFileTime(DWORD Seconds, FILETIME *ft) { const ULONGLONG nano100 = (ULONGLONG(Seconds) * 10000000ULL) + DeltaToEpochInMsec; ft->dwLowDateTime = nano100; ft->dwHighDateTime = nano100 >> 32; } VOID WINAPI GetSystemTime(SYSTEMTIME *st) { UTCDateTimeToSystemTime(QDateTime::currentDateTimeUtc(), st); } VOID WINAPI GetSystemTimeAsFileTime(FILETIME *time) { SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, time); } DWORD WINAPI GetTickCount() { using namespace std::chrono; return duration_cast(steady_clock::now().time_since_epoch()).count(); } BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime, FILETIME *lpFileTime) { const QDateTime dt(QDate(lpSystemTime->wYear, lpSystemTime->wMonth, lpSystemTime->wDay), QTime(lpSystemTime->wHour, lpSystemTime->wMinute, lpSystemTime->wSecond, lpSystemTime->wMilliseconds), Qt::UTC); LocalDateTimeToFileTime(dt.toLocalTime(), 0ULL, lpFileTime); return TRUE; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/myPrivate.h0100777000000000000000000000065513761647206023255 0ustar00 void WINAPI RtlSecondsSince1970ToFileTime( DWORD Seconds, FILETIME * ft ); extern "C" int global_use_utf16_conversion; #ifdef ENV_HAVE_LSTAT extern "C" int global_use_lstat; #endif const char *my_getlocale(void); #ifdef NEED_NAME_WINDOWS_TO_UNIX static inline const char * nameWindowToUnix(const char * lpFileName) { if ((lpFileName[0] == 'c') && (lpFileName[1] == ':')) return lpFileName+2; return lpFileName; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/myWindows.pri0100777000000000000000000000043613761647206023635 0ustar00HEADERS += $$7ZIP_BASE/CPP/myWindows/StdAfx.h \ $$7ZIP_BASE/CPP/myWindows/config.h \ $$7ZIP_BASE/CPP/myWindows/initguid.h \ $$7ZIP_BASE/CPP/myWindows/myPrivate.h SOURCES += $$7ZIP_BASE/CPP/myWindows/myDateAndTime.cpp \ $$7ZIP_BASE/CPP/myWindows/myCommandLineParser.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/myWindows/StdAfx.h0100777000000000000000000001050613761647206022462 0ustar00// stdafx.h #ifndef __STDAFX_H #define __STDAFX_H #include "config.h" #define MAXIMUM_WAIT_OBJECTS 64 #define NO_INLINE /* FIXME */ #ifdef ENV_HAVE_PTHREAD #include #endif #include "Common/Common.h" #include "Common/MyWindows.h" #include "Common/MyTypes.h" #include "../include_windows/tchar.h" #include "../include_windows/windows.h" #include #include #include #include #include #include #include #include #include #ifdef __NETWARE__ #include #endif #undef CS /* fix for Solaris 10 x86 */ #ifdef __cplusplus # define EXTERN_C extern "C" #else # define EXTERN_C extern #endif /***************************/ #ifndef ENV_HAVE_WCHAR__H EXTERN_C_BEGIN size_t wcslen(const wchar_t *); wchar_t *wcscpy(wchar_t * , const wchar_t * ); wchar_t *wcscat(wchar_t * , const wchar_t * ); EXTERN_C_END #endif /***************************/ #define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L) /************************* LastError *************************/ inline DWORD WINAPI GetLastError(void) { return errno; } inline void WINAPI SetLastError( DWORD err ) { errno = err; } #define AreFileApisANSI() (1) void Sleep(unsigned millisleep); typedef pid_t t_processID; t_processID GetCurrentProcess(void); #define NORMAL_PRIORITY_CLASS (0) #define IDLE_PRIORITY_CLASS (10) void SetPriorityClass(t_processID , int priority); #ifdef __cplusplus class wxWindow; typedef wxWindow *HWND; #define MB_ICONERROR (0x00000200) // wxICON_ERROR #define MB_YESNOCANCEL (0x00000002 | 0x00000008 | 0x00000010) // wxYES | wxNO | wxCANCEL #define MB_ICONQUESTION (0x00000400) // wxICON_QUESTION #define MB_TASKMODAL (0) // FIXME #define MB_SYSTEMMODAL (0) // FIXME #define MB_OK (0x00000004) // wxOK #define MB_ICONSTOP (0x00000200) // wxICON_STOP #define MB_OKCANCEL (0x00000004 | 0x00000010) // wxOK | wxCANCEL #define MessageBox MessageBoxW int MessageBoxW(wxWindow * parent, const TCHAR * mes, const TCHAR * title,int flag); // FIXME #define IDCLOSE (5001) // wxID_CLOSE #define IDEXIT (5006) // wxID_EXIT #define IDOK (5100) // wxID_OK #define IDCANCEL (5101) // wxID_CANCEL #define IDABORT (5115) // wxID_ABORT #define IDYES (5103) // wxID_YES #define IDNO (5104) // wxID_NO #define IDHELP (5009) // wxID_HELP // Show #define SW_HIDE 0 #define SW_SHOW 5 typedef void *HINSTANCE; typedef int INT_PTR; // FIXME 64 bits ? typedef unsigned int UINT_PTR; // FIXME 64 bits ? typedef long LONG_PTR; // FIXME 64 bits ? typedef long DWORD_PTR; // FIXME 64 bits ? typedef UINT_PTR WPARAM; /* WARNING LPARAM shall be 'long' because of CListView::SortItems and wxListCtrl::SortItems : */ typedef LONG_PTR LPARAM; typedef LONG_PTR LRESULT; #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xFFFF)) #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) #define CALLBACK /* */ #define ERROR_NEGATIVE_SEEK 0x100131 // FIXME #define FACILITY_WIN32 7 // FIXME #define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) > 0 ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)) : (HRESULT)(x) ) // FIXME /************ Windows2.h ***********/ typedef void * WNDPROC; typedef void * CREATESTRUCT; typedef struct { HWND hwndFrom; UINT code; #define NM_DBLCLK 1 #define LVN_ITEMCHANGED 2 #define LVN_COLUMNCLICK 3 #define CBEN_BEGINEDIT 10 #define CBEN_ENDEDITW 11 } NMHDR; typedef NMHDR * LPNMHDR; typedef struct tagNMLISTVIEW { NMHDR hdr; INT iItem; INT iSubItem; UINT uNewState; UINT uOldState; // UINT uChanged; // POINT ptAction; LPARAM lParam; } NMLISTVIEW, *LPNMLISTVIEW; typedef void * LPNMITEMACTIVATE; #define NM_RCLICK 1234 /* FIXME */ // FIXME #define WM_CREATE 1 #define WM_COMMAND 2 #define WM_NOTIFY 3 #define WM_DESTROY 4 #define WM_CLOSE 5 #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xFFFF)) /************ LANG ***********/ typedef WORD LANGID; LANGID GetUserDefaultLangID(void); LANGID GetSystemDefaultLangID(void); #define PRIMARYLANGID(l) ((WORD)(l) & 0x3ff) #define SUBLANGID(l) ((WORD)(l) >> 10) #if defined( __x86_64__ ) #define _WIN64 1 #endif #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/0040777000000000000000000000000013761647206020550 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Defs.h0100777000000000000000000000101513761647206021577 0ustar00// Windows/Defs.h #ifndef __WINDOWS_DEFS_H #define __WINDOWS_DEFS_H #include "../myWindows/StdAfx.h" #include "../Common/MyWindows.h" // #ifdef _WIN32 inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } inline bool BOOLToBool(BOOL v) { return (v != FALSE); } inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } // #endif inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/DLL.cpp0100777000000000000000000001223113761647206021666 0ustar00// Windows/DLL.cpp #include "StdAfx.h" #ifdef __APPLE_CC__ #include #elif ENV_BEOS #include #include #else #define UINT64 DLL_UINT64 // HP-UX , dlfcn.h defines UINT64 but p7zip also defines UINT64 #include // dlopen ... #undef UINT64 #endif #include "DLL.h" #include "Defs.h" #ifdef _UNICODE #include "../Common/StringConvert.h" #endif #define NEED_NAME_WINDOWS_TO_UNIX #include "myPrivate.h" // #define TRACEN(u) u; #define TRACEN(u) /* */ namespace NWindows { namespace NDLL { bool CLibrary::Free() { TRACEN((printf("CLibrary::Free(this=%p,%p)\n",(void *)this,(void *)_module))) if (_module == 0) return true; #ifdef __APPLE_CC__ int ret = NSUnLinkModule ((NSModule)_module, 0); #elif ENV_BEOS int ret = unload_add_on((image_id)_module); #else int ret = dlclose(_module); #endif TRACEN((printf("CLibrary::Free dlclose(%p)=%d\n",(void *)_module,ret))) if (ret != 0) return false; _module = 0; return true; } static FARPROC local_GetProcAddress(HMODULE module,LPCSTR lpProcName) { void *ptr = 0; TRACEN((printf("local_GetProcAddress(%p,%s)\n",(void *)module,lpProcName))) if (module) { #ifdef __APPLE_CC__ char name[MAX_PATHNAME_LEN]; snprintf(name,sizeof(name),"_%s",lpProcName); name[sizeof(name)-1] = 0; TRACEN((printf("NSLookupSymbolInModule(%p,%s)\n",(void *)module,name))) NSSymbol sym; sym = NSLookupSymbolInModule((NSModule)module, name); if (sym) { ptr = NSAddressOfSymbol(sym); } else { ptr = 0; } #elif ENV_BEOS if (get_image_symbol((image_id)module, lpProcName, B_SYMBOL_TYPE_TEXT, &ptr) != B_OK) ptr = 0; #else ptr = dlsym (module, lpProcName); #endif TRACEN((printf("CLibrary::GetProc : dlsym(%p,%s)=%p\n",(void *)module,lpProcName,ptr))) } return (FARPROC)ptr; } FARPROC CLibrary::GetProc(LPCSTR lpProcName) const { TRACEN((printf("CLibrary::GetProc(%p,%s)\n",(void *)_module,lpProcName))) return local_GetProcAddress(_module,lpProcName); } bool CLibrary::Load(LPCTSTR lpLibFileName) { if(!Free()) return false; void *handler = 0; char name[MAX_PATHNAME_LEN+1]; #ifdef _UNICODE AString name2 = UnicodeStringToMultiByte(lpLibFileName); strcpy(name,nameWindowToUnix((const char *)name2)); #else strcpy(name,nameWindowToUnix(lpLibFileName)); #endif // replace ".dll" with ".so" size_t len = strlen(name); if ((len >=4) && (strcmp(name+len-4,".dll") == 0)) { strcpy(name+len-4,".so"); } TRACEN((printf("CLibrary::Load(this=%p,%ls) => %s\n",(void *)this,lpLibFileName,name))) #ifdef __APPLE_CC__ NSObjectFileImage image; NSObjectFileImageReturnCode nsret; nsret = NSCreateObjectFileImageFromFile (name, &image); if (nsret == NSObjectFileImageSuccess) { TRACEN((printf("NSCreateObjectFileImageFromFile(%s) : OK\n",name))) handler = (HMODULE)NSLinkModule(image,name,NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW); } else { TRACEN((printf("NSCreateObjectFileImageFromFile(%s) : ERROR\n",name))) } #elif ENV_BEOS // normalize path (remove things like "./", "..", etc..), otherwise it won't work BPath p(name, NULL, true); status_t err = B_OK; image_id image = load_add_on(p.Path()); TRACEN((printf("load_add_on(%s)=%d\n",p.Path(),(int)image))) if (image < 0) { err = (image_id)handler; handler = 0; } else { err = 0; handler = (HMODULE)image; } #else int options_dlopen = 0; #ifdef RTLD_LOCAL options_dlopen |= RTLD_LOCAL; #endif #ifdef RTLD_NOW options_dlopen |= RTLD_NOW; #endif #ifdef RTLD_GROUP #if ! (defined(hpux) || defined(__hpux)) options_dlopen |= RTLD_GROUP; // mainly for solaris but not for HPUX #endif #endif TRACEN((printf("CLibrary::Load - dlopen(%s,0x%d)\n",name,options_dlopen))) handler = dlopen(name,options_dlopen); #endif // __APPLE_CC__ TRACEN((printf("CLibrary::Load(%s) => %p\n",name,handler))) if (handler) { // Call DllMain() like in Windows : useless now // Propagate the value of global_use_utf16_conversion into the plugins int *tmp = (int *)local_GetProcAddress(handler,"global_use_utf16_conversion"); if (tmp) *tmp = global_use_utf16_conversion; tmp = (int *)local_GetProcAddress(handler,"global_use_lstat"); if (tmp) *tmp = global_use_lstat; // test construtors calls void (*fctTest)(void) = (void (*)(void))local_GetProcAddress(handler,"sync_TestConstructor"); if (fctTest) fctTest(); } else { #ifdef __APPLE_CC__ NSLinkEditErrors c; int num_err; const char *file,*err; NSLinkEditError(&c,&num_err,&file,&err); printf("Can't load '%ls' (%s)\n", lpLibFileName,err); #elif ENV_BEOS printf("Can't load '%ls' (%s)\n", lpLibFileName,strerror(err)); #else printf("Can't load '%ls' (%s)\n", lpLibFileName,dlerror()); #endif } _module = handler; TRACEN((printf("CLibrary::Load(this=%p,%ls) => _module=%p\n",(void *)this,lpLibFileName,_module))) return true; } #ifndef _SFX FString GetModuleDirPrefix() { FString s; const char *p7zip_home_dir = getenv("P7ZIP_HOME_DIR"); if (p7zip_home_dir) { return MultiByteToUnicodeString(p7zip_home_dir,CP_ACP); } return FTEXT(".") FSTRING_PATH_SEPARATOR; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/DLL.h0100777000000000000000000000163013761647206021334 0ustar00// Windows/DLL.h #ifndef __WINDOWS_DLL_H #define __WINDOWS_DLL_H #include "../Common/MyString.h" typedef void * HMODULE; // #define LOAD_LIBRARY_AS_DATAFILE 0 typedef int (*FARPROC)(); namespace NWindows { namespace NDLL { class CLibrary { HMODULE _module; public: CLibrary(): _module(NULL) {}; ~CLibrary() { Free(); } operator HMODULE() const { return _module; } HMODULE* operator&() { return &_module; } bool IsLoaded() const { return (_module != NULL); }; void Attach(HMODULE m) { Free(); _module = m; } HMODULE Detach() { HMODULE m = _module; _module = NULL; return m; } bool Free(); // bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE); bool Load(CFSTR path); FARPROC GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); } }; bool MyGetModuleFileName(FString &path); FString GetModuleDirPrefix(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileDir.cpp0100777000000000000000000005122613761647206022600 0ustar00// Windows/FileDir.cpp #include "StdAfx.h" #ifndef _UNICODE #include "../Common/StringConvert.h" #endif #include "FileDir.h" #include "FileFind.h" #include "FileName.h" #include "../Common/StringConvert.h" #include "../Common/IntToString.h" #define NEED_NAME_WINDOWS_TO_UNIX #include "myPrivate.h" #include "Windows/Synchronization.h" #include // rmdir #include #include // mkdir #include #include #include // #define TRACEN(u) u; #define TRACEN(u) /* */ int g_filedir = 1; static NWindows::NSynchronization::CCriticalSection g_CountCriticalSection; class Umask { public: mode_t current_umask; mode_t mask; Umask() { current_umask = umask (0); /* get and set the umask */ umask(current_umask); /* restore the umask */ mask = 0777 & (~current_umask); } }; static Umask gbl_umask; extern BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds ); #ifdef _UNICODE AString nameWindowToUnix2(LPCWSTR name) // FIXME : optimization ? { AString astr = UnicodeStringToMultiByte(name); return AString(nameWindowToUnix((const char *)astr)); } #endif DWORD WINAPI GetFullPathNameW( LPCTSTR name, DWORD len, LPTSTR buffer, LPTSTR *lastpart ) { // FIXME if (name == 0) return 0; DWORD name_len = lstrlen(name); if (name[0] == '/') { DWORD ret = name_len+2; if (ret >= len) { TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 0)\n",name, (int)len))) return 0; } lstrcpy(buffer,L"c:"); lstrcat(buffer,name); *lastpart=buffer; TCHAR *ptr=buffer; while (*ptr) { if (*ptr == '/') *lastpart=ptr+1; ptr++; } TRACEN((printf("GetFullPathNameA(%ls,%d,%ls,%ls)=%d\n",name, (int)len,buffer, *lastpart,(int)ret))) return ret; } if (isascii(name[0]) && (name[1] == ':')) { // FIXME isascii DWORD ret = name_len; if (ret >= len) { TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 1)\n",name, (int)len))) return 0; } lstrcpy(buffer,name); *lastpart=buffer; TCHAR *ptr=buffer; while (*ptr) { if (*ptr == '/') *lastpart=ptr+1; ptr++; } TRACEN((printf("GetFullPathNameA(%ls,%d,%ls,%ls)=%d\n",name, (int)len,buffer, *lastpart,(int)ret))) return ret; } // name is a relative pathname. // if (len < 2) { TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 2)\n",name, (int)len))) return 0; } DWORD ret = 0; char begin[MAX_PATHNAME_LEN]; /* DWORD begin_len = GetCurrentDirectoryA(MAX_PATHNAME_LEN,begin); */ DWORD begin_len = 0; begin[0]='c'; begin[1]=':'; char * cret = getcwd(begin+2, MAX_PATHNAME_LEN - 3); if (cret) { begin_len = strlen(begin); } if (begin_len >= 1) { // strlen(begin) + strlen("/") + strlen(name) ret = begin_len + 1 + name_len; if (ret >= len) { TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 4)\n",name, (int)len))) return 0; } UString wbegin = GetUnicodeString(begin); lstrcpy(buffer,wbegin); lstrcat(buffer,L"/"); lstrcat(buffer,name); *lastpart=buffer + begin_len + 1; TCHAR *ptr=buffer; while (*ptr) { if (*ptr == '/') *lastpart=ptr+1; ptr++; } TRACEN((printf("GetFullPathNameA(%ls,%d,%ls,%ls)=%d\n",name, (int)len,buffer, *lastpart,(int)ret))) } else { ret = 0; TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 5)\n",name, (int)len))) } return ret; } static int copy_fd(int fin,int fout) { char buffer[16384]; ssize_t ret_in; ssize_t ret_out; do { ret_out = -1; do { ret_in = read(fin, buffer,sizeof(buffer)); } while (ret_in < 0 && (errno == EINTR)); if (ret_in >= 1) { do { ret_out = write (fout, buffer, ret_in); } while (ret_out < 0 && (errno == EINTR)); } else if (ret_in == 0) { ret_out = 0; } } while (ret_out >= 1); return ret_out; } static BOOL CopyFile(const char *src,const char *dst) { int ret = -1; #ifdef O_BINARY int flags = O_BINARY; #else int flags = 0; #endif #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif // printf("##DBG CopyFile(%s,%s)\n",src,dst); int fout = open(dst,O_CREAT | O_WRONLY | O_EXCL | flags, 0600); if (fout != -1) { int fin = open(src,O_RDONLY | flags , 0600); if (fin != -1) { ret = copy_fd(fin,fout); if (ret == 0) ret = close(fin); else close(fin); } if (ret == 0) ret = close(fout); else close(fout); } if (ret == 0) return TRUE; return FALSE; } #ifndef _UNICODE extern bool g_IsNT; #endif namespace NWindows { namespace NFile { // SetCurrentDirectory doesn't support \\?\ prefix #ifdef WIN_LONG_PATH bool GetLongPathBase(CFSTR fileName, UString &res); bool GetLongPath(CFSTR fileName, UString &res); #endif namespace NDir { #ifdef _WIN32 #ifndef UNDER_CE bool MyGetWindowsDirectory(FString &path) { UINT needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetWindowsDirectory(s, MAX_PATH + 1); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1); path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } bool MyGetSystemDirectory(FString &path) { UINT needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetSystemDirectory(s, MAX_PATH + 1); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1); path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } #endif #endif // _WIN32 bool SetDirTime(CFSTR fileName, const FILETIME * /* cTime */ , const FILETIME *aTime, const FILETIME *mTime) { AString cfilename = UnicodeStringToMultiByte(fileName); const char * unix_filename = nameWindowToUnix((const char *)cfilename); struct utimbuf buf; struct stat oldbuf; int ret = stat(unix_filename,&oldbuf); if (ret == 0) { buf.actime = oldbuf.st_atime; buf.modtime = oldbuf.st_mtime; } else { time_t current_time = time(0); buf.actime = current_time; buf.modtime = current_time; } if (aTime) { LARGE_INTEGER ltime; DWORD dw; ltime.QuadPart = aTime->dwHighDateTime; ltime.QuadPart = (ltime.QuadPart << 32) | aTime->dwLowDateTime; RtlTimeToSecondsSince1970( <ime, &dw ); buf.actime = dw; } if (mTime) { LARGE_INTEGER ltime; DWORD dw; ltime.QuadPart = mTime->dwHighDateTime; ltime.QuadPart = (ltime.QuadPart << 32) | mTime->dwLowDateTime; RtlTimeToSecondsSince1970( <ime, &dw ); buf.modtime = dw; } /* ret = */ utime(unix_filename, &buf); return true; } #ifdef WIN_LONG_PATH bool GetLongPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2) { if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2)) return false; if (d1.IsEmpty() && d2.IsEmpty()) return false; if (d1.IsEmpty()) d1 = fs2us(s1); if (d2.IsEmpty()) d2 = fs2us(s2); return true; } #endif static int convert_to_symlink(const char * name) { FILE *file = fopen(name,"rb"); if (file) { char buf[MAX_PATHNAME_LEN+1]; char * ret = fgets(buf,sizeof(buf)-1,file); fclose(file); if (ret) { int ir = unlink(name); if (ir == 0) { ir = symlink(buf,name); } return ir; } } return -1; } bool SetFileAttrib(CFSTR fileName, DWORD fileAttributes) { if (!fileName) { SetLastError(ERROR_PATH_NOT_FOUND); TRACEN((printf("SetFileAttrib(NULL,%d) : false-1\n",fileAttributes))) return false; } #ifdef _UNICODE AString name = nameWindowToUnix2(fileName); #else const char * name = nameWindowToUnix(fileName); #endif struct stat stat_info; #ifdef ENV_HAVE_LSTAT if (global_use_lstat) { if(lstat(name,&stat_info)!=0) { TRACEN((printf("SetFileAttrib(%s,%d) : false-2-1\n",(const char *)name,fileAttributes))) return false; } } else #endif { if(stat(name,&stat_info)!=0) { TRACEN((printf("SetFileAttrib(%s,%d) : false-2-2\n",(const char *)name,fileAttributes))) return false; } } if (fileAttributes & FILE_ATTRIBUTE_UNIX_EXTENSION) { stat_info.st_mode = fileAttributes >> 16; #ifdef ENV_HAVE_LSTAT if (S_ISLNK(stat_info.st_mode)) { if ( convert_to_symlink(name) != 0) { TRACEN((printf("SetFileAttrib(%s,%d) : false-3\n",(const char *)name,fileAttributes))) return false; } } else #endif if (S_ISREG(stat_info.st_mode)) { TRACEN((printf("##DBG chmod-2(%s,%o)\n",(const char *)name,(unsigned)stat_info.st_mode & gbl_umask.mask))) chmod(name,stat_info.st_mode & gbl_umask.mask); } else if (S_ISDIR(stat_info.st_mode)) { // user/7za must be able to create files in this directory stat_info.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); TRACEN((printf("##DBG chmod-3(%s,%o)\n",(const char *)name,(unsigned)stat_info.st_mode & gbl_umask.mask))) chmod(name,stat_info.st_mode & gbl_umask.mask); } #ifdef ENV_HAVE_LSTAT } else if (!S_ISLNK(stat_info.st_mode)) { // do not use chmod on a link #else } else { #endif /* Only Windows Attributes */ if( S_ISDIR(stat_info.st_mode)) { /* Remark : FILE_ATTRIBUTE_READONLY ignored for directory. */ TRACEN((printf("##DBG chmod-4(%s,%o)\n",(const char *)name,(unsigned)stat_info.st_mode & gbl_umask.mask))) chmod(name,stat_info.st_mode & gbl_umask.mask); } else { if (fileAttributes & FILE_ATTRIBUTE_READONLY) stat_info.st_mode &= ~0222; /* octal!, clear write permission bits */ TRACEN((printf("##DBG chmod-5(%s,%o)\n",(const char *)name,(unsigned)stat_info.st_mode & gbl_umask.mask))) chmod(name,stat_info.st_mode & gbl_umask.mask); } } TRACEN((printf("SetFileAttrib(%s,%d) : true\n",(const char *)name,fileAttributes))) return true; } bool RemoveDir(CFSTR path) { if (!path || !*path) { SetLastError(ERROR_PATH_NOT_FOUND); return FALSE; } AString name = nameWindowToUnix2(path); TRACEN((printf("RemoveDirectoryA(%s)\n",(const char *)name))) if (rmdir( (const char *)name ) != 0) { return FALSE; } return TRUE; } bool MyMoveFile(CFSTR existFileName, CFSTR newFileName) { #ifdef _UNICODE AString src = nameWindowToUnix2(existFileName); AString dst = nameWindowToUnix2(newFileName); #else const char * src = nameWindowToUnix(existFileName); const char * dst = nameWindowToUnix(newFileName); #endif TRACEN((printf("MyMoveFile(%s,%s)\n",(const char *)src,(const char *)dst))) int ret = rename(src,dst); if (ret != 0) { if (errno == EXDEV) // FIXED : bug #1112167 (Temporary directory must be on same partition as target) { BOOL bret = CopyFile(src,dst); if (bret == FALSE) return false; struct stat info_file; ret = stat(src,&info_file); if (ret == 0) { TRACEN((printf("##DBG chmod-1(%s,%o)\n",(const char *)dst,(unsigned)info_file.st_mode & gbl_umask.mask))) ret = chmod(dst,info_file.st_mode & gbl_umask.mask); } if (ret == 0) { ret = unlink(src); } if (ret == 0) return true; } return false; } return true; } bool CreateDir(CFSTR path) { if (!path || !*path) { SetLastError(ERROR_PATH_NOT_FOUND); return false; } #ifdef _UNICODE AString name = nameWindowToUnix2(path); #else const char * name = nameWindowToUnix(path); #endif bool bret = false; if (mkdir( name, 0700 ) == 0) bret = true; TRACEN((printf("CreateDir(%s)=%d\n",(const char *)name,(int)bret))) return bret; } bool CreateComplexDir(CFSTR _aPathName) { AString name = nameWindowToUnix2(_aPathName); TRACEN((printf("CreateComplexDir(%s)\n",(const char *)name))) FString pathName = _aPathName; int pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos > 0 && pos == pathName.Len() - 1) { if (pathName.Len() == 3 && pathName[1] == L':') return true; // Disk folder; pathName.Delete(pos); } FString pathName2 = pathName; pos = pathName.Len(); TRACEN((printf("CreateComplexDir(%s) pathName2=%ls\n",(const char *)name,(CFSTR)pathName2))) for (;;) { if (CreateDir(pathName)) break; TRACEN((printf("CreateComplexDir(%s) GetLastError=%d (ERROR_ALREADY_EXISTS=%d)\n",(const char *)name,::GetLastError(), ERROR_ALREADY_EXISTS))) if (::GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef _WIN32 // FIXED for supporting symbolic link instead of a directory NFind::CFileInfo fileInfo; if (!fileInfo.Find(pathName)) // For network folders return true; if (!fileInfo.IsDir()) return false; #endif break; } pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos < 0 || pos == 0) return false; if (pathName[pos - 1] == L':') return false; pathName = pathName.Left(pos); } pathName = pathName2; while (pos < pathName.Len()) { pos = pathName.Find(FCHAR_PATH_SEPARATOR, pos + 1); if (pos < 0) pos = pathName.Len(); if (!CreateDir(pathName.Left(pos))) return false; } return true; } bool DeleteFileAlways(CFSTR name) { if (!name || !*name) { SetLastError(ERROR_PATH_NOT_FOUND); return false; } #ifdef _UNICODE AString unixname = nameWindowToUnix2(name); #else const char * unixname = nameWindowToUnix(name); #endif bool bret = false; if (remove(unixname) == 0) bret = true; TRACEN((printf("DeleteFileAlways(%s)=%d\n",(const char *)unixname,(int)bret))) return bret; } bool RemoveDirWithSubItems(const FString &path) { bool needRemoveSubItems = true; { NFind::CFileInfo fi; if (!fi.Find(path)) return false; if (!fi.IsDir()) { ::SetLastError(ERROR_DIRECTORY); return false; } if (fi.HasReparsePoint()) needRemoveSubItems = false; } if (needRemoveSubItems) { FString s = path; s += FCHAR_PATH_SEPARATOR; unsigned prefixSize = s.Len(); s += FCHAR_ANY_MASK; NFind::CEnumerator enumerator(s); NFind::CFileInfo fi; while (enumerator.Next(fi)) { s.DeleteFrom(prefixSize); s += fi.Name; if (fi.IsDir()) { if (!RemoveDirWithSubItems(s)) return false; } else if (!DeleteFileAlways(s)) return false; } } if (!SetFileAttrib(path, 0)) return false; return RemoveDir(path); } bool RemoveDirectoryWithSubItems(const FString &path); // FIXME static bool RemoveDirectorySubItems2(const FString pathPrefix, const NFind::CFileInfo &fileInfo) { if (fileInfo.IsDir()) return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name); return DeleteFileAlways(pathPrefix + fileInfo.Name); } bool RemoveDirectoryWithSubItems(const FString &path) { NFind::CFileInfo fileInfo; FString pathPrefix = path + FCHAR_PATH_SEPARATOR; { NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); while (enumerator.Next(fileInfo)) if (!RemoveDirectorySubItems2(pathPrefix, fileInfo)) return false; } if (!SetFileAttrib(path, 0)) return false; return RemoveDir(path); } #ifdef UNDER_CE bool MyGetFullPathName(CFSTR fileName, FString &resFullPath) { resFullPath = fileName; return true; } #else #ifdef WIN_LONG_PATH static FString GetLastPart(CFSTR path) { int i = MyStringLen(path); for (; i > 0; i--) { FChar c = path[i - 1]; if (c == FCHAR_PATH_SEPARATOR || c == '/') break; } return path + i; } static void AddTrailingDots(CFSTR oldPath, FString &newPath) { int len = MyStringLen(oldPath); int i; for (i = len; i > 0 && oldPath[i - 1] == '.'; i--); if (i == 0 || i == len) return; FString oldName = GetLastPart(oldPath); FString newName = GetLastPart(newPath); int nonDotsLen = oldName.Len() - (len - i); if (nonDotsLen == 0 || newName.CompareNoCase(oldName.Left(nonDotsLen)) != 0) return; for (; i != len; i++) newPath += '.'; } #endif bool MyGetFullPathName(CFSTR fileName, FString &resFullPath) { resFullPath.Empty(); #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; LPTSTR fileNamePointer = 0; DWORD needLength = ::GetFullPathName(fs2fas(fileName), MAX_PATH + 1, s, &fileNamePointer); if (needLength == 0 || needLength > MAX_PATH) return false; resFullPath = fas2fs(s); return true; } else #endif { LPWSTR fileNamePointer = 0; WCHAR s[MAX_PATH + 2]; s[0] = 0; DWORD needLength = ::GetFullPathNameW(fs2us(fileName), MAX_PATH + 1, s, &fileNamePointer); if (needLength == 0) return false; if (needLength <= MAX_PATH) { resFullPath = us2fs(s); return true; } #ifdef WIN_LONG_PATH needLength++; UString temp; LPWSTR buffer = temp.GetBuffer(needLength + 1); buffer[0] = 0; DWORD needLength2 = ::GetFullPathNameW(fs2us(fileName), needLength, buffer, &fileNamePointer); temp.ReleaseBuffer(); if (needLength2 > 0 && needLength2 <= needLength) { resFullPath = us2fs(temp); AddTrailingDots(fileName, resFullPath); return true; } #endif return false; } } bool SetCurrentDir(CFSTR path) { AString apath = UnicodeStringToMultiByte(path); return chdir((const char*)apath) == 0; } bool GetCurrentDir(FString &path) { char begin[MAX_PATHNAME_LEN]; begin[0]='c'; begin[1]=':'; char * cret = getcwd(begin+2, MAX_PATHNAME_LEN - 3); if (cret) { #ifdef _UNICODE path = GetUnicodeString(begin); #else path = begin; #endif return true; } return false; } #endif bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) { bool res = MyGetFullPathName(path, resDirPrefix); if (!res) resDirPrefix = path; int pos = resDirPrefix.ReverseFind(FCHAR_PATH_SEPARATOR); resFileName = resDirPrefix.Ptr(pos + 1); resDirPrefix.DeleteFrom(pos + 1); return res; } bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) { FString resFileName; return GetFullPathAndSplit(path, resDirPrefix, resFileName); } bool MyGetTempPath(FString &path) { path = L"c:/tmp/"; // final '/' is needed return true; } static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile) { #ifdef _WIN32 UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); #else static UInt32 memo_count = 0; UInt32 count; g_CountCriticalSection.Enter(); count = memo_count++; g_CountCriticalSection.Leave(); UINT number = (UINT)getpid(); UInt32 d = (GetTickCount() << 12) ^ (count << 14) ^ number; #endif for (unsigned i = 0; i < 100; i++) { path = prefix; if (addRandom) { FChar s[16]; UInt32 value = d; unsigned k; for (k = 0; k < 8; k++) { unsigned t = value & 0xF; value >>= 4; s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } s[k] = '\0'; if (outFile) path += FChar('.'); path += s; UInt32 step = GetTickCount() + 2; if (step == 0) step = 1; d += step; } addRandom = true; if (outFile) path += FTEXT(".tmp"); if (NFind::DoesFileOrDirExist(path)) { SetLastError(ERROR_ALREADY_EXISTS); continue; } if (outFile) { if (outFile->Create(path, false)) return true; } else { if (CreateDir(path)) return true; } DWORD error = GetLastError(); if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) break; } path.Empty(); return false; } bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) { if (!Remove()) return false; if (!CreateTempFile(prefix, false, _path, outFile)) return false; _mustBeDeleted = true; return true; } bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile) { if (!Remove()) return false; FString tempPath; if (!MyGetTempPath(tempPath)) return false; if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile)) return false; _mustBeDeleted = true; return true; } bool CTempFile::Remove() { if (!_mustBeDeleted) return true; _mustBeDeleted = !DeleteFileAlways(_path); return !_mustBeDeleted; } bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) { if (deleteDestBefore) if (NFind::DoesFileExist(name)) if (!DeleteFileAlways(name)) return false; DisableDeleting(); return MyMoveFile(_path, name); } bool CTempDir::Create(CFSTR prefix) { if (!Remove()) return false; FString tempPath; if (!MyGetTempPath(tempPath)) return false; if (!CreateTempFile(tempPath + prefix, true, _path, NULL)) return false; _mustBeDeleted = true; return true; } bool CTempDir::Remove() { if (!_mustBeDeleted) return true; _mustBeDeleted = !RemoveDirectoryWithSubItems(_path); return !_mustBeDeleted; } }}} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileDir.h0100777000000000000000000000422613761647206022243 0ustar00// Windows/FileDir.h #ifndef __WINDOWS_FILE_DIR_H #define __WINDOWS_FILE_DIR_H #include "../Common/MyString.h" #include "FileIO.h" namespace NWindows { namespace NFile { namespace NDir { bool GetWindowsDir(FString &path); bool GetSystemDir(FString &path); bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); bool SetFileAttrib(CFSTR path, DWORD attrib); bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); #ifndef UNDER_CE bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); #endif bool RemoveDir(CFSTR path); bool CreateDir(CFSTR path); bool CreateComplexDir(CFSTR path); bool DeleteFileAlways(CFSTR name); bool RemoveDirWithSubItems(const FString &path); bool MyGetFullPathName(CFSTR path, FString &resFullPath); bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix); #ifndef UNDER_CE bool SetCurrentDir(CFSTR path); bool GetCurrentDir(FString &resultPath); #endif bool MyGetTempPath(FString &resultPath); class CTempFile { bool _mustBeDeleted; FString _path; void DisableDeleting() { _mustBeDeleted = false; } public: CTempFile(): _mustBeDeleted(false) {} ~CTempFile() { Remove(); } const FString &GetPath() const { return _path; } bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); bool Remove(); bool MoveTo(CFSTR name, bool deleteDestBefore); }; class CTempDir { bool _mustBeDeleted; FString _path; public: CTempDir(): _mustBeDeleted(false) {} ~CTempDir() { Remove(); } const FString &GetPath() const { return _path; } void DisableDeleting() { _mustBeDeleted = false; } bool Create(CFSTR namePrefix) ; bool Remove(); }; #if !defined(UNDER_CE) class CCurrentDirRestorer { FString _path; public: bool NeedRestore; CCurrentDirRestorer(): NeedRestore(true) { GetCurrentDir(_path); } ~CCurrentDirRestorer() { if (!NeedRestore) return; FString s; if (GetCurrentDir(s)) if (s != _path) SetCurrentDir(_path); } }; #endif }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileFind.cpp0100777000000000000000000003314413761647206022741 0ustar00// Windows/FileFind.cpp #include "StdAfx.h" #include "FileFind.h" #include "FileIO.h" #include "../Common/StringConvert.h" #ifndef _UNICODE extern bool g_IsNT; #endif #include #include #include #ifdef ENV_HAVE_LSTAT extern "C" { int global_use_lstat=1; // default behaviour : p7zip stores symlinks instead of dumping the files they point to } #endif #define NEED_NAME_WINDOWS_TO_UNIX #include "myPrivate.h" // #define TRACEN(u) u; #define TRACEN(u) /* */ void my_windows_split_path(const AString &p_path, AString &dir , AString &base) { int pos = p_path.ReverseFind('/'); if (pos == -1) { // no separator dir = "."; if (p_path.IsEmpty()) base = "."; else base = p_path; } else if ((pos+1) < p_path.Len()) { // true separator base = p_path.Ptr(pos+1); while ((pos >= 1) && (p_path[pos-1] == '/')) pos--; if (pos == 0) dir = "/"; else dir = p_path.Left(pos); } else { // separator at the end of the path // pos = p_path.find_last_not_of("/"); pos = -1; int ind = 0; while (p_path[ind]) { if (p_path[ind] != '/') pos = ind; ind++; } if (pos == -1) { base = "/"; dir = "/"; } else { my_windows_split_path(p_path.Left(pos+1),dir,base); } } } static void my_windows_split_path(const UString &p_path, UString &dir , UString &base) { int pos = p_path.ReverseFind(L'/'); if (pos == -1) { // no separator dir = L"."; if (p_path.IsEmpty()) base = L"."; else base = p_path; } else if ((pos+1) < p_path.Len()) { // true separator base = p_path.Ptr(pos+1); while ((pos >= 1) && (p_path[pos-1] == L'/')) pos--; if (pos == 0) dir = L"/"; else dir = p_path.Left(pos); } else { // separator at the end of the path // pos = p_path.find_last_not_of("/"); pos = -1; int ind = 0; while (p_path[ind]) { if (p_path[ind] != L'/') pos = ind; ind++; } if (pos == -1) { base = L"/"; dir = L"/"; } else { my_windows_split_path(p_path.Left(pos+1),dir,base); } } } static int filter_pattern(const char *string , const char *pattern , int flags_nocase) { if ((string == 0) || (*string==0)) { if (pattern == 0) return 1; while (*pattern=='*') ++pattern; return (!*pattern); } switch (*pattern) { case '*': if (!filter_pattern(string+1,pattern,flags_nocase)) return filter_pattern(string,pattern+1,flags_nocase); return 1; case 0: if (*string==0) return 1; break; case '?': return filter_pattern(string+1,pattern+1,flags_nocase); default: if ( ((flags_nocase) && (tolower(*pattern)==tolower(*string))) || (*pattern == *string) ) { return filter_pattern(string+1,pattern+1,flags_nocase); } break; } return 0; } namespace NWindows { namespace NFile { #ifdef SUPPORT_DEVICE_FILE bool IsDeviceName(CFSTR n); #endif #if defined(WIN_LONG_PATH) bool GetLongPath(CFSTR fileName, UString &res); #endif namespace NFind { bool CFileInfo::IsDots() const { if (!IsDir() || Name.IsEmpty()) return false; if (Name[0] != FTEXT('.')) return false; return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == FTEXT('.')); } #define WIN_FD_TO_MY_FI(fi, fd) \ fi.Attrib = fd.dwFileAttributes; \ fi.CTime = fd.ftCreationTime; \ fi.ATime = fd.ftLastAccessTime; \ fi.MTime = fd.ftLastWriteTime; \ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ fi.IsDevice = false; /* #ifdef UNDER_CE fi.ObjectID = fd.dwOID; #else fi.ReparseTag = fd.dwReserved0; #endif */ #ifndef _UNICODE static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); fi.Name = fas2fs(fd.cFileName); } #endif //////////////////////////////// // CFindFile bool CFindFile::Close() { if(_dirp == 0) return true; int ret = closedir(_dirp); if (ret == 0) { _dirp = 0; return true; } return false; } static bool originalFilename(const UString & src, AString & res) { // Try to recover the original filename res = ""; int i=0; while (src[i]) { if (src[i] >= 256) { return false; } else { res += char(src[i]); } i++; } return true; } // Warning this function cannot update "fileInfo.Name" static int fillin_CFileInfo(CFileInfo &fileInfo,const char *filename,bool ignoreLink) { struct stat stat_info; int ret; #ifdef ENV_HAVE_LSTAT if ( (global_use_lstat) && (ignoreLink == false)) { ret = lstat(filename,&stat_info); } else #endif { ret = stat(filename,&stat_info); } // printf("fillin_CFileInfo(%s,%d)=%d mode=%o\n",filename,(int)ignoreLink,ret,(unsigned)stat_info.st_mode); if (ret != 0) return ret; /* FIXME : FILE_ATTRIBUTE_HIDDEN ? */ if (S_ISDIR(stat_info.st_mode)) { fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY; } else { fileInfo.Attrib = FILE_ATTRIBUTE_ARCHIVE; } if (!(stat_info.st_mode & S_IWUSR)) fileInfo.Attrib |= FILE_ATTRIBUTE_READONLY; fileInfo.Attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((stat_info.st_mode & 0xFFFF) << 16); RtlSecondsSince1970ToFileTime( stat_info.st_ctime, &fileInfo.CTime ); RtlSecondsSince1970ToFileTime( stat_info.st_mtime, &fileInfo.MTime ); RtlSecondsSince1970ToFileTime( stat_info.st_atime, &fileInfo.ATime ); fileInfo.IsDevice = false; if (S_ISDIR(stat_info.st_mode)) { fileInfo.Size = 0; } else { // file or symbolic link fileInfo.Size = stat_info.st_size; // for a symbolic link, size = size of filename } return 0; } static int fillin_CFileInfo(CFileInfo &fi,const char *dir,const char *name,bool ignoreLink) { char filename[MAX_PATHNAME_LEN]; size_t dir_len = strlen(dir); size_t name_len = strlen(name); size_t total = dir_len + 1 + name_len + 1; // 1 = strlen("/"); + le zero character if (total >= MAX_PATHNAME_LEN) throw "fillin_CFileInfo - internal error - MAX_PATHNAME_LEN"; memcpy(filename,dir,dir_len); if (dir_len >= 1) { if (filename[dir_len-1] == CHAR_PATH_SEPARATOR) { // delete the '/' dir_len--; } } filename[dir_len] = CHAR_PATH_SEPARATOR; memcpy(filename+(dir_len+1),name,name_len+1); // copy also final '\0' #ifdef _UNICODE fi.Name = GetUnicodeString(name, CP_ACP); #else fi.Name = name; #endif int ret = fillin_CFileInfo(fi,filename,ignoreLink); if (ret != 0) { AString err_msg = "stat error for "; err_msg += filename; err_msg += " ("; err_msg += strerror(errno); err_msg += ")"; throw err_msg; } return ret; } bool CFindFile::FindFirst(CFSTR cfWildcard, CFileInfo &fi, bool ignoreLink) { if (!Close()) return false; AString Awildcard = UnicodeStringToMultiByte(cfWildcard, CP_ACP); const char * wildcard = (const char *)Awildcard; if ((!wildcard) || (wildcard[0]==0)) { SetLastError(ERROR_PATH_NOT_FOUND); return false; } my_windows_split_path(nameWindowToUnix(wildcard),_directory,_pattern); TRACEN((printf("CFindFile::FindFirst : %s (dirname=%s,pattern=%s)\n",wildcard,(const char *)_directory,(const char *)_pattern))) _dirp = ::opendir((const char *)_directory); TRACEN((printf("CFindFile::FindFirst : opendir=%p\n",_dirp))) if ((_dirp == 0) && (global_use_utf16_conversion)) { // Try to recover the original filename UString ustr = MultiByteToUnicodeString(_directory, 0); AString resultString; bool is_good = originalFilename(ustr, resultString); if (is_good) { _dirp = ::opendir((const char *)resultString); _directory = resultString; } } if (_dirp == 0) return false; struct dirent *dp; while ((dp = readdir(_dirp)) != NULL) { if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) { int retf = fillin_CFileInfo(fi,(const char *)_directory,dp->d_name,ignoreLink); if (retf) { TRACEN((printf("CFindFile::FindFirst : closedir-1(dirp=%p)\n",_dirp))) closedir(_dirp); _dirp = 0; SetLastError( ERROR_NO_MORE_FILES ); return false; } TRACEN((printf("CFindFile::FindFirst -%s- true\n",dp->d_name))) return true; } } TRACEN((printf("CFindFile::FindFirst : closedir-2(dirp=%p)\n",_dirp))) closedir(_dirp); _dirp = 0; SetLastError( ERROR_NO_MORE_FILES ); return false; } bool CFindFile::FindNext(CFileInfo &fi) { if (_dirp == 0) { SetLastError( ERROR_INVALID_HANDLE ); return false; } struct dirent *dp; while ((dp = readdir(_dirp)) != NULL) { if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) { int retf = fillin_CFileInfo(fi,(const char *)_directory,dp->d_name,false); if (retf) { TRACEN((printf("FindNextFileA -%s- ret_handle=FALSE (errno=%d)\n",dp->d_name,errno))) return false; } TRACEN((printf("FindNextFileA -%s- true\n",dp->d_name))) return true; } } TRACEN((printf("FindNextFileA ret_handle=FALSE (ERROR_NO_MORE_FILES)\n"))) SetLastError( ERROR_NO_MORE_FILES ); return false; } #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; void CFileInfoBase::Clear() { Size = 0; MY_CLEAR_FILETIME(CTime); MY_CLEAR_FILETIME(ATime); MY_CLEAR_FILETIME(MTime); Attrib = 0; } bool CFileInfo::Find(CFSTR wildcard, bool ignoreLink) { #ifdef SUPPORT_DEVICE_FILE if (IsDeviceName(wildcard)) { Clear(); IsDevice = true; NIO::CInFile inFile; if (!inFile.Open(wildcard)) return false; Name = wildcard + 4; if (inFile.LengthDefined) Size = inFile.Length; return true; } #endif CFindFile finder; if (finder.FindFirst(wildcard, *this,ignoreLink)) return true; #ifdef _WIN32 { DWORD lastError = GetLastError(); if (lastError == ERROR_BAD_NETPATH || lastError == ERROR_FILE_NOT_FOUND) { int len = MyStringLen(wildcard); if (len > 2 && wildcard[0] == '\\' && wildcard[1] == '\\') { int pos = FindCharPosInString(wildcard + 2, FTEXT('\\')); if (pos >= 0) { pos += 2 + 1; len -= pos; CFSTR remString = wildcard + pos; int pos2 = FindCharPosInString(remString, FTEXT('\\')); FString s = wildcard; if (pos2 < 0 || pos2 == len - 1) { FString s = wildcard; if (pos2 < 0) { pos2 = len; s += FTEXT('\\'); } s += FCHAR_ANY_MASK; if (finder.FindFirst(s, *this)) if (Name == FTEXT(".")) { Name.SetFrom(s.Ptr(pos), pos2); return true; } ::SetLastError(lastError); } } } } } #endif return false; } bool DoesFileExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && !fi.IsDir(); } bool DoesDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && fi.IsDir(); } bool DoesFileOrDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name); } bool CEnumerator::NextAny(CFileInfo &fi) { if (_findFile.IsHandleAllocated()) return _findFile.FindNext(fi); else return _findFile.FindFirst(_wildcard, fi); } bool CEnumerator::Next(CFileInfo &fi) { for (;;) { if (!NextAny(fi)) return false; if (!fi.IsDots()) return true; } } bool CEnumerator::Next(CFileInfo &fi, bool &found) { if (Next(fi)) { found = true; return true; } found = false; return (::GetLastError() == ERROR_NO_MORE_FILES); } //////////////////////////////// // CFindChangeNotification // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. #ifdef _WIN32 bool CFindChangeNotification::Close() { if (!IsHandleAllocated()) return true; if (!::FindCloseChangeNotification(_handle)) return false; _handle = INVALID_HANDLE_VALUE; return true; } HANDLE CFindChangeNotification::FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter) { #ifndef _UNICODE if (!g_IsNT) _handle = ::FindFirstChangeNotification(fs2fas(pathName), BoolToBOOL(watchSubtree), notifyFilter); else #endif { _handle = ::FindFirstChangeNotificationW(fs2us(pathName), BoolToBOOL(watchSubtree), notifyFilter); #ifdef WIN_LONG_PATH if (!IsHandleAllocated()) { UString longPath; if (GetLongPath(pathName, longPath)) _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); } #endif } return _handle; } #ifndef UNDER_CE bool MyGetLogicalDriveStrings(CObjectVector &driveStrings) { driveStrings.Clear(); #ifndef _UNICODE if (!g_IsNT) { driveStrings.Clear(); UINT32 size = GetLogicalDriveStrings(0, NULL); if (size == 0) return false; AString buf; UINT32 newSize = GetLogicalDriveStrings(size, buf.GetBuffer(size)); if (newSize == 0 || newSize > size) return false; AString s; for (UINT32 i = 0; i < newSize; i++) { char c = buf[i]; if (c == '\0') { driveStrings.Add(fas2fs(s)); s.Empty(); } else s += c; } return s.IsEmpty(); } else #endif { UINT32 size = GetLogicalDriveStringsW(0, NULL); if (size == 0) return false; UString buf; UINT32 newSize = GetLogicalDriveStringsW(size, buf.GetBuffer(size)); if (newSize == 0 || newSize > size) return false; UString s; for (UINT32 i = 0; i < newSize; i++) { WCHAR c = buf[i]; if (c == L'\0') { driveStrings.Add(us2fs(s)); s.Empty(); } else s += c; } return s.IsEmpty(); } } #endif #endif // _WIN32 }}} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileFind.h0100777000000000000000000000704313761647206022405 0ustar00// Windows/FileFind.h #ifndef __WINDOWS_FILE_FIND_H #define __WINDOWS_FILE_FIND_H #include "../Common/MyString.h" #include "../Common/MyTypes.h" #include "Defs.h" #include /* for DIR */ #include namespace NWindows { namespace NFile { namespace NFind { namespace NAttributes { inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; } inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; } inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } } class CFileInfoBase { bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } protected: void Clear(); public: UInt64 Size; FILETIME CTime; FILETIME ATime; FILETIME MTime; DWORD Attrib; bool IsDevice; /* #ifdef UNDER_CE DWORD ObjectID; #else UINT32 ReparseTag; #endif */ bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } }; struct CFileInfo: public CFileInfoBase { FString Name; bool IsDots() const; bool Find(CFSTR wildcard, bool ignoreLink = false); }; class CFindFile { friend class CEnumerator; DIR *_dirp; AString _pattern; AString _directory; public: bool IsHandleAllocated() const { return (_dirp != 0); } CFindFile(): _dirp(0) {} ~CFindFile() { Close(); } bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo, bool ignoreLink = false); bool FindNext(CFileInfo &fileInfo); bool Close(); }; bool DoesFileExist(CFSTR name); bool DoesDirExist(CFSTR name); bool DoesFileOrDirExist(CFSTR name); class CEnumerator { CFindFile _findFile; FString _wildcard; bool NextAny(CFileInfo &fileInfo); public: CEnumerator(const FString &wildcard): _wildcard(wildcard) {} bool Next(CFileInfo &fileInfo); bool Next(CFileInfo &fileInfo, bool &found); }; #ifdef _WIN32 class CFindChangeNotification { HANDLE _handle; public: operator HANDLE () { return _handle; } bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; } CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} ~CFindChangeNotification() { Close(); } bool Close(); HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter); bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); } }; #endif #ifndef UNDER_CE bool MyGetLogicalDriveStrings(CObjectVector &driveStrings); #endif }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileIO.cpp0100777000000000000000000002562213761647206022372 0ustar00// Windows/FileIO.cpp #include "StdAfx.h" #include "FileIO.h" #include "Defs.h" #include "../Common/StringConvert.h" #include #include #include #include #include #define NEED_NAME_WINDOWS_TO_UNIX #include "myPrivate.h" #include #include #ifdef ENV_HAVE_LSTAT #define FD_LINK (-2) #endif #define GENERIC_READ 0x80000000 #define GENERIC_WRITE 0x40000000 extern BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds ); namespace NWindows { namespace NFile { namespace NIO { CFileBase::~CFileBase() { Close(); } bool CFileBase::Create(LPCSTR filename, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,bool ignoreSymbolicLink) { Close(); int flags = 0; const char * name = nameWindowToUnix(filename); #ifdef O_BINARY flags |= O_BINARY; #endif #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif /* now use the umask value */ int mask = umask(0); (void)umask(mask); int mode = 0666 & ~(mask & 066); /* keep the R/W for the user */ if (dwDesiredAccess & GENERIC_WRITE) flags |= O_WRONLY; if (dwDesiredAccess & GENERIC_READ) flags |= O_RDONLY; switch (dwCreationDisposition) { case CREATE_NEW : flags |= O_CREAT | O_EXCL; break; case CREATE_ALWAYS : flags |= O_CREAT; break; case OPEN_EXISTING : break; case OPEN_ALWAYS : flags |= O_CREAT; break; // case TRUNCATE_EXISTING : flags |= O_TRUNC; break; } // printf("##DBG open(%s,0x%x,%o)##\n",name,flags,(unsigned)mode); _fd = -1; #ifdef ENV_HAVE_LSTAT if ((global_use_lstat) && (ignoreSymbolicLink == false)) { _size = readlink(name, _buffer, sizeof(_buffer)-1); if (_size > 0) { if (dwDesiredAccess & GENERIC_READ) { _fd = FD_LINK; _offset = 0; _buffer[_size]=0; } else if (dwDesiredAccess & GENERIC_WRITE) { // does not overwrite the file pointed by symbolic link if (!unlink(name)) return false; } } } #endif if (_fd == -1) { _fd = open(name,flags, mode); } if ((_fd == -1) && (global_use_utf16_conversion)) { // bug #1204993 - Try to recover the original filename UString ustr = MultiByteToUnicodeString(AString(name), 0); AString resultString; int is_good = 1; for (int i = 0; i < ustr.Len(); i++) { if (ustr[i] >= 256) { is_good = 0; break; } else { resultString += char(ustr[i]); } } if (is_good) { _fd = open((const char *)resultString,flags, mode); } } if (_fd == -1) { /* !ENV_HAVE_LSTAT : an invalid symbolic link => errno == ENOENT */ return false; } else { _unix_filename = name; } return true; } bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink) { Close(); return Create(UnicodeStringToMultiByte(fileName, CP_ACP), desiredAccess, shareMode, creationDisposition, flagsAndAttributes,ignoreSymbolicLink); } bool CFileBase::Close() { struct utimbuf buf; buf.actime = _lastAccessTime; buf.modtime = _lastWriteTime; _lastAccessTime = _lastWriteTime = (time_t)-1; if(_fd == -1) return true; #ifdef ENV_HAVE_LSTAT if(_fd == FD_LINK) { _fd = -1; return true; } #endif int ret = ::close(_fd); if (ret == 0) { _fd = -1; /* On some OS (mingwin, MacOSX ...), you must close the file before updating times */ if ((buf.actime != (time_t)-1) || (buf.modtime != (time_t)-1)) { struct stat oldbuf; int ret = stat((const char*)(_unix_filename),&oldbuf); if (ret == 0) { if (buf.actime == (time_t)-1) buf.actime = oldbuf.st_atime; if (buf.modtime == (time_t)-1) buf.modtime = oldbuf.st_mtime; } else { time_t current_time = time(0); if (buf.actime == (time_t)-1) buf.actime = current_time; if (buf.modtime == (time_t)-1) buf.modtime = current_time; } /* ret = */ utime((const char *)(_unix_filename), &buf); } return true; } return false; } bool CFileBase::GetLength(UINT64 &length) const { if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } #ifdef ENV_HAVE_LSTAT if (_fd == FD_LINK) { length = _size; return true; } #endif off_t pos_cur = ::lseek(_fd, 0, SEEK_CUR); if (pos_cur == (off_t)-1) return false; off_t pos_end = ::lseek(_fd, 0, SEEK_END); if (pos_end == (off_t)-1) return false; off_t pos_cur2 = ::lseek(_fd, pos_cur, SEEK_SET); if (pos_cur2 == (off_t)-1) return false; length = (UINT64)pos_end; return true; } bool CFileBase::Seek(INT64 distanceToMove, DWORD moveMethod, UINT64 &newPosition) { if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } #ifdef ENV_HAVE_LSTAT if (_fd == FD_LINK) { INT64 offset; switch (moveMethod) { case STREAM_SEEK_SET : offset = distanceToMove; break; case STREAM_SEEK_CUR : offset = _offset + distanceToMove; break; case STREAM_SEEK_END : offset = _size + distanceToMove; break; default : offset = -1; } if (offset < 0) { SetLastError( EINVAL ); return false; } if (offset > _size) offset = _size; newPosition = _offset = offset; return true; } #endif bool ret = true; off_t pos = (off_t)distanceToMove; off_t newpos = ::lseek(_fd,pos,moveMethod); if (newpos == ((off_t)-1)) { ret = false; } else { newPosition = (UINT64)newpos; } return ret; } bool CFileBase::Seek(UINT64 position, UINT64 &newPosition) { return Seek(position, FILE_BEGIN, newPosition); } ///////////////////////// // CInFile bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } bool CInFile::Open(LPCTSTR fileName,bool ignoreSymbolicLink) { return Create(fileName, GENERIC_READ , FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,ignoreSymbolicLink); } #ifndef _UNICODE bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } bool CInFile::Open(LPCWSTR fileName,bool ignoreSymbolicLink) { return Create(fileName, GENERIC_READ , FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,ignoreSymbolicLink); } #endif // ReadFile and WriteFile functions in Windows have BUG: // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES // (Insufficient system resources exist to complete the requested service). // static UINT32 kChunkSizeMax = (1 << 24); bool CInFile::ReadPart(void *data, UINT32 size, UINT32 &processedSize) { // if (size > kChunkSizeMax) // size = kChunkSizeMax; return Read(data,size,processedSize); } bool CInFile::Read(void *buffer, UINT32 bytesToRead, UINT32 &bytesRead) { if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } if (bytesToRead == 0) { bytesRead =0; return TRUE; } #ifdef ENV_HAVE_LSTAT if (_fd == FD_LINK) { if (_offset >= _size) { bytesRead = 0; return TRUE; } int len = (_size - _offset); if (len > bytesToRead) len = bytesToRead; memcpy(buffer,_buffer+_offset,len); bytesRead = len; _offset += len; return TRUE; } #endif ssize_t ret; do { ret = read(_fd,buffer,bytesToRead); } while (ret < 0 && (errno == EINTR)); if (ret != -1) { bytesRead = ret; return TRUE; } bytesRead =0; return FALSE; } ///////////////////////// // COutFile bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } static inline DWORD GetCreationDisposition(bool createAlways) { return createAlways? CREATE_ALWAYS: CREATE_NEW; } bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition) { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } bool COutFile::Create(LPCTSTR fileName, bool createAlways) { return Open(fileName, GetCreationDisposition(createAlways)); } bool COutFile::CreateAlways(LPCTSTR fileName, DWORD /* flagsAndAttributes */ ) { return Open(fileName, true); // FIXME } #ifndef _UNICODE bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition) { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } bool COutFile::Create(LPCWSTR fileName, bool createAlways) { return Open(fileName, GetCreationDisposition(createAlways)); } #endif bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) { LARGE_INTEGER ltime; DWORD dw; if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } /* On some OS (cygwin, MacOSX ...), you must close the file before updating times */ if (aTime) { ltime.QuadPart = aTime->dwHighDateTime; ltime.QuadPart = (ltime.QuadPart << 32) | aTime->dwLowDateTime; RtlTimeToSecondsSince1970( <ime, &dw ); _lastAccessTime = dw; } if (mTime) { ltime.QuadPart = mTime->dwHighDateTime; ltime.QuadPart = (ltime.QuadPart << 32) | mTime->dwLowDateTime; RtlTimeToSecondsSince1970( <ime, &dw ); _lastWriteTime = dw; } return true; } bool COutFile::SetMTime(const FILETIME *mTime) { return SetTime(NULL, NULL, mTime); } bool COutFile::WritePart(const void *data, UINT32 size, UINT32 &processedSize) { // if (size > kChunkSizeMax) // size = kChunkSizeMax; return Write(data,size,processedSize); } bool COutFile::Write(const void *buffer, UINT32 bytesToWrite, UINT32 &bytesWritten) { if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } ssize_t ret; do { ret = write(_fd,buffer, bytesToWrite); } while (ret < 0 && (errno == EINTR)); if (ret != -1) { bytesWritten = ret; return TRUE; } bytesWritten =0; return FALSE; } bool COutFile::SetEndOfFile() { if (_fd == -1) { SetLastError( ERROR_INVALID_HANDLE ); return false; } bool bret = false; off_t pos_cur = lseek(_fd, 0, SEEK_CUR); if (pos_cur != (off_t)-1) { int iret = ftruncate(_fd, pos_cur); if (iret == 0) bret = true; } return bret; } bool COutFile::SetLength(UINT64 length) { UINT64 newPosition; if(!Seek(length, newPosition)) return false; if(newPosition != length) return false; return SetEndOfFile(); } }}} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileIO.h0100777000000000000000000000604713761647206022037 0ustar00// Windows/FileIO.h #ifndef __WINDOWS_FILEIO_H #define __WINDOWS_FILEIO_H #include #ifndef _WIN32 #define FILE_SHARE_READ 1 #define FILE_SHARE_WRITE 2 #define FILE_BEGIN SEEK_SET #define FILE_CURRENT SEEK_CUR #define FILE_END SEEK_END #define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif namespace NWindows { namespace NFile { namespace NIO { class CFileBase { protected: int _fd; AString _unix_filename; time_t _lastAccessTime; time_t _lastWriteTime; #ifdef ENV_HAVE_LSTAT int _size; char _buffer[MAX_PATHNAME_LEN+1]; int _offset; #endif bool Create(LPCSTR fileName, DWORD desiredAccess, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink=false); bool Create(LPCWSTR fileName, DWORD desiredAccess, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink=false); public: CFileBase(): _fd(-1) {}; virtual ~CFileBase(); virtual bool Close(); bool GetLength(UINT64 &length) const; bool Seek(INT64 distanceToMove, DWORD moveMethod, UINT64 &newPosition); bool Seek(UINT64 position, UINT64 &newPosition); }; class CInFile: public CFileBase { public: bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool OpenShared(LPCTSTR fileName, bool /* shareForWrite */ ,bool ignoreSymbolicLink=false) { return Open(fileName,ignoreSymbolicLink); } bool Open(LPCTSTR fileName,bool ignoreSymbolicLink=false); #ifndef _UNICODE bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool OpenShared(LPCWSTR fileName, bool /* shareForWrite */ ,bool ignoreSymbolicLink=false) { return Open(fileName,ignoreSymbolicLink); } bool Open(LPCWSTR fileName,bool ignoreSymbolicLink=false); #endif bool ReadPart(void *data, UINT32 size, UINT32 &processedSize); bool Read(void *data, UINT32 size, UINT32 &processedSize); }; class COutFile: public CFileBase { public: bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool Open(LPCTSTR fileName, DWORD creationDisposition); bool Create(LPCTSTR fileName, bool createAlways); bool CreateAlways(LPCTSTR fileName, DWORD flagsAndAttributes); #ifndef _UNICODE bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool Open(LPCWSTR fileName, DWORD creationDisposition); bool Create(LPCWSTR fileName, bool createAlways); #endif /* void SetOpenCreationDisposition(DWORD creationDisposition) { m_CreationDisposition = creationDisposition; } void SetOpenCreationDispositionCreateAlways() { m_CreationDisposition = CREATE_ALWAYS; } */ bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); bool SetMTime(const FILETIME *mTime); bool WritePart(const void *data, UINT32 size, UINT32 &processedSize); bool Write(const void *data, UINT32 size, UINT32 &processedSize); bool SetEndOfFile(); bool SetLength(UINT64 length); }; }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileName.cpp0100777000000000000000000000161713761647206022741 0ustar00// Windows/FileName.cpp #include "StdAfx.h" #include "Windows/FileName.h" #include "Common/Wildcard.h" // FIXME namespace NWindows { namespace NFile { namespace NDir { bool MyGetFullPathName(CFSTR path, FString &resFullPath); }}} namespace NWindows { namespace NFile { namespace NName { bool IsAbsolutePath(const wchar_t *s) { return s[0] == WCHAR_PATH_SEPARATOR; } // FIXME void NormalizeDirPathPrefix(CSysString &dirPath) { if (dirPath.IsEmpty()) return; if (dirPath.ReverseFind(kDirDelimiter) != dirPath.Len() - 1) dirPath += kDirDelimiter; } #ifndef _UNICODE void NormalizeDirPathPrefix(UString &dirPath) { if (dirPath.IsEmpty()) return; if (dirPath.ReverseFind(wchar_t(kDirDelimiter)) != dirPath.Len() - 1) dirPath += wchar_t(kDirDelimiter); } #endif bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) { res = FString(dirPrefix) + FString(s); return true; } }}} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/FileName.h0100777000000000000000000000122413761647206022400 0ustar00// Windows/FileName.h #ifndef __WINDOWS_FILENAME_H #define __WINDOWS_FILENAME_H #include "../../C/7zTypes.h" #include "../Common/MyString.h" namespace NWindows { namespace NFile { namespace NName { const TCHAR kDirDelimiter = CHAR_PATH_SEPARATOR; const TCHAR kAnyStringWildcard = '*'; void NormalizeDirPathPrefix(CSysString &dirPath); // ensures that it ended with '\\' #ifndef _UNICODE void NormalizeDirPathPrefix(UString &dirPath); // ensures that it ended with '\\' #endif bool IsAbsolutePath(const wchar_t *s); bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath); // FIXME bool GetFullPath(CFSTR path, FString &fullPath); }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/PropVariant.cpp0100777000000000000000000001410113761647206023516 0ustar00// Windows/PropVariant.cpp #include "StdAfx.h" #include "../Common/Defs.h" #include "PropVariant.h" namespace NWindows { namespace NCOM { HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() { p->bstrVal = ::SysAllocStringLen(0, numChars); if (!p->bstrVal) { p->vt = VT_ERROR; p->scode = E_OUTOFMEMORY; return E_OUTOFMEMORY; } p->vt = VT_BSTR; return S_OK; } HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() { UINT len = (UINT)strlen(s); p->bstrVal = ::SysAllocStringLen(0, len); if (!p->bstrVal) { p->vt = VT_ERROR; p->scode = E_OUTOFMEMORY; return E_OUTOFMEMORY; } p->vt = VT_BSTR; BSTR dest = p->bstrVal; for (UINT i = 0; i <= len; i++) dest[i] = s[i]; return S_OK; } CPropVariant::CPropVariant(const PROPVARIANT &varSrc) { vt = VT_EMPTY; InternalCopy(&varSrc); } CPropVariant::CPropVariant(const CPropVariant &varSrc) { vt = VT_EMPTY; InternalCopy(&varSrc); } CPropVariant::CPropVariant(BSTR bstrSrc) { vt = VT_EMPTY; *this = bstrSrc; } CPropVariant::CPropVariant(LPCOLESTR lpszSrc) { vt = VT_EMPTY; *this = lpszSrc; } CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) { InternalCopy(&varSrc); return *this; } CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) { InternalCopy(&varSrc); return *this; } CPropVariant& CPropVariant::operator=(BSTR bstrSrc) { *this = (LPCOLESTR)bstrSrc; return *this; } static const char *kMemException = "out of memory"; CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) { InternalClear(); vt = VT_BSTR; wReserved1 = 0; bstrVal = ::SysAllocString(lpszSrc); if (!bstrVal && lpszSrc) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } return *this; } CPropVariant& CPropVariant::operator=(const char *s) { InternalClear(); vt = VT_BSTR; wReserved1 = 0; UINT len = (UINT)strlen(s); bstrVal = ::SysAllocStringLen(0, len); if (!bstrVal) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } else { for (UINT i = 0; i <= len; i++) bstrVal[i] = s[i]; } return *this; } CPropVariant& CPropVariant::operator=(bool bSrc) throw() { if (vt != VT_BOOL) { InternalClear(); vt = VT_BOOL; } boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; return *this; } BSTR CPropVariant::AllocBstr(unsigned numChars) { if (vt != VT_EMPTY) InternalClear(); vt = VT_BSTR; wReserved1 = 0; bstrVal = ::SysAllocStringLen(0, numChars); if (!bstrVal) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } return bstrVal; } #define SET_PROP_FUNC(type, id, dest) \ CPropVariant& CPropVariant::operator=(type value) throw() \ { if (vt != id) { InternalClear(); vt = id; } \ dest = value; return *this; } SET_PROP_FUNC(Byte, VT_UI1, bVal) // SET_PROP_FUNC(Int16, VT_I2, iVal) SET_PROP_FUNC(Int32, VT_I4, lVal) SET_PROP_FUNC(UInt32, VT_UI4, ulVal) SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() { switch (prop->vt) { case VT_EMPTY: case VT_UI1: case VT_I1: case VT_I2: case VT_UI2: case VT_BOOL: case VT_I4: case VT_UI4: case VT_R4: case VT_INT: case VT_UINT: case VT_ERROR: case VT_FILETIME: case VT_UI8: case VT_R8: case VT_CY: case VT_DATE: prop->vt = VT_EMPTY; prop->wReserved1 = 0; prop->wReserved2 = 0; prop->wReserved3 = 0; prop->uhVal.QuadPart = 0; return S_OK; } return ::VariantClear((VARIANTARG *)prop); // return ::PropVariantClear(prop); // PropVariantClear can clear VT_BLOB. } HRESULT CPropVariant::Clear() throw() { if (vt == VT_EMPTY) return S_OK; return PropVariant_Clear(this); } HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() { ::VariantClear((tagVARIANT *)this); switch(pSrc->vt) { case VT_UI1: case VT_I1: case VT_I2: case VT_UI2: case VT_BOOL: case VT_I4: case VT_UI4: case VT_R4: case VT_INT: case VT_UINT: case VT_ERROR: case VT_FILETIME: case VT_UI8: case VT_R8: case VT_CY: case VT_DATE: memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); return S_OK; } return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast(pSrc)); } HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() { HRESULT hr = Clear(); if (FAILED(hr)) return hr; memcpy(this, pSrc, sizeof(PROPVARIANT)); pSrc->vt = VT_EMPTY; return S_OK; } HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() { if (pDest->vt != VT_EMPTY) { HRESULT hr = PropVariant_Clear(pDest); if (FAILED(hr)) return hr; } memcpy(pDest, this, sizeof(PROPVARIANT)); vt = VT_EMPTY; return S_OK; } HRESULT CPropVariant::InternalClear() throw() { if (vt == VT_EMPTY) return S_OK; HRESULT hr = Clear(); if (FAILED(hr)) { vt = VT_ERROR; scode = hr; } return hr; } void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) { HRESULT hr = Copy(pSrc); if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) throw kMemException; vt = VT_ERROR; scode = hr; } } int CPropVariant::Compare(const CPropVariant &a) throw() { if (vt != a.vt) return MyCompare(vt, a.vt); switch (vt) { case VT_EMPTY: return 0; // case VT_I1: return MyCompare(cVal, a.cVal); case VT_UI1: return MyCompare(bVal, a.bVal); case VT_I2: return MyCompare(iVal, a.iVal); case VT_UI2: return MyCompare(uiVal, a.uiVal); case VT_I4: return MyCompare(lVal, a.lVal); case VT_UI4: return MyCompare(ulVal, a.ulVal); // case VT_UINT: return MyCompare(uintVal, a.uintVal); case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); case VT_BOOL: return -MyCompare(boolVal, a.boolVal); case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); case VT_BSTR: return 0; // Not implemented default: return 0; } } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/PropVariant.h0100777000000000000000000000573413761647206023177 0ustar00// Windows/PropVariant.h #ifndef __WINDOWS_PROP_VARIANT_H #define __WINDOWS_PROP_VARIANT_H #include "../Common/MyTypes.h" #include "../Common/MyWindows.h" namespace NWindows { namespace NCOM { HRESULT PropVariant_Clear(PROPVARIANT *p) throw(); HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw(); HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw(); inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw() { p->vt = VT_UI4; p->ulVal = v; } inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw() { p->vt = VT_UI8; p->uhVal.QuadPart = v; } inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw() { p->vt = VT_FILETIME; p->filetime.dwLowDateTime = (DWORD)v; p->filetime.dwHighDateTime = (DWORD)(v >> 32); } inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() { p->vt = VT_BOOL; p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE); } class CPropVariant : public tagPROPVARIANT { public: CPropVariant() { vt = VT_EMPTY; wReserved1 = 0; // wReserved2 = 0; // wReserved3 = 0; // uhVal.QuadPart = 0; bstrVal = 0; } ~CPropVariant() throw() { Clear(); } CPropVariant(const PROPVARIANT &varSrc); CPropVariant(const CPropVariant &varSrc); CPropVariant(BSTR bstrSrc); CPropVariant(LPCOLESTR lpszSrc); CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }; CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } private: CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } public: CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } CPropVariant(Int64 value) { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } CPropVariant& operator=(const CPropVariant &varSrc); CPropVariant& operator=(const PROPVARIANT &varSrc); CPropVariant& operator=(BSTR bstrSrc); CPropVariant& operator=(LPCOLESTR lpszSrc); CPropVariant& operator=(const char *s); CPropVariant& operator=(bool bSrc) throw(); CPropVariant& operator=(Byte value) throw(); private: CPropVariant& operator=(Int16 value) throw(); public: CPropVariant& operator=(Int32 value) throw(); CPropVariant& operator=(UInt32 value) throw(); CPropVariant& operator=(UInt64 value) throw(); CPropVariant& operator=(Int64 value) throw(); CPropVariant& operator=(const FILETIME &value) throw(); BSTR AllocBstr(unsigned numChars); HRESULT Clear() throw(); HRESULT Copy(const PROPVARIANT *pSrc) throw(); HRESULT Attach(PROPVARIANT *pSrc) throw(); HRESULT Detach(PROPVARIANT *pDest) throw(); HRESULT InternalClear() throw(); void InternalCopy(const PROPVARIANT *pSrc); int Compare(const CPropVariant &a) throw(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/PropVariantConv.cpp0100777000000000000000000000643313761647206024355 0ustar00// PropVariantConvert.cpp #include "StdAfx.h" #include "../Common/IntToString.h" #include "Defs.h" #include "PropVariantConv.h" #define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds) throw() { SYSTEMTIME st; if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) { *s = 0; return false; } unsigned val = st.wYear; if (val >= 10000) { *s++ = (char)('0' + val / 10000); val %= 10000; } { s[3] = (char)('0' + val % 10); val /= 10; s[2] = (char)('0' + val % 10); val /= 10; s[1] = (char)('0' + val % 10); s[0] = (char)('0' + val / 10); s += 4; } UINT_TO_STR_2('-', st.wMonth); UINT_TO_STR_2('-', st.wDay); if (includeTime) { UINT_TO_STR_2(' ', st.wHour); UINT_TO_STR_2(':', st.wMinute); if (includeSeconds) UINT_TO_STR_2(':', st.wSecond); } *s = 0; return true; } void ConvertFileTimeToString(const FILETIME &ft, wchar_t *dest, bool includeTime, bool includeSeconds) throw() { char s[32]; ConvertFileTimeToString(ft, s, includeTime, includeSeconds); for (unsigned i = 0;; i++) { unsigned char c = s[i]; dest[i] = c; if (c == 0) return; } } void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw() { *dest = 0; switch (prop.vt) { case VT_EMPTY: return; case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; case VT_FILETIME: ConvertFileTimeToString(prop.filetime, dest, true, true); return; // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2); } } void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw() { *dest = 0; switch (prop.vt) { case VT_EMPTY: return; case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; case VT_FILETIME: ConvertFileTimeToString(prop.filetime, dest, true, true); return; // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2); } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/PropVariantConv.h0100777000000000000000000000210213761647206024007 0ustar00// Windows/PropVariantConv.h #ifndef __PROP_VARIANT_CONV_H #define __PROP_VARIANT_CONV_H #include "../Common/MyTypes.h" // provide at least 32 bytes for buffer including zero-end bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true) throw(); void ConvertFileTimeToString(const FILETIME &ft, wchar_t *s, bool includeTime = true, bool includeSeconds = true) throw(); // provide at least 32 bytes for buffer including zero-end // don't send VT_BSTR to these functions void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(); void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw(); inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value) { switch (prop.vt) { case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true; case VT_UI4: value = prop.ulVal; return true; case VT_UI2: value = prop.uiVal; return true; case VT_UI1: value = prop.bVal; return true; case VT_EMPTY: return false; default: throw 151199; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Synchronization.cpp0100777000000000000000000001336313761647206024463 0ustar00// Windows/Synchronization.cpp #include "StdAfx.h" #include "Synchronization.h" // #define TRACEN(u) u; #define TRACEN(u) /* */ #define MAGIC 0x1234CAFE class CSynchroTest { int _magic; public: CSynchroTest() { _magic = MAGIC; } void testConstructor() { if (_magic != MAGIC) { printf("ERROR : no constructors called during loading of plugins (please look at LINK_SHARED in makefile.machine)\n"); exit(EXIT_FAILURE); } } }; static CSynchroTest gbl_synchroTest; extern "C" void sync_TestConstructor(void) { gbl_synchroTest.testConstructor(); } namespace NWindows { namespace NSynchronization { #ifndef ENV_BEOS #ifdef DEBUG_SYNCHRO void CSynchro::dump_error(int ligne,int ret,const char *text,void *param) { printf("\n##T%d#ERROR2 (l=%d) %s : param=%p ret = %d (%s)##\n",(int)pthread_self(),ligne,text,param,ret,strerror(ret)); // abort(); } CSynchro::CSynchro() { TRACEN((printf("\nT%d : E1-CSynchro(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond))) _isValid = false; } void CSynchro::Create() { TRACEN((printf("\nT%d : E1-CSynchro::Create(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond))) pthread_mutexattr_t mutexattr; memset(&mutexattr,0,sizeof(mutexattr)); int ret = pthread_mutexattr_init(&mutexattr); if (ret != 0) { dump_error(__LINE__,ret,"pthread_mutexattr_init",&mutexattr); } ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK); if (ret != 0) dump_error(__LINE__,ret,"pthread_mutexattr_settype",&mutexattr); ret = ::pthread_mutex_init(&_object,&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"pthread_mutex_init",&_object); ret = ::pthread_cond_init(&_cond,0); if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_init",&_cond); TRACEN((printf("\nT%d : E2-CSynchro::Create(m=%p,cond=%p)\n",(int)pthread_self(),(void *)&_object,(void *)&_cond))) } CSynchro::~CSynchro() { TRACEN((printf("\nT%d : E1-~CSynchro(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond))) if (_isValid) { int ret = ::pthread_mutex_destroy(&_object); if (ret != 0) dump_error(__LINE__,ret,"pthread_mutex_destroy",&_object); ret = ::pthread_cond_destroy(&_cond); if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_destroy",&_cond); TRACEN((printf("\nT%d : E2-~CSynchro(m=%p,cond=%p)\n",(int)pthread_self(),(void *)&_object,(void *)&_cond))) } _isValid = false; } void CSynchro::Enter() { TRACEN((printf("\nT%d : E1-CSynchro::Enter(%p)\n",(int)pthread_self(),(void *)&_object))) int ret = ::pthread_mutex_lock(&_object); if (ret != 0) { dump_error(__LINE__,ret,"CSynchro::Enter-pthread_mutex_lock",&_object); } TRACEN((printf("\nT%d : E2-CSynchro::Enter(%p)\n",(int)pthread_self(),(void *)&_object))) } void CSynchro::Leave() { TRACEN((printf("\nT%d : E1-CSynchro::Leave(%p)\n",(int)pthread_self(),(void *)&_object))) int ret = ::pthread_mutex_unlock(&_object); if (ret != 0) dump_error(__LINE__,ret,"Leave::pthread_mutex_unlock",&_object); TRACEN((printf("\nT%d : E2-CSynchro::Leave(%p)\n",(int)pthread_self(),(void *)&_object))) } void CSynchro::WaitCond() { TRACEN((printf("\nT%d : E1-CSynchro::WaitCond(%p,%p)\n",(int)pthread_self(),(void *)&_cond,(void *)&_object))) int ret = ::pthread_cond_wait(&_cond, &_object); if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_wait",&_cond); TRACEN((printf("\nT%d : E2-CSynchro::WaitCond(%p,%p)\n",(int)pthread_self(),(void *)&_cond,(void *)&_object))) } void CSynchro::LeaveAndSignal() { TRACEN((printf("\nT%d : E1-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_cond))) int ret = ::pthread_cond_broadcast(&_cond); if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_broadcast",&_cond); TRACEN((printf("\nT%d : E2-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_object))) ret = ::pthread_mutex_unlock(&_object); if (ret != 0) dump_error(__LINE__,ret,"LeaveAndSignal::pthread_mutex_unlock",&_object); TRACEN((printf("\nT%d : E3-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_cond))) } #endif #endif }} DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout ) { TRACEN((printf("\nT%d : E1-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count))) if (wait_all != FALSE) { printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) wait_all(%d) != FALSE\n\n",(unsigned)wait_all); abort(); } if (timeout != INFINITE) { printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) timeout(%u) != INFINITE\n\n",(unsigned)timeout); abort(); } if (count < 1) { printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) count(%u) < 1\n\n",(unsigned)count); abort(); } NWindows::NSynchronization::CSynchro *synchro = handles[0]->_sync; TRACEN((printf("\nT%d : E2-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count))) synchro->Enter(); TRACEN((printf("\nT%d : E3-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count))) #ifdef DEBUG_SYNCHRO for(DWORD i=1;i_sync) { printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) synchro(%p) != handles[%d]->_sync(%p)\n\n", synchro,(unsigned)i,handles[i]->_sync); abort(); } } #endif while(1) { for(DWORD i=0;iIsSignaledAndUpdate()) { synchro->Leave(); TRACEN((printf("\nT%d : E4-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count))) return WAIT_OBJECT_0+i; } } synchro->WaitCond(); } synchro->Leave(); return ETIMEDOUT; // WAIT_TIMEOUT; } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Synchronization.h0100777000000000000000000001075113761647206024126 0ustar00// Windows/Synchronization.h #ifndef __WINDOWS_SYNCHRONIZATION_H #define __WINDOWS_SYNCHRONIZATION_H #include "Defs.h" extern "C" { #include "../../C/Threads.h" } #ifdef _WIN32 #include "Handle.h" #endif namespace NWindows { namespace NSynchronization { class Uncopyable { protected: Uncopyable() {} // allow construction ~Uncopyable() {} // and destruction of derived objects... private: Uncopyable(const Uncopyable&); // ...but prevent copying Uncopyable& operator=(const Uncopyable&); }; class CBaseEvent // FIXME : private Uncopyable { protected: ::CEvent _object; public: bool IsCreated() { return Event_IsCreated(&_object) != 0; } #ifdef _WIN32 operator HANDLE() { return _object.handle; } #endif CBaseEvent() { Event_Construct(&_object); } ~CBaseEvent() { Close(); } WRes Close() { return Event_Close(&_object); } #ifdef _WIN32 WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES securityAttributes = NULL) { _object.handle = ::CreateEvent(securityAttributes, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); if (_object.handle != 0) return 0; return ::GetLastError(); } WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) { _object.handle = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); if (_object.handle != 0) return 0; return ::GetLastError(); } #endif WRes Set() { return Event_Set(&_object); } // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } WRes Reset() { return Event_Reset(&_object); } WRes Lock() { return Event_Wait(&_object); } }; class CManualResetEvent: public CBaseEvent { public: WRes Create(bool initiallyOwn = false) { return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); } WRes CreateIfNotCreated() { if (IsCreated()) return 0; return ManualResetEvent_CreateNotSignaled(&_object); } #ifdef _WIN32 WRes CreateWithName(bool initiallyOwn, LPCTSTR name) { return CBaseEvent::Create(true, initiallyOwn, name); } #endif }; class CAutoResetEvent: public CBaseEvent { public: WRes Create() { return AutoResetEvent_CreateNotSignaled(&_object); } WRes CreateIfNotCreated() { if (IsCreated()) return 0; return AutoResetEvent_CreateNotSignaled(&_object); } }; #ifdef _WIN32 class CObject: public CHandle { public: WRes Lock(DWORD timeoutInterval = INFINITE) { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } }; class CMutex: public CObject { public: WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES securityAttributes = NULL) { _handle = ::CreateMutex(securityAttributes, BoolToBOOL(initiallyOwn), name); if (_handle != 0) return 0; return ::GetLastError(); } WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) { _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); if (_handle != 0) return 0; return ::GetLastError(); } WRes Release() { return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); } }; class CMutexLock { CMutex *_object; public: CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } ~CMutexLock() { _object->Release(); } }; #endif class CSemaphore : private Uncopyable { ::CSemaphore _object; public: CSemaphore() { Semaphore_Construct(&_object); } ~CSemaphore() { Close(); } WRes Close() { return Semaphore_Close(&_object); } #ifdef _WIN32 operator HANDLE() { return _object.handle; } #endif WRes Create(UInt32 initiallyCount, UInt32 maxCount) { return Semaphore_Create(&_object, initiallyCount, maxCount); } WRes Release() { return Semaphore_Release1(&_object); } WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } WRes Lock() { return Semaphore_Wait(&_object); } }; class CCriticalSection : private Uncopyable { ::CCriticalSection _object; public: CCriticalSection() { CriticalSection_Init(&_object); } ~CCriticalSection() { CriticalSection_Delete(&_object); } void Enter() { CriticalSection_Enter(&_object); } void Leave() { CriticalSection_Leave(&_object); } }; class CCriticalSectionLock : private Uncopyable { CCriticalSection *_object; void Unlock() { _object->Leave(); } public: CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } ~CCriticalSectionLock() { Unlock(); } }; }} #ifndef _WIN32 #include "Synchronization2.h" #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Synchronization2.h0100777000000000000000000001157513761647206024215 0ustar00// Windows/Synchronization.h #ifdef ENV_BEOS #include #include #include #endif /* Remark : WFMO = WaitForMultipleObjects */ namespace NWindows { namespace NSynchronization { struct CBaseHandleWFMO; } } typedef NWindows::NSynchronization::CBaseHandleWFMO *HANDLE; DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout ); namespace NWindows { namespace NSynchronization { #ifdef ENV_BEOS class CSynchro : BLocker, private Uncopyable { #define MAX_THREAD 256 thread_id _waiting[MAX_THREAD]; // std::list _waiting; int index_waiting; public: CSynchro() { index_waiting = 0; } void Create() { index_waiting = 0; } ~CSynchro() {} void Enter() { Lock(); } void Leave() { Unlock(); } void WaitCond() { _waiting[index_waiting++] = find_thread(NULL); // _waiting.push_back(find_thread(NULL)); thread_id sender; Unlock(); int msg = receive_data(&sender, NULL, 0); Lock(); } void LeaveAndSignal() { // Unlock(); // Lock(); // for (std::list::iterator index = _waiting.begin(); index != _waiting.end(); index++) for(int index = 0 ; index < index_waiting ; index++) { send_data(_waiting[index], '7zCN', NULL, 0); } index_waiting = 0; // _waiting.clear(); Unlock(); } }; #else // #ifdef ENV_BEOS #ifdef DEBUG_SYNCHRO class CSynchro: private Uncopyable { pthread_mutex_t _object; pthread_cond_t _cond; bool _isValid; void dump_error(int ligne,int ret,const char *text,void *param); public: CSynchro(); ~CSynchro(); void Create(); void Enter(); void Leave(); void WaitCond(); void LeaveAndSignal(); }; #else // #ifdef DEBUG_SYNCHRO class CSynchro : private Uncopyable { pthread_mutex_t _object; pthread_cond_t _cond; bool _isValid; public: CSynchro() { _isValid = false; } ~CSynchro() { if (_isValid) { ::pthread_mutex_destroy(&_object); ::pthread_cond_destroy(&_cond); } _isValid = false; } void Create() { ::pthread_mutex_init(&_object,0); ::pthread_cond_init(&_cond,0); } void Enter() { ::pthread_mutex_lock(&_object); } void Leave() { ::pthread_mutex_unlock(&_object); } void WaitCond() { ::pthread_cond_wait(&_cond, &_object); } void LeaveAndSignal() { ::pthread_cond_broadcast(&_cond); ::pthread_mutex_unlock(&_object); } }; #endif // #ifdef DEBUG_SYNCHRO #endif // #ifdef ENV_BEOS struct CBaseHandleWFMO // FIXME : private Uncopyable { CSynchro *_sync; CBaseHandleWFMO() { } operator HANDLE() { return this; } virtual bool IsSignaledAndUpdate() = 0; }; class CBaseEventWFMO : public CBaseHandleWFMO { bool _manual_reset; bool _state; public: bool IsCreated() { return (this->_sync != 0); } CBaseEventWFMO() { this->_sync = 0; } ~CBaseEventWFMO() { Close(); } WRes Close() { this->_sync = 0; return S_OK; } WRes Create(CSynchro *sync,bool manualReset, bool initiallyOwn) { this->_sync = sync; this->_manual_reset = manualReset; this->_state = initiallyOwn; return S_OK; } WRes Set() { this->_sync->Enter(); this->_state = true; this->_sync->LeaveAndSignal(); return S_OK; } WRes Reset() { this->_sync->Enter(); this->_state = false; this->_sync->Leave(); return S_OK; } virtual bool IsSignaledAndUpdate() { if (this->_state == true) { if (this->_manual_reset == false) this->_state = false; return true; } return false; } }; class CManualResetEventWFMO: public CBaseEventWFMO { public: WRes Create(CSynchro *sync,bool initiallyOwn = false) { return CBaseEventWFMO::Create(sync,true, initiallyOwn); } }; class CAutoResetEventWFMO: public CBaseEventWFMO { public: WRes Create(CSynchro *sync) { return CBaseEventWFMO::Create(sync,false, false); } WRes CreateIfNotCreated(CSynchro *sync) { if (IsCreated()) return 0; return CBaseEventWFMO::Create(sync,false, false); } }; class CSemaphoreWFMO : public CBaseHandleWFMO { LONG _count; LONG _maxCount; public: CSemaphoreWFMO() : _count(0), _maxCount(0) { this->_sync=0;} WRes Create(CSynchro *sync,LONG initiallyCount, LONG maxCount) { if ((initiallyCount < 0) || (initiallyCount > maxCount) || (maxCount < 1)) return S_FALSE; this->_sync = sync; this->_count = initiallyCount; this->_maxCount = maxCount; return S_OK; } WRes Release(LONG releaseCount = 1) { if (releaseCount < 1) return S_FALSE; this->_sync->Enter(); LONG newCount = this->_count + releaseCount; if (newCount > this->_maxCount) { this->_sync->Leave(); return S_FALSE; } this->_count = newCount; this->_sync->LeaveAndSignal(); return S_OK; } WRes Close() { this->_sync=0; return S_OK; } virtual bool IsSignaledAndUpdate() { if (this->_count > 0) { this->_count--; return true; } return false; } }; }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/System.cpp0100777000000000000000000001052013761647206022536 0ustar00#include #include #if defined (__NetBSD__) || defined(__OpenBSD__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) #include #include #elif defined(__linux__) || defined(__CYGWIN__) || defined(sun) || defined(__NETWARE__) #include #elif defined(hpux) || defined(__hpux) #include #include #endif #if defined(__NETWARE__) #include #endif #if defined(ENV_BEOS) #include #endif #include "Common/MyTypes.h" namespace NWindows { namespace NSystem { /************************ GetNumberOfProcessors ************************/ #if defined (__NetBSD__) || defined(__OpenBSD__) UInt32 GetNumberOfProcessors() { int mib[2], value; int nbcpu = 1; mib[0] = CTL_HW; mib[1] = HW_NCPU; size_t len = sizeof(size_t); if (sysctl(mib, 2, &value, &len, NULL, 0) >= 0) if (value > nbcpu) nbcpu = value; return nbcpu; } #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) UInt32 GetNumberOfProcessors() { int nbcpu = 1; size_t value; size_t len = sizeof(value); if (sysctlbyname("hw.ncpu", &value, &len, NULL, 0) == 0) nbcpu = value; return nbcpu; } #elif defined (__APPLE__) UInt32 GetNumberOfProcessors() { int nbcpu = 1,value; size_t valSize = sizeof(value); if (sysctlbyname ("hw.ncpu", &value, &valSize, NULL, 0) == 0) nbcpu = value; return nbcpu; } #elif defined(__linux__) || defined(__CYGWIN__) || defined(sun) UInt32 GetNumberOfProcessors() { int nbcpu = sysconf (_SC_NPROCESSORS_CONF); if (nbcpu < 1) nbcpu = 1; return nbcpu; } #elif defined(hpux) || defined(__hpux) UInt32 GetNumberOfProcessors() { struct pst_dynamic psd; if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) return (UInt32)psd.psd_proc_cnt; return 1; } #elif defined(__NETWARE__) UInt32 GetNumberOfProcessors() { // int nbcpu = get_nprocs_conf(); int nbcpu = get_nprocs(); if (nbcpu < 1) nbcpu = 1; return nbcpu; } #elif defined(ENV_BEOS) UInt32 GetNumberOfProcessors() { system_info info; get_system_info(&info); int nbcpu = info.cpu_count; if (nbcpu < 1) nbcpu = 1; return nbcpu; } #else #warning Generic GetNumberOfProcessors UInt32 GetNumberOfProcessors() { return 1; } #endif /************************ GetRamSize ************************/ UInt64 GetRamSize() { UInt64 ullTotalPhys = 128 * 1024 * 1024; // default : 128MB #ifdef linux FILE * f = fopen( "/proc/meminfo", "r" ); if (f) { char buffer[256]; unsigned long total; ullTotalPhys = 0; while (fgets( buffer, sizeof(buffer), f )) { /* old style /proc/meminfo ... */ if (sscanf( buffer, "Mem: %lu", &total)) { ullTotalPhys += total; } /* new style /proc/meminfo ... */ if (sscanf(buffer, "MemTotal: %lu", &total)) ullTotalPhys = ((UInt64)total)*1024; } fclose( f ); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__APPLE__) #ifdef HW_MEMSIZE uint64_t val = 0; // support 2Gb+ RAM int mib[2] = { CTL_HW, HW_MEMSIZE }; #else // HW_MEMSIZE unsigned int val = 0; // For old system int mib[2] = { CTL_HW, HW_PHYSMEM }; #endif // HW_MEMSIZE size_t size_sys = sizeof(val); sysctl(mib, 2, &val, &size_sys, NULL, 0); if (val) ullTotalPhys = val; #elif defined(__CYGWIN__) unsigned long pagesize=4096; // FIXME - sysconf(_SC_PAGESIZE) returns 65536 !? // see http://readlist.com/lists/cygwin.com/cygwin/0/3313.html unsigned long maxpages=sysconf(_SC_PHYS_PAGES); ullTotalPhys = ((UInt64)pagesize)*maxpages; #elif defined ( sun ) || defined(__NETWARE__) unsigned long pagesize=sysconf(_SC_PAGESIZE); unsigned long maxpages=sysconf(_SC_PHYS_PAGES); ullTotalPhys = ((UInt64)pagesize)*maxpages; #elif defined(hpux) || defined(__hpux) struct pst_static pst; union pstun pu; pu.pst_static = &pst; if ( pstat( PSTAT_STATIC, pu, (size_t)sizeof(pst), (size_t)0, 0 ) != -1 ) { ullTotalPhys = ((UInt64)pst.physical_memory)*pst.page_size; } #elif defined(ENV_BEOS) system_info info; get_system_info(&info); ullTotalPhys = info.max_pages; ullTotalPhys *= 4096; #else #warning Generic GetRamSize #endif return ullTotalPhys; } } } qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/System.h0100777000000000000000000000032713761647206022207 0ustar00// Windows/System.h #ifndef __WINDOWS_SYSTEM_H #define __WINDOWS_SYSTEM_H #include "../Common/MyTypes.h" namespace NWindows { namespace NSystem { UInt32 GetNumberOfProcessors(); UInt64 GetRamSize(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Thread.h0100777000000000000000000000217413761647206022134 0ustar00// Windows/Thread.h #ifndef __WINDOWS_THREAD_H #define __WINDOWS_THREAD_H #include "Defs.h" extern "C" { #include "../../C/Threads.h" } namespace NWindows { class CThread { ::CThread thread; public: CThread() { Thread_Construct(&thread); } ~CThread() { Close(); } bool IsCreated() { return Thread_WasCreated(&thread) != 0; } WRes Close() { return Thread_Close(&thread); } WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) { return Thread_Create(&thread, startAddress, parameter); } WRes Wait() { return Thread_Wait(&thread); } #ifdef _WIN32 operator HANDLE() { return thread; } void Attach(HANDLE handle) { thread = handle; } HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } DWORD Resume() { return ::ResumeThread(thread); } DWORD Suspend() { return ::SuspendThread(thread); } bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } int GetPriority() { return ::GetThreadPriority(thread); } bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } #endif }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/TimeUtils.cpp0100777000000000000000000001256513761647206023204 0ustar00// Windows/TimeUtils.cpp #include "StdAfx.h" #include "Defs.h" #include "TimeUtils.h" namespace NWindows { namespace NTime { static const UInt32 kNumTimeQuantumsInSecond = 10000000; static const UInt32 kFileTimeStartYear = 1601; static const UInt32 kDosTimeStartYear = 1980; static const UInt32 kUnixTimeStartYear = 1970; static const UInt64 kUnixTimeOffset = (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() { #if defined(_WIN32) && !defined(UNDER_CE) return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); #else ft.dwLowDateTime = 0; ft.dwHighDateTime = 0; UInt64 res; if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F, (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res)) return false; res *= kNumTimeQuantumsInSecond; ft.dwLowDateTime = (UInt32)res; ft.dwHighDateTime = (UInt32)(res >> 32); return true; #endif } static const UInt32 kHighDosTime = 0xFF9FBF7D; static const UInt32 kLowDosTime = 0x210000; #define PERIOD_4 (4 * 365 + 1) #define PERIOD_100 (PERIOD_4 * 25 - 1) #define PERIOD_400 (PERIOD_100 * 4 + 1) bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() { #if defined(_WIN32) && !defined(UNDER_CE) WORD datePart, timePart; if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) { dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; return false; } dosTime = (((UInt32)datePart) << 16) + timePart; #else unsigned year, mon, day, hour, min, sec; UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; unsigned temp; UInt32 v; v64 += (kNumTimeQuantumsInSecond * 2 - 1); v64 /= kNumTimeQuantumsInSecond; sec = (unsigned)(v64 % 60); v64 /= 60; min = (unsigned)(v64 % 60); v64 /= 60; hour = (unsigned)(v64 % 24); v64 /= 24; v = (UInt32)v64; year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400); v %= PERIOD_400; temp = (unsigned)(v / PERIOD_100); if (temp == 4) temp = 3; year += temp * 100; v -= temp * PERIOD_100; temp = v / PERIOD_4; if (temp == 25) temp = 24; year += temp * 4; v -= temp * PERIOD_4; temp = v / 365; if (temp == 4) temp = 3; year += temp; v -= temp * 365; if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ms[1] = 29; for (mon = 1; mon <= 12; mon++) { unsigned s = ms[mon - 1]; if (v < s) break; v -= s; } day = (unsigned)v + 1; dosTime = kLowDosTime; if (year < kDosTimeStartYear) return false; year -= kDosTimeStartYear; dosTime = kHighDosTime; if (year >= 128) return false; dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1); #endif return true; } void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() { UInt64 v = (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; ft.dwLowDateTime = (DWORD)v; ft.dwHighDateTime = (DWORD)(v >> 32); } bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() { if (unixTime > kNumSecondsInFileTime - kUnixTimeOffset) { ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1; return false; } Int64 v = (Int64)kUnixTimeOffset + unixTime; if (v < 0) { ft.dwLowDateTime = ft.dwHighDateTime = 0; return false; } UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond; ft.dwLowDateTime = (DWORD)v2; ft.dwHighDateTime = (DWORD)(v2 >> 32); return true; } Int64 FileTimeToUnixTime64(const FILETIME &ft) throw() { UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; return (Int64)(winTime / kNumTimeQuantumsInSecond) - kUnixTimeOffset; } bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw() { UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; winTime /= kNumTimeQuantumsInSecond; if (winTime < kUnixTimeOffset) { unixTime = 0; return false; } winTime -= kUnixTimeOffset; if (winTime > 0xFFFFFFFF) { unixTime = 0xFFFFFFFF; return false; } unixTime = (UInt32)winTime; return true; } bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() { resSeconds = 0; if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) return false; UInt32 numYears = year - kFileTimeStartYear; UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400; Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ms[1] = 29; month--; for (unsigned i = 0; i < month; i++) numDays += ms[i]; numDays += day - 1; resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; return true; } void GetCurUtcFileTime(FILETIME &ft) throw() { // Both variants provide same low resolution on WinXP: about 15 ms. // But GetSystemTimeAsFileTime is much faster. #ifdef UNDER_CE SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); #else GetSystemTimeAsFileTime(&ft); #endif } }} qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/TimeUtils.h0100777000000000000000000000141213761647206022636 0ustar00// Windows/TimeUtils.h #ifndef __WINDOWS_TIME_UTILS_H #define __WINDOWS_TIME_UTILS_H #include "../Common/MyTypes.h" namespace NWindows { namespace NTime { bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw(); bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw(); bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw(); bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); Int64 FileTimeToUnixTime64(const FILETIME &ft) throw(); bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); void GetCurUtcFileTime(FILETIME &ft) throw(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/CPP/Windows/Windows.pri0100777000000000000000000000174013761647206022720 0ustar00HEADERS += $$7ZIP_BASE/CPP/Windows/DLL.h \ $$7ZIP_BASE/CPP/Windows/Defs.h \ $$7ZIP_BASE/CPP/Windows/FileDir.h \ $$7ZIP_BASE/CPP/Windows/FileFind.h \ $$7ZIP_BASE/CPP/Windows/FileIO.h \ $$7ZIP_BASE/CPP/Windows/FileName.h \ $$7ZIP_BASE/CPP/Windows/PropVariant.h \ $$7ZIP_BASE/CPP/Windows/PropVariantConv.h \ $$7ZIP_BASE/CPP/Windows/Synchronization.h \ $$7ZIP_BASE/CPP/Windows/Synchronization2.h \ $$7ZIP_BASE/CPP/Windows/System.h \ $$7ZIP_BASE/CPP/Windows/Thread.h \ $$7ZIP_BASE/CPP/Windows/TimeUtils.h SOURCES += $$7ZIP_BASE/CPP/Windows/DLL.cpp \ $$7ZIP_BASE/CPP/Windows/FileDir.cpp \ $$7ZIP_BASE/CPP/Windows/FileFind.cpp \ $$7ZIP_BASE/CPP/Windows/FileIO.cpp \ $$7ZIP_BASE/CPP/Windows/FileName.cpp \ $$7ZIP_BASE/CPP/Windows/PropVariant.cpp \ $$7ZIP_BASE/CPP/Windows/PropVariantConv.cpp \ $$7ZIP_BASE/CPP/Windows/Synchronization.cpp \ $$7ZIP_BASE/CPP/Windows/System.cpp \ $$7ZIP_BASE/CPP/Windows/TimeUtils.cpp qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zCrc.c0100777000000000000000000000400613761647206020012 0ustar00/* 7zCrc.c -- CRC32 init 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #define kCrcPoly 0xEDB88320 #ifdef MY_CPU_X86_OR_AMD64 #define CRC_NUM_TABLES 8 UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #elif defined(MY_CPU_LE) #define CRC_NUM_TABLES 4 #else #define CRC_NUM_TABLES 5 #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); CRC_FUNC g_CrcUpdate; UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) { return g_CrcUpdate(v, data, size, g_CrcTable); } UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) { return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } void MY_FAST_CALL CrcGenerateTable() { UInt32 i; for (i = 0; i < 256; i++) { UInt32 r = i; unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); g_CrcTable[i] = r; } for (; i < 256 * CRC_NUM_TABLES; i++) { UInt32 r = g_CrcTable[i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } #ifdef MY_CPU_LE g_CrcUpdate = CrcUpdateT4; #if CRC_NUM_TABLES == 8 #ifdef P7ZIP_USE_ASM if (!CPU_Is_InOrder()) g_CrcUpdate = CrcUpdateT8; #endif #endif #else { #ifndef MY_CPU_BE UInt32 k = 1; if (*(const Byte *)&k == 1) g_CrcUpdate = CrcUpdateT4; else #endif { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { UInt32 x = g_CrcTable[i - 256]; g_CrcTable[i] = CRC_UINT32_SWAP(x); } g_CrcUpdate = CrcUpdateT1_BeT4; } } #endif } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zCrc.h0100777000000000000000000000114413761647206020017 0ustar00/* 7zCrc.h -- CRC32 calculation 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_CRC_H #define __7Z_CRC_H #include "7zTypes.h" EXTERN_C_BEGIN extern UInt32 g_CrcTable[]; /* Call CrcGenerateTable one time before other CRC functions */ void MY_FAST_CALL CrcGenerateTable(void); #define CRC_INIT_VAL 0xFFFFFFFF #define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) #define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zCrcOpt.c0100777000000000000000000000324213761647206020476 0ustar00/* 7zCrcOpt.c -- CRC32 calculation 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = table[0x300 + (v & 0xFF)] ^ table[0x200 + ((v >> 8) & 0xFF)] ^ table[0x100 + ((v >> 16) & 0xFF)] ^ table[0x000 + ((v >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { return CrcUpdateT4(v, data, size, table); } #endif #ifndef MY_CPU_LE #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); v = CRC_UINT32_SWAP(v); table += 0x100; for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = table[0x000 + (v & 0xFF)] ^ table[0x100 + ((v >> 8) & 0xFF)] ^ table[0x200 + ((v >> 16) & 0xFF)] ^ table[0x300 + ((v >> 24))]; } table -= 0x100; v = CRC_UINT32_SWAP(v); for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zStream.c0100777000000000000000000000766113761647206020550 0ustar00/* 7zStream.c -- 7z Stream functions 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "7zTypes.h" SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; RINOK(stream->Read(stream, buf, &processed)); if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); size -= processed; } return SZ_OK; } SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) { return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) { size_t processed = 1; RINOK(stream->Read(stream, buf, &processed)); return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; } SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) { Int64 t = offset; return stream->Seek(stream, &t, SZ_SEEK_SET); } SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) { const void *lookBuf; if (*size == 0) return SZ_OK; RINOK(stream->Look(stream, &lookBuf, size)); memcpy(buf, lookBuf, *size); return stream->Skip(stream, *size); } SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; RINOK(stream->Read(stream, buf, &processed)); if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); size -= processed; } return SZ_OK; } SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) { return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) { SRes res = SZ_OK; CLookToRead *p = (CLookToRead *)pp; size_t size2 = p->size - p->pos; if (size2 == 0 && *size > 0) { p->pos = 0; size2 = LookToRead_BUF_SIZE; res = p->realStream->Read(p->realStream, p->buf, &size2); p->size = size2; } if (size2 < *size) *size = size2; *buf = p->buf + p->pos; return res; } static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) { SRes res = SZ_OK; CLookToRead *p = (CLookToRead *)pp; size_t size2 = p->size - p->pos; if (size2 == 0 && *size > 0) { p->pos = 0; if (*size > LookToRead_BUF_SIZE) *size = LookToRead_BUF_SIZE; res = p->realStream->Read(p->realStream, p->buf, size); size2 = p->size = *size; } if (size2 < *size) *size = size2; *buf = p->buf + p->pos; return res; } static SRes LookToRead_Skip(void *pp, size_t offset) { CLookToRead *p = (CLookToRead *)pp; p->pos += offset; return SZ_OK; } static SRes LookToRead_Read(void *pp, void *buf, size_t *size) { CLookToRead *p = (CLookToRead *)pp; size_t rem = p->size - p->pos; if (rem == 0) return p->realStream->Read(p->realStream, buf, size); if (rem > *size) rem = *size; memcpy(buf, p->buf + p->pos, rem); p->pos += rem; *size = rem; return SZ_OK; } static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) { CLookToRead *p = (CLookToRead *)pp; p->pos = p->size = 0; return p->realStream->Seek(p->realStream, pos, origin); } void LookToRead_CreateVTable(CLookToRead *p, int lookahead) { p->s.Look = lookahead ? LookToRead_Look_Lookahead : LookToRead_Look_Exact; p->s.Skip = LookToRead_Skip; p->s.Read = LookToRead_Read; p->s.Seek = LookToRead_Seek; } void LookToRead_Init(CLookToRead *p) { p->pos = p->size = 0; } static SRes SecToLook_Read(void *pp, void *buf, size_t *size) { CSecToLook *p = (CSecToLook *)pp; return LookInStream_LookRead(p->realStream, buf, size); } void SecToLook_CreateVTable(CSecToLook *p) { p->s.Read = SecToLook_Read; } static SRes SecToRead_Read(void *pp, void *buf, size_t *size) { CSecToRead *p = (CSecToRead *)pp; return p->realStream->Read(p->realStream, buf, size); } void SecToRead_CreateVTable(CSecToRead *p) { p->s.Read = SecToRead_Read; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zTypes.h0100777000000000000000000001255113761647206020420 0ustar00/* 7zTypes.h -- Basic types 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H #ifdef _WIN32 /* #include */ #endif #include #ifndef EXTERN_C_BEGIN #ifdef __cplusplus #define EXTERN_C_BEGIN extern "C" { #define EXTERN_C_END } #else #define EXTERN_C_BEGIN #define EXTERN_C_END #endif #endif EXTERN_C_BEGIN #define SZ_OK 0 #define SZ_ERROR_DATA 1 #define SZ_ERROR_MEM 2 #define SZ_ERROR_CRC 3 #define SZ_ERROR_UNSUPPORTED 4 #define SZ_ERROR_PARAM 5 #define SZ_ERROR_INPUT_EOF 6 #define SZ_ERROR_OUTPUT_EOF 7 #define SZ_ERROR_READ 8 #define SZ_ERROR_WRITE 9 #define SZ_ERROR_PROGRESS 10 #define SZ_ERROR_FAIL 11 #define SZ_ERROR_THREAD 12 #define SZ_ERROR_ARCHIVE 16 #define SZ_ERROR_NO_ARCHIVE 17 typedef int SRes; #ifdef _WIN32 /* typedef DWORD WRes; */ typedef unsigned WRes; #else typedef int WRes; #endif #ifndef RINOK #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } #endif typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; #ifdef _LZMA_UINT32_IS_ULONG typedef long Int32; typedef unsigned long UInt32; #else typedef int Int32; typedef unsigned int UInt32; #endif #ifdef _SZ_NO_INT_64 /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. NOTES: Some code will work incorrectly in that case! */ typedef long Int64; typedef unsigned long UInt64; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 Int64; typedef unsigned __int64 UInt64; #define UINT64_CONST(n) n #else typedef long long int Int64; typedef unsigned long long int UInt64; #define UINT64_CONST(n) n ## ULL #endif #endif #ifdef _LZMA_NO_SYSTEM_SIZE_T typedef UInt32 SizeT; #else typedef size_t SizeT; #endif typedef int Bool; #define True 1 #define False 0 #ifdef _WIN32 #define MY_STD_CALL __stdcall #else #define MY_STD_CALL #endif #ifdef _MSC_VER #if _MSC_VER >= 1300 #define MY_NO_INLINE __declspec(noinline) #else #define MY_NO_INLINE #endif #define MY_CDECL __cdecl #define MY_FAST_CALL __fastcall #else #define MY_NO_INLINE #define MY_CDECL #define MY_FAST_CALL #endif /* The following interfaces use first parameter as pointer to structure */ typedef struct { Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ } IByteIn; typedef struct { void (*Write)(void *p, Byte b); } IByteOut; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) < input(*size)) is allowed */ } ISeqInStream; /* it can return SZ_ERROR_INPUT_EOF */ SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); typedef struct { size_t (*Write)(void *p, const void *buf, size_t size); /* Returns: result - the number of actually written bytes. (result < size) means error */ } ISeqOutStream; typedef enum { SZ_SEEK_SET = 0, SZ_SEEK_CUR = 1, SZ_SEEK_END = 2 } ESzSeek; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ISeekInStream; typedef struct { SRes (*Look)(void *p, const void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ SRes (*Skip)(void *p, size_t offset); /* offset must be <= output(*size) of Look */ SRes (*Read)(void *p, void *buf, size_t *size); /* reads directly (without buffer). It's same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ILookInStream; SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); /* reads via ILookInStream::Read */ SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); #define LookToRead_BUF_SIZE (1 << 14) typedef struct { ILookInStream s; ISeekInStream *realStream; size_t pos; size_t size; Byte buf[LookToRead_BUF_SIZE]; } CLookToRead; void LookToRead_CreateVTable(CLookToRead *p, int lookahead); void LookToRead_Init(CLookToRead *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToLook; void SecToLook_CreateVTable(CSecToLook *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToRead; void SecToRead_CreateVTable(CSecToRead *p); typedef struct { SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); /* Returns: result. (result != SZ_OK) means break. Value (UInt64)(Int64)-1 for size means unknown value. */ } ICompressProgress; typedef struct { void *(*Alloc)(void *p, size_t size); void (*Free)(void *p, void *address); /* address can be 0 */ } ISzAlloc; #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Free(p, a) (p)->Free((p), a) #ifdef _WIN32 #define CHAR_PATH_SEPARATOR '\\' #define WCHAR_PATH_SEPARATOR L'\\' #define STRING_PATH_SEPARATOR "\\" #define WSTRING_PATH_SEPARATOR L"\\" #else #define CHAR_PATH_SEPARATOR '/' #define WCHAR_PATH_SEPARATOR L'/' #define STRING_PATH_SEPARATOR "/" #define WSTRING_PATH_SEPARATOR L"/" #endif EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/7zVersion.h0100777000000000000000000000057413761647206020743 0ustar00#define MY_VER_MAJOR 9 #define MY_VER_MINOR 38 #define MY_VER_BUILD 00 #define MY_VERSION "9.38 beta" // #define MY_7ZIP_VERSION "9.38" #define MY_DATE "2015-01-03" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_COPYRIGHT ": Igor Pavlov : Public domain" #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE #define P7ZIP_VERSION "9.38.1" qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Alloc.c0100777000000000000000000001450413761647206020060 0ustar00/* Alloc.c -- Memory allocation functions 2008-09-24 Igor Pavlov Public domain */ #ifdef _WIN32 #include #endif #include #include #ifdef _7ZIP_LARGE_PAGES #ifdef __linux__ #ifndef _7ZIP_ST #include #endif #include #include #include #include #include #endif #endif #include "Alloc.h" /* #define _SZ_ALLOC_DEBUG */ /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ #ifdef _SZ_ALLOC_DEBUG #include int g_allocCount = 0; int g_allocCountMid = 0; int g_allocCountBig = 0; #endif #ifdef P7ZIP_USE_ASM // #include extern int posix_memalign (void **, size_t, size_t); void *align_alloc(size_t size) { // return _mm_malloc(size,16); void * ptr = 0; if (posix_memalign (&ptr, 16, size) == 0) return ptr; else return NULL; } void align_free(void * ptr) { // _mm_free(ptr); free(ptr); } #else void *align_alloc(size_t size) { return malloc(size); } void align_free(void * ptr) { free(ptr); } #endif void *MyAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG { void *p = align_alloc(size); fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p); return p; } #else return align_alloc(size); #endif } void MyFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address); #endif align_free(address); } #ifndef _WIN32 #ifdef _7ZIP_LARGE_PAGES #ifdef __linux__ #define _7ZIP_MAX_HUGE_ALLOCS 64 static void *g_HugePageAddr[_7ZIP_MAX_HUGE_ALLOCS] = { NULL }; static size_t g_HugePageLen[_7ZIP_MAX_HUGE_ALLOCS]; static char *g_HugetlbPath; #endif #endif #ifdef _7ZIP_LARGE_PAGES static void *VirtualAlloc(size_t size, int memLargePages) { if (memLargePages) { #ifdef __linux__ /* huge pages support for Linux; added by Joachim Henke */ #ifndef _7ZIP_ST static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #endif int i; void * address = NULL; #ifndef _7ZIP_ST pthread_mutex_lock(&mutex); #endif for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i) { if (g_HugePageAddr[i] == NULL) { int fd, pathlen = strlen(g_HugetlbPath); char tempname[pathlen+12]; memcpy(tempname, g_HugetlbPath, pathlen); memcpy(tempname + pathlen, "/7z-XXXXXX", 11); fd = mkstemp(tempname); unlink(tempname); if (fd < 0) { fprintf(stderr,"cant't open %s (%s)\n",tempname,strerror(errno)); break; } address = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (address == MAP_FAILED) { address = NULL; break; } g_HugePageLen[i] = size; g_HugePageAddr[i] = address; // fprintf(stderr,"HUGE[%d]=%ld %p\n",i,(long)size,address); break; } } #ifndef _7ZIP_ST pthread_mutex_unlock(&mutex); #endif return address; #endif } return align_alloc(size); } #else static void *VirtualAlloc(size_t size, int memLargePages ) { return align_alloc(size); } #endif static int VirtualFree(void *address) { #ifdef _7ZIP_LARGE_PAGES #ifdef __linux__ int i; for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i) { if (g_HugePageAddr[i] == address) { munmap(address, g_HugePageLen[i]); g_HugePageAddr[i] = NULL; return 1; } } #endif #endif align_free(address); return 1; } #endif void *MidAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); #endif return VirtualAlloc(size, 0); } void MidFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); #endif if (address == 0) return; VirtualFree(address); } #ifdef _7ZIP_LARGE_PAGES size_t g_LargePageSize = 0; #ifdef _WIN32 typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); #elif defined(__linux__) size_t largePageMinimum() { size_t size; g_HugetlbPath = getenv("HUGETLB_PATH"); if (g_HugetlbPath == NULL) { // not defined => try to find out the directory static char dir_hugetlbfs[1024]; const char * filename = "/etc/mtab"; // mounted filesystems FILE *fp; struct mntent * info; dir_hugetlbfs[0]=0; fp = setmntent(filename,"r"); if (fp) { info = getmntent(fp); while(info) { /* printf("%s:\n",info->mnt_fsname); printf(" dir='%s'\n",info->mnt_dir); printf(" type='%s'\n",info->mnt_type); */ if (strcmp(info->mnt_type,"hugetlbfs") == 0) { strcpy(dir_hugetlbfs,info->mnt_dir); break; } info = getmntent(fp); } endmntent(fp); } if (dir_hugetlbfs[0]) { g_HugetlbPath = dir_hugetlbfs; // fprintf(stderr," Found hugetlbfs = '%s'\n",g_HugetlbPath); } } if (g_HugetlbPath == NULL || (size = pathconf(g_HugetlbPath, _PC_REC_MIN_XFER_SIZE)) <= getpagesize()) return 0; return size; } #else #define largePageMinimum() 0 #endif #endif void SetLargePageSize() { #ifdef _7ZIP_LARGE_PAGES size_t size; #ifdef _WIN32 GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); if (largePageMinimum == 0) return; #endif size = largePageMinimum(); if (size == 0 || (size & (size - 1)) != 0) return; g_LargePageSize = size; // fprintf(stderr,"SetLargePageSize : %ld\n",(long)g_LargePageSize); #endif } void *BigAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); #endif #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18)) { void *res = VirtualAlloc( (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 1); if (res != 0) return res; } #endif return VirtualAlloc(size, 0); } void BigFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); #endif if (address == 0) return; VirtualFree(address); } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Alloc.h0100777000000000000000000000066313761647206020066 0ustar00/* Alloc.h -- Memory allocation functions 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __COMMON_ALLOC_H #define __COMMON_ALLOC_H #include #ifdef __cplusplus extern "C" { #endif void *MyAlloc(size_t size); void MyFree(void *address); void SetLargePageSize(); void *MidAlloc(size_t size); void MidFree(void *address); void *BigAlloc(size_t size); void BigFree(void *address); #ifdef __cplusplus } #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Bra.c0100777000000000000000000000610013761647206017523 0ustar00/* Bra.c -- Converters for RISC code 2010-04-16 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; ip += 8; for (i = 0; i <= size; i += 4) { if (data[i + 3] == 0xEB) { UInt32 dest; UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); src <<= 2; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 2; data[i + 2] = (Byte)(dest >> 16); data[i + 1] = (Byte)(dest >> 8); data[i + 0] = (Byte)dest; } } return i; } SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; ip += 4; for (i = 0; i <= size; i += 2) { if ((data[i + 1] & 0xF8) == 0xF0 && (data[i + 3] & 0xF8) == 0xF8) { UInt32 dest; UInt32 src = (((UInt32)data[i + 1] & 0x7) << 19) | ((UInt32)data[i + 0] << 11) | (((UInt32)data[i + 3] & 0x7) << 8) | (data[i + 2]); src <<= 1; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 1; data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); data[i + 0] = (Byte)(dest >> 11); data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); data[i + 2] = (Byte)dest; i += 2; } } return i; } SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; for (i = 0; i <= size; i += 4) { if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) { UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | ((UInt32)data[i + 1] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 3] & (~3)); UInt32 dest; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); data[i + 1] = (Byte)(dest >> 16); data[i + 2] = (Byte)(dest >> 8); data[i + 3] &= 0x3; data[i + 3] |= dest; } } return i; } SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { UInt32 i; if (size < 4) return 0; size -= 4; for (i = 0; i <= size; i += 4) { if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) { UInt32 src = ((UInt32)data[i + 0] << 24) | ((UInt32)data[i + 1] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 3]); UInt32 dest; src <<= 2; if (encoding) dest = ip + i + src; else dest = src - (ip + i); dest >>= 2; dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; data[i + 0] = (Byte)(dest >> 24); data[i + 1] = (Byte)(dest >> 16); data[i + 2] = (Byte)(dest >> 8); data[i + 3] = (Byte)dest; } } return i; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Bra.h0100777000000000000000000000347613761647206017545 0ustar00/* Bra.h -- Branch converters for executables 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __BRA_H #define __BRA_H #include "7zTypes.h" EXTERN_C_BEGIN /* These functions convert relative addresses to absolute addresses in CALL instructions to increase the compression ratio. In: data - data buffer size - size of data ip - current virtual Instruction Pinter (IP) value state - state variable for x86 converter encoding - 0 (for decoding), 1 (for encoding) Out: state - state variable for x86 converter Returns: The number of processed bytes. If you call these functions with multiple calls, you must start next call with first byte after block of processed bytes. Type Endian Alignment LookAhead x86 little 1 4 ARMT little 2 2 ARM little 4 0 PPC big 4 0 SPARC big 4 0 IA64 little 16 0 size must be >= Alignment + LookAhead, if it's not last block. If (size < Alignment + LookAhead), converter returns 0. Example: UInt32 ip = 0; for () { ; size must be >= Alignment + LookAhead, if it's not last block SizeT processed = Convert(data, size, ip, 1); data += processed; size -= processed; ip += processed; } */ #define x86_Convert_Init(state) { state = 0; } SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Bra86.c0100777000000000000000000000326513761647206017712 0ustar00/* Bra86.c -- Converter for x86 code (BCJ) 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" #define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) { SizeT pos = 0; UInt32 mask = *state & 7; if (size < 5) return 0; size -= 4; ip += 5; for (;;) { Byte *p = data + pos; const Byte *limit = data + size; for (; p < limit; p++) if ((*p & 0xFE) == 0xE8) break; { SizeT d = (SizeT)(p - data - pos); pos = (SizeT)(p - data); if (p >= limit) { *state = (d > 2 ? 0 : mask >> (unsigned)d); return pos; } if (d > 2) mask = 0; else { mask >>= (unsigned)d; if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) { mask = (mask >> 1) | 4; pos++; continue; } } } if (Test86MSByte(p[4])) { UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); UInt32 cur = ip + (UInt32)pos; pos += 5; if (encoding) v += cur; else v -= cur; if (mask != 0) { unsigned sh = (mask & 6) << 2; if (Test86MSByte((Byte)(v >> sh))) { v ^= (((UInt32)0x100 << sh) - 1); if (encoding) v += cur; else v -= cur; } mask = 0; } p[1] = (Byte)v; p[2] = (Byte)(v >> 8); p[3] = (Byte)(v >> 16); p[4] = (Byte)(0 - ((v >> 24) & 1)); } else { mask = (mask >> 1) | 4; pos++; } } } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/BraIA64.c0100777000000000000000000000330213761647206020110 0ustar00/* BraIA64.c -- Converter for IA-64 code 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" static const Byte kBranchTable[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 16) return 0; size -= 16; for (i = 0; i <= size; i += 16) { UInt32 instrTemplate = data[i] & 0x1F; UInt32 mask = kBranchTable[instrTemplate]; UInt32 bitPos = 5; int slot; for (slot = 0; slot < 3; slot++, bitPos += 41) { UInt32 bytePos, bitRes; UInt64 instruction, instNorm; int j; if (((mask >> slot) & 1) == 0) continue; bytePos = (bitPos >> 3); bitRes = bitPos & 0x7; instruction = 0; for (j = 0; j < 6; j++) instruction += (UInt64)data[i + j + bytePos] << (8 * j); instNorm = instruction >> bitRes; if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) { UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); UInt32 dest; src |= ((UInt32)(instNorm >> 36) & 1) << 20; src <<= 4; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 4; instNorm &= ~((UInt64)(0x8FFFFF) << 13); instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); instruction &= (1 << bitRes) - 1; instruction |= (instNorm << bitRes); for (j = 0; j < 6; j++) data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); } } } return i; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/C.pri0100777000000000000000000000252213761647206017555 0ustar00HEADERS += $$7ZIP_BASE/C/7zCrc.h \ $$7ZIP_BASE/C/7zTypes.h \ $$7ZIP_BASE/C/7zVersion.h \ $$7ZIP_BASE/C/Alloc.h \ $$7ZIP_BASE/C/Bra.h \ $$7ZIP_BASE/C/Compiler.h \ $$7ZIP_BASE/C/CpuArch.h \ $$7ZIP_BASE/C/Delta.h \ $$7ZIP_BASE/C/LzFind.h \ $$7ZIP_BASE/C/LzFindMt.h \ $$7ZIP_BASE/C/LzHash.h \ $$7ZIP_BASE/C/Lzma2Dec.h \ $$7ZIP_BASE/C/Lzma2Enc.h \ $$7ZIP_BASE/C/LzmaDec.h \ $$7ZIP_BASE/C/LzmaEnc.h \ $$7ZIP_BASE/C/MtCoder.h \ $$7ZIP_BASE/C/Precomp.h \ $$7ZIP_BASE/C/RotateDefs.h \ $$7ZIP_BASE/C/Sha256.h \ $$7ZIP_BASE/C/Threads.h \ $$7ZIP_BASE/C/Xz.h \ $$7ZIP_BASE/C/XzCrc64.h \ $$7ZIP_BASE/C/XzEnc.h SOURCES += $$7ZIP_BASE/C/7zCrc.c \ $$7ZIP_BASE/C/7zCrcOpt.c \ $$7ZIP_BASE/C/7zStream.c \ $$7ZIP_BASE/C/Alloc.c \ $$7ZIP_BASE/C/Bra.c \ $$7ZIP_BASE/C/Bra86.c \ $$7ZIP_BASE/C/BraIA64.c \ $$7ZIP_BASE/C/Delta.c \ $$7ZIP_BASE/C/LzFind.c \ $$7ZIP_BASE/C/LzFindMt.c \ $$7ZIP_BASE/C/Lzma2Dec.c \ $$7ZIP_BASE/C/Lzma2Enc.c \ $$7ZIP_BASE/C/LzmaDec.c \ $$7ZIP_BASE/C/LzmaEnc.c \ $$7ZIP_BASE/C/MtCoder.c \ $$7ZIP_BASE/C/Sha256.c \ $$7ZIP_BASE/C/Threads.c \ $$7ZIP_BASE/C/Xz.c \ $$7ZIP_BASE/C/XzCrc64.c \ $$7ZIP_BASE/C/XzCrc64Opt.c \ $$7ZIP_BASE/C/XzDec.c \ $$7ZIP_BASE/C/XzEnc.c \ $$7ZIP_BASE/C/XzIn.c qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Compiler.h0100777000000000000000000000175313761647206020607 0ustar00/* Compiler.h -- Compiler ypes 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_COMPILER_H #define __7Z_COMPILER_H #ifdef _MSC_VER #ifdef UNDER_CE #define RPC_NO_WINDOWS_H /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int #endif #if _MSC_VER >= 1300 #pragma warning(disable : 4996) // This function or variable may be unsafe #else #pragma warning(disable : 4511) // copy constructor could not be generated #pragma warning(disable : 4512) // assignment operator could not be generated #pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4710) // not inlined #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information #endif #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/CpuArch.h0100777000000000000000000000763013761647206020362 0ustar00/* CpuArch.h -- CPU specific code 2013-11-12: Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H #include "7zTypes.h" EXTERN_C_BEGIN /* MY_CPU_LE means that CPU is LITTLE ENDIAN. If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. */ #if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(__AMD64__) || defined(__amd64__) #define MY_CPU_AMD64 #endif #if defined(MY_CPU_AMD64) || defined(_M_IA64) #define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__) #define MY_CPU_X86 #endif #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) #define MY_CPU_X86_OR_AMD64 #endif #if defined(MY_CPU_X86) || defined(_M_ARM) #define MY_CPU_32BIT #endif #if defined(_WIN32) && defined(_M_ARM) #define MY_CPU_ARM_LE #endif #if defined(_WIN32) && defined(_M_IA64) #define MY_CPU_IA64_LE #endif #if defined(MY_CPU_X86_OR_AMD64) #define MY_CPU_LE_UNALIGN #endif #if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) #define MY_CPU_LE #endif #if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) #define MY_CPU_BE #endif #if defined(MY_CPU_LE) && defined(MY_CPU_BE) Stop_Compiling_Bad_Endian #endif #ifdef MY_CPU_LE_UNALIGN #define GetUi16(p) (*(const UInt16 *)(const void *)(p)) #define GetUi32(p) (*(const UInt32 *)(const void *)(p)) #define GetUi64(p) (*(const UInt64 *)(const void *)(p)) #define SetUi16(p, d) *(UInt16 *)(p) = (d); #define SetUi32(p, d) *(UInt32 *)(p) = (d); #define SetUi64(p, d) *(UInt64 *)(p) = (d); #else #define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) #define GetUi32(p) ( \ ((const Byte *)(p))[0] | \ ((UInt32)((const Byte *)(p))[1] << 8) | \ ((UInt32)((const Byte *)(p))[2] << 16) | \ ((UInt32)((const Byte *)(p))[3] << 24)) #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) #define SetUi16(p, d) { UInt32 _x_ = (d); \ ((Byte *)(p))[0] = (Byte)_x_; \ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } #define SetUi32(p, d) { UInt32 _x_ = (d); \ ((Byte *)(p))[0] = (Byte)_x_; \ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } #define SetUi64(p, d) { UInt64 _x64_ = (d); \ SetUi32(p, (UInt32)_x64_); \ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } #endif #if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) #include #pragma intrinsic(_byteswap_ulong) #pragma intrinsic(_byteswap_uint64) #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) #else #define GetBe32(p) ( \ ((UInt32)((const Byte *)(p))[0] << 24) | \ ((UInt32)((const Byte *)(p))[1] << 16) | \ ((UInt32)((const Byte *)(p))[2] << 8) | \ ((const Byte *)(p))[3] ) #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) #endif #define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])) #ifdef MY_CPU_X86_OR_AMD64 #ifdef P7ZIP_USE_ASM typedef struct { UInt32 maxFunc; UInt32 vendor[3]; UInt32 ver; UInt32 b; UInt32 c; UInt32 d; } Cx86cpuid; enum { CPU_FIRM_INTEL, CPU_FIRM_AMD, CPU_FIRM_VIA }; Bool x86cpuid_CheckAndRead(Cx86cpuid *p); int x86cpuid_GetFirm(const Cx86cpuid *p); #define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) #define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) #define x86cpuid_GetStepping(p) ((p)->ver & 0xF) Bool CPU_Is_InOrder(); Bool CPU_Is_Aes_Supported(); #endif #endif EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Delta.c0100777000000000000000000000237113761647206020056 0ustar00/* Delta.c -- Delta converter 2009-05-26 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Delta.h" void Delta_Init(Byte *state) { unsigned i; for (i = 0; i < DELTA_STATE_SIZE; i++) state[i] = 0; } static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) { unsigned i; for (i = 0; i < size; i++) dest[i] = src[i]; } void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) { Byte buf[DELTA_STATE_SIZE]; unsigned j = 0; MyMemCpy(buf, state, delta); { SizeT i; for (i = 0; i < size;) { for (j = 0; j < delta && i < size; i++, j++) { Byte b = data[i]; data[i] = (Byte)(b - buf[j]); buf[j] = b; } } } if (j == delta) j = 0; MyMemCpy(state, buf + j, delta - j); MyMemCpy(state + delta - j, buf, j); } void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) { Byte buf[DELTA_STATE_SIZE]; unsigned j = 0; MyMemCpy(buf, state, delta); { SizeT i; for (i = 0; i < size;) { for (j = 0; j < delta && i < size; i++, j++) { buf[j] = data[i] = (Byte)(buf[j] + data[i]); } } } if (j == delta) j = 0; MyMemCpy(state, buf + j, delta - j); MyMemCpy(state + delta - j, buf, j); } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Delta.h0100777000000000000000000000057013761647206020062 0ustar00/* Delta.h -- Delta converter 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __DELTA_H #define __DELTA_H #include "7zTypes.h" EXTERN_C_BEGIN #define DELTA_STATE_SIZE 256 void Delta_Init(Byte *state); void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzFind.c0100777000000000000000000004642213761647206020220 0ustar00/* LzFind.c -- Match finder for LZ algorithms 2009-04-22 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "LzFind.h" #include "LzHash.h" #define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ #define kNormalizeMask (~(kNormalizeStepMin - 1)) #define kMaxHistorySize ((UInt32)3 << 30) #define kStartMaxLen 3 static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) { if (!p->directInput) { alloc->Free(alloc, p->bufferBase); p->bufferBase = 0; } } /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) { UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; if (p->directInput) { p->blockSize = blockSize; return 1; } if (p->bufferBase == 0 || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } return (p->bufferBase != 0); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) { p->posLimit -= subValue; p->pos -= subValue; p->streamPos -= subValue; } static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; if (p->directInput) { UInt32 curSize = 0xFFFFFFFF - p->streamPos; if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize; p->streamPos += curSize; if (p->directInputRem == 0) p->streamEndWasReached = 1; return; } for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return; if (size == 0) { p->streamEndWasReached = 1; return; } p->streamPos += (UInt32)size; if (p->streamPos - p->pos > p->keepSizeAfter) return; } } void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, p->buffer - p->keepSizeBefore, (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); p->buffer = p->bufferBase + p->keepSizeBefore; } int MatchFinder_NeedMove(CMatchFinder *p) { if (p->directInput) return 0; /* if (p->streamEndWasReached) return 0; */ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); } void MatchFinder_ReadIfRequired(CMatchFinder *p) { if (p->streamEndWasReached) return; if (p->keepSizeAfter >= p->streamPos - p->pos) MatchFinder_ReadBlock(p); } static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) { if (MatchFinder_NeedMove(p)) MatchFinder_MoveBlock(p); MatchFinder_ReadBlock(p); } static void MatchFinder_SetDefaultSettings(CMatchFinder *p) { p->cutValue = 32; p->btMode = 1; p->numHashBytes = 4; p->bigHash = 0; } #define kCrcPoly 0xEDB88320 void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; p->bufferBase = 0; p->directInput = 0; p->hash = 0; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; int j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r; } } static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); p->hash = 0; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) { MatchFinder_FreeThisClassMemory(p, alloc); LzInWindow_Free(p, alloc); } static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) return 0; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); } int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) { UInt32 sizeReserv; if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } sizeReserv = historySize >> 1; if (historySize > ((UInt32)2 << 30)) sizeReserv = historySize >> 2; sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1; UInt32 hs; p->matchMaxLen = matchMaxLen; { p->fixedHashSize = 0; if (p->numHashBytes == 2) hs = (1 << 16) - 1; else { hs = historySize - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); hs |= (hs >> 8); hs >>= 1; hs |= 0xFFFF; /* don't change it! It's required for Deflate */ if (hs > (1 << 24)) { if (p->numHashBytes == 3) hs = (1 << 24) - 1; else hs >>= 1; } } p->hashMask = hs; hs++; if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; hs += p->fixedHashSize; } { UInt32 prevSize = p->hashSizeSum + p->numSons; UInt32 newSize; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); newSize = p->hashSizeSum + p->numSons; if (p->hash != 0 && prevSize == newSize) return 1; MatchFinder_FreeThisClassMemory(p, alloc); p->hash = AllocRefs(newSize, alloc); if (p->hash != 0) { p->son = p->hash + p->hashSizeSum; return 1; } } } MatchFinder_Free(p, alloc); return 0; } static void MatchFinder_SetLimits(CMatchFinder *p) { UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; if (limit2 <= p->keepSizeAfter) { if (limit2 > 0) limit2 = 1; } else limit2 -= p->keepSizeAfter; if (limit2 < limit) limit = limit2; { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen) lenLimit = p->matchMaxLen; p->lenLimit = lenLimit; } p->posLimit = p->pos + limit; } void MatchFinder_Init(CMatchFinder *p) { UInt32 i; for (i = 0; i < p->hashSizeSum; i++) p->hash[i] = kEmptyHashValue; p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; MatchFinder_ReadBlock(p); MatchFinder_SetLimits(p); } static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) { UInt32 i; for (i = 0; i < numItems; i++) { UInt32 value = items[i]; if (value <= subValue) value = kEmptyHashValue; else value -= subValue; items[i] = value; } } static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); MatchFinder_ReduceOffsets(p, subValue); } static void MatchFinder_CheckLimits(CMatchFinder *p) { if (p->pos == kMaxValForNormalize) MatchFinder_Normalize(p); if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) MatchFinder_CheckAndMoveAndRead(p); if (p->cyclicBufferPos == p->cyclicBufferSize) p->cyclicBufferPos = 0; MatchFinder_SetLimits(p); } static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { son[_cyclicBufferPos] = curMatch; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) return distances; { const Byte *pb = cur - delta; curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; if (pb[maxLen] == cur[maxLen] && *pb == *cur) { UInt32 len = 0; while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) return distances; } } } } } UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return distances; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return distances; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { while (++len != lenLimit) if (pb[len] != cur[len]) break; { if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } #define MOVE_POS \ ++p->cyclicBufferPos; \ p->buffer++; \ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); #define MOVE_POS_RET MOVE_POS return offset; static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue #define GET_MATCHES_FOOTER(offset, maxLen) \ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ distances + offset, maxLen) - distances); MOVE_POS_RET; #define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) } UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, delta2, maxLen, offset; GET_MATCHES_HEADER(3) HASH3_CALC; delta2 = p->pos - p->hash[hash2Value]; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; maxLen = 2; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[0] = maxLen; distances[1] = delta2 - 1; offset = 2; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { p->son[p->cyclicBufferPos] = curMatch; MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) - (distances)); MOVE_POS_RET } UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances, 2) - (distances)); MOVE_POS_RET } static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value; SKIP_HEADER(3) HASH3_CALC; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->pos; p->hash[kFix4HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; } else if (p->numHashBytes == 2) { vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; } else if (p->numHashBytes == 3) { vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } else { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzFind.h0100777000000000000000000000626513761647206020226 0ustar00/* LzFind.h -- Match finder for LZ algorithms 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H #include "7zTypes.h" EXTERN_C_BEGIN typedef UInt32 CLzRef; typedef struct _CMatchFinder { Byte *buffer; UInt32 pos; UInt32 posLimit; UInt32 streamPos; UInt32 lenLimit; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ UInt32 matchMaxLen; CLzRef *hash; CLzRef *son; UInt32 hashMask; UInt32 cutValue; Byte *bufferBase; ISeqInStream *stream; int streamEndWasReached; UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; int directInput; size_t directInputRem; int btMode; int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; UInt32 numSons; SRes result; UInt32 crc[256]; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) #define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p); void MatchFinder_ReadIfRequired(CMatchFinder *p); void MatchFinder_Construct(CMatchFinder *p); /* Conditions: historySize <= 3 GB keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB */ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *distances, UInt32 maxLen); /* Conditions: Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. Mf_GetPointerToCurrentPos_Func's result must be used only before any other function */ typedef void (*Mf_Init_Func)(void *object); typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); typedef void (*Mf_Skip_Func)(void *object, UInt32); typedef struct _IMatchFinder { Mf_Init_Func Init; Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; Mf_Skip_Func Skip; } IMatchFinder; void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); void MatchFinder_Init(CMatchFinder *p); UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzFindMt.c0100777000000000000000000005323313761647206020517 0ustar00/* LzFindMt.c -- multithreaded Match finder for LZ algorithms 2014-12-29 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "LzHash.h" #include "LzFindMt.h" void MtSync_Construct(CMtSync *p) { p->wasCreated = False; p->csWasInitialized = False; p->csWasEntered = False; Thread_Construct(&p->thread); Event_Construct(&p->canStart); Event_Construct(&p->wasStarted); Event_Construct(&p->wasStopped); Semaphore_Construct(&p->freeSemaphore); Semaphore_Construct(&p->filledSemaphore); } void MtSync_GetNextBlock(CMtSync *p) { if (p->needStart) { p->numProcessedBlocks = 1; p->needStart = False; p->stopWriting = False; p->exit = False; Event_Reset(&p->wasStarted); Event_Reset(&p->wasStopped); Event_Set(&p->canStart); Event_Wait(&p->wasStarted); } else { CriticalSection_Leave(&p->cs); p->csWasEntered = False; p->numProcessedBlocks++; Semaphore_Release1(&p->freeSemaphore); } Semaphore_Wait(&p->filledSemaphore); CriticalSection_Enter(&p->cs); p->csWasEntered = True; } /* MtSync_StopWriting must be called if Writing was started */ void MtSync_StopWriting(CMtSync *p) { UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart) return; p->stopWriting = True; if (p->csWasEntered) { CriticalSection_Leave(&p->cs); p->csWasEntered = False; } Semaphore_Release1(&p->freeSemaphore); Event_Wait(&p->wasStopped); while (myNumBlocks++ != p->numProcessedBlocks) { Semaphore_Wait(&p->filledSemaphore); Semaphore_Release1(&p->freeSemaphore); } p->needStart = True; } void MtSync_Destruct(CMtSync *p) { if (Thread_WasCreated(&p->thread)) { MtSync_StopWriting(p); p->exit = True; if (p->needStart) Event_Set(&p->canStart); Thread_Wait(&p->thread); Thread_Close(&p->thread); } if (p->csWasInitialized) { CriticalSection_Delete(&p->cs); p->csWasInitialized = False; } Event_Close(&p->canStart); Event_Close(&p->wasStarted); Event_Close(&p->wasStopped); Semaphore_Close(&p->freeSemaphore); Semaphore_Close(&p->filledSemaphore); p->wasCreated = False; } #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { if (p->wasCreated) return SZ_OK; RINOK_THREAD(CriticalSection_Init(&p->cs)); p->csWasInitialized = True; RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); p->needStart = True; RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); p->wasCreated = True; return SZ_OK; } static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); if (res != SZ_OK) MtSync_Destruct(p); return res; } void MtSync_Init(CMtSync *p) { p->needStart = True; } #define kMtMaxValForNormalize 0xFFFFFFFF #define DEF_GetHeads2(name, v, action) \ static void GetHeads ## name(const Byte *p, UInt32 pos, \ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ { action; for (; numHeads != 0; numHeads--) { \ const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; for (;;) { UInt32 numProcessedBlocks = 0; Event_Wait(&p->canStart); Event_Set(&p->wasStarted); for (;;) { if (p->exit) return; if (p->stopWriting) { p->numProcessedBlocks = numProcessedBlocks; Event_Set(&p->wasStopped); break; } { CMatchFinder *mf = mt->MatchFinder; if (MatchFinder_NeedMove(mf)) { CriticalSection_Enter(&mt->btSync.cs); CriticalSection_Enter(&mt->hashSync.cs); { const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); const Byte *afterPtr; MatchFinder_MoveBlock(mf); afterPtr = MatchFinder_GetPointerToCurrentPos(mf); mt->pointerToCurPos -= beforePtr - afterPtr; mt->buffer -= beforePtr - afterPtr; } CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs); continue; } Semaphore_Wait(&p->freeSemaphore); MatchFinder_ReadIfRequired(mf); if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) { UInt32 subValue = (mf->pos - mf->historySize - 1); MatchFinder_ReduceOffsets(mf, subValue); MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); } { UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; UInt32 num = mf->streamPos - mf->pos; heads[0] = 2; heads[1] = num; if (num >= mf->numHashBytes) { num = num - mf->numHashBytes + 1; if (num > kMtHashBlockSize - 2) num = kMtHashBlockSize - 2; mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); heads[0] += num; } mf->pos += num; mf->buffer += num; } } Semaphore_Release1(&p->filledSemaphore); } } } void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) { MtSync_GetNextBlock(&p->hashSync); p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; p->hashNumAvail = p->hashBuf[p->hashBufPos++]; } #define kEmptyHashValue 0 /* #define MFMT_GM_INLINE */ #ifdef MFMT_GM_INLINE #define NO_INLINE MY_FAST_CALL Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) { do { UInt32 *distances = _distances + 1; UInt32 curMatch = pos - *hash++; CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; UInt32 cutValue = _cutValue; UInt32 maxLen = _maxLen; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; break; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; break; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } pos++; _cyclicBufferPos++; cur++; { UInt32 num = (UInt32)(distances - _distances); *_distances = num - 1; _distances += num; limit -= num; } } while (limit > 0 && --size != 0); *posRes = pos; return limit; } #endif void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 numProcessed = 0; UInt32 curPos = 2; UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); distances[1] = p->hashNumAvail; while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit) { MatchFinderMt_GetNextBlock_Hash(p); distances[1] = numProcessed + p->hashNumAvail; if (p->hashNumAvail >= p->numHashBytes) continue; for (; p->hashNumAvail != 0; p->hashNumAvail--) distances[curPos++] = 0; break; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos; UInt32 lenLimit = p->matchMaxLen; UInt32 pos = p->pos; UInt32 cyclicBufferPos = p->cyclicBufferPos; if (lenLimit >= p->hashNumAvail) lenLimit = p->hashNumAvail; { UInt32 size2 = p->hashNumAvail - lenLimit + 1; if (size2 < size) size = size2; size2 = p->cyclicBufferSize - cyclicBufferPos; if (size2 < size) size = size2; } #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { UInt32 *startDistances = distances + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, startDistances + 1, p->numHashBytes - 1) - startDistances); *startDistances = num - 1; curPos += num; cyclicBufferPos++; pos++; p->buffer++; } #else { UInt32 posRes; curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); p->hashBufPos += posRes - pos; cyclicBufferPos += posRes - pos; p->buffer += posRes - pos; pos = posRes; } #endif numProcessed += pos - p->pos; p->hashNumAvail -= pos - p->pos; p->pos = pos; if (cyclicBufferPos == p->cyclicBufferSize) cyclicBufferPos = 0; p->cyclicBufferPos = cyclicBufferPos; } } distances[0] = curPos; } void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; if (!sync->needStart) { CriticalSection_Enter(&sync->cs); sync->csWasEntered = True; } BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) { UInt32 subValue = p->pos - p->cyclicBufferSize; MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); p->pos -= subValue; } if (!sync->needStart) { CriticalSection_Leave(&sync->cs); sync->csWasEntered = False; } } void BtThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->btSync; for (;;) { UInt32 blockIndex = 0; Event_Wait(&p->canStart); Event_Set(&p->wasStarted); for (;;) { if (p->exit) return; if (p->stopWriting) { p->numProcessedBlocks = blockIndex; MtSync_StopWriting(&mt->hashSync); Event_Set(&p->wasStopped); break; } Semaphore_Wait(&p->freeSemaphore); BtFillBlock(mt, blockIndex++); Semaphore_Release1(&p->filledSemaphore); } } } void MatchFinderMt_Construct(CMatchFinderMt *p) { p->hashBuf = 0; MtSync_Construct(&p->hashSync); MtSync_Construct(&p->btSync); } void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hashBuf); p->hashBuf = 0; } void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) { MtSync_Destruct(&p->hashSync); MtSync_Destruct(&p->btSync); MatchFinderMt_FreeMem(p, alloc); } #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; allocaDummy[0] = 0; allocaDummy[1] = allocaDummy[0]; BtThreadFunc((CMatchFinderMt *)p); return 0; } SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) { CMatchFinder *mf = p->MatchFinder; p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; if (p->hashBuf == 0) { p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); if (p->hashBuf == 0) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; } keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); keepAddBufferAfter += kMtHashBlockSize; if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) return SZ_ERROR_MEM; RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); return SZ_OK; } /* Call it after ReleaseStream / SetStream */ void MatchFinderMt_Init(CMatchFinderMt *p) { CMatchFinder *mf = p->MatchFinder; p->btBufPos = p->btBufPosLimit = 0; p->hashBufPos = p->hashBufPosLimit = 0; MatchFinder_Init(mf); p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; p->lzPos = p->historySize + 1; p->hash = mf->hash; p->fixedHashSize = mf->fixedHashSize; p->crc = mf->crc; p->son = mf->son; p->matchMaxLen = mf->matchMaxLen; p->numHashBytes = mf->numHashBytes; p->pos = mf->pos; p->buffer = mf->buffer; p->cyclicBufferPos = mf->cyclicBufferPos; p->cyclicBufferSize = mf->cyclicBufferSize; p->cutValue = mf->cutValue; } /* ReleaseStream is required to finish multithreading */ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) { MtSync_StopWriting(&p->btSync); /* p->MatchFinder->ReleaseStream(); */ } void MatchFinderMt_Normalize(CMatchFinderMt *p) { MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); p->lzPos = p->historySize + 1; } void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { UInt32 blockIndex; MtSync_GetNextBlock(&p->btSync); blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; p->btBufPosLimit += p->btBuf[p->btBufPos++]; p->btNumAvailBytes = p->btBuf[p->btBufPos++]; if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) MatchFinderMt_Normalize(p); } const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { GET_NEXT_BLOCK_IF_REQUIRED; return p->btNumAvailBytes; } Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) { return p->pointerToCurPos[index]; } UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, curMatch2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH2_CALC curMatch2 = hash[hash2Value]; hash[hash2Value] = lzPos; if (curMatch2 >= matchMinPos) if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { *distances++ = 2; *distances++ = lzPos - curMatch2 - 1; } return distances; } UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, hash3Value, curMatch2, curMatch3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH3_CALC curMatch2 = hash[ hash2Value]; curMatch3 = hash[kFix3HashSize + hash3Value]; hash[ hash2Value] = hash[kFix3HashSize + hash3Value] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { distances[0] = 3; return distances + 2; } distances[0] = 2; distances += 2; } if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { *distances++ = 3; *distances++ = lzPos - curMatch3 - 1; } return distances; } /* UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH4_CALC curMatch2 = hash[ hash2Value]; curMatch3 = hash[kFix3HashSize + hash3Value]; curMatch4 = hash[kFix4HashSize + hash4Value]; hash[ hash2Value] = hash[kFix3HashSize + hash3Value] = hash[kFix4HashSize + hash4Value] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; return distances + 2; } distances[0] = 2; distances += 2; } if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch3 - 1; if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) { distances[0] = 4; return distances + 2; } distances[0] = 3; distances += 2; } if (curMatch4 >= matchMinPos) if ( cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] ) { *distances++ = 4; *distances++ = lzPos - curMatch4 - 1; } return distances; } */ #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; p->btBufPos += 1 + len; p->btNumAvailBytes--; { UInt32 i; for (i = 0; i < len; i += 2) { *distances++ = *btBuf++; *distances++ = *btBuf++; } } INCREASE_LZ_POS return len; } UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; p->btBufPos += 1 + len; if (len == 0) { if (p->btNumAvailBytes-- >= 4) len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); } else { /* Condition: there are matches in btBuf with length < p->numHashBytes */ UInt32 *distances2; p->btNumAvailBytes--; distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); do { *distances2++ = *btBuf++; *distances2++ = *btBuf++; } while ((len -= 2) != 0); len = (UInt32)(distances2 - (distances)); } INCREASE_LZ_POS return len; } #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER2_MT { p->btNumAvailBytes--; SKIP_FOOTER_MT } void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(2) UInt32 hash2Value; MT_HASH2_CALC hash[hash2Value] = p->lzPos; SKIP_FOOTER_MT } void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(3) UInt32 hash2Value, hash3Value; MT_HASH3_CALC hash[kFix3HashSize + hash3Value] = hash[ hash2Value] = p->lzPos; SKIP_FOOTER_MT } /* void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) UInt32 hash2Value, hash3Value, hash4Value; MT_HASH4_CALC hash[kFix4HashSize + hash4Value] = hash[kFix3HashSize + hash3Value] = hash[ hash2Value] = p->lzPos; SKIP_FOOTER_MT } */ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; switch(p->MatchFinder->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2; p->MixMatchesFunc = (Mf_Mix_Matches)0; vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; break; case 3: p->GetHeadsFunc = GetHeads3; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; break; default: /* case 4: */ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; /* p->GetHeadsFunc = GetHeads4; */ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break; /* default: p->GetHeadsFunc = GetHeads5; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; break; */ } } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzFindMt.h0100777000000000000000000000453613761647206020526 0ustar00/* LzFindMt.h -- multithreaded Match finder for LZ algorithms 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_MT_H #define __LZ_FIND_MT_H #include "LzFind.h" #include "Threads.h" EXTERN_C_BEGIN #define kMtHashBlockSize (1 << 13) #define kMtHashNumBlocks (1 << 3) #define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) #define kMtBtBlockSize (1 << 14) #define kMtBtNumBlocks (1 << 6) #define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) typedef struct _CMtSync { Bool wasCreated; Bool needStart; Bool exit; Bool stopWriting; CThread thread; CAutoResetEvent canStart; CAutoResetEvent wasStarted; CAutoResetEvent wasStopped; CSemaphore freeSemaphore; CSemaphore filledSemaphore; Bool csWasInitialized; Bool csWasEntered; CCriticalSection cs; UInt32 numProcessedBlocks; } CMtSync; typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); /* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ #define kMtCacheLineDummy 128 typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); typedef struct _CMatchFinderMt { /* LZ */ const Byte *pointerToCurPos; UInt32 *btBuf; UInt32 btBufPos; UInt32 btBufPosLimit; UInt32 lzPos; UInt32 btNumAvailBytes; UInt32 *hash; UInt32 fixedHashSize; UInt32 historySize; const UInt32 *crc; Mf_Mix_Matches MixMatchesFunc; /* LZ + BT */ CMtSync btSync; Byte btDummy[kMtCacheLineDummy]; /* BT */ UInt32 *hashBuf; UInt32 hashBufPos; UInt32 hashBufPosLimit; UInt32 hashNumAvail; CLzRef *son; UInt32 matchMaxLen; UInt32 numHashBytes; UInt32 pos; Byte *buffer; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be historySize + 1 */ UInt32 cutValue; /* BT + Hash */ CMtSync hashSync; /* Byte hashDummy[kMtCacheLineDummy]; */ /* Hash */ Mf_GetHeads GetHeadsFunc; CMatchFinder *MatchFinder; } CMatchFinderMt; void MatchFinderMt_Construct(CMatchFinderMt *p); void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc); SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzHash.h0100777000000000000000000000365413761647206020230 0ustar00/* LzHash.h -- HASH functions for LZ algorithms 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H #define kHash2Size (1 << 10) #define kHash3Size (1 << 16) #define kHash4Size (1 << 20) #define kFix3HashSize (kHash2Size) #define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) #define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ hash4Value &= (kHash4Size - 1); } /* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ #define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Lzma2Dec.c0100777000000000000000000002306713761647206020433 0ustar00/* Lzma2Dec.c -- LZMA2 Decoder 2010-12-15 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */ #include "Precomp.h" #ifdef SHOW_DEBUG_INFO #include #endif #include #include "Lzma2Dec.h" /* 00000000 - EOS 00000001 U U - Uncompressed Reset Dic 00000010 U U - Uncompressed No Reset 100uuuuu U U P P - LZMA no reset 101uuuuu U U P P - LZMA reset state 110uuuuu U U P P S - LZMA reset state + new prop 111uuuuu U U P P S - LZMA reset state + new prop + reset dic u, U - Unpack Size P - Pack Size S - Props */ #define LZMA2_CONTROL_LZMA (1 << 7) #define LZMA2_CONTROL_COPY_NO_RESET 2 #define LZMA2_CONTROL_COPY_RESET_DIC 1 #define LZMA2_CONTROL_EOF 0 #define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) #define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) #define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) #define LZMA2_LCLP_MAX 4 #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) #ifdef SHOW_DEBUG_INFO #define PRF(x) x #else #define PRF(x) #endif typedef enum { LZMA2_STATE_CONTROL, LZMA2_STATE_UNPACK0, LZMA2_STATE_UNPACK1, LZMA2_STATE_PACK0, LZMA2_STATE_PACK1, LZMA2_STATE_PROP, LZMA2_STATE_DATA, LZMA2_STATE_DATA_CONT, LZMA2_STATE_FINISHED, LZMA2_STATE_ERROR } ELzma2State; static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) { UInt32 dicSize; if (prop > 40) return SZ_ERROR_UNSUPPORTED; dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); props[0] = (Byte)LZMA2_LCLP_MAX; props[1] = (Byte)(dicSize); props[2] = (Byte)(dicSize >> 8); props[3] = (Byte)(dicSize >> 16); props[4] = (Byte)(dicSize >> 24); return SZ_OK; } SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) { Byte props[LZMA_PROPS_SIZE]; RINOK(Lzma2Dec_GetOldProps(prop, props)); return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) { Byte props[LZMA_PROPS_SIZE]; RINOK(Lzma2Dec_GetOldProps(prop, props)); return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } void Lzma2Dec_Init(CLzma2Dec *p) { p->state = LZMA2_STATE_CONTROL; p->needInitDic = True; p->needInitState = True; p->needInitProp = True; LzmaDec_Init(&p->decoder); } static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { switch(p->state) { case LZMA2_STATE_CONTROL: p->control = b; PRF(printf("\n %4X ", p->decoder.dicPos)); PRF(printf(" %2X", b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if ((p->control & 0x7F) > 2) return LZMA2_STATE_ERROR; p->unpackSize = 0; } else p->unpackSize = (UInt32)(p->control & 0x1F) << 16; return LZMA2_STATE_UNPACK0; case LZMA2_STATE_UNPACK0: p->unpackSize |= (UInt32)b << 8; return LZMA2_STATE_UNPACK1; case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; PRF(printf(" %8d", p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: p->packSize = (UInt32)b << 8; return LZMA2_STATE_PACK1; case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; PRF(printf(" %8d", p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { int lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; b /= 9; p->decoder.prop.pb = b / 5; lp = b % 5; if (lc + lp > LZMA2_LCLP_MAX) return LZMA2_STATE_ERROR; p->decoder.prop.lc = lc; p->decoder.prop.lp = lp; p->needInitProp = False; return LZMA2_STATE_DATA; } } return LZMA2_STATE_ERROR; } static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) { memcpy(p->dic + p->dicPos, src, size); p->dicPos += size; if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) p->checkDicSize = p->prop.dicSize; p->processedPos += (UInt32)size; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState); SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); continue; } { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen; ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; if (p->unpackSize <= destSizeCur) { destSizeCur = (SizeT)p->unpackSize; curFinishMode = LZMA_FINISH_END; } if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->state == LZMA2_STATE_DATA) { Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) return SZ_ERROR_DATA; p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); } if (srcSizeCur > destSizeCur) srcSizeCur = destSizeCur; if (srcSizeCur == 0) return SZ_ERROR_DATA; LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); src += srcSizeCur; *srcLen += srcSizeCur; p->unpackSize -= (UInt32)srcSizeCur; p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; } else { SizeT outSizeProcessed; SRes res; if (p->state == LZMA2_STATE_DATA) { int mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); Bool initState = (mode > 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) return SZ_ERROR_DATA; LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize; res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); src += srcSizeCur; *srcLen += srcSizeCur; p->packSize -= (UInt32)srcSizeCur; outSizeProcessed = p->decoder.dicPos - dicPos; p->unpackSize -= (UInt32)outSizeProcessed; RINOK(res); if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) return res; if (srcSizeCur == 0 && outSizeProcessed == 0) { if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || p->unpackSize != 0 || p->packSize != 0) return SZ_ERROR_DATA; p->state = LZMA2_STATE_CONTROL; } if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; } SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen, inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT srcSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->decoder.dicPos == p->decoder.dicBufSize) p->decoder.dicPos = 0; dicPos = p->decoder.dicPos; if (outSize > p->decoder.dicBufSize - dicPos) { outSizeCur = p->decoder.dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); src += srcSizeCur; inSize -= srcSizeCur; *srcLen += srcSizeCur; outSizeCur = p->decoder.dicPos - dicPos; memcpy(dest, p->decoder.dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzma2Dec p; SRes res; SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; Lzma2Dec_Construct(&p); RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); p.decoder.dic = dest; p.decoder.dicBufSize = outSize; Lzma2Dec_Init(&p); *srcLen = inSize; res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); *destLen = p.decoder.dicPos; if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; Lzma2Dec_FreeProbs(&p, alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Lzma2Dec.h0100777000000000000000000000416313761647206020434 0ustar00/* Lzma2Dec.h -- LZMA2 Decoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA2_DEC_H #define __LZMA2_DEC_H #include "LzmaDec.h" EXTERN_C_BEGIN /* ---------- State Interface ---------- */ typedef struct { CLzmaDec decoder; UInt32 packSize; UInt32 unpackSize; int state; Byte control; Bool needInitDic; Bool needInitState; Bool needInitProp; } CLzma2Dec; #define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) #define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); #define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); void Lzma2Dec_Init(CLzma2Dec *p); /* finishMode: It has meaning only if the decoding reaches output limit (*destLen or dicLimit). LZMA_FINISH_ANY - use smallest number of input bytes LZMA_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT SZ_ERROR_DATA - Data error */ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - use smallest number of input bytes LZMA_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Lzma2Enc.c0100777000000000000000000002747513761647206020454 0ustar00/* Lzma2Enc.c -- LZMA2 Encoder 2012-06-19 : Igor Pavlov : Public domain */ #include "Precomp.h" /* #include */ #include /* #define _7ZIP_ST */ #include "Lzma2Enc.h" #ifndef _7ZIP_ST #include "MtCoder.h" #else #define NUM_MT_CODER_THREADS_MAX 1 #endif #define LZMA2_CONTROL_LZMA (1 << 7) #define LZMA2_CONTROL_COPY_NO_RESET 2 #define LZMA2_CONTROL_COPY_RESET_DIC 1 #define LZMA2_CONTROL_EOF 0 #define LZMA2_LCLP_MAX 4 #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) #define LZMA2_PACK_SIZE_MAX (1 << 16) #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX #define LZMA2_UNPACK_SIZE_MAX (1 << 21) #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX #define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) #define PRF(x) /* x */ /* ---------- CLzma2EncInt ---------- */ typedef struct { CLzmaEncHandle enc; UInt64 srcPos; Byte props; Bool needInitState; Bool needInitProp; } CLzma2EncInt; static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props) { Byte propsEncoded[LZMA_PROPS_SIZE]; SizeT propsSize = LZMA_PROPS_SIZE; RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); p->srcPos = 0; p->props = propsEncoded[0]; p->needInitState = True; p->needInitProp = True; return SZ_OK; } SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); void LzmaEnc_Finish(CLzmaEncHandle pp); void LzmaEnc_SaveState(CLzmaEncHandle pp); void LzmaEnc_RestoreState(CLzmaEncHandle pp); static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, size_t *packSizeRes, ISeqOutStream *outStream) { size_t packSizeLimit = *packSizeRes; size_t packSize = packSizeLimit; UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); Bool useCopyBlock; SRes res; *packSizeRes = 0; if (packSize < lzHeaderSize) return SZ_ERROR_OUTPUT_EOF; packSize -= lzHeaderSize; LzmaEnc_SaveState(p->enc); res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); if (unpackSize == 0) return res; if (res == SZ_OK) useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); else { if (res != SZ_ERROR_OUTPUT_EOF) return res; res = SZ_OK; useCopyBlock = True; } if (useCopyBlock) { size_t destPos = 0; PRF(printf("################# COPY ")); while (unpackSize > 0) { UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; if (packSizeLimit - destPos < u + 3) return SZ_ERROR_OUTPUT_EOF; outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); outBuf[destPos++] = (Byte)((u - 1) >> 8); outBuf[destPos++] = (Byte)(u - 1); memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); unpackSize -= u; destPos += u; p->srcPos += u; if (outStream) { *packSizeRes += destPos; if (outStream->Write(outStream, outBuf, destPos) != destPos) return SZ_ERROR_WRITE; destPos = 0; } else *packSizeRes = destPos; /* needInitState = True; */ } LzmaEnc_RestoreState(p->enc); return SZ_OK; } { size_t destPos = 0; UInt32 u = unpackSize - 1; UInt32 pm = (UInt32)(packSize - 1); unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); PRF(printf(" ")); outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); outBuf[destPos++] = (Byte)(u >> 8); outBuf[destPos++] = (Byte)u; outBuf[destPos++] = (Byte)(pm >> 8); outBuf[destPos++] = (Byte)pm; if (p->needInitProp) outBuf[destPos++] = p->props; p->needInitProp = False; p->needInitState = False; destPos += packSize; p->srcPos += unpackSize; if (outStream) if (outStream->Write(outStream, outBuf, destPos) != destPos) return SZ_ERROR_WRITE; *packSizeRes = destPos; return SZ_OK; } } /* ---------- Lzma2 Props ---------- */ void Lzma2EncProps_Init(CLzma2EncProps *p) { LzmaEncProps_Init(&p->lzmaProps); p->numTotalThreads = -1; p->numBlockThreads = -1; p->blockSize = 0; } void Lzma2EncProps_Normalize(CLzma2EncProps *p) { int t1, t1n, t2, t3; { CLzmaEncProps lzmaProps = p->lzmaProps; LzmaEncProps_Normalize(&lzmaProps); t1n = lzmaProps.numThreads; } t1 = p->lzmaProps.numThreads; t2 = p->numBlockThreads; t3 = p->numTotalThreads; if (t2 > NUM_MT_CODER_THREADS_MAX) t2 = NUM_MT_CODER_THREADS_MAX; if (t3 <= 0) { if (t2 <= 0) t2 = 1; t3 = t1n * t2; } else if (t2 <= 0) { t2 = t3 / t1n; if (t2 == 0) { t1 = 1; t2 = t3; } if (t2 > NUM_MT_CODER_THREADS_MAX) t2 = NUM_MT_CODER_THREADS_MAX; } else if (t1 <= 0) { t1 = t3 / t2; if (t1 == 0) t1 = 1; } else t3 = t1n * t2; p->lzmaProps.numThreads = t1; LzmaEncProps_Normalize(&p->lzmaProps); if (p->blockSize == 0) { UInt32 dictSize = p->lzmaProps.dictSize; UInt64 blockSize = (UInt64)dictSize << 2; const UInt32 kMinSize = (UInt32)1 << 20; const UInt32 kMaxSize = (UInt32)1 << 28; if (blockSize < kMinSize) blockSize = kMinSize; if (blockSize > kMaxSize) blockSize = kMaxSize; if (blockSize < dictSize) blockSize = dictSize; p->blockSize = (size_t)blockSize; } if (t2 > 1) { UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1; if (temp > p->lzmaProps.reduceSize) { UInt64 numBlocks = temp / p->blockSize; if (numBlocks < t2) { t2 = (UInt32)numBlocks; t3 = t1 * t2; } } } p->numBlockThreads = t2; p->numTotalThreads = t3; } static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) { return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; } /* ---------- Lzma2 ---------- */ typedef struct { Byte propEncoded; CLzma2EncProps props; Byte *outBuf; ISzAlloc *alloc; ISzAlloc *allocBig; CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX]; #ifndef _7ZIP_ST CMtCoder mtCoder; #endif } CLzma2Enc; /* ---------- Lzma2EncThread ---------- */ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) { UInt64 packTotal = 0; SRes res = SZ_OK; if (mainEncoder->outBuf == 0) { mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); if (mainEncoder->outBuf == 0) return SZ_ERROR_MEM; } RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE, mainEncoder->alloc, mainEncoder->allocBig)); for (;;) { size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream); if (res != SZ_OK) break; packTotal += packSize; res = Progress(progress, p->srcPos, packTotal); if (res != SZ_OK) break; if (packSize == 0) break; } LzmaEnc_Finish(p->enc); if (res == SZ_OK) { Byte b = 0; if (outStream->Write(outStream, &b, 1) != 1) return SZ_ERROR_WRITE; } return res; } #ifndef _7ZIP_ST typedef struct { IMtCoderCallback funcTable; CLzma2Enc *lzma2Enc; } CMtCallbackImp; static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize, const Byte *src, size_t srcSize, int finished) { CMtCallbackImp *imp = (CMtCallbackImp *)pp; CLzma2Enc *mainEncoder = imp->lzma2Enc; CLzma2EncInt *p = &mainEncoder->coders[index]; SRes res = SZ_OK; { size_t destLim = *destSize; *destSize = 0; if (srcSize != 0) { RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE, mainEncoder->alloc, mainEncoder->allocBig)); while (p->srcPos < srcSize) { size_t packSize = destLim - *destSize; res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL); if (res != SZ_OK) break; *destSize += packSize; if (packSize == 0) { res = SZ_ERROR_FAIL; break; } if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK) { res = SZ_ERROR_PROGRESS; break; } } LzmaEnc_Finish(p->enc); if (res != SZ_OK) return res; } if (finished) { if (*destSize == destLim) return SZ_ERROR_OUTPUT_EOF; dest[(*destSize)++] = 0; } } return res; } #endif /* ---------- Lzma2Enc ---------- */ CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig) { CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc)); if (p == 0) return NULL; Lzma2EncProps_Init(&p->props); Lzma2EncProps_Normalize(&p->props); p->outBuf = 0; p->alloc = alloc; p->allocBig = allocBig; { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) p->coders[i].enc = 0; } #ifndef _7ZIP_ST MtCoder_Construct(&p->mtCoder); #endif return p; } void Lzma2Enc_Destroy(CLzma2EncHandle pp) { CLzma2Enc *p = (CLzma2Enc *)pp; unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) { CLzma2EncInt *t = &p->coders[i]; if (t->enc) { LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); t->enc = 0; } } #ifndef _7ZIP_ST MtCoder_Destruct(&p->mtCoder); #endif IAlloc_Free(p->alloc, p->outBuf); IAlloc_Free(p->alloc, pp); } SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) { CLzma2Enc *p = (CLzma2Enc *)pp; CLzmaEncProps lzmaProps = props->lzmaProps; LzmaEncProps_Normalize(&lzmaProps); if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) return SZ_ERROR_PARAM; p->props = *props; Lzma2EncProps_Normalize(&p->props); return SZ_OK; } Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) { CLzma2Enc *p = (CLzma2Enc *)pp; unsigned i; UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); for (i = 0; i < 40; i++) if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) break; return (Byte)i; } SRes Lzma2Enc_Encode(CLzma2EncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) { CLzma2Enc *p = (CLzma2Enc *)pp; int i; for (i = 0; i < p->props.numBlockThreads; i++) { CLzma2EncInt *t = &p->coders[i]; if (t->enc == NULL) { t->enc = LzmaEnc_Create(p->alloc); if (t->enc == NULL) return SZ_ERROR_MEM; } } #ifndef _7ZIP_ST if (p->props.numBlockThreads <= 1) #endif return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); #ifndef _7ZIP_ST { CMtCallbackImp mtCallback; mtCallback.funcTable.Code = MtCallbackImp_Code; mtCallback.lzma2Enc = p; p->mtCoder.progress = progress; p->mtCoder.inStream = inStream; p->mtCoder.outStream = outStream; p->mtCoder.alloc = p->alloc; p->mtCoder.mtCallback = &mtCallback.funcTable; p->mtCoder.blockSize = p->props.blockSize; p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16; p->mtCoder.numThreads = p->props.numBlockThreads; return MtCoder_Code(&p->mtCoder); } #endif } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Lzma2Enc.h0100777000000000000000000000334513761647206020447 0ustar00/* Lzma2Enc.h -- LZMA2 Encoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA2_ENC_H #define __LZMA2_ENC_H #include "LzmaEnc.h" EXTERN_C_BEGIN typedef struct { CLzmaEncProps lzmaProps; size_t blockSize; int numBlockThreads; int numTotalThreads; } CLzma2EncProps; void Lzma2EncProps_Init(CLzma2EncProps *p); void Lzma2EncProps_Normalize(CLzma2EncProps *p); /* ---------- CLzmaEnc2Handle Interface ---------- */ /* Lzma2Enc_* functions can return the following exit codes: Returns: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater in props SZ_ERROR_WRITE - Write callback error SZ_ERROR_PROGRESS - some break from progress callback SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ typedef void * CLzma2EncHandle; CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig); void Lzma2Enc_Destroy(CLzma2EncHandle p); SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); SRes Lzma2Enc_Encode(CLzma2EncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); /* ---------- One Call Interface ---------- */ /* Lzma2Encode Return code: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater SZ_ERROR_OUTPUT_EOF - output buffer overflow SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ /* SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); */ EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzmaDec.c0100777000000000000000000006631413761647206020353 0ustar00/* LzmaDec.c -- LZMA Decoder 2015-01-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "LzmaDec.h" #include #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define RC_INIT_SIZE 5 #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ { UPDATE_0(p); i = (i + i); A0; } else \ { UPDATE_1(p); i = (i + i) + 1; A1; } #define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) #define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } #define TREE_DECODE(probs, limit, i) \ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } /* #define _LZMA_SIZE_OPT */ #ifdef _LZMA_SIZE_OPT #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) #else #define TREE_6_DECODE(probs, i) \ { i = 1; \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ i -= 0x40; } #endif #define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) #define MATCHED_LITER_DEC \ matchByte <<= 1; \ bit = (matchByte & offs); \ probLit = prob + offs + bit + symbol; \ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0_CHECK range = bound; #define UPDATE_1_CHECK range -= bound; code -= bound; #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ { UPDATE_0_CHECK; i = (i + i); A0; } else \ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) #define TREE_DECODE_CHECK(probs, limit, i) \ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } #define kNumPosBitsMax 4 #define kNumPosStatesMax (1 << kNumPosBitsMax) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define LenChoice 0 #define LenChoice2 (LenChoice + 1) #define LenLow (LenChoice2 + 1) #define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) #define kNumLenProbs (LenHigh + kLenNumHighSymbols) #define kNumStates 12 #define kNumLitStates 7 #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #define kNumPosSlotBits 6 #define kNumLenToPosStates 4 #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kMatchMinLen 2 #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define IsMatch 0 #define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) #define IsRepG0 (IsRep + kNumStates) #define IsRepG1 (IsRepG0 + kNumStates) #define IsRepG2 (IsRepG1 + kNumStates) #define IsRep0Long (IsRepG2 + kNumStates) #define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) #define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) #define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) #define LenCoder (Align + kAlignTableSize) #define RepLenCoder (LenCoder + kNumLenProbs) #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 #define LZMA_LIT_SIZE 768 #define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization Out: Result: SZ_OK - OK SZ_ERROR_DATA - Error p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished = kMatchSpecLenStart + 1 : Flush marker = kMatchSpecLenStart + 2 : State Init Marker */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { CLzmaProb *probs = p->probs; unsigned state = p->state; UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; unsigned lc = p->prop.lc; Byte *dic = p->dic; SizeT dicBufSize = p->dicBufSize; SizeT dicPos = p->dicPos; UInt32 processedPos = p->processedPos; UInt32 checkDicSize = p->checkDicSize; unsigned len = 0; const Byte *buf = p->buf; UInt32 range = p->range; UInt32 code = p->code; do { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = processedPos & pbMask; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { unsigned symbol; UPDATE_0(prob); prob = probs + Literal; if (checkDicSize != 0 || processedPos != 0) prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; #ifdef _LZMA_SIZE_OPT do { NORMAL_LITER_DEC } while (symbol < 0x100); #else NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC #endif } else { unsigned matchByte = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; #ifdef _LZMA_SIZE_OPT do { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC } while (symbol < 0x100); #else { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC } #endif } dic[dicPos++] = (Byte)symbol; processedPos++; continue; } else { UPDATE_1(prob); prob = probs + IsRep + state; IF_BIT_0(prob) { UPDATE_0(prob); state += kNumStates; prob = probs + LenCoder; } else { UPDATE_1(prob); if (checkDicSize == 0 && processedPos == 0) return SZ_ERROR_DATA; prob = probs + IsRepG0 + state; IF_BIT_0(prob) { UPDATE_0(prob); prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { UPDATE_0(prob); dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; continue; } UPDATE_1(prob); } else { UInt32 distance; UPDATE_1(prob); prob = probs + IsRepG1 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep1; } else { UPDATE_1(prob); prob = probs + IsRepG2 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep2; } else { UPDATE_1(prob); distance = rep3; rep3 = rep2; } rep2 = rep1; } rep1 = rep0; rep0 = distance; } state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = (1 << kLenNumLowBits); } else { UPDATE_1(probLen); probLen = prob + LenChoice2; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = (1 << kLenNumMidBits); } else { UPDATE_1(probLen); probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = (1 << kLenNumHighBits); } } TREE_DECODE(probLen, limit, len); len += offset; } if (state >= kNumStates) { UInt32 distance; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_6_DECODE(prob, distance); if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; int numDirectBits = (int)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { distance <<= numDirectBits; prob = probs + SpecPos + distance - posSlot - 1; { UInt32 mask = 1; unsigned i = 1; do { GET_BIT2(prob + i, i, ; , distance |= mask); mask <<= 1; } while (--numDirectBits != 0); } } else { numDirectBits -= kNumAlignBits; do { NORMALIZE range >>= 1; { UInt32 t; code -= range; t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ distance = (distance << 1) + (t + 1); code += range & t; } /* distance <<= 1; if (code >= range) { code -= range; distance |= 1; } */ } while (--numDirectBits != 0); prob = probs + Align; distance <<= kNumAlignBits; { unsigned i = 1; GET_BIT2(prob + i, i, ; , distance |= 1); GET_BIT2(prob + i, i, ; , distance |= 2); GET_BIT2(prob + i, i, ; , distance |= 4); GET_BIT2(prob + i, i, ; , distance |= 8); } if (distance == (UInt32)0xFFFFFFFF) { len += kMatchSpecLenStart; state -= kNumStates; break; } } } rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance + 1; if (checkDicSize == 0) { if (distance >= processedPos) return SZ_ERROR_DATA; } else if (distance >= checkDicSize) return SZ_ERROR_DATA; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; if (limit == dicPos) return SZ_ERROR_DATA; { SizeT rem = limit - dicPos; unsigned curLen = ((rem < len) ? (unsigned)rem : len); SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); processedPos += curLen; len -= curLen; if (pos + curLen <= dicBufSize) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; const Byte *lim = dest + curLen; dicPos += curLen; do *(dest) = (Byte)*(dest + src); while (++dest != lim); } else { do { dic[dicPos++] = dic[pos]; if (++pos == dicBufSize) pos = 0; } while (--curLen != 0); } } } } while (dicPos < limit && buf < bufLimit); NORMALIZE; p->buf = buf; p->range = range; p->code = code; p->remainLen = len; p->dicPos = dicPos; p->processedPos = processedPos; p->reps[0] = rep0; p->reps[1] = rep1; p->reps[2] = rep2; p->reps[3] = rep3; p->state = state; return SZ_OK; } static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) { if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) { Byte *dic = p->dic; SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; UInt32 rep0 = p->reps[0]; if (limit - dicPos < len) len = (unsigned)(limit - dicPos); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; p->processedPos += len; p->remainLen -= len; while (len != 0) { len--; dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; } } static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { do { SizeT limit2 = limit; if (p->checkDicSize == 0) { UInt32 rem = p->prop.dicSize - p->processedPos; if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); if (p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) { p->remainLen = kMatchSpecLenStart; } return 0; } typedef enum { DUMMY_ERROR, /* unexpected end of input stream */ DUMMY_LIT, DUMMY_MATCH, DUMMY_REP } ELzmaDummy; static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) { UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) prob += (LZMA_LIT_SIZE * ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { unsigned symbol = 1; do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); } else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) } while (symbol < 0x100); } res = DUMMY_LIT; } else { unsigned len; UPDATE_1_CHECK; prob = probs + IsRep + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; state = 0; prob = probs + LenCoder; res = DUMMY_MATCH; } else { UPDATE_1_CHECK; res = DUMMY_REP; prob = probs + IsRepG0 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; NORMALIZE_CHECK; return DUMMY_REP; } else { UPDATE_1_CHECK; } } else { UPDATE_1_CHECK; prob = probs + IsRepG1 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; prob = probs + IsRepG2 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; } } } state = kNumStates; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = 1 << kLenNumLowBits; } else { UPDATE_1_CHECK; probLen = prob + LenChoice2; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = 1 << kLenNumMidBits; } else { UPDATE_1_CHECK; probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = 1 << kLenNumHighBits; } } TREE_DECODE_CHECK(probLen, limit, len); len += offset; } if (state < 4) { unsigned posSlot; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { int numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ if (posSlot < kEndPosModelIndex) { prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; } else { numDirectBits -= kNumAlignBits; do { NORMALIZE_CHECK range >>= 1; code -= range & (((code - range) >> 31) - 1); /* if (code >= range) code -= range; */ } while (--numDirectBits != 0); prob = probs + Align; numDirectBits = kNumAlignBits; } { unsigned i = 1; do { GET_BIT_CHECK(prob + i, i); } while (--numDirectBits != 0); } } } } } NORMALIZE_CHECK; return res; } static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) { p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); p->range = 0xFFFFFFFF; p->needFlush = 0; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; p->remainLen = 0; p->tempBufSize = 0; if (initDic) { p->processedPos = 0; p->checkDicSize = 0; p->needInitState = 1; } if (initState) p->needInitState = 1; } void LzmaDec_Init(CLzmaDec *p) { p->dicPos = 0; LzmaDec_InitDicAndState(p, True, True); } static void LzmaDec_InitStateReal(CLzmaDec *p) { UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); UInt32 i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; p->state = 0; p->needInitState = 0; } SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; (*srcLen) = 0; LzmaDec_WriteRem(p, dicLimit); *status = LZMA_STATUS_NOT_SPECIFIED; while (p->remainLen != kMatchSpecLenStart) { int checkEndMarkNow; if (p->needFlush != 0) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; if (p->tempBufSize < RC_INIT_SIZE) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; LzmaDec_InitRc(p, p->tempBuf); p->tempBufSize = 0; } checkEndMarkNow = 0; if (p->dicPos >= dicLimit) { if (p->remainLen == 0 && p->code == 0) { *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; return SZ_OK; } if (finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->remainLen != 0) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } checkEndMarkNow = 1; } if (p->needInitState) LzmaDec_InitStateReal(p); if (p->tempBufSize == 0) { SizeT processed; const Byte *bufLimit; if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, src, inSize); if (dummyRes == DUMMY_ERROR) { memcpy(p->tempBuf, src, inSize); p->tempBufSize = (unsigned)inSize; (*srcLen) += inSize; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } bufLimit = src; } else bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; p->buf = src; if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) return SZ_ERROR_DATA; processed = (SizeT)(p->buf - src); (*srcLen) += processed; src += processed; inSize -= processed; } else { unsigned rem = p->tempBufSize, lookAhead = 0; while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) p->tempBuf[rem++] = src[lookAhead++]; p->tempBufSize = rem; if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); if (dummyRes == DUMMY_ERROR) { (*srcLen) += lookAhead; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } } p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; p->tempBufSize = 0; } } if (p->code == 0) *status = LZMA_STATUS_FINISHED_WITH_MARK; return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; } SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen; SizeT inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT inSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->dicPos == p->dicBufSize) p->dicPos = 0; dicPos = p->dicPos; if (outSize > p->dicBufSize - dicPos) { outSizeCur = p->dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); src += inSizeCur; inSize -= inSizeCur; *srcLen += inSizeCur; outSizeCur = p->dicPos - dicPos; memcpy(dest, p->dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); p->probs = 0; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); p->dic = 0; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) { LzmaDec_FreeProbs(p, alloc); LzmaDec_FreeDict(p, alloc); } SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) { UInt32 dicSize; Byte d; if (size < LZMA_PROPS_SIZE) return SZ_ERROR_UNSUPPORTED; else dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); if (dicSize < LZMA_DIC_MIN) dicSize = LZMA_DIC_MIN; p->dicSize = dicSize; d = data[0]; if (d >= (9 * 5 * 5)) return SZ_ERROR_UNSUPPORTED; p->lc = d % 9; d /= 9; p->pb = d / 5; p->lp = d % 5; return SZ_OK; } static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); if (p->probs == 0 || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; if (p->probs == 0) return SZ_ERROR_MEM; } return SZ_OK; } SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); p->prop = propNew; return SZ_OK; } SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); dicBufSize = propNew.dicSize; if (p->dic == 0 || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); if (p->dic == 0) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; } } p->dicBufSize = dicBufSize; p->prop = propNew; return SZ_OK; } SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzmaDec p; SRes res; SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; if (inSize < RC_INIT_SIZE) return SZ_ERROR_INPUT_EOF; LzmaDec_Construct(&p); RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); p.dic = dest; p.dicBufSize = outSize; LzmaDec_Init(&p); *srcLen = inSize; res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); *destLen = p.dicPos; if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; LzmaDec_FreeProbs(&p, alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzmaDec.h0100777000000000000000000001524613761647206020356 0ustar00/* LzmaDec.h -- LZMA Decoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H #include "7zTypes.h" EXTERN_C_BEGIN /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, but memory usage for CLzmaDec::probs will be doubled in that case */ #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif /* ---------- LZMA Properties ---------- */ #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaProps { unsigned lc, lp, pb; UInt32 dicSize; } CLzmaProps; /* LzmaProps_Decode - decodes properties Returns: SZ_OK SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); /* ---------- LZMA Decoder state ---------- */ /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ #define LZMA_REQUIRED_INPUT_MAX 20 typedef struct { CLzmaProps prop; CLzmaProb *probs; Byte *dic; const Byte *buf; UInt32 range, code; SizeT dicPos; SizeT dicBufSize; UInt32 processedPos; UInt32 checkDicSize; unsigned state; UInt32 reps[4]; unsigned remainLen; int needFlush; int needInitState; UInt32 numProbs; unsigned tempBufSize; Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } void LzmaDec_Init(CLzmaDec *p); /* There are two types of LZMA streams: 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ typedef enum { LZMA_FINISH_ANY, /* finish at any point */ LZMA_FINISH_END /* block must be finished at the end */ } ELzmaFinishMode; /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! You must use LZMA_FINISH_END, when you know that current output buffer covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, and output value of destLen will be less than output buffer size limit. You can check status result also. You can use multiple checks to test data integrity after full decompression: 1) Check Result and "status" variable. 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. You must use correct finish mode in that case. */ typedef enum { LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ } ELzmaStatus; /* ELzmaStatus is used only as output value for function call */ /* ---------- Interfaces ---------- */ /* There are 3 levels of interfaces: 1) Dictionary Interface 2) Buffer Interface 3) One Call Interface You can select any of these interfaces, but don't mix functions from different groups for same object. */ /* There are two variants to allocate state for Dictionary Interface: 1) LzmaDec_Allocate / LzmaDec_Free 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs You can use variant 2, if you set dictionary buffer manually. For Buffer Interface you must always use variant 1. LzmaDec_Allocate* can return: SZ_OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); /* ---------- Dictionary Interface ---------- */ /* You can use it, if you want to eliminate the overhead for data copying from dictionary to some other external buffer. You must work with CLzmaDec variables directly in this interface. STEPS: LzmaDec_Constr() LzmaDec_Allocate() for (each new stream) { LzmaDec_Init() while (it needs more decompression) { LzmaDec_DecodeToDic() use data from CLzmaDec::dic and update CLzmaDec::dicPos } } LzmaDec_Free() */ /* LzmaDec_DecodeToDic The decoding to internal dictionary buffer (CLzmaDec::dic). You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! finishMode: It has meaning only if the decoding reaches output limit (dicLimit). LZMA_FINISH_ANY - Decode just dicLimit bytes. LZMA_FINISH_END - Stream must be finished after dicLimit. Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error */ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- Buffer Interface ---------- */ /* It's zlib-like interface. See LzmaDec_DecodeToDic description for information about STEPS and return results, but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need to work with CLzmaDec variables manually. finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). */ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* LzmaDecode finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzmaEnc.c0100777000000000000000000017235013761647206020363 0ustar00/* LzmaEnc.c -- LZMA Encoder 2014-12-29 : Igor Pavlov : Public domain */ #include "Precomp.h" #include /* #define SHOW_STAT */ /* #define SHOW_STAT2 */ #if defined(SHOW_STAT) || defined(SHOW_STAT2) #include #endif #include "LzmaEnc.h" #include "LzFind.h" #ifndef _7ZIP_ST #include "LzFindMt.h" #endif #ifdef SHOW_STAT static unsigned g_STAT_OFFSET = 0; #endif #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) #define kBlockSize (9 << 10) #define kUnpackBlockSize (1 << 18) #define kMatchArraySize (1 << 21) #define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) #define kNumMaxDirectBits (31) #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define kProbInitValue (kBitModelTotal >> 1) #define kNumMoveReducingBits 4 #define kNumBitPriceShiftBits 4 #define kBitPrice (1 << kNumBitPriceShiftBits) void LzmaEncProps_Init(CLzmaEncProps *p) { p->level = 5; p->dictSize = p->mc = 0; p->reduceSize = (UInt64)(Int64)-1; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; p->writeEndMark = 0; } void LzmaEncProps_Normalize(CLzmaEncProps *p) { int level = p->level; if (level < 0) level = 5; p->level = level; if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->dictSize > p->reduceSize) { unsigned i; for (i = 11; i <= 30; i++) { if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } } } if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST ((p->btMode && p->algo) ? 2 : 1); #else 1; #endif } UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) { CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); return props.dictSize; } /* #define LZMA_LOG_BSR */ /* Define it for Intel's CPU */ #ifdef LZMA_LOG_BSR #define kDicLogSizeMaxCompress 30 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res); return res; } #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } #else #define kNumLogBits (9 + (int)sizeof(size_t) / 2) #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) void LzmaEnc_FastPosInit(Byte *g_FastPos) { int c = 2, slotFast; g_FastPos[0] = 0; g_FastPos[1] = 1; for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) { UInt32 k = (1 << ((slotFast >> 1) - 1)); UInt32 j; for (j = 0; j < k; j++, c++) g_FastPos[c] = (Byte)slotFast; } } #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } */ #define GetPosSlot1(pos) p->g_FastPos[pos] #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } #endif #define LZMA_NUM_REPS 4 typedef unsigned CState; typedef struct { UInt32 price; CState state; int prev1IsChar; int prev2; UInt32 posPrev2; UInt32 backPrev2; UInt32 posPrev; UInt32 backPrev; UInt32 backs[LZMA_NUM_REPS]; } COptimal; #define kNumOpts (1 << 12) #define kNumLenToPosStates 4 #define kNumPosSlotBits 6 #define kDicLogSizeMin 0 #define kDicLogSizeMax 32 #define kDistTableSizeMax (kDicLogSizeMax * 2) #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kAlignMask (kAlignTableSize - 1) #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif #define LZMA_PB_MAX 4 #define LZMA_LC_MAX 8 #define LZMA_LP_MAX 4 #define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define LZMA_MATCH_LEN_MIN 2 #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) #define kNumStates 12 typedef struct { CLzmaProb choice; CLzmaProb choice2; CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; typedef struct { CLenEnc p; UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; typedef struct { UInt32 range; Byte cache; UInt64 low; UInt64 cacheSize; Byte *buf; Byte *bufLim; Byte *bufBase; ISeqOutStream *outStream; UInt64 processed; SRes res; } CRangeEnc; typedef struct { CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; } CSaveState; typedef struct { IMatchFinder matchFinder; void *matchFinderObj; #ifndef _7ZIP_ST Bool mtMode; CMatchFinderMt matchFinderMt; #endif CMatchFinder matchFinderBase; #ifndef _7ZIP_ST Byte pad[128]; #endif UInt32 optimumEndIndex; UInt32 optimumCurrentIndex; UInt32 longestMatchLength; UInt32 numPairs; UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR Byte g_FastPos[1 << kNumLogBits]; #endif UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; UInt32 numFastBytes; UInt32 additionalOffset; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; UInt32 alignPriceCount; UInt32 distTableSize; unsigned lc, lp, pb; unsigned lpMask, pbMask; CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; unsigned lclp; Bool fastMode; CRangeEnc rc; Bool writeEndMark; UInt64 nowPos64; UInt32 matchPriceCount; Bool finished; Bool multiThread; SRes result; UInt32 dictSize; int needInit; CSaveState saveState; } CLzmaEnc; void LzmaEnc_SaveState(CLzmaEncHandle pp) { CLzmaEnc *p = (CLzmaEnc *)pp; CSaveState *dest = &p->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp) { CLzmaEnc *dest = (CLzmaEnc *)pp; const CSaveState *p = &dest->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) { CLzmaEnc *p = (CLzmaEnc *)pp; CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30)) return SZ_ERROR_PARAM; p->dictSize = props.dictSize; { unsigned fb = props.fb; if (fb < 5) fb = 5; if (fb > LZMA_MATCH_LEN_MAX) fb = LZMA_MATCH_LEN_MAX; p->numFastBytes = fb; } p->lc = props.lc; p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); p->matchFinderBase.btMode = props.btMode; { UInt32 numHashBytes = 4; if (props.btMode) { if (props.numHashBytes < 2) numHashBytes = 2; else if (props.numHashBytes < 4) numHashBytes = props.numHashBytes; } p->matchFinderBase.numHashBytes = numHashBytes; } p->matchFinderBase.cutValue = props.mc; p->writeEndMark = props.writeEndMark; #ifndef _7ZIP_ST /* if (newMultiThread != _multiThread) { ReleaseMatchFinder(); _multiThread = newMultiThread; } */ p->multiThread = (props.numThreads > 1); #endif return SZ_OK; } static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; #define IsCharState(s) ((s) < 7) #define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) #define kInfinityPrice (1 << 30) static void RangeEnc_Construct(CRangeEnc *p) { p->outStream = 0; p->bufBase = 0; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) #define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { if (p->bufBase == 0) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); if (p->bufBase == 0) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; } return 1; } static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->bufBase); p->bufBase = 0; } static void RangeEnc_Init(CRangeEnc *p) { /* Stream.Init(); */ p->low = 0; p->range = 0xFFFFFFFF; p->cacheSize = 1; p->cache = 0; p->buf = p->bufBase; p->processed = 0; p->res = SZ_OK; } static void RangeEnc_FlushStream(CRangeEnc *p) { size_t num; if (p->res != SZ_OK) return; num = p->buf - p->bufBase; if (num != p->outStream->Write(p->outStream, p->bufBase, num)) p->res = SZ_ERROR_WRITE; p->processed += num; p->buf = p->bufBase; } static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) { if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0) { Byte temp = p->cache; do { Byte *buf = p->buf; *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); p->buf = buf; if (buf == p->bufLim) RangeEnc_FlushStream(p); temp = 0xFF; } while (--p->cacheSize != 0); p->cache = (Byte)((UInt32)p->low >> 24); } p->cacheSize++; p->low = (UInt32)p->low << 8; } static void RangeEnc_FlushData(CRangeEnc *p) { int i; for (i = 0; i < 5; i++) RangeEnc_ShiftLow(p); } static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits) { do { p->range >>= 1; p->low += p->range & (0 - ((value >> --numBits) & 1)); if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } while (numBits != 0); } static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) { UInt32 ttt = *prob; UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; if (symbol == 0) { p->range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } else { p->low += newBound; p->range -= newBound; ttt -= ttt >> kNumMoveBits; } *prob = (CLzmaProb)ttt; if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) { symbol |= 0x100; do { RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); } static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) { UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); } void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) { const int kCyclesBits = kNumBitPriceShiftBits; UInt32 w = i; UInt32 bitCount = 0; int j; for (j = 0; j < kCyclesBits; j++) { w = w * w; bitCount <<= 1; while (w >= ((UInt32)1 << 16)) { w >>= 1; bitCount++; } } ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); } } #define GET_PRICE(prob, symbol) \ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICEa(prob, symbol) \ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100; do { price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); return price; } static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); return price; } static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = numBitLevels; i != 0;) { UInt32 bit; i--; bit = (symbol >> i) & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; } } static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = 0; i < numBitLevels; i++) { UInt32 bit = symbol & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; symbol >>= 1; } } static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels); while (symbol != 1) { price += GET_PRICEa(probs[symbol >> 1], symbol & 1); symbol >>= 1; } return price; } static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1; int i; for (i = numBitLevels; i != 0; i--) { UInt32 bit = symbol & 1; symbol >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) | bit; } return price; } static void LenEnc_Init(CLenEnc *p) { unsigned i; p->choice = p->choice2 = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) p->low[i] = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) p->mid[i] = kProbInitValue; for (i = 0; i < kLenNumHighSymbols; i++) p->high[i] = kProbInitValue; } static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) { if (symbol < kLenNumLowSymbols) { RangeEnc_EncodeBit(rc, &p->choice, 0); RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); } else { RangeEnc_EncodeBit(rc, &p->choice, 1); if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) { RangeEnc_EncodeBit(rc, &p->choice2, 0); RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); } else { RangeEnc_EncodeBit(rc, &p->choice2, 1); RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); } } } static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice); UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); UInt32 i = 0; for (i = 0; i < kLenNumLowSymbols; i++) { if (i >= numSymbols) return; prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); } for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) { if (i >= numSymbols) return; prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); } for (; i < numSymbols; i++) prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice) if (--p->counters[posState] == 0) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void MovePos(CLzmaEnc *p, UInt32 num) { #ifdef SHOW_STAT g_STAT_OFFSET += num; printf("\n MovePos %d", num); #endif if (num != 0) { p->additionalOffset += num; p->matchFinder.Skip(p->matchFinderObj, num); } } static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) { UInt32 lenRes = 0, numPairs; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); #ifdef SHOW_STAT printf("\n i = %d numPairs = %d ", g_STAT_OFFSET, numPairs / 2); g_STAT_OFFSET++; { UInt32 i; for (i = 0; i < numPairs; i += 2) printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); } #endif if (numPairs > 0) { lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { const Byte *pby2 = pby - distance; for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); } } } p->additionalOffset++; *numDistancePairsRes = numPairs; return lenRes; } #define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; #define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; #define IsShortRep(p) ((p)->backPrev == 0) static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) { return GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]); } static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) { UInt32 price; if (repIndex == 0) { price = GET_PRICE_0(p->isRepG0[state]); price += GET_PRICE_1(p->isRep0Long[state][posState]); } else { price = GET_PRICE_1(p->isRepG0[state]); if (repIndex == 1) price += GET_PRICE_0(p->isRepG1[state]); else { price += GET_PRICE_1(p->isRepG1[state]); price += GET_PRICE(p->isRepG2[state], repIndex - 2); } } return price; } static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) { return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + GetPureRepPrice(p, repIndex, state, posState); } static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) { UInt32 posMem = p->opt[cur].posPrev; UInt32 backMem = p->opt[cur].backPrev; p->optimumEndIndex = cur; do { if (p->opt[cur].prev1IsChar) { MakeAsChar(&p->opt[posMem]) p->opt[posMem].posPrev = posMem - 1; if (p->opt[cur].prev2) { p->opt[posMem - 1].prev1IsChar = False; p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; } } { UInt32 posPrev = posMem; UInt32 backCur = backMem; backMem = p->opt[posPrev].backPrev; posMem = p->opt[posPrev].posPrev; p->opt[posPrev].backPrev = backCur; p->opt[posPrev].posPrev = cur; cur = posPrev; } } while (cur != 0); *backRes = p->opt[0].backPrev; p->optimumCurrentIndex = p->opt[0].posPrev; return p->optimumCurrentIndex; } #define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; UInt32 matchPrice, repMatchPrice, normalMatchPrice; UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; UInt32 *matches; const Byte *data; Byte curByte, matchByte; if (p->optimumEndIndex != p->optimumCurrentIndex) { const COptimal *opt = &p->opt[p->optimumCurrentIndex]; UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; *backRes = opt->backPrev; p->optimumCurrentIndex = opt->posPrev; return lenRes; } p->optimumCurrentIndex = p->optimumEndIndex = 0; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; if (numAvail < 2) { *backRes = (UInt32)(-1); return 1; } if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repMaxIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; data2 = data - (reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; continue; } for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); repLens[i] = lenTest; if (lenTest > repLens[repMaxIndex]) repMaxIndex = i; } if (repLens[repMaxIndex] >= p->numFastBytes) { UInt32 lenRes; *backRes = repMaxIndex; lenRes = repLens[repMaxIndex]; MovePos(p, lenRes - 1); return lenRes; } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } curByte = *data; matchByte = *(data - (reps[0] + 1)); if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) { *backRes = (UInt32)-1; return 1; } p->opt[0].state = (CState)p->state; posState = (position & p->pbMask); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + (!IsCharState(p->state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } MakeAsChar(&p->opt[1]); matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); if (matchByte == curByte) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); if (shortRepPrice < p->opt[1].price) { p->opt[1].price = shortRepPrice; MakeAsShortRep(&p->opt[1]); } } lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); if (lenEnd < 2) { *backRes = p->opt[1].backPrev; return 1; } p->opt[1].posPrev = 0; for (i = 0; i < LZMA_NUM_REPS; i++) p->opt[0].backs[i] = reps[i]; len = lenEnd; do p->opt[len--].price = kInfinityPrice; while (len >= 2); for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 repLen = repLens[i]; UInt32 price; if (repLen < 2) continue; price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; COptimal *opt = &p->opt[repLen]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = i; opt->prev1IsChar = False; } } while (--repLen >= 2); } normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); if (len <= mainLen) { UInt32 offs = 0; while (len > matches[offs]) offs += 2; for (; ; len++) { COptimal *opt; UInt32 distance = matches[offs + 1]; UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(len); if (distance < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][distance]; else { UInt32 slot; GetPosSlot2(distance, slot); curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; } opt = &p->opt[len]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = distance + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (len == matches[offs]) { offs += 2; if (offs == numPairs) break; } } } cur = 0; #ifdef SHOW_STAT2 if (position >= 0) { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); } #endif for (;;) { UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; Bool nextIsChar; Byte curByte, matchByte; const Byte *data; COptimal *curOpt; COptimal *nextOpt; cur++; if (cur == lenEnd) return Backward(p, backRes, cur); newLen = ReadMatchDistances(p, &numPairs); if (newLen >= p->numFastBytes) { p->numPairs = numPairs; p->longestMatchLength = newLen; return Backward(p, backRes, cur); } position++; curOpt = &p->opt[cur]; posPrev = curOpt->posPrev; if (curOpt->prev1IsChar) { posPrev--; if (curOpt->prev2) { state = p->opt[curOpt->posPrev2].state; if (curOpt->backPrev2 < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } else state = p->opt[posPrev].state; state = kLiteralNextStates[state]; } else state = p->opt[posPrev].state; if (posPrev == cur - 1) { if (IsShortRep(curOpt)) state = kShortRepNextStates[state]; else state = kLiteralNextStates[state]; } else { UInt32 pos; const COptimal *prevOpt; if (curOpt->prev1IsChar && curOpt->prev2) { posPrev = curOpt->posPrev2; pos = curOpt->backPrev2; state = kRepNextStates[state]; } else { pos = curOpt->backPrev; if (pos < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } prevOpt = &p->opt[posPrev]; if (pos < LZMA_NUM_REPS) { UInt32 i; reps[0] = prevOpt->backs[pos]; for (i = 1; i <= pos; i++) reps[i] = prevOpt->backs[i - 1]; for (; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i]; } else { UInt32 i; reps[0] = (pos - LZMA_NUM_REPS); for (i = 1; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i - 1]; } } curOpt->state = (CState)state; curOpt->backs[0] = reps[0]; curOpt->backs[1] = reps[1]; curOpt->backs[2] = reps[2]; curOpt->backs[3] = reps[3]; curPrice = curOpt->price; nextIsChar = False; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; curByte = *data; matchByte = *(data - (reps[0] + 1)); posState = (position & p->pbMask); curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); curAnd1Price += (!IsCharState(state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } nextOpt = &p->opt[cur + 1]; if (curAnd1Price < nextOpt->price) { nextOpt->price = curAnd1Price; nextOpt->posPrev = cur; MakeAsChar(nextOpt); nextIsChar = True; } matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); if (shortRepPrice <= nextOpt->price) { nextOpt->price = shortRepPrice; nextOpt->posPrev = cur; MakeAsShortRep(nextOpt); nextIsChar = True; } } numAvailFull = p->numAvail; { UInt32 temp = kNumOpts - 1 - cur; if (temp < numAvailFull) numAvailFull = temp; } if (numAvailFull < 2) continue; numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); if (!nextIsChar && matchByte != curByte) /* speed optimization */ { /* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; const Byte *data2 = data - (reps[0] + 1); UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); lenTest2 = temp - 1; if (lenTest2 >= 2) { UInt32 state2 = kLiteralNextStates[state]; UInt32 posStateNext = (position + 1) & p->pbMask; UInt32 nextRepMatchPrice = curAnd1Price + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = False; } } } } startLen = 2; /* speed optimization */ { UInt32 repIndex; for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) { UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; const Byte *data2 = data - (reps[repIndex] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); while (lenEnd < cur + lenTest) p->opt[++lenEnd].price = kInfinityPrice; lenTestTemp = lenTest; price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; COptimal *opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = repIndex; opt->prev1IsChar = False; } } while (--lenTest >= 2); lenTest = lenTestTemp; if (repIndex == 0) startLen = lenTest + 1; /* if (_maxMode) */ { UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = price + p->repLenEnc.prices[posState][lenTest - 2] + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (position + lenTest + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + lenTest + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = repIndex; } } } } } } /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ if (newLen > numAvail) { newLen = numAvail; for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); matches[numPairs] = newLen; numPairs += 2; } if (newLen >= startLen) { UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); UInt32 offs, curBack, posSlot; UInt32 lenTest; while (lenEnd < cur + newLen) p->opt[++lenEnd].price = kInfinityPrice; offs = 0; while (startLen > matches[offs]) offs += 2; curBack = matches[offs + 1]; GetPosSlot2(curBack, posSlot); for (lenTest = /*2*/ startLen; ; lenTest++) { UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(lenTest); COptimal *opt; if (curBack < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; else curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = curBack + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ const Byte *data2 = data - (curBack + 1); UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (posStateNext + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 offset = cur + lenTest + 1 + lenTest2; UInt32 curAndLenPrice; COptimal *opt; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = curBack + LZMA_NUM_REPS; } } } offs += 2; if (offs == numPairs) break; curBack = matches[offs + 1]; if (curBack >= kNumFullDistances) GetPosSlot2(curBack, posSlot); } } } } } #define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) { UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; const Byte *data; const UInt32 *matches; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; *backRes = (UInt32)-1; if (numAvail < 2) return 1; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repLen = repIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++); if (len >= p->numFastBytes) { *backRes = i; MovePos(p, len - 1); return len; } if (len > repLen) { repIndex = i; repLen = len; } } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } mainDist = 0; /* for GCC */ if (mainLen >= 2) { mainDist = matches[numPairs - 1]; while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) { if (!ChangePair(matches[numPairs - 3], mainDist)) break; numPairs -= 2; mainLen = matches[numPairs - 2]; mainDist = matches[numPairs - 1]; } if (mainLen == 2 && mainDist >= 0x80) mainLen = 1; } if (repLen >= 2 && ( (repLen + 1 >= mainLen) || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) { *backRes = repIndex; MovePos(p, repLen - 1); return repLen; } if (mainLen < 2 || numAvail <= 2) return 1; p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); if (p->longestMatchLength >= 2) { UInt32 newDistance = matches[p->numPairs - 1]; if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || (p->longestMatchLength > mainLen + 1) || (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) return 1; } data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1; for (len = 2; len < limit && data[len] == data2[len]; len++); if (len >= limit) return 1; } *backRes = mainDist + LZMA_NUM_REPS; MovePos(p, mainLen - 2); return mainLen; } static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) { UInt32 len; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; len = LZMA_MATCH_LEN_MIN; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); } static SRes CheckErrors(CLzmaEnc *p) { if (p->result != SZ_OK) return p->result; if (p->rc.res != SZ_OK) p->result = SZ_ERROR_WRITE; if (p->matchFinderBase.result != SZ_OK) p->result = SZ_ERROR_READ; if (p->result != SZ_OK) p->finished = True; return p->result; } static SRes Flush(CLzmaEnc *p, UInt32 nowPos) { /* ReleaseMFStream(); */ p->finished = True; if (p->writeEndMark) WriteEndMarker(p, nowPos & p->pbMask); RangeEnc_FlushData(&p->rc); RangeEnc_FlushStream(&p->rc); return CheckErrors(p); } static void FillAlignPrices(CLzmaEnc *p) { UInt32 i; for (i = 0; i < kAlignTableSize; i++) p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); p->alignPriceCount = 0; } static void FillDistancesPrices(CLzmaEnc *p) { UInt32 tempPrices[kNumFullDistances]; UInt32 i, lenToPosState; for (i = kStartPosModelIndex; i < kNumFullDistances; i++) { UInt32 posSlot = GetPosSlot1(i); UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); } for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) { UInt32 posSlot; const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; for (posSlot = 0; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); { UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; UInt32 i; for (i = 0; i < kStartPosModelIndex; i++) distancesPrices[i] = posSlotPrices[i]; for (; i < kNumFullDistances; i++) distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; } } p->matchPriceCount = 0; } void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase; #endif { CLzmaEncProps props; LzmaEncProps_Init(&props); LzmaEnc_SetProps(p, &props); } #ifndef LZMA_LOG_BSR LzmaEnc_FastPosInit(p->g_FastPos); #endif LzmaEnc_InitPriceTables(p->ProbPrices); p->litProbs = 0; p->saveState.litProbs = 0; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); if (p != 0) LzmaEnc_Construct((CLzmaEnc *)p); return p; } void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); p->litProbs = 0; p->saveState.litProbs = 0; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) { #ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); } void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) { LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); alloc->Free(alloc, p); } static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) { UInt32 nowPos32, startPos32; if (p->needInit) { p->matchFinder.Init(p->matchFinderObj); p->needInit = 0; } if (p->finished) return p->result; RINOK(CheckErrors(p)); nowPos32 = (UInt32)p->nowPos64; startPos32 = nowPos32; if (p->nowPos64 == 0) { UInt32 numPairs; Byte curByte; if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) return Flush(p, nowPos32); ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++; } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) for (;;) { UInt32 pos, len, posState; if (p->fastMode) len = GetOptimumFast(p, &pos); else len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask; if (len == 1 && pos == (UInt32)-1) { Byte curByte; CLzmaProb *probs; const Byte *data; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; curByte = *data; probs = LIT_PROBS(nowPos32, *(data - 1)); if (IsCharState(p->state)) LitEnc_Encode(&p->rc, probs, curByte); else LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); p->state = kLiteralNextStates[p->state]; } else { RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); if (pos < LZMA_NUM_REPS) { RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); if (pos == 0) { RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); } else { UInt32 distance = p->reps[pos]; RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); if (pos == 1) RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); else { RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); if (pos == 3) p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; } p->reps[1] = p->reps[0]; p->reps[0] = distance; } if (len == 1) p->state = kShortRepNextStates[p->state]; else { LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); p->state = kRepNextStates[p->state]; } } else { UInt32 posSlot; RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); pos -= LZMA_NUM_REPS; GetPosSlot(pos, posSlot); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); UInt32 posReduced = pos - base; if (posSlot < kEndPosModelIndex) RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); else { RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); p->alignPriceCount++; } } p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; p->reps[1] = p->reps[0]; p->reps[0] = pos; p->matchPriceCount++; } } p->additionalOffset -= len; nowPos32 += len; if (p->additionalOffset == 0) { UInt32 processed; if (!p->fastMode) { if (p->matchPriceCount >= (1 << 7)) FillDistancesPrices(p); if (p->alignPriceCount >= kAlignTableSize) FillAlignPrices(p); } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) break; processed = nowPos32 - startPos32; if (useLimits) { if (processed + kNumOpts + 300 >= maxUnpackSize || RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } else if (processed >= (1 << 15)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p); } } } p->nowPos64 += nowPos32 - startPos32; return Flush(p, nowPos32); } #define kBigHashDicLimit ((UInt32)1 << 24) static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; #ifndef _7ZIP_ST p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); #endif { unsigned lclp = p->lc + p->lp; if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); if (p->litProbs == 0 || p->saveState.litProbs == 0) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM; } p->lclp = lclp; } } p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize; #ifndef _7ZIP_ST if (p->mtMode) { RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); p->matchFinderObj = &p->matchFinderMt; MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); } else #endif { if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) return SZ_ERROR_MEM; p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } return SZ_OK; } void LzmaEnc_Init(CLzmaEnc *p) { UInt32 i; p->state = 0; for (i = 0 ; i < LZMA_NUM_REPS; i++) p->reps[i] = 0; RangeEnc_Init(&p->rc); for (i = 0; i < kNumStates; i++) { UInt32 j; for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) { p->isMatch[i][j] = kProbInitValue; p->isRep0Long[i][j] = kProbInitValue; } p->isRep[i] = kProbInitValue; p->isRepG0[i] = kProbInitValue; p->isRepG1[i] = kProbInitValue; p->isRepG2[i] = kProbInitValue; } { UInt32 num = 0x300 << (p->lp + p->lc); for (i = 0; i < num; i++) p->litProbs[i] = kProbInitValue; } { for (i = 0; i < kNumLenToPosStates; i++) { CLzmaProb *probs = p->posSlotEncoder[i]; UInt32 j; for (j = 0; j < (1 << kNumPosSlotBits); j++) probs[j] = kProbInitValue; } } { for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) p->posEncoders[i] = kProbInitValue; } LenEnc_Init(&p->lenEnc.p); LenEnc_Init(&p->repLenEnc.p); for (i = 0; i < (1 << kNumAlignBits); i++) p->posAlignEncoder[i] = kProbInitValue; p->optimumEndIndex = 0; p->optimumCurrentIndex = 0; p->additionalOffset = 0; p->pbMask = (1 << p->pb) - 1; p->lpMask = (1 << p->lp) - 1; } void LzmaEnc_InitPrices(CLzmaEnc *p) { if (!p->fastMode) { FillDistancesPrices(p); FillAlignPrices(p); } p->lenEnc.tableSize = p->repLenEnc.tableSize = p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); } static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 i; for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) if (p->dictSize <= ((UInt32)1 << i)) break; p->distTableSize = i * 2; p->finished = False; p->result = SZ_OK; RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); LzmaEnc_Init(p); LzmaEnc_InitPrices(p); p->nowPos64 = 0; return SZ_OK; } static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; p->rc.outStream = outStream; return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); } SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) { p->matchFinderBase.directInput = 1; p->matchFinderBase.bufferBase = (Byte *)src; p->matchFinderBase.directInputRem = srcLen; } SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; LzmaEnc_SetInputBuf(p, src, srcLen); p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } void LzmaEnc_Finish(CLzmaEncHandle pp) { #ifndef _7ZIP_ST CLzmaEnc *p = (CLzmaEnc *)pp; if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else pp = pp; #endif } typedef struct { ISeqOutStream funcTable; Byte *data; SizeT rem; Bool overflow; } CSeqOutStreamBuf; static size_t MyWrite(void *pp, const void *data, size_t size) { CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; if (p->rem < size) { size = p->rem; p->overflow = True; } memcpy(p->data, data, size); p->rem -= size; p->data += size; return size; } UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { CLzmaEnc *p = (CLzmaEnc *)pp; UInt64 nowPos64; SRes res; CSeqOutStreamBuf outStream; outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = False; p->finished = False; p->result = SZ_OK; if (reInit) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); p->rc.outStream = &outStream.funcTable; res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); *unpackSize = (UInt32)(p->nowPos64 - nowPos64); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK; #ifndef _7ZIP_ST Byte allocaDummy[0x300]; allocaDummy[0] = 0; allocaDummy[1] = allocaDummy[0]; #endif for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); if (res != SZ_OK || p->finished != 0) break; if (progress != 0) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK) { res = SZ_ERROR_PROGRESS; break; } } } LzmaEnc_Finish(p); return res; } SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; int i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); for (i = 11; i <= 30; i++) { if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) props[1 + i] = (Byte)(dictSize >> (8 * i)); return SZ_OK; } SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { SRes res; CLzmaEnc *p = (CLzmaEnc *)pp; CSeqOutStreamBuf outStream; LzmaEnc_SetInputBuf(p, src, srcLen); outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; p->rc.outStream = &outStream.funcTable; res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); if (res == SZ_OK) res = LzmaEnc_Encode2(p, progress); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; if (p == 0) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props); if (res == SZ_OK) { res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); if (res == SZ_OK) res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, writeEndMark, progress, alloc, allocBig); } LzmaEnc_Destroy(p, alloc, allocBig); return res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/LzmaEnc.h0100777000000000000000000000573713761647206020374 0ustar00/* LzmaEnc.h -- LZMA Encoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_ENC_H #define __LZMA_ENC_H #include "7zTypes.h" EXTERN_C_BEGIN #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaEncProps { int level; /* 0 <= level <= 9 */ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version (1 << 12) <= dictSize <= (1 << 30) for 64-bit version default = (1 << 24) */ UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. Encoder uses this value to reduce dictionary size */ int lc; /* 0 <= lc <= 8, default = 3 */ int lp; /* 0 <= lp <= 4, default = 0 */ int pb; /* 0 <= pb <= 4, default = 2 */ int algo; /* 0 - fast, 1 - normal, default = 1 */ int fb; /* 5 <= fb <= 273, default = 32 */ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ int numHashBytes; /* 2, 3 or 4, default = 4 */ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ int numThreads; /* 1 or 2, default = 2 */ } CLzmaEncProps; void LzmaEncProps_Init(CLzmaEncProps *p); void LzmaEncProps_Normalize(CLzmaEncProps *p); UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); /* ---------- CLzmaEncHandle Interface ---------- */ /* LzmaEnc_* functions can return the following exit codes: Returns: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater in props SZ_ERROR_WRITE - Write callback error. SZ_ERROR_PROGRESS - some break from progress callback SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ typedef void * CLzmaEncHandle; CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); /* ---------- One Call Interface ---------- */ /* LzmaEncode Return code: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater SZ_ERROR_OUTPUT_EOF - output buffer overflow SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/MtCoder.c0100777000000000000000000001750513761647206020367 0ustar00/* MtCoder.c -- Multi-thread Coder 2010-09-24 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "MtCoder.h" void LoopThread_Construct(CLoopThread *p) { Thread_Construct(&p->thread); Event_Construct(&p->startEvent); Event_Construct(&p->finishedEvent); } void LoopThread_Close(CLoopThread *p) { Thread_Close(&p->thread); Event_Close(&p->startEvent); Event_Close(&p->finishedEvent); } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp) { CLoopThread *p = (CLoopThread *)pp; for (;;) { if (Event_Wait(&p->startEvent) != 0) return SZ_ERROR_THREAD; if (p->stop) return 0; p->res = p->func(p->param); if (Event_Set(&p->finishedEvent) != 0) return SZ_ERROR_THREAD; } } WRes LoopThread_Create(CLoopThread *p) { p->stop = 0; RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent)); RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent)); return Thread_Create(&p->thread, LoopThreadFunc, p); } WRes LoopThread_StopAndWait(CLoopThread *p) { p->stop = 1; if (Event_Set(&p->startEvent) != 0) return SZ_ERROR_THREAD; return Thread_Wait(&p->thread); } WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); } WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); } static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) { return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; } static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) p->inSizes[i] = p->outSizes[i] = 0; p->totalInSize = p->totalOutSize = 0; p->progress = progress; p->res = SZ_OK; } static void MtProgress_Reinit(CMtProgress *p, unsigned index) { p->inSizes[index] = 0; p->outSizes[index] = 0; } #define UPDATE_PROGRESS(size, prev, total) \ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; } SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize) { SRes res; CriticalSection_Enter(&p->cs); UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize) UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize) if (p->res == SZ_OK) p->res = Progress(p->progress, p->totalInSize, p->totalOutSize); res = p->res; CriticalSection_Leave(&p->cs); return res; } static void MtProgress_SetError(CMtProgress *p, SRes res) { CriticalSection_Enter(&p->cs); if (p->res == SZ_OK) p->res = res; CriticalSection_Leave(&p->cs); } static void MtCoder_SetError(CMtCoder* p, SRes res) { CriticalSection_Enter(&p->cs); if (p->res == SZ_OK) p->res = res; CriticalSection_Leave(&p->cs); } /* ---------- MtThread ---------- */ void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder) { p->mtCoder = mtCoder; p->outBuf = 0; p->inBuf = 0; Event_Construct(&p->canRead); Event_Construct(&p->canWrite); LoopThread_Construct(&p->thread); } #define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; } static void CMtThread_CloseEvents(CMtThread *p) { Event_Close(&p->canRead); Event_Close(&p->canWrite); } static void CMtThread_Destruct(CMtThread *p) { CMtThread_CloseEvents(p); if (Thread_WasCreated(&p->thread.thread)) { LoopThread_StopAndWait(&p->thread); LoopThread_Close(&p->thread); } if (p->mtCoder->alloc) IAlloc_Free(p->mtCoder->alloc, p->outBuf); p->outBuf = 0; if (p->mtCoder->alloc) IAlloc_Free(p->mtCoder->alloc, p->inBuf); p->inBuf = 0; } #define MY_BUF_ALLOC(buf, size, newSize) \ if (buf == 0 || size != newSize) \ { IAlloc_Free(p->mtCoder->alloc, buf); \ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \ if (buf == 0) return SZ_ERROR_MEM; } static SRes CMtThread_Prepare(CMtThread *p) { MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize) MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize) p->stopReading = False; p->stopWriting = False; RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite)); return SZ_OK; } static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) { size_t size = *processedSize; *processedSize = 0; while (size != 0) { size_t curSize = size; SRes res = stream->Read(stream, data, &curSize); *processedSize += curSize; data += curSize; size -= curSize; RINOK(res); if (curSize == 0) return SZ_OK; } return SZ_OK; } #define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1] static SRes MtThread_Process(CMtThread *p, Bool *stop) { CMtThread *next; *stop = True; if (Event_Wait(&p->canRead) != 0) return SZ_ERROR_THREAD; next = GET_NEXT_THREAD(p); if (p->stopReading) { next->stopReading = True; return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD; } { size_t size = p->mtCoder->blockSize; size_t destSize = p->outBufSize; RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size)); next->stopReading = *stop = (size != p->mtCoder->blockSize); if (Event_Set(&next->canRead) != 0) return SZ_ERROR_THREAD; RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index, p->outBuf, &destSize, p->inBuf, size, *stop)); MtProgress_Reinit(&p->mtCoder->mtProgress, p->index); if (Event_Wait(&p->canWrite) != 0) return SZ_ERROR_THREAD; if (p->stopWriting) return SZ_ERROR_FAIL; if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize) return SZ_ERROR_WRITE; return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD; } } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) { CMtThread *p = (CMtThread *)pp; for (;;) { Bool stop; CMtThread *next = GET_NEXT_THREAD(p); SRes res = MtThread_Process(p, &stop); if (res != SZ_OK) { MtCoder_SetError(p->mtCoder, res); MtProgress_SetError(&p->mtCoder->mtProgress, res); next->stopReading = True; next->stopWriting = True; Event_Set(&next->canRead); Event_Set(&next->canWrite); return res; } if (stop) return 0; } } void MtCoder_Construct(CMtCoder* p) { unsigned i; p->alloc = 0; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) { CMtThread *t = &p->threads[i]; t->index = i; CMtThread_Construct(t, p); } CriticalSection_Init(&p->cs); CriticalSection_Init(&p->mtProgress.cs); } void MtCoder_Destruct(CMtCoder* p) { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) CMtThread_Destruct(&p->threads[i]); CriticalSection_Delete(&p->cs); CriticalSection_Delete(&p->mtProgress.cs); } SRes MtCoder_Code(CMtCoder *p) { unsigned i, numThreads = p->numThreads; SRes res = SZ_OK; p->res = SZ_OK; MtProgress_Init(&p->mtProgress, p->progress); for (i = 0; i < numThreads; i++) { RINOK(CMtThread_Prepare(&p->threads[i])); } for (i = 0; i < numThreads; i++) { CMtThread *t = &p->threads[i]; CLoopThread *lt = &t->thread; if (!Thread_WasCreated(<->thread)) { lt->func = ThreadFunc; lt->param = t; if (LoopThread_Create(lt) != SZ_OK) { res = SZ_ERROR_THREAD; break; } } } if (res == SZ_OK) { unsigned j; for (i = 0; i < numThreads; i++) { CMtThread *t = &p->threads[i]; if (LoopThread_StartSubThread(&t->thread) != SZ_OK) { res = SZ_ERROR_THREAD; p->threads[0].stopReading = True; break; } } Event_Set(&p->threads[0].canWrite); Event_Set(&p->threads[0].canRead); for (j = 0; j < i; j++) LoopThread_WaitSubThread(&p->threads[j].thread); } for (i = 0; i < numThreads; i++) CMtThread_CloseEvents(&p->threads[i]); return (res == SZ_OK) ? p->res : res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/MtCoder.h0100777000000000000000000000366213761647206020373 0ustar00/* MtCoder.h -- Multi-thread Coder 2009-11-19 : Igor Pavlov : Public domain */ #ifndef __MT_CODER_H #define __MT_CODER_H #include "Threads.h" EXTERN_C_BEGIN typedef struct { CThread thread; CAutoResetEvent startEvent; CAutoResetEvent finishedEvent; int stop; THREAD_FUNC_TYPE func; LPVOID param; THREAD_FUNC_RET_TYPE res; } CLoopThread; void LoopThread_Construct(CLoopThread *p); void LoopThread_Close(CLoopThread *p); WRes LoopThread_Create(CLoopThread *p); WRes LoopThread_StopAndWait(CLoopThread *p); WRes LoopThread_StartSubThread(CLoopThread *p); WRes LoopThread_WaitSubThread(CLoopThread *p); #ifndef _7ZIP_ST #define NUM_MT_CODER_THREADS_MAX 32 #else #define NUM_MT_CODER_THREADS_MAX 1 #endif typedef struct { UInt64 totalInSize; UInt64 totalOutSize; ICompressProgress *progress; SRes res; CCriticalSection cs; UInt64 inSizes[NUM_MT_CODER_THREADS_MAX]; UInt64 outSizes[NUM_MT_CODER_THREADS_MAX]; } CMtProgress; SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize); struct _CMtCoder; typedef struct { struct _CMtCoder *mtCoder; Byte *outBuf; size_t outBufSize; Byte *inBuf; size_t inBufSize; unsigned index; CLoopThread thread; Bool stopReading; Bool stopWriting; CAutoResetEvent canRead; CAutoResetEvent canWrite; } CMtThread; typedef struct { SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize, const Byte *src, size_t srcSize, int finished); } IMtCoderCallback; typedef struct _CMtCoder { size_t blockSize; size_t destBlockSize; unsigned numThreads; ISeqInStream *inStream; ISeqOutStream *outStream; ICompressProgress *progress; ISzAlloc *alloc; IMtCoderCallback *mtCallback; CCriticalSection cs; SRes res; CMtProgress mtProgress; CMtThread threads[NUM_MT_CODER_THREADS_MAX]; } CMtCoder; void MtCoder_Construct(CMtCoder* p); void MtCoder_Destruct(CMtCoder* p); SRes MtCoder_Code(CMtCoder *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Precomp.h0100777000000000000000000000025413761647206020435 0ustar00/* Precomp.h -- StdAfx 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_PRECOMP_H #define __7Z_PRECOMP_H #include "Compiler.h" /* #include "7zTypes.h" */ #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/RotateDefs.h0100777000000000000000000000074113761647206021071 0ustar00/* RotateDefs.h -- Rotate functions 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __ROTATE_DEFS_H #define __ROTATE_DEFS_H #ifdef _MSC_VER #include // #if (_MSC_VER >= 1200) #pragma intrinsic(_rotl) #pragma intrinsic(_rotr) // #endif #define rotlFixed(x, n) _rotl((x), (n)) #define rotrFixed(x, n) _rotr((x), (n)) #else #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Sha256.c0100777000000000000000000001163213761647206017775 0ustar00/* Crypto/Sha256.c -- SHA-256 Hash 2010-06-11 : Igor Pavlov : Public domain This code is based on public domain code from Wei Dai's Crypto++ library. */ #include "Precomp.h" #include "RotateDefs.h" #include "Sha256.h" /* define it for speed optimization */ /* #define _SHA256_UNROLL */ /* #define _SHA256_UNROLL2 */ void Sha256_Init(CSha256 *p) { p->state[0] = 0x6a09e667; p->state[1] = 0xbb67ae85; p->state[2] = 0x3c6ef372; p->state[3] = 0xa54ff53a; p->state[4] = 0x510e527f; p->state[5] = 0x9b05688c; p->state[6] = 0x1f83d9ab; p->state[7] = 0x5be0cd19; p->count = 0; } #define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) #define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) #define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) #define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) #define blk0(i) (W[i] = data[i]) #define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) #define Ch(x,y,z) (z^(x&(y^z))) #define Maj(x,y,z) ((x&y)|(z&(x|y))) #define a(i) T[(0-(i))&7] #define b(i) T[(1-(i))&7] #define c(i) T[(2-(i))&7] #define d(i) T[(3-(i))&7] #define e(i) T[(4-(i))&7] #define f(i) T[(5-(i))&7] #define g(i) T[(6-(i))&7] #define h(i) T[(7-(i))&7] #ifdef _SHA256_UNROLL2 #define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ d += h; h += S0(a) + Maj(a, b, c) #define RX_8(i) \ R(a,b,c,d,e,f,g,h, i); \ R(h,a,b,c,d,e,f,g, i+1); \ R(g,h,a,b,c,d,e,f, i+2); \ R(f,g,h,a,b,c,d,e, i+3); \ R(e,f,g,h,a,b,c,d, i+4); \ R(d,e,f,g,h,a,b,c, i+5); \ R(c,d,e,f,g,h,a,b, i+6); \ R(b,c,d,e,f,g,h,a, i+7) #else #define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) #ifdef _SHA256_UNROLL #define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); #endif #endif static const UInt32 K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; static void Sha256_Transform(UInt32 *state, const UInt32 *data) { UInt32 W[16]; unsigned j; #ifdef _SHA256_UNROLL2 UInt32 a,b,c,d,e,f,g,h; a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; #else UInt32 T[8]; for (j = 0; j < 8; j++) T[j] = state[j]; #endif for (j = 0; j < 64; j += 16) { #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) RX_8(0); RX_8(8); #else unsigned i; for (i = 0; i < 16; i++) { R(i); } #endif } #ifdef _SHA256_UNROLL2 state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; #else for (j = 0; j < 8; j++) state[j] += T[j]; #endif /* Wipe variables */ /* memset(W, 0, sizeof(W)); */ /* memset(T, 0, sizeof(T)); */ } #undef S0 #undef S1 #undef s0 #undef s1 static void Sha256_WriteByteBlock(CSha256 *p) { UInt32 data32[16]; unsigned i; for (i = 0; i < 16; i++) data32[i] = ((UInt32)(p->buffer[i * 4 ]) << 24) + ((UInt32)(p->buffer[i * 4 + 1]) << 16) + ((UInt32)(p->buffer[i * 4 + 2]) << 8) + ((UInt32)(p->buffer[i * 4 + 3])); Sha256_Transform(p->state, data32); } void Sha256_Update(CSha256 *p, const Byte *data, size_t size) { UInt32 curBufferPos = (UInt32)p->count & 0x3F; while (size > 0) { p->buffer[curBufferPos++] = *data++; p->count++; size--; if (curBufferPos == 64) { curBufferPos = 0; Sha256_WriteByteBlock(p); } } } void Sha256_Final(CSha256 *p, Byte *digest) { UInt64 lenInBits = (p->count << 3); UInt32 curBufferPos = (UInt32)p->count & 0x3F; unsigned i; p->buffer[curBufferPos++] = 0x80; while (curBufferPos != (64 - 8)) { curBufferPos &= 0x3F; if (curBufferPos == 0) Sha256_WriteByteBlock(p); p->buffer[curBufferPos++] = 0; } for (i = 0; i < 8; i++) { p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56); lenInBits <<= 8; } Sha256_WriteByteBlock(p); for (i = 0; i < 8; i++) { *digest++ = (Byte)(p->state[i] >> 24); *digest++ = (Byte)(p->state[i] >> 16); *digest++ = (Byte)(p->state[i] >> 8); *digest++ = (Byte)(p->state[i]); } Sha256_Init(p); } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Sha256.h0100777000000000000000000000066613761647206020007 0ustar00/* Sha256.h -- SHA-256 Hash 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __CRYPTO_SHA256_H #define __CRYPTO_SHA256_H #include "7zTypes.h" EXTERN_C_BEGIN #define SHA256_DIGEST_SIZE 32 typedef struct { UInt32 state[8]; UInt64 count; Byte buffer[64]; } CSha256; void Sha256_Init(CSha256 *p); void Sha256_Update(CSha256 *p, const Byte *data, size_t size); void Sha256_Final(CSha256 *p, Byte *digest); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Threads.c0100777000000000000000000003406513761647206020424 0ustar00/* Threads.c */ #include "Threads.h" #ifdef ENV_BEOS #include #else #include #include #endif #include #if defined(__linux__) #define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP #endif #ifdef ENV_BEOS /* TODO : optimize the code and verify the returned values */ WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) { thread->_tid = spawn_thread((int32 (*)(void *))startAddress, "CThread", B_LOW_PRIORITY, parameter); if (thread->_tid >= B_OK) { resume_thread(thread->_tid); } else { thread->_tid = B_BAD_THREAD_ID; } thread->_created = 1; return 0; // SZ_OK; } WRes Thread_Wait(CThread *thread) { int ret; if (thread->_created == 0) return EINVAL; if (thread->_tid >= B_OK) { status_t exit_value; wait_for_thread(thread->_tid, &exit_value); thread->_tid = B_BAD_THREAD_ID; } else { return EINVAL; } thread->_created = 0; return 0; } WRes Thread_Close(CThread *thread) { if (!thread->_created) return SZ_OK; thread->_tid = B_BAD_THREAD_ID; thread->_created = 0; return SZ_OK; } WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled) { p->_index_waiting = 0; p->_manual_reset = manualReset; p->_state = (initialSignaled ? TRUE : FALSE); p->_created = 1; p->_sem = create_sem(1,"event"); return 0; } WRes Event_Set(CEvent *p) { int index; acquire_sem(p->_sem); p->_state = TRUE; for(index = 0 ; index < p->_index_waiting ; index++) { send_data(p->_waiting[index], '7zCN', NULL, 0); } p->_index_waiting = 0; release_sem(p->_sem); return 0; } WRes Event_Reset(CEvent *p) { acquire_sem(p->_sem); p->_state = FALSE; release_sem(p->_sem); return 0; } WRes Event_Wait(CEvent *p) { acquire_sem(p->_sem); while (p->_state == FALSE) { thread_id sender; p->_waiting[p->_index_waiting++] = find_thread(NULL); release_sem(p->_sem); /* int msg = */ receive_data(&sender, NULL, 0); acquire_sem(p->_sem); } if (p->_manual_reset == FALSE) { p->_state = FALSE; } release_sem(p->_sem); return 0; } WRes Event_Close(CEvent *p) { if (p->_created) { p->_created = 0; delete_sem(p->_sem); } return 0; } WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount) { p->_index_waiting = 0; p->_count = initiallyCount; p->_maxCount = maxCount; p->_created = 1; p->_sem = create_sem(1,"sem"); return 0; } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) { UInt32 newCount; int index; if (releaseCount < 1) return EINVAL; acquire_sem(p->_sem); newCount = p->_count + releaseCount; if (newCount > p->_maxCount) { release_sem(p->_sem); return EINVAL; } p->_count = newCount; for(index = 0 ; index < p->_index_waiting ; index++) { send_data(p->_waiting[index], '7zCN', NULL, 0); } p->_index_waiting = 0; release_sem(p->_sem); return 0; } WRes Semaphore_Wait(CSemaphore *p) { acquire_sem(p->_sem); while (p->_count < 1) { thread_id sender; p->_waiting[p->_index_waiting++] = find_thread(NULL); release_sem(p->_sem); /* int msg = */ receive_data(&sender, NULL, 0); acquire_sem(p->_sem); } p->_count--; release_sem(p->_sem); return 0; } WRes Semaphore_Close(CSemaphore *p) { if (p->_created) { p->_created = 0; delete_sem(p->_sem); } return 0; } WRes CriticalSection_Init(CCriticalSection * lpCriticalSection) { lpCriticalSection->_sem = create_sem(1,"cc"); return 0; } #else /* !ENV_BEOS */ WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) { pthread_attr_t attr; int ret; thread->_created = 0; ret = pthread_attr_init(&attr); if (ret) return ret; ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); if (ret) return ret; ret = pthread_create(&thread->_tid, &attr, (void * (*)(void *))startAddress, parameter); /* ret2 = */ pthread_attr_destroy(&attr); if (ret) return ret; thread->_created = 1; return 0; // SZ_OK; } WRes Thread_Wait(CThread *thread) { void *thread_return; int ret; if (thread->_created == 0) return EINVAL; ret = pthread_join(thread->_tid,&thread_return); thread->_created = 0; return ret; } WRes Thread_Close(CThread *thread) { if (!thread->_created) return SZ_OK; pthread_detach(thread->_tid); thread->_tid = 0; thread->_created = 0; return SZ_OK; } #ifdef DEBUG_SYNCHRO #include static void dump_error(int ligne,int ret,const char *text,void *param) { printf("\n##T%d#ERROR2 (l=%d) %s : param=%p ret = %d (%s)##\n",(int)pthread_self(),ligne,text,param,ret,strerror(ret)); // abort(); } WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled) { int ret; pthread_mutexattr_t mutexattr; memset(&mutexattr,0,sizeof(mutexattr)); ret = pthread_mutexattr_init(&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&mutexattr); ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK); if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_settype",&mutexattr); ret = pthread_mutex_init(&p->_mutex,&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&p->_mutex); if (ret == 0) { ret = pthread_cond_init(&p->_cond,0); if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_cond_init",&p->_cond); p->_manual_reset = manualReset; p->_state = (initialSignaled ? TRUE : FALSE); p->_created = 1; } return ret; } WRes Event_Set(CEvent *p) { int ret = pthread_mutex_lock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_lock",&p->_mutex); if (ret == 0) { p->_state = TRUE; ret = pthread_cond_broadcast(&p->_cond); if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_cond_broadcast",&p->_cond); if (ret == 0) { ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_unlock",&p->_mutex); } } return ret; } WRes Event_Reset(CEvent *p) { int ret = pthread_mutex_lock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_lock",&p->_mutex); if (ret == 0) { p->_state = FALSE; ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_unlock",&p->_mutex); } return ret; } WRes Event_Wait(CEvent *p) { int ret = pthread_mutex_lock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_lock",&p->_mutex); if (ret == 0) { while ((p->_state == FALSE) && (ret == 0)) { ret = pthread_cond_wait(&p->_cond, &p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_cond_wait",&p->_mutex); } if (ret == 0) { if (p->_manual_reset == FALSE) { p->_state = FALSE; } ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_unlock",&p->_mutex); } } return ret; } WRes Event_Close(CEvent *p) { if (p->_created) { int ret; p->_created = 0; ret = pthread_mutex_destroy(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_mutex_destroy",&p->_mutex); ret = pthread_cond_destroy(&p->_cond); if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_cond_destroy",&p->_cond); } return 0; } WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount) { int ret; pthread_mutexattr_t mutexattr; memset(&mutexattr,0,sizeof(mutexattr)); ret = pthread_mutexattr_init(&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&mutexattr); ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK); if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_settype",&mutexattr); ret = pthread_mutex_init(&p->_mutex,&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&p->_mutex); if (ret == 0) { ret = pthread_cond_init(&p->_cond,0); if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_cond_init",&p->_mutex); p->_count = initiallyCount; p->_maxCount = maxCount; p->_created = 1; } return ret; } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) { int ret; if (releaseCount < 1) return EINVAL; ret = pthread_mutex_lock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_lock",&p->_mutex); if (ret == 0) { UInt32 newCount = p->_count + releaseCount; if (newCount > p->_maxCount) { ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex); return EINVAL; } p->_count = newCount; ret = pthread_cond_broadcast(&p->_cond); if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_cond_broadcast",&p->_cond); if (ret == 0) { ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex); } } return ret; } WRes Semaphore_Wait(CSemaphore *p) { int ret = pthread_mutex_lock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_lock",&p->_mutex); if (ret == 0) { while ((p->_count < 1) && (ret == 0)) { ret = pthread_cond_wait(&p->_cond, &p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_cond_wait",&p->_mutex); } if (ret == 0) { p->_count--; ret = pthread_mutex_unlock(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_unlock",&p->_mutex); } } return ret; } WRes Semaphore_Close(CSemaphore *p) { if (p->_created) { int ret; p->_created = 0; ret = pthread_mutex_destroy(&p->_mutex); if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_mutex_destroy",&p->_mutex); ret = pthread_cond_destroy(&p->_cond); if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_cond_destroy",&p->_cond); } return 0; } WRes CriticalSection_Init(CCriticalSection * lpCriticalSection) { if (lpCriticalSection) { int ret; pthread_mutexattr_t mutexattr; memset(&mutexattr,0,sizeof(mutexattr)); ret = pthread_mutexattr_init(&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&mutexattr); ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK); if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_settype",&mutexattr); ret = pthread_mutex_init(&lpCriticalSection->_mutex,&mutexattr); if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&lpCriticalSection->_mutex); return ret; } return EINTR; } void CriticalSection_Enter(CCriticalSection * lpCriticalSection) { if (lpCriticalSection) { int ret = pthread_mutex_lock(&(lpCriticalSection->_mutex)); if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_lock",&(lpCriticalSection->_mutex)); } } void CriticalSection_Leave(CCriticalSection * lpCriticalSection) { if (lpCriticalSection) { int ret = pthread_mutex_unlock(&(lpCriticalSection->_mutex)); if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_unlock",&(lpCriticalSection->_mutex)); } } void CriticalSection_Delete(CCriticalSection * lpCriticalSection) { if (lpCriticalSection) { int ret = pthread_mutex_destroy(&(lpCriticalSection->_mutex)); if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_destroy",&(lpCriticalSection->_mutex)); } } #else WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled) { pthread_mutex_init(&p->_mutex,0); pthread_cond_init(&p->_cond,0); p->_manual_reset = manualReset; p->_state = (initialSignaled ? TRUE : FALSE); p->_created = 1; return 0; } WRes Event_Set(CEvent *p) { pthread_mutex_lock(&p->_mutex); p->_state = TRUE; pthread_cond_broadcast(&p->_cond); pthread_mutex_unlock(&p->_mutex); return 0; } WRes Event_Reset(CEvent *p) { pthread_mutex_lock(&p->_mutex); p->_state = FALSE; pthread_mutex_unlock(&p->_mutex); return 0; } WRes Event_Wait(CEvent *p) { pthread_mutex_lock(&p->_mutex); while (p->_state == FALSE) { pthread_cond_wait(&p->_cond, &p->_mutex); } if (p->_manual_reset == FALSE) { p->_state = FALSE; } pthread_mutex_unlock(&p->_mutex); return 0; } WRes Event_Close(CEvent *p) { if (p->_created) { p->_created = 0; pthread_mutex_destroy(&p->_mutex); pthread_cond_destroy(&p->_cond); } return 0; } WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount) { pthread_mutex_init(&p->_mutex,0); pthread_cond_init(&p->_cond,0); p->_count = initiallyCount; p->_maxCount = maxCount; p->_created = 1; return 0; } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) { UInt32 newCount; if (releaseCount < 1) return EINVAL; pthread_mutex_lock(&p->_mutex); newCount = p->_count + releaseCount; if (newCount > p->_maxCount) { pthread_mutex_unlock(&p->_mutex); return EINVAL; } p->_count = newCount; pthread_cond_broadcast(&p->_cond); pthread_mutex_unlock(&p->_mutex); return 0; } WRes Semaphore_Wait(CSemaphore *p) { pthread_mutex_lock(&p->_mutex); while (p->_count < 1) { pthread_cond_wait(&p->_cond, &p->_mutex); } p->_count--; pthread_mutex_unlock(&p->_mutex); return 0; } WRes Semaphore_Close(CSemaphore *p) { if (p->_created) { p->_created = 0; pthread_mutex_destroy(&p->_mutex); pthread_cond_destroy(&p->_cond); } return 0; } WRes CriticalSection_Init(CCriticalSection * lpCriticalSection) { return pthread_mutex_init(&(lpCriticalSection->_mutex),0); } #endif /* DEBUG_SYNCHRO */ #endif /* ENV_BEOS */ WRes ManualResetEvent_Create(CManualResetEvent *p, int initialSignaled) { return Event_Create(p, TRUE, initialSignaled); } WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } WRes AutoResetEvent_Create(CAutoResetEvent *p, int initialSignaled) { return Event_Create(p, FALSE, initialSignaled); } WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Threads.h0100777000000000000000000000601213761647206020420 0ustar00/* Threads.h -- multithreading library 2008-11-22 : Igor Pavlov : Public domain */ #ifndef __7Z_THRESDS_H #define __7Z_THRESDS_H #include "7zTypes.h" #include "windows.h" #ifdef ENV_BEOS #include #define MAX_THREAD 256 #else #include #endif /* #define DEBUG_SYNCHRO 1 */ typedef struct _CThread { #ifdef ENV_BEOS thread_id _tid; #else pthread_t _tid; #endif int _created; } CThread; #define Thread_Construct(thread) (thread)->_created = 0 #define Thread_WasCreated(thread) ((thread)->_created != 0) typedef unsigned THREAD_FUNC_RET_TYPE; #define THREAD_FUNC_CALL_TYPE MY_STD_CALL #define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); WRes Thread_Create(CThread *thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter); WRes Thread_Wait(CThread *thread); WRes Thread_Close(CThread *thread); typedef struct _CEvent { int _created; int _manual_reset; int _state; #ifdef ENV_BEOS thread_id _waiting[MAX_THREAD]; int _index_waiting; sem_id _sem; #else pthread_mutex_t _mutex; pthread_cond_t _cond; #endif } CEvent; typedef CEvent CAutoResetEvent; typedef CEvent CManualResetEvent; #define Event_Construct(event) (event)->_created = 0 #define Event_IsCreated(event) ((event)->_created) WRes ManualResetEvent_Create(CManualResetEvent *event, int initialSignaled); WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *event); WRes AutoResetEvent_Create(CAutoResetEvent *event, int initialSignaled); WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *event); WRes Event_Set(CEvent *event); WRes Event_Reset(CEvent *event); WRes Event_Wait(CEvent *event); WRes Event_Close(CEvent *event); typedef struct _CSemaphore { int _created; UInt32 _count; UInt32 _maxCount; #ifdef ENV_BEOS thread_id _waiting[MAX_THREAD]; int _index_waiting; sem_id _sem; #else pthread_mutex_t _mutex; pthread_cond_t _cond; #endif } CSemaphore; #define Semaphore_Construct(p) (p)->_created = 0 WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount); WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); #define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) WRes Semaphore_Wait(CSemaphore *p); WRes Semaphore_Close(CSemaphore *p); typedef struct { #ifdef ENV_BEOS sem_id _sem; #else pthread_mutex_t _mutex; #endif } CCriticalSection; WRes CriticalSection_Init(CCriticalSection *p); #ifdef ENV_BEOS #define CriticalSection_Delete(p) delete_sem((p)->_sem) #define CriticalSection_Enter(p) acquire_sem((p)->_sem) #define CriticalSection_Leave(p) release_sem((p)->_sem) #else #ifdef DEBUG_SYNCHRO void CriticalSection_Delete(CCriticalSection *); void CriticalSection_Enter(CCriticalSection *); void CriticalSection_Leave(CCriticalSection *); #else #define CriticalSection_Delete(p) pthread_mutex_destroy(&((p)->_mutex)) #define CriticalSection_Enter(p) pthread_mutex_lock(&((p)->_mutex)) #define CriticalSection_Leave(p) pthread_mutex_unlock(&((p)->_mutex)) #endif #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Xz.c0100777000000000000000000000355613761647206017434 0ustar00/* Xz.c - Xz 2009-04-15 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #include "Xz.h" #include "XzCrc64.h" Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) { unsigned i = 0; do { buf[i++] = (Byte)((v & 0x7F) | 0x80); v >>= 7; } while (v != 0); buf[i - 1] &= 0x7F; return i; } void Xz_Construct(CXzStream *p) { p->numBlocks = p->numBlocksAllocated = 0; p->blocks = 0; p->flags = 0; } void Xz_Free(CXzStream *p, ISzAlloc *alloc) { alloc->Free(alloc, p->blocks); p->numBlocks = p->numBlocksAllocated = 0; p->blocks = 0; } unsigned XzFlags_GetCheckSize(CXzStreamFlags f) { int t = XzFlags_GetCheckType(f); return (t == 0) ? 0 : (4 << ((t - 1) / 3)); } void XzCheck_Init(CXzCheck *p, int mode) { p->mode = mode; switch (mode) { case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; } } void XzCheck_Update(CXzCheck *p, const void *data, size_t size) { switch (p->mode) { case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; } } int XzCheck_Final(CXzCheck *p, Byte *digest) { switch (p->mode) { case XZ_CHECK_CRC32: SetUi32(digest, CRC_GET_DIGEST(p->crc)); break; case XZ_CHECK_CRC64: { int i; UInt64 v = CRC64_GET_DIGEST(p->crc64); for (i = 0; i < 8; i++, v >>= 8) digest[i] = (Byte)(v & 0xFF); break; } case XZ_CHECK_SHA256: Sha256_Final(&p->sha, digest); break; default: return 0; } return 1; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/Xz.h0100777000000000000000000001633313761647206017436 0ustar00/* Xz.h - Xz interface 2014-12-30 : Igor Pavlov : Public domain */ #ifndef __XZ_H #define __XZ_H #include "Sha256.h" EXTERN_C_BEGIN #define XZ_ID_Subblock 1 #define XZ_ID_Delta 3 #define XZ_ID_X86 4 #define XZ_ID_PPC 5 #define XZ_ID_IA64 6 #define XZ_ID_ARM 7 #define XZ_ID_ARMT 8 #define XZ_ID_SPARC 9 #define XZ_ID_LZMA2 0x21 unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); /* ---------- xz block ---------- */ #define XZ_BLOCK_HEADER_SIZE_MAX 1024 #define XZ_NUM_FILTERS_MAX 4 #define XZ_BF_NUM_FILTERS_MASK 3 #define XZ_BF_PACK_SIZE (1 << 6) #define XZ_BF_UNPACK_SIZE (1 << 7) #define XZ_FILTER_PROPS_SIZE_MAX 20 typedef struct { UInt64 id; UInt32 propsSize; Byte props[XZ_FILTER_PROPS_SIZE_MAX]; } CXzFilter; typedef struct { UInt64 packSize; UInt64 unpackSize; Byte flags; CXzFilter filters[XZ_NUM_FILTERS_MAX]; } CXzBlock; #define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) #define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) #define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) SRes XzBlock_Parse(CXzBlock *p, const Byte *header); SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes); /* ---------- xz stream ---------- */ #define XZ_SIG_SIZE 6 #define XZ_FOOTER_SIG_SIZE 2 extern Byte XZ_SIG[XZ_SIG_SIZE]; extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; #define XZ_STREAM_FLAGS_SIZE 2 #define XZ_STREAM_CRC_SIZE 4 #define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) #define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) #define XZ_CHECK_MASK 0xF #define XZ_CHECK_NO 0 #define XZ_CHECK_CRC32 1 #define XZ_CHECK_CRC64 4 #define XZ_CHECK_SHA256 10 typedef struct { int mode; UInt32 crc; UInt64 crc64; CSha256 sha; } CXzCheck; void XzCheck_Init(CXzCheck *p, int mode); void XzCheck_Update(CXzCheck *p, const void *data, size_t size); int XzCheck_Final(CXzCheck *p, Byte *digest); typedef UInt16 CXzStreamFlags; #define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) #define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) #define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) unsigned XzFlags_GetCheckSize(CXzStreamFlags f); SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); typedef struct { UInt64 unpackSize; UInt64 totalSize; } CXzBlockSizes; typedef struct { CXzStreamFlags flags; size_t numBlocks; size_t numBlocksAllocated; CXzBlockSizes *blocks; UInt64 startOffset; } CXzStream; void Xz_Construct(CXzStream *p); void Xz_Free(CXzStream *p, ISzAlloc *alloc); #define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) UInt64 Xz_GetUnpackSize(const CXzStream *p); UInt64 Xz_GetPackSize(const CXzStream *p); typedef struct { size_t num; size_t numAllocated; CXzStream *streams; } CXzs; void Xzs_Construct(CXzs *p); void Xzs_Free(CXzs *p, ISzAlloc *alloc); SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc); UInt64 Xzs_GetNumBlocks(const CXzs *p); UInt64 Xzs_GetUnpackSize(const CXzs *p); typedef enum { CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ CODER_STATUS_NOT_FINISHED, /* stream was not finished */ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ } ECoderStatus; typedef enum { CODER_FINISH_ANY, /* finish at any point */ CODER_FINISH_END /* block must be finished at the end */ } ECoderFinishMode; typedef struct _IStateCoder { void *p; void (*Free)(void *p, ISzAlloc *alloc); SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc); void (*Init)(void *p); SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished); } IStateCoder; #define MIXCODER_NUM_FILTERS_MAX 4 typedef struct { ISzAlloc *alloc; Byte *buf; int numCoders; int finished[MIXCODER_NUM_FILTERS_MAX - 1]; size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; } CMixCoder; void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc); void MixCoder_Free(CMixCoder *p); void MixCoder_Init(CMixCoder *p); SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId); SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, ECoderStatus *status); typedef enum { XZ_STATE_STREAM_HEADER, XZ_STATE_STREAM_INDEX, XZ_STATE_STREAM_INDEX_CRC, XZ_STATE_STREAM_FOOTER, XZ_STATE_STREAM_PADDING, XZ_STATE_BLOCK_HEADER, XZ_STATE_BLOCK, XZ_STATE_BLOCK_FOOTER } EXzState; typedef struct { EXzState state; UInt32 pos; unsigned alignPos; unsigned indexPreSize; CXzStreamFlags streamFlags; UInt32 blockHeaderSize; UInt64 packSize; UInt64 unpackSize; UInt64 numBlocks; UInt64 indexSize; UInt64 indexPos; UInt64 padSize; UInt64 numStartedStreams; UInt64 numFinishedStreams; UInt64 numTotalBlocks; UInt32 crc; CMixCoder decoder; CXzBlock block; CXzCheck check; CSha256 sha; Byte shaDigest[SHA256_DIGEST_SIZE]; Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; } CXzUnpacker; void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc); void XzUnpacker_Init(CXzUnpacker *p); void XzUnpacker_Free(CXzUnpacker *p); /* finishMode: It has meaning only if the decoding reaches output limit (*destLen). CODER_FINISH_ANY - use smallest number of input bytes CODER_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: CODER_STATUS_NOT_FINISHED, CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams, call XzUnpacker_IsStreamWasFinished to check that current stream was finished SZ_ERROR_MEM - Memory allocation error SZ_ERROR_DATA - Data error SZ_ERROR_UNSUPPORTED - Unsupported method or method properties SZ_ERROR_CRC - CRC error // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: - xz Stream Signature failure - CRC32 of xz Stream Header is failed - The size of Stream padding is not multiple of four bytes. It's possible to get that error, if xz stream was finished and the stream contains some another data. In that case you can call XzUnpacker_GetExtraSize() function to get real size of xz stream. */ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status); Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p); /* Call XzUnpacker_GetExtraSize after XzUnpacker_Code function to detect real size of xz stream in two cases: XzUnpacker_Code() returns: res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT res == SZ_ERROR_NO_ARCHIVE */ UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzCrc64.c0100777000000000000000000000405113761647206020225 0ustar00/* XzCrc64.c -- CRC64 calculation 2011-06-28 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "XzCrc64.h" #include "CpuArch.h" #define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) #ifdef MY_CPU_LE #define CRC_NUM_TABLES 4 #else #define CRC_NUM_TABLES 5 #define CRC_UINT64_SWAP(v) \ ((v >> 56) | \ ((v >> 40) & ((UInt64)0xFF << 8)) | \ ((v >> 24) & ((UInt64)0xFF << 16)) | \ ((v >> 8) & ((UInt64)0xFF << 24)) | \ ((v << 8) & ((UInt64)0xFF << 32)) | \ ((v << 24) & ((UInt64)0xFF << 40)) | \ ((v << 40) & ((UInt64)0xFF << 48)) | \ (v << 56)) UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); #endif #ifndef MY_CPU_BE UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); #endif typedef UInt64 (MY_FAST_CALL *CRC_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); static CRC_FUNC g_Crc64Update; UInt64 g_Crc64Table[256 * CRC_NUM_TABLES]; UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) { return g_Crc64Update(v, data, size, g_Crc64Table); } UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) { return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; } void MY_FAST_CALL Crc64GenerateTable() { UInt32 i; for (i = 0; i < 256; i++) { UInt64 r = i; unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrc64Poly & ~((r & 1) - 1)); g_Crc64Table[i] = r; } for (; i < 256 * CRC_NUM_TABLES; i++) { UInt64 r = g_Crc64Table[i - 256]; g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); } #ifdef MY_CPU_LE g_Crc64Update = XzCrc64UpdateT4; #else { #ifndef MY_CPU_BE UInt32 k = 1; if (*(const Byte *)&k == 1) g_Crc64Update = XzCrc64UpdateT4; else #endif { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { UInt64 x = g_Crc64Table[i - 256]; g_Crc64Table[i] = CRC_UINT64_SWAP(x); } g_Crc64Update = XzCrc64UpdateT1_BeT4; } } #endif } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzCrc64.h0100777000000000000000000000114713761647206020235 0ustar00/* XzCrc64.h -- CRC64 calculation 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __XZ_CRC64_H #define __XZ_CRC64_H #include #include "7zTypes.h" EXTERN_C_BEGIN extern UInt64 g_Crc64Table[]; void MY_FAST_CALL Crc64GenerateTable(void); #define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) #define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzCrc64Opt.c0100777000000000000000000000350413761647206020712 0ustar00/* XzCrc64Opt.c -- CRC64 calculation 2011-06-28 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #ifndef MY_CPU_BE UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)v ^ *(const UInt32 *)p; v = (v >> 32) ^ table[0x300 + ((d ) & 0xFF)] ^ table[0x200 + ((d >> 8) & 0xFF)] ^ table[0x100 + ((d >> 16) & 0xFF)] ^ table[0x000 + ((d >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif #ifndef MY_CPU_LE #define CRC_UINT64_SWAP(v) \ ((v >> 56) | \ ((v >> 40) & ((UInt64)0xFF << 8)) | \ ((v >> 24) & ((UInt64)0xFF << 16)) | \ ((v >> 8) & ((UInt64)0xFF << 24)) | \ ((v << 8) & ((UInt64)0xFF << 32)) | \ ((v << 24) & ((UInt64)0xFF << 40)) | \ ((v << 40) & ((UInt64)0xFF << 48)) | \ (v << 56)) UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); v = CRC_UINT64_SWAP(v); table += 0x100; for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p; v = (v << 32) ^ table[0x000 + ((d ) & 0xFF)] ^ table[0x100 + ((d >> 8) & 0xFF)] ^ table[0x200 + ((d >> 16) & 0xFF)] ^ table[0x300 + ((d >> 24))]; } table -= 0x100; v = CRC_UINT64_SWAP(v); for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzDec.c0100777000000000000000000005366213761647206020053 0ustar00/* XzDec.c -- Xz Decode 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" /* #define XZ_DUMP */ #ifdef XZ_DUMP #include #endif #include #include #include "7zCrc.h" #include "Alloc.h" #include "Bra.h" #include "CpuArch.h" #include "Delta.h" #include "Lzma2Dec.h" #ifdef USE_SUBBLOCK #include "Bcj3Dec.c" #include "SbDec.c" #endif #include "Xz.h" #define XZ_CHECK_SIZE_MAX 64 #define CODER_BUF_SIZE (1 << 17) unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) { int i, limit; *value = 0; limit = (maxSize > 9) ? 9 : (int)maxSize; for (i = 0; i < limit;) { Byte b = p[i]; *value |= (UInt64)(b & 0x7F) << (7 * i++); if ((b & 0x80) == 0) return (b == 0 && i != 1) ? 0 : i; } return 0; } /* ---------- BraState ---------- */ #define BRA_BUF_SIZE (1 << 14) typedef struct { size_t bufPos; size_t bufConv; size_t bufTotal; UInt32 methodId; int encodeMode; UInt32 delta; UInt32 ip; UInt32 x86State; Byte deltaState[DELTA_STATE_SIZE]; Byte buf[BRA_BUF_SIZE]; } CBraState; void BraState_Free(void *pp, ISzAlloc *alloc) { alloc->Free(alloc, pp); } SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { CBraState *p = ((CBraState *)pp); alloc = alloc; p->ip = 0; if (p->methodId == XZ_ID_Delta) { if (propSize != 1) return SZ_ERROR_UNSUPPORTED; p->delta = (unsigned)props[0] + 1; } else { if (propSize == 4) { UInt32 v = GetUi32(props); switch(p->methodId) { case XZ_ID_PPC: case XZ_ID_ARM: case XZ_ID_SPARC: if ((v & 3) != 0) return SZ_ERROR_UNSUPPORTED; break; case XZ_ID_ARMT: if ((v & 1) != 0) return SZ_ERROR_UNSUPPORTED; break; case XZ_ID_IA64: if ((v & 0xF) != 0) return SZ_ERROR_UNSUPPORTED; break; } p->ip = v; } else if (propSize != 0) return SZ_ERROR_UNSUPPORTED; } return SZ_OK; } void BraState_Init(void *pp) { CBraState *p = ((CBraState *)pp); p->bufPos = p->bufConv = p->bufTotal = 0; x86_Convert_Init(p->x86State); if (p->methodId == XZ_ID_Delta) Delta_Init(p->deltaState); } #define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break; static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { CBraState *p = ((CBraState *)pp); SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; *destLen = 0; *srcLen = 0; finishMode = finishMode; *wasFinished = 0; while (destLenOrig > 0) { if (p->bufPos != p->bufConv) { size_t curSize = p->bufConv - p->bufPos; if (curSize > destLenOrig) curSize = destLenOrig; memcpy(dest, p->buf + p->bufPos, curSize); p->bufPos += curSize; *destLen += curSize; dest += curSize; destLenOrig -= curSize; continue; } p->bufTotal -= p->bufPos; memmove(p->buf, p->buf + p->bufPos, p->bufTotal); p->bufPos = 0; p->bufConv = 0; { size_t curSize = BRA_BUF_SIZE - p->bufTotal; if (curSize > srcLenOrig) curSize = srcLenOrig; memcpy(p->buf + p->bufTotal, src, curSize); *srcLen += curSize; src += curSize; srcLenOrig -= curSize; p->bufTotal += curSize; } if (p->bufTotal == 0) break; switch(p->methodId) { case XZ_ID_Delta: if (p->encodeMode) Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal); else Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal); p->bufConv = p->bufTotal; break; case XZ_ID_X86: p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode); break; CASE_BRA_CONV(PPC) CASE_BRA_CONV(IA64) CASE_BRA_CONV(ARM) CASE_BRA_CONV(ARMT) CASE_BRA_CONV(SPARC) default: return SZ_ERROR_UNSUPPORTED; } p->ip += (UInt32)p->bufConv; if (p->bufConv == 0) { if (!srcWasFinished) break; p->bufConv = p->bufTotal; } } if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished) *wasFinished = 1; return SZ_OK; } SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc) { CBraState *decoder; if (id != XZ_ID_Delta && id != XZ_ID_X86 && id != XZ_ID_PPC && id != XZ_ID_IA64 && id != XZ_ID_ARM && id != XZ_ID_ARMT && id != XZ_ID_SPARC) return SZ_ERROR_UNSUPPORTED; p->p = 0; decoder = (CBraState *)alloc->Alloc(alloc, sizeof(CBraState)); if (decoder == 0) return SZ_ERROR_MEM; decoder->methodId = (UInt32)id; decoder->encodeMode = encodeMode; p->p = decoder; p->Free = BraState_Free; p->SetProps = BraState_SetProps; p->Init = BraState_Init; p->Code = BraState_Code; return SZ_OK; } /* ---------- SbState ---------- */ #ifdef USE_SUBBLOCK static void SbState_Free(void *pp, ISzAlloc *alloc) { CSbDec *p = (CSbDec *)pp; SbDec_Free(p); alloc->Free(alloc, pp); } static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { pp = pp; props = props; alloc = alloc; return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; } static void SbState_Init(void *pp) { SbDec_Init((CSbDec *)pp); } static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { CSbDec *p = (CSbDec *)pp; SRes res; srcWasFinished = srcWasFinished; p->dest = dest; p->destLen = *destLen; p->src = src; p->srcLen = *srcLen; p->finish = finishMode; /* change it */ res = SbDec_Decode((CSbDec *)pp); *destLen -= p->destLen; *srcLen -= p->srcLen; *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ return res; } SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) { CSbDec *decoder; p->p = 0; decoder = alloc->Alloc(alloc, sizeof(CSbDec)); if (decoder == 0) return SZ_ERROR_MEM; p->p = decoder; p->Free = SbState_Free; p->SetProps = SbState_SetProps; p->Init = SbState_Init; p->Code = SbState_Code; SbDec_Construct(decoder); SbDec_SetAlloc(decoder, alloc); return SZ_OK; } #endif /* ---------- Lzma2State ---------- */ static void Lzma2State_Free(void *pp, ISzAlloc *alloc) { Lzma2Dec_Free((CLzma2Dec *)pp, alloc); alloc->Free(alloc, pp); } static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { if (propSize != 1) return SZ_ERROR_UNSUPPORTED; return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc); } static void Lzma2State_Init(void *pp) { Lzma2Dec_Init((CLzma2Dec *)pp); } static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { ELzmaStatus status; /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status); srcWasFinished = srcWasFinished; *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK); return res; } static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) { CLzma2Dec *decoder = (CLzma2Dec *)alloc->Alloc(alloc, sizeof(CLzma2Dec)); p->p = decoder; if (decoder == 0) return SZ_ERROR_MEM; p->Free = Lzma2State_Free; p->SetProps = Lzma2State_SetProps; p->Init = Lzma2State_Init; p->Code = Lzma2State_Code; Lzma2Dec_Construct(decoder); return SZ_OK; } void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc) { int i; p->alloc = alloc; p->buf = 0; p->numCoders = 0; for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) p->coders[i].p = NULL; } void MixCoder_Free(CMixCoder *p) { int i; for (i = 0; i < p->numCoders; i++) { IStateCoder *sc = &p->coders[i]; if (p->alloc && sc->p) sc->Free(sc->p, p->alloc); } p->numCoders = 0; if (p->buf) { p->alloc->Free(p->alloc, p->buf); p->buf = 0; /* 9.31: the BUG was fixed */ } } void MixCoder_Init(CMixCoder *p) { int i; for (i = 0; i < p->numCoders - 1; i++) { p->size[i] = 0; p->pos[i] = 0; p->finished[i] = 0; } for (i = 0; i < p->numCoders; i++) { IStateCoder *coder = &p->coders[i]; coder->Init(coder->p); } } SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId) { IStateCoder *sc = &p->coders[coderIndex]; p->ids[coderIndex] = methodId; switch(methodId) { case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc); #ifdef USE_SUBBLOCK case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); #endif } if (coderIndex == 0) return SZ_ERROR_UNSUPPORTED; return BraState_SetFromMethod(sc, methodId, 0, p->alloc); } SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, ECoderStatus *status) { SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; Bool allFinished = True; *destLen = 0; *srcLen = 0; *status = CODER_STATUS_NOT_FINISHED; if (p->buf == 0) { p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); if (p->buf == 0) return SZ_ERROR_MEM; } if (p->numCoders != 1) finishMode = CODER_FINISH_ANY; for (;;) { Bool processed = False; int i; /* if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) break; */ for (i = 0; i < p->numCoders; i++) { SRes res; IStateCoder *coder = &p->coders[i]; Byte *destCur; SizeT destLenCur, srcLenCur; const Byte *srcCur; int srcFinishedCur; int encodingWasFinished; if (i == 0) { srcCur = src; srcLenCur = srcLenOrig - *srcLen; srcFinishedCur = srcWasFinished; } else { srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1]; srcLenCur = p->size[i - 1] - p->pos[i - 1]; srcFinishedCur = p->finished[i - 1]; } if (i == p->numCoders - 1) { destCur = dest; destLenCur = destLenOrig - *destLen; } else { if (p->pos[i] != p->size[i]) continue; destCur = p->buf + (CODER_BUF_SIZE * i); destLenCur = CODER_BUF_SIZE; } res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished); if (!encodingWasFinished) allFinished = False; if (i == 0) { *srcLen += srcLenCur; src += srcLenCur; } else { p->pos[i - 1] += srcLenCur; } if (i == p->numCoders - 1) { *destLen += destLenCur; dest += destLenCur; } else { p->size[i] = destLenCur; p->pos[i] = 0; p->finished[i] = encodingWasFinished; } if (res != SZ_OK) return res; if (destLenCur != 0 || srcLenCur != 0) processed = True; } if (!processed) break; } if (allFinished) *status = CODER_STATUS_FINISHED_WITH_MARK; return SZ_OK; } SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) { *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) return SZ_ERROR_NO_ARCHIVE; return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; } static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) { return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) && (GetUi32(buf) == CrcCalc(buf + 4, 6) && flags == GetBe16(buf + 8) && memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0); } #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } SRes XzBlock_Parse(CXzBlock *p, const Byte *header) { unsigned pos; int numFilters, i; UInt32 headerSize = (UInt32)header[0] << 2; if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) return SZ_ERROR_ARCHIVE; pos = 1; if (pos == headerSize) return SZ_ERROR_ARCHIVE; p->flags = header[pos++]; if (XzBlock_HasPackSize(p)) { READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) return SZ_ERROR_ARCHIVE; } if (XzBlock_HasUnpackSize(p)) READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); numFilters = XzBlock_GetNumFilters(p); for (i = 0; i < numFilters; i++) { CXzFilter *filter = p->filters + i; UInt64 size; READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); READ_VARINT_AND_CHECK(header, pos, headerSize, &size); if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) return SZ_ERROR_ARCHIVE; filter->propsSize = (UInt32)size; memcpy(filter->props, header + pos, (size_t)size); pos += (unsigned)size; #ifdef XZ_DUMP printf("\nf[%d] = %2X: ", i, filter->id); { int i; for (i = 0; i < size; i++) printf(" %2X", filter->props[i]); } #endif } while (pos < headerSize) if (header[pos++] != 0) return SZ_ERROR_ARCHIVE; return SZ_OK; } SRes XzDec_Init(CMixCoder *p, const CXzBlock *block) { int i; Bool needReInit = True; int numFilters = XzBlock_GetNumFilters(block); if (numFilters == p->numCoders) { for (i = 0; i < numFilters; i++) if (p->ids[i] != block->filters[numFilters - 1 - i].id) break; needReInit = (i != numFilters); } if (needReInit) { MixCoder_Free(p); p->numCoders = numFilters; for (i = 0; i < numFilters; i++) { const CXzFilter *f = &block->filters[numFilters - 1 - i]; RINOK(MixCoder_SetFromMethod(p, i, f->id)); } } for (i = 0; i < numFilters; i++) { const CXzFilter *f = &block->filters[numFilters - 1 - i]; IStateCoder *sc = &p->coders[i]; RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); } MixCoder_Init(p); return SZ_OK; } void XzUnpacker_Init(CXzUnpacker *p) { p->state = XZ_STATE_STREAM_HEADER; p->pos = 0; p->numStartedStreams = 0; p->numFinishedStreams = 0; p->numTotalBlocks = 0; p->padSize = 0; } void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc) { MixCoder_Construct(&p->decoder, alloc); XzUnpacker_Init(p); } void XzUnpacker_Free(CXzUnpacker *p) { MixCoder_Free(&p->decoder); } SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status) { SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; *destLen = 0; *srcLen = 0; *status = CODER_STATUS_NOT_SPECIFIED; for (;;) { SizeT srcRem = srcLenOrig - *srcLen; if (p->state == XZ_STATE_BLOCK) { SizeT destLen2 = destLenOrig - *destLen; SizeT srcLen2 = srcLenOrig - *srcLen; SRes res; if (srcLen2 == 0 && destLen2 == 0) { *status = CODER_STATUS_NOT_FINISHED; return SZ_OK; } res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status); XzCheck_Update(&p->check, dest, destLen2); (*srcLen) += srcLen2; src += srcLen2; p->packSize += srcLen2; (*destLen) += destLen2; dest += destLen2; p->unpackSize += destLen2; RINOK(res); if (*status == CODER_STATUS_FINISHED_WITH_MARK) { Byte temp[32]; unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags)); num += Xz_WriteVarInt(temp + num, p->unpackSize); Sha256_Update(&p->sha, temp, num); p->indexSize += num; p->numBlocks++; p->state = XZ_STATE_BLOCK_FOOTER; p->pos = 0; p->alignPos = 0; } else if (srcLen2 == 0 && destLen2 == 0) return SZ_OK; continue; } if (srcRem == 0) { *status = CODER_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } switch (p->state) { case XZ_STATE_STREAM_HEADER: { if (p->pos < XZ_STREAM_HEADER_SIZE) { if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) return SZ_ERROR_NO_ARCHIVE; p->buf[p->pos++] = *src++; (*srcLen)++; } else { RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); p->numStartedStreams++; p->state = XZ_STATE_BLOCK_HEADER; Sha256_Init(&p->sha); p->indexSize = 0; p->numBlocks = 0; p->pos = 0; } break; } case XZ_STATE_BLOCK_HEADER: { if (p->pos == 0) { p->buf[p->pos++] = *src++; (*srcLen)++; if (p->buf[0] == 0) { p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); p->indexPos = p->indexPreSize; p->indexSize += p->indexPreSize; Sha256_Final(&p->sha, p->shaDigest); Sha256_Init(&p->sha); p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); p->state = XZ_STATE_STREAM_INDEX; } p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; } else if (p->pos != p->blockHeaderSize) { UInt32 cur = p->blockHeaderSize - p->pos; if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; } else { RINOK(XzBlock_Parse(&p->block, p->buf)); p->numTotalBlocks++; p->state = XZ_STATE_BLOCK; p->packSize = 0; p->unpackSize = 0; XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); RINOK(XzDec_Init(&p->decoder, &p->block)); } break; } case XZ_STATE_BLOCK_FOOTER: { if (((p->packSize + p->alignPos) & 3) != 0) { (*srcLen)++; p->alignPos++; if (*src++ != 0) return SZ_ERROR_CRC; } else { UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); UInt32 cur = checkSize - p->pos; if (cur != 0) { if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; } else { Byte digest[XZ_CHECK_SIZE_MAX]; p->state = XZ_STATE_BLOCK_HEADER; p->pos = 0; if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) return SZ_ERROR_CRC; } } break; } case XZ_STATE_STREAM_INDEX: { if (p->pos < p->indexPreSize) { (*srcLen)++; if (*src++ != p->buf[p->pos++]) return SZ_ERROR_CRC; } else { if (p->indexPos < p->indexSize) { UInt64 cur = p->indexSize - p->indexPos; if (srcRem > cur) srcRem = (SizeT)cur; p->crc = CrcUpdate(p->crc, src, srcRem); Sha256_Update(&p->sha, src, srcRem); (*srcLen) += srcRem; src += srcRem; p->indexPos += srcRem; } else if ((p->indexPos & 3) != 0) { Byte b = *src++; p->crc = CRC_UPDATE_BYTE(p->crc, b); (*srcLen)++; p->indexPos++; p->indexSize++; if (b != 0) return SZ_ERROR_CRC; } else { Byte digest[SHA256_DIGEST_SIZE]; p->state = XZ_STATE_STREAM_INDEX_CRC; p->indexSize += 4; p->pos = 0; Sha256_Final(&p->sha, digest); if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) return SZ_ERROR_CRC; } } break; } case XZ_STATE_STREAM_INDEX_CRC: { if (p->pos < 4) { (*srcLen)++; p->buf[p->pos++] = *src++; } else { p->state = XZ_STATE_STREAM_FOOTER; p->pos = 0; if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf)) return SZ_ERROR_CRC; } break; } case XZ_STATE_STREAM_FOOTER: { UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; if (p->pos == XZ_STREAM_FOOTER_SIZE) { p->state = XZ_STATE_STREAM_PADDING; p->numFinishedStreams++; p->padSize = 0; if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) return SZ_ERROR_CRC; } break; } case XZ_STATE_STREAM_PADDING: { if (*src != 0) { if (((UInt32)p->padSize & 3) != 0) return SZ_ERROR_NO_ARCHIVE; p->pos = 0; p->state = XZ_STATE_STREAM_HEADER; } else { (*srcLen)++; src++; p->padSize++; } break; } case XZ_STATE_BLOCK: break; /* to disable GCC warning */ } } /* if (p->state == XZ_STATE_FINISHED) *status = CODER_STATUS_FINISHED_WITH_MARK; return SZ_OK; */ } Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p) { return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); } UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p) { UInt64 num = 0; if (p->state == XZ_STATE_STREAM_PADDING) num += p->padSize; else if (p->state == XZ_STATE_STREAM_HEADER) num += p->padSize + p->pos; return num; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzEnc.c0100777000000000000000000003154513761647206020061 0ustar00/* XzEnc.c -- Xz Encode 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include #include "7zCrc.h" #include "Alloc.h" #include "Bra.h" #include "CpuArch.h" #ifdef USE_SUBBLOCK #include "Bcj3Enc.c" #include "SbFind.c" #include "SbEnc.c" #endif #include "XzEnc.h" static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); } static void SzBigFree(void *p, void *address) { p = p; BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; #define XzBlock_ClearFlags(p) (p)->flags = 0; #define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1); #define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size) { return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; } static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc) { *crc = CrcUpdate(*crc, buf, size); return WriteBytes(s, buf, size); } SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) { UInt32 crc; Byte header[XZ_STREAM_HEADER_SIZE]; memcpy(header, XZ_SIG, XZ_SIG_SIZE); header[XZ_SIG_SIZE] = (Byte)(f >> 8); header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); } SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) { Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; unsigned pos = 1; int numFilters, i; header[pos++] = p->flags; if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); numFilters = XzBlock_GetNumFilters(p); for (i = 0; i < numFilters; i++) { const CXzFilter *f = &p->filters[i]; pos += Xz_WriteVarInt(header + pos, f->id); pos += Xz_WriteVarInt(header + pos, f->propsSize); memcpy(header + pos, f->props, f->propsSize); pos += f->propsSize; } while((pos & 3) != 0) header[pos++] = 0; header[0] = (Byte)(pos >> 2); SetUi32(header + pos, CrcCalc(header, pos)); return WriteBytes(s, header, pos + 4); } SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s) { Byte buf[32]; UInt64 globalPos; { UInt32 crc = CRC_INIT_VAL; unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); size_t i; globalPos = pos; buf[0] = 0; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); for (i = 0; i < p->numBlocks; i++) { const CXzBlockSizes *block = &p->blocks[i]; pos = Xz_WriteVarInt(buf, block->totalSize); pos += Xz_WriteVarInt(buf + pos, block->unpackSize); globalPos += pos; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); } pos = ((unsigned)globalPos & 3); if (pos != 0) { buf[0] = buf[1] = buf[2] = 0; RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc)); globalPos += 4 - pos; } { SetUi32(buf, CRC_GET_DIGEST(crc)); RINOK(WriteBytes(s, buf, 4)); globalPos += 4; } } { UInt32 indexSize = (UInt32)((globalPos >> 2) - 1); SetUi32(buf + 4, indexSize); buf[8] = (Byte)(p->flags >> 8); buf[9] = (Byte)(p->flags & 0xFF); SetUi32(buf, CrcCalc(buf + 4, 6)); memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE); return WriteBytes(s, buf, 12); } } SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc) { if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks) { size_t num = (p->numBlocks + 1) * 2; size_t newSize = sizeof(CXzBlockSizes) * num; CXzBlockSizes *blocks; if (newSize / sizeof(CXzBlockSizes) != num) return SZ_ERROR_MEM; blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize); if (blocks == 0) return SZ_ERROR_MEM; if (p->numBlocks != 0) { memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes)); Xz_Free(p, alloc); } p->blocks = blocks; p->numBlocksAllocated = num; } { CXzBlockSizes *block = &p->blocks[p->numBlocks++]; block->totalSize = totalSize; block->unpackSize = unpackSize; } return SZ_OK; } /* ---------- CSeqCheckInStream ---------- */ typedef struct { ISeqInStream p; ISeqInStream *realStream; UInt64 processed; CXzCheck check; } CSeqCheckInStream; void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode) { p->processed = 0; XzCheck_Init(&p->check, mode); } void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) { XzCheck_Final(&p->check, digest); } static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size) { CSeqCheckInStream *p = (CSeqCheckInStream *)pp; SRes res = p->realStream->Read(p->realStream, data, size); XzCheck_Update(&p->check, data, *size); p->processed += *size; return res; } /* ---------- CSeqSizeOutStream ---------- */ typedef struct { ISeqOutStream p; ISeqOutStream *realStream; UInt64 processed; } CSeqSizeOutStream; static size_t MyWrite(void *pp, const void *data, size_t size) { CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp; size = p->realStream->Write(p->realStream, data, size); p->processed += size; return size; } /* ---------- CSeqInFilter ---------- */ #define FILTER_BUF_SIZE (1 << 20) typedef struct { ISeqInStream p; ISeqInStream *realStream; IStateCoder StateCoder; Byte *buf; size_t curPos; size_t endPos; int srcWasFinished; } CSeqInFilter; static SRes SeqInFilter_Read(void *pp, void *data, size_t *size) { CSeqInFilter *p = (CSeqInFilter *)pp; size_t sizeOriginal = *size; if (sizeOriginal == 0) return SZ_OK; *size = 0; for (;;) { if (!p->srcWasFinished && p->curPos == p->endPos) { p->curPos = 0; p->endPos = FILTER_BUF_SIZE; RINOK(p->realStream->Read(p->realStream, p->buf, &p->endPos)); if (p->endPos == 0) p->srcWasFinished = 1; } { SizeT srcLen = p->endPos - p->curPos; int wasFinished; SRes res; *size = sizeOriginal; res = p->StateCoder.Code(p->StateCoder.p, data, size, p->buf + p->curPos, &srcLen, p->srcWasFinished, CODER_FINISH_ANY, &wasFinished); p->curPos += srcLen; if (*size != 0 || srcLen == 0 || res != 0) return res; } } } static void SeqInFilter_Construct(CSeqInFilter *p) { p->buf = NULL; p->p.Read = SeqInFilter_Read; } static void SeqInFilter_Free(CSeqInFilter *p) { if (p->buf) { g_Alloc.Free(&g_Alloc, p->buf); p->buf = NULL; } } SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc); static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props) { if (!p->buf) { p->buf = g_Alloc.Alloc(&g_Alloc, FILTER_BUF_SIZE); if (!p->buf) return SZ_ERROR_MEM; } p->curPos = p->endPos = 0; p->srcWasFinished = 0; RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, &g_Alloc)); RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, &g_Alloc)); p->StateCoder.Init(p->StateCoder.p); return SZ_OK; } /* ---------- CSbEncInStream ---------- */ #ifdef USE_SUBBLOCK typedef struct { ISeqInStream p; ISeqInStream *inStream; CSbEnc enc; } CSbEncInStream; static SRes SbEncInStream_Read(void *pp, void *data, size_t *size) { CSbEncInStream *p = (CSbEncInStream *)pp; size_t sizeOriginal = *size; if (sizeOriginal == 0) return S_OK; for (;;) { if (p->enc.needRead && !p->enc.readWasFinished) { size_t processed = p->enc.needReadSizeMax; RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); p->enc.readPos += processed; if (processed == 0) { p->enc.readWasFinished = True; p->enc.isFinalFinished = True; } p->enc.needRead = False; } *size = sizeOriginal; RINOK(SbEnc_Read(&p->enc, data, size)); if (*size != 0 || !p->enc.needRead) return S_OK; } } void SbEncInStream_Construct(CSbEncInStream *p, ISzAlloc *alloc) { SbEnc_Construct(&p->enc, alloc); p->p.Read = SbEncInStream_Read; } SRes SbEncInStream_Init(CSbEncInStream *p) { return SbEnc_Init(&p->enc); } void SbEncInStream_Free(CSbEncInStream *p) { SbEnc_Free(&p->enc); } #endif typedef struct { CLzma2EncHandle lzma2; #ifdef USE_SUBBLOCK CSbEncInStream sb; #endif CSeqInFilter filter; ISzAlloc *alloc; ISzAlloc *bigAlloc; } CLzma2WithFilters; static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc) { p->alloc = alloc; p->bigAlloc = bigAlloc; p->lzma2 = NULL; #ifdef USE_SUBBLOCK SbEncInStream_Construct(&p->sb, alloc); #endif SeqInFilter_Construct(&p->filter); } static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p) { p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc); if (p->lzma2 == 0) return SZ_ERROR_MEM; return SZ_OK; } static void Lzma2WithFilters_Free(CLzma2WithFilters *p) { SeqInFilter_Free(&p->filter); #ifdef USE_SUBBLOCK SbEncInStream_Free(&p->sb); #endif if (p->lzma2) { Lzma2Enc_Destroy(p->lzma2); p->lzma2 = NULL; } } void XzProps_Init(CXzProps *p) { p->lzma2Props = 0; p->filterProps = 0; p->checkId = XZ_CHECK_CRC32; } void XzFilterProps_Init(CXzFilterProps *p) { p->id = 0; p->delta = 0; p->ip= 0; p->ipDefined = False; } static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf, ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress) { xz->flags = (Byte)props->checkId; RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, props->lzma2Props)); RINOK(Xz_WriteHeader(xz->flags, outStream)); { CSeqCheckInStream checkInStream; CSeqSizeOutStream seqSizeOutStream; CXzBlock block; int filterIndex = 0; CXzFilter *filter = NULL; const CXzFilterProps *fp = props->filterProps; XzBlock_ClearFlags(&block); XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); if (fp) { filter = &block.filters[filterIndex++]; filter->id = fp->id; filter->propsSize = 0; if (fp->id == XZ_ID_Delta) { filter->props[0] = (Byte)(fp->delta - 1); filter->propsSize = 1; } else if (fp->ipDefined) { SetUi32(filter->props, fp->ip); filter->propsSize = 4; } } { CXzFilter *f = &block.filters[filterIndex++]; f->id = XZ_ID_LZMA2; f->propsSize = 1; f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); } seqSizeOutStream.p.Write = MyWrite; seqSizeOutStream.realStream = outStream; seqSizeOutStream.processed = 0; RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p)); checkInStream.p.Read = SeqCheckInStream_Read; checkInStream.realStream = inStream; SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags)); if (fp) { #ifdef USE_SUBBLOCK if (fp->id == XZ_ID_Subblock) { lzmaf->sb.inStream = &checkInStream.p; RINOK(SbEncInStream_Init(&lzmaf->sb)); } else #endif { lzmaf->filter.realStream = &checkInStream.p; RINOK(SeqInFilter_Init(&lzmaf->filter, filter)); } } { UInt64 packPos = seqSizeOutStream.processed; SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p, fp ? #ifdef USE_SUBBLOCK (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p: #endif &lzmaf->filter.p: &checkInStream.p, progress); RINOK(res); block.unpackSize = checkInStream.processed; block.packSize = seqSizeOutStream.processed - packPos; } { unsigned padSize = 0; Byte buf[128]; while((((unsigned)block.packSize + padSize) & 3) != 0) buf[padSize++] = 0; SeqCheckInStream_GetDigest(&checkInStream, buf + padSize); RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags))); RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc)); } } return Xz_WriteFooter(xz, outStream); } SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress) { SRes res; CXzStream xz; CLzma2WithFilters lzmaf; Xz_Construct(&xz); Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc); res = Lzma2WithFilters_Create(&lzmaf); if (res == SZ_OK) res = Xz_Compress(&xz, &lzmaf, outStream, inStream, props, progress); Lzma2WithFilters_Free(&lzmaf); Xz_Free(&xz, &g_Alloc); return res; } SRes Xz_EncodeEmpty(ISeqOutStream *outStream) { SRes res; CXzStream xz; Xz_Construct(&xz); res = Xz_WriteHeader(xz.flags, outStream); if (res == SZ_OK) res = Xz_WriteFooter(&xz, outStream); Xz_Free(&xz, &g_Alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzEnc.h0100777000000000000000000000121413761647206020054 0ustar00/* XzEnc.h -- Xz Encode 2011-02-07 : Igor Pavlov : Public domain */ #ifndef __XZ_ENC_H #define __XZ_ENC_H #include "Lzma2Enc.h" #include "Xz.h" EXTERN_C_BEGIN typedef struct { UInt32 id; UInt32 delta; UInt32 ip; int ipDefined; } CXzFilterProps; void XzFilterProps_Init(CXzFilterProps *p); typedef struct { const CLzma2EncProps *lzma2Props; const CXzFilterProps *filterProps; unsigned checkId; } CXzProps; void XzProps_Init(CXzProps *p); SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress); SRes Xz_EncodeEmpty(ISeqOutStream *outStream); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/unix/C/XzIn.c0100777000000000000000000002016113761647206017712 0ustar00/* XzIn.c - Xz input 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "7zCrc.h" #include "CpuArch.h" #include "Xz.h" SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) { Byte sig[XZ_STREAM_HEADER_SIZE]; RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) return SZ_ERROR_NO_ARCHIVE; return Xz_ParseHeader(p, sig); } #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes) { Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; unsigned headerSize; *headerSizeRes = 0; RINOK(SeqInStream_ReadByte(inStream, &header[0])); headerSize = ((unsigned)header[0] << 2) + 4; if (headerSize == 0) { *headerSizeRes = 1; *isIndex = True; return SZ_OK; } *isIndex = False; *headerSizeRes = headerSize; RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); return XzBlock_Parse(p, header); } #define ADD_SIZE_CHECH(size, val) \ { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } UInt64 Xz_GetUnpackSize(const CXzStream *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->numBlocks; i++) ADD_SIZE_CHECH(size, p->blocks[i].unpackSize); return size; } UInt64 Xz_GetPackSize(const CXzStream *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->numBlocks; i++) ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); return size; } /* SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) { return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); } */ static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc) { size_t i, numBlocks, pos = 1; UInt32 crc; if (size < 5 || buf[0] != 0) return SZ_ERROR_ARCHIVE; size -= 4; crc = CrcCalc(buf, size); if (crc != GetUi32(buf + size)) return SZ_ERROR_ARCHIVE; { UInt64 numBlocks64; READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); numBlocks = (size_t)numBlocks64; if (numBlocks != numBlocks64 || numBlocks * 2 > size) return SZ_ERROR_ARCHIVE; } Xz_Free(p, alloc); if (numBlocks != 0) { p->numBlocks = numBlocks; p->numBlocksAllocated = numBlocks; p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); if (p->blocks == 0) return SZ_ERROR_MEM; for (i = 0; i < numBlocks; i++) { CXzBlockSizes *block = &p->blocks[i]; READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); if (block->totalSize == 0) return SZ_ERROR_ARCHIVE; } } while ((pos & 3) != 0) if (buf[pos++] != 0) return SZ_ERROR_ARCHIVE; return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; } static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc) { SRes res; size_t size; Byte *buf; if (indexSize > ((UInt32)1 << 31)) return SZ_ERROR_UNSUPPORTED; size = (size_t)indexSize; if (size != indexSize) return SZ_ERROR_UNSUPPORTED; buf = alloc->Alloc(alloc, size); if (buf == 0) return SZ_ERROR_MEM; res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); if (res == SZ_OK) res = Xz_ReadIndex2(p, buf, size, alloc); alloc->Free(alloc, buf); return res; } static SRes SeekFromCur(ILookInStream *inStream, Int64 *res) { return inStream->Seek(inStream, res, SZ_SEEK_CUR); } static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc) { UInt64 indexSize; Byte buf[XZ_STREAM_FOOTER_SIZE]; if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; *startOffset = -XZ_STREAM_FOOTER_SIZE; RINOK(SeekFromCur(stream, startOffset)); RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) { UInt32 total = 0; *startOffset += XZ_STREAM_FOOTER_SIZE; for (;;) { size_t i; #define TEMP_BUF_SIZE (1 << 10) Byte tempBuf[TEMP_BUF_SIZE]; if (*startOffset < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) return SZ_ERROR_NO_ARCHIVE; i = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset; total += (UInt32)i; *startOffset = -(Int64)i; RINOK(SeekFromCur(stream, startOffset)); RINOK(LookInStream_Read2(stream, tempBuf, i, SZ_ERROR_NO_ARCHIVE)); for (; i != 0; i--) if (tempBuf[i - 1] != 0) break; if (i != 0) { if ((i & 3) != 0) return SZ_ERROR_NO_ARCHIVE; *startOffset += i; break; } } if (*startOffset < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; *startOffset -= XZ_STREAM_FOOTER_SIZE; RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) return SZ_ERROR_NO_ARCHIVE; } p->flags = (CXzStreamFlags)GetBe16(buf + 8); if (!XzFlags_IsSupported(p->flags)) return SZ_ERROR_UNSUPPORTED; if (GetUi32(buf) != CrcCalc(buf + 4, 6)) return SZ_ERROR_ARCHIVE; indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE); RINOK(SeekFromCur(stream, startOffset)); RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); { UInt64 totalSize = Xz_GetPackSize(p); UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize; if (totalSize == XZ_SIZE_OVERFLOW || sum >= ((UInt64)1 << 63) || totalSize >= ((UInt64)1 << 63)) return SZ_ERROR_ARCHIVE; *startOffset = -(Int64)sum; RINOK(SeekFromCur(stream, startOffset)); } { CXzStreamFlags headerFlags; CSecToRead secToRead; SecToRead_CreateVTable(&secToRead); secToRead.realStream = stream; RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s)); return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; } } /* ---------- Xz Streams ---------- */ void Xzs_Construct(CXzs *p) { p->num = p->numAllocated = 0; p->streams = 0; } void Xzs_Free(CXzs *p, ISzAlloc *alloc) { size_t i; for (i = 0; i < p->num; i++) Xz_Free(&p->streams[i], alloc); alloc->Free(alloc, p->streams); p->num = p->numAllocated = 0; p->streams = 0; } UInt64 Xzs_GetNumBlocks(const CXzs *p) { UInt64 num = 0; size_t i; for (i = 0; i < p->num; i++) num += p->streams[i].numBlocks; return num; } UInt64 Xzs_GetUnpackSize(const CXzs *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->num; i++) ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i])); return size; } /* UInt64 Xzs_GetPackSize(const CXzs *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->num; i++) ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i])); return size; } */ SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc) { Int64 endOffset = 0; RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END)); *startOffset = endOffset; for (;;) { CXzStream st; SRes res; Xz_Construct(&st); res = Xz_ReadBackward(&st, stream, startOffset, alloc); st.startOffset = *startOffset; RINOK(res); if (p->num == p->numAllocated) { size_t newNum = p->num + p->num / 4 + 1; Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream)); if (data == 0) return SZ_ERROR_MEM; p->numAllocated = newNum; if (p->num != 0) memcpy(data, p->streams, p->num * sizeof(CXzStream)); alloc->Free(alloc, p->streams); p->streams = (CXzStream *)data; } p->streams[p->num++] = st; if (*startOffset == 0) break; RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) return SZ_ERROR_PROGRESS; } return SZ_OK; } qt-installer-framework-4.0.1/src/libs/7zip/unix/unix.pri0100777000000000000000000000072413761647206020176 0ustar00include(C/C.pri) include(CPP/7zip/7zip.pri) include(CPP/7zip/Archive/7z/7z.pri) include(CPP/7zip/Archive/Archive.pri) include(CPP/7zip/Archive/Common/Common.pri) include(CPP/7zip/Common/Common.pri) include(CPP/7zip/Compress/Compress.pri) include(CPP/7zip/UI/Common/Common.pri) include(CPP/7zip/UI/Console/Console.pri) include(CPP/Common/Common.pri) include(CPP/include_windows/include_windows.pri) include(CPP/myWindows/myWindows.pri) include(CPP/Windows/Windows.pri) qt-installer-framework-4.0.1/src/libs/7zip/win/0040777000000000000000000000000013761647206016306 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/C/0040777000000000000000000000000013761647206016470 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/0040777000000000000000000000000013761647206016730 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/0040777000000000000000000000000013761647206017621 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/7zip.pri0100777000000000000000000000034313761647206021226 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/ICoder.h \ $$7ZIP_BASE/CPP/7zip/IDecl.h \ $$7ZIP_BASE/CPP/7zip/IPassword.h \ $$7ZIP_BASE/CPP/7zip/IProgress.h \ $$7ZIP_BASE/CPP/7zip/IStream.h \ $$7ZIP_BASE/CPP/7zip/PropID.h qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/0040777000000000000000000000000013761647206021202 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/0040777000000000000000000000000013761647206021542 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7z.pri0100777000000000000000000000266613761647206022630 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zCompressionMode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zItem.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.h \ $$7ZIP_BASE/CPP/7zip/Archive/7z/StdAfx.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zExtract.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandlerOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h0100777000000000000000000000157113761647206025306 0ustar00// 7zCompressionMode.h #ifndef __7Z_COMPRESSION_MODE_H #define __7Z_COMPRESSION_MODE_H #include "../../Common/MethodId.h" #include "../../Common/MethodProps.h" namespace NArchive { namespace N7z { struct CMethodFull: public CProps { CMethodId Id; UInt32 NumInStreams; UInt32 NumOutStreams; bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; struct CBind { UInt32 InCoder; UInt32 InStream; UInt32 OutCoder; UInt32 OutStream; }; struct CCompressionMethodMode { CObjectVector Methods; CRecordVector Binds; #ifndef _7ZIP_ST UInt32 NumThreads; #endif bool PasswordIsDefined; UString Password; bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } CCompressionMethodMode(): PasswordIsDefined(false) #ifndef _7ZIP_ST , NumThreads(1) #endif {} }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp0100777000000000000000000002453613761647206023724 0ustar00// 7zDecode.cpp #include "StdAfx.h" #include "../../Common/LimitedStreams.h" #include "../../Common/LockedStream.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "7zDecode.h" namespace NArchive { namespace N7z { static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, CBindInfoEx &bindInfo) { bindInfo.Clear(); bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); unsigned i; for (i = 0; i < folder.BindPairs.Size(); i++) { NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; } bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); UInt32 outStreamIndex = 0; for (i = 0; i < folder.Coders.Size(); i++) { NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; const CCoderInfo &coderInfo = folder.Coders[i]; coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) if (folder.FindBindPairForOutStream(outStreamIndex) < 0) bindInfo.OutStreams.Add(outStreamIndex); } bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); for (i = 0; i < folder.PackStreams.Size(); i++) bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; } static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, const NCoderMixer::CCoderStreamsInfo &a2) { return (a1.NumInStreams == a2.NumInStreams) && (a1.NumOutStreams == a2.NumOutStreams); } static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2) { return (a1.InIndex == a2.InIndex) && (a1.OutIndex == a2.OutIndex); } static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) { if (a1.Coders.Size() != a2.Coders.Size()) return false; unsigned i; for (i = 0; i < a1.Coders.Size(); i++) if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) return false; if (a1.BindPairs.Size() != a2.BindPairs.Size()) return false; for (i = 0; i < a1.BindPairs.Size(); i++) if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) return false; for (i = 0; i < a1.CoderMethodIDs.Size(); i++) if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) return false; if (a1.InStreams.Size() != a2.InStreams.Size()) return false; if (a1.OutStreams.Size() != a2.OutStreams.Size()) return false; return true; } CDecoder::CDecoder(bool multiThread) { #ifndef _ST_MODE multiThread = true; #endif _multiThread = multiThread; _bindInfoExPrevIsDefined = false; } HRESULT CDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ) { const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; CFolder folderInfo; folders.ParseFolderInfo(folderIndex, folderInfo); if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) return E_NOTIMPL; /* We don't need to init isEncrypted and passwordIsDefined We must upgrade them only #ifndef _NO_CRYPTO isEncrypted = false; passwordIsDefined = false; #endif */ CObjectVector< CMyComPtr > inStreams; CLockedInStream lockedInStream; lockedInStream.Init(inStream); for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) { CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; CMyComPtr lockedStreamImp = lockedStreamImpSpec; lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStream = streamSpec; streamSpec->SetStream(lockedStreamImp); streamSpec->Init(packPositions[j + 1] - packPositions[j]); inStreams.Add(inStream); } unsigned numCoders = folderInfo.Coders.Size(); CBindInfoEx bindInfo; ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); bool createNewCoders; if (!_bindInfoExPrevIsDefined) createNewCoders = true; else createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); if (createNewCoders) { unsigned i; _decoders.Clear(); // _decoders2.Clear(); _mixerCoder.Release(); if (_multiThread) { _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderMTSpec; _mixerCoderCommon = _mixerCoderMTSpec; } else { #ifdef _ST_MODE _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; _mixerCoder = _mixerCoderSTSpec; _mixerCoderCommon = _mixerCoderSTSpec; #endif } RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr decoder; CMyComPtr decoder2; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS coderInfo.MethodID, decoder, decoder2, false)); CMyComPtr decoderUnknown; if (coderInfo.IsSimpleCoder()) { if (decoder == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder; if (_multiThread) _mixerCoderMTSpec->AddCoder(decoder); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder(decoder, false); #endif } else { if (decoder2 == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder2; if (_multiThread) _mixerCoderMTSpec->AddCoder2(decoder2); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder2(decoder2, false); #endif } _decoders.Add(decoderUnknown); #ifdef EXTERNAL_CODECS CMyComPtr setCompressCodecsInfo; decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif } _bindInfoExPrev = bindInfo; _bindInfoExPrevIsDefined = true; } unsigned i; _mixerCoderCommon->ReInit(); UInt32 packStreamIndex = 0; UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; UInt32 unpackStreamIndex = unpackStreamIndexStart; UInt32 coderIndex = 0; // UInt32 coder2Index = 0; for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr &decoder = _decoders[coderIndex]; { CMyComPtr setDecoderProperties; decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); if (setDecoderProperties) { const CByteBuffer &props = coderInfo.Props; size_t size = props.Size(); if (size > 0xFFFFFFFF) return E_NOTIMPL; // if (size > 0) { RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); } } } #if !defined(_7ZIP_ST) && !defined(_SFX) if (mtMode) { CMyComPtr setCoderMt; decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(numThreads)); } } #endif #ifndef _NO_CRYPTO { CMyComPtr cryptoSetPassword; decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { isEncrypted = true; if (!getTextPassword) return E_NOTIMPL; CMyComBSTR passwordBSTR; RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); passwordIsDefined = true; size_t len = 0; if (passwordBSTR) len = MyStringLen((BSTR)passwordBSTR); CByteBuffer buffer(len * 2); for (size_t i = 0; i < len; i++) { wchar_t c = passwordBSTR[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); } } #endif coderIndex++; UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; CObjArray packSizes(numInStreams); CObjArray packSizesPointers(numInStreams); CObjArray unpackSizesPointers(numOutStreams); UInt32 j; for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; for (j = 0; j < numInStreams; j++, packStreamIndex++) { int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); if (bindPairIndex >= 0) packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; else { int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); if (index < 0) return S_FALSE; // check it packSizes[j] = packPositions[index + 1] - packPositions[index]; packSizesPointers[j] = &packSizes[j]; } } _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); } UInt32 mainCoder, temp; bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); if (_multiThread) _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); /* else _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; */ if (numCoders == 0) return 0; unsigned num = inStreams.Size(); CObjArray inStreamPointers(num); for (i = 0; i < num; i++) inStreamPointers[i] = inStreams[i]; ISequentialOutStream *outStreamPointer = outStream; return _mixerCoder->Code( inStreamPointers, NULL, num, &outStreamPointer, NULL, 1, compressProgress); } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h0100777000000000000000000000254713761647206023367 0ustar00// 7zDecode.h #ifndef __7Z_DECODE_H #define __7Z_DECODE_H #include "../../IStream.h" #include "../../IPassword.h" #include "../Common/CoderMixer2.h" #include "../Common/CoderMixer2MT.h" #ifdef _ST_MODE #include "../Common/CoderMixer2ST.h" #endif #include "../../Common/CreateCoder.h" #include "7zIn.h" namespace NArchive { namespace N7z { struct CBindInfoEx: public NCoderMixer::CBindInfo { CRecordVector CoderMethodIDs; void Clear() { CBindInfo::Clear(); CoderMethodIDs.Clear(); } }; class CDecoder { bool _bindInfoExPrevIsDefined; CBindInfoEx _bindInfoExPrev; bool _multiThread; #ifdef _ST_MODE NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec; #endif NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec; NCoderMixer::CCoderMixer2 *_mixerCoderCommon; CMyComPtr _mixerCoder; CObjectVector > _decoders; // CObjectVector > _decoders2; public: CDecoder(bool multiThread); HRESULT Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp0100777000000000000000000003357413761647206023740 0ustar00// 7zEncode.cpp #include "StdAfx.h" #include "../../Common/CreateCoder.h" #include "../../Common/FilterCoder.h" #include "../../Common/LimitedStreams.h" #include "../../Common/InOutTempBuffer.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "7zEncode.h" #include "7zSpecStream.h" static const UInt64 k_Delta = 0x03; static const UInt64 k_BCJ = 0x03030103; static const UInt64 k_BCJ2 = 0x0303011B; namespace NArchive { namespace N7z { static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo, const CRecordVector decompressionMethods, CFolder &folder) { // bindInfo.CoderMethodIDs.Clear(); // folder.OutStreams.Clear(); folder.BindPairs.SetSize(bindInfo.BindPairs.Size()); unsigned i; for (i = 0; i < bindInfo.BindPairs.Size(); i++) { CBindPair &bp = folder.BindPairs[i]; const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i]; bp.InIndex = mixerBp.InIndex; bp.OutIndex = mixerBp.OutIndex; } folder.Coders.SetSize(bindInfo.Coders.Size()); for (i = 0; i < bindInfo.Coders.Size(); i++) { CCoderInfo &coderInfo = folder.Coders[i]; const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; coderInfo.MethodID = decompressionMethods[i]; // coderInfo.Props can be nonFree; } folder.PackStreams.SetSize(bindInfo.InStreams.Size()); for (i = 0; i < bindInfo.InStreams.Size(); i++) folder.PackStreams[i] = bindInfo.InStreams[i]; } static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) { CMyComPtr setCoderProperties; coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); if (setCoderProperties) return props.SetCoderProps(setCoderProperties, dataSizeReduce); return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; } HRESULT CEncoder::CreateMixerCoder( DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce) { _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderSpec; RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); FOR_VECTOR (i, _options.Methods) { const CMethodFull &methodFull = _options.Methods[i]; CCoderInfo &encodingInfo = _codersInfo.AddNew(); encodingInfo.MethodID = methodFull.Id; CMyComPtr encoder; CMyComPtr encoder2; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS methodFull.Id, encoder, encoder2, true)); if (!encoder && !encoder2) return E_FAIL; CMyComPtr encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2; #ifndef _7ZIP_ST { CMyComPtr setCoderMt; encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); } } #endif RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); /* CMyComPtr resetSalt; encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); if (resetSalt) { resetSalt->ResetSalt(); } */ #ifdef EXTERNAL_CODECS CMyComPtr setCompressCodecsInfo; encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif CMyComPtr cryptoSetPassword; encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { const UInt32 sizeInBytes = _options.Password.Len() * 2; CByteBuffer buffer(sizeInBytes); for (unsigned i = 0; i < _options.Password.Len(); i++) { wchar_t c = _options.Password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); } if (encoder) _mixerCoderSpec->AddCoder(encoder); else _mixerCoderSpec->AddCoder2(encoder2); } return S_OK; } HRESULT CEncoder::Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector &coderUnpackSizes, UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector &packSizes, ICompressProgressInfo *compressProgress) { RINOK(EncoderConstr()); if (!_mixerCoderSpec) { RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); } _mixerCoderSpec->ReInit(); // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); CObjectVector inOutTempBuffers; CObjectVector tempBufferSpecs; CObjectVector > tempBuffers; unsigned numMethods = _bindInfo.Coders.Size(); unsigned i; for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CInOutTempBuffer &iotb = inOutTempBuffers.AddNew(); iotb.Create(); iotb.InitWriting(); } for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp; CMyComPtr tempBuffer = tempBufferSpec; tempBufferSpec->Init(&inOutTempBuffers[i - 1]); tempBuffers.Add(tempBuffer); tempBufferSpecs.Add(tempBufferSpec); } for (i = 0; i < numMethods; i++) _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); if (_bindInfo.InStreams.IsEmpty()) return E_FAIL; UInt32 mainCoderIndex, mainStreamIndex; _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); if (inStreamSize) { CRecordVector sizePointers; for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) if (i == mainStreamIndex) sizePointers.Add(inStreamSize); else sizePointers.Add(NULL); _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL); } // UInt64 outStreamStartPos; // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; CMyComPtr outStreamSizeCount; inStreamSizeCountSpec->Init(inStream); CRecordVector inStreamPointers; CRecordVector outStreamPointers; inStreamPointers.Add(inStreamSizeCount); if (_bindInfo.OutStreams.Size() != 0) { outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; outStreamSizeCount = outStreamSizeCountSpec; outStreamSizeCountSpec->SetStream(outStream); outStreamSizeCountSpec->Init(); outStreamPointers.Add(outStreamSizeCount); } for (i = 1; i < _bindInfo.OutStreams.Size(); i++) outStreamPointers.Add(tempBuffers[i - 1]); for (i = 0; i < _codersInfo.Size(); i++) { CCoderInfo &encodingInfo = _codersInfo[i]; CMyComPtr resetInitVector; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); if (resetInitVector) { resetInitVector->ResetInitVector(); } CMyComPtr writeCoderProperties; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); if (writeCoderProperties) { CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; CMyComPtr outStream(outStreamSpec); outStreamSpec->Init(); writeCoderProperties->WriteCoderProperties(outStream); outStreamSpec->CopyToBuffer(encodingInfo.Props); } } UInt32 progressIndex = mainCoderIndex; for (i = 0; i + 1 < _codersInfo.Size(); i++) { UInt64 m = _codersInfo[i].MethodID; if (m == k_Delta || m == k_BCJ || m == k_BCJ2) progressIndex = i + 1; } _mixerCoderSpec->SetProgressCoderIndex(progressIndex); RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); if (_bindInfo.OutStreams.Size() != 0) packSizes.Add(outStreamSizeCountSpec->GetSize()); for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; RINOK(inOutTempBuffer.WriteToStream(outStream)); packSizes.Add(inOutTempBuffer.GetDataSize()); } unpackSize = 0; for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) { int binder = _bindInfo.FindBinderForInStream( _bindReverseConverter->DestOutToSrcInMap[i]); UInt64 streamSize; if (binder < 0) { streamSize = inStreamSizeCountSpec->GetSize(); unpackSize = streamSize; } else streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); coderUnpackSizes.Add(streamSize); } for (i = 0; i < numMethods; i++) folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; return S_OK; } CEncoder::CEncoder(const CCompressionMethodMode &options): _bindReverseConverter(0), _constructed(false) { if (options.IsEmpty()) throw 1; _options = options; _mixerCoderSpec = NULL; } HRESULT CEncoder::EncoderConstr() { if (_constructed) return S_OK; if (_options.Methods.IsEmpty()) { // it has only password method; if (!_options.PasswordIsDefined) throw 1; if (!_options.Binds.IsEmpty()) throw 1; NCoderMixer::CCoderStreamsInfo coderStreamsInfo; CMethodFull method; method.NumInStreams = 1; method.NumOutStreams = 1; coderStreamsInfo.NumInStreams = 1; coderStreamsInfo.NumOutStreams = 1; method.Id = k_AES; _options.Methods.Add(method); _bindInfo.Coders.Add(coderStreamsInfo); _bindInfo.InStreams.Add(0); _bindInfo.OutStreams.Add(0); } else { UInt32 numInStreams = 0, numOutStreams = 0; unsigned i; for (i = 0; i < _options.Methods.Size(); i++) { const CMethodFull &methodFull = _options.Methods[i]; NCoderMixer::CCoderStreamsInfo coderStreamsInfo; coderStreamsInfo.NumInStreams = methodFull.NumOutStreams; coderStreamsInfo.NumOutStreams = methodFull.NumInStreams; if (_options.Binds.IsEmpty()) { if (i < _options.Methods.Size() - 1) { NCoderMixer::CBindPair bindPair; bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; bindPair.OutIndex = numOutStreams; _bindInfo.BindPairs.Add(bindPair); } else if (coderStreamsInfo.NumOutStreams != 0) _bindInfo.OutStreams.Insert(0, numOutStreams); for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) _bindInfo.OutStreams.Add(numOutStreams + j); } numInStreams += coderStreamsInfo.NumInStreams; numOutStreams += coderStreamsInfo.NumOutStreams; _bindInfo.Coders.Add(coderStreamsInfo); } if (!_options.Binds.IsEmpty()) { for (i = 0; i < _options.Binds.Size(); i++) { NCoderMixer::CBindPair bindPair; const CBind &bind = _options.Binds[i]; bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream; bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream; _bindInfo.BindPairs.Add(bindPair); } for (i = 0; i < (int)numOutStreams; i++) if (_bindInfo.FindBinderForOutStream(i) == -1) _bindInfo.OutStreams.Add(i); } for (i = 0; i < (int)numInStreams; i++) if (_bindInfo.FindBinderForInStream(i) == -1) _bindInfo.InStreams.Add(i); if (_bindInfo.InStreams.IsEmpty()) throw 1; // this is error // Make main stream first in list int inIndex = _bindInfo.InStreams[0]; for (;;) { UInt32 coderIndex, coderStreamIndex; _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); int binder = _bindInfo.FindBinderForOutStream(outIndex); if (binder >= 0) { inIndex = _bindInfo.BindPairs[binder].InIndex; continue; } for (i = 0; i < _bindInfo.OutStreams.Size(); i++) if (_bindInfo.OutStreams[i] == outIndex) { _bindInfo.OutStreams.Delete(i); _bindInfo.OutStreams.Insert(0, outIndex); break; } break; } if (_options.PasswordIsDefined) { unsigned numCryptoStreams = _bindInfo.OutStreams.Size(); for (i = 0; i < numCryptoStreams; i++) { NCoderMixer::CBindPair bindPair; bindPair.InIndex = numInStreams + i; bindPair.OutIndex = _bindInfo.OutStreams[i]; _bindInfo.BindPairs.Add(bindPair); } _bindInfo.OutStreams.Clear(); /* if (numCryptoStreams == 0) numCryptoStreams = 1; */ for (i = 0; i < numCryptoStreams; i++) { NCoderMixer::CCoderStreamsInfo coderStreamsInfo; CMethodFull method; method.NumInStreams = 1; method.NumOutStreams = 1; coderStreamsInfo.NumInStreams = method.NumOutStreams; coderStreamsInfo.NumOutStreams = method.NumInStreams; method.Id = k_AES; _options.Methods.Add(method); _bindInfo.Coders.Add(coderStreamsInfo); _bindInfo.OutStreams.Add(numOutStreams + i); } } } for (int i = _options.Methods.Size() - 1; i >= 0; i--) { const CMethodFull &methodFull = _options.Methods[i]; _decompressionMethods.Add(methodFull.Id); } _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); _constructed = true; return S_OK; } CEncoder::~CEncoder() { delete _bindReverseConverter; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h0100777000000000000000000000252113761647206023371 0ustar00// 7zEncode.h #ifndef __7Z_ENCODE_H #define __7Z_ENCODE_H // #include "../../Common/StreamObjects.h" #include "7zCompressionMode.h" #include "../Common/CoderMixer2.h" #include "../Common/CoderMixer2MT.h" #ifdef _ST_MODE #include "../Common/CoderMixer2ST.h" #endif #include "7zItem.h" #include "../../Common/CreateCoder.h" namespace NArchive { namespace N7z { class CEncoder { NCoderMixer::CCoderMixer2MT *_mixerCoderSpec; CMyComPtr _mixerCoder; CObjectVector _codersInfo; CCompressionMethodMode _options; NCoderMixer::CBindInfo _bindInfo; NCoderMixer::CBindInfo _decompressBindInfo; NCoderMixer::CBindReverseConverter *_bindReverseConverter; CRecordVector _decompressionMethods; HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce); bool _constructed; public: CEncoder(const CCompressionMethodMode &options); ~CEncoder(); HRESULT EncoderConstr(); HRESULT Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector &coderUnpackSizes, UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector &packSizes, ICompressProgressInfo *compressProgress); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp0100777000000000000000000001521113761647206024141 0ustar00// 7zExtract.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../Common/ProgressUtils.h" #include "7zDecode.h" // #include "7z1Decode.h" #include "7zFolderOutStream.h" #include "7zHandler.h" namespace NArchive { namespace N7z { struct CExtractFolderInfo { #ifdef _7Z_VOL int VolumeIndex; #endif CNum FileIndex; CNum FolderIndex; CBoolVector ExtractStatuses; UInt64 UnpackSize; CExtractFolderInfo( #ifdef _7Z_VOL int volumeIndex, #endif CNum fileIndex, CNum folderIndex): #ifdef _7Z_VOL VolumeIndex(volumeIndex), #endif FileIndex(fileIndex), FolderIndex(folderIndex), UnpackSize(0) { if (fileIndex != kNumNoIndex) { ExtractStatuses.ClearAndSetSize(1); ExtractStatuses[0] = true; } }; }; STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) { COM_TRY_BEGIN bool testMode = (testModeSpec != 0); CMyComPtr extractCallback = extractCallbackSpec; UInt64 importantTotalUnpacked = 0; bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = #ifdef _7Z_VOL _refs.Size(); #else _db.Files.Size(); #endif if (numItems == 0) return S_OK; /* if (_volumes.Size() != 1) return E_FAIL; const CVolume &volume = _volumes.Front(); const CDbEx &_db = volume.Database; IInStream *_inStream = volume.Stream; */ CObjectVector extractFolderInfoVector; for (UInt32 ii = 0; ii < numItems; ii++) { // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex]; UInt32 ref2Index = allFilesMode ? ii : indices[ii]; // const CRef2 &ref2 = _refs[ref2Index]; // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++) { #ifdef _7Z_VOL // const CRef &ref = ref2.Refs[ri]; const CRef &ref = _refs[ref2Index]; int volumeIndex = ref.VolumeIndex; const CVolume &volume = _volumes[volumeIndex]; const CDbEx &db = volume.Database; UInt32 fileIndex = ref.ItemIndex; #else const CDbEx &db = _db; UInt32 fileIndex = ref2Index; #endif CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex]; if (folderIndex == kNumNoIndex) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif fileIndex, kNumNoIndex)); continue; } if (extractFolderInfoVector.IsEmpty() || folderIndex != extractFolderInfoVector.Back().FolderIndex #ifdef _7Z_VOL || volumeIndex != extractFolderInfoVector.Back().VolumeIndex #endif ) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif kNumNoIndex, folderIndex)); UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex); importantTotalUnpacked += unpackSize; extractFolderInfoVector.Back().UnpackSize = unpackSize; } CExtractFolderInfo &efi = extractFolderInfoVector.Back(); // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; CNum startIndex = db.FolderStartFileIndex[folderIndex]; for (CNum index = efi.ExtractStatuses.Size(); index <= fileIndex - startIndex; index++) { // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize; // Count partial_folder_size // efi.UnpackSize += unpackSize; // importantTotalUnpacked += unpackSize; efi.ExtractStatuses.Add(index == fileIndex - startIndex); } } } RINOK(extractCallback->SetTotal(importantTotalUnpacked)); CDecoder decoder( #ifdef _ST_MODE false #else true #endif ); // CDecoder1 decoder; UInt64 totalPacked = 0; UInt64 totalUnpacked = 0; UInt64 curPacked, curUnpacked; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) { lps->OutSize = totalUnpacked; lps->InSize = totalPacked; RINOK(lps->SetCur()); if (i >= extractFolderInfoVector.Size()) break; const CExtractFolderInfo &efi = extractFolderInfoVector[i]; curUnpacked = efi.UnpackSize; curPacked = 0; CFolderOutStream *folderOutStream = new CFolderOutStream; CMyComPtr outStream(folderOutStream); #ifdef _7Z_VOL const CVolume &volume = _volumes[efi.VolumeIndex]; const CDbEx &db = volume.Database; #else const CDbEx &db = _db; #endif CNum startIndex; if (efi.FileIndex != kNumNoIndex) startIndex = efi.FileIndex; else startIndex = db.FolderStartFileIndex[efi.FolderIndex]; HRESULT result = folderOutStream->Init(&db, #ifdef _7Z_VOL volume.StartRef2Index, #else 0, #endif startIndex, &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0); RINOK(result); if (efi.FileIndex != kNumNoIndex) continue; CNum folderIndex = efi.FolderIndex; curPacked = _db.GetFolderFullPackSize(folderIndex); #ifndef _NO_CRYPTO CMyComPtr getTextPassword; if (extractCallback) extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif try { #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; #endif HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume.Stream, #else _inStream, #endif db.ArcInfo.DataStartPosition, db, folderIndex, outStream, progress _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , true, _numThreads #endif ); if (result == S_FALSE) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } if (result == E_NOTIMPL) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod)); continue; } if (result != S_OK) return result; if (folderOutStream->WasWritingFinished() != S_OK) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } } catch(...) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); continue; } } return S_OK; COM_TRY_END } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp0100777000000000000000000000537213761647206025414 0ustar00// 7zFolderInStream.cpp #include "StdAfx.h" #include "7zFolderInStream.h" namespace NArchive { namespace N7z { CFolderInStream::CFolderInStream() { _inStreamWithHashSpec = new CSequentialInStreamWithCRC; _inStreamWithHash = _inStreamWithHashSpec; } void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles) { _updateCallback = updateCallback; _numFiles = numFiles; _fileIndex = 0; _fileIndices = fileIndices; Processed.Clear(); CRCs.Clear(); Sizes.Clear(); _fileIsOpen = false; _currentSizeIsDefined = false; } HRESULT CFolderInStream::OpenStream() { _filePos = 0; while (_fileIndex < _numFiles) { CMyComPtr stream; HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream); if (result != S_OK && result != S_FALSE) return result; _fileIndex++; _inStreamWithHashSpec->SetStream(stream); _inStreamWithHashSpec->Init(); if (stream) { _fileIsOpen = true; CMyComPtr streamGetSize; stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); if (streamGetSize) { RINOK(streamGetSize->GetSize(&_currentSize)); _currentSizeIsDefined = true; } return S_OK; } RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); Sizes.Add(0); Processed.Add(result == S_OK); AddDigest(); } return S_OK; } void CFolderInStream::AddDigest() { CRCs.Add(_inStreamWithHashSpec->GetCRC()); } HRESULT CFolderInStream::CloseStream() { RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); _inStreamWithHashSpec->ReleaseStream(); _fileIsOpen = false; _currentSizeIsDefined = false; Processed.Add(true); Sizes.Add(_filePos); AddDigest(); return S_OK; } STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != 0) *processedSize = 0; while (size > 0) { if (_fileIsOpen) { UInt32 processed2; RINOK(_inStreamWithHash->Read(data, size, &processed2)); if (processed2 == 0) { RINOK(CloseStream()); continue; } if (processedSize != 0) *processedSize = processed2; _filePos += processed2; break; } if (_fileIndex >= _numFiles) break; RINOK(OpenStream()); } return S_OK; } STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; unsigned index2 = (unsigned)subStream; if (subStream > Sizes.Size()) return E_FAIL; if (index2 < Sizes.Size()) { *value = Sizes[index2]; return S_OK; } if (!_currentSizeIsDefined) return S_FALSE; *value = _currentSize; return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h0100777000000000000000000000240313761647206025051 0ustar00// 7zFolderInStream.h #ifndef __7Z_FOLDER_IN_STREAM_H #define __7Z_FOLDER_IN_STREAM_H #include "../../ICoder.h" #include "../IArchive.h" #include "../Common/InStreamWithCRC.h" #include "7zItem.h" namespace NArchive { namespace N7z { class CFolderInStream: public ISequentialInStream, public ICompressGetSubStreamSize, public CMyUnknownImp { CSequentialInStreamWithCRC *_inStreamWithHashSpec; CMyComPtr _inStreamWithHash; CMyComPtr _updateCallback; bool _currentSizeIsDefined; bool _fileIsOpen; UInt64 _currentSize; UInt64 _filePos; const UInt32 *_fileIndices; UInt32 _numFiles; UInt32 _fileIndex; HRESULT OpenStream(); HRESULT CloseStream(); void AddDigest(); public: CRecordVector Processed; CRecordVector CRCs; CRecordVector Sizes; MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); CFolderInStream(); void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles); UInt64 GetFullSize() const { UInt64 size = 0; FOR_VECTOR (i, Sizes) size += Sizes[i]; return size; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp0100777000000000000000000000714513761647206025615 0ustar00// 7zFolderOutStream.cpp #include "StdAfx.h" #include "7zFolderOutStream.h" namespace NArchive { namespace N7z { CFolderOutStream::CFolderOutStream() { _crcStreamSpec = new COutStreamWithCRC; _crcStream = _crcStreamSpec; } HRESULT CFolderOutStream::Init( const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, bool testMode, bool checkCrc) { _db = db; _ref2Offset = ref2Offset; _startIndex = startIndex; _extractStatuses = extractStatuses; _extractCallback = extractCallback; _testMode = testMode; _checkCrc = checkCrc; _currentIndex = 0; _fileIsOpen = false; return ProcessEmptyFiles(); } HRESULT CFolderOutStream::OpenFile() { Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract) : NExtract::NAskMode::kSkip; CMyComPtr realOutStream; UInt32 index = _startIndex + _currentIndex; RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode)); _crcStreamSpec->SetStream(realOutStream); _crcStreamSpec->Init(_checkCrc); _fileIsOpen = true; const CFileItem &fi = _db->Files[index]; _rem = fi.Size; if (askMode == NExtract::NAskMode::kExtract && !realOutStream && !_db->IsItemAnti(index) && !fi.IsDir) askMode = NExtract::NAskMode::kSkip; return _extractCallback->PrepareOperation(askMode); } HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res) { _crcStreamSpec->ReleaseStream(); _fileIsOpen = false; _currentIndex++; return _extractCallback->SetOperationResult(res); } HRESULT CFolderOutStream::CloseFileAndSetResult() { const CFileItem &fi = _db->Files[_startIndex + _currentIndex]; return CloseFileAndSetResult( (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ? NExtract::NOperationResult::kOK : NExtract::NOperationResult::kCRCError); } HRESULT CFolderOutStream::ProcessEmptyFiles() { while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) { RINOK(OpenFile()); RINOK(CloseFileAndSetResult()); } return S_OK; } STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size != 0) { if (_fileIsOpen) { UInt32 cur = size < _rem ? size : (UInt32)_rem; RINOK(_crcStream->Write(data, cur, &cur)); if (cur == 0) break; data = (const Byte *)data + cur; size -= cur; _rem -= cur; if (processedSize != NULL) *processedSize += cur; if (_rem == 0) { RINOK(CloseFileAndSetResult()); RINOK(ProcessEmptyFiles()); continue; } } else { RINOK(ProcessEmptyFiles()); if (_currentIndex == _extractStatuses->Size()) { // we support partial extracting if (processedSize != NULL) *processedSize += size; break; } RINOK(OpenFile()); } } return S_OK; } STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; if ((int)subStream >= _extractStatuses->Size()) return S_FALSE; *value = _db->Files[_startIndex + (int)subStream].Size; return S_OK; } HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) { while (_currentIndex < _extractStatuses->Size()) { if (_fileIsOpen) { RINOK(CloseFileAndSetResult(resultEOperationResult)); } else { RINOK(OpenFile()); } } return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h0100777000000000000000000000263713761647206025263 0ustar00// 7zFolderOutStream.h #ifndef __7Z_FOLDER_OUT_STREAM_H #define __7Z_FOLDER_OUT_STREAM_H #include "../../IStream.h" #include "../IArchive.h" #include "../Common/OutStreamWithCRC.h" #include "7zIn.h" namespace NArchive { namespace N7z { class CFolderOutStream: public ISequentialOutStream, public ICompressGetSubStreamSize, public CMyUnknownImp { COutStreamWithCRC *_crcStreamSpec; CMyComPtr _crcStream; const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr _extractCallback; UInt32 _ref2Offset; UInt32 _startIndex; unsigned _currentIndex; bool _testMode; bool _checkCrc; bool _fileIsOpen; UInt64 _rem; HRESULT OpenFile(); HRESULT CloseFileAndSetResult(Int32 res); HRESULT CloseFileAndSetResult(); HRESULT ProcessEmptyFiles(); public: MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) CFolderOutStream(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); HRESULT Init( const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, bool testMode, bool checkCrc); HRESULT FlushCorrupted(Int32 resultEOperationResult); HRESULT WasWritingFinished() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp0100777000000000000000000004435313761647206024115 0ustar00// 7zHandler.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #ifndef __7Z_SET_PROPERTIES #include "../../../Windows/System.h" #endif #include "../Common/ItemNameUtils.h" #include "7zHandler.h" #include "7zProperties.h" #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY #include "../Common/ParseProperties.h" #endif #endif using namespace NWindows; using namespace NCOM; namespace NArchive { namespace N7z { CHandler::CHandler() { #ifndef _NO_CRYPTO _isEncrypted = false; _passwordIsDefined = false; #endif #ifdef EXTRACT_ONLY _crcSize = 4; #ifdef __7Z_SET_PROPERTIES _numThreads = NSystem::GetNumberOfProcessors(); #endif #endif } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _db.Files.Size(); return S_OK; } #ifdef _SFX IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { *numProps = 0; return S_OK; } STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */) { return E_NOTIMPL; } #else static const Byte kArcProps[] = { kpidHeadersSize, kpidMethod, kpidSolid, kpidNumBlocks // , kpidIsTree }; IMP_IInArchive_ArcProps static inline char GetHex(unsigned value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) { int len = 0; do { s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; } while (id != 0); return (unsigned)-len; } static void ConvertMethodIdToString(AString &res, UInt64 id) { const unsigned kLen = 32; char s[kLen]; unsigned len = kLen - 1; s[len] = 0; res += s + len - ConvertMethodIdToString_Back(s + len, id); } static unsigned GetStringForSizeValue(char *s, UInt32 val) { unsigned i; for (i = 0; i <= 31; i++) if (((UInt32)1 << i) == val) { if (i < 10) { s[0] = (char)('0' + i); s[1] = 0; return 1; } if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); } else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); } else { s[0] = '3'; s[1] = (char)('0' + i - 30); } s[2] = 0; return 2; } char c = 'b'; if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } ::ConvertUInt32ToString(val, s); unsigned pos = MyStringLen(s); s[pos++] = c; s[pos] = 0; return pos; } /* static inline void AddHexToString(UString &res, Byte value) { res += GetHex((Byte)(value >> 4)); res += GetHex((Byte)(value & 0xF)); } */ static char *AddProp32(char *s, const char *name, UInt32 v) { *s++ = ':'; s = MyStpCpy(s, name); ::ConvertUInt32ToString(v, s); return s + MyStringLen(s); } void CHandler::AddMethodName(AString &s, UInt64 id) { UString methodName; FindMethod(EXTERNAL_CODECS_VARS id, methodName); if (methodName.IsEmpty()) { for (unsigned i = 0; i < methodName.Len(); i++) if (methodName[i] >= 0x80) { methodName.Empty(); break; } } if (methodName.IsEmpty()) ConvertMethodIdToString(s, id); else for (unsigned i = 0; i < methodName.Len(); i++) s += (char)methodName[i]; } #endif STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { #ifndef _SFX COM_TRY_BEGIN #endif NCOM::CPropVariant prop; switch (propID) { #ifndef _SFX case kpidMethod: { AString s; const CParsedMethods &pm = _db.ParsedMethods; FOR_VECTOR (i, pm.IDs) { UInt64 id = pm.IDs[i]; if (!s.IsEmpty()) s += ' '; char temp[16]; if (id == k_LZMA2) { s += "LZMA2:"; if ((pm.Lzma2Prop & 1) == 0) ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp); else GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11)); s += temp; } else if (id == k_LZMA) { s += "LZMA:"; GetStringForSizeValue(temp, pm.LzmaDic); s += temp; } else AddMethodName(s, id); } prop = s; break; } case kpidSolid: prop = _db.IsSolid(); break; case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; case kpidHeadersSize: prop = _db.HeadersSize; break; case kpidPhySize: prop = _db.PhySize; break; case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; /* case kpidIsTree: if (_db.IsTree) prop = true; break; case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; case kpidIsAux: if (_db.IsTree) prop = true; break; */ // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; #endif case kpidWarningFlags: { UInt32 v = 0; if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; if (v != 0) prop = v; break; } case kpidErrorFlags: { UInt32 v = 0; if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; prop = v; break; } } prop.Detach(value); return S_OK; #ifndef _SFX COM_TRY_END #endif } static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index) { UInt64 value; if (v.GetItem(index, value)) PropVarEm_Set_FileTime64(prop, value); } bool CHandler::IsFolderEncrypted(CNum folderIndex) const { if (folderIndex == kNumNoIndex) return false; size_t startPos = _db.FoCodersDataOffset[folderIndex]; const Byte *p = _db.CodersData + startPos; size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; CInByte2 inByte; inByte.Init(p, size); CNum numCoders = inByte.ReadNum(); for (; numCoders != 0; numCoders--) { Byte mainByte = inByte.ReadByte(); unsigned idSize = (mainByte & 0xF); const Byte *longID = inByte.GetPtr(); UInt64 id64 = 0; for (unsigned j = 0; j < idSize; j++) id64 = ((id64 << 8) | longID[j]); inByte.SkipDataNoCheck(idSize); if (id64 == k_AES) return true; if ((mainByte & 0x20) != 0) inByte.SkipDataNoCheck(inByte.ReadNum()); } return false; } STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) { *numProps = 0; return S_OK; } STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) { *name = NULL; *propID = kpidNtSecure; return S_OK; } STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) { /* const CFileItem &file = _db.Files[index]; *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); *parent = (UInt32)(Int32)file.Parent; */ *parentType = NParentType::kDir; *parent = (UInt32)(Int32)-1; return S_OK; } STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) { *data = NULL; *dataSize = 0; *propType = 0; if (/* _db.IsTree && propID == kpidName || !_db.IsTree && */ propID == kpidPath) { if (_db.NameOffsets && _db.NamesBuf) { size_t offset = _db.NameOffsets[index]; size_t size = (_db.NameOffsets[index + 1] - offset) * 2; if (size < ((UInt32)1 << 31)) { *data = (const void *)(_db.NamesBuf + offset * 2); *dataSize = (UInt32)size; *propType = NPropDataType::kUtf16z; } } return S_OK; } /* if (propID == kpidNtSecure) { if (index < (UInt32)_db.SecureIDs.Size()) { int id = _db.SecureIDs[index]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; if (size >= 0) { *data = _db.SecureBuf + offs; *dataSize = (UInt32)size; *propType = NPropDataType::kRaw; } } } */ return S_OK; } #ifndef _SFX HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const { PropVariant_Clear(prop); if (folderIndex == kNumNoIndex) return S_OK; // for (int ttt = 0; ttt < 1; ttt++) { const unsigned kTempSize = 256; char temp[kTempSize]; unsigned pos = kTempSize; temp[--pos] = 0; size_t startPos = _db.FoCodersDataOffset[folderIndex]; const Byte *p = _db.CodersData + startPos; size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; CInByte2 inByte; inByte.Init(p, size); // numCoders == 0 ??? CNum numCoders = inByte.ReadNum(); bool needSpace = false; for (; numCoders != 0; numCoders--, needSpace = true) { if (pos < 32) // max size of property break; Byte mainByte = inByte.ReadByte(); unsigned idSize = (mainByte & 0xF); const Byte *longID = inByte.GetPtr(); UInt64 id64 = 0; for (unsigned j = 0; j < idSize; j++) id64 = ((id64 << 8) | longID[j]); inByte.SkipDataNoCheck(idSize); if ((mainByte & 0x10) != 0) { inByte.ReadNum(); // NumInStreams inByte.ReadNum(); // NumOutStreams } CNum propsSize = 0; const Byte *props = NULL; if ((mainByte & 0x20) != 0) { propsSize = inByte.ReadNum(); props = inByte.GetPtr(); inByte.SkipDataNoCheck(propsSize); } const char *name = NULL; char s[32]; s[0] = 0; if (id64 <= (UInt32)0xFFFFFFFF) { UInt32 id = (UInt32)id64; if (id == k_LZMA) { name = "LZMA"; if (propsSize == 5) { UInt32 dicSize = GetUi32((const Byte *)props + 1); char *dest = s + GetStringForSizeValue(s, dicSize); UInt32 d = props[0]; if (d != 0x5D) { UInt32 lc = d % 9; d /= 9; UInt32 pb = d / 5; UInt32 lp = d % 5; if (lc != 3) dest = AddProp32(dest, "lc", lc); if (lp != 0) dest = AddProp32(dest, "lp", lp); if (pb != 2) dest = AddProp32(dest, "pb", pb); } } } else if (id == k_LZMA2) { name = "LZMA2"; if (propsSize == 1) { Byte p = props[0]; if ((p & 1) == 0) ConvertUInt32ToString((UInt32)((p >> 1) + 12), s); else GetStringForSizeValue(s, 3 << ((p >> 1) + 11)); } } else if (id == k_PPMD) { name = "PPMD"; if (propsSize == 5) { Byte order = *props; char *dest = s; *dest++ = 'o'; ConvertUInt32ToString(order, dest); dest += MyStringLen(dest); dest = MyStpCpy(dest, ":mem"); GetStringForSizeValue(dest, GetUi32(props + 1)); } } else if (id == k_Delta) { name = "Delta"; if (propsSize == 1) ConvertUInt32ToString((UInt32)props[0] + 1, s); } else if (id == k_BCJ2) name = "BCJ2"; else if (id == k_BCJ) name = "BCJ"; else if (id == k_AES) { name = "7zAES"; if (propsSize >= 1) { Byte firstByte = props[0]; UInt32 numCyclesPower = firstByte & 0x3F; ConvertUInt32ToString(numCyclesPower, s); } } } if (name) { unsigned nameLen = MyStringLen(name); unsigned propsLen = MyStringLen(s); unsigned totalLen = nameLen + propsLen; if (propsLen != 0) totalLen++; if (needSpace) totalLen++; if (totalLen + 5 >= pos) break; pos -= totalLen; MyStringCopy(temp + pos, name); if (propsLen != 0) { char *dest = temp + pos + nameLen; *dest++ = ':'; MyStringCopy(dest, s); } if (needSpace) temp[pos + totalLen - 1] = ' '; } else { UString methodName; FindMethod(EXTERNAL_CODECS_VARS id64, methodName); if (methodName.IsEmpty()) { for (unsigned j = 0; j < methodName.Len(); j++) if (methodName[j] >= 0x80) { methodName.Empty(); break; } } if (needSpace) temp[--pos] = ' '; if (methodName.IsEmpty()) pos -= ConvertMethodIdToString_Back(temp + pos, id64); else { unsigned len = methodName.Len(); if (len + 5 > pos) break; pos -= len; for (unsigned i = 0; i < len; i++) temp[pos + i] = (char)methodName[i]; } } } if (numCoders != 0 && pos >= 4) { temp[--pos] = ' '; temp[--pos] = '.'; temp[--pos] = '.'; temp[--pos] = '.'; } return PropVarEm_Set_Str(prop, temp + pos); // } } #endif STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { PropVariant_Clear(value); // COM_TRY_BEGIN // NCOM::CPropVariant prop; /* const CRef2 &ref2 = _refs[index]; if (ref2.Refs.IsEmpty()) return E_FAIL; const CRef &ref = ref2.Refs.Front(); */ const CFileItem &item = _db.Files[index]; UInt32 index2 = index; switch(propID) { case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; case kpidSize: { PropVarEm_Set_UInt64(value, item.Size); // prop = ref2.Size; break; } case kpidPackSize: { // prop = ref2.PackSize; { CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); /* else PropVarEm_Set_UInt64(value, 0); */ } else PropVarEm_Set_UInt64(value, 0); } break; } // case kpidIsAux: prop = _db.IsItemAux(index2); break; case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; case kpidAttrib: if (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); break; case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; /* case kpidIsAltStream: prop = item.IsAltStream; break; case kpidNtSecure: { int id = _db.SecureIDs[index]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; if (size >= 0) { prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); } break; } */ case kpidPath: return _db.GetPath_Prop(index, value); #ifndef _SFX case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); case kpidBlock: { CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) PropVarEm_Set_UInt32(value, (UInt32)folderIndex); } break; case kpidPackedSize0: case kpidPackedSize1: case kpidPackedSize2: case kpidPackedSize3: case kpidPackedSize4: { /* CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { const CFolder &folderInfo = _db.Folders[folderIndex]; if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) { prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); } else prop = (UInt64)0; } else prop = (UInt64)0; */ } break; #endif } // prop.Detach(value); return S_OK; // COM_TRY_END } STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) { COM_TRY_BEGIN Close(); #ifndef _SFX _fileInfoPopIDs.Clear(); #endif try { CMyComPtr openArchiveCallbackTemp = openArchiveCallback; #ifndef _NO_CRYPTO CMyComPtr getTextPassword; if (openArchiveCallback) openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif CInArchive archive; _db.IsArc = false; RINOK(archive.Open(stream, maxCheckStartPosition)); _db.IsArc = true; HRESULT result = archive.ReadDatabase( EXTERNAL_CODECS_VARS _db #ifndef _NO_CRYPTO , getTextPassword, _isEncrypted, _passwordIsDefined #endif ); RINOK(result); _inStream = stream; } catch(...) { Close(); // return E_INVALIDARG; // we must return out_of_memory here return S_FALSE; } // _inStream = stream; #ifndef _SFX FillPopIDs(); #endif return S_OK; COM_TRY_END } STDMETHODIMP CHandler::Close() { COM_TRY_BEGIN _inStream.Release(); _db.Clear(); #ifndef _NO_CRYPTO _isEncrypted = false; _passwordIsDefined = false; #endif return S_OK; COM_TRY_END } #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); _numThreads = numProcessors; for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; UInt32 number; int index = ParseStringToUInt32(name, number); if (index == 0) { if (name.IsPrefixedBy(L"mt")) { RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads)); continue; } else return E_INVALIDARG; } } return S_OK; COM_TRY_END } #endif #endif IMPL_ISetCompressCodecsInfo }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h0100777000000000000000000000676613761647206023570 0ustar00// 7z/Handler.h #ifndef __7Z_HANDLER_H #define __7Z_HANDLER_H #include "../../ICoder.h" #include "../IArchive.h" #include "../../Common/CreateCoder.h" #ifndef EXTRACT_ONLY #include "../Common/HandlerOut.h" #endif #include "7zCompressionMode.h" #include "7zIn.h" namespace NArchive { namespace N7z { const UInt32 k_Copy = 0x0; const UInt32 k_Delta = 3; const UInt32 k_LZMA2 = 0x21; const UInt32 k_LZMA = 0x030101; const UInt32 k_PPMD = 0x030401; const UInt32 k_BCJ = 0x03030103; const UInt32 k_BCJ2 = 0x0303011B; const UInt32 k_Deflate = 0x040108; const UInt32 k_BZip2 = 0x040202; #ifndef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY #if !defined(_7ZIP_ST) && !defined(_SFX) #define __7Z_SET_PROPERTIES #endif #else #define __7Z_SET_PROPERTIES #endif #endif #ifndef EXTRACT_ONLY class COutHandler: public CMultiMethodProps { HRESULT SetSolidFromString(const UString &s); HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value); public: bool _removeSfxBlock; UInt64 _numSolidFiles; UInt64 _numSolidBytes; bool _numSolidBytesDefined; bool _solidExtension; bool _compressHeaders; bool _encryptHeadersSpecified; bool _encryptHeaders; // bool _useParents; 9.26 CBoolPair Write_CTime; CBoolPair Write_ATime; CBoolPair Write_MTime; bool _volumeMode; void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } void InitSolid() { InitSolidFiles(); InitSolidSize(); _solidExtension = false; _numSolidBytesDefined = false; } void InitProps(); COutHandler() { InitProps(); } HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); }; #endif class CHandler: public IInArchive, public IArchiveGetRawProps, #ifdef __7Z_SET_PROPERTIES public ISetProperties, #endif #ifndef EXTRACT_ONLY public IOutArchive, #endif PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp #ifndef EXTRACT_ONLY , public COutHandler #endif { public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) #ifdef __7Z_SET_PROPERTIES MY_QUERYINTERFACE_ENTRY(ISetProperties) #endif #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY(IOutArchive) #endif QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) INTERFACE_IArchiveGetRawProps(;) #ifdef __7Z_SET_PROPERTIES STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) #endif DECL_ISetCompressCodecsInfo CHandler(); private: CMyComPtr _inStream; NArchive::N7z::CDbEx _db; #ifndef _NO_CRYPTO bool _isEncrypted; bool _passwordIsDefined; #endif #ifdef EXTRACT_ONLY #ifdef __7Z_SET_PROPERTIES UInt32 _numThreads; #endif UInt32 _crcSize; #else CRecordVector _binds; HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); void AddDefaultMethod(); HRESULT SetMainMethod(CCompressionMethodMode &method, CObjectVector &methodsInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); #endif bool IsFolderEncrypted(CNum folderIndex) const; #ifndef _SFX CRecordVector _fileInfoPopIDs; void FillPopIDs(); void AddMethodName(AString &s, UInt64 id); HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; #endif DECL_EXTERNAL_CODECS_VARS }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp0100777000000000000000000005415013761647206024601 0ustar00// 7zHandlerOut.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" #include "../../../Common/Wildcard.h" #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" #include "7zHandler.h" #include "7zOut.h" #include "7zUpdate.h" using namespace NWindows; namespace NArchive { namespace N7z { static const wchar_t *k_LZMA_Name = L"LZMA"; static const wchar_t *kDefaultMethodName = L"LZMA2"; static const wchar_t *k_Copy_Name = L"Copy"; static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; static const UInt32 k_NumFastBytes_ForHeaders = 273; static const UInt32 k_Level_ForHeaders = 5; static const UInt32 k_Dictionary_ForHeaders = #ifdef UNDER_CE 1 << 18; #else 1 << 20; #endif STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { *type = NFileTimeType::kWindows; return S_OK; } HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) { if (!FindMethod( EXTERNAL_CODECS_VARS m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams)) return E_INVALIDARG; (CProps &)dest = (CProps &)m; return S_OK; } HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) { if (!_compressHeaders) return S_OK; COneMethodInfo m; m.MethodName = k_LZMA_Name; m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders); m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); m.AddNumThreadsProp(1); CMethodFull methodFull; RINOK(PropsMethod_To_FullMethod(methodFull, m)); headerMethod.Methods.Add(methodFull); return S_OK; } void CHandler::AddDefaultMethod() { FOR_VECTOR (i, _methods) { UString &methodName = _methods[i].MethodName; if (methodName.IsEmpty()) methodName = kDefaultMethodName; } if (_methods.IsEmpty()) { COneMethodInfo m; m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); _methods.Add(m); } } HRESULT CHandler::SetMainMethod( CCompressionMethodMode &methodMode, CObjectVector &methods #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { AddDefaultMethod(); const UInt64 kSolidBytes_Min = (1 << 24); const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; bool needSolid = false; FOR_VECTOR (i, methods) { COneMethodInfo &oneMethodInfo = methods[i]; SetGlobalLevelAndThreads(oneMethodInfo #ifndef _7ZIP_ST , numThreads #endif ); CMethodFull methodFull; RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); methodMode.Methods.Add(methodFull); if (methodFull.Id != k_Copy) needSolid = true; if (_numSolidBytesDefined) continue; UInt32 dicSize; switch (methodFull.Id) { case k_LZMA: case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; case k_Deflate: dicSize = (UInt32)1 << 15; break; case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; default: continue; } _numSolidBytes = (UInt64)dicSize << 7; if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min; if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max; _numSolidBytesDefined = true; } if (!_numSolidBytesDefined) if (needSolid) _numSolidBytes = kSolidBytes_Max; else _numSolidBytes = 0; _numSolidBytesDefined = true; return S_OK; } static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined) { // ft = 0; // ftDefined = false; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) { ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); ftDefined = true; } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; else { ft = 0; ftDefined = false; } return S_OK; } /* #ifdef _WIN32 static const wchar_t kDirDelimiter1 = L'\\'; #endif static const wchar_t kDirDelimiter2 = L'/'; static inline bool IsCharDirLimiter(wchar_t c) { return ( #ifdef _WIN32 c == kDirDelimiter1 || #endif c == kDirDelimiter2); } static int FillSortIndex(CObjectVector &treeFolders, int cur, int curSortIndex) { CTreeFolder &tf = treeFolders[cur]; tf.SortIndex = curSortIndex++; for (int i = 0; i < tf.SubFolders.Size(); i++) curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); tf.SortIndexEnd = curSortIndex; return curSortIndex; } static int FindSubFolder(const CObjectVector &treeFolders, int cur, const UString &name, int &insertPos) { const CIntVector &subFolders = treeFolders[cur].SubFolders; int left = 0, right = subFolders.Size(); insertPos = -1; for (;;) { if (left == right) { insertPos = left; return -1; } int mid = (left + right) / 2; int midFolder = subFolders[mid]; int compare = CompareFileNames(name, treeFolders[midFolder].Name); if (compare == 0) return midFolder; if (compare < 0) right = mid; else left = mid + 1; } } static int AddFolder(CObjectVector &treeFolders, int cur, const UString &name) { int insertPos; int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); if (folderIndex < 0) { folderIndex = treeFolders.Size(); CTreeFolder &newFolder = treeFolders.AddNew(); newFolder.Parent = cur; newFolder.Name = name; treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); } // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; return folderIndex; } */ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { COM_TRY_BEGIN const CDbEx *db = 0; #ifdef _7Z_VOL if (_volumes.Size() > 1) return E_FAIL; const CVolume *volume = 0; if (_volumes.Size() == 1) { volume = &_volumes.Front(); db = &volume->Database; } #else if (_inStream != 0) db = &_db; #endif /* CMyComPtr getRawProps; updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); CUniqBlocks secureBlocks; secureBlocks.AddUniq(NULL, 0); CObjectVector treeFolders; { CTreeFolder folder; folder.Parent = -1; treeFolders.Add(folder); } */ CObjectVector updateItems; bool need_CTime = (Write_CTime.Def && Write_CTime.Val); bool need_ATime = (Write_ATime.Def && Write_ATime.Val); bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); if (db) { if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); } UString s; for (UInt32 i = 0; i < numItems; i++) { Int32 newData, newProps; UInt32 indexInArchive; if (!updateCallback) return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); CUpdateItem ui; ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); ui.IndexInArchive = indexInArchive; ui.IndexInClient = i; ui.IsAnti = false; ui.Size = 0; UString name; // bool isAltStream = false; if (ui.IndexInArchive != -1) { if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) return E_INVALIDARG; const CFileItem &fi = db->Files[ui.IndexInArchive]; if (!ui.NewProps) { _db.GetPath(ui.IndexInArchive, name); } ui.IsDir = fi.IsDir; ui.Size = fi.Size; // isAltStream = fi.IsAltStream; ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); if (!ui.NewProps) { ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); } } if (ui.NewProps) { bool folderStatusIsDefined; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); if (prop.vt == VT_EMPTY) ui.AttribDefined = false; else if (prop.vt != VT_UI4) return E_INVALIDARG; else { ui.Attrib = prop.ulVal; ui.AttribDefined = true; } } // we need MTime to sort files. if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); /* if (getRawProps) { const void *data; UInt32 dataSize; UInt32 propType; getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); if (dataSize != 0 && propType != NPropDataType::kRaw) return E_FAIL; ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); } */ { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_EMPTY) { } else if (prop.vt != VT_BSTR) return E_INVALIDARG; else { name = NItemName::MakeLegalName(prop.bstrVal); } } { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)); if (prop.vt == VT_EMPTY) folderStatusIsDefined = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else { ui.IsDir = (prop.boolVal != VARIANT_FALSE); folderStatusIsDefined = true; } } { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)); if (prop.vt == VT_EMPTY) ui.IsAnti = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else ui.IsAnti = (prop.boolVal != VARIANT_FALSE); } /* { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); if (prop.vt == VT_EMPTY) isAltStream = false; else if (prop.vt != VT_BOOL) return E_INVALIDARG; else isAltStream = (prop.boolVal != VARIANT_FALSE); } */ if (ui.IsAnti) { ui.AttribDefined = false; ui.CTimeDefined = false; ui.ATimeDefined = false; ui.MTimeDefined = false; ui.Size = 0; } if (!folderStatusIsDefined && ui.AttribDefined) ui.SetDirStatusFromAttrib(); } else { /* if (_db.SecureIDs.IsEmpty()) ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); else { int id = _db.SecureIDs[ui.IndexInArchive]; size_t offs = _db.SecureOffsets[id]; size_t size = _db.SecureOffsets[id + 1] - offs; ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); } */ } /* { int folderIndex = 0; if (_useParents) { int j; s.Empty(); for (j = 0; j < name.Len(); j++) { wchar_t c = name[j]; if (IsCharDirLimiter(c)) { folderIndex = AddFolder(treeFolders, folderIndex, s); s.Empty(); continue; } s += c; } if (isAltStream) { int colonPos = s.Find(':'); if (colonPos < 0) { // isAltStream = false; return E_INVALIDARG; } UString mainName = s.Left(colonPos); int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); if (treeFolders[newFolderIndex].UpdateItemIndex < 0) { for (int j = updateItems.Size() - 1; j >= 0; j--) { CUpdateItem &ui2 = updateItems[j]; if (ui2.ParentFolderIndex == folderIndex && ui2.Name == mainName) { ui2.TreeFolderIndex = newFolderIndex; treeFolders[newFolderIndex].UpdateItemIndex = j; } } } folderIndex = newFolderIndex; s.Delete(0, colonPos + 1); } ui.Name = s; } else ui.Name = name; ui.IsAltStream = isAltStream; ui.ParentFolderIndex = folderIndex; ui.TreeFolderIndex = -1; if (ui.IsDir && !s.IsEmpty()) { ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); } } */ ui.Name = name; if (ui.NewData) { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; ui.Size = (UInt64)prop.uhVal.QuadPart; if (ui.Size != 0 && ui.IsAnti) return E_INVALIDARG; } updateItems.Add(ui); } /* FillSortIndex(treeFolders, 0, 0); for (i = 0; i < (UInt32)updateItems.Size(); i++) { CUpdateItem &ui = updateItems[i]; ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; } */ CCompressionMethodMode methodMode, headerMethod; HRESULT res = SetMainMethod(methodMode, _methods #ifndef _7ZIP_ST , _numThreads #endif ); RINOK(res); methodMode.Binds = _binds; RINOK(SetHeaderMethod(headerMethod)); #ifndef _7ZIP_ST methodMode.NumThreads = _numThreads; headerMethod.NumThreads = 1; #endif CMyComPtr getPassword2; updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); methodMode.PasswordIsDefined = false; methodMode.Password.Empty(); if (getPassword2) { CMyComBSTR password; Int32 passwordIsDefined; RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); if (methodMode.PasswordIsDefined && (BSTR)password) methodMode.Password = password; } bool compressMainHeader = _compressHeaders; // check it bool encryptHeaders = false; if (methodMode.PasswordIsDefined) { if (_encryptHeadersSpecified) encryptHeaders = _encryptHeaders; #ifndef _NO_CRYPTO else encryptHeaders = _passwordIsDefined; #endif compressMainHeader = true; if (encryptHeaders) { headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; headerMethod.Password = methodMode.Password; } } if (numItems < 2) compressMainHeader = false; CUpdateOptions options; options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; int level = GetLevel(); options.UseFilters = level != 0 && _autoFilter; options.MaxFilter = level >= 8; options.HeaderOptions.CompressMainHeader = compressMainHeader; /* options.HeaderOptions.WriteCTime = Write_CTime; options.HeaderOptions.WriteATime = Write_ATime; options.HeaderOptions.WriteMTime = Write_MTime; */ options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; options.RemoveSfxBlock = _removeSfxBlock; options.VolumeMode = _volumeMode; COutArchive archive; CArchiveDatabaseOut newDatabase; CMyComPtr getPassword; updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); /* if (secureBlocks.Sorted.Size() > 1) { secureBlocks.GetReverseMap(); for (int i = 0; i < updateItems.Size(); i++) { int &secureIndex = updateItems[i].SecureIndex; secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; } } */ res = Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume ? volume->Stream: 0, volume ? db : 0, #else _inStream, db, #endif updateItems, // treeFolders, // secureBlocks, archive, newDatabase, outStream, updateCallback, options #ifndef _NO_CRYPTO , getPassword #endif ); RINOK(res); updateItems.ClearAndFree(); return archive.WriteDatabase(EXTERNAL_CODECS_VARS newDatabase, options.HeaderMethod, options.HeaderOptions); COM_TRY_END } static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) { stream = 0; int index = ParseStringToUInt32(srcString, coder); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); if (srcString[0] == 's') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); } return S_OK; } void COutHandler::InitProps() { CMultiMethodProps::Init(); _removeSfxBlock = false; _compressHeaders = true; _encryptHeadersSpecified = false; _encryptHeaders = false; // _useParents = false; Write_CTime.Init(); Write_ATime.Init(); Write_MTime.Init(); _volumeMode = false; InitSolid(); } HRESULT COutHandler::SetSolidFromString(const UString &s) { UString s2 = s; s2.MakeLower_Ascii(); for (unsigned i = 0; i < s2.Len();) { const wchar_t *start = ((const wchar_t *)s2) + i; const wchar_t *end; UInt64 v = ConvertStringToUInt64(start, &end); if (start == end) { if (s2[i++] != 'e') return E_INVALIDARG; _solidExtension = true; continue; } i += (int)(end - start); if (i == s2.Len()) return E_INVALIDARG; wchar_t c = s2[i++]; if (c == 'f') { if (v < 1) v = 1; _numSolidFiles = v; } else { unsigned numBits; switch (c) { case 'b': numBits = 0; break; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; case 't': numBits = 40; break; default: return E_INVALIDARG; } _numSolidBytes = (v << numBits); _numSolidBytesDefined = true; } } return S_OK; } HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) { bool isSolid; switch (value.vt) { case VT_EMPTY: isSolid = true; break; case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; case VT_BSTR: if (StringToBool(value.bstrVal, isSolid)) break; return SetSolidFromString(value.bstrVal); default: return E_INVALIDARG; } if (isSolid) InitSolid(); else _numSolidFiles = 1; return S_OK; } static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) { RINOK(PROPVARIANT_to_bool(prop, dest.Val)); dest.Def = true; return S_OK; } HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; if (name[0] == L's') { name.Delete(0); if (name.IsEmpty()) return SetSolidFromPROPVARIANT(value); if (value.vt != VT_EMPTY) return E_INVALIDARG; return SetSolidFromString(name); } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Ptr(index); if (index == 0) { if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); if (name.IsEqualTo("hcf")) { bool compressHeadersFull = true; RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); return compressHeadersFull ? S_OK: E_INVALIDARG; } if (name.IsEqualTo("he")) { RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); _encryptHeadersSpecified = true; return S_OK; } if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); } return CMultiMethodProps::SetProperty(name, value); } STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN _binds.Clear(); InitProps(); for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; if (name[0] == 'b') { if (value.vt != VT_EMPTY) return E_INVALIDARG; name.Delete(0); CBind bind; RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream)); if (name[0] != ':') return E_INVALIDARG; name.Delete(0); RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream)); if (!name.IsEmpty()) return E_INVALIDARG; _binds.Add(bind); continue; } RINOK(SetProperty(name, value)); } unsigned numEmptyMethods = GetNumEmptyMethods(); if (numEmptyMethods > 0) { unsigned k; for (k = 0; k < _binds.Size(); k++) { const CBind &bind = _binds[k]; if (bind.InCoder < (UInt32)numEmptyMethods || bind.OutCoder < (UInt32)numEmptyMethods) return E_INVALIDARG; } for (k = 0; k < _binds.Size(); k++) { CBind &bind = _binds[k]; bind.InCoder -= (UInt32)numEmptyMethods; bind.OutCoder -= (UInt32)numEmptyMethods; } _methods.DeleteFrontal(numEmptyMethods); } AddDefaultMethod(); if (!_filterMethod.MethodName.IsEmpty()) { FOR_VECTOR (k, _binds) { CBind &bind = _binds[k]; bind.InCoder++; bind.OutCoder++; } _methods.Insert(0, _filterMethod); } FOR_VECTOR (k, _binds) { const CBind &bind = _binds[k]; if (bind.InCoder >= (UInt32)_methods.Size() || bind.OutCoder >= (UInt32)_methods.Size()) return E_INVALIDARG; } return S_OK; COM_TRY_END } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp0100777000000000000000000000074213761647206023722 0ustar00// 7zHeader.cpp #include "StdAfx.h" #include "7zHeader.h" namespace NArchive { namespace N7z { Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; #ifdef _7Z_VOL Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; #endif // We can change signature. So file doesn't contain correct signature. // struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } }; // static SignatureInitializer g_SignatureInitializer; }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h0100777000000000000000000000272513761647206023372 0ustar00// 7z/7zHeader.h #ifndef __7Z_HEADER_H #define __7Z_HEADER_H #include "../../../Common/MyTypes.h" namespace NArchive { namespace N7z { const unsigned kSignatureSize = 6; extern Byte kSignature[kSignatureSize]; // #define _7Z_VOL // 7z-MultiVolume is not finished yet. // It can work already, but I still do not like some // things of that new multivolume format. // So please keep it commented. #ifdef _7Z_VOL extern Byte kFinishSignature[kSignatureSize]; #endif struct CArchiveVersion { Byte Major; Byte Minor; }; const Byte kMajorVersion = 0; struct CStartHeader { UInt64 NextHeaderOffset; UInt64 NextHeaderSize; UInt32 NextHeaderCRC; }; const UInt32 kStartHeaderSize = 20; #ifdef _7Z_VOL struct CFinishHeader: public CStartHeader { UInt64 ArchiveStartOffset; // data offset from end if that struct UInt64 AdditionalStartBlockSize; // start signature & start header size }; const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; #endif namespace NID { enum EEnum { kEnd, kHeader, kArchiveProperties, kAdditionalStreamsInfo, kMainStreamsInfo, kFilesInfo, kPackInfo, kUnpackInfo, kSubStreamsInfo, kSize, kCRC, kFolder, kCodersUnpackSize, kNumUnpackStream, kEmptyStream, kEmptyFile, kAnti, kName, kCTime, kATime, kMTime, kWinAttrib, kComment, kEncodedHeader, kStartPos, kDummy // kNtSecure, // kParent, // kIsAux }; } }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp0100777000000000000000000012175713761647206023112 0ustar00// 7zIn.cpp #include "StdAfx.h" #ifdef _WIN32 #include #else #include #endif #include "../../../../C/7zCrc.h" #include "../../../../C/CpuArch.h" #include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" #include "7zDecode.h" #include "7zIn.h" #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader #ifndef _SFX #define FORMAT_7Z_RECOVERY #endif using namespace NWindows; using namespace NCOM; namespace NArchive { namespace N7z { static const UInt32 k_LZMA2 = 0x21; static const UInt32 k_LZMA = 0x030101; static void BoolVector_Fill_False(CBoolVector &v, unsigned size) { v.ClearAndSetSize(size); bool *p = &v[0]; for (unsigned i = 0; i < size; i++) p[i] = false; } static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) { if (index >= (UInt32)v.Size()) return true; bool res = v[index]; v[index] = true; return res; } bool CFolder::CheckStructure(unsigned numUnpackSizes) const { const unsigned kNumCodersMax = sizeof(UInt32) * 8; // don't change it const unsigned kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax const unsigned kNumBindsMax = 32; if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) return false; { CBoolVector v; BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); unsigned i; for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) return false; for (i = 0; i < PackStreams.Size(); i++) if (BoolVector_GetAndSet(v, PackStreams[i])) return false; BoolVector_Fill_False(v, numUnpackSizes); for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) return false; } UInt32 mask[kMaskSize]; unsigned i; for (i = 0; i < kMaskSize; i++) mask[i] = 0; { CUIntVector inStreamToCoder, outStreamToCoder; for (i = 0; i < Coders.Size(); i++) { CNum j; const CCoderInfo &coder = Coders[i]; for (j = 0; j < coder.NumInStreams; j++) inStreamToCoder.Add(i); for (j = 0; j < coder.NumOutStreams; j++) outStreamToCoder.Add(i); } for (i = 0; i < BindPairs.Size(); i++) { const CBindPair &bp = BindPairs[i]; mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]); } } for (i = 0; i < kMaskSize; i++) for (unsigned j = 0; j < kMaskSize; j++) if (((1 << j) & mask[i]) != 0) mask[i] |= mask[j]; for (i = 0; i < kMaskSize; i++) if (((1 << i) & mask[i]) != 0) return false; return true; } class CInArchiveException {}; class CUnsupportedFeatureException: public CInArchiveException {}; static void ThrowException() { throw CInArchiveException(); } static inline void ThrowEndOfData() { ThrowException(); } static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } static inline void ThrowIncorrect() { ThrowException(); } class CStreamSwitch { CInArchive *_archive; bool _needRemove; bool _needUpdatePos; public: CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} ~CStreamSwitch() { Remove(); } void Remove(); void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); void Set(CInArchive *archive, const CByteBuffer &byteBuffer); void Set(CInArchive *archive, const CObjectVector *dataVector); }; void CStreamSwitch::Remove() { if (_needRemove) { if (_archive->_inByteBack->GetRem() != 0) _archive->ThereIsHeaderError = true; _archive->DeleteByteStream(_needUpdatePos); _needRemove = false; } } void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) { Remove(); _archive = archive; _archive->AddByteStream(data, size); _needRemove = true; _needUpdatePos = needUpdatePos; } void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) { Set(archive, byteBuffer, byteBuffer.Size(), false); } void CStreamSwitch::Set(CInArchive *archive, const CObjectVector *dataVector) { Remove(); Byte external = archive->ReadByte(); if (external != 0) { CNum dataIndex = archive->ReadNum(); if (dataIndex >= dataVector->Size()) ThrowIncorrect(); Set(archive, (*dataVector)[dataIndex]); } } void CInArchive::AddByteStream(const Byte *buf, size_t size) { if (_numInByteBufs == kNumBufLevelsMax) ThrowIncorrect(); _inByteBack = &_inByteVector[_numInByteBufs++]; _inByteBack->Init(buf, size); } Byte CInByte2::ReadByte() { if (_pos >= _size) ThrowEndOfData(); return _buffer[_pos++]; } void CInByte2::ReadBytes(Byte *data, size_t size) { if (size > _size - _pos) ThrowEndOfData(); memcpy(data, _buffer + _pos, size); _pos += size; } void CInByte2::SkipData(UInt64 size) { if (size > _size - _pos) ThrowEndOfData(); _pos += (size_t)size; } void CInByte2::SkipData() { SkipData(ReadNumber()); } static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) { if (size == 0) { processed = 0; return 0; } Byte firstByte = *p++; size--; if ((firstByte & 0x80) == 0) { processed = 1; return firstByte; } Byte mask = 0x40; if (size == 0) { processed = 0; return 0; } UInt64 value = (UInt64)*p; p++; size--; for (unsigned i = 1; i < 8; i++) { if ((firstByte & mask) == 0) { UInt64 highPart = firstByte & (mask - 1); value += (highPart << (i * 8)); processed = i + 1; return value; } if (size == 0) { processed = 0; return 0; } value |= ((UInt64)*p << (i * 8)); p++; size--; mask >>= 1; } processed = 9; return value; } UInt64 CInByte2::ReadNumber() { size_t processed; UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); if (processed == 0) ThrowEndOfData(); _pos += processed; return res; } CNum CInByte2::ReadNum() { /* if (_pos < _size) { Byte val = _buffer[_pos]; if ((unsigned)val < 0x80) { _pos++; return (unsigned)val; } } */ UInt64 value = ReadNumber(); if (value > kNumMax) ThrowUnsupported(); return (CNum)value; } UInt32 CInByte2::ReadUInt32() { if (_pos + 4 > _size) ThrowEndOfData(); UInt32 res = Get32(_buffer + _pos); _pos += 4; return res; } UInt64 CInByte2::ReadUInt64() { if (_pos + 8 > _size) ThrowEndOfData(); UInt64 res = Get64(_buffer + _pos); _pos += 8; return res; } #define CHECK_SIGNATURE if (p[0] != '7' || p[1] != 'z' || p[2] != 0xBC || p[3] != 0xAF || p[4] != 0x27 || p[5] != 0x1C) return false; static inline bool TestSignature(const Byte *p) { CHECK_SIGNATURE return CrcCalc(p + 12, 20) == Get32(p + 8); } #ifdef FORMAT_7Z_RECOVERY static inline bool TestSignature2(const Byte *p) { CHECK_SIGNATURE; if (CrcCalc(p + 12, 20) == Get32(p + 8)) return true; for (unsigned i = 8; i < kHeaderSize; i++) if (p[i] != 0) return false; return (p[6] != 0 || p[7] != 0); } #else #define TestSignature2(p) TestSignature(p) #endif HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); if (TestSignature2(_header)) return S_OK; if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) return S_FALSE; const UInt32 kBufSize = 1 << 15; CByteArr buf(kBufSize); memcpy(buf, _header, kHeaderSize); UInt64 offset = 0; for (;;) { UInt32 readSize = kBufSize - kHeaderSize; { UInt64 rem = *searchHeaderSizeLimit - offset; if (readSize > rem) readSize = (UInt32)rem; if (readSize == 0) return S_FALSE; } UInt32 processed = 0; RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)); if (processed == 0) return S_FALSE; for (UInt32 pos = 0;;) { const Byte *p = buf + pos + 1; const Byte *lim = buf + processed; for (; p <= lim; p += 4) { if (p[0] == '7') break; if (p[1] == '7') { p += 1; break; } if (p[2] == '7') { p += 2; break; } if (p[3] == '7') { p += 3; break; } }; if (p > lim) break; pos = (UInt32)(p - buf); if (TestSignature(p)) { memcpy(_header, p, kHeaderSize); _arhiveBeginStreamPosition += offset + pos; return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL); } } offset += processed; memmove(buf, buf + processed, kHeaderSize); } } // S_FALSE means that file is not archive HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { HeadersSize = 0; Close(); RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) RINOK(stream->Seek(0, STREAM_SEEK_END, &_fileEndPosition)) RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL)) RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); _stream = stream; return S_OK; } void CInArchive::Close() { _numInByteBufs = 0; _stream.Release(); ThereIsHeaderError = false; } void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) { for (;;) { if (ReadID() == NID::kEnd) break; SkipData(); } } // CFolder &folder can be non empty. So we must set all fields void CInByte2::ParseFolder(CFolder &folder) { CNum numCoders = ReadNum(); folder.Coders.SetSize(numCoders); CNum numInStreams = 0; CNum numOutStreams = 0; CNum i; for (i = 0; i < numCoders; i++) { CCoderInfo &coder = folder.Coders[i]; { Byte mainByte = ReadByte(); if ((mainByte & 0xC0) != 0) ThrowUnsupported(); unsigned idSize = (mainByte & 0xF); if (idSize > 8 || idSize > GetRem()) ThrowUnsupported(); const Byte *longID = GetPtr(); UInt64 id = 0; for (unsigned j = 0; j < idSize; j++) id = ((id << 8) | longID[j]); SkipDataNoCheck(idSize); coder.MethodID = id; if ((mainByte & 0x10) != 0) { coder.NumInStreams = ReadNum(); coder.NumOutStreams = ReadNum(); } else { coder.NumInStreams = 1; coder.NumOutStreams = 1; } if ((mainByte & 0x20) != 0) { CNum propsSize = ReadNum(); coder.Props.Alloc((size_t)propsSize); ReadBytes((Byte *)coder.Props, (size_t)propsSize); } else coder.Props.Free(); } numInStreams += coder.NumInStreams; numOutStreams += coder.NumOutStreams; } CNum numBindPairs = numOutStreams - 1; folder.BindPairs.SetSize(numBindPairs); for (i = 0; i < numBindPairs; i++) { CBindPair &bp = folder.BindPairs[i]; bp.InIndex = ReadNum(); bp.OutIndex = ReadNum(); } if (numInStreams < numBindPairs) ThrowUnsupported(); CNum numPackStreams = numInStreams - numBindPairs; folder.PackStreams.SetSize(numPackStreams); if (numPackStreams == 1) { for (i = 0; i < numInStreams; i++) if (folder.FindBindPairForInStream(i) < 0) { folder.PackStreams[0] = i; break; } if (i == numInStreams) ThrowUnsupported(); } else for (i = 0; i < numPackStreams; i++) folder.PackStreams[i] = ReadNum(); } void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const { size_t startPos = FoCodersDataOffset[folderIndex]; CInByte2 inByte; inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); inByte.ParseFolder(folder); if (inByte.GetRem() != 0) throw 20120424; } void CDatabase::GetPath(unsigned index, UString &path) const { path.Empty(); if (!NameOffsets || !NamesBuf) return; size_t offset = NameOffsets[index]; size_t size = NameOffsets[index + 1] - offset - 1; if (size >= (1 << 20)) return; wchar_t *s = path.GetBuffer((unsigned)size); const Byte *p = ((const Byte *)NamesBuf + offset * 2); #if defined(_WIN32) && defined(MY_CPU_LE) wmemcpy(s, (const wchar_t *)p, size); #else for (size_t i = 0; i < size; i++) { *s = Get16(p); p += 2; s++; } #endif path.ReleaseBuffer((unsigned)size); } HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() { PropVariant_Clear(path); if (!NameOffsets || !NamesBuf) return S_OK; size_t offset = NameOffsets[index]; size_t size = NameOffsets[index + 1] - offset; if (size >= (1 << 14)) return S_OK; RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1)); wchar_t *s = path->bstrVal; const Byte *p = ((const Byte *)NamesBuf + offset * 2); for (size_t i = 0; i < size; i++) { wchar_t c = Get16(p); p += 2; #if WCHAR_PATH_SEPARATOR != L'/' if (c == L'/') c = WCHAR_PATH_SEPARATOR; #endif *s++ = c; } return S_OK; /* unsigned cur = index; unsigned size = 0; for (int i = 0;; i++) { size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; size += (unsigned)len; if (i > 256 || len > (1 << 14) || size > (1 << 14)) return PropVarEm_Set_Str(path, "[TOO-LONG]"); cur = Files[cur].Parent; if (cur < 0) break; } size--; RINOK(PropVarEm_Alloc_Bstr(path, size)); wchar_t *s = path->bstrVal; s += size; *s = 0; cur = index; for (;;) { unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; do { p -= 2; --s; wchar_t c = Get16(p); if (c == '/') c = WCHAR_PATH_SEPARATOR; *s = c; } while (--len); const CFileItem &file = Files[cur]; cur = file.Parent; if (cur < 0) return S_OK; *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); } */ } void CInArchive::WaitId(UInt64 id) { for (;;) { UInt64 type = ReadID(); if (type == id) return; if (type == NID::kEnd) ThrowIncorrect(); SkipData(); } } void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) { ReadBoolVector2(numItems, crcs.Defs); crcs.Vals.ClearAndSetSize(numItems); UInt32 *p = &crcs.Vals[0]; const bool *defs = &crcs.Defs[0]; for (unsigned i = 0; i < numItems; i++) { UInt32 crc = 0; if (defs[i]) crc = ReadUInt32(); p[i] = crc; } } void CInArchive::ReadPackInfo(CFolders &f) { CNum numPackStreams = ReadNum(); WaitId(NID::kSize); f.PackPositions.Alloc(numPackStreams + 1); f.NumPackStreams = numPackStreams; UInt64 sum = 0; for (CNum i = 0; i < numPackStreams; i++) { f.PackPositions[i] = sum; UInt64 packSize = ReadNumber(); sum += packSize; if (sum < packSize) ThrowIncorrect(); } f.PackPositions[numPackStreams] = sum; UInt64 type; for (;;) { type = ReadID(); if (type == NID::kEnd) return; if (type == NID::kCRC) { CUInt32DefVector PackCRCs; ReadHashDigests(numPackStreams, PackCRCs); continue; } SkipData(); } } void CInArchive::ReadUnpackInfo( const CObjectVector *dataVector, CFolders &folders) { WaitId(NID::kFolder); CNum numFolders = ReadNum(); CNum numCodersOutStreams = 0; { CStreamSwitch streamSwitch; streamSwitch.Set(this, dataVector); const Byte *startBufPtr = _inByteBack->GetPtr(); folders.NumFolders = numFolders; folders.FoStartPackStreamIndex.Alloc(numFolders + 1); folders.FoToMainUnpackSizeIndex.Alloc(numFolders); folders.FoCodersDataOffset.Alloc(numFolders + 1); folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); CRecordVector InStreamUsed; CRecordVector OutStreamUsed; CNum packStreamIndex = 0; CNum fo; CInByte2 *inByte = _inByteBack; for (fo = 0; fo < numFolders; fo++) { UInt32 numOutStreams = 0; UInt32 indexOfMainStream = 0; UInt32 numPackStreams = 0; folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; numOutStreams = 0; CNum numInStreams = 0; CNum numCoders = inByte->ReadNum(); for (CNum ci = 0; ci < numCoders; ci++) { Byte mainByte = inByte->ReadByte(); if ((mainByte & 0xC0) != 0) ThrowUnsupported(); unsigned idSize = (mainByte & 0xF); if (idSize > 8) ThrowUnsupported(); if (idSize > inByte->GetRem()) ThrowEndOfData(); const Byte *longID = inByte->GetPtr(); UInt64 id = 0; for (unsigned j = 0; j < idSize; j++) id = ((id << 8) | longID[j]); inByte->SkipDataNoCheck(idSize); if (folders.ParsedMethods.IDs.Size() < 128) folders.ParsedMethods.IDs.AddToUniqueSorted(id); CNum coderInStreams = 1; CNum coderOutStreams = 1; if ((mainByte & 0x10) != 0) { coderInStreams = inByte->ReadNum(); coderOutStreams = inByte->ReadNum(); } numInStreams += coderInStreams; if (numInStreams < coderInStreams) ThrowUnsupported(); numOutStreams += coderOutStreams; if (numOutStreams < coderOutStreams) ThrowUnsupported(); if ((mainByte & 0x20) != 0) { CNum propsSize = inByte->ReadNum(); if (propsSize > inByte->GetRem()) ThrowEndOfData(); if (id == k_LZMA2 && propsSize == 1) { Byte v = *_inByteBack->GetPtr(); if (folders.ParsedMethods.Lzma2Prop < v) folders.ParsedMethods.Lzma2Prop = v; } else if (id == k_LZMA && propsSize == 5) { UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); if (folders.ParsedMethods.LzmaDic < dicSize) folders.ParsedMethods.LzmaDic = dicSize; } inByte->SkipDataNoCheck((size_t)propsSize); } } if (numOutStreams == 1 && numInStreams == 1) { indexOfMainStream = 0; numPackStreams = 1; } else { UInt32 i; if (numOutStreams == 0) ThrowUnsupported(); CNum numBindPairs = numOutStreams - 1; if (numInStreams < numBindPairs) ThrowUnsupported(); if (numInStreams >= 256 || numOutStreams >= 256) ThrowUnsupported(); InStreamUsed.ClearAndSetSize(numInStreams); for (i = 0; i < numInStreams; i++) InStreamUsed[i] = false; OutStreamUsed.ClearAndSetSize(numOutStreams); for (i = 0; i < numOutStreams; i++) OutStreamUsed[i] = false; for (i = 0; i < numBindPairs; i++) { CNum index = ReadNum(); if (index >= numInStreams || InStreamUsed[index]) ThrowUnsupported(); InStreamUsed[index] = true; index = ReadNum(); if (index >= numOutStreams || OutStreamUsed[index]) ThrowUnsupported(); OutStreamUsed[index] = true; } numPackStreams = numInStreams - numBindPairs; if (numPackStreams != 1) for (i = 0; i < numPackStreams; i++) inByte->ReadNum(); // PackStreams for (i = 0; i < numOutStreams; i++) if (!OutStreamUsed[i]) { indexOfMainStream = i; break; } if (i == numOutStreams) ThrowUnsupported(); } folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; numCodersOutStreams += numOutStreams; folders.FoStartPackStreamIndex[fo] = packStreamIndex; packStreamIndex += numPackStreams; folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; } size_t dataSize = _inByteBack->GetPtr() - startBufPtr; folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; folders.FoStartPackStreamIndex[fo] = packStreamIndex; folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; folders.CodersData.CopyFrom(startBufPtr, dataSize); } WaitId(NID::kCodersUnpackSize); folders.CoderUnpackSizes.Alloc(numCodersOutStreams); for (CNum i = 0; i < numCodersOutStreams; i++) folders.CoderUnpackSizes[i] = ReadNumber(); for (;;) { UInt64 type = ReadID(); if (type == NID::kEnd) return; if (type == NID::kCRC) { ReadHashDigests(numFolders, folders.FolderCRCs); continue; } SkipData(); } } void CInArchive::ReadSubStreamsInfo( CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests) { folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); CNum i; for (i = 0; i < folders.NumFolders; i++) folders.NumUnpackStreamsVector[i] = 1; UInt64 type; for (;;) { type = ReadID(); if (type == NID::kNumUnpackStream) { for (i = 0; i < folders.NumFolders; i++) folders.NumUnpackStreamsVector[i] = ReadNum(); continue; } if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) break; SkipData(); } if (type == NID::kSize) { for (i = 0; i < folders.NumFolders; i++) { // v3.13 incorrectly worked with empty folders // v4.07: we check that folder is empty CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 0) continue; UInt64 sum = 0; for (CNum j = 1; j < numSubstreams; j++) { UInt64 size = ReadNumber(); unpackSizes.Add(size); sum += size; if (sum < size) ThrowIncorrect(); } UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); if (folderUnpackSize < sum) ThrowIncorrect(); unpackSizes.Add(folderUnpackSize - sum); } type = ReadID(); } else { for (i = 0; i < folders.NumFolders; i++) { /* v9.26 - v9.29 incorrectly worked: if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ CNum val = folders.NumUnpackStreamsVector[i]; if (val > 1) ThrowIncorrect(); if (val == 1) unpackSizes.Add(folders.GetFolderUnpackSize(i)); } } unsigned numDigests = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) numDigests += numSubstreams; } for (;;) { if (type == NID::kEnd) break; if (type == NID::kCRC) { // CUInt32DefVector digests2; // ReadHashDigests(numDigests, digests2); CBoolVector digests2; ReadBoolVector2(numDigests, digests2); digests.ClearAndSetSize(unpackSizes.Size()); unsigned k = 0; unsigned k2 = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { digests.Defs[k] = true; digests.Vals[k] = folders.FolderCRCs.Vals[i]; k++; } else for (CNum j = 0; j < numSubstreams; j++) { bool defined = digests2[k2++]; digests.Defs[k] = defined; UInt32 crc = 0; if (defined) crc = ReadUInt32(); digests.Vals[k] = crc; k++; } } // if (k != unpackSizes.Size()) throw 1234567; } else SkipData(); type = ReadID(); } if (digests.Defs.Size() != unpackSizes.Size()) { digests.ClearAndSetSize(unpackSizes.Size()); unsigned k = 0; for (i = 0; i < folders.NumFolders; i++) { CNum numSubstreams = folders.NumUnpackStreamsVector[i]; if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { digests.Defs[k] = true; digests.Vals[k] = folders.FolderCRCs.Vals[i]; k++; } else for (CNum j = 0; j < numSubstreams; j++) { digests.Defs[k] = false; digests.Vals[k] = 0; k++; } } } } void CInArchive::ReadStreamsInfo( const CObjectVector *dataVector, UInt64 &dataOffset, CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests) { UInt64 type = ReadID(); if (type == NID::kPackInfo) { dataOffset = ReadNumber(); ReadPackInfo(folders); type = ReadID(); } if (type == NID::kUnpackInfo) { ReadUnpackInfo(dataVector, folders); type = ReadID(); } if (folders.NumFolders != 0 && !folders.PackPositions) { // if there are folders, we need PackPositions also folders.PackPositions.Alloc(1); folders.PackPositions[0] = 0; } if (type == NID::kSubStreamsInfo) { ReadSubStreamsInfo(folders, unpackSizes, digests); type = ReadID(); } else { folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); /* If digests.Defs.Size() == 0, it means that there are no crcs. So we don't need to fill digests with values. */ // digests.Vals.ClearAndSetSize(folders.NumFolders); // BoolVector_Fill_False(digests.Defs, folders.NumFolders); for (CNum i = 0; i < folders.NumFolders; i++) { folders.NumUnpackStreamsVector[i] = 1; unpackSizes.Add(folders.GetFolderUnpackSize(i)); // digests.Vals[i] = 0; } } if (type != NID::kEnd) ThrowIncorrect(); } void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) { v.ClearAndSetSize(numItems); Byte b = 0; Byte mask = 0; bool *p = &v[0]; for (unsigned i = 0; i < numItems; i++) { if (mask == 0) { b = ReadByte(); mask = 0x80; } p[i] = ((b & mask) != 0); mask >>= 1; } } void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) { Byte allAreDefined = ReadByte(); if (allAreDefined == 0) { ReadBoolVector(numItems, v); return; } v.ClearAndSetSize(numItems); bool *p = &v[0]; for (unsigned i = 0; i < numItems; i++) p[i] = true; } void CInArchive::ReadUInt64DefVector(const CObjectVector &dataVector, CUInt64DefVector &v, unsigned numItems) { ReadBoolVector2(numItems, v.Defs); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); v.Vals.ClearAndSetSize(numItems); UInt64 *p = &v.Vals[0]; const bool *defs = &v.Defs[0]; for (unsigned i = 0; i < numItems; i++) { UInt64 t = 0; if (defs[i]) t = ReadUInt64(); p[i] = t; } } HRESULT CInArchive::ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector &dataVector _7Z_DECODER_CRYPRO_VARS_DECL ) { CFolders folders; CRecordVector unpackSizes; CUInt32DefVector digests; ReadStreamsInfo(NULL, dataOffset, folders, unpackSizes, digests); CDecoder decoder( #ifdef _ST_MODE false #else true #endif ); for (CNum i = 0; i < folders.NumFolders; i++) { CByteBuffer &data = dataVector.AddNew(); UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); size_t unpackSize = (size_t)unpackSize64; if (unpackSize != unpackSize64) ThrowUnsupported(); data.Alloc(unpackSize); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr outStream = outStreamSpec; outStreamSpec->Init(data, unpackSize); HRESULT result = decoder.Decode( EXTERNAL_CODECS_LOC_VARS _stream, baseOffset + dataOffset, folders, i, outStream, NULL _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , false, 1 #endif ); RINOK(result); if (folders.FolderCRCs.ValidAndDefined(i)) if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) ThrowIncorrect(); } HeadersSize += folders.PackPositions[folders.NumPackStreams]; return S_OK; } HRESULT CInArchive::ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { UInt64 type = ReadID(); if (type == NID::kArchiveProperties) { ReadArchiveProperties(db.ArcInfo); type = ReadID(); } CObjectVector dataVector; if (type == NID::kAdditionalStreamsInfo) { HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS db.ArcInfo.StartPositionAfterHeader, db.ArcInfo.DataStartPosition2, dataVector _7Z_DECODER_CRYPRO_VARS ); RINOK(result); db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } CRecordVector unpackSizes; CUInt32DefVector digests; if (type == NID::kMainStreamsInfo) { ReadStreamsInfo(&dataVector, db.ArcInfo.DataStartPosition, (CFolders &)db, unpackSizes, digests); db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } db.Files.Clear(); if (type == NID::kFilesInfo) { CNum numFiles = ReadNum(); db.Files.ClearAndSetSize(numFiles); CNum i; /* db.Files.Reserve(numFiles); CNum i; for (i = 0; i < numFiles; i++) db.Files.Add(CFileItem()); */ db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); // if (!db.PackSizes.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); if (numFiles > 0 && !digests.Defs.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; for (;;) { UInt64 type = ReadID(); if (type == NID::kEnd) break; UInt64 size = ReadNumber(); if (size > _inByteBack->GetRem()) ThrowIncorrect(); CStreamSwitch switchProp; switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); bool addPropIdToList = true; bool isKnownType = true; if (type > ((UInt32)1 << 30)) isKnownType = false; else switch((UInt32)type) { case NID::kName: { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); size_t rem = _inByteBack->GetRem(); db.NamesBuf.Alloc(rem); ReadBytes(db.NamesBuf, rem); db.NameOffsets.Alloc(db.Files.Size() + 1); size_t pos = 0; unsigned i; for (i = 0; i < db.Files.Size(); i++) { size_t curRem = (rem - pos) / 2; const UInt16 *buf = (const UInt16 *)(db.NamesBuf + pos); size_t j; for (j = 0; j < curRem && buf[j] != 0; j++); if (j == curRem) ThrowEndOfData(); db.NameOffsets[i] = pos / 2; pos += j * 2 + 2; } db.NameOffsets[i] = pos / 2; if (pos != rem) ThereIsHeaderError = true; break; } case NID::kWinAttrib: { CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; file.AttribDefined = boolVector[i]; if (file.AttribDefined) file.Attrib = ReadUInt32(); } break; } /* case NID::kIsAux: { ReadBoolVector(db.Files.Size(), db.IsAux); break; } case NID::kParent: { db.IsTree = true; // CBoolVector boolVector; // ReadBoolVector2(db.Files.Size(), boolVector); // CStreamSwitch streamSwitch; // streamSwitch.Set(this, &dataVector); CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); db.ThereAreAltStreams = false; for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; // file.Parent = -1; // if (boolVector[i]) file.Parent = (int)ReadUInt32(); file.IsAltStream = !boolVector[i]; if (file.IsAltStream) db.ThereAreAltStreams = true; } break; } */ case NID::kEmptyStream: { ReadBoolVector(numFiles, emptyStreamVector); numEmptyStreams = 0; for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) if (emptyStreamVector[i]) numEmptyStreams++; BoolVector_Fill_False(emptyFileVector, numEmptyStreams); BoolVector_Fill_False(antiFileVector, numEmptyStreams); break; } case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; case NID::kDummy: { for (UInt64 j = 0; j < size; j++) if (ReadByte() != 0) ThereIsHeaderError = true; addPropIdToList = false; break; } /* case NID::kNtSecure: { try { { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); UInt32 numDescriptors = ReadUInt32(); size_t offset = 0; db.SecureOffsets.Clear(); for (i = 0; i < numDescriptors; i++) { UInt32 size = ReadUInt32(); db.SecureOffsets.Add(offset); offset += size; } // ThrowIncorrect();; db.SecureOffsets.Add(offset); db.SecureBuf.SetCapacity(offset); for (i = 0; i < numDescriptors; i++) { offset = db.SecureOffsets[i]; ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); } db.SecureIDs.Clear(); for (unsigned i = 0; i < db.Files.Size(); i++) { db.SecureIDs.Add(ReadNum()); // db.SecureIDs.Add(ReadUInt32()); } // ReadUInt32(); if (_inByteBack->GetRem() != 0) ThrowIncorrect();; } } catch(CInArchiveException &) { ThereIsHeaderError = true; addPropIdToList = isKnownType = false; db.ClearSecure(); } break; } */ default: addPropIdToList = isKnownType = false; } if (isKnownType) { if (addPropIdToList) db.ArcInfo.FileInfoPopIDs.Add(type); } else { db.UnsupportedFeatureWarning = true; _inByteBack->SkipRem(); } // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02) if (_inByteBack->GetRem() != 0) ThrowIncorrect(); } type = ReadID(); // Read (NID::kEnd) end of headers CNum emptyFileIndex = 0; CNum sizeIndex = 0; CNum numAntiItems = 0; for (i = 0; i < numEmptyStreams; i++) if (antiFileVector[i]) numAntiItems++; for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; bool isAnti; file.HasStream = !emptyStreamVector[i]; file.Crc = 0; if (file.HasStream) { file.IsDir = false; isAnti = false; file.Size = unpackSizes[sizeIndex]; file.CrcDefined = digests.ValidAndDefined(sizeIndex); if (file.CrcDefined) file.Crc = digests.Vals[sizeIndex]; sizeIndex++; } else { file.IsDir = !emptyFileVector[emptyFileIndex]; isAnti = antiFileVector[emptyFileIndex]; emptyFileIndex++; file.Size = 0; file.CrcDefined = false; } if (numAntiItems != 0) db.IsAnti.Add(isAnti); } } db.FillLinks(); /* if (type != NID::kEnd) ThrowIncorrect(); if (_inByteBack->GetRem() != 0) ThrowIncorrect(); */ return S_OK; } void CDbEx::FillLinks() { FolderStartFileIndex.ClearAndSetSize(NumFolders); FileIndexToFolderIndexMap.ClearAndSetSize(Files.Size()); CNum folderIndex = 0; CNum indexInFolder = 0; unsigned i; for (i = 0; i < Files.Size(); i++) { bool emptyStream = !Files[i].HasStream; if (indexInFolder == 0) { if (emptyStream) { FileIndexToFolderIndexMap[i] = kNumNoIndex; continue; } // v3.13 incorrectly worked with empty folders // v4.07: we skip empty folders for (;;) { if (folderIndex >= NumFolders) ThrowIncorrect(); FolderStartFileIndex[folderIndex] = i; if (NumUnpackStreamsVector[folderIndex] != 0) break; folderIndex++; } } FileIndexToFolderIndexMap[i] = folderIndex; if (emptyStream) continue; if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) { folderIndex++; indexInFolder = 0; } } if (indexInFolder != 0) folderIndex++; /* if (indexInFolder != 0) ThrowIncorrect(); */ for (;;) { if (folderIndex >= NumFolders) return; FolderStartFileIndex[folderIndex] = i; /* if (NumUnpackStreamsVector[folderIndex] != 0) ThrowIncorrect();; */ folderIndex++; } } HRESULT CInArchive::ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { db.Clear(); db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; db.ArcInfo.Version.Major = _header[6]; db.ArcInfo.Version.Minor = _header[7]; if (db.ArcInfo.Version.Major != kMajorVersion) { // db.UnsupportedVersion = true; return S_FALSE; } UInt64 nextHeaderOffset = Get64(_header + 12); UInt64 nextHeaderSize = Get64(_header + 20); UInt32 nextHeaderCRC = Get32(_header + 28); #ifdef FORMAT_7Z_RECOVERY UInt32 crcFromArc = Get32(_header + 8); if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) { UInt64 cur, fileSize; RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); const unsigned kCheckSize = 512; Byte buf[kCheckSize]; RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); UInt64 rem = fileSize - cur; unsigned checkSize = kCheckSize; if (rem < kCheckSize) checkSize = (unsigned)(rem); if (checkSize < 3) return S_FALSE; RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); if (buf[checkSize - 1] != 0) return S_FALSE; unsigned i; for (i = checkSize - 2;; i--) { if (buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo || buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo) break; if (i == 0) return S_FALSE; } nextHeaderSize = checkSize - i; nextHeaderOffset = rem - nextHeaderSize; nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); db.StartHeaderWasRecovered = true; } else #endif { // Crc was tested already at signature check // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); } db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; db.PhySize = kHeaderSize; db.IsArc = false; if ((Int64)nextHeaderOffset < 0 || nextHeaderSize > ((UInt64)1 << 62)) return S_FALSE; if (nextHeaderSize == 0) { if (nextHeaderOffset != 0) return S_FALSE; db.IsArc = true; return S_OK; } if (!db.StartHeaderWasRecovered) db.IsArc = true; HeadersSize += kHeaderSize + nextHeaderSize; db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) { db.UnexpectedEnd = true; return S_FALSE; } RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); size_t nextHeaderSize_t = (size_t)nextHeaderSize; if (nextHeaderSize_t != nextHeaderSize) return E_OUTOFMEMORY; CByteBuffer buffer2(nextHeaderSize_t); RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)); if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) ThrowIncorrect(); if (!db.StartHeaderWasRecovered) db.PhySizeWasConfirmed = true; CStreamSwitch streamSwitch; streamSwitch.Set(this, buffer2); CObjectVector dataVector; UInt64 type = ReadID(); if (type != NID::kHeader) { if (type != NID::kEncodedHeader) ThrowIncorrect(); HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS db.ArcInfo.StartPositionAfterHeader, db.ArcInfo.DataStartPosition2, dataVector _7Z_DECODER_CRYPRO_VARS ); RINOK(result); if (dataVector.Size() == 0) return S_OK; if (dataVector.Size() > 1) ThrowIncorrect(); streamSwitch.Remove(); streamSwitch.Set(this, dataVector.Front()); if (ReadID() != NID::kHeader) ThrowIncorrect(); } db.IsArc = true; db.HeadersSize = HeadersSize; return ReadHeader( EXTERNAL_CODECS_LOC_VARS db _7Z_DECODER_CRYPRO_VARS ); } HRESULT CInArchive::ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ) { try { HRESULT res = ReadDatabase2( EXTERNAL_CODECS_LOC_VARS db _7Z_DECODER_CRYPRO_VARS ); if (ThereIsHeaderError) db.ThereIsHeaderError = true; if (res == E_NOTIMPL) ThrowUnsupported(); return res; } catch(CUnsupportedFeatureException &) { db.UnsupportedFeatureError = true; return S_FALSE; } catch(CInArchiveException &) { db.ThereIsHeaderError = true; return S_FALSE; } } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h0100777000000000000000000002320713761647206022546 0ustar00// 7zIn.h #ifndef __7Z_IN_H #define __7Z_IN_H #include "../../../Common/MyCom.h" #include "../../../Windows/PropVariant.h" #include "../../IPassword.h" #include "../../IStream.h" #include "../../Common/CreateCoder.h" #include "../../Common/InBuffer.h" #include "7zItem.h" namespace NArchive { namespace N7z { /* We don't need to init isEncrypted and passwordIsDefined We must upgrade them only */ #ifdef _NO_CRYPTO #define _7Z_DECODER_CRYPRO_VARS_DECL #define _7Z_DECODER_CRYPRO_VARS #else #define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined #define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined #endif struct CParsedMethods { Byte Lzma2Prop; UInt32 LzmaDic; CRecordVector IDs; CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} }; struct CFolders { CNum NumPackStreams; CNum NumFolders; CObjArray PackPositions; // NumPackStreams + 1 // CUInt32DefVector PackCRCs; // we don't use PackCRCs now CUInt32DefVector FolderCRCs; // NumFolders CObjArray NumUnpackStreamsVector; // NumFolders CObjArray CoderUnpackSizes; // including unpack sizes of bind coders CObjArray FoToCoderUnpackSizes; // NumFolders + 1 CObjArray FoStartPackStreamIndex; // NumFolders + 1 CObjArray FoToMainUnpackSizeIndex; // NumFolders CObjArray FoCodersDataOffset; // NumFolders + 1 CByteBuffer CodersData; CParsedMethods ParsedMethods; void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const { return FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]; } UInt64 GetFolderUnpackSize(unsigned folderIndex) const { return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]]; } UInt64 GetStreamPackSize(unsigned index) const { return PackPositions[index + 1] - PackPositions[index]; } void Clear() { NumPackStreams = 0; PackPositions.Free(); // PackCRCs.Clear(); NumFolders = 0; FolderCRCs.Clear(); NumUnpackStreamsVector.Free(); CoderUnpackSizes.Free(); FoToCoderUnpackSizes.Free(); FoStartPackStreamIndex.Free(); FoToMainUnpackSizeIndex.Free(); FoCodersDataOffset.Free(); CodersData.Free(); } }; struct CDatabase: public CFolders { CRecordVector Files; CUInt64DefVector CTime; CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; CRecordVector IsAnti; /* CRecordVector IsAux; CByteBuffer SecureBuf; CRecordVector SecureIDs; */ CByteBuffer NamesBuf; CObjArray NameOffsets; // numFiles + 1, offsets of utf-16 symbols /* void ClearSecure() { SecureBuf.Free(); SecureIDs.Clear(); } */ void Clear() { CFolders::Clear(); // ClearSecure(); NamesBuf.Free(); NameOffsets.Free(); Files.Clear(); CTime.Clear(); ATime.Clear(); MTime.Clear(); StartPos.Clear(); IsAnti.Clear(); // IsAux.Clear(); } bool IsSolid() const { for (CNum i = 0; i < NumFolders; i++) if (NumUnpackStreamsVector[i] > 1) return true; return false; } bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } const void * GetName(unsigned index) const { if (!NameOffsets || !NamesBuf) return NULL; return (const void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); }; void GetPath(unsigned index, UString &path) const; HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw(); }; struct CInArchiveInfo { CArchiveVersion Version; UInt64 StartPosition; UInt64 StartPositionAfterHeader; UInt64 DataStartPosition; UInt64 DataStartPosition2; CRecordVector FileInfoPopIDs; void Clear() { StartPosition = 0; StartPositionAfterHeader = 0; DataStartPosition = 0; DataStartPosition2 = 0; FileInfoPopIDs.Clear(); } }; struct CDbEx: public CDatabase { CInArchiveInfo ArcInfo; CRecordVector FolderStartFileIndex; CRecordVector FileIndexToFolderIndexMap; UInt64 HeadersSize; UInt64 PhySize; /* CRecordVector SecureOffsets; bool IsTree; bool ThereAreAltStreams; */ bool IsArc; bool PhySizeWasConfirmed; bool ThereIsHeaderError; bool UnexpectedEnd; // bool UnsupportedVersion; bool StartHeaderWasRecovered; bool UnsupportedFeatureWarning; bool UnsupportedFeatureError; /* void ClearSecureEx() { ClearSecure(); SecureOffsets.Clear(); } */ void Clear() { IsArc = false; PhySizeWasConfirmed = false; ThereIsHeaderError = false; UnexpectedEnd = false; // UnsupportedVersion = false; StartHeaderWasRecovered = false; UnsupportedFeatureError = false; UnsupportedFeatureWarning = false; /* IsTree = false; ThereAreAltStreams = false; */ CDatabase::Clear(); // SecureOffsets.Clear(); ArcInfo.Clear(); FolderStartFileIndex.Clear(); FileIndexToFolderIndexMap.Clear(); HeadersSize = 0; PhySize = 0; } void FillLinks(); UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const { return ArcInfo.DataStartPosition + PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder]; } UInt64 GetFolderFullPackSize(unsigned folderIndex) const { return PackPositions[FoStartPackStreamIndex[folderIndex + 1]] - PackPositions[FoStartPackStreamIndex[folderIndex]]; } UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const { unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex; return PackPositions[i + 1] - PackPositions[i]; } UInt64 GetFilePackSize(CNum fileIndex) const { CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; if (folderIndex != kNumNoIndex) if (FolderStartFileIndex[folderIndex] == fileIndex) return GetFolderFullPackSize(folderIndex); return 0; } }; const unsigned kNumBufLevelsMax = 4; struct CInByte2 { const Byte *_buffer; public: size_t _size; size_t _pos; size_t GetRem() const { return _size - _pos; } const Byte *GetPtr() const { return _buffer + _pos; } void Init(const Byte *buffer, size_t size) { _buffer = buffer; _size = size; _pos = 0; } Byte ReadByte(); void ReadBytes(Byte *data, size_t size); void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; } void SkipData(UInt64 size); void SkipData(); void SkipRem() { _pos = _size; } UInt64 ReadNumber(); CNum ReadNum(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); void ParseFolder(CFolder &folder); }; class CStreamSwitch; const UInt32 kHeaderSize = 32; class CInArchive { friend class CStreamSwitch; CMyComPtr _stream; unsigned _numInByteBufs; CInByte2 _inByteVector[kNumBufLevelsMax]; CInByte2 *_inByteBack; bool ThereIsHeaderError; UInt64 _arhiveBeginStreamPosition; UInt64 _fileEndPosition; Byte _header[kHeaderSize]; UInt64 HeadersSize; void AddByteStream(const Byte *buffer, size_t size); void DeleteByteStream(bool needUpdatePos) { _numInByteBufs--; if (_numInByteBufs > 0) { _inByteBack = &_inByteVector[_numInByteBufs - 1]; if (needUpdatePos) _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos; } } private: HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } Byte ReadByte() { return _inByteBack->ReadByte(); } UInt64 ReadNumber() { return _inByteBack->ReadNumber(); } CNum ReadNum() { return _inByteBack->ReadNum(); } UInt64 ReadID() { return _inByteBack->ReadNumber(); } UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); } UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } void SkipData(UInt64 size) { _inByteBack->SkipData(size); } void SkipData() { _inByteBack->SkipData(); } void WaitId(UInt64 id); void ReadArchiveProperties(CInArchiveInfo &archiveInfo); void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); void ReadPackInfo(CFolders &f); void ReadUnpackInfo( const CObjectVector *dataVector, CFolders &folders); void ReadSubStreamsInfo( CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests); void ReadStreamsInfo( const CObjectVector *dataVector, UInt64 &dataOffset, CFolders &folders, CRecordVector &unpackSizes, CUInt32DefVector &digests); void ReadBoolVector(unsigned numItems, CBoolVector &v); void ReadBoolVector2(unsigned numItems, CBoolVector &v); void ReadUInt64DefVector(const CObjectVector &dataVector, CUInt64DefVector &v, unsigned numItems); HRESULT ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector &dataVector _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); public: CInArchive(): _numInByteBufs(0) { } HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive void Close(); HRESULT ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db _7Z_DECODER_CRYPRO_VARS_DECL ); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h0100777000000000000000000000642013761647206023074 0ustar00// 7zItem.h #ifndef __7Z_ITEM_H #define __7Z_ITEM_H #include "../../../Common/MyBuffer.h" #include "../../../Common/MyString.h" #include "../../Common/MethodId.h" #include "7zHeader.h" namespace NArchive { namespace N7z { const UInt64 k_AES = 0x06F10701; typedef UInt32 CNum; const CNum kNumMax = 0x7FFFFFFF; const CNum kNumNoIndex = 0xFFFFFFFF; struct CCoderInfo { CMethodId MethodID; CByteBuffer Props; CNum NumInStreams; CNum NumOutStreams; bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; struct CBindPair { CNum InIndex; CNum OutIndex; }; struct CFolder { CObjArray2 Coders; CObjArray2 BindPairs; CObjArray2 PackStreams; CNum GetNumOutStreams() const { CNum result = 0; FOR_VECTOR(i, Coders) result += Coders[i].NumOutStreams; return result; } int FindBindPairForInStream(CNum inStreamIndex) const { FOR_VECTOR(i, BindPairs) if (BindPairs[i].InIndex == inStreamIndex) return i; return -1; } int FindBindPairForOutStream(CNum outStreamIndex) const { FOR_VECTOR(i, BindPairs) if (BindPairs[i].OutIndex == outStreamIndex) return i; return -1; } int FindPackStreamArrayIndex(CNum inStreamIndex) const { FOR_VECTOR(i, PackStreams) if (PackStreams[i] == inStreamIndex) return i; return -1; } int GetIndexOfMainOutStream() const { for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--) if (FindBindPairForOutStream(i) < 0) return i; throw 1; } bool IsEncrypted() const { for (int i = Coders.Size() - 1; i >= 0; i--) if (Coders[i].MethodID == k_AES) return true; return false; } bool CheckStructure(unsigned numUnpackSizes) const; }; struct CUInt32DefVector { CBoolVector Defs; CRecordVector Vals; void ClearAndSetSize(unsigned newSize) { Defs.ClearAndSetSize(newSize); Vals.ClearAndSetSize(newSize); } void Clear() { Defs.Clear(); Vals.Clear(); } void ReserveDown() { Defs.ReserveDown(); Vals.ReserveDown(); } bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } }; struct CUInt64DefVector { CBoolVector Defs; CRecordVector Vals; void Clear() { Defs.Clear(); Vals.Clear(); } void ReserveDown() { Defs.ReserveDown(); Vals.ReserveDown(); } bool GetItem(unsigned index, UInt64 &value) const { if (index < Defs.Size() && Defs[index]) { value = Vals[index]; return true; } value = 0; return false; } void SetItem(unsigned index, bool defined, UInt64 value); bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } }; struct CFileItem { UInt64 Size; UInt32 Attrib; UInt32 Crc; /* int Parent; bool IsAltStream; */ bool HasStream; // Test it !!! it means that there is // stream in some folder. It can be empty stream bool IsDir; bool CrcDefined; bool AttribDefined; CFileItem(): /* Parent(-1), IsAltStream(false), */ HasStream(true), IsDir(false), CrcDefined(false), AttribDefined(false) {} void SetAttrib(UInt32 attrib) { AttribDefined = true; Attrib = attrib; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp0100777000000000000000000005325513761647206023310 0ustar00// 7zOut.cpp #include "StdAfx.h" #include "../../../../C/7zCrc.h" #include "../../Common/StreamObjects.h" #include "7zOut.h" namespace NArchive { namespace N7z { HRESULT COutArchive::WriteSignature() { Byte buf[8]; memcpy(buf, kSignature, kSignatureSize); buf[kSignatureSize] = kMajorVersion; buf[kSignatureSize + 1] = 4; return WriteDirect(buf, 8); } #ifdef _7Z_VOL HRESULT COutArchive::WriteFinishSignature() { RINOK(WriteDirect(kFinishSignature, kSignatureSize)); CArchiveVersion av; av.Major = kMajorVersion; av.Minor = 2; RINOK(WriteDirectByte(av.Major)); return WriteDirectByte(av.Minor); } #endif static void SetUInt32(Byte *p, UInt32 d) { for (int i = 0; i < 4; i++, d >>= 8) p[i] = (Byte)d; } static void SetUInt64(Byte *p, UInt64 d) { for (int i = 0; i < 8; i++, d >>= 8) p[i] = (Byte)d; } HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) { Byte buf[24]; SetUInt64(buf + 4, h.NextHeaderOffset); SetUInt64(buf + 12, h.NextHeaderSize); SetUInt32(buf + 20, h.NextHeaderCRC); SetUInt32(buf, CrcCalc(buf + 4, 20)); return WriteDirect(buf, 24); } #ifdef _7Z_VOL HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) { CCRC crc; crc.UpdateUInt64(h.NextHeaderOffset); crc.UpdateUInt64(h.NextHeaderSize); crc.UpdateUInt32(h.NextHeaderCRC); crc.UpdateUInt64(h.ArchiveStartOffset); crc.UpdateUInt64(h.AdditionalStartBlockSize); RINOK(WriteDirectUInt32(crc.GetDigest())); RINOK(WriteDirectUInt64(h.NextHeaderOffset)); RINOK(WriteDirectUInt64(h.NextHeaderSize)); RINOK(WriteDirectUInt32(h.NextHeaderCRC)); RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); return WriteDirectUInt64(h.AdditionalStartBlockSize); } #endif HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker) { Close(); #ifdef _7Z_VOL // endMarker = false; _endMarker = endMarker; #endif SeqStream = stream; if (!endMarker) { SeqStream.QueryInterface(IID_IOutStream, &Stream); if (!Stream) { return E_NOTIMPL; // endMarker = true; } } #ifdef _7Z_VOL if (endMarker) { /* CStartHeader sh; sh.NextHeaderOffset = (UInt32)(Int32)-1; sh.NextHeaderSize = (UInt32)(Int32)-1; sh.NextHeaderCRC = 0; WriteStartHeader(sh); */ } else #endif { if (!Stream) return E_FAIL; RINOK(WriteSignature()); RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos)); } return S_OK; } void COutArchive::Close() { SeqStream.Release(); Stream.Release(); } HRESULT COutArchive::SkipPrefixArchiveHeader() { #ifdef _7Z_VOL if (_endMarker) return S_OK; #endif Byte buf[24]; memset(buf, 0, 24); return WriteDirect(buf, 24); } UInt64 COutArchive::GetPos() const { if (_countMode) return _countSize; if (_writeToStream) return _outByte.GetProcessedSize(); return _outByte2.GetPos(); } void COutArchive::WriteBytes(const void *data, size_t size) { if (_countMode) _countSize += size; else if (_writeToStream) { _outByte.WriteBytes(data, size); _crc = CrcUpdate(_crc, data, size); } else _outByte2.WriteBytes(data, size); } void COutArchive::WriteByte(Byte b) { if (_countMode) _countSize++; else if (_writeToStream) { _outByte.WriteByte(b); _crc = CRC_UPDATE_BYTE(_crc, b); } else _outByte2.WriteByte(b); } void COutArchive::WriteUInt32(UInt32 value) { for (int i = 0; i < 4; i++) { WriteByte((Byte)value); value >>= 8; } } void COutArchive::WriteUInt64(UInt64 value) { for (int i = 0; i < 8; i++) { WriteByte((Byte)value); value >>= 8; } } void COutArchive::WriteNumber(UInt64 value) { Byte firstByte = 0; Byte mask = 0x80; int i; for (i = 0; i < 8; i++) { if (value < ((UInt64(1) << ( 7 * (i + 1))))) { firstByte |= Byte(value >> (8 * i)); break; } firstByte |= mask; mask >>= 1; } WriteByte(firstByte); for (;i > 0; i--) { WriteByte((Byte)value); value >>= 8; } } static UInt32 GetBigNumberSize(UInt64 value) { int i; for (i = 1; i < 9; i++) if (value < (((UInt64)1 << (i * 7)))) break; return i; } #ifdef _7Z_VOL UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) { UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; if (nameLength != 0) { nameLength = (nameLength + 1) * 2; result += nameLength + GetBigNumberSize(nameLength) + 2; } if (props) { result += 20; } if (result >= 128) result++; result += kSignatureSize + 2 + kFinishHeaderSize; return result; } UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) { UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); int testSize; if (volSize > headersSizeBase) testSize = volSize - headersSizeBase; else testSize = 1; UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); UInt64 pureSize = 1; if (volSize > headersSize) pureSize = volSize - headersSize; return pureSize; } #endif void COutArchive::WriteFolder(const CFolder &folder) { WriteNumber(folder.Coders.Size()); unsigned i; for (i = 0; i < folder.Coders.Size(); i++) { const CCoderInfo &coder = folder.Coders[i]; { size_t propsSize = coder.Props.Size(); UInt64 id = coder.MethodID; int idSize; for (idSize = 1; idSize < sizeof(id); idSize++) if ((id >> (8 * idSize)) == 0) break; Byte longID[15]; for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) longID[t] = (Byte)(id & 0xFF); Byte b; b = (Byte)(idSize & 0xF); bool isComplex = !coder.IsSimpleCoder(); b |= (isComplex ? 0x10 : 0); b |= ((propsSize != 0) ? 0x20 : 0 ); WriteByte(b); WriteBytes(longID, idSize); if (isComplex) { WriteNumber(coder.NumInStreams); WriteNumber(coder.NumOutStreams); } if (propsSize == 0) continue; WriteNumber(propsSize); WriteBytes(coder.Props, propsSize); } } for (i = 0; i < folder.BindPairs.Size(); i++) { const CBindPair &bindPair = folder.BindPairs[i]; WriteNumber(bindPair.InIndex); WriteNumber(bindPair.OutIndex); } if (folder.PackStreams.Size() > 1) for (i = 0; i < folder.PackStreams.Size(); i++) { WriteNumber(folder.PackStreams[i]); } } void COutArchive::WriteBoolVector(const CBoolVector &boolVector) { Byte b = 0; Byte mask = 0x80; FOR_VECTOR (i, boolVector) { if (boolVector[i]) b |= mask; mask >>= 1; if (mask == 0) { WriteByte(b); mask = 0x80; b = 0; } } if (mask != 0x80) WriteByte(b); } static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) { WriteByte(id); WriteNumber(Bv_GetSizeInBytes(boolVector)); WriteBoolVector(boolVector); } void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) { unsigned numDefined = 0; unsigned i; for (i = 0; i < digests.Defs.Size(); i++) if (digests.Defs[i]) numDefined++; if (numDefined == 0) return; WriteByte(NID::kCRC); if (numDefined == digests.Defs.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(digests.Defs); } for (i = 0; i < digests.Defs.Size(); i++) if (digests.Defs[i]) WriteUInt32(digests.Vals[i]); } void COutArchive::WritePackInfo( UInt64 dataOffset, const CRecordVector &packSizes, const CUInt32DefVector &packCRCs) { if (packSizes.IsEmpty()) return; WriteByte(NID::kPackInfo); WriteNumber(dataOffset); WriteNumber(packSizes.Size()); WriteByte(NID::kSize); FOR_VECTOR (i, packSizes) WriteNumber(packSizes[i]); WriteHashDigests(packCRCs); WriteByte(NID::kEnd); } void COutArchive::WriteUnpackInfo(const CObjectVector &folders, const COutFolders &outFolders) { if (folders.IsEmpty()) return; WriteByte(NID::kUnpackInfo); WriteByte(NID::kFolder); WriteNumber(folders.Size()); { WriteByte(0); FOR_VECTOR (i, folders) WriteFolder(folders[i]); } WriteByte(NID::kCodersUnpackSize); FOR_VECTOR (i, outFolders.CoderUnpackSizes) WriteNumber(outFolders.CoderUnpackSizes[i]); WriteHashDigests(outFolders.FolderUnpackCRCs); WriteByte(NID::kEnd); } void COutArchive::WriteSubStreamsInfo(const CObjectVector &folders, const COutFolders &outFolders, const CRecordVector &unpackSizes, const CUInt32DefVector &digests) { const CRecordVector &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector; WriteByte(NID::kSubStreamsInfo); unsigned i; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) if (numUnpackStreamsInFolders[i] != 1) { WriteByte(NID::kNumUnpackStream); for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) WriteNumber(numUnpackStreamsInFolders[i]); break; } for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) if (numUnpackStreamsInFolders[i] > 1) { WriteByte(NID::kSize); CNum index = 0; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) { CNum num = numUnpackStreamsInFolders[i]; for (CNum j = 0; j < num; j++) { if (j + 1 != num) WriteNumber(unpackSizes[index]); index++; } } break; } CUInt32DefVector digests2; unsigned digestIndex = 0; for (i = 0; i < folders.Size(); i++) { unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i]; if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i)) digestIndex++; else for (unsigned j = 0; j < numSubStreams; j++, digestIndex++) { digests2.Defs.Add(digests.Defs[digestIndex]); digests2.Vals.Add(digests.Vals[digestIndex]); } } WriteHashDigests(digests2); WriteByte(NID::kEnd); } // 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) { if (!_useAlign) return; pos += (unsigned)GetPos(); pos &= (alignSize - 1); if (pos == 0) return; unsigned skip = alignSize - pos; if (skip < 2) skip += alignSize; skip -= 2; WriteByte(NID::kDummy); WriteByte((Byte)skip); for (unsigned i = 0; i < skip; i++) WriteByte(0); } void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize) { const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize); WriteByte(type); WriteNumber(dataSize); if (numDefined == v.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(v); } WriteByte(0); } void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) { unsigned numDefined = 0; unsigned i; for (i = 0; i < v.Defs.Size(); i++) if (v.Defs[i]) numDefined++; if (numDefined == 0) return; WriteAlignedBoolHeader(v.Defs, numDefined, type, 8); for (i = 0; i < v.Defs.Size(); i++) if (v.Defs[i]) WriteUInt64(v.Vals[i]); } HRESULT COutArchive::EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders) { CBufInStream *streamSpec = new CBufInStream; CMyComPtr stream = streamSpec; streamSpec->Init(data, data.Size()); outFolders.FolderUnpackCRCs.Defs.Add(true); outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); // outFolders.NumUnpackStreamsVector.Add(1); UInt64 dataSize64 = data.Size(); UInt64 unpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS stream, NULL, &dataSize64, folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL)) return S_OK; } void COutArchive::WriteHeader( const CArchiveDatabaseOut &db, // const CHeaderOptions &headerOptions, UInt64 &headerOffset) { /* bool thereIsSecure = (db.SecureBuf.Size() != 0); */ _useAlign = true; unsigned i; UInt64 packedSize = 0; for (i = 0; i < db.PackSizes.Size(); i++) packedSize += db.PackSizes[i]; headerOffset = packedSize; WriteByte(NID::kHeader); // Archive Properties if (db.Folders.Size() > 0) { WriteByte(NID::kMainStreamsInfo); WritePackInfo(0, db.PackSizes, db.PackCRCs); WriteUnpackInfo(db.Folders, (const COutFolders &)db); CRecordVector unpackSizes; CUInt32DefVector digests; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (!file.HasStream) continue; unpackSizes.Add(file.Size); digests.Defs.Add(file.CrcDefined); digests.Vals.Add(file.Crc); } WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests); WriteByte(NID::kEnd); } if (db.Files.IsEmpty()) { WriteByte(NID::kEnd); return; } WriteByte(NID::kFilesInfo); WriteNumber(db.Files.Size()); { /* ---------- Empty Streams ---------- */ CBoolVector emptyStreamVector; emptyStreamVector.ClearAndSetSize(db.Files.Size()); unsigned numEmptyStreams = 0; for (i = 0; i < db.Files.Size(); i++) if (db.Files[i].HasStream) emptyStreamVector[i] = false; else { emptyStreamVector[i] = true; numEmptyStreams++; } if (numEmptyStreams != 0) { WritePropBoolVector(NID::kEmptyStream, emptyStreamVector); CBoolVector emptyFileVector, antiVector; emptyFileVector.ClearAndSetSize(numEmptyStreams); antiVector.ClearAndSetSize(numEmptyStreams); bool thereAreEmptyFiles = false, thereAreAntiItems = false; unsigned cur = 0; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (file.HasStream) continue; emptyFileVector[cur] = !file.IsDir; if (!file.IsDir) thereAreEmptyFiles = true; bool isAnti = db.IsItemAnti(i); antiVector[cur] = isAnti; if (isAnti) thereAreAntiItems = true; cur++; } if (thereAreEmptyFiles) WritePropBoolVector(NID::kEmptyFile, emptyFileVector); if (thereAreAntiItems) WritePropBoolVector(NID::kAnti, antiVector); } } { /* ---------- Names ---------- */ unsigned numDefined = 0; size_t namesDataSize = 0; FOR_VECTOR (i, db.Files) { const UString &name = db.Names[i]; if (!name.IsEmpty()) numDefined++; namesDataSize += (name.Len() + 1) * 2; } if (numDefined > 0) { namesDataSize++; SkipAlign(2 + GetBigNumberSize(namesDataSize), 16); WriteByte(NID::kName); WriteNumber(namesDataSize); WriteByte(0); FOR_VECTOR (i, db.Files) { const UString &name = db.Names[i]; for (unsigned t = 0; t <= name.Len(); t++) { wchar_t c = name[t]; WriteByte((Byte)c); WriteByte((Byte)(c >> 8)); } } } } /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime); /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime); /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime); WriteUInt64DefVector(db.StartPos, NID::kStartPos); { /* ---------- Write Attrib ---------- */ CBoolVector boolVector; boolVector.ClearAndSetSize(db.Files.Size()); unsigned numDefined = 0; for (i = 0; i < db.Files.Size(); i++) { bool defined = db.Files[i].AttribDefined; boolVector[i] = defined; if (defined) numDefined++; } if (numDefined != 0) { WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4); for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (file.AttribDefined) WriteUInt32(file.Attrib); } } } /* { // ---------- Write IsAux ---------- unsigned numAux = 0; const CBoolVector &isAux = db.IsAux; for (i = 0; i < isAux.Size(); i++) if (isAux[i]) numAux++; if (numAux > 0) { const unsigned bvSize = Bv_GetSizeInBytes(isAux); WriteByte(NID::kIsAux); WriteNumber(bvSize); WriteBoolVector(isAux); } } { // ---------- Write Parent ---------- CBoolVector boolVector; boolVector.Reserve(db.Files.Size()); unsigned numIsDir = 0; unsigned numParentLinks = 0; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; bool defined = !file.IsAltStream; boolVector.Add(defined); if (defined) numIsDir++; if (file.Parent >= 0) numParentLinks++; } if (numParentLinks > 0) { // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4); const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector); const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1; SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4); WriteByte(NID::kParent); WriteNumber(dataSize); if (numIsDir == boolVector.Size()) WriteByte(1); else { WriteByte(0); WriteBoolVector(boolVector); } for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; // if (file.Parent >= 0) WriteUInt32(file.Parent); } } } if (thereIsSecure) { UInt64 secureDataSize = 1 + 4 + db.SecureBuf.Size() + db.SecureSizes.Size() * 4; // secureDataSize += db.SecureIDs.Size() * 4; for (i = 0; i < db.SecureIDs.Size(); i++) secureDataSize += GetBigNumberSize(db.SecureIDs[i]); SkipAlign(2 + GetBigNumberSize(secureDataSize), 4); WriteByte(NID::kNtSecure); WriteNumber(secureDataSize); WriteByte(0); WriteUInt32(db.SecureSizes.Size()); for (i = 0; i < db.SecureSizes.Size(); i++) WriteUInt32(db.SecureSizes[i]); WriteBytes(db.SecureBuf, db.SecureBuf.Size()); for (i = 0; i < db.SecureIDs.Size(); i++) { WriteNumber(db.SecureIDs[i]); // WriteUInt32(db.SecureIDs[i]); } } */ WriteByte(NID::kEnd); // for files WriteByte(NID::kEnd); // for headers } HRESULT COutArchive::WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions) { if (!db.CheckNumFiles()) return E_FAIL; UInt64 headerOffset; UInt32 headerCRC; UInt64 headerSize; if (db.IsEmpty()) { headerSize = 0; headerOffset = 0; headerCRC = CrcCalc(0, 0); } else { bool encodeHeaders = false; if (options != 0) if (options->IsEmpty()) options = 0; if (options != 0) if (options->PasswordIsDefined || headerOptions.CompressMainHeader) encodeHeaders = true; _outByte.SetStream(SeqStream); _outByte.Init(); _crc = CRC_INIT_VAL; _countMode = encodeHeaders; _writeToStream = true; _countSize = 0; WriteHeader(db, /* headerOptions, */ headerOffset); if (encodeHeaders) { CByteBuffer buf(_countSize); _outByte2.Init((Byte *)buf, _countSize); _countMode = false; _writeToStream = false; WriteHeader(db, /* headerOptions, */ headerOffset); if (_countSize != _outByte2.GetPos()) return E_FAIL; CCompressionMethodMode encryptOptions; encryptOptions.PasswordIsDefined = options->PasswordIsDefined; encryptOptions.Password = options->Password; CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); CRecordVector packSizes; CObjectVector folders; COutFolders outFolders; RINOK(EncodeStream( EXTERNAL_CODECS_LOC_VARS encoder, buf, packSizes, folders, outFolders)); _writeToStream = true; if (folders.Size() == 0) throw 1; WriteID(NID::kEncodedHeader); WritePackInfo(headerOffset, packSizes, CUInt32DefVector()); WriteUnpackInfo(folders, outFolders); WriteByte(NID::kEnd); FOR_VECTOR (i, packSizes) headerOffset += packSizes[i]; } RINOK(_outByte.Flush()); headerCRC = CRC_GET_DIGEST(_crc); headerSize = _outByte.GetProcessedSize(); } #ifdef _7Z_VOL if (_endMarker) { CFinishHeader h; h.NextHeaderSize = headerSize; h.NextHeaderCRC = headerCRC; h.NextHeaderOffset = UInt64(0) - (headerSize + 4 + kFinishHeaderSize); h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; h.AdditionalStartBlockSize = 0; RINOK(WriteFinishHeader(h)); return WriteFinishSignature(); } else #endif { CStartHeader h; h.NextHeaderSize = headerSize; h.NextHeaderCRC = headerCRC; h.NextHeaderOffset = headerOffset; RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL)); return WriteStartHeader(h); } } void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) { while (index >= Defs.Size()) Defs.Add(false); Defs[index] = defined; if (!defined) return; while (index >= Vals.Size()) Vals.Add(0); Vals[index] = value; } void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name) { unsigned index = Files.Size(); CTime.SetItem(index, file2.CTimeDefined, file2.CTime); ATime.SetItem(index, file2.ATimeDefined, file2.ATime); MTime.SetItem(index, file2.MTimeDefined, file2.MTime); StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); SetItem_Anti(index, file2.IsAnti); // SetItem_Aux(index, file2.IsAux); Names.Add(name); Files.Add(file); } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h0100777000000000000000000001560213761647206022747 0ustar00// 7zOut.h #ifndef __7Z_OUT_H #define __7Z_OUT_H #include "7zCompressionMode.h" #include "7zEncode.h" #include "7zHeader.h" #include "7zItem.h" #include "../../Common/OutBuffer.h" #include "../../Common/StreamUtils.h" namespace NArchive { namespace N7z { class CWriteBufferLoc { Byte *_data; size_t _size; size_t _pos; public: CWriteBufferLoc(): _size(0), _pos(0) {} void Init(Byte *data, size_t size) { _data = data; _size = size; _pos = 0; } void WriteBytes(const void *data, size_t size) { if (size > _size - _pos) throw 1; memcpy(_data + _pos, data, size); _pos += size; } void WriteByte(Byte b) { if (_size == _pos) throw 1; _data[_pos++] = b; } size_t GetPos() const { return _pos; } }; struct CHeaderOptions { bool CompressMainHeader; /* bool WriteCTime; bool WriteATime; bool WriteMTime; */ CHeaderOptions(): CompressMainHeader(true) /* , WriteCTime(false) , WriteATime(false) , WriteMTime(true) */ {} }; struct CFileItem2 { UInt64 CTime; UInt64 ATime; UInt64 MTime; UInt64 StartPos; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; bool StartPosDefined; bool IsAnti; // bool IsAux; void Init() { CTimeDefined = false; ATimeDefined = false; MTimeDefined = false; StartPosDefined = false; IsAnti = false; // IsAux = false; } }; struct COutFolders { CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. CRecordVector NumUnpackStreamsVector; CRecordVector CoderUnpackSizes; // including unpack sizes of bind coders void OutFoldersClear() { FolderUnpackCRCs.Clear(); NumUnpackStreamsVector.Clear(); CoderUnpackSizes.Clear(); } void OutFoldersReserveDown() { FolderUnpackCRCs.ReserveDown(); NumUnpackStreamsVector.ReserveDown(); CoderUnpackSizes.ReserveDown(); } }; struct CArchiveDatabaseOut: public COutFolders { CRecordVector PackSizes; CUInt32DefVector PackCRCs; CObjectVector Folders; CRecordVector Files; UStringVector Names; CUInt64DefVector CTime; CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; CRecordVector IsAnti; /* CRecordVector IsAux; CByteBuffer SecureBuf; CRecordVector SecureSizes; CRecordVector SecureIDs; void ClearSecure() { SecureBuf.Free(); SecureSizes.Clear(); SecureIDs.Clear(); } */ void Clear() { OutFoldersClear(); PackSizes.Clear(); PackCRCs.Clear(); Folders.Clear(); Files.Clear(); Names.Clear(); CTime.Clear(); ATime.Clear(); MTime.Clear(); StartPos.Clear(); IsAnti.Clear(); /* IsAux.Clear(); ClearSecure(); */ } void ReserveDown() { OutFoldersReserveDown(); PackSizes.ReserveDown(); PackCRCs.ReserveDown(); Folders.ReserveDown(); Files.ReserveDown(); Names.ReserveDown(); CTime.ReserveDown(); ATime.ReserveDown(); MTime.ReserveDown(); StartPos.ReserveDown(); IsAnti.ReserveDown(); /* IsAux.ReserveDown(); */ } bool IsEmpty() const { return ( PackSizes.IsEmpty() && NumUnpackStreamsVector.IsEmpty() && Folders.IsEmpty() && Files.IsEmpty()); } bool CheckNumFiles() const { unsigned size = Files.Size(); return ( CTime.CheckSize(size) && ATime.CheckSize(size) && MTime.CheckSize(size) && StartPos.CheckSize(size) && (size == IsAnti.Size() || IsAnti.Size() == 0)); } bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } void SetItem_Anti(unsigned index, bool isAnti) { while (index >= IsAnti.Size()) IsAnti.Add(false); IsAnti[index] = isAnti; } /* void SetItem_Aux(unsigned index, bool isAux) { while (index >= IsAux.Size()) IsAux.Add(false); IsAux[index] = isAux; } */ void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); }; class COutArchive { UInt64 _prefixHeaderPos; HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); } UInt64 GetPos() const; void WriteBytes(const void *data, size_t size); void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); } void WriteByte(Byte b); void WriteUInt32(UInt32 value); void WriteUInt64(UInt64 value); void WriteNumber(UInt64 value); void WriteID(UInt64 value) { WriteNumber(value); } void WriteFolder(const CFolder &folder); HRESULT WriteFileHeader(const CFileItem &itemInfo); void WriteBoolVector(const CBoolVector &boolVector); void WritePropBoolVector(Byte id, const CBoolVector &boolVector); void WriteHashDigests(const CUInt32DefVector &digests); void WritePackInfo( UInt64 dataOffset, const CRecordVector &packSizes, const CUInt32DefVector &packCRCs); void WriteUnpackInfo( const CObjectVector &folders, const COutFolders &outFolders); void WriteSubStreamsInfo( const CObjectVector &folders, const COutFolders &outFolders, const CRecordVector &unpackSizes, const CUInt32DefVector &digests); void SkipAlign(unsigned pos, unsigned alignSize); void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize); void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type); HRESULT EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders); void WriteHeader( const CArchiveDatabaseOut &db, // const CHeaderOptions &headerOptions, UInt64 &headerOffset); bool _countMode; bool _writeToStream; size_t _countSize; UInt32 _crc; COutBuffer _outByte; CWriteBufferLoc _outByte2; #ifdef _7Z_VOL bool _endMarker; #endif bool _useAlign; HRESULT WriteSignature(); #ifdef _7Z_VOL HRESULT WriteFinishSignature(); #endif HRESULT WriteStartHeader(const CStartHeader &h); #ifdef _7Z_VOL HRESULT WriteFinishHeader(const CFinishHeader &h); #endif CMyComPtr Stream; public: COutArchive() { _outByte.Create(1 << 16); } CMyComPtr SeqStream; HRESULT Create(ISequentialOutStream *stream, bool endMarker); void Close(); HRESULT SkipPrefixArchiveHeader(); HRESULT WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions); #ifdef _7Z_VOL static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false); static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false); #endif }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp0100777000000000000000000000753613761647206024676 0ustar00// 7zProperties.cpp #include "StdAfx.h" #include "7zProperties.h" #include "7zHeader.h" #include "7zHandler.h" // #define _MULTI_PACK namespace NArchive { namespace N7z { struct CPropMap { UInt64 FilePropID; STATPROPSTG StatPROPSTG; }; static const CPropMap kPropMap[] = { { NID::kName, { NULL, kpidPath, VT_BSTR } }, { NID::kSize, { NULL, kpidSize, VT_UI8 } }, { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } }, #ifdef _MULTI_PACK { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } }, { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } }, { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } }, { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } }, { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } }, #endif { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } }, { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } }, { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, // { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } }, { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } } #ifndef _SFX , { 97, { NULL,kpidEncrypted, VT_BOOL } }, { 98, { NULL,kpidMethod, VT_BSTR } }, { 99, { NULL,kpidBlock, VT_UI4 } } #endif }; static int FindPropInMap(UInt64 filePropID) { for (int i = 0; i < ARRAY_SIZE(kPropMap); i++) if (kPropMap[i].FilePropID == filePropID) return i; return -1; } static void CopyOneItem(CRecordVector &src, CRecordVector &dest, UInt32 item) { FOR_VECTOR (i, src) if (src[i] == item) { dest.Add(item); src.Delete(i); return; } } static void RemoveOneItem(CRecordVector &src, UInt32 item) { FOR_VECTOR (i, src) if (src[i] == item) { src.Delete(i); return; } } static void InsertToHead(CRecordVector &dest, UInt32 item) { FOR_VECTOR (i, dest) if (dest[i] == item) { dest.Delete(i); break; } dest.Insert(0, item); } #define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id); void CHandler::FillPopIDs() { _fileInfoPopIDs.Clear(); #ifdef _7Z_VOL if (_volumes.Size() < 1) return; const CVolume &volume = _volumes.Front(); const CArchiveDatabaseEx &_db = volume.Database; #endif CRecordVector fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs; RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); /* RemoveOneItem(fileInfoPopIDs, NID::kParent); RemoveOneItem(fileInfoPopIDs, NID::kNtSecure); */ COPY_ONE_ITEM(kName); COPY_ONE_ITEM(kAnti); COPY_ONE_ITEM(kSize); COPY_ONE_ITEM(kPackInfo); COPY_ONE_ITEM(kCTime); COPY_ONE_ITEM(kMTime); COPY_ONE_ITEM(kATime); COPY_ONE_ITEM(kWinAttrib); COPY_ONE_ITEM(kCRC); COPY_ONE_ITEM(kComment); _fileInfoPopIDs += fileInfoPopIDs; #ifndef _SFX _fileInfoPopIDs.Add(97); _fileInfoPopIDs.Add(98); _fileInfoPopIDs.Add(99); #endif #ifdef _MULTI_PACK _fileInfoPopIDs.Add(100); _fileInfoPopIDs.Add(101); _fileInfoPopIDs.Add(102); _fileInfoPopIDs.Add(103); _fileInfoPopIDs.Add(104); #endif #ifndef _SFX InsertToHead(_fileInfoPopIDs, NID::kMTime); InsertToHead(_fileInfoPopIDs, NID::kPackInfo); InsertToHead(_fileInfoPopIDs, NID::kSize); InsertToHead(_fileInfoPopIDs, NID::kName); #endif } STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { *numProps = _fileInfoPopIDs.Size(); return S_OK; } STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) { if ((int)index >= _fileInfoPopIDs.Size()) return E_INVALIDARG; int indexInMap = FindPropInMap(_fileInfoPopIDs[index]); if (indexInMap == -1) return E_INVALIDARG; const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG; *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h0100777000000000000000000000041713761647206024332 0ustar00// 7zProperties.h #ifndef __7Z_PROPERTIES_H #define __7Z_PROPERTIES_H #include "../../PropID.h" namespace NArchive { namespace N7z { enum { kpidPackedSize0 = kpidUserDefined, kpidPackedSize1, kpidPackedSize2, kpidPackedSize3, kpidPackedSize4 }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp0100777000000000000000000000057613761647206024323 0ustar00// 7zRegister.cpp #include "StdAfx.h" #include "../../Common/RegisterArc.h" #include "7zHandler.h" namespace NArchive { namespace N7z { IMP_CreateArcIn IMP_CreateArcOut static CArcInfo g_ArcInfo = { "7z", "7z", 0, 7, 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}, 0, NArcInfoFlags::kFindSignature, REF_CreateArc_Pair }; REGISTER_ARC_DEC_SIG(7z) // REGISTER_ARC(7z) }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp0100777000000000000000000000110713761647206024574 0ustar00// 7zSpecStream.cpp #include "StdAfx.h" #include "7zSpecStream.h" STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize; HRESULT result = _stream->Read(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return result; } STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value) { if (!_getSubStreamSize) return E_NOTIMPL; return _getSubStreamSize->GetSubStreamSize(subStream, value); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h0100777000000000000000000000151013761647206024237 0ustar00// 7zSpecStream.h #ifndef __7Z_SPEC_STREAM_H #define __7Z_SPEC_STREAM_H #include "../../IStream.h" #include "../../ICoder.h" #include "../../../Common/MyCom.h" class CSequentialInStreamSizeCount2: public ISequentialInStream, public ICompressGetSubStreamSize, public CMyUnknownImp { CMyComPtr _stream; CMyComPtr _getSubStreamSize; UInt64 _size; public: void Init(ISequentialInStream *stream) { _stream = stream; _getSubStreamSize = 0; _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); _size = 0; } UInt64 GetSize() const { return _size; } MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp0100777000000000000000000010753013761647206023757 0ustar00// 7zUpdate.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Compress/CopyCoder.h" #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" #include "7zDecode.h" #include "7zEncode.h" #include "7zFolderInStream.h" #include "7zHandler.h" #include "7zOut.h" #include "7zUpdate.h" namespace NArchive { namespace N7z { #ifdef MY_CPU_X86_OR_AMD64 #define USE_86_FILTER #endif static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, UInt64 position, UInt64 size, ICompressProgressInfo *progress) { RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0)); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStreamLimited(streamSpec); streamSpec->SetStream(inStream); streamSpec->Init(size); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL); } static int GetReverseSlashPos(const UString &name) { int slashPos = name.ReverseFind(L'/'); #ifdef _WIN32 int slash1Pos = name.ReverseFind(L'\\'); slashPos = MyMax(slashPos, slash1Pos); #endif return slashPos; } int CUpdateItem::GetExtensionPos() const { int slashPos = GetReverseSlashPos(Name); int dotPos = Name.ReverseFind(L'.'); if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) return Name.Len(); return dotPos + 1; } UString CUpdateItem::GetExtension() const { return Name.Ptr(GetExtensionPos()); } #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } #define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) /* static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) { size_t c1 = a1.GetCapacity(); size_t c2 = a2.GetCapacity(); RINOZ_COMP(c1, c2); for (size_t i = 0; i < c1; i++) RINOZ_COMP(a1[i], a2[i]); return 0; } static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) { RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); RINOZ_COMP(c1.MethodID, c2.MethodID); return CompareBuffers(c1.Props, c2.Props); } static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2) { RINOZ_COMP(b1.InIndex, b2.InIndex); return MyCompare(b1.OutIndex, b2.OutIndex); } static int CompareFolders(const CFolder &f1, const CFolder &f2) { int s1 = f1.Coders.Size(); int s2 = f2.Coders.Size(); RINOZ_COMP(s1, s2); int i; for (i = 0; i < s1; i++) RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); s1 = f1.BindPairs.Size(); s2 = f2.BindPairs.Size(); RINOZ_COMP(s1, s2); for (i = 0; i < s1; i++) RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i])); return 0; } */ /* static int CompareFiles(const CFileItem &f1, const CFileItem &f2) { return CompareFileNames(f1.Name, f2.Name); } */ struct CFolderRepack { int FolderIndex; int Group; CNum NumCopyFiles; }; static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */) { RINOZ_COMP(p1->Group, p2->Group); int i1 = p1->FolderIndex; int i2 = p2->FolderIndex; /* // In that version we don't want to parse folders here, so we don't compare folders // probably it must be improved in future const CDbEx &db = *(const CDbEx *)param; RINOZ(CompareFolders( db.Folders[i1], db.Folders[i2])); */ return MyCompare(i1, i2); /* RINOZ_COMP( db.NumUnpackStreamsVector[i1], db.NumUnpackStreamsVector[i2]); if (db.NumUnpackStreamsVector[i1] == 0) return 0; return CompareFiles( db.Files[db.FolderStartFileIndex[i1]], db.Files[db.FolderStartFileIndex[i2]]); */ } /* we sort empty files and dirs in such order: - Dir.NonAnti (name sorted) - File.NonAnti (name sorted) - File.Anti (name sorted) - Dir.Anti (reverse name sorted) */ static int CompareEmptyItems(const int *p1, const int *p2, void *param) { const CObjectVector &updateItems = *(const CObjectVector *)param; const CUpdateItem &u1 = updateItems[*p1]; const CUpdateItem &u2 = updateItems[*p2]; // NonAnti < Anti if (u1.IsAnti != u2.IsAnti) return (u1.IsAnti ? 1 : -1); if (u1.IsDir != u2.IsDir) { // Dir.NonAnti < File < Dir.Anti if (u1.IsDir) return (u1.IsAnti ? 1 : -1); return (u2.IsAnti ? -1 : 1); } int n = CompareFileNames(u1.Name, u2.Name); return (u1.IsDir && u1.IsAnti) ? -n : n; } static const char *g_Exts = " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" " zip jar ear war msi" " 3gp avi mov mpeg mpg mpe wmv" " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" " swf " " chm hxi hxs" " gif jpeg jpg jp2 png tiff bmp ico psd psp" " awg ps eps cgm dxf svg vrml wmf emf ai md" " cad dwg pps key sxi" " max 3ds" " iso bin nrg mdf img pdi tar cpio xpi" " vfd vhd vud vmc vsv" " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" " f77 f f90 f95" " asm sql manifest dep " " mak clw csproj vcproj sln dsp dsw " " class " " bat cmd" " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs" " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" " abw afp cwk lwp wpd wps wpt wrf wri" " abf afm bdf fon mgf otf pcf pfa snf ttf" " dbf mdb nsf ntf wdb db fdb gdb" " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " " pdb pch idb ncb opt"; static int GetExtIndex(const char *ext) { int extIndex = 1; const char *p = g_Exts; for (;;) { char c = *p++; if (c == 0) return extIndex; if (c == ' ') continue; int pos = 0; for (;;) { char c2 = ext[pos++]; if (c2 == 0 && (c == 0 || c == ' ')) return extIndex; if (c != c2) break; c = *p++; } extIndex++; for (;;) { if (c == 0) return extIndex; if (c == ' ') break; c = *p++; } } } struct CRefItem { const CUpdateItem *UpdateItem; UInt32 Index; UInt32 ExtensionPos; UInt32 NamePos; unsigned ExtensionIndex; CRefItem() {}; CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): UpdateItem(&ui), Index(index), ExtensionPos(0), NamePos(0), ExtensionIndex(0) { if (sortByType) { int slashPos = GetReverseSlashPos(ui.Name); NamePos = slashPos + 1; int dotPos = ui.Name.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos) ExtensionPos = ui.Name.Len(); else { ExtensionPos = dotPos + 1; if (ExtensionPos != ui.Name.Len()) { AString s; for (unsigned pos = ExtensionPos;; pos++) { wchar_t c = ui.Name[pos]; if (c >= 0x80) break; if (c == 0) { ExtensionIndex = GetExtIndex(s); break; } s += (char)MyCharLower_Ascii((char)c); } } } } } }; struct CSortParam { // const CObjectVector *TreeFolders; bool SortByType; }; /* we sort files in such order: - Dir.NonAnti (name sorted) - alt streams - Dirs - Dir.Anti (reverse name sorted) */ static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) { const CRefItem &a1 = *p1; const CRefItem &a2 = *p2; const CUpdateItem &u1 = *a1.UpdateItem; const CUpdateItem &u2 = *a2.UpdateItem; /* if (u1.IsAltStream != u2.IsAltStream) return u1.IsAltStream ? 1 : -1; */ // Actually there are no dirs that time. They were stored in other steps // So that code is unused? if (u1.IsDir != u2.IsDir) return u1.IsDir ? 1 : -1; if (u1.IsDir) { if (u1.IsAnti != u2.IsAnti) return (u1.IsAnti ? 1 : -1); int n = CompareFileNames(u1.Name, u2.Name); return -n; } // bool sortByType = *(bool *)param; const CSortParam *sortParam = (const CSortParam *)param; bool sortByType = sortParam->SortByType; if (sortByType) { RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex); RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))); RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))); if (!u1.MTimeDefined && u2.MTimeDefined) return 1; if (u1.MTimeDefined && !u2.MTimeDefined) return -1; if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime); RINOZ_COMP(u1.Size, u2.Size); } /* int par1 = a1.UpdateItem->ParentFolderIndex; int par2 = a2.UpdateItem->ParentFolderIndex; const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; if (b1 < b2) { if (e1 <= b2) return -1; // p2 in p1 int par = par2; for (;;) { const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; par = tf.Parent; if (par == par1) { RINOZ(CompareFileNames(u1.Name, tf.Name)); break; } } } else if (b2 < b1) { if (e2 <= b1) return 1; // p1 in p2 int par = par1; for (;;) { const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; par = tf.Parent; if (par == par2) { RINOZ(CompareFileNames(tf.Name, u2.Name)); break; } } } */ // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); RINOK(CompareFileNames(u1.Name, u2.Name)); RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient); RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive); return 0; } struct CSolidGroup { CRecordVector Indices; }; static const wchar_t *g_ExeExts[] = { L"dll" , L"exe" , L"ocx" , L"sfx" , L"sys" }; static bool IsExeExt(const wchar_t *ext) { for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++) if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0) return true; return false; } static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m) { m.Id = methodID; m.NumInStreams = numInStreams; m.NumOutStreams = 1; } static void AddBcj2Methods(CCompressionMethodMode &mode) { CMethodFull m; GetMethodFull(k_LZMA, 1, m); m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); m.AddProp32(NCoderPropID::kNumFastBytes, 128); m.AddProp32(NCoderPropID::kNumThreads, 1); m.AddProp32(NCoderPropID::kLitPosBits, 2); m.AddProp32(NCoderPropID::kLitContextBits, 0); // m.AddPropString(NCoderPropID::kMatchFinder, L"BT2"); mode.Methods.Add(m); mode.Methods.Add(m); CBind bind; bind.OutCoder = 0; bind.InStream = 0; bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); bind.InCoder = 2; bind.OutStream = 1; mode.Binds.Add(bind); bind.InCoder = 3; bind.OutStream = 2; mode.Binds.Add(bind); } static void MakeExeMethod(CCompressionMethodMode &mode, bool useFilters, bool addFilter, bool bcj2Filter) { if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2) return; if (mode.Methods.Size() == 2) { if (mode.Methods[0].Id == k_BCJ2) AddBcj2Methods(mode); return; } if (!addFilter) return; bcj2Filter = bcj2Filter; #ifdef USE_86_FILTER if (bcj2Filter) { CMethodFull m; GetMethodFull(k_BCJ2, 4, m); mode.Methods.Insert(0, m); AddBcj2Methods(mode); } else { CMethodFull m; GetMethodFull(k_BCJ, 1, m); mode.Methods.Insert(0, m); CBind bind; bind.OutCoder = 0; bind.InStream = 0; bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); } #endif } static void FromUpdateItemToFileItem(const CUpdateItem &ui, CFileItem &file, CFileItem2 &file2) { if (ui.AttribDefined) file.SetAttrib(ui.Attrib); file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; file2.IsAnti = ui.IsAnti; // file2.IsAux = false; file2.StartPosDefined = false; file.Size = ui.Size; file.IsDir = ui.IsDir; file.HasStream = ui.HasStream(); // file.IsAltStream = ui.IsAltStream; } class CFolderOutStream2: public ISequentialOutStream, public CMyUnknownImp { COutStreamWithCRC *_crcStreamSpec; CMyComPtr _crcStream; const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr _outStream; UInt32 _startIndex; unsigned _currentIndex; bool _fileIsOpen; UInt64 _rem; void OpenFile(); void CloseFile(); HRESULT CloseFileAndSetResult(); HRESULT ProcessEmptyFiles(); public: MY_UNKNOWN_IMP CFolderOutStream2() { _crcStreamSpec = new COutStreamWithCRC; _crcStream = _crcStreamSpec; } HRESULT Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream); void ReleaseOutStream(); HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream) { _db = db; _startIndex = startIndex; _extractStatuses = extractStatuses; _outStream = outStream; _currentIndex = 0; _fileIsOpen = false; return ProcessEmptyFiles(); } void CFolderOutStream2::ReleaseOutStream() { _outStream.Release(); _crcStreamSpec->ReleaseStream(); } void CFolderOutStream2::OpenFile() { _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL); _crcStreamSpec->Init(true); _fileIsOpen = true; _rem = _db->Files[_startIndex + _currentIndex].Size; } void CFolderOutStream2::CloseFile() { _crcStreamSpec->ReleaseStream(); _fileIsOpen = false; _currentIndex++; } HRESULT CFolderOutStream2::CloseFileAndSetResult() { const CFileItem &file = _db->Files[_startIndex + _currentIndex]; CloseFile(); return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE; } HRESULT CFolderOutStream2::ProcessEmptyFiles() { while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) { OpenFile(); RINOK(CloseFileAndSetResult()); } return S_OK; } STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size != 0) { if (_fileIsOpen) { UInt32 cur = size < _rem ? size : (UInt32)_rem; RINOK(_crcStream->Write(data, cur, &cur)); if (cur == 0) break; data = (const Byte *)data + cur; size -= cur; _rem -= cur; if (processedSize != NULL) *processedSize += cur; if (_rem == 0) { RINOK(CloseFileAndSetResult()); RINOK(ProcessEmptyFiles()); continue; } } else { RINOK(ProcessEmptyFiles()); if (_currentIndex == _extractStatuses->Size()) { // we don't support partial extracting return E_FAIL; } OpenFile(); } } return S_OK; } class CThreadDecoder: public CVirtThread { public: HRESULT Result; CMyComPtr InStream; CFolderOutStream2 *FosSpec; CMyComPtr Fos; UInt64 StartPos; const CFolders *Folders; int FolderIndex; #ifndef _NO_CRYPTO CMyComPtr getTextPassword; #endif DECL_EXTERNAL_CODECS_LOC_VARS2; CDecoder Decoder; #ifndef _7ZIP_ST bool MtMode; UInt32 NumThreads; #endif CThreadDecoder(): Decoder(true) { #ifndef _7ZIP_ST MtMode = false; NumThreads = 1; #endif FosSpec = new CFolderOutStream2; Fos = FosSpec; Result = E_FAIL; } ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); } virtual void Execute(); }; void CThreadDecoder::Execute() { try { #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; #endif Result = Decoder.Decode( EXTERNAL_CODECS_LOC_VARS InStream, StartPos, *Folders, FolderIndex, Fos, NULL _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , MtMode, NumThreads #endif ); } catch(...) { Result = E_FAIL; } if (Result == S_OK) Result = FosSpec->CheckFinishedState(); FosSpec->ReleaseOutStream(); } bool static Is86FilteredFolder(const CFolder &f) { FOR_VECTOR(i, f.Coders) { CMethodId m = f.Coders[i].MethodID; if (m == k_BCJ || m == k_BCJ2) return true; } return false; } #ifndef _NO_CRYPTO class CCryptoGetTextPassword: public ICryptoGetTextPassword, public CMyUnknownImp { public: UString Password; MY_UNKNOWN_IMP STDMETHOD(CryptoGetTextPassword)(BSTR *password); }; STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password) { return StringToBstr(Password, password); } #endif static const int kNumGroupsMax = 4; static bool Is86Group(int group) { return (group & 1) != 0; } static bool IsEncryptedGroup(int group) { return (group & 2) != 0; } static int GetGroupIndex(bool encrypted, int bcjFiltered) { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); } static void GetFile(const CDatabase &inDb, int index, CFileItem &file, CFileItem2 &file2) { file = inDb.Files[index]; file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); file2.IsAnti = inDb.IsItemAnti(index); // file2.IsAux = inDb.IsItemAux(index); } HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, const CDbEx *db, const CObjectVector &updateItems, // const CObjectVector &treeFolders, // const CUniqBlocks &secureBlocks, COutArchive &archive, CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getDecoderPassword #endif ) { UInt64 numSolidFiles = options.NumSolidFiles; if (numSolidFiles == 0) numSolidFiles = 1; // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); /* CMyComPtr outStream; RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); if (!outStream) return E_NOTIMPL; */ UInt64 startBlockSize = db != 0 ? db->ArcInfo.StartPosition: 0; if (startBlockSize > 0 && !options.RemoveSfxBlock) { RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL)); } CIntArr fileIndexToUpdateIndexMap; CRecordVector folderRefs; UInt64 complexity = 0; UInt64 inSizeForReduce2 = 0; bool needEncryptedRepack = false; if (db != 0) { fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); unsigned i; for (i = 0; i < db->Files.Size(); i++) fileIndexToUpdateIndexMap[i] = -1; for (i = 0; i < updateItems.Size(); i++) { int index = updateItems[i].IndexInArchive; if (index != -1) fileIndexToUpdateIndexMap[index] = i; } for (i = 0; i < (int)db->NumFolders; i++) { CNum indexInFolder = 0; CNum numCopyItems = 0; CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; UInt64 repackSize = 0; for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) { const CFileItem &file = db->Files[fi]; if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0 && !updateItems[updateIndex].NewData) { numCopyItems++; repackSize += file.Size; } } } if (numCopyItems == 0) continue; CFolderRepack rep; rep.FolderIndex = i; rep.NumCopyFiles = numCopyItems; CFolder f; db->ParseFolderInfo(i, f); bool isEncrypted = f.IsEncrypted(); rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f)); folderRefs.Add(rep); if (numCopyItems == numUnpackStreams) complexity += db->GetFolderFullPackSize(i); else { complexity += repackSize; if (repackSize > inSizeForReduce2) inSizeForReduce2 = repackSize; if (isEncrypted) needEncryptedRepack = true; } } folderRefs.Sort(CompareFolderRepacks, (void *)db); } UInt64 inSizeForReduce = 0; unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { complexity += ui.Size; if (numSolidFiles != 1) inSizeForReduce += ui.Size; else if (ui.Size > inSizeForReduce) inSizeForReduce = ui.Size; } } if (inSizeForReduce2 > inSizeForReduce) inSizeForReduce = inSizeForReduce2; RINOK(updateCallback->SetTotal(complexity)); CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(updateCallback, true); CStreamBinder sb; RINOK(sb.CreateEvents()); CThreadDecoder threadDecoder; if (!folderRefs.IsEmpty()) { #ifdef EXTERNAL_CODECS threadDecoder.__externalCodecs = __externalCodecs; #endif RINOK(threadDecoder.Create()); } CObjectVector groups; for (i = 0; i < kNumGroupsMax; i++) groups.AddNew(); { // ---------- Split files to groups ---------- bool useFilters = options.UseFilters; const CCompressionMethodMode &method = *options.Method; if (method.Methods.Size() != 1 || method.Binds.Size() != 0) useFilters = false; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (!ui.NewData || !ui.HasStream()) continue; bool filteredGroup = false; if (useFilters) { int dotPos = ui.Name.ReverseFind(L'.'); if (dotPos >= 0) filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1)); } groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i); } } #ifndef _NO_CRYPTO CCryptoGetTextPassword *getPasswordSpec = NULL; if (needEncryptedRepack) { getPasswordSpec = new CCryptoGetTextPassword; threadDecoder.getTextPassword = getPasswordSpec; if (options.Method->PasswordIsDefined) getPasswordSpec->Password = options.Method->Password; else { if (!getDecoderPassword) return E_NOTIMPL; CMyComBSTR password; RINOK(getDecoderPassword->CryptoGetTextPassword(&password)); if ((BSTR)password) getPasswordSpec->Password = password; } } #endif // ---------- Compress ---------- RINOK(archive.Create(seqOutStream, false)); RINOK(archive.SkipPrefixArchiveHeader()); /* CIntVector treeFolderToArcIndex; treeFolderToArcIndex.Reserve(treeFolders.Size()); for (i = 0; i < treeFolders.Size(); i++) treeFolderToArcIndex.Add(-1); // ---------- Write Tree (only AUX dirs) ---------- for (i = 1; i < treeFolders.Size(); i++) { const CTreeFolder &treeFolder = treeFolders[i]; CFileItem file; CFileItem2 file2; file2.Init(); int secureID = 0; if (treeFolder.UpdateItemIndex < 0) { // we can store virtual dir item wuthout attrib, but we want all items have attrib. file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); file2.IsAux = true; } else { const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; // if item is not dir, then it's parent for alt streams. // we will write such items later if (!ui.IsDir) continue; secureID = ui.SecureIndex; if (ui.NewProps) FromUpdateItemToFileItem(ui, file, file2); else GetFile(*db, ui.IndexInArchive, file, file2); } file.Size = 0; file.HasStream = false; file.IsDir = true; file.Parent = treeFolder.Parent; treeFolderToArcIndex[i] = newDatabase.Files.Size(); newDatabase.AddFile(file, file2, treeFolder.Name); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(secureID); } */ { /* ---------- Write non-AUX dirs and Empty files ---------- */ CRecordVector emptyRefs; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { if (ui.HasStream()) continue; } else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream) continue; /* if (ui.TreeFolderIndex >= 0) continue; */ emptyRefs.Add(i); } emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); for (i = 0; i < emptyRefs.Size(); i++) { const CUpdateItem &ui = updateItems[emptyRefs[i]]; CFileItem file; CFileItem2 file2; UString name; if (ui.NewProps) { FromUpdateItemToFileItem(ui, file, file2); name = ui.Name; } else { GetFile(*db, ui.IndexInArchive, file, file2); db->GetPath(ui.IndexInArchive, name); } /* if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); file.Parent = ui.ParentFolderIndex; */ newDatabase.AddFile(file, file2, name); } } unsigned folderRefIndex = 0; lps->ProgressOffset = 0; for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++) { const CSolidGroup &group = groups[groupIndex]; CCompressionMethodMode method = *options.Method; MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter); if (IsEncryptedGroup(groupIndex)) { if (!method.PasswordIsDefined) { #ifndef _NO_CRYPTO if (getPasswordSpec) method.Password = getPasswordSpec->Password; #endif method.PasswordIsDefined = true; } } else { method.PasswordIsDefined = false; method.Password.Empty(); } CEncoder encoder(method); for (; folderRefIndex < folderRefs.Size(); folderRefIndex++) { const CFolderRepack &rep = folderRefs[folderRefIndex]; if (rep.Group != groupIndex) break; int folderIndex = rep.FolderIndex; if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex]) { UInt64 packSize = db->GetFolderFullPackSize(folderIndex); RINOK(WriteRange(inStream, archive.SeqStream, db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); lps->ProgressOffset += packSize; CFolder &folder = newDatabase.Folders.AddNew(); db->ParseFolderInfo(folderIndex, folder); CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; for (unsigned j = 0; j < folder.PackStreams.Size(); j++) { newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); } UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex]; UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; for (; indexStart < indexEnd; indexStart++) newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]); } else { CBoolVector extractStatuses; CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { bool needExtract = false; if (db->Files[fi].HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0 && !updateItems[updateIndex].NewData) needExtract = true; } extractStatuses.Add(needExtract); } unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curUnpackSize; { CMyComPtr sbInStream; { CMyComPtr sbOutStream; sb.CreateStreams(&sbInStream, &sbOutStream); sb.ReInit(); RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); } threadDecoder.InStream = inStream; threadDecoder.Folders = (const CFolders *)db; threadDecoder.FolderIndex = folderIndex; threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); threadDecoder.Start(); RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS sbInStream, NULL, &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); threadDecoder.WaitExecuteFinish(); } RINOK(threadDecoder.Result); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; lps->InSize += curUnpackSize; } newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { CFileItem file; CFileItem2 file2; GetFile(*db, fi, file, file2); UString name; db->GetPath(fi, name); if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0) { const CUpdateItem &ui = updateItems[updateIndex]; if (ui.NewData) continue; if (ui.NewProps) { CFileItem uf; FromUpdateItemToFileItem(ui, uf, file2); uf.Size = file.Size; uf.Crc = file.Crc; uf.CrcDefined = file.CrcDefined; uf.HasStream = file.HasStream; file = uf; name = ui.Name; } /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); */ newDatabase.AddFile(file, file2, name); } } } } unsigned numFiles = group.Indices.Size(); if (numFiles == 0) continue; CRecordVector refItems; refItems.ClearAndSetSize(numFiles); bool sortByType = (numSolidFiles > 1); for (i = 0; i < numFiles; i++) refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); CSortParam sortParam; // sortParam.TreeFolders = &treeFolders; sortParam.SortByType = sortByType; refItems.Sort(CompareUpdateItems, (void *)&sortParam); CObjArray indices(numFiles); for (i = 0; i < numFiles; i++) { UInt32 index = refItems[i].Index; indices[i] = index; /* const CUpdateItem &ui = updateItems[index]; CFileItem file; if (ui.NewProps) FromUpdateItemToFileItem(ui, file); else file = db.Files[ui.IndexInArchive]; if (file.IsAnti || file.IsDir) return E_FAIL; newDatabase.Files.Add(file); */ } for (i = 0; i < numFiles;) { UInt64 totalSize = 0; int numSubFiles; UString prevExtension; for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) { const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; totalSize += ui.Size; if (totalSize > options.NumSolidBytes) break; if (options.SolidExtension) { UString ext = ui.GetExtension(); if (numSubFiles == 0) prevExtension = ext; else if (!ext.IsEqualToNoCase(prevExtension)) break; } } if (numSubFiles < 1) numSubFiles = 1; CFolderInStream *inStreamSpec = new CFolderInStream; CMyComPtr solidInStream(inStreamSpec); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curFolderUnpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS solidInStream, NULL, &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; lps->InSize += curFolderUnpackSize; // for () // newDatabase.PackCRCsDefined.Add(false); // newDatabase.PackCRCs.Add(0); CNum numUnpackStreams = 0; for (int subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &ui = updateItems[indices[i + subIndex]]; CFileItem file; CFileItem2 file2; UString name; if (ui.NewProps) { FromUpdateItemToFileItem(ui, file, file2); name = ui.Name; } else { GetFile(*db, ui.IndexInArchive, file, file2); db->GetPath(ui.IndexInArchive, name); } if (file2.IsAnti || file.IsDir) return E_FAIL; /* CFileItem &file = newDatabase.Files[ startFileIndexInDatabase + i + subIndex]; */ if (!inStreamSpec->Processed[subIndex]) { continue; // file.Name += L".locked"; } file.Crc = inStreamSpec->CRCs[subIndex]; file.Size = inStreamSpec->Sizes[subIndex]; if (file.Size != 0) { file.CrcDefined = true; file.HasStream = true; numUnpackStreams++; } else { file.CrcDefined = false; file.HasStream = false; } /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); */ newDatabase.AddFile(file, file2, name); } // numUnpackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); i += numSubFiles; } } if (folderRefIndex != folderRefs.Size()) return E_FAIL; RINOK(lps->SetCur()); /* folderRefs.ClearAndFree(); fileIndexToUpdateIndexMap.ClearAndFree(); groups.ClearAndFree(); */ /* for (i = 0; i < newDatabase.Files.Size(); i++) { CFileItem &file = newDatabase.Files[i]; file.Parent = treeFolderToArcIndex[file.Parent]; } if (totalSecureDataSize != 0) { newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); size_t pos = 0; newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); for (i = 0; i < secureBlocks.Sorted.Size(); i++) { const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; size_t size = buf.GetCapacity(); memcpy(newDatabase.SecureBuf + pos, buf, size); newDatabase.SecureSizes.Add((UInt32)size); pos += size; } } */ newDatabase.ReserveDown(); return S_OK; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h0100777000000000000000000000435413761647206023424 0ustar00// 7zUpdate.h #ifndef __7Z_UPDATE_H #define __7Z_UPDATE_H #include "../IArchive.h" // #include "../../Common/UniqBlocks.h" #include "7zCompressionMode.h" #include "7zIn.h" #include "7zOut.h" namespace NArchive { namespace N7z { /* struct CTreeFolder { UString Name; int Parent; CIntVector SubFolders; int UpdateItemIndex; int SortIndex; int SortIndexEnd; CTreeFolder(): UpdateItemIndex(-1) {} }; */ struct CUpdateItem { int IndexInArchive; int IndexInClient; UInt64 CTime; UInt64 ATime; UInt64 MTime; UInt64 Size; UString Name; /* bool IsAltStream; int ParentFolderIndex; int TreeFolderIndex; */ // that code is not used in 9.26 // int ParentSortIndex; // int ParentSortIndexEnd; UInt32 Attrib; bool NewData; bool NewProps; bool IsAnti; bool IsDir; bool AttribDefined; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; // int SecureIndex; // 0 means (no_security) bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } CUpdateItem(): // ParentSortIndex(-1), // IsAltStream(false), IsAnti(false), IsDir(false), AttribDefined(false), CTimeDefined(false), ATimeDefined(false), MTimeDefined(false) // SecureIndex(0) {} void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }; int GetExtensionPos() const; UString GetExtension() const; }; struct CUpdateOptions { const CCompressionMethodMode *Method; const CCompressionMethodMode *HeaderMethod; bool UseFilters; bool MaxFilter; CHeaderOptions HeaderOptions; UInt64 NumSolidFiles; UInt64 NumSolidBytes; bool SolidExtension; bool RemoveSfxBlock; bool VolumeMode; }; HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, const CDbEx *db, const CObjectVector &updateItems, // const CObjectVector &treeFolders, // treeFolders[0] is root // const CUniqBlocks &secureBlocks, COutArchive &archive, CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getDecoderPassword #endif ); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h0100777000000000000000000000014013761647206023077 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Archive.pri0100777000000000000000000000037613761647206023305 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/IArchive.h \ $$7ZIP_BASE/CPP/7zip/Archive/StdAfx.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/LzmaHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/SplitHandler.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/XzHandler.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/0040777000000000000000000000000013761647206022432 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp0100777000000000000000000000676613761647206025300 0ustar00// CoderMixer2.cpp #include "StdAfx.h" #include "CoderMixer2.h" namespace NCoderMixer { CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): _srcBindInfo(srcBindInfo) { srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); UInt32 j; _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams); DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams); for (j = 0; j < NumSrcInStreams; j++) { _srcInToDestOutMap[j] = 0; DestOutToSrcInMap[j] = 0; } _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams); _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams); for (j = 0; j < _numSrcOutStreams; j++) { _srcOutToDestInMap[j] = 0; _destInToSrcOutMap[j] = 0; } UInt32 destInOffset = 0; UInt32 destOutOffset = 0; UInt32 srcInOffset = NumSrcInStreams; UInt32 srcOutOffset = _numSrcOutStreams; for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--) { const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i]; srcInOffset -= srcCoderInfo.NumInStreams; srcOutOffset -= srcCoderInfo.NumOutStreams; UInt32 j; for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++) { UInt32 index = srcInOffset + j; _srcInToDestOutMap[index] = destOutOffset; DestOutToSrcInMap[destOutOffset] = index; } for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++) { UInt32 index = srcOutOffset + j; _srcOutToDestInMap[index] = destInOffset; _destInToSrcOutMap[destInOffset] = index; } } } void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) { destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size()); destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size()); destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size()); destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size()); unsigned i; for (i = _srcBindInfo.Coders.Size(); i != 0;) { i--; const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; CCoderStreamsInfo destCoderInfo; destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; destBindInfo.Coders.AddInReserved(destCoderInfo); } for (i = _srcBindInfo.BindPairs.Size(); i != 0;) { i--; const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; CBindPair destBindPair; destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; destBindInfo.BindPairs.AddInReserved(destBindPair); } for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); } void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, CRecordVector &sizePointers, UInt32 numItems) { sizes.ClearAndSetSize(numItems); sizePointers.ClearAndSetSize(numItems); for (UInt32 i = 0; i < numItems; i++) { if (!srcSizes || !srcSizes[i]) { sizes[i] = 0; sizePointers[i] = NULL; } else { sizes[i] = *(srcSizes[i]); sizePointers[i] = &sizes[i]; } } } void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h0100777000000000000000000001020413761647206024723 0ustar00// CoderMixer2.h #ifndef __CODER_MIXER2_H #define __CODER_MIXER2_H #include "../../../Common/MyCom.h" #include "../../../Common/MyVector.h" #include "../../ICoder.h" namespace NCoderMixer { struct CBindPair { UInt32 InIndex; UInt32 OutIndex; }; struct CCoderStreamsInfo { UInt32 NumInStreams; UInt32 NumOutStreams; }; struct CBindInfo { CRecordVector Coders; CRecordVector BindPairs; CRecordVector InStreams; CRecordVector OutStreams; void Clear() { Coders.Clear(); BindPairs.Clear(); InStreams.Clear(); OutStreams.Clear(); } /* UInt32 GetCoderStartOutStream(UInt32 coderIndex) const { UInt32 numOutStreams = 0; for (UInt32 i = 0; i < coderIndex; i++) numOutStreams += Coders[i].NumOutStreams; return numOutStreams; } */ void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const { numInStreams = 0; numOutStreams = 0; FOR_VECTOR (i, Coders) { const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; numInStreams += coderStreamsInfo.NumInStreams; numOutStreams += coderStreamsInfo.NumOutStreams; } } int FindBinderForInStream(UInt32 inStream) const { FOR_VECTOR (i, BindPairs) if (BindPairs[i].InIndex == inStream) return i; return -1; } int FindBinderForOutStream(UInt32 outStream) const { FOR_VECTOR (i, BindPairs) if (BindPairs[i].OutIndex == outStream) return i; return -1; } UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const { UInt32 streamIndex = 0; for (UInt32 i = 0; i < coderIndex; i++) streamIndex += Coders[i].NumInStreams; return streamIndex; } UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const { UInt32 streamIndex = 0; for (UInt32 i = 0; i < coderIndex; i++) streamIndex += Coders[i].NumOutStreams; return streamIndex; } void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const { for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) { UInt32 curSize = Coders[coderIndex].NumInStreams; if (streamIndex < curSize) { coderStreamIndex = streamIndex; return; } streamIndex -= curSize; } throw 1; } void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const { for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) { UInt32 curSize = Coders[coderIndex].NumOutStreams; if (streamIndex < curSize) { coderStreamIndex = streamIndex; return; } streamIndex -= curSize; } throw 1; } }; class CBindReverseConverter { UInt32 _numSrcOutStreams; NCoderMixer::CBindInfo _srcBindInfo; CRecordVector _srcInToDestOutMap; CRecordVector _srcOutToDestInMap; CRecordVector _destInToSrcOutMap; public: UInt32 NumSrcInStreams; CRecordVector DestOutToSrcInMap; CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo); void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo); }; void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, CRecordVector &sizePointers, UInt32 numItems); struct CCoderInfo2 { CMyComPtr Coder; CMyComPtr Coder2; UInt32 NumInStreams; UInt32 NumOutStreams; CRecordVector InSizes; CRecordVector OutSizes; CRecordVector InSizePointers; CRecordVector OutSizePointers; CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): NumInStreams(numInStreams), NumOutStreams(numOutStreams) {} void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); HRESULT QueryInterface(REFGUID iid, void** pp) const { IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; return p->QueryInterface(iid, pp); } }; class CCoderMixer2 { public: virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0; virtual void ReInit() = 0; virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0; }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp0100777000000000000000000001354013761647206025525 0ustar00// CoderMixer2MT.cpp #include "StdAfx.h" #include "CoderMixer2MT.h" namespace NCoderMixer { CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): CCoderInfo2(numInStreams, numOutStreams) { InStreams.ClearAndReserve(NumInStreams); OutStreams.ClearAndReserve(NumOutStreams); } void CCoder2::Execute() { Code(NULL); } void CCoder2::Code(ICompressProgressInfo *progress) { InStreamPointers.ClearAndReserve(NumInStreams); OutStreamPointers.ClearAndReserve(NumOutStreams); UInt32 i; for (i = 0; i < NumInStreams; i++) { if (InSizePointers[i]) InSizePointers[i] = &InSizes[i]; InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); } for (i = 0; i < NumOutStreams; i++) { if (OutSizePointers[i]) OutSizePointers[i] = &OutSizes[i]; OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); } if (Coder) Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], InSizePointers[0], OutSizePointers[0], progress); else Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams, &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress); { unsigned i; for (i = 0; i < InStreams.Size(); i++) InStreams[i].Release(); for (i = 0; i < OutStreams.Size(); i++) OutStreams[i].Release(); } } /* void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); } */ ////////////////////////////////////// // CCoderMixer2MT HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) { _bindInfo = bindInfo; _streamBinders.Clear(); FOR_VECTOR (i, _bindInfo.BindPairs) { RINOK(_streamBinders.AddNew().CreateEvents()); } return S_OK; } void CCoderMixer2MT::AddCoderCommon() { const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()]; CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams); _coders.Add(threadCoderInfo); } void CCoderMixer2MT::AddCoder(ICompressCoder *coder) { AddCoderCommon(); _coders.Back().Coder = coder; } void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) { AddCoderCommon(); _coders.Back().Coder2 = coder; } void CCoderMixer2MT::ReInit() { FOR_VECTOR (i, _streamBinders) _streamBinders[i].ReInit(); } HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams) { /* if (_coders.Size() != _bindInfo.Coders.Size()) throw 0; */ unsigned i; for (i = 0; i < _coders.Size(); i++) { CCoder2 &coderInfo = _coders[i]; const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i]; coderInfo.InStreams.Clear(); UInt32 j; for (j = 0; j < coderStreamsInfo.NumInStreams; j++) coderInfo.InStreams.Add(NULL); coderInfo.OutStreams.Clear(); for (j = 0; j < coderStreamsInfo.NumOutStreams; j++) coderInfo.OutStreams.Add(NULL); } for (i = 0; i < _bindInfo.BindPairs.Size(); i++) { const CBindPair &bindPair = _bindInfo.BindPairs[i]; UInt32 inCoderIndex, inCoderStreamIndex; UInt32 outCoderIndex, outCoderStreamIndex; _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex); _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex); _streamBinders[i].CreateStreams( &_coders[inCoderIndex].InStreams[inCoderStreamIndex], &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]); CMyComPtr inSetSize, outSetSize; _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); if (inSetSize && outSetSize) { const UInt32 kBufSize = 1 << 19; inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); } } for (i = 0; i < _bindInfo.InStreams.Size(); i++) { UInt32 inCoderIndex, inCoderStreamIndex; _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex); _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i]; } for (i = 0; i < _bindInfo.OutStreams.Size(); i++) { UInt32 outCoderIndex, outCoderStreamIndex; _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex); _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i]; } return S_OK; } HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) { FOR_VECTOR (i, _coders) if (_coders[i].Result == code) return code; return S_OK; } STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) return E_INVALIDARG; Init(inStreams, outStreams); unsigned i; for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) { RINOK(_coders[i].Create()); } for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].Start(); _coders[_progressCoderIndex].Code(progress); for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].WaitExecuteFinish(); RINOK(ReturnIfError(E_ABORT)); RINOK(ReturnIfError(E_OUTOFMEMORY)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK && result != E_FAIL && result != S_FALSE) return result; } RINOK(ReturnIfError(S_FALSE)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK) return result; } return S_OK; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h0100777000000000000000000000417413761647206025175 0ustar00// CoderMixer2MT.h #ifndef __CODER_MIXER2_MT_H #define __CODER_MIXER2_MT_H #include "CoderMixer2.h" #include "../../../Common/MyCom.h" #include "../../Common/StreamBinder.h" #include "../../Common/VirtThread.h" namespace NCoderMixer { struct CCoder2: public CCoderInfo2, public CVirtThread { CRecordVector InStreamPointers; CRecordVector OutStreamPointers; public: HRESULT Result; CObjectVector< CMyComPtr > InStreams; CObjectVector< CMyComPtr > OutStreams; CCoder2(UInt32 numInStreams, UInt32 numOutStreams); ~CCoder2() { CVirtThread::WaitThreadFinish(); } // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); virtual void Execute(); void Code(ICompressProgressInfo *progress); }; /* SetBindInfo() for each coder AddCoder[2]() SetProgressIndex(UInt32 coderIndex); for each file { ReInit() for each coder SetCoderInfo Code } */ class CCoderMixer2MT: public ICompressCoder2, public CCoderMixer2, public CMyUnknownImp { CBindInfo _bindInfo; CObjectVector _streamBinders; unsigned _progressCoderIndex; void AddCoderCommon(); HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams); HRESULT ReturnIfError(HRESULT code); public: CObjectVector _coders; MY_UNKNOWN_IMP STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); HRESULT SetBindInfo(const CBindInfo &bindInfo); void AddCoder(ICompressCoder *coder); void AddCoder2(ICompressCoder2 *coder); void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; } void ReInit(); void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); } UInt64 GetWriteProcessedSize(UInt32 binderIndex) const { return _streamBinders[binderIndex].ProcessedSize; } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/Common.pri0100777000000000000000000000205013761647206024373 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ParseProperties.h \ $$7ZIP_BASE/CPP/7zip/Archive/Common/StdAfx.h SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.cpp \ $$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp0100777000000000000000000000062213761647206026075 0ustar00// DummyOutStream.cpp #include "StdAfx.h" #include "DummyOutStream.h" STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = size; HRESULT res = S_OK; if (_stream) res = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return res; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h0100777000000000000000000000111113761647206025534 0ustar00// DummyOutStream.h #ifndef __DUMMY_OUT_STREAM_H #define __DUMMY_OUT_STREAM_H #include "../../../Common/MyCom.h" #include "../../IStream.h" class CDummyOutStream: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; public: void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } void ReleaseStream() { _stream.Release(); } void Init() { _size = 0; } MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); UInt64 GetSize() const { return _size; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.cpp0100777000000000000000000000617013761647206025207 0ustar00// HandlerOut.cpp #include "StdAfx.h" #ifndef _7ZIP_ST #include "../../../Windows/System.h" #endif #include "../Common/ParseProperties.h" #include "HandlerOut.h" using namespace NWindows; namespace NArchive { static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value) { if (m.FindProp(propID) < 0) m.AddProp32(propID, value); } void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { UInt32 level = _level; if (level != (UInt32)(Int32)-1) SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); #ifndef _7ZIP_ST SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); #endif } void CMultiMethodProps::Init() { #ifndef _7ZIP_ST _numProcessors = _numThreads = NSystem::GetNumberOfProcessors(); #endif _level = (UInt32)(Int32)-1; _autoFilter = true; _crcSize = 4; _filterMethod.Clear(); _methods.Clear(); } HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; if (name[0] == 'x') { name.Delete(0); _level = 9; return ParsePropToUInt32(name, value, _level); } if (name == L"crc") { name.Delete(0, 3); _crcSize = 4; return ParsePropToUInt32(name, value, _crcSize); } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Ptr(index); if (index == 0) { if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); #endif return S_OK; } if (name.IsEqualTo("f")) { HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); if (res == S_OK) return res; if (value.vt != VT_BSTR) return E_INVALIDARG; return _filterMethod.ParseMethodFromPROPVARIANT(L"", value); } number = 0; } if (number > 64) return E_FAIL; for (int j = _methods.Size(); j <= (int)number; j++) _methods.Add(COneMethodInfo()); return _methods[number].ParseMethodFromPROPVARIANT(realName, value); } void CSingleMethodProps::Init() { Clear(); #ifndef _7ZIP_ST _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); AddNumThreadsProp(_numThreads); #endif _level = (UInt32)(Int32)-1; } HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { Init(); for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; if (name[0] == L'x') { UInt32 a = 9; RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); _level = a; AddLevelProp(a); } else if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); AddNumThreadsProp(_numThreads); #endif } else return ParseMethodFromPROPVARIANT(names[i], value); } return S_OK; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.h0100777000000000000000000000236113761647206024652 0ustar00// HandlerOut.h #ifndef __HANDLER_OUT_H #define __HANDLER_OUT_H #include "../../Common/MethodProps.h" namespace NArchive { class CMultiMethodProps { UInt32 _level; public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; #endif UInt32 _crcSize; CObjectVector _methods; COneMethodInfo _filterMethod; bool _autoFilter; void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); unsigned GetNumEmptyMethods() const { unsigned i; for (i = 0; i < _methods.Size(); i++) if (!_methods[i].IsEmpty()) break; return i; } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } void Init(); CMultiMethodProps() { Init(); } HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); }; class CSingleMethodProps: public COneMethodInfo { UInt32 _level; public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; #endif void Init(); CSingleMethodProps() { Init(); } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.cpp0100777000000000000000000000226113761647206026045 0ustar00// InStreamWithCRC.cpp #include "StdAfx.h" #include "InStreamWithCRC.h" STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessed = 0; HRESULT result = S_OK; if (_stream) result = _stream->Read(data, size, &realProcessed); _size += realProcessed; if (size != 0 && realProcessed == 0) _wasFinished = true; _crc = CrcUpdate(_crc, data, realProcessed); if (processedSize) *processedSize = realProcessed; return result; } STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessed = 0; HRESULT result = S_OK; if (_stream) result = _stream->Read(data, size, &realProcessed); _size += realProcessed; /* if (size != 0 && realProcessed == 0) _wasFinished = true; */ _crc = CrcUpdate(_crc, data, realProcessed); if (processedSize) *processedSize = realProcessed; return result; } STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin != STREAM_SEEK_SET || offset != 0) return E_FAIL; _size = 0; _crc = CRC_INIT_VAL; return _stream->Seek(offset, seekOrigin, newPosition); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.h0100777000000000000000000000301413761647206025507 0ustar00// InStreamWithCRC.h #ifndef __IN_STREAM_WITH_CRC_H #define __IN_STREAM_WITH_CRC_H #include "../../../../C/7zCrc.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" class CSequentialInStreamWithCRC: public ISequentialInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); private: CMyComPtr _stream; UInt64 _size; UInt32 _crc; bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } void Init() { _size = 0; _wasFinished = false; _crc = CRC_INIT_VAL; } void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt64 GetSize() const { return _size; } bool WasFinished() const { return _wasFinished; } }; class CInStreamWithCRC: public IInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); private: CMyComPtr _stream; UInt64 _size; UInt32 _crc; // bool _wasFinished; public: void SetStream(IInStream *stream) { _stream = stream; } void Init() { _size = 0; // _wasFinished = false; _crc = CRC_INIT_VAL; } void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt64 GetSize() const { return _size; } // bool WasFinished() const { return _wasFinished; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.cpp0100777000000000000000000000315413761647206025661 0ustar00// Archive/Common/ItemNameUtils.cpp #include "StdAfx.h" #include "ItemNameUtils.h" namespace NArchive { namespace NItemName { static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR; static const wchar_t kDirDelimiter = L'/'; void ReplaceToOsPathSeparator(wchar_t *s) { #ifdef _WIN32 for (;;) { wchar_t c = *s; if (c == 0) break; if (c == kDirDelimiter) *s = kOSDirDelimiter; s++; } #endif } UString MakeLegalName(const UString &name) { UString zipName = name; zipName.Replace(kOSDirDelimiter, kDirDelimiter); return zipName; } UString GetOSName(const UString &name) { UString newName = name; newName.Replace(kDirDelimiter, kOSDirDelimiter); return newName; } UString GetOSName2(const UString &name) { if (name.IsEmpty()) return UString(); UString newName = GetOSName(name); if (newName.Back() == kOSDirDelimiter) newName.DeleteBack(); return newName; } void ConvertToOSName2(UString &name) { if (!name.IsEmpty()) { name.Replace(kDirDelimiter, kOSDirDelimiter); if (name.Back() == kOSDirDelimiter) name.DeleteBack(); } } bool HasTailSlash(const AString &name, UINT #if defined(_WIN32) && !defined(UNDER_CE) codePage #endif ) { if (name.IsEmpty()) return false; LPCSTR prev = #if defined(_WIN32) && !defined(UNDER_CE) CharPrevExA((WORD)codePage, name, &name[name.Len()], 0); #else (LPCSTR)(name) + (name.Len() - 1); #endif return (*prev == '/'); } #ifndef _WIN32 UString WinNameToOSName(const UString &name) { UString newName = name; newName.Replace(L'\\', kOSDirDelimiter); return newName; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.h0100777000000000000000000000116713761647206025330 0ustar00// Archive/Common/ItemNameUtils.h #ifndef __ARCHIVE_ITEM_NAME_UTILS_H #define __ARCHIVE_ITEM_NAME_UTILS_H #include "../../../Common/MyString.h" namespace NArchive { namespace NItemName { void ReplaceToOsPathSeparator(wchar_t *s); UString MakeLegalName(const UString &name); UString GetOSName(const UString &name); UString GetOSName2(const UString &name); void ConvertToOSName2(UString &name); bool HasTailSlash(const AString &name, UINT codePage); #ifdef _WIN32 inline UString WinNameToOSName(const UString &name) { return name; } #else UString WinNameToOSName(const UString &name); #endif }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.cpp0100777000000000000000000001103213761647206025401 0ustar00// MultiStream.cpp #include "StdAfx.h" #include "MultiStream.h" STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _totalLength) return S_OK; { unsigned left = 0, mid = _streamIndex, right = Streams.Size(); for (;;) { CSubStreamInfo &m = Streams[mid]; if (_pos < m.GlobalOffset) right = mid; else if (_pos >= m.GlobalOffset + m.Size) left = mid + 1; else { _streamIndex = mid; break; } mid = (left + right) / 2; } _streamIndex = mid; } CSubStreamInfo &s = Streams[_streamIndex]; UInt64 localPos = _pos - s.GlobalOffset; if (localPos != s.LocalPos) { RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos)); } UInt64 rem = s.Size - localPos; if (size > rem) size = (UInt32)rem; HRESULT result = s.Stream->Read(data, size, &size); _pos += size; s.LocalPos += size; if (processedSize) *processedSize = size; return result; } STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _totalLength; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } /* class COutVolumeStream: public ISequentialOutStream, public CMyUnknownImp { unsigned _volIndex; UInt64 _volSize; UInt64 _curPos; CMyComPtr _volumeStream; COutArchive _archive; CCRC _crc; public: MY_UNKNOWN_IMP CFileItem _file; CUpdateOptions _options; CMyComPtr VolumeCallback; void Init(IArchiveUpdateCallback2 *volumeCallback, const UString &name) { _file.Name = name; _file.IsStartPosDefined = true; _file.StartPos = 0; VolumeCallback = volumeCallback; _volIndex = 0; _volSize = 0; } HRESULT Flush(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; HRESULT COutVolumeStream::Flush() { if (_volumeStream) { _file.UnPackSize = _curPos; _file.FileCRC = _crc.GetDigest(); RINOK(WriteVolumeHeader(_archive, _file, _options)); _archive.Close(); _volumeStream.Release(); _file.StartPos += _file.UnPackSize; } return S_OK; } */ /* STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_streamIndex >= Streams.Size()) { CSubStreamInfo subStream; RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size)); RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream)); subStream.Pos = 0; Streams.Add(subStream); continue; } CSubStreamInfo &subStream = Streams[_streamIndex]; if (_offsetPos >= subStream.Size) { _offsetPos -= subStream.Size; _streamIndex++; continue; } if (_offsetPos != subStream.Pos) { CMyComPtr outStream; RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)); RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); subStream.Pos = _offsetPos; } UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos); UInt32 realProcessed; RINOK(subStream.Stream->Write(data, curSize, &realProcessed)); data = (void *)((Byte *)data + realProcessed); size -= realProcessed; subStream.Pos += realProcessed; _offsetPos += realProcessed; _absPos += realProcessed; if (_absPos > _length) _length = _absPos; if (processedSize != NULL) *processedSize += realProcessed; if (subStream.Pos == subStream.Size) { _streamIndex++; _offsetPos = 0; } if (realProcessed != curSize && realProcessed == 0) return E_FAIL; } return S_OK; } STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _absPos; break; case STREAM_SEEK_END: offset += _length; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _absPos = offset; _offsetPos = _absPos; _streamIndex = 0; if (newPosition) *newPosition = offset; return S_OK; } */ qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.h0100777000000000000000000000334713761647206025060 0ustar00// MultiStream.h #ifndef __MULTI_STREAM_H #define __MULTI_STREAM_H #include "../../../Common/MyCom.h" #include "../../../Common/MyVector.h" #include "../../IStream.h" class CMultiStream: public IInStream, public CMyUnknownImp { UInt64 _pos; UInt64 _totalLength; unsigned _streamIndex; public: struct CSubStreamInfo { CMyComPtr Stream; UInt64 Size; UInt64 GlobalOffset; UInt64 LocalPos; CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} }; CObjectVector Streams; HRESULT Init() { UInt64 total = 0; FOR_VECTOR (i, Streams) { CSubStreamInfo &s = Streams[i]; s.GlobalOffset = total; total += Streams[i].Size; RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos)); } _totalLength = total; _pos = 0; _streamIndex = 0; return S_OK; } MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; /* class COutMultiStream: public IOutStream, public CMyUnknownImp { unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; struct CSubStreamInfo { CMyComPtr Stream; UInt64 Size; UInt64 Pos; }; CObjectVector Streams; public: CMyComPtr VolumeCallback; void Init() { _streamIndex = 0; _offsetPos = 0; _absPos = 0; _length = 0; } MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; */ #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp0100777000000000000000000000063113761647206026245 0ustar00// OutStreamWithCRC.cpp #include "StdAfx.h" #include "OutStreamWithCRC.h" STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (_stream) result = _stream->Write(data, size, &size); if (_calculate) _crc = CrcUpdate(_crc, data, size); _size += size; if (processedSize != NULL) *processedSize = size; return result; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.h0100777000000000000000000000160413761647206025713 0ustar00// OutStreamWithCRC.h #ifndef __OUT_STREAM_WITH_CRC_H #define __OUT_STREAM_WITH_CRC_H #include "../../../../C/7zCrc.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" class COutStreamWithCRC: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; UInt32 _crc; bool _calculate; public: MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(bool calculate = true) { _size = 0; _calculate = calculate; _crc = CRC_INIT_VAL; } void EnableCalc(bool calculate) { _calculate = calculate; } void InitCRC() { _crc = CRC_INIT_VAL; } UInt64 GetSize() const { return _size; } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.h0100777000000000000000000000013013761647206025724 0ustar00// ParseProperties.h #ifndef __PARSE_PROPERTIES_H #define __PARSE_PROPERTIES_H #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/Common/StdAfx.h0100777000000000000000000000014013761647206023767 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/IArchive.h0100777000000000000000000003620513761647206023053 0ustar00// IArchive.h #ifndef __IARCHIVE_H #define __IARCHIVE_H #include "../IProgress.h" #include "../IStream.h" #include "../PropID.h" #define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x) #define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x) namespace NFileTimeType { enum EEnum { kWindows, kUnix, kDOS }; } namespace NArcInfoFlags { const UInt32 kKeepName = 1 << 0; // keep name of file in archive name const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams const UInt32 kNtSecure = 1 << 2; // the handler supports NT security const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive const UInt32 kMultiSignature = 1 << 4; // there are several signatures const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset const UInt32 kStartOpen = 1 << 6; // call handler for each start position const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links const UInt32 kHardLinks = 1 << 11; // the handler supports hard links } namespace NArchive { namespace NHandlerPropID { enum { kName = 0, // VT_BSTR kClassID, // binary GUID in VT_BSTR kExtension, // VT_BSTR kAddExtension, // VT_BSTR kUpdate, // VT_BOOL kKeepName, // VT_BOOL kSignature, // binary in VT_BSTR kMultiSignature, // binary in VT_BSTR kSignatureOffset, // VT_UI4 kAltStreams, // VT_BOOL kNtSecure, // VT_BOOL kFlags // VT_UI4 // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) }; } namespace NExtract { namespace NAskMode { enum { kExtract = 0, kTest, kSkip }; } namespace NOperationResult { enum { kOK = 0, kUnsupportedMethod, kDataError, kCRCError, kUnavailable, kUnexpectedEnd, kDataAfterEnd, kIsNotArc, kHeadersError }; } } namespace NUpdate { namespace NOperationResult { enum { kOK = 0 , // kError }; } } } #define INTERFACE_IArchiveOpenCallback(x) \ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) { INTERFACE_IArchiveOpenCallback(PURE); }; /* IArchiveExtractCallback::GetStream Result: (*inStream == NULL) - for directories (*inStream == NULL) - if link (hard link or symbolic link) was created */ #define INTERFACE_IArchiveExtractCallback(x) \ INTERFACE_IProgress(x) \ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \ ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) { INTERFACE_IArchiveExtractCallback(PURE) }; #define INTERFACE_IArchiveOpenVolumeCallback(x) \ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \ ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30) { INTERFACE_IArchiveOpenVolumeCallback(PURE); }; ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40) { STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE; }; ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50) { STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE; }; /* IInArchive::Open stream if (kUseGlobalOffset), stream current position can be non 0. if (!kUseGlobalOffset), stream current position is 0. if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream if (*maxCheckStartPosition == 0), the handler must check only current position as archive start IInArchive::Extract: indices must be sorted numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" testMode != 0 means "test files without writing to outStream" IInArchive::GetArchiveProperty: kpidOffset - start offset of archive. VT_EMPTY : means offset = 0. VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed kpidPhySize - size of archive. VT_EMPTY means unknown size. kpidPhySize is allowed to be larger than file size. In that case it must show supposed size. kpidIsDeleted: kpidIsAltStream: kpidIsAux: kpidINode: must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. Notes: Don't call IInArchive functions for same IInArchive object from different threads simultaneously. Some IInArchive handlers will work incorrectly in that case. */ /* MSVC allows the code where there is throw() in declaration of function, but there is no throw() in definition of function. */ #ifdef _MSC_VER #define MY_NO_THROW_DECL_ONLY throw() #else #define MY_NO_THROW_DECL_ONLY #endif #define INTERFACE_IInArchive(x) \ STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; ARCHIVE_INTERFACE(IInArchive, 0x60) { INTERFACE_IInArchive(PURE) }; namespace NParentType { enum { kDir = 0, kAltStream }; }; namespace NPropDataType { const UInt32 kMask_ZeroEnd = 1 << 4; // const UInt32 kMask_BigEndian = 1 << 5; const UInt32 kMask_Utf = 1 << 6; // const UInt32 kMask_Utf8 = kMask_Utf | 0; const UInt32 kMask_Utf16 = kMask_Utf | 1; // const UInt32 kMask_Utf32 = kMask_Utf | 2; const UInt32 kNotDefined = 0; const UInt32 kRaw = 1; const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; }; // UTF string (pointer to wchar_t) with zero end and little-endian. #define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) /* GetRawProp: Result: S_OK - even if property is not set */ #define INTERFACE_IArchiveGetRawProps(x) \ STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \ STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \ STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x; ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70) { INTERFACE_IArchiveGetRawProps(PURE) }; #define INTERFACE_IArchiveGetRootProps(x) \ STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71) { INTERFACE_IArchiveGetRootProps(PURE) }; ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61) { STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE; }; /* OpenForSize Result: S_FALSE - is not archive ? - DATA error */ /* const UInt32 kOpenFlags_RealPhySize = 1 << 0; const UInt32 kOpenFlags_NoSeek = 1 << 1; // const UInt32 kOpenFlags_BeforeExtract = 1 << 2; */ /* Flags: 0 - opens archive with IInStream, if IInStream interface is supported - if phySize is not available, it doesn't try to make full parse to get phySize kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, the handler can return S_OK, but it doesn't check even Signature. So next Extract can be called for that sequential stream. */ /* ARCHIVE_INTERFACE(IArchiveOpen2, 0x62) { STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE; }; */ // ---------- UPDATE ---------- /* GetUpdateItemInfo outs: *newData *newProps 0 0 - Copy data and properties from archive 0 1 - Copy data from archive, request new properties 1 0 - that combination is unused now 1 1 - Request new data and new properties. It can be used even for folders indexInArchive = -1 if there is no item in archive, or if it doesn't matter. GetStream out: Result: S_OK: (*inStream == NULL) - only for directories - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file (*inStream != NULL) - for any file, even for empty file or anti-file S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) (*inStream == NULL) The order of calling for hard links: - GetStream() - GetProperty(kpidHardLink) */ #define INTERFACE_IArchiveUpdateCallback(x) \ INTERFACE_IProgress(x); \ STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \ STDMETHOD(SetOperationResult)(Int32 operationResult) x; \ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80) { INTERFACE_IArchiveUpdateCallback(PURE); }; #define INTERFACE_IArchiveUpdateCallback2(x) \ INTERFACE_IArchiveUpdateCallback(x) \ STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \ STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) { INTERFACE_IArchiveUpdateCallback2(PURE); }; /* UpdateItems() ------------- outStream: output stream. (the handler) MUST support the case when Seek position in outStream is not ZERO. but the caller calls with empty outStream and seek position is ZERO?? archives with stub: If archive is open and the handler and (Offset > 0), then the handler knows about stub size. UpdateItems(): 1) the handler MUST copy that stub to outStream 2) the caller MUST NOT copy the stub to outStream, if "rsfx" property is set with SetProperties the handler must support the case where ISequentialOutStream *outStream */ #define INTERFACE_IOutArchive(x) \ STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \ STDMETHOD(GetFileTimeType)(UInt32 *type) x; ARCHIVE_INTERFACE(IOutArchive, 0xA0) { INTERFACE_IOutArchive(PURE) }; ARCHIVE_INTERFACE(ISetProperties, 0x03) { STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE; }; ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04) { STDMETHOD(KeepModeForNextOpen)() PURE; }; /* Exe handler: the handler for executable format (PE, ELF, Mach-O). SFX archive: executable stub + some tail data. before 9.31: exe handler didn't parse SFX archives as executable format. for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05) { STDMETHOD(AllowTail)(Int32 allowTail) PURE; }; #define IMP_IInArchive_GetProp(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \ #define IMP_IInArchive_GetProp_WITH_NAME(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ const STATPROPSTG &srcItem = k[index]; \ *propID = srcItem.propid; *varType = srcItem.vt; \ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \ #define IMP_IInArchive_Props \ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps) #define IMP_IInArchive_Props_WITH_NAME \ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps) #define IMP_IInArchive_ArcProps \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps) #define IMP_IInArchive_ArcProps_WITH_NAME \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps) #define IMP_IInArchive_ArcProps_NO_Table \ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ { *numProps = 0; return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \ { return E_NOTIMPL; } \ #define IMP_IInArchive_ArcProps_NO \ IMP_IInArchive_ArcProps_NO_Table \ STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \ { value->vt = VT_EMPTY; return S_OK; } #define k_IsArc_Res_NO 0 #define k_IsArc_Res_YES 1 #define k_IsArc_Res_NEED_MORE 2 // #define k_IsArc_Res_YES_LOW_PROB 3 #define API_FUNC_IsArc EXTERN_C UInt32 WINAPI #define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI extern "C" { typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject); typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size); typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc); typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats); typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value); typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value); typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); typedef HRESULT (WINAPI *Func_SetLargePageMode)(); typedef IOutArchive * (*Func_CreateOutArchive)(); typedef IInArchive * (*Func_CreateInArchive)(); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp0100777000000000000000000003332713761647206024117 0ustar00// LzmaHandler.cpp #include "StdAfx.h" #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" #include "../../Windows/PropVariant.h" #include "../Common/CreateCoder.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "../Compress/LzmaDecoder.h" #include "Common/DummyOutStream.h" using namespace NWindows; namespace NArchive { namespace NLzma { static bool CheckDicSize(const Byte *p) { UInt32 dicSize = GetUi32(p); if (dicSize == 1) return true; for (unsigned i = 0; i <= 30; i++) if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) return true; return (dicSize == 0xFFFFFFFF); } static const Byte kProps[] = { kpidSize, kpidPackSize, kpidMethod }; static const Byte kArcProps[] = { kpidNumStreams }; struct CHeader { UInt64 Size; Byte FilterID; Byte LzmaProps[5]; UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); } bool HasSize() const { return (Size != (UInt64)(Int64)-1); } bool Parse(const Byte *buf, bool isThereFilter); }; bool CHeader::Parse(const Byte *buf, bool isThereFilter) { FilterID = 0; if (isThereFilter) FilterID = buf[0]; const Byte *sig = buf + (isThereFilter ? 1 : 0); for (int i = 0; i < 5; i++) LzmaProps[i] = sig[i]; Size = GetUi64(sig + 5); return LzmaProps[0] < 5 * 5 * 9 && FilterID < 2 && (!HasSize() || Size < ((UInt64)1 << 56)) && CheckDicSize(LzmaProps + 1); } class CDecoder { CMyComPtr _lzmaDecoder; CMyComPtr _bcjStream; public: NCompress::NLzma::CDecoder *_lzmaDecoderSpec; ~CDecoder(); HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS bool filtered, ISequentialInStream *inStream); HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress); UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); } void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); } HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize) { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); } }; static const UInt32 k_BCJ = 0x03030103; HRESULT CDecoder::Create( DECL_EXTERNAL_CODECS_LOC_VARS bool filteredMode, ISequentialInStream *inStream) { if (!_lzmaDecoder) { _lzmaDecoderSpec = new NCompress::NLzma::CDecoder; _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } if (filteredMode) { if (!_bcjStream) { CMyComPtr coder; RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false)); if (!coder) return E_NOTIMPL; coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream); if (!_bcjStream) return E_NOTIMPL; } } return _lzmaDecoderSpec->SetInStream(inStream); } CDecoder::~CDecoder() { ReleaseInStream(); } HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { if (header.FilterID > 1) return E_NOTIMPL; { CMyComPtr setDecoderProperties; _lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); if (!setDecoderProperties) return E_NOTIMPL; RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5)); } CMyComPtr setOutStream; bool filteredMode = (header.FilterID == 1); if (filteredMode) { _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream); if (!setOutStream) return E_NOTIMPL; RINOK(setOutStream->SetOutStream(outStream)); outStream = _bcjStream; } const UInt64 *Size = header.HasSize() ? &header.Size : NULL; HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress); if (filteredMode) { CMyComPtr flush; _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush); if (flush) { HRESULT res2 = flush->Flush(); if (res == S_OK) res = res2; } HRESULT res2 = setOutStream->ReleaseOutStream(); if (res == S_OK) res = res2; } RINOK(res); if (header.HasSize()) if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size) return S_FALSE; return S_OK; } class CHandler: public IInArchive, public IArchiveOpenSeq, PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { CHeader _header; bool _lzma86; CMyComPtr _stream; CMyComPtr _seqStream; bool _isArc; bool _needSeekToStart; bool _dataAfterEnd; bool _needMoreInput; bool _packSize_Defined; bool _unpackSize_Defined; bool _numStreams_Defined; bool _unsupported; bool _dataError; UInt64 _packSize; UInt64 _unpackSize; UInt64 _numStreams; DECL_EXTERNAL_CODECS_VARS DECL_ISetCompressCodecsInfo public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq) QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); CHandler(bool lzma86) { _lzma86 = lzma86; } unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } }; IMP_IInArchive_Props IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; case kpidErrorFlags: { UInt32 v = 0; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_dataError) v |= kpv_ErrorFlags_DataError; prop = v; } } prop.Detach(value); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = 1; return S_OK; } static void DictSizeToString(UInt32 value, char *s) { for (int i = 0; i <= 31; i++) if (((UInt32)1 << i) == value) { ::ConvertUInt32ToString(i, s); return; } char c = 'b'; if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; } else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; } ::ConvertUInt32ToString(value, s); s += MyStringLen(s); *s++ = c; *s = 0; } STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; case kpidMethod: if (_stream) { char sz[64]; char *s = sz; if (_header.FilterID != 0) s = MyStpCpy(s, "BCJ "); s = MyStpCpy(s, "LZMA:"); DictSizeToString(_header.GetDicSize(), s); prop = sz; } break; } prop.Detach(value); return S_OK; } API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) { const UInt32 kHeaderSize = 1 + 4 + 8; if (size < kHeaderSize) return k_IsArc_Res_NEED_MORE; if (p[0] >= 5 * 5 * 9) return k_IsArc_Res_NO; UInt64 unpackSize = GetUi64(p + 1 + 4); if (unpackSize != (UInt64)(Int64)-1) { if (size >= ((UInt64)1 << 56)) return k_IsArc_Res_NO; } if (unpackSize != 0) { if (size < kHeaderSize + 2) return k_IsArc_Res_NEED_MORE; if (p[kHeaderSize] != 0) return k_IsArc_Res_NO; if (unpackSize != (UInt64)(Int64)-1) { if ((p[kHeaderSize + 1] & 0x80) != 0) return k_IsArc_Res_NO; } } if (!CheckDicSize(p + 1)) // return k_IsArc_Res_YES_LOW_PROB; return k_IsArc_Res_NO; return k_IsArc_Res_YES; } } API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) { if (size < 1) return k_IsArc_Res_NEED_MORE; Byte filterID = p[0]; if (filterID != 0 && filterID != 1) return k_IsArc_Res_NO; return IsArc_Lzma(p + 1, size - 1); } } STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) { Close(); const UInt32 kBufSize = 1 + 5 + 8 + 2; Byte buf[kBufSize]; RINOK(ReadStream_FALSE(inStream, buf, kBufSize)); if (!_header.Parse(buf, _lzma86)) return S_FALSE; const Byte *start = buf + GetHeaderSize(); if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 return S_FALSE; RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize)); if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0) return S_FALSE; _isArc = true; _stream = inStream; _seqStream = inStream; _needSeekToStart = true; return S_OK; } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); _isArc = true; _seqStream = stream; return S_OK; } STDMETHODIMP CHandler::Close() { _isArc = false; _packSize_Defined = false; _unpackSize_Defined = false; _numStreams_Defined = false; _dataAfterEnd = false; _needMoreInput = false; _unsupported = false; _dataError = false; _packSize = 0; _needSeekToStart = false; _stream.Release(); _seqStream.Release(); return S_OK; } class CCompressProgressInfoImp: public ICompressProgressInfo, public CMyUnknownImp { CMyComPtr Callback; public: UInt64 Offset; MY_UNKNOWN_IMP1(ICompressProgressInfo) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); void Init(IArchiveOpenCallback *callback) { Callback = callback; } }; STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) { if (Callback) { UInt64 files = 0; UInt64 value = Offset + *inSize; return Callback->SetCompleted(&files, &value); } return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; if (_packSize_Defined) extractCallback->SetTotal(_packSize); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); if (!testMode && !realOutStream) return S_OK; extractCallback->PrepareOperation(askMode); CDummyOutStream *outStreamSpec = new CDummyOutStream; CMyComPtr outStream(outStreamSpec); outStreamSpec->SetStream(realOutStream); outStreamSpec->Init(); realOutStream.Release(); CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, true); if (_needSeekToStart) { if (!_stream) return E_FAIL; RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } else _needSeekToStart = true; CDecoder decoder; HRESULT result = decoder.Create( EXTERNAL_CODECS_VARS _lzma86, _seqStream); RINOK(result); bool firstItem = true; UInt64 packSize = 0; UInt64 unpackSize = 0; UInt64 numStreams = 0; bool dataAfterEnd = false; for (;;) { lps->InSize = packSize; lps->OutSize = unpackSize; RINOK(lps->SetCur()); const UInt32 kBufSize = 1 + 5 + 8; Byte buf[kBufSize]; const UInt32 headerSize = GetHeaderSize(); UInt32 processed; RINOK(decoder.ReadInput(buf, headerSize, &processed)); if (processed != headerSize) { if (processed != 0) dataAfterEnd = true; break; } CHeader st; if (!st.Parse(buf, _lzma86)) { dataAfterEnd = true; break; } numStreams++; firstItem = false; result = decoder.Code(st, outStream, progress); packSize = decoder.GetInputProcessedSize(); unpackSize = outStreamSpec->GetSize(); if (result == E_NOTIMPL) { _unsupported = true; result = S_FALSE; break; } if (result == S_FALSE) break; RINOK(result); } if (firstItem) { _isArc = false; result = S_FALSE; } else if (result == S_OK || result == S_FALSE) { if (dataAfterEnd) _dataAfterEnd = true; else if (decoder._lzmaDecoderSpec->NeedMoreInput) _needMoreInput = true; _packSize = packSize; _unpackSize = unpackSize; _numStreams = numStreams; _packSize_Defined = true; _unpackSize_Defined = true; _numStreams_Defined = true; } Int32 opResult = NExtract::NOperationResult::kOK; if (!_isArc) opResult = NExtract::NOperationResult::kIsNotArc; else if (_needMoreInput) opResult = NExtract::NOperationResult::kUnexpectedEnd; else if (_unsupported) opResult = NExtract::NOperationResult::kUnsupportedMethod; else if (_dataAfterEnd) opResult = NExtract::NOperationResult::kDataAfterEnd; else if (result == S_FALSE) opResult = NExtract::NOperationResult::kDataError; else if (result == S_OK) opResult = NExtract::NOperationResult::kOK; else return result; outStream.Release(); return extractCallback->SetOperationResult(opResult); COM_TRY_END } IMPL_ISetCompressCodecsInfo namespace NLzmaAr { IMP_CreateArcIn_2(CHandler(false)) static CArcInfo g_ArcInfo = { "lzma", "lzma", 0, 0xA, 0, { 0 }, // 2, { 0x5D, 0x00 }, 0, NArcInfoFlags::kStartOpen | NArcInfoFlags::kKeepName, CreateArc, NULL, IsArc_Lzma }; REGISTER_ARC(Lzma) } namespace NLzma86Ar { IMP_CreateArcIn_2(CHandler(true)) static CArcInfo g_ArcInfo = { "lzma86", "lzma86", 0, 0xB, 0, { 0 }, 0, NArcInfoFlags::kKeepName, CreateArc, NULL, IsArc_Lzma86 }; REGISTER_ARC(Lzma86) } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/SplitHandler.cpp0100777000000000000000000002041113761647206024275 0ustar00// SplitHandler.cpp #include "StdAfx.h" #include "../../Common/ComTry.h" #include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Compress/CopyCoder.h" #include "Common/MultiStream.h" using namespace NWindows; namespace NArchive { namespace NSplit { static const Byte kProps[] = { kpidPath, kpidSize }; static const Byte kArcProps[] = { kpidNumVolumes, kpidTotalPhySize }; class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { CObjectVector > _streams; CRecordVector _sizes; UString _subName; UInt64 _totalSize; HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; IMP_IInArchive_Props IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidMainSubfile: prop = (UInt32)0; break; case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; case kpidTotalPhySize: prop = _totalSize; break; case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; } prop.Detach(value); return S_OK; } struct CSeqName { UString _unchangedPart; UString _changedPart; bool _splitStyle; UString GetNextName() { UString newName; if (_splitStyle) { int i; int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == 'z') { newName.InsertAtFront('a'); continue; } else if (c == 'Z') { newName.InsertAtFront('A'); continue; } c++; if ((c == 'z' || c == 'Z') && i == 0) { _unchangedPart += c; wchar_t newChar = (c == 'z') ? L'a' : L'A'; newName.Empty(); numLetters++; for (int k = 0; k < numLetters; k++) newName += newChar; break; } newName.InsertAtFront(c); i--; for (; i >= 0; i--) newName.InsertAtFront(_changedPart[i]); break; } } else { int i; int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == '9') { newName.InsertAtFront('0'); if (i == 0) newName.InsertAtFront('1'); continue; } c++; newName.InsertAtFront(c); i--; for (; i >= 0; i--) newName.InsertAtFront(_changedPart[i]); break; } } _changedPart = newName; return _unchangedPart + _changedPart; } }; HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { Close(); if (!callback) return S_FALSE; CMyComPtr volumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); if (!volumeCallback) return S_FALSE; UString name; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidName, &prop)); if (prop.vt != VT_BSTR) return S_FALSE; name = prop.bstrVal; } int dotPos = name.ReverseFind('.'); const UString prefix = name.Left(dotPos + 1); const UString ext = name.Ptr(dotPos + 1); UString ext2 = ext; ext2.MakeLower_Ascii(); CSeqName seqName; unsigned numLetters = 2; bool splitStyle = false; if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) { splitStyle = true; while (numLetters < ext2.Len()) { if (ext2[ext2.Len() - numLetters - 1] != 'a') break; numLetters++; } } else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) { while (numLetters < ext2.Len()) { if (ext2[ext2.Len() - numLetters - 1] != '0') break; numLetters++; } if (numLetters != ext.Len()) return S_FALSE; } else return S_FALSE; seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); seqName._changedPart = ext.RightPtr(numLetters); seqName._splitStyle = splitStyle; if (prefix.Len() < 1) _subName = L"file"; else _subName.SetFrom(prefix, prefix.Len() - 1); UInt64 size; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; } _totalSize += size; _sizes.Add(size); _streams.Add(stream); { UInt64 numFiles = _streams.Size(); RINOK(callback->SetCompleted(&numFiles, NULL)); } for (;;) { const UString fullName = seqName.GetNextName(); CMyComPtr nextStream; HRESULT result = volumeCallback->GetStream(fullName, &nextStream); if (result == S_FALSE) break; if (result != S_OK) return result; if (!stream) break; { NCOM::CPropVariant prop; RINOK(volumeCallback->GetProperty(kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; } _totalSize += size; _sizes.Add(size); _streams.Add(nextStream); { UInt64 numFiles = _streams.Size(); RINOK(callback->SetCompleted(&numFiles, NULL)); } } if (_streams.Size() == 1) { if (splitStyle) return S_FALSE; } return S_OK; } STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN HRESULT res = Open2(stream, callback); if (res != S_OK) Close(); return res; COM_TRY_END } STDMETHODIMP CHandler::Close() { _totalSize = 0; _subName.Empty(); _streams.Clear(); _sizes.Clear(); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _streams.IsEmpty() ? 0 : 1; return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidPath: prop = _subName; break; case kpidSize: case kpidPackSize: prop = _totalSize; break; } prop.Detach(value); return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; UInt64 currentTotalSize = 0; RINOK(extractCallback->SetTotal(_totalSize)); CMyComPtr outStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &outStream, askMode)); if (!testMode && !outStream) return S_OK; RINOK(extractCallback->PrepareOperation(askMode)); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); FOR_VECTOR (i, _streams) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); IInStream *inStream = _streams[i]; RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); currentTotalSize += copyCoderSpec->TotalSize; } outStream.Release(); return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN if (index != 0) return E_INVALIDARG; *stream = 0; CMultiStream *streamSpec = new CMultiStream; CMyComPtr streamTemp = streamSpec; FOR_VECTOR (i, _streams) { CMultiStream::CSubStreamInfo subStreamInfo; subStreamInfo.Stream = _streams[i]; subStreamInfo.Size = _sizes[i]; streamSpec->Streams.Add(subStreamInfo); } streamSpec->Init(); *stream = streamTemp.Detach(); return S_OK; COM_TRY_END } IMP_CreateArcIn static CArcInfo g_ArcInfo = { "Split", "001", 0, 0xEA, 0, { 0 }, 0, 0, CreateArc }; REGISTER_ARC(Split) }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/StdAfx.h0100777000000000000000000000013513761647206022543 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Archive/XzHandler.cpp0100777000000000000000000005346413761647206023621 0ustar00// XzHandler.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../../../C/XzCrc64.h" #include "../../../C/XzEnc.h" #include "../../Common/ComTry.h" #include "../../Common/Defs.h" #include "../../Common/IntToString.h" #include "../ICoder.h" #include "../Common/CWrappers.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" #include "IArchive.h" #include "Common/HandlerOut.h" using namespace NWindows; namespace NCompress { namespace NLzma2 { HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); }} static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; namespace NArchive { namespace NXz { struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; static const wchar_t *k_LZMA2_Name = L"LZMA2"; struct CStatInfo { UInt64 InSize; UInt64 OutSize; UInt64 PhySize; UInt64 NumStreams; UInt64 NumBlocks; bool UnpackSize_Defined; bool NumStreams_Defined; bool NumBlocks_Defined; bool IsArc; bool UnexpectedEnd; bool DataAfterEnd; bool Unsupported; bool HeadersError; bool DataError; bool CrcError; CStatInfo() { Clear(); } void Clear() { InSize = 0; OutSize = 0; PhySize = 0; NumStreams = 0; NumBlocks = 0; UnpackSize_Defined = false; NumStreams_Defined = false; NumBlocks_Defined = false; UnexpectedEnd = false; DataAfterEnd = false; Unsupported = false; HeadersError = false; DataError = false; CrcError = false; IsArc = false; } }; struct IDecodeState: public CStatInfo { SRes DecodeRes; IDecodeState(): DecodeRes(SZ_OK) {} virtual HRESULT Progress() = 0; HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream); }; struct CVirtProgress_To_LocalProgress: public IDecodeState { CLocalProgress *lps; CMyComPtr progress; HRESULT Progress(); }; HRESULT CVirtProgress_To_LocalProgress::Progress() { lps->InSize = InSize; lps->OutSize = OutSize; return lps->SetCur(); } class CHandler: public IInArchive, public IArchiveOpenSeq, #ifndef EXTRACT_ONLY public IOutArchive, public ISetProperties, public CMultiMethodProps, #endif public CMyUnknownImp { CStatInfo _stat; bool _isArc; bool _needSeekToStart; bool _phySize_Defined; CMyComPtr _stream; CMyComPtr _seqStream; UInt32 _filterId; AString _methodsString; void Init() { _filterId = 0; CMultiMethodProps::Init(); } HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress) { RINOK(progress.Decode(seqInStream, outStream)); _stat = progress; _phySize_Defined = true; return S_OK; } public: MY_QUERYINTERFACE_BEGIN2(IInArchive) MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq) #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY(IOutArchive) MY_QUERYINTERFACE_ENTRY(ISetProperties) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE INTERFACE_IInArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif CHandler(); }; CHandler::CHandler() { Init(); } static const Byte kProps[] = { kpidSize, kpidPackSize, kpidMethod }; static const Byte kArcProps[] = { kpidMethod, kpidNumStreams, kpidNumBlocks }; IMP_IInArchive_Props IMP_IInArchive_ArcProps static inline char GetHex(unsigned value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } static inline void AddHexToString(AString &s, Byte value) { s += GetHex(value >> 4); s += GetHex(value & 0xF); } static void AddUInt32ToString(AString &s, UInt32 value) { char temp[16]; ConvertUInt32ToString(value, temp); s += temp; } static void Lzma2PropToString(AString &s, unsigned prop) { char c = 0; UInt32 size; if ((prop & 1) == 0) size = prop / 2 + 12; else { c = 'k'; size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1); if (prop > 17) { size >>= 10; c = 'm'; } } AddUInt32ToString(s, size); if (c != 0) s += c; } struct CMethodNamePair { UInt32 Id; const char *Name; }; static const CMethodNamePair g_NamePairs[] = { { XZ_ID_Subblock, "SB" }, { XZ_ID_Delta, "Delta" }, { XZ_ID_X86, "BCJ" }, { XZ_ID_PPC, "PPC" }, { XZ_ID_IA64, "IA64" }, { XZ_ID_ARM, "ARM" }, { XZ_ID_ARMT, "ARMT" }, { XZ_ID_SPARC, "SPARC" }, { XZ_ID_LZMA2, "LZMA2" } }; static AString GetMethodString(const CXzFilter &f) { const char *p = NULL; for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++) if (g_NamePairs[i].Id == f.id) { p = g_NamePairs[i].Name; break; } char temp[32]; if (!p) { ::ConvertUInt64ToString(f.id, temp); p = temp; } AString s = p; if (f.propsSize > 0) { s += ':'; if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) Lzma2PropToString(s, f.props[0]); else if (f.id == XZ_ID_Delta && f.propsSize == 1) AddUInt32ToString(s, (UInt32)f.props[0] + 1); else { s += '['; for (UInt32 bi = 0; bi < f.propsSize; bi++) AddHexToString(s, f.props[bi]); s += ']'; } } return s; } static void AddString(AString &dest, const AString &src) { if (!dest.IsEmpty()) dest += ' '; dest += src; } static const char *kChecks[] = { "NoCheck" , "CRC32" , NULL , NULL , "CRC64" , NULL , NULL , NULL , NULL , NULL , "SHA256" , NULL , NULL , NULL , NULL , NULL }; static AString GetCheckString(const CXzs &xzs) { size_t i; UInt32 mask = 0; for (i = 0; i < xzs.num; i++) mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags)); AString s; for (i = 0; i <= XZ_CHECK_MASK; i++) if (((mask >> i) & 1) != 0) { AString s2; if (kChecks[i]) s2 = kChecks[i]; else { s2 = "Check-"; AddUInt32ToString(s2, (UInt32)i); } AddString(s, s2); } return s; } STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; switch (propID) { case kpidPhySize: if (_phySize_Defined) prop = _stat.PhySize; break; case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break; case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break; case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; case kpidErrorFlags: { UInt32 v = 0; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError; if (_stat.Unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_stat.DataError) v |= kpv_ErrorFlags_DataError; if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError; prop = v; } } prop.Detach(value); return S_OK; COM_TRY_END } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = 1; return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; switch (propID) { case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; case kpidPackSize: if (_phySize_Defined) prop = _stat.PhySize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; } prop.Detach(value); return S_OK; COM_TRY_END } struct COpenCallbackWrap { ICompressProgress p; IArchiveOpenCallback *OpenCallback; HRESULT Res; COpenCallbackWrap(IArchiveOpenCallback *progress); }; static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */) { COpenCallbackWrap *p = (COpenCallbackWrap *)pp; p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); return (SRes)p->Res; } COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback) { p.Progress = OpenCallbackProgress; OpenCallback = callback; Res = SZ_OK; } struct CXzsCPP { CXzs p; CXzsCPP() { Xzs_Construct(&p); } ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } }; struct CVirtProgress_To_OpenProgress: public IDecodeState { IArchiveOpenCallback *Callback; UInt64 Offset; HRESULT Progress(); }; HRESULT CVirtProgress_To_OpenProgress::Progress() { if (Callback) { UInt64 files = 0; UInt64 value = Offset + InSize; return Callback->SetCompleted(&files, &value); } return S_OK; } static HRESULT SRes_to_Open_HRESULT(SRes res) { switch (res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PROGRESS: return E_ABORT; /* case SZ_ERROR_UNSUPPORTED: case SZ_ERROR_CRC: case SZ_ERROR_DATA: case SZ_ERROR_ARCHIVE: case SZ_ERROR_NO_ARCHIVE: return S_FALSE; */ } return S_FALSE; } HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) { _needSeekToStart = true; { CXzStreamFlags st; CSeqInStreamWrap inStreamWrap(inStream); SRes res = Xz_ReadHeader(&st, &inStreamWrap.p); if (res != SZ_OK) return SRes_to_Open_HRESULT(res); { CXzBlock block; Bool isIndex; UInt32 headerSizeRes; SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes); if (res2 == SZ_OK && !isIndex) { unsigned numFilters = XzBlock_GetNumFilters(&block); for (unsigned i = 0; i < numFilters; i++) AddString(_methodsString, GetMethodString(block.filters[i])); } } } RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize)); RINOK(callback->SetTotal(NULL, &_stat.PhySize)); CSeekInStreamWrap inStreamImp(inStream); CLookToRead lookStream; LookToRead_CreateVTable(&lookStream, True); lookStream.realStream = &inStreamImp.p; LookToRead_Init(&lookStream); COpenCallbackWrap openWrap(callback); CXzsCPP xzs; Int64 startPosition; SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &g_Alloc); if (res == SZ_ERROR_PROGRESS) return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; /* if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) res = SZ_OK; */ if (res == SZ_OK && startPosition == 0) { _phySize_Defined = true; _stat.OutSize = Xzs_GetUnpackSize(&xzs.p); _stat.UnpackSize_Defined = true; _stat.NumStreams = xzs.p.num; _stat.NumStreams_Defined = true; _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p); _stat.NumBlocks_Defined = true; AddString(_methodsString, GetCheckString(xzs.p)); } else { res = SZ_OK; } RINOK(SRes_to_Open_HRESULT(res)); _stream = inStream; _seqStream = inStream; _isArc = true; return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN { Close(); return Open2(inStream, /* 0, */ callback); } COM_TRY_END } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); _seqStream = stream; _isArc = true; _needSeekToStart = false; return S_OK; } STDMETHODIMP CHandler::Close() { _stat.Clear(); _isArc = false; _needSeekToStart = false; _phySize_Defined = false; _methodsString.Empty(); _stream.Release(); _seqStream.Release(); return S_OK; } class CSeekToSeqStream: public IInStream, public CMyUnknownImp { public: CMyComPtr Stream; MY_UNKNOWN_IMP1(IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize) { return Stream->Read(data, size, processedSize); } STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; } struct CXzUnpackerCPP { Byte *InBuf; Byte *OutBuf; CXzUnpacker p; CXzUnpackerCPP(): InBuf(0), OutBuf(0) { XzUnpacker_Construct(&p, &g_Alloc); } ~CXzUnpackerCPP() { XzUnpacker_Free(&p); MyFree(InBuf); MyFree(OutBuf); } }; HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream) { const size_t kInBufSize = 1 << 15; const size_t kOutBufSize = 1 << 21; DecodeRes = SZ_OK; CXzUnpackerCPP xzu; XzUnpacker_Init(&xzu.p); xzu.InBuf = (Byte *)MyAlloc(kInBufSize); xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); if (!xzu.InBuf || !xzu.OutBuf) return E_OUTOFMEMORY; UInt32 inSize = 0; SizeT inPos = 0; SizeT outPos = 0; for (;;) { if (inPos == inSize) { inPos = inSize = 0; RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize)); } SizeT inLen = inSize - inPos; SizeT outLen = kOutBufSize - outPos; ECoderStatus status; SRes res = XzUnpacker_Code(&xzu.p, xzu.OutBuf + outPos, &outLen, xzu.InBuf + inPos, &inLen, (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status); inPos += inLen; outPos += outLen; InSize += inLen; OutSize += outLen; DecodeRes = res; bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK); if (outStream) { if (outPos == kOutBufSize || finished) { if (outPos != 0) { RINOK(WriteStream(outStream, xzu.OutBuf, outPos)); outPos = 0; } } } else outPos = 0; RINOK(Progress()); if (finished) { PhySize = InSize; NumStreams = xzu.p.numStartedStreams; if (NumStreams > 0) IsArc = true; NumBlocks = xzu.p.numTotalBlocks; UnpackSize_Defined = true; NumStreams_Defined = true; NumBlocks_Defined = true; UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p); if (res == SZ_OK) { if (status == CODER_STATUS_NEEDS_MORE_INPUT) { extraSize = 0; if (!XzUnpacker_IsStreamWasFinished(&xzu.p)) { // finished at padding bytes, but padding is not aligned for 4 UnexpectedEnd = true; res = SZ_ERROR_DATA; } } else // status == CODER_STATUS_NOT_FINISHED res = SZ_ERROR_DATA; } else if (res == SZ_ERROR_NO_ARCHIVE) { if (InSize == extraSize) IsArc = false; else { if (extraSize != 0 || inPos != inSize) { DataAfterEnd = true; res = SZ_OK; } } } DecodeRes = res; PhySize -= extraSize; switch (res) { case SZ_OK: break; case SZ_ERROR_NO_ARCHIVE: IsArc = false; break; case SZ_ERROR_ARCHIVE: HeadersError = true; break; case SZ_ERROR_UNSUPPORTED: Unsupported = true; break; case SZ_ERROR_CRC: CrcError = true; break; case SZ_ERROR_DATA: DataError = true; break; default: DataError = true; break; } break; } } return S_OK; } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; extractCallback->SetTotal(_stat.PhySize); UInt64 currentTotalPacked = 0; RINOK(extractCallback->SetCompleted(¤tTotalPacked)); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); if (!testMode && !realOutStream) return S_OK; extractCallback->PrepareOperation(askMode); CVirtProgress_To_LocalProgress vp; vp.lps = new CLocalProgress; vp.progress = vp.lps; vp.lps->Init(extractCallback, true); if (_needSeekToStart) { if (!_stream) return E_FAIL; RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } else _needSeekToStart = true; RINOK(Decode2(_seqStream, realOutStream, vp)); Int32 opRes; if (!vp.IsArc) opRes = NExtract::NOperationResult::kIsNotArc; else if (vp.UnexpectedEnd) opRes = NExtract::NOperationResult::kUnexpectedEnd; else if (vp.DataAfterEnd) opRes = NExtract::NOperationResult::kDataAfterEnd; else if (vp.CrcError) opRes = NExtract::NOperationResult::kCRCError; else if (vp.Unsupported) opRes = NExtract::NOperationResult::kUnsupportedMethod; else if (vp.HeadersError) opRes = NExtract::NOperationResult::kDataError; else if (vp.DataError) opRes = NExtract::NOperationResult::kDataError; else if (vp.DecodeRes != SZ_OK) opRes = NExtract::NOperationResult::kDataError; else opRes = NExtract::NOperationResult::kOK; realOutStream.Release(); return extractCallback->SetOperationResult(opRes); COM_TRY_END } #ifndef EXTRACT_ONLY STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { *timeType = NFileTimeType::kUnix; return S_OK; } STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { CSeqOutStreamWrap seqOutStream(outStream); if (numItems == 0) { SRes res = Xz_EncodeEmpty(&seqOutStream.p); return SResToHRESULT(res); } if (numItems != 1) return E_INVALIDARG; Int32 newData, newProps; UInt32 indexInArchive; if (!updateCallback) return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); if (IntToBool(newProps)) { { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); if (prop.vt != VT_EMPTY) if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) return E_INVALIDARG; } } if (IntToBool(newData)) { UInt64 size; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; RINOK(updateCallback->SetTotal(size)); } CLzma2EncProps lzma2Props; Lzma2EncProps_Init(&lzma2Props); lzma2Props.lzmaProps.level = GetLevel(); CMyComPtr fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); CSeqInStreamWrap seqInStream(fileInStream); { NCOM::CPropVariant prop = (UInt64)size; RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props)); } FOR_VECTOR (i, _methods) { COneMethodInfo &m = _methods[i]; SetGlobalLevelAndThreads(m #ifndef _7ZIP_ST , _numThreads #endif ); { FOR_VECTOR (j, m.Props) { const CProp &prop = m.Props[j]; RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props)); } } } #ifndef _7ZIP_ST lzma2Props.numTotalThreads = _numThreads; #endif CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(updateCallback, true); CCompressProgressWrap progressWrap(progress); CXzProps xzProps; CXzFilterProps filter; XzProps_Init(&xzProps); XzFilterProps_Init(&filter); xzProps.lzma2Props = &lzma2Props; xzProps.filterProps = (_filterId != 0 ? &filter : NULL); switch (_crcSize) { case 0: xzProps.checkId = XZ_CHECK_NO; break; case 4: xzProps.checkId = XZ_CHECK_CRC32; break; case 8: xzProps.checkId = XZ_CHECK_CRC64; break; case 32: xzProps.checkId = XZ_CHECK_SHA256; break; default: return E_INVALIDARG; } filter.id = _filterId; if (_filterId == XZ_ID_Delta) { bool deltaDefined = false; FOR_VECTOR (j, _filterMethod.Props) { const CProp &prop = _filterMethod.Props[j]; if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) { UInt32 delta = (UInt32)prop.Value.ulVal; if (delta < 1 || delta > 256) return E_INVALIDARG; filter.delta = delta; deltaDefined = true; } } if (!deltaDefined) return E_INVALIDARG; } SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &xzProps, &progressWrap.p); if (res == SZ_OK) return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); return SResToHRESULT(res); } if (indexInArchive != 0) return E_INVALIDARG; if (_stream) RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); return NCompress::CopyStream(_stream, outStream, NULL); } STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN Init(); for (UInt32 i = 0; i < numProps; i++) { RINOK(SetProperty(names[i], values[i])); } if (!_filterMethod.MethodName.IsEmpty()) { unsigned k; for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++) { const CMethodNamePair &pair = g_NamePairs[k]; if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name)) { _filterId = pair.Id; break; } } if (k == ARRAY_SIZE(g_NamePairs)) return E_INVALIDARG; } _methods.DeleteFrontal(GetNumEmptyMethods()); if (_methods.Size() > 1) return E_INVALIDARG; if (_methods.Size() == 1) { UString &methodName = _methods[0].MethodName; if (methodName.IsEmpty()) methodName = k_LZMA2_Name; else if (!methodName.IsEqualToNoCase(k_LZMA2_Name)) return E_INVALIDARG; } return S_OK; COM_TRY_END } #endif IMP_CreateArcIn IMP_CreateArcOut static CArcInfo g_ArcInfo = { "xz", "xz txz", "* .tar", 0xC, 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 }, 0, NArcInfoFlags::kKeepName, REF_CreateArc_Pair }; REGISTER_ARC(xz) }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/0040777000000000000000000000000013761647206021051 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/Common.pri0100777000000000000000000000361213761647206023017 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Common/CWrappers.h \ $$7ZIP_BASE/CPP/7zip/Common/CreateCoder.h \ $$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.h \ $$7ZIP_BASE/CPP/7zip/Common/FileStreams.h \ $$7ZIP_BASE/CPP/7zip/Common/FilterCoder.h \ $$7ZIP_BASE/CPP/7zip/Common/InBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.h \ $$7ZIP_BASE/CPP/7zip/Common/LockedStream.h \ $$7ZIP_BASE/CPP/7zip/Common/MethodId.h \ $$7ZIP_BASE/CPP/7zip/Common/MethodProps.h \ $$7ZIP_BASE/CPP/7zip/Common/OutBuffer.h \ $$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.h \ $$7ZIP_BASE/CPP/7zip/Common/RegisterArc.h \ $$7ZIP_BASE/CPP/7zip/Common/RegisterCodec.h \ $$7ZIP_BASE/CPP/7zip/Common/StdAfx.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamBinder.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamObjects.h \ $$7ZIP_BASE/CPP/7zip/Common/StreamUtils.h \ $$7ZIP_BASE/CPP/7zip/Common/UniqBlocks.h \ $$7ZIP_BASE/CPP/7zip/Common/VirtThread.h SOURCES += $$7ZIP_BASE/CPP/7zip/Common/CWrappers.cpp \ $$7ZIP_BASE/CPP/7zip/Common/CreateCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FileStreams.cpp \ $$7ZIP_BASE/CPP/7zip/Common/FilterCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/InBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.cpp \ $$7ZIP_BASE/CPP/7zip/Common/LockedStream.cpp \ $$7ZIP_BASE/CPP/7zip/Common/MethodProps.cpp \ $$7ZIP_BASE/CPP/7zip/Common/OutBuffer.cpp \ $$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Common/PropId.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamBinder.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamObjects.cpp \ $$7ZIP_BASE/CPP/7zip/Common/StreamUtils.cpp \ $$7ZIP_BASE/CPP/7zip/Common/UniqBlocks.cpp \ $$7ZIP_BASE/CPP/7zip/Common/VirtThread.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.cpp0100777000000000000000000002406713761647206023746 0ustar00// CreateCoder.cpp #include "StdAfx.h" #include "../../Windows/Defs.h" #include "../../Windows/PropVariant.h" #include "CreateCoder.h" #include "FilterCoder.h" #include "RegisterCodec.h" static const unsigned int kNumCodecsMax = 64; unsigned int g_NumCodecs = 0; const CCodecInfo *g_Codecs[kNumCodecsMax]; void RegisterCodec(const CCodecInfo *codecInfo) throw() { if (g_NumCodecs < kNumCodecsMax) g_Codecs[g_NumCodecs++] = codecInfo; } static const unsigned int kNumHashersMax = 16; unsigned int g_NumHashers = 0; const CHasherInfo *g_Hashers[kNumHashersMax]; void RegisterHasher(const CHasherInfo *hashInfo) throw() { if (g_NumHashers < kNumHashersMax) g_Hashers[g_NumHashers++] = hashInfo; } #ifdef EXTERNAL_CODECS static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) { NWindows::NCOM::CPropVariant prop; RINOK(codecsInfo->GetProperty(index, propID, &prop)); if (prop.vt == VT_EMPTY) res = 1; else if (prop.vt == VT_UI4) res = prop.ulVal; else return E_INVALIDARG; return S_OK; } static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) { NWindows::NCOM::CPropVariant prop; RINOK(codecsInfo->GetProperty(index, propID, &prop)); if (prop.vt == VT_EMPTY) res = true; else if (prop.vt == VT_BOOL) res = VARIANT_BOOLToBool(prop.boolVal); else return E_INVALIDARG; return S_OK; } HRESULT CExternalCodecs::LoadCodecs() { if (GetCodecs) { UInt32 num; RINOK(GetCodecs->GetNumberOfMethods(&num)); for (UInt32 i = 0; i < num; i++) { CCodecInfoEx info; NWindows::NCOM::CPropVariant prop; RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)); // if (prop.vt != VT_BSTR) // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal); // memcpy(info.Id.ID, prop.bstrVal, info.Id.IDSize); if (prop.vt != VT_UI8) continue; // old Interface info.Id = prop.uhVal.QuadPart; prop.Clear(); RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)); if (prop.vt == VT_BSTR) info.Name = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_INVALIDARG; RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kInStreams, info.NumInStreams)); RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kOutStreams, info.NumOutStreams)); RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)); RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)); Codecs.Add(info); } } if (GetHashers) { UInt32 num = GetHashers->GetNumHashers(); for (UInt32 i = 0; i < num; i++) { CHasherInfoEx info; NWindows::NCOM::CPropVariant prop; RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) continue; info.Id = prop.uhVal.QuadPart; prop.Clear(); RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)); if (prop.vt == VT_BSTR) info.Name = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_INVALIDARG; Hashers.Add(info); } } return S_OK; } #endif bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (name.IsEqualToNoCase(codec.Name)) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = 1; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (codec.Name.IsEqualToNoCase(name)) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = codec.NumOutStreams; return true; } } #endif return false; } bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (methodId == codec.Id) { name = codec.Name; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (methodId == codec.Id) { name = codec.Name; return true; } } #endif return false; } bool FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId) { UInt32 i; for (i = 0; i < g_NumHashers; i++) { const CHasherInfo &codec = *g_Hashers[i]; if (name.IsEqualToNoCase(codec.Name)) { methodId = codec.Id; return true; } } #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) { const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; if (codec.Name.IsEqualToNoCase(name)) { methodId = codec.Id; return true; } } #endif return false; } void GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector &methods) { methods.ClearAndSetSize(g_NumHashers); UInt32 i; for (i = 0; i < g_NumHashers; i++) methods[i] = (*g_Hashers[i]).Id; #ifdef EXTERNAL_CODECS if (__externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) methods.Add(__externalCodecs->Hashers[i].Id); #endif } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, CMyComPtr &coder, CMyComPtr &coder2, bool encode, bool onlyCoder) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (codec.Id == methodId) { if (encode) { if (codec.CreateEncoder) { void *p = codec.CreateEncoder(); if (codec.IsFilter) filter = (ICompressFilter *)p; else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; else coder2 = (ICompressCoder2 *)p; break; } } else if (codec.CreateDecoder) { void *p = codec.CreateDecoder(); if (codec.IsFilter) filter = (ICompressFilter *)p; else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; else coder2 = (ICompressCoder2 *)p; break; } } } #ifdef EXTERNAL_CODECS if (!filter && !coder && !coder2 && __externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) { const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; if (codec.Id == methodId) { if (encode) { if (codec.EncoderIsAssigned) { if (codec.IsSimpleCodec()) { HRESULT result = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder); if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) return result; if (!coder) { RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter)); } } else { RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2)); } break; } } else if (codec.DecoderIsAssigned) { if (codec.IsSimpleCodec()) { HRESULT result = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder); if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) return result; if (!coder) { RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter)); } } else { RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2)); } break; } } } #endif if (onlyCoder && filter) { CFilterCoder *coderSpec = new CFilterCoder; coder = coderSpec; coderSpec->Filter = filter; } return S_OK; } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, CMyComPtr &coder2, bool encode) { CMyComPtr filter; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, filter, coder, coder2, encode, true); } HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, bool encode) { CMyComPtr filter; CMyComPtr coder2; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, coder, coder2, encode); } HRESULT CreateFilter( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, bool encode) { CMyComPtr coder; CMyComPtr coder2; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, filter, coder, coder2, encode, false); } HRESULT CreateHasher( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name, CMyComPtr &hasher) { UInt32 i; for (i = 0; i < g_NumHashers; i++) { const CHasherInfo &codec = *g_Hashers[i]; if (codec.Id == methodId) { hasher = (IHasher *)codec.CreateHasher(); name = codec.Name; break; } } #ifdef EXTERNAL_CODECS if (!hasher && __externalCodecs) for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) { const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; if (codec.Id == methodId) { name = codec.Name; return __externalCodecs->GetHashers->CreateHasher(i, &hasher); } } #endif return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.h0100777000000000000000000000655013761647206023410 0ustar00// CreateCoder.h #ifndef __CREATE_CODER_H #define __CREATE_CODER_H #include "../../Common/MyCom.h" #include "../../Common/MyString.h" #include "../ICoder.h" #include "MethodId.h" #ifdef EXTERNAL_CODECS struct CCodecInfoEx { UString Name; CMethodId Id; UInt32 NumInStreams; UInt32 NumOutStreams; bool EncoderIsAssigned; bool DecoderIsAssigned; bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; } CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {} }; struct CHasherInfoEx { UString Name; CMethodId Id; }; #define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo, #define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo) #define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo); #define IMPL_ISetCompressCodecsInfo2(x) \ STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \ COM_TRY_BEGIN __externalCodecs.GetCodecs = compressCodecsInfo; return __externalCodecs.LoadCodecs(); COM_TRY_END } #define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler) struct CExternalCodecs { CMyComPtr GetCodecs; CMyComPtr GetHashers; CObjectVector Codecs; CObjectVector Hashers; HRESULT LoadCodecs(); }; #define EXTERNAL_CODECS_VARS2 &__externalCodecs #define DECL_EXTERNAL_CODECS_VARS CExternalCodecs __externalCodecs; #define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2, #define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *__externalCodecs #define EXTERNAL_CODECS_LOC_VARS2 __externalCodecs #define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2, #define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2, #else #define PUBLIC_ISetCompressCodecsInfo #define QUERY_ENTRY_ISetCompressCodecsInfo #define DECL_ISetCompressCodecsInfo #define IMPL_ISetCompressCodecsInfo #define EXTERNAL_CODECS_VARS2 #define DECL_EXTERNAL_CODECS_VARS #define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2 #define DECL_EXTERNAL_CODECS_LOC_VARS2 #define EXTERNAL_CODECS_LOC_VARS2 #define DECL_EXTERNAL_CODECS_LOC_VARS #define EXTERNAL_CODECS_LOC_VARS #endif bool FindMethod( DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams); bool FindMethod( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name); bool FindHashMethod( DECL_EXTERNAL_CODECS_LOC_VARS const UString &name, CMethodId &methodId); void GetHashMethods( DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector &methods); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, CMyComPtr &coder, CMyComPtr &coder2, bool encode, bool onlyCoder); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, CMyComPtr &coder2, bool encode); HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &coder, bool encode); HRESULT CreateFilter( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr &filter, bool encode); HRESULT CreateHasher( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, UString &name, CMyComPtr &hacher); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/CWrappers.cpp0100777000000000000000000001173613761647206023473 0ustar00// CWrappers.h #include "StdAfx.h" #include "../../../C/Alloc.h" #include "CWrappers.h" #include "StreamUtils.h" #define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1) #define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x) static SRes CompressProgress(void *pp, UInt64 inSize, UInt64 outSize) throw() { CCompressProgressWrap *p = (CCompressProgressWrap *)pp; p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize)); return (SRes)p->Res; } CCompressProgressWrap::CCompressProgressWrap(ICompressProgressInfo *progress) throw() { p.Progress = CompressProgress; Progress = progress; Res = SZ_OK; } static const UInt32 kStreamStepSize = (UInt32)1 << 31; SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) { switch (res) { case S_OK: return SZ_OK; case E_OUTOFMEMORY: return SZ_ERROR_MEM; case E_INVALIDARG: return SZ_ERROR_PARAM; case E_ABORT: return SZ_ERROR_PROGRESS; case S_FALSE: return SZ_ERROR_DATA; case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED; } return defaultRes; } static SRes MyRead(void *object, void *data, size_t *size) throw() { CSeqInStreamWrap *p = (CSeqInStreamWrap *)object; UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); p->Res = (p->Stream->Read(data, curSize, &curSize)); *size = curSize; p->Processed += curSize; if (p->Res == S_OK) return SZ_OK; return HRESULT_To_SRes(p->Res, SZ_ERROR_READ); } static size_t MyWrite(void *object, const void *data, size_t size) throw() { CSeqOutStreamWrap *p = (CSeqOutStreamWrap *)object; if (p->Stream) { p->Res = WriteStream(p->Stream, data, size); if (p->Res != 0) return 0; } else p->Res = S_OK; p->Processed += size; return size; } CSeqInStreamWrap::CSeqInStreamWrap(ISequentialInStream *stream) throw() { p.Read = MyRead; Stream = stream; Processed = 0; } CSeqOutStreamWrap::CSeqOutStreamWrap(ISequentialOutStream *stream) throw() { p.Write = MyWrite; Stream = stream; Res = SZ_OK; Processed = 0; } HRESULT SResToHRESULT(SRes res) throw() { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; case SZ_ERROR_PROGRESS: return E_ABORT; case SZ_ERROR_DATA: return S_FALSE; case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; } return E_FAIL; } static SRes InStreamWrap_Read(void *pp, void *data, size_t *size) throw() { CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp; UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); p->Res = p->Stream->Read(data, curSize, &curSize); *size = curSize; return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; } static SRes InStreamWrap_Seek(void *pp, Int64 *offset, ESzSeek origin) throw() { CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp; UInt32 moveMethod; switch(origin) { case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break; case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break; case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break; default: return SZ_ERROR_PARAM; } UInt64 newPosition; p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition); *offset = (Int64)newPosition; return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; } CSeekInStreamWrap::CSeekInStreamWrap(IInStream *stream) throw() { Stream = stream; p.Read = InStreamWrap_Read; p.Seek = InStreamWrap_Seek; Res = S_OK; } /* ---------- CByteInBufWrap ---------- */ void CByteInBufWrap::Free() throw() { ::MidFree(Buf); Buf = 0; } bool CByteInBufWrap::Alloc(UInt32 size) throw() { if (Buf == 0 || size != Size) { Free(); Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size); Size = size; } return (Buf != 0); } Byte CByteInBufWrap::ReadByteFromNewBlock() throw() { if (Res == S_OK) { UInt32 avail; Processed += (Cur - Buf); Res = Stream->Read(Buf, Size, &avail); Cur = Buf; Lim = Buf + avail; if (avail != 0) return *Cur++; } Extra = true; return 0; } static Byte Wrap_ReadByte(void *pp) throw() { CByteInBufWrap *p = (CByteInBufWrap *)pp; if (p->Cur != p->Lim) return *p->Cur++; return p->ReadByteFromNewBlock(); } CByteInBufWrap::CByteInBufWrap(): Buf(0) { p.Read = Wrap_ReadByte; } /* ---------- CByteOutBufWrap ---------- */ void CByteOutBufWrap::Free() throw() { ::MidFree(Buf); Buf = 0; } bool CByteOutBufWrap::Alloc(size_t size) throw() { if (Buf == 0 || size != Size) { Free(); Buf = (Byte *)::MidAlloc(size); Size = size; } return (Buf != 0); } HRESULT CByteOutBufWrap::Flush() throw() { if (Res == S_OK) { size_t size = (Cur - Buf); Res = WriteStream(Stream, Buf, size); if (Res == S_OK) Processed += size; Cur = Buf; } return Res; } static void Wrap_WriteByte(void *pp, Byte b) throw() { CByteOutBufWrap *p = (CByteOutBufWrap *)pp; Byte *dest = p->Cur; *dest = b; p->Cur = ++dest; if (dest == p->Lim) p->Flush(); } CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(0) { p.Write = Wrap_WriteByte; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/CWrappers.h0100777000000000000000000000370713761647206023137 0ustar00// CWrappers.h #ifndef __C_WRAPPERS_H #define __C_WRAPPERS_H #include "../ICoder.h" #include "../../Common/MyCom.h" struct CCompressProgressWrap { ICompressProgress p; ICompressProgressInfo *Progress; HRESULT Res; CCompressProgressWrap(ICompressProgressInfo *progress) throw(); }; struct CSeqInStreamWrap { ISeqInStream p; ISequentialInStream *Stream; HRESULT Res; UInt64 Processed; CSeqInStreamWrap(ISequentialInStream *stream) throw(); }; struct CSeekInStreamWrap { ISeekInStream p; IInStream *Stream; HRESULT Res; CSeekInStreamWrap(IInStream *stream) throw(); }; struct CSeqOutStreamWrap { ISeqOutStream p; ISequentialOutStream *Stream; HRESULT Res; UInt64 Processed; CSeqOutStreamWrap(ISequentialOutStream *stream) throw(); }; HRESULT SResToHRESULT(SRes res) throw(); struct CByteInBufWrap { IByteIn p; const Byte *Cur; const Byte *Lim; Byte *Buf; UInt32 Size; ISequentialInStream *Stream; UInt64 Processed; bool Extra; HRESULT Res; CByteInBufWrap(); ~CByteInBufWrap() { Free(); } void Free() throw(); bool Alloc(UInt32 size) throw(); void Init() { Lim = Cur = Buf; Processed = 0; Extra = false; Res = S_OK; } UInt64 GetProcessed() const { return Processed + (Cur - Buf); } Byte ReadByteFromNewBlock() throw(); Byte ReadByte() { if (Cur != Lim) return *Cur++; return ReadByteFromNewBlock(); } }; struct CByteOutBufWrap { IByteOut p; Byte *Cur; const Byte *Lim; Byte *Buf; size_t Size; ISequentialOutStream *Stream; UInt64 Processed; HRESULT Res; CByteOutBufWrap() throw(); ~CByteOutBufWrap() { Free(); } void Free() throw(); bool Alloc(size_t size) throw(); void Init() { Cur = Buf; Lim = Buf + Size; Processed = 0; Res = S_OK; } UInt64 GetProcessed() const { return Processed + (Cur - Buf); } HRESULT Flush() throw(); void WriteByte(Byte b) { *Cur++ = b; if (Cur == Lim) Flush(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.cpp0100777000000000000000000000242713761647206025237 0ustar00// FilePathAutoRename.cpp #include "StdAfx.h" #include "../../Common/Defs.h" #include "../../Common/IntToString.h" #include "../../Windows/FileFind.h" #include "FilePathAutoRename.h" using namespace NWindows; static bool MakeAutoName(const FString &name, const FString &extension, unsigned value, FString &path) { FChar number[16]; ConvertUInt32ToString(value, number); path = name; path += number; path += extension; return NFile::NFind::DoesFileOrDirExist(path); } bool AutoRenamePath(FString &fullProcessedPath) { FString path; int dotPos = fullProcessedPath.ReverseFind(FTEXT('.')); int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); #ifdef _WIN32 int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); slashPos = MyMax(slashPos, slash1Pos); #endif FString name, extension; if (dotPos > slashPos && dotPos > 0) { name.SetFrom(fullProcessedPath, dotPos); extension = fullProcessedPath.Ptr(dotPos); } else name = fullProcessedPath; name += L'_'; unsigned left = 1, right = (1 << 30); while (left != right) { unsigned mid = (left + right) / 2; if (MakeAutoName(name, extension, mid, path)) left = mid + 1; else right = mid; } return !MakeAutoName(name, extension, right, fullProcessedPath); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.h0100777000000000000000000000027313761647206024701 0ustar00// FilePathAutoRename.h #ifndef __FILE_PATH_AUTO_RENAME_H #define __FILE_PATH_AUTO_RENAME_H #include "../../Common/MyString.h" bool AutoRenamePath(FString &fullProcessedPath); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FileStreams.cpp0100777000000000000000000002347213761647206024003 0ustar00// FileStreams.cpp #include "StdAfx.h" #ifndef _WIN32 #include #include #include #endif #ifdef SUPPORT_DEVICE_FILE #include "../../../C/Alloc.h" #include "../../Common/Defs.h" #endif #include "FileStreams.h" static inline HRESULT ConvertBoolToHRESULT(bool result) { #ifdef _WIN32 if (result) return S_OK; DWORD lastError = ::GetLastError(); if (lastError == 0) return E_FAIL; return HRESULT_FROM_WIN32(lastError); #else return result ? S_OK: E_FAIL; #endif } #ifdef SUPPORT_DEVICE_FILE static const UInt32 kClusterSize = 1 << 18; CInFileStream::CInFileStream(): VirtPos(0), PhyPos(0), Buf(0), BufSize(0), SupportHardLinks(false) { } #endif CInFileStream::~CInFileStream() { #ifdef SUPPORT_DEVICE_FILE MidFree(Buf); #endif } STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef USE_WIN_FILE #ifdef SUPPORT_DEVICE_FILE if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (File.IsDeviceFile) { if (File.SizeDefined) { if (VirtPos >= File.Size) return VirtPos == File.Size ? S_OK : E_FAIL; UInt64 rem = File.Size - VirtPos; if (size > rem) size = (UInt32)rem; } for (;;) { const UInt32 mask = kClusterSize - 1; const UInt64 mask2 = ~(UInt64)mask; UInt64 alignedPos = VirtPos & mask2; if (BufSize > 0 && BufStartPos == alignedPos) { UInt32 pos = (UInt32)VirtPos & mask; if (pos >= BufSize) return S_OK; UInt32 rem = MyMin(BufSize - pos, size); memcpy(data, Buf + pos, rem); VirtPos += rem; if (processedSize) *processedSize += rem; return S_OK; } bool useBuf = false; if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 ) useBuf = true; else { UInt64 end = VirtPos + size; if ((end & mask) != 0) { end &= mask2; if (end <= VirtPos) useBuf = true; else size = (UInt32)(end - VirtPos); } } if (!useBuf) break; if (alignedPos != PhyPos) { UInt64 realNewPosition; bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition); if (!result) return ConvertBoolToHRESULT(result); PhyPos = realNewPosition; } BufStartPos = alignedPos; UInt32 readSize = kClusterSize; if (File.SizeDefined) readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize); if (!Buf) { Buf = (Byte *)MidAlloc(kClusterSize); if (!Buf) return E_OUTOFMEMORY; } bool result = File.Read1(Buf, readSize, BufSize); if (!result) return ConvertBoolToHRESULT(result); if (BufSize == 0) return S_OK; PhyPos += BufSize; } if (VirtPos != PhyPos) { UInt64 realNewPosition; bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition); if (!result) return ConvertBoolToHRESULT(result); PhyPos = VirtPos = realNewPosition; } } #endif UInt32 realProcessedSize; bool result = File.ReadPart(data, size, realProcessedSize); if (processedSize) *processedSize = realProcessedSize; #ifdef SUPPORT_DEVICE_FILE VirtPos += realProcessedSize; PhyPos += realProcessedSize; #endif return ConvertBoolToHRESULT(result); #else if (processedSize) *processedSize = 0; ssize_t res = File.Read(data, (size_t)size); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; #endif } #ifdef UNDER_CE STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { size_t s2 = fread(data, 1, size, stdin); int error = ferror(stdin); if (processedSize) *processedSize = s2; if (s2 <= size && error == 0) return S_OK; return E_FAIL; } #else STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef _WIN32 DWORD realProcessedSize; UInt32 sizeTemp = (1 << 20); if (sizeTemp > size) sizeTemp = size; BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); if (processedSize) *processedSize = realProcessedSize; if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) return S_OK; return ConvertBoolToHRESULT(res != FALSE); #else if (processedSize) *processedSize = 0; ssize_t res; do { res = read(0, data, (size_t)size); } while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; #endif } #endif STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE #ifdef SUPPORT_DEVICE_FILE if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END)) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += VirtPos; break; case STREAM_SEEK_END: offset += File.Size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; VirtPos = offset; if (newPosition) *newPosition = offset; return S_OK; } #endif UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); #ifdef SUPPORT_DEVICE_FILE PhyPos = VirtPos = realNewPosition; #endif if (newPosition) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); #else off_t res = File.Seek((off_t)offset, seekOrigin); if (res == -1) return E_FAIL; if (newPosition) *newPosition = (UInt64)res; return S_OK; #endif } STDMETHODIMP CInFileStream::GetSize(UInt64 *size) { return ConvertBoolToHRESULT(File.GetLength(*size)); } #ifdef USE_WIN_FILE STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) { BY_HANDLE_FILE_INFORMATION info; if (File.GetFileInformation(&info)) { if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; if (cTime) *cTime = info.ftCreationTime; if (aTime) *aTime = info.ftLastAccessTime; if (mTime) *mTime = info.ftLastWriteTime; if (attrib) *attrib = info.dwFileAttributes; return S_OK; } return GetLastError(); } STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) { BY_HANDLE_FILE_INFORMATION info; if (File.GetFileInformation(&info)) { props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; props->VolID = info.dwVolumeSerialNumber; props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; props->FileID_High = 0; props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; props->Attrib = info.dwFileAttributes; props->CTime = info.ftCreationTime; props->ATime = info.ftLastAccessTime; props->MTime = info.ftLastWriteTime; return S_OK; } return GetLastError(); } #endif ////////////////////////// // COutFileStream HRESULT COutFileStream::Close() { return ConvertBoolToHRESULT(File.Close()); } STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { #ifdef USE_WIN_FILE UInt32 realProcessedSize; bool result = File.WritePart(data, size, realProcessedSize); ProcessedSize += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return ConvertBoolToHRESULT(result); #else if (processedSize) *processedSize = 0; ssize_t res = File.Write(data, (size_t)size); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; ProcessedSize += res; return S_OK; #endif } STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); if (newPosition) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); #else off_t res = File.Seek((off_t)offset, seekOrigin); if (res == -1) return E_FAIL; if (newPosition) *newPosition = (UInt64)res; return S_OK; #endif } STDMETHODIMP COutFileStream::SetSize(UInt64 newSize) { #ifdef USE_WIN_FILE UInt64 currentPos; if (!File.Seek(0, FILE_CURRENT, currentPos)) return E_FAIL; bool result = File.SetLength(newSize); UInt64 currentPos2; result = result && File.Seek(currentPos, currentPos2); return result ? S_OK : E_FAIL; #else return E_FAIL; #endif } #ifdef UNDER_CE STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { size_t s2 = fwrite(data, 1, size, stdout); if (processedSize) *processedSize = s2; return (s2 == size) ? S_OK : E_FAIL; } #else STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; #ifdef _WIN32 UInt32 realProcessedSize; BOOL res = TRUE; if (size > 0) { // Seems that Windows doesn't like big amounts writing to stdout. // So we limit portions by 32KB. UInt32 sizeTemp = (1 << 15); if (sizeTemp > size) sizeTemp = size; res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), data, sizeTemp, (DWORD *)&realProcessedSize, NULL); size -= realProcessedSize; data = (const void *)((const Byte *)data + realProcessedSize); if (processedSize) *processedSize += realProcessedSize; } return ConvertBoolToHRESULT(res != FALSE); #else ssize_t res; do { res = write(1, data, (size_t)size); } while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; if (processedSize) *processedSize = (UInt32)res; return S_OK; return S_OK; #endif } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FileStreams.h0100777000000000000000000000577213761647206023453 0ustar00// FileStreams.h #ifndef __FILE_STREAMS_H #define __FILE_STREAMS_H #ifdef _WIN32 #define USE_WIN_FILE #endif #include "../../Common/MyString.h" #ifdef USE_WIN_FILE #include "../../Windows/FileIO.h" #else #include "../../Common/C_FileIO.h" #endif #include "../../Common/MyCom.h" #include "../IStream.h" class CInFileStream: public IInStream, public IStreamGetSize, #ifdef USE_WIN_FILE public IStreamGetProps, public IStreamGetProps2, #endif public CMyUnknownImp { public: #ifdef USE_WIN_FILE NWindows::NFile::NIO::CInFile File; #ifdef SUPPORT_DEVICE_FILE UInt64 VirtPos; UInt64 PhyPos; UInt64 BufStartPos; Byte *Buf; UInt32 BufSize; #endif #else NC::NFile::NIO::CInFile File; #endif bool SupportHardLinks; virtual ~CInFileStream(); #ifdef SUPPORT_DEVICE_FILE CInFileStream(); #endif bool Open(CFSTR fileName) { return File.Open(fileName); } bool OpenShared(CFSTR fileName, bool shareForWrite) { return File.OpenShared(fileName, shareForWrite); } MY_QUERYINTERFACE_BEGIN2(IInStream) MY_QUERYINTERFACE_ENTRY(IStreamGetSize) #ifdef USE_WIN_FILE MY_QUERYINTERFACE_ENTRY(IStreamGetProps) MY_QUERYINTERFACE_ENTRY(IStreamGetProps2) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(GetSize)(UInt64 *size); #ifdef USE_WIN_FILE STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib); STDMETHOD(GetProps2)(CStreamFileProps *props); #endif }; class CStdInFileStream: public ISequentialInStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP virtual ~CStdInFileStream() {} STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; class COutFileStream: public IOutStream, public CMyUnknownImp { public: #ifdef USE_WIN_FILE NWindows::NFile::NIO::COutFile File; #else NC::NFile::NIO::COutFile File; #endif virtual ~COutFileStream() {} bool Create(CFSTR fileName, bool createAlways) { ProcessedSize = 0; return File.Create(fileName, createAlways); } bool Open(CFSTR fileName, DWORD creationDisposition) { ProcessedSize = 0; return File.Open(fileName, creationDisposition); } HRESULT Close(); UInt64 ProcessedSize; #ifdef USE_WIN_FILE bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) { return File.SetTime(cTime, aTime, mTime); } bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); } #endif MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; class CStdOutFileStream: public ISequentialOutStream, public CMyUnknownImp { public: MY_UNKNOWN_IMP virtual ~CStdOutFileStream() {} STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.cpp0100777000000000000000000001455513761647206023771 0ustar00// FilterCoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../../Common/Defs.h" #include "FilterCoder.h" #include "StreamUtils.h" static const UInt32 kBufferSize = 1 << 17; CFilterCoder::CFilterCoder() { _buffer = (Byte *)::MidAlloc(kBufferSize); if (_buffer == 0) throw 1; } CFilterCoder::~CFilterCoder() { ::MidFree(_buffer); } HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size) { if (_outSizeIsDefined) { UInt64 remSize = _outSize - _nowPos64; if (size > remSize) size = (UInt32)remSize; } RINOK(WriteStream(outStream, _buffer, size)); _nowPos64 += size; return S_OK; } STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { RINOK(Init()); UInt32 bufferPos = 0; _outSizeIsDefined = (outSize != 0); if (_outSizeIsDefined) _outSize = *outSize; while (!_outSizeIsDefined || _nowPos64 < _outSize) { size_t processedSize = kBufferSize - bufferPos; // Change it: It can be optimized using ReadPart RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize)); UInt32 endPos = bufferPos + (UInt32)processedSize; bufferPos = Filter->Filter(_buffer, endPos); if (bufferPos > endPos) { for (; endPos < bufferPos; endPos++) _buffer[endPos] = 0; bufferPos = Filter->Filter(_buffer, endPos); } if (bufferPos == 0) { if (endPos == 0) return S_OK; return WriteWithLimit(outStream, endPos); } RINOK(WriteWithLimit(outStream, bufferPos)); if (progress != NULL) { RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64)); } UInt32 i = 0; while (bufferPos < endPos) _buffer[i++] = _buffer[bufferPos++]; bufferPos = i; } return S_OK; } STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) { _bufferPos = 0; _outStream = outStream; return Init(); } STDMETHODIMP CFilterCoder::ReleaseOutStream() { _outStream.Release(); return S_OK; } STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos); memcpy(_buffer + _bufferPos, data, sizeTemp); size -= sizeTemp; if (processedSize != NULL) *processedSize += sizeTemp; data = (const Byte *)data + sizeTemp; UInt32 endPos = _bufferPos + sizeTemp; _bufferPos = Filter->Filter(_buffer, endPos); if (_bufferPos == 0) { _bufferPos = endPos; break; } if (_bufferPos > endPos) { if (size != 0) return E_FAIL; break; } RINOK(WriteWithLimit(_outStream, _bufferPos)); UInt32 i = 0; while (_bufferPos < endPos) _buffer[i++] = _buffer[_bufferPos++]; _bufferPos = i; } return S_OK; } STDMETHODIMP CFilterCoder::Flush() { if (_bufferPos != 0) { // _buffer contains only data refused by previous Filter->Filter call. UInt32 endPos = Filter->Filter(_buffer, _bufferPos); if (endPos > _bufferPos) { for (; _bufferPos < endPos; _bufferPos++) _buffer[_bufferPos] = 0; if (Filter->Filter(_buffer, endPos) != endPos) return E_FAIL; } RINOK(WriteWithLimit(_outStream, _bufferPos)); _bufferPos = 0; } CMyComPtr flush; _outStream.QueryInterface(IID_IOutStreamFlush, &flush); if (flush) return flush->Flush(); return S_OK; } void CFilterCoder::SetInStream_NoSubFilterInit(ISequentialInStream *inStream) { _convertedPosBegin = _convertedPosEnd = _bufferPos = 0; _inStream = inStream; Init2(); } STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) { SetInStream_NoSubFilterInit(inStream); return Init(); } STDMETHODIMP CFilterCoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_convertedPosBegin != _convertedPosEnd) { UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin); memcpy(data, _buffer + _convertedPosBegin, sizeTemp); _convertedPosBegin += sizeTemp; data = (void *)((Byte *)data + sizeTemp); size -= sizeTemp; if (processedSize != NULL) *processedSize += sizeTemp; break; } UInt32 i; for (i = 0; _convertedPosEnd + i < _bufferPos; i++) _buffer[i] = _buffer[_convertedPosEnd + i]; _bufferPos = i; _convertedPosBegin = _convertedPosEnd = 0; size_t processedSizeTemp = kBufferSize - _bufferPos; RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp)); _bufferPos += (UInt32)processedSizeTemp; _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); if (_convertedPosEnd == 0) { if (_bufferPos == 0) break; _convertedPosEnd = _bufferPos; // check it continue; } if (_convertedPosEnd > _bufferPos) { for (; _bufferPos < _convertedPosEnd; _bufferPos++) _buffer[_bufferPos] = 0; _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); } } return S_OK; } #ifndef _NO_CRYPTO STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) { return _setPassword->CryptoSetPassword(data, size); } STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size) { return _cryptoProperties->SetKey(data, size); } STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size) { return _cryptoProperties->SetInitVector(data, size); } #endif #ifndef EXTRACT_ONLY STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *properties, UInt32 numProperties) { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); } STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream) { return _writeCoderProperties->WriteCoderProperties(outStream); } /* STDMETHODIMP CFilterCoder::ResetSalt() { return _CryptoResetSalt->ResetSalt(); } */ STDMETHODIMP CFilterCoder::ResetInitVector() { return _CryptoResetInitVector->ResetInitVector(); } #endif STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) { return _setDecoderProperties->SetDecoderProperties2(data, size); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.h0100777000000000000000000001042213761647206023423 0ustar00// FilterCoder.h #ifndef __FILTER_CODER_H #define __FILTER_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../IPassword.h" #define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \ { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ *outObject = (void *)(i *)this; } class CFilterCoder: public ICompressCoder, public ICompressSetInStream, public ISequentialInStream, public ICompressSetOutStream, public ISequentialOutStream, public IOutStreamFlush, #ifndef _NO_CRYPTO public ICryptoSetPassword, public ICryptoProperties, #endif #ifndef EXTRACT_ONLY public ICompressSetCoderProperties, public ICompressWriteCoderProperties, // public ICryptoResetSalt, public ICryptoResetInitVector, #endif public ICompressSetDecoderProperties2, public CMyUnknownImp { protected: Byte *_buffer; CMyComPtr _inStream; CMyComPtr _outStream; UInt32 _bufferPos; UInt32 _convertedPosBegin; UInt32 _convertedPosEnd; bool _outSizeIsDefined; UInt64 _outSize; UInt64 _nowPos64; void Init2() { _nowPos64 = 0; _outSizeIsDefined = false; } HRESULT Init() { Init2(); return Filter->Init(); } CMyComPtr _setPassword; CMyComPtr _cryptoProperties; #ifndef EXTRACT_ONLY CMyComPtr _SetCoderProperties; CMyComPtr _writeCoderProperties; // CMyComPtr _CryptoResetSalt; CMyComPtr _CryptoResetInitVector; #endif CMyComPtr _setDecoderProperties; public: CMyComPtr Filter; CFilterCoder(); ~CFilterCoder(); HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size); public: MY_QUERYINTERFACE_BEGIN2(ICompressCoder) MY_QUERYINTERFACE_ENTRY(ICompressSetInStream) MY_QUERYINTERFACE_ENTRY(ISequentialInStream) MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream) MY_QUERYINTERFACE_ENTRY(ISequentialOutStream) MY_QUERYINTERFACE_ENTRY(IOutStreamFlush) #ifndef _NO_CRYPTO MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword) MY_QUERYINTERFACE_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties) #endif #ifndef EXTRACT_ONLY MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties) MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties) // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt) MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector) #endif MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties) MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(ReleaseInStream)(); STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream); STDMETHOD(ReleaseOutStream)(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Flush)(); #ifndef _NO_CRYPTO STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); STDMETHOD(SetKey)(const Byte *data, UInt32 size); STDMETHOD(SetInitVector)(const Byte *data, UInt32 size); #endif #ifndef EXTRACT_ONLY STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *properties, UInt32 numProperties); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); // STDMETHOD(ResetSalt)(); STDMETHOD(ResetInitVector)(); #endif STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); void SetInStream_NoSubFilterInit(ISequentialInStream *inStream); }; class CInStreamReleaser { public: CFilterCoder *FilterCoder; CInStreamReleaser(): FilterCoder(0) {} ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); } }; class COutStreamReleaser { public: CFilterCoder *FilterCoder; COutStreamReleaser(): FilterCoder(0) {} ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/InBuffer.cpp0100777000000000000000000000461113761647206023257 0ustar00// InBuffer.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "InBuffer.h" CInBufferBase::CInBufferBase() throw(): _buf(0), _bufLim(0), _bufBase(0), _stream(0), _processedSize(0), _bufSize(0), _wasFinished(false), NumExtraBytes(0) {} bool CInBuffer::Create(size_t bufSize) throw() { const unsigned kMinBlockSize = 1; if (bufSize < kMinBlockSize) bufSize = kMinBlockSize; if (_bufBase != 0 && _bufSize == bufSize) return true; Free(); _bufSize = bufSize; _bufBase = (Byte *)::MidAlloc(bufSize); return (_bufBase != 0); } void CInBuffer::Free() throw() { ::MidFree(_bufBase); _bufBase = 0; } void CInBufferBase::Init() throw() { _processedSize = 0; _buf = _bufBase; _bufLim = _buf; _wasFinished = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif NumExtraBytes = 0; } bool CInBufferBase::ReadBlock() { #ifdef _NO_EXCEPTIONS if (ErrorCode != S_OK) return false; #endif if (_wasFinished) return false; _processedSize += (_buf - _bufBase); _buf = _bufBase; _bufLim = _bufBase; UInt32 processed; // FIX_ME: we can improve it to support (_bufSize >= (1 << 32)) HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed); #ifdef _NO_EXCEPTIONS ErrorCode = result; #else if (result != S_OK) throw CInBufferException(result); #endif _bufLim = _buf + processed; _wasFinished = (processed == 0); return !_wasFinished; } bool CInBufferBase::ReadByte_FromNewBlock(Byte &b) { if (!ReadBlock()) { NumExtraBytes++; b = 0xFF; return false; } b = *_buf++; return true; } Byte CInBufferBase::ReadByte_FromNewBlock() { if (!ReadBlock()) { NumExtraBytes++; return 0xFF; } return *_buf++; } size_t CInBufferBase::ReadBytes(Byte *buf, size_t size) { if ((size_t)(_bufLim - _buf) >= size) { const Byte *src = _buf; for (size_t i = 0; i < size; i++) buf[i] = src[i]; _buf += size; return size; } for (size_t i = 0; i < size; i++) { if (_buf >= _bufLim) if (!ReadBlock()) return i; buf[i] = *_buf++; } return size; } size_t CInBufferBase::Skip(size_t size) { size_t processed = 0; for (;;) { size_t rem = (_bufLim - _buf); if (rem >= size) { _buf += size; return processed + size; } _buf += rem; processed += rem; size -= rem; if (!ReadBlock()) return processed; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/InBuffer.h0100777000000000000000000000362313761647206022726 0ustar00// InBuffer.h #ifndef __IN_BUFFER_H #define __IN_BUFFER_H #include "../../Common/MyException.h" #include "../IStream.h" #ifndef _NO_EXCEPTIONS struct CInBufferException: public CSystemException { CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} }; #endif class CInBufferBase { protected: Byte *_buf; Byte *_bufLim; Byte *_bufBase; ISequentialInStream *_stream; UInt64 _processedSize; size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger // only up to 32-bits values now are supported! bool _wasFinished; bool ReadBlock(); bool ReadByte_FromNewBlock(Byte &b); Byte ReadByte_FromNewBlock(); public: #ifdef _NO_EXCEPTIONS HRESULT ErrorCode; #endif UInt32 NumExtraBytes; CInBufferBase() throw(); UInt64 GetStreamSize() const { return _processedSize + (_buf - _bufBase); } UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (_buf - _bufBase); } bool WasFinished() const { return _wasFinished; } void SetStream(ISequentialInStream *stream) { _stream = stream; } void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos) { _bufBase = buf; _bufSize = bufSize; _processedSize = 0; _buf = buf + pos; _bufLim = buf + end; _wasFinished = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif NumExtraBytes = 0; } void Init() throw(); bool ReadByte(Byte &b) { if (_buf >= _bufLim) return ReadByte_FromNewBlock(b); b = *_buf++; return true; } Byte ReadByte() { if (_buf >= _bufLim) return ReadByte_FromNewBlock(); return *_buf++; } size_t ReadBytes(Byte *buf, size_t size); size_t Skip(size_t size); }; class CInBuffer: public CInBufferBase { public: ~CInBuffer() { Free(); } bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported! void Free() throw(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.cpp0100777000000000000000000000473313761647206024602 0ustar00// InOutTempBuffer.cpp #include "StdAfx.h" #include "../../../C/7zCrc.h" #include "../../Common/Defs.h" #include "InOutTempBuffer.h" #include "StreamUtils.h" using namespace NWindows; using namespace NFile; using namespace NDir; static const UInt32 kTempBufSize = (1 << 20); static CFSTR kTempFilePrefixString = FTEXT("7zt"); CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { } void CInOutTempBuffer::Create() { if (!_buf) _buf = new Byte[kTempBufSize]; } CInOutTempBuffer::~CInOutTempBuffer() { delete []_buf; } void CInOutTempBuffer::InitWriting() { _bufPos = 0; _tempFileCreated = false; _size = 0; _crc = CRC_INIT_VAL; } bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size) { if (size == 0) return true; if (!_tempFileCreated) { if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile)) return false; _tempFileCreated = true; } UInt32 processed; if (!_outFile.Write(data, size, processed)) return false; _crc = CrcUpdate(_crc, data, processed); _size += processed; return (processed == size); } bool CInOutTempBuffer::Write(const void *data, UInt32 size) { if (_bufPos < kTempBufSize) { UInt32 cur = MyMin(kTempBufSize - _bufPos, size); memcpy(_buf + _bufPos, data, cur); _crc = CrcUpdate(_crc, data, cur); _bufPos += cur; size -= cur; data = ((const Byte *)data) + cur; _size += cur; } return WriteToFile(data, size); } HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream) { if (!_outFile.Close()) return E_FAIL; UInt64 size = 0; UInt32 crc = CRC_INIT_VAL; if (_bufPos > 0) { RINOK(WriteStream(stream, _buf, _bufPos)); crc = CrcUpdate(crc, _buf, _bufPos); size += _bufPos; } if (_tempFileCreated) { NIO::CInFile inFile; if (!inFile.Open(_tempFile.GetPath())) return E_FAIL; while (size < _size) { UInt32 processed; if (!inFile.ReadPart(_buf, kTempBufSize, processed)) return E_FAIL; if (processed == 0) break; RINOK(WriteStream(stream, _buf, processed)); crc = CrcUpdate(crc, _buf, processed); size += processed; } } return (_crc == crc && size == _size) ? S_OK : E_FAIL; } STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed) { if (!_buf->Write(data, size)) { if (processed != NULL) *processed = 0; return E_FAIL; } if (processed != NULL) *processed = size; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.h0100777000000000000000000000170313761647206024241 0ustar00// InOutTempBuffer.h #ifndef __IN_OUT_TEMP_BUFFER_H #define __IN_OUT_TEMP_BUFFER_H #include "../../Common/MyCom.h" #include "../../Windows/FileDir.h" #include "../IStream.h" class CInOutTempBuffer { NWindows::NFile::NDir::CTempFile _tempFile; NWindows::NFile::NIO::COutFile _outFile; Byte *_buf; UInt32 _bufPos; bool _tempFileCreated; UInt64 _size; UInt32 _crc; bool WriteToFile(const void *data, UInt32 size); public: CInOutTempBuffer(); ~CInOutTempBuffer(); void Create(); void InitWriting(); bool Write(const void *data, UInt32 size); HRESULT WriteToStream(ISequentialOutStream *stream); UInt64 GetDataSize() const { return _size; } }; class CSequentialOutTempBufferImp: public ISequentialOutStream, public CMyUnknownImp { CInOutTempBuffer *_buf; public: void Init(CInOutTempBuffer *buffer) { _buf = buffer; } MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.cpp0100777000000000000000000002146713761647206024515 0ustar00// LimitedStreams.cpp #include "StdAfx.h" #include "LimitedStreams.h" #include "../../Common/Defs.h" STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = 0; UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size); HRESULT result = S_OK; if (sizeToRead > 0) { result = _stream->Read(data, sizeToRead, &realProcessedSize); _pos += realProcessedSize; if (realProcessedSize == 0) _wasFinished = true; } if (processedSize) *processedSize = realProcessedSize; return result; } STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= _size) { // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. return S_OK; // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF } UInt64 rem = _size - _virtPos; if (rem < size) size = (UInt32)rem; UInt64 newPos = _startOffset + _virtPos; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } HRESULT res = _stream->Read(data, size, &size); if (processedSize) *processedSize = size; _physPos += size; _virtPos += size; return res; } STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) { *resStream = 0; CLimitedInStream *streamSpec = new CLimitedInStream; CMyComPtr streamTemp = streamSpec; streamSpec->SetStream(inStream); RINOK(streamSpec->InitAndSeek(pos, size)); streamSpec->SeekToStart(); *resStream = streamTemp.Detach(); return S_OK; } STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= Size) return S_OK; if (_curRem == 0) { UInt32 blockSize = (UInt32)1 << BlockSizeLog; UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); UInt32 phyBlock = Vector[virtBlock]; UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } _curRem = blockSize - offsetInBlock; for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) _curRem += (UInt32)1 << BlockSizeLog; UInt64 rem = Size - _virtPos; if (_curRem > rem) _curRem = (UInt32)rem; } if (size > _curRem) size = _curRem; HRESULT res = Stream->Read(data, size, &size); if (processedSize) *processedSize = size; _physPos += size; _virtPos += size; _curRem -= size; return res; } STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += Size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; if (_virtPos != (UInt64)offset) _curRem = 0; _virtPos = offset; if (newPosition) *newPosition = offset; return S_OK; } STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= Extents.Back().Virt) return S_OK; if (size == 0) return S_OK; unsigned left = 0, right = Extents.Size() - 1; for (;;) { unsigned mid = (left + right) / 2; if (mid == left) break; if (_virtPos < Extents[mid].Virt) right = mid; else left = mid; } const CSeekExtent &extent = Extents[left]; UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); if (_needStartSeek || _phyPos != phyPos) { _needStartSeek = false; _phyPos = phyPos; RINOK(SeekToPhys()); } UInt64 rem = Extents[left + 1].Virt - _virtPos; if (size > rem) size = (UInt32)rem; HRESULT res = Stream->Read(data, size, &size); _phyPos += size; _virtPos += size; if (processedSize) *processedSize = size; return res; } STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += Extents.Back().Virt; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (processedSize) *processedSize = 0; if (size > _size) { if (_size == 0) { _overflow = true; if (!_overflowIsAllowed) return E_FAIL; if (processedSize) *processedSize = size; return S_OK; } size = (UInt32)_size; } if (_stream) result = _stream->Write(data, size, &size); _size -= size; if (processedSize) *processedSize = size; return result; } STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 cur; HRESULT res = Stream->Read(data, size, &cur); if (processedSize) *processedSize = cur; _virtPos += cur; return res; } STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: { UInt64 pos = 0; RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)); if (pos < Offset) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = pos - Offset; if (newPosition) *newPosition = _virtPos; return S_OK; } default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); } STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (_virtPos >= _size) { // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. return S_OK; // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF } UInt64 rem = _size - _virtPos; if (rem < size) size = (UInt32)rem; UInt64 newPos = _startOffset + _virtPos; UInt64 offsetInCache = newPos - _cachePhyPos; HRESULT res = S_OK; if (newPos >= _cachePhyPos && offsetInCache <= _cacheSize && size <= _cacheSize - (size_t)offsetInCache) memcpy(data, _cache + (size_t)offsetInCache, size); else { if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } res = _stream->Read(data, size, &size); _physPos += size; } if (processedSize) *processedSize = size; _virtPos += size; return res; } STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return S_OK; } STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 cur; HRESULT res = Stream->Write(data, size, &cur); if (processedSize) *processedSize = cur; _virtPos += cur; if (_virtSize < _virtPos) _virtSize = _virtPos; return res; } STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _virtPos; break; case STREAM_SEEK_END: offset += _virtSize; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _virtPos = offset; if (newPosition) *newPosition = _virtPos; return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); } STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize) { _virtSize = newSize; return Stream->SetSize(Offset + newSize); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.h0100777000000000000000000001327013761647206024153 0ustar00// LimitedStreams.h #ifndef __LIMITED_STREAMS_H #define __LIMITED_STREAMS_H #include "../../Common/MyBuffer.h" #include "../../Common/MyCom.h" #include "../../Common/MyVector.h" #include "../IStream.h" class CLimitedSequentialInStream: public ISequentialInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; UInt64 _pos; bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(UInt64 streamSize) { _size = streamSize; _pos = 0; _wasFinished = false; } MY_UNKNOWN_IMP1(ISequentialInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); UInt64 GetSize() const { return _pos; } bool WasFinished() const { return _wasFinished; } }; class CLimitedInStream: public IInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _virtPos; UInt64 _physPos; UInt64 _size; UInt64 _startOffset; HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } public: void SetStream(IInStream *stream) { _stream = stream; } HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) { _startOffset = startOffset; _physPos = startOffset; _virtPos = 0; _size = size; return SeekToPhys(); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } }; HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream); class CClusterInStream: public IInStream, public CMyUnknownImp { UInt64 _virtPos; UInt64 _physPos; UInt32 _curRem; public: CMyComPtr Stream; UInt64 StartOffset; UInt64 Size; unsigned BlockSizeLog; CRecordVector Vector; HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } HRESULT InitAndSeek() { _curRem = 0; _virtPos = 0; _physPos = StartOffset; if (Vector.Size() > 0) { _physPos = StartOffset + (Vector[0] << BlockSizeLog); return SeekToPhys(); } return S_OK; } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; struct CSeekExtent { UInt64 Phy; UInt64 Virt; }; class CExtentsStream: public IInStream, public CMyUnknownImp { UInt64 _phyPos; UInt64 _virtPos; bool _needStartSeek; HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); } public: CMyComPtr Stream; CRecordVector Extents; MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); void ReleaseStream() { Stream.Release(); } void Init() { _virtPos = 0; _phyPos = 0; _needStartSeek = true; } }; class CLimitedSequentialOutStream: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; bool _overflow; bool _overflowIsAllowed; public: MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(UInt64 size, bool overflowIsAllowed = false) { _size = size; _overflow = false; _overflowIsAllowed = overflowIsAllowed; } bool IsFinishedOK() const { return (_size == 0 && !_overflow); } UInt64 GetRem() const { return _size; } }; class CTailInStream: public IInStream, public CMyUnknownImp { UInt64 _virtPos; public: CMyComPtr Stream; UInt64 Offset; void Init() { _virtPos = 0; } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Stream->Seek(Offset, STREAM_SEEK_SET, NULL); } }; class CLimitedCachedInStream: public IInStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _virtPos; UInt64 _physPos; UInt64 _size; UInt64 _startOffset; const Byte *_cache; size_t _cacheSize; size_t _cachePhyPos; HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } public: CByteBuffer Buffer; void SetStream(IInStream *stream) { _stream = stream; } void SetCache(size_t cacheSize, size_t cachePos) { _cache = Buffer; _cacheSize = cacheSize; _cachePhyPos = cachePos; } HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) { _startOffset = startOffset; _physPos = startOffset; _virtPos = 0; _size = size; return SeekToPhys(); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } }; class CTailOutStream: public IOutStream, public CMyUnknownImp { UInt64 _virtPos; UInt64 _virtSize; public: CMyComPtr Stream; UInt64 Offset; virtual ~CTailOutStream() {} MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStream) void Init() { _virtPos = 0; _virtSize = 0; } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/LockedStream.cpp0100777000000000000000000000125113761647206024131 0ustar00// LockedStream.cpp #include "StdAfx.h" #include "LockedStream.h" HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize) { NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL)); return _stream->Read(data, size, processedSize); } STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = 0; HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize); _pos += realProcessedSize; if (processedSize != NULL) *processedSize = realProcessedSize; return result; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/LockedStream.h0100777000000000000000000000146113761647206023601 0ustar00// LockedStream.h #ifndef __LOCKEDSTREAM_H #define __LOCKEDSTREAM_H #include "../../Windows/Synchronization.h" #include "../../Common/MyCom.h" #include "../IStream.h" class CLockedInStream { CMyComPtr _stream; NWindows::NSynchronization::CCriticalSection _criticalSection; public: void Init(IInStream *stream) { _stream = stream; } HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize); }; class CLockedSequentialInStreamImp: public ISequentialInStream, public CMyUnknownImp { CLockedInStream *_lockedInStream; UInt64 _pos; public: void Init(CLockedInStream *lockedInStream, UInt64 startPos) { _lockedInStream = lockedInStream; _pos = startPos; } MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/MethodId.h0100777000000000000000000000020713761647206022716 0ustar00// MethodId.h #ifndef __7Z_METHOD_ID_H #define __7Z_METHOD_ID_H #include "../../Common/MyTypes.h" typedef UInt64 CMethodId; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/MethodProps.cpp0100777000000000000000000002277613761647206024037 0ustar00// MethodProps.cpp #include "StdAfx.h" #include "../../Common/StringToInt.h" #include "MethodProps.h" using namespace NWindows; bool StringToBool(const UString &s, bool &res) { if (s.IsEmpty() || s == L"+" || StringsAreEqualNoCase_Ascii(s, "ON")) { res = true; return true; } if (s == L"-" || StringsAreEqualNoCase_Ascii(s, "OFF")) { res = false; return true; } return false; } HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest) { switch (prop.vt) { case VT_EMPTY: dest = true; return S_OK; case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK; case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG; } return E_INVALIDARG; } unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number) { const wchar_t *start = srcString; const wchar_t *end; number = ConvertStringToUInt32(start, &end); return (unsigned)(end - start); } HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) { // =VT_UI4 // =VT_EMPTY // {stringUInt32}=VT_EMPTY if (prop.vt == VT_UI4) { if (!name.IsEmpty()) return E_INVALIDARG; resValue = prop.ulVal; return S_OK; } if (prop.vt != VT_EMPTY) return E_INVALIDARG; if (name.IsEmpty()) return S_OK; UInt32 v; if (ParseStringToUInt32(name, v) != name.Len()) return E_INVALIDARG; resValue = v; return S_OK; } HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) { if (name.IsEmpty()) { switch (prop.vt) { case VT_UI4: numThreads = prop.ulVal; break; default: { bool val; RINOK(PROPVARIANT_to_bool(prop, val)); numThreads = (val ? defaultNumThreads : 1); break; } } return S_OK; } if (prop.vt != VT_EMPTY) return E_INVALIDARG; return ParsePropToUInt32(name, prop, numThreads); } static HRESULT StringToDictSize(const UString &s, UInt32 &dicSize) { const wchar_t *end; UInt32 number = ConvertStringToUInt32(s, &end); unsigned numDigits = (unsigned)(end - s); if (numDigits == 0 || s.Len() > numDigits + 1) return E_INVALIDARG; const unsigned kLogDictSizeLimit = 32; if (s.Len() == numDigits) { if (number >= kLogDictSizeLimit) return E_INVALIDARG; dicSize = (UInt32)1 << (unsigned)number; return S_OK; } unsigned numBits; switch (MyCharLower_Ascii(s[numDigits])) { case 'b': dicSize = number; return S_OK; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; default: return E_INVALIDARG; } if (number >= ((UInt32)1 << (kLogDictSizeLimit - numBits))) return E_INVALIDARG; dicSize = number << numBits; return S_OK; } static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue) { if (prop.vt == VT_UI4) { UInt32 v = prop.ulVal; if (v >= 32) return E_INVALIDARG; resValue = (UInt32)1 << v; return S_OK; } if (prop.vt == VT_BSTR) return StringToDictSize(prop.bstrVal, resValue); return E_INVALIDARG; } void CProps::AddProp32(PROPID propid, UInt32 level) { CProp prop; prop.IsOptional = true; prop.Id = propid; prop.Value = (UInt32)level; Props.Add(prop); } class CCoderProps { PROPID *_propIDs; NCOM::CPropVariant *_props; unsigned _numProps; unsigned _numPropsMax; public: CCoderProps(unsigned numPropsMax) { _numPropsMax = numPropsMax; _numProps = 0; _propIDs = new PROPID[numPropsMax]; _props = new NCOM::CPropVariant[numPropsMax]; } ~CCoderProps() { delete []_propIDs; delete []_props; } void AddProp(const CProp &prop); HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) { return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); } }; void CCoderProps::AddProp(const CProp &prop) { if (_numProps >= _numPropsMax) throw 1; _propIDs[_numProps] = prop.Id; _props[_numProps] = prop.Value; _numProps++; } HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const { CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0)); FOR_VECTOR (i, Props) coderProps.AddProp(Props[i]); if (dataSizeReduce) { CProp prop; prop.Id = NCoderPropID::kReduceSize; prop.Value = *dataSizeReduce; coderProps.AddProp(prop); } return coderProps.SetProps(scp); } int CMethodProps::FindProp(PROPID id) const { for (int i = Props.Size() - 1; i >= 0; i--) if (Props[i].Id == id) return i; return -1; } int CMethodProps::GetLevel() const { int i = FindProp(NCoderPropID::kLevel); if (i < 0) return 5; if (Props[i].Value.vt != VT_UI4) return 9; UInt32 level = Props[i].Value.ulVal; return level > 9 ? 9 : (int)level; } struct CNameToPropID { VARTYPE VarType; const char *Name; }; static const CNameToPropID g_NameToPropID[] = { { VT_UI4, "" }, { VT_UI4, "d" }, { VT_UI4, "mem" }, { VT_UI4, "o" }, { VT_UI4, "c" }, { VT_UI4, "pb" }, { VT_UI4, "lc" }, { VT_UI4, "lp" }, { VT_UI4, "fb" }, { VT_BSTR, "mf" }, { VT_UI4, "mc" }, { VT_UI4, "pass" }, { VT_UI4, "a" }, { VT_UI4, "mt" }, { VT_BOOL, "eos" }, { VT_UI4, "x" }, { VT_UI4, "reduceSize" } }; static int FindPropIdExact(const UString &name) { for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++) if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) return i; return -1; } static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) { if (varType == srcProp.vt) { destProp = srcProp; return true; } if (varType == VT_BOOL) { bool res; if (PROPVARIANT_to_bool(srcProp, res) != S_OK) return false; destProp = res; return true; } if (srcProp.vt == VT_EMPTY) { destProp = srcProp; return true; } return false; } static void SplitParams(const UString &srcString, UStringVector &subStrings) { subStrings.Clear(); UString s; int len = srcString.Len(); if (len == 0) return; for (int i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L':') { subStrings.Add(s); s.Empty(); } else s += c; } subStrings.Add(s); } static void SplitParam(const UString ¶m, UString &name, UString &value) { int eqPos = param.Find(L'='); if (eqPos >= 0) { name.SetFrom(param, eqPos); value = param.Ptr(eqPos + 1); return; } unsigned i; for (i = 0; i < param.Len(); i++) { wchar_t c = param[i]; if (c >= L'0' && c <= L'9') break; } name.SetFrom(param, i); value = param.Ptr(i); } static bool IsLogSizeProp(PROPID propid) { switch (propid) { case NCoderPropID::kDictionarySize: case NCoderPropID::kUsedMemorySize: case NCoderPropID::kBlockSize: case NCoderPropID::kReduceSize: return true; } return false; } HRESULT CMethodProps::SetParam(const UString &name, const UString &value) { int index = FindPropIdExact(name); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; CProp prop; prop.Id = index; if (IsLogSizeProp(prop.Id)) { UInt32 dicSize; RINOK(StringToDictSize(value, dicSize)); prop.Value = dicSize; } else { NCOM::CPropVariant propValue; if (nameToPropID.VarType == VT_BSTR) propValue = value; else if (nameToPropID.VarType == VT_BOOL) { bool res; if (!StringToBool(value, res)) return E_INVALIDARG; propValue = res; } else if (!value.IsEmpty()) { UInt32 number; if (ParseStringToUInt32(value, number) == value.Len()) propValue = number; else propValue = value; } if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) return E_INVALIDARG; } Props.Add(prop); return S_OK; } HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) { UStringVector params; SplitParams(srcString, params); FOR_VECTOR (i, params) { const UString ¶m = params[i]; UString name, value; SplitParam(param, name, value); RINOK(SetParam(name, value)); } return S_OK; } HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) { if (realName.Len() == 0) { // [empty]=method return E_INVALIDARG; } if (value.vt == VT_EMPTY) { // {realName}=[empty] UString name, value; SplitParam(realName, name, value); return SetParam(name, value); } // {realName}=value int index = FindPropIdExact(realName); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; CProp prop; prop.Id = index; if (IsLogSizeProp(prop.Id)) { UInt32 dicSize; RINOK(PROPVARIANT_to_DictSize(value, dicSize)); prop.Value = dicSize; } else { if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) return E_INVALIDARG; } Props.Add(prop); return S_OK; } HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) { int splitPos = s.Find(':'); MethodName = s; if (splitPos < 0) return S_OK; MethodName.DeleteFrom(splitPos); return ParseParamsFromString(s.Ptr(splitPos + 1)); } HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) { if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) return ParseParamsFromPROPVARIANT(realName, value); // -m{N}=method if (value.vt != VT_BSTR) return E_INVALIDARG; return ParseMethodFromString(value.bstrVal); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/MethodProps.h0100777000000000000000000001063313761647206023471 0ustar00// MethodProps.h #ifndef __7Z_METHOD_PROPS_H #define __7Z_METHOD_PROPS_H #include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" #include "../ICoder.h" bool StringToBool(const UString &s, bool &res); HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest); unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number); HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads); struct CProp { PROPID Id; bool IsOptional; NWindows::NCOM::CPropVariant Value; CProp(): IsOptional(false) {} }; struct CProps { CObjectVector Props; void Clear() { Props.Clear(); } bool AreThereNonOptionalProps() const { FOR_VECTOR (i, Props) if (!Props[i].IsOptional) return true; return false; } void AddProp32(PROPID propid, UInt32 level); void AddPropString(PROPID propid, const wchar_t *s) { CProp prop; prop.IsOptional = true; prop.Id = propid; prop.Value = s; Props.Add(prop); } HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const; }; class CMethodProps: public CProps { HRESULT SetParam(const UString &name, const UString &value); public: int GetLevel() const; int Get_NumThreads() const { int i = FindProp(NCoderPropID::kNumThreads); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return (int)Props[i].Value.ulVal; return -1; } bool Get_DicSize(UInt32 &res) const { res = 0; int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) { res = Props[i].Value.ulVal; return true; } return false; } int FindProp(PROPID id) const; UInt32 Get_Lzma_Algo() const { int i = FindProp(NCoderPropID::kAlgorithm); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; return GetLevel() >= 5 ? 1 : 0; } UInt32 Get_Lzma_DicSize() const { int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; int level = GetLevel(); return level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)); } UInt32 Get_Lzma_NumThreads(bool &fixedNumber) const { fixedNumber = false; int numThreads = Get_NumThreads(); if (numThreads >= 0) { fixedNumber = true; return numThreads < 2 ? 1 : 2; } return Get_Lzma_Algo() == 0 ? 1 : 2; } UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const { fixedNumber = false; int numThreads = Get_NumThreads(); if (numThreads >= 0) { fixedNumber = true; if (numThreads < 1) return 1; if (numThreads > 64) return 64; return numThreads; } return 1; } UInt32 Get_BZip2_BlockSize() const { int i = FindProp(NCoderPropID::kDictionarySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) { UInt32 blockSize = Props[i].Value.ulVal; const UInt32 kDicSizeMin = 100000; const UInt32 kDicSizeMax = 900000; if (blockSize < kDicSizeMin) blockSize = kDicSizeMin; if (blockSize > kDicSizeMax) blockSize = kDicSizeMax; return blockSize; } int level = GetLevel(); return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1)); } UInt32 Get_Ppmd_MemSize() const { int i = FindProp(NCoderPropID::kUsedMemorySize); if (i >= 0) if (Props[i].Value.vt == VT_UI4) return Props[i].Value.ulVal; int level = GetLevel(); return level >= 9 ? (192 << 20) : ((UInt32)1 << (level + 19)); } void AddLevelProp(UInt32 level) { AddProp32(NCoderPropID::kLevel, level); } void AddNumThreadsProp(UInt32 numThreads) { AddProp32(NCoderPropID::kNumThreads, numThreads); } HRESULT ParseParamsFromString(const UString &srcString); HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); }; class COneMethodInfo: public CMethodProps { public: UString MethodName; void Clear() { CMethodProps::Clear(); MethodName.Empty(); } bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); } HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); HRESULT ParseMethodFromString(const UString &s); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.cpp0100777000000000000000000000401113761647206023452 0ustar00// OutBuffer.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "OutBuffer.h" bool COutBuffer::Create(UInt32 bufSize) throw() { const UInt32 kMinBlockSize = 1; if (bufSize < kMinBlockSize) bufSize = kMinBlockSize; if (_buf != 0 && _bufSize == bufSize) return true; Free(); _bufSize = bufSize; _buf = (Byte *)::MidAlloc(bufSize); return (_buf != 0); } void COutBuffer::Free() throw() { ::MidFree(_buf); _buf = 0; } void COutBuffer::Init() throw() { _streamPos = 0; _limitPos = _bufSize; _pos = 0; _processedSize = 0; _overDict = false; #ifdef _NO_EXCEPTIONS ErrorCode = S_OK; #endif } UInt64 COutBuffer::GetProcessedSize() const throw() { UInt64 res = _processedSize + _pos - _streamPos; if (_streamPos > _pos) res += _bufSize; return res; } HRESULT COutBuffer::FlushPart() throw() { // _streamPos < _bufSize UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos); HRESULT result = S_OK; #ifdef _NO_EXCEPTIONS result = ErrorCode; #endif if (_buf2 != 0) { memcpy(_buf2, _buf + _streamPos, size); _buf2 += size; } if (_stream != 0 #ifdef _NO_EXCEPTIONS && (ErrorCode == S_OK) #endif ) { UInt32 processedSize = 0; result = _stream->Write(_buf + _streamPos, size, &processedSize); size = processedSize; } _streamPos += size; if (_streamPos == _bufSize) _streamPos = 0; if (_pos == _bufSize) { _overDict = true; _pos = 0; } _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize; _processedSize += size; return result; } HRESULT COutBuffer::Flush() throw() { #ifdef _NO_EXCEPTIONS if (ErrorCode != S_OK) return ErrorCode; #endif while (_streamPos != _pos) { HRESULT result = FlushPart(); if (result != S_OK) return result; } return S_OK; } void COutBuffer::FlushWithCheck() { HRESULT result = Flush(); #ifdef _NO_EXCEPTIONS ErrorCode = result; #else if (result != S_OK) throw COutBufferException(result); #endif } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.h0100777000000000000000000000236213761647206023126 0ustar00// OutBuffer.h #ifndef __OUT_BUFFER_H #define __OUT_BUFFER_H #include "../IStream.h" #include "../../Common/MyCom.h" #include "../../Common/MyException.h" #ifndef _NO_EXCEPTIONS struct COutBufferException: public CSystemException { COutBufferException(HRESULT errorCode): CSystemException(errorCode) {} }; #endif class COutBuffer { protected: Byte *_buf; UInt32 _pos; UInt32 _limitPos; UInt32 _streamPos; UInt32 _bufSize; ISequentialOutStream *_stream; UInt64 _processedSize; Byte *_buf2; bool _overDict; HRESULT FlushPart() throw(); public: #ifdef _NO_EXCEPTIONS HRESULT ErrorCode; #endif COutBuffer(): _buf(0), _pos(0), _stream(0), _buf2(0) {} ~COutBuffer() { Free(); } bool Create(UInt32 bufSize) throw(); void Free() throw(); void SetMemStream(Byte *buf) { _buf2 = buf; } void SetStream(ISequentialOutStream *stream) { _stream = stream; } void Init() throw(); HRESULT Flush() throw(); void FlushWithCheck(); void WriteByte(Byte b) { _buf[_pos++] = b; if (_pos == _limitPos) FlushWithCheck(); } void WriteBytes(const void *data, size_t size) { for (size_t i = 0; i < size; i++) WriteByte(((const Byte *)data)[i]); } UInt64 GetProcessedSize() const throw(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.cpp0100777000000000000000000000174713761647206024413 0ustar00// ProgressUtils.cpp #include "StdAfx.h" #include "ProgressUtils.h" CLocalProgress::CLocalProgress() { ProgressOffset = InSize = OutSize = 0; SendRatio = SendProgress = true; } void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain) { _ratioProgress.Release(); _progress = progress; _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress); _inSizeIsMain = inSizeIsMain; } STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { UInt64 inSizeNew = InSize, outSizeNew = OutSize; if (inSize) inSizeNew += (*inSize); if (outSize) outSizeNew += (*outSize); if (SendRatio && _ratioProgress) { RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew)); } inSizeNew += ProgressOffset; outSizeNew += ProgressOffset; if (SendProgress) return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew); return S_OK; } HRESULT CLocalProgress::SetCur() { return SetRatioInfo(NULL, NULL); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.h0100777000000000000000000000120513761647206024045 0ustar00// ProgressUtils.h #ifndef __PROGRESSUTILS_H #define __PROGRESSUTILS_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../IProgress.h" class CLocalProgress: public ICompressProgressInfo, public CMyUnknownImp { CMyComPtr _progress; CMyComPtr _ratioProgress; bool _inSizeIsMain; public: UInt64 ProgressOffset; UInt64 InSize; UInt64 OutSize; bool SendRatio; bool SendProgress; CLocalProgress(); void Init(IProgress *progress, bool inSizeIsMain); HRESULT SetCur(); MY_UNKNOWN_IMP STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/PropId.cpp0100777000000000000000000000225713761647206022760 0ustar00// PropId.cpp #include "StdAfx.h" #include "../PropID.h" // VARTYPE Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] = { VT_EMPTY, VT_UI4, VT_UI4, VT_BSTR, VT_BSTR, VT_BSTR, VT_BOOL, VT_UI8, VT_UI8, VT_UI4, VT_FILETIME, VT_FILETIME, VT_FILETIME, VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_UI4, VT_UI4, VT_BSTR, VT_BOOL, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, VT_UI8, VT_BSTR, VT_UI8, VT_BSTR, VT_UI8, VT_UI8, VT_BSTR, // or VT_UI8 kpidUnpackVer VT_UI4, // or VT_UI8 kpidVolume VT_BOOL, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI4, VT_BOOL, VT_BOOL, VT_BSTR, VT_UI8, VT_UI8, VT_UI4, // kpidChecksum VT_BSTR, VT_UI8, VT_BSTR, // or VT_UI8 kpidId VT_BSTR, VT_BSTR, VT_UI4, VT_UI4, VT_BSTR, VT_BSTR, VT_UI8, VT_UI8, VT_UI4, VT_BSTR, VT_BSTR, VT_BSTR, VT_BSTR, // kpidNtSecure VT_BOOL, VT_BOOL, VT_BOOL, VT_BOOL, VT_BSTR, // SHA-1 VT_BSTR, // SHA-256 VT_BSTR, VT_UI8, VT_UI4, VT_UI4, VT_BSTR, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_UI8, VT_BSTR, VT_BSTR, VT_BSTR, VT_BOOL, VT_BOOL, VT_BOOL, VT_UI8, VT_UI8 }; qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h0100777000000000000000000000332713761647206023441 0ustar00// RegisterArc.h #ifndef __REGISTER_ARC_H #define __REGISTER_ARC_H #include "../Archive/IArchive.h" #include struct CArcInfo { const char *Name; const char *Ext; const char *AddExt; Byte ClassId; Byte SignatureSize; Byte Signature[20]; UInt16 SignatureOffset; UInt16 Flags; Func_CreateInArchive CreateInArchive; Func_CreateOutArchive CreateOutArchive; Func_IsArc IsArc; bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } std::once_flag once; }; void RegisterArc(const CArcInfo *arcInfo) throw(); #define REGISTER_ARC_NAME(x) CRegister ## x #define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) \ { \ REGISTER_ARC_NAME(x)() \ { \ std::call_once(g_ArcInfo.once, [] { RegisterArc(&g_ArcInfo); }); \ } \ }; \ static REGISTER_ARC_NAME(x) g_RegisterArc; \ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) \ { \ REGISTER_ARC_NAME(x)() { \ std::call_once(g_ArcInfo.once, [] { \ g_ArcInfo.Signature[0]--; \ RegisterArc(&g_ArcInfo); \ }); \ } \ }; \ static REGISTER_ARC_NAME(x) g_RegisterArc; \ void registerArcDec##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; } #define IMP_CreateArcIn_2(c) \ static IInArchive *CreateArc() { return new c; } #define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler) #ifdef EXTRACT_ONLY #define IMP_CreateArcOut #define REF_CreateArc_Pair CreateArc, NULL #else #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler; } #define REF_CreateArc_Pair CreateArc, CreateArcOut #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h0100777000000000000000000000332413761647206023746 0ustar00// RegisterCodec.h #ifndef __REGISTER_CODEC_H #define __REGISTER_CODEC_H #include "../Common/MethodId.h" #include "../ICoder.h" #include typedef void * (*CreateCodecP)(); struct CCodecInfo { CreateCodecP CreateDecoder; CreateCodecP CreateEncoder; CMethodId Id; const wchar_t *Name; UInt32 NumInStreams; bool IsFilter; std::once_flag once; }; void RegisterCodec(const CCodecInfo *codecInfo) throw(); #define REGISTER_CODEC_NAME(x) CRegisterCodec ## x #define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) \ { \ REGISTER_CODEC_NAME(x)() \ { \ std::call_once(g_CodecInfo.once, [] { RegisterCodec(&g_CodecInfo); }); \ } \ }; \ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; } #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x #define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) \ { \ REGISTER_CODECS_NAME(x)() \ { \ for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \ std::call_once(g_CodecsInfo[i].once, [&i] { RegisterCodec(&g_CodecsInfo[i]); }); \ } \ }; \ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; } struct CHasherInfo { IHasher * (*CreateHasher)(); CMethodId Id; const wchar_t *Name; UInt32 DigestSize; }; void RegisterHasher(const CHasherInfo *hasher) throw(); #define REGISTER_HASHER_NAME(x) CRegisterHasher ## x #define REGISTER_HASHER(x) struct REGISTER_HASHER_NAME(x) { \ REGISTER_HASHER_NAME(x)() { RegisterHasher(&g_HasherInfo); }}; \ static REGISTER_HASHER_NAME(x) g_RegisterHasher; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StdAfx.h0100777000000000000000000000013513761647206022412 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.cpp0100777000000000000000000000577013761647206024145 0ustar00// StreamBinder.cpp #include "StdAfx.h" #include "../../Common/MyCom.h" #include "StreamBinder.h" class CBinderInStream: public ISequentialInStream, public CMyUnknownImp { CStreamBinder *_binder; public: MY_UNKNOWN_IMP STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); ~CBinderInStream() { _binder->CloseRead(); } CBinderInStream(CStreamBinder *binder): _binder(binder) {} }; STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { return _binder->Read(data, size, processedSize); } class CBinderOutStream: public ISequentialOutStream, public CMyUnknownImp { CStreamBinder *_binder; public: MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); ~CBinderOutStream() { _binder->CloseWrite(); } CBinderOutStream(CStreamBinder *binder): _binder(binder) {} }; STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { return _binder->Write(data, size, processedSize); } WRes CStreamBinder::CreateEvents() { RINOK(_canWrite_Event.Create(true)); RINOK(_canRead_Event.Create()); return _readingWasClosed_Event.Create(); } void CStreamBinder::ReInit() { _waitWrite = true; _canRead_Event.Reset(); _readingWasClosed_Event.Reset(); ProcessedSize = 0; } void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream) { _waitWrite = true; _bufSize = 0; _buf = NULL; ProcessedSize = 0; CBinderInStream *inStreamSpec = new CBinderInStream(this); CMyComPtr inStreamLoc(inStreamSpec); *inStream = inStreamLoc.Detach(); CBinderOutStream *outStreamSpec = new CBinderOutStream(this); CMyComPtr outStreamLoc(outStreamSpec); *outStream = outStreamLoc.Detach(); } // (_canRead_Event && _bufSize == 0) means that stream is finished. HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size != 0) { if (_waitWrite) { RINOK(_canRead_Event.Lock()); _waitWrite = false; } if (size > _bufSize) size = _bufSize; if (size != 0) { memcpy(data, _buf, size); _buf = ((const Byte *)_buf) + size; ProcessedSize += size; if (processedSize) *processedSize = size; _bufSize -= size; if (_bufSize == 0) { _waitWrite = true; _canRead_Event.Reset(); _canWrite_Event.Set(); } } } return S_OK; } HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size != 0) { _buf = data; _bufSize = size; _canWrite_Event.Reset(); _canRead_Event.Set(); HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event }; DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); if (waitResult != WAIT_OBJECT_0 + 0) return S_FALSE; if (processedSize) *processedSize = size; } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.h0100777000000000000000000000154213761647206023603 0ustar00// StreamBinder.h #ifndef __STREAM_BINDER_H #define __STREAM_BINDER_H #include "../../Windows/Synchronization.h" #include "../IStream.h" class CStreamBinder { NWindows::NSynchronization::CManualResetEvent _canWrite_Event; NWindows::NSynchronization::CManualResetEvent _canRead_Event; NWindows::NSynchronization::CManualResetEvent _readingWasClosed_Event; bool _waitWrite; UInt32 _bufSize; const void *_buf; public: UInt64 ProcessedSize; WRes CreateEvents(); void CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream); void ReInit(); HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize); void CloseRead() { _readingWasClosed_Event.Set(); } void CloseWrite() { // _bufSize must be = 0 _canRead_Event.Set(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.cpp0100777000000000000000000001377513761647206024337 0ustar00// StreamObjects.cpp #include "StdAfx.h" #include #include "../../../C/Alloc.h" #include "StreamObjects.h" STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _size) return S_OK; size_t rem = _size - (size_t)_pos; if (rem > size) rem = (size_t)size; memcpy(data, _data + (size_t)_pos, rem); _pos += rem; if (processedSize) *processedSize = (UInt32)rem; return S_OK; } STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } /* void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream) { CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr streamTemp = inStreamSpec; inStreamSpec->Init((const Byte *)data, size); *stream = streamTemp.Detach(); } */ void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream) { CReferenceBuf *referenceBuf = new CReferenceBuf; CMyComPtr ref = referenceBuf; referenceBuf->Buf.CopyFrom((const Byte *)data, size); CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr streamTemp = inStreamSpec; inStreamSpec->Init(referenceBuf); *stream = streamTemp.Detach(); } void CByteDynBuffer::Free() throw() { free(_buf); _buf = 0; _capacity = 0; } bool CByteDynBuffer::EnsureCapacity(size_t cap) throw() { if (cap <= _capacity) return true; size_t delta; if (_capacity > 64) delta = _capacity / 4; else if (_capacity > 8) delta = 16; else delta = 4; cap = MyMax(_capacity + delta, cap); Byte *buf = (Byte *)realloc(_buf, cap); if (!buf) return false; _buf = buf; _capacity = cap; return true; } Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) { addSize += _size; if (addSize < _size) return NULL; if (!_buffer.EnsureCapacity(addSize)) return NULL; return (Byte *)_buffer + _size; } void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const { dest.CopyFrom((const Byte *)_buffer, _size); } STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; Byte *buf = GetBufPtrForWriting(size); if (!buf) return E_OUTOFMEMORY; memcpy(buf, data, size); UpdateSize(size); if (processedSize) *processedSize = size; return S_OK; } STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { size_t rem = _size - _pos; if (rem > size) rem = (size_t)size; memcpy(_buffer + _pos, data, rem); _pos += rem; if (processedSize) *processedSize = (UInt32)rem; return (rem != 0 || size == 0) ? S_OK : E_FAIL; } STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize; HRESULT result = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return result; } static const UInt64 kEmptyTag = (UInt64)(Int64)-1; void CCachedInStream::Free() throw() { MyFree(_tags); _tags = 0; MidFree(_data); _data = 0; } bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw() { unsigned sizeLog = blockSizeLog + numBlocksLog; if (sizeLog >= sizeof(size_t) * 8) return false; size_t dataSize = (size_t)1 << sizeLog; if (_data == 0 || dataSize != _dataSize) { MidFree(_data); _data = (Byte *)MidAlloc(dataSize); if (_data == 0) return false; _dataSize = dataSize; } if (_tags == 0 || numBlocksLog != _numBlocksLog) { MyFree(_tags); _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); if (_tags == 0) return false; _numBlocksLog = numBlocksLog; } _blockSizeLog = blockSizeLog; return true; } void CCachedInStream::Init(UInt64 size) throw() { _size = size; _pos = 0; size_t numBlocks = (size_t)1 << _numBlocksLog; for (size_t i = 0; i < numBlocks; i++) _tags[i] = kEmptyTag; } STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (_pos >= _size) return S_OK; { UInt64 rem = _size - _pos; if (size > rem) size = (UInt32)rem; } while (size != 0) { UInt64 cacheTag = _pos >> _blockSizeLog; size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); Byte *p = _data + (cacheIndex << _blockSizeLog); if (_tags[cacheIndex] != cacheTag) { UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); size_t blockSize = (size_t)1 << _blockSizeLog; if (blockSize > remInBlock) blockSize = (size_t)remInBlock; RINOK(ReadBlock(cacheTag, p, blockSize)); _tags[cacheIndex] = cacheTag; } size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1); UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size); memcpy(data, p + offset, cur); if (processedSize) *processedSize += cur; data = (void *)((const Byte *)data + cur); _pos += cur; size -= cur; } return S_OK; } STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) { case STREAM_SEEK_SET: break; case STREAM_SEEK_CUR: offset += _pos; break; case STREAM_SEEK_END: offset += _size; break; default: return STG_E_INVALIDFUNCTION; } if (offset < 0) return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; _pos = offset; if (newPosition) *newPosition = offset; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.h0100777000000000000000000000707413761647206023777 0ustar00// StreamObjects.h #ifndef __STREAM_OBJECTS_H #define __STREAM_OBJECTS_H #include "../../Common/MyBuffer.h" #include "../../Common/MyCom.h" #include "../../Common/MyVector.h" #include "../IStream.h" struct CReferenceBuf: public IUnknown, public CMyUnknownImp { CByteBuffer Buf; MY_UNKNOWN_IMP }; class CBufInStream: public IInStream, public CMyUnknownImp { const Byte *_data; UInt64 _pos; size_t _size; CMyComPtr _ref; public: void Init(const Byte *data, size_t size, IUnknown *ref = 0) { _data = data; _size = size; _pos = 0; _ref = ref; } void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); } MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; // void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream); void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream); class CByteDynBuffer { size_t _capacity; Byte *_buf; public: CByteDynBuffer(): _capacity(0), _buf(0) {}; // there is no copy constructor. So don't copy this object. ~CByteDynBuffer() { Free(); } void Free() throw(); size_t GetCapacity() const { return _capacity; } operator Byte*() const { return _buf; }; operator const Byte*() const { return _buf; }; bool EnsureCapacity(size_t capacity) throw(); }; class CDynBufSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { CByteDynBuffer _buffer; size_t _size; public: CDynBufSeqOutStream(): _size(0) {} void Init() { _size = 0; } size_t GetSize() const { return _size; } const Byte *GetBuffer() const { return _buffer; } void CopyToBuffer(CByteBuffer &dest) const; Byte *GetBufPtrForWriting(size_t addSize); void UpdateSize(size_t addSize) { _size += addSize; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CBufPtrSeqOutStream: public ISequentialOutStream, public CMyUnknownImp { Byte *_buffer; size_t _size; size_t _pos; public: void Init(Byte *buffer, size_t size) { _buffer = buffer; _pos = 0; _size = size; } size_t GetPos() const { return _pos; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CSequentialOutStreamSizeCount: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; public: void SetStream(ISequentialOutStream *stream) { _stream = stream; } void Init() { _size = 0; } UInt64 GetSize() const { return _size; } MY_UNKNOWN_IMP1(ISequentialOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; class CCachedInStream: public IInStream, public CMyUnknownImp { UInt64 *_tags; Byte *_data; size_t _dataSize; unsigned _blockSizeLog; unsigned _numBlocksLog; UInt64 _size; UInt64 _pos; protected: virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0; public: CCachedInStream(): _tags(0), _data(0) {} virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!! void Free() throw(); bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw(); void Init(UInt64 size) throw(); MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.cpp0100777000000000000000000000305613761647206024035 0ustar00// StreamUtils.cpp #include "StdAfx.h" #include "StreamUtils.h" static const UInt32 kBlockSize = ((UInt32)1 << 31); HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw() { size_t size = *processedSize; *processedSize = 0; while (size != 0) { UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; UInt32 processedSizeLoc; HRESULT res = stream->Read(data, curSize, &processedSizeLoc); *processedSize += processedSizeLoc; data = (void *)((Byte *)data + processedSizeLoc); size -= processedSizeLoc; RINOK(res); if (processedSizeLoc == 0) return S_OK; } return S_OK; } HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw() { size_t processedSize = size; RINOK(ReadStream(stream, data, &processedSize)); return (size == processedSize) ? S_OK : S_FALSE; } HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw() { size_t processedSize = size; RINOK(ReadStream(stream, data, &processedSize)); return (size == processedSize) ? S_OK : E_FAIL; } HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw() { while (size != 0) { UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; UInt32 processedSizeLoc; HRESULT res = stream->Write(data, curSize, &processedSizeLoc); data = (const void *)((const Byte *)data + processedSizeLoc); size -= processedSizeLoc; RINOK(res); if (processedSizeLoc == 0) return E_FAIL; } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.h0100777000000000000000000000070213761647206023475 0ustar00// StreamUtils.h #ifndef __STREAM_UTILS_H #define __STREAM_UTILS_H #include "../IStream.h" HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw(); HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw(); HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw(); HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/UniqBlocks.cpp0100777000000000000000000000220113761647206023622 0ustar00// UniqBlocks.cpp #include "StdAfx.h" #include "UniqBlocks.h" int CUniqBlocks::AddUniq(const Byte *data, size_t size) { unsigned left = 0, right = Sorted.Size(); while (left != right) { unsigned mid = (left + right) / 2; int index = Sorted[mid]; const CByteBuffer &buf = Bufs[index]; size_t sizeMid = buf.Size(); if (size < sizeMid) right = mid; else if (size > sizeMid) left = mid + 1; else { int cmp = memcmp(data, buf, size); if (cmp == 0) return index; if (cmp < 0) right = mid; else left = mid + 1; } } int index = Bufs.Size(); Sorted.Insert(left, index); CByteBuffer &buf = Bufs.AddNew(); buf.CopyFrom(data, size); return index; } UInt64 CUniqBlocks::GetTotalSizeInBytes() const { UInt64 size = 0; FOR_VECTOR (i, Bufs) size += Bufs[i].Size(); return size; } void CUniqBlocks::GetReverseMap() { unsigned num = Sorted.Size(); BufIndexToSortedIndex.ClearAndSetSize(num); int *p = &BufIndexToSortedIndex[0]; unsigned i; for (i = 0; i < num; i++) p[i] = 0; for (i = 0; i < num; i++) p[Sorted[i]] = i; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/UniqBlocks.h0100777000000000000000000000106213761647206023273 0ustar00// UniqBlocks.h #ifndef __UNIQ_BLOCKS_H #define __UNIQ_BLOCKS_H #include "../../Common/MyTypes.h" #include "../../Common/MyBuffer.h" #include "../../Common/MyVector.h" struct CUniqBlocks { CObjectVector Bufs; CIntVector Sorted; CIntVector BufIndexToSortedIndex; int AddUniq(const Byte *data, size_t size); UInt64 GetTotalSizeInBytes() const; void GetReverseMap(); bool IsOnlyEmpty() const { if (Bufs.Size() == 0) return true; if (Bufs.Size() > 1) return false; return Bufs[0].Size() == 0; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/VirtThread.cpp0100777000000000000000000000143213761647206023631 0ustar00// VirtThread.cpp #include "StdAfx.h" #include "VirtThread.h" static THREAD_FUNC_DECL CoderThread(void *p) { for (;;) { CVirtThread *t = (CVirtThread *)p; t->StartEvent.Lock(); if (t->Exit) return 0; t->Execute(); t->FinishedEvent.Set(); } } WRes CVirtThread::Create() { RINOK(StartEvent.CreateIfNotCreated()); RINOK(FinishedEvent.CreateIfNotCreated()); StartEvent.Reset(); FinishedEvent.Reset(); Exit = false; if (Thread.IsCreated()) return S_OK; return Thread.Create(CoderThread, this); } void CVirtThread::Start() { Exit = false; StartEvent.Set(); } void CVirtThread::WaitThreadFinish() { Exit = true; if (StartEvent.IsCreated()) StartEvent.Set(); if (Thread.IsCreated()) { Thread.Wait(); Thread.Close(); } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Common/VirtThread.h0100777000000000000000000000106313761647206023276 0ustar00// VirtThread.h #ifndef __VIRT_THREAD_H #define __VIRT_THREAD_H #include "../../Windows/Synchronization.h" #include "../../Windows/Thread.h" struct CVirtThread { NWindows::NSynchronization::CAutoResetEvent StartEvent; NWindows::NSynchronization::CAutoResetEvent FinishedEvent; NWindows::CThread Thread; bool Exit; ~CVirtThread() { WaitThreadFinish(); } void WaitThreadFinish(); // call it in destructor of child class ! WRes Create(); void Start(); virtual void Execute() = 0; void WaitExecuteFinish() { FinishedEvent.Lock(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/0040777000000000000000000000000013761647206021414 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.cpp0100777000000000000000000002350413761647206023661 0ustar00// Bcj2Coder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "Bcj2Coder.h" namespace NCompress { namespace NBcj2 { inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); } inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); } inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); } #ifndef EXTRACT_ONLY static const unsigned kBufSize = 1 << 17; #define NUM_BITS 2 #define SIGN_BIT (1 << NUM_BITS) #define MASK_HIGH (0x100 - (1 << (NUM_BITS + 1))) static const UInt32 kDefaultLimit = (1 << (24 + NUM_BITS)); static bool inline Test86MSByte(Byte b) { return (((b) + SIGN_BIT) & MASK_HIGH) == 0; } CEncoder::~CEncoder() { ::MidFree(_buf); } HRESULT CEncoder::Flush() { RINOK(_mainStream.Flush()); RINOK(_callStream.Flush()); RINOK(_jumpStream.Flush()); _rc.FlushData(); return _rc.FlushStream(); } HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != 1 || numOutStreams != 4) return E_INVALIDARG; if (!_mainStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_callStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_jumpStream.Create(1 << 18)) return E_OUTOFMEMORY; if (!_rc.Create(1 << 20)) return E_OUTOFMEMORY; if (_buf == 0) { _buf = (Byte *)MidAlloc(kBufSize); if (_buf == 0) return E_OUTOFMEMORY; } bool sizeIsDefined = false; UInt64 inSize = 0; if (inSizes) if (inSizes[0]) { inSize = *inSizes[0]; if (inSize <= kDefaultLimit) sizeIsDefined = true; } ISequentialInStream *inStream = inStreams[0]; _mainStream.SetStream(outStreams[0]); _mainStream.Init(); _callStream.SetStream(outStreams[1]); _callStream.Init(); _jumpStream.SetStream(outStreams[2]); _jumpStream.Init(); _rc.SetStream(outStreams[3]); _rc.Init(); for (unsigned i = 0; i < 256 + 2; i++) _statusEncoder[i].Init(); CMyComPtr getSubStreamSize; { inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); } UInt32 nowPos = 0; UInt64 nowPos64 = 0; UInt32 bufPos = 0; Byte prevByte = 0; UInt64 subStreamIndex = 0; UInt64 subStreamStartPos = 0; UInt64 subStreamEndPos = 0; for (;;) { UInt32 processedSize = 0; for (;;) { UInt32 size = kBufSize - (bufPos + processedSize); UInt32 processedSizeLoc; if (size == 0) break; RINOK(inStream->Read(_buf + bufPos + processedSize, size, &processedSizeLoc)); if (processedSizeLoc == 0) break; processedSize += processedSizeLoc; } UInt32 endPos = bufPos + processedSize; if (endPos < 5) { // change it for (bufPos = 0; bufPos < endPos; bufPos++) { Byte b = _buf[bufPos]; _mainStream.WriteByte(b); UInt32 index; if (b == 0xE8) index = prevByte; else if (b == 0xE9) index = 256; else if (IsJcc(prevByte, b)) index = 257; else { prevByte = b; continue; } _statusEncoder[index].Encode(&_rc, 0); prevByte = b; } return Flush(); } bufPos = 0; UInt32 limit = endPos - 5; while (bufPos <= limit) { Byte b = _buf[bufPos]; _mainStream.WriteByte(b); if (!IsJ(prevByte, b)) { bufPos++; prevByte = b; continue; } Byte nextByte = _buf[bufPos + 4]; UInt32 src = (UInt32(nextByte) << 24) | (UInt32(_buf[bufPos + 3]) << 16) | (UInt32(_buf[bufPos + 2]) << 8) | (_buf[bufPos + 1]); UInt32 dest = (nowPos + bufPos + 5) + src; // if (Test86MSByte(nextByte)) bool convert; if (getSubStreamSize) { UInt64 currentPos = (nowPos64 + bufPos); while (subStreamEndPos < currentPos) { UInt64 subStreamSize; HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); if (result == S_OK) { subStreamStartPos = subStreamEndPos; subStreamEndPos += subStreamSize; subStreamIndex++; } else if (result == S_FALSE || result == E_NOTIMPL) { getSubStreamSize.Release(); subStreamStartPos = 0; subStreamEndPos = subStreamStartPos - 1; } else return result; } if (getSubStreamSize == NULL) { if (sizeIsDefined) convert = (dest < inSize); else convert = Test86MSByte(nextByte); } else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) convert = Test86MSByte(nextByte); else { UInt64 dest64 = (currentPos + 5) + Int64(Int32(src)); convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos); } } else if (sizeIsDefined) convert = (dest < inSize); else convert = Test86MSByte(nextByte); unsigned index = GetIndex(prevByte, b); if (convert) { _statusEncoder[index].Encode(&_rc, 1); bufPos += 5; COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; for (int i = 24; i >= 0; i -= 8) s.WriteByte((Byte)(dest >> i)); prevByte = nextByte; } else { _statusEncoder[index].Encode(&_rc, 0); bufPos++; prevByte = b; } } nowPos += bufPos; nowPos64 += bufPos; if (progress) { /* const UInt64 compressedSize = _mainStream.GetProcessedSize() + _callStream.GetProcessedSize() + _jumpStream.GetProcessedSize() + _rc.GetProcessedSize(); */ RINOK(progress->SetRatioInfo(&nowPos64, NULL)); } UInt32 i = 0; while (bufPos < endPos) _buf[i++] = _buf[bufPos++]; bufPos = i; } } STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) { try { return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); } catch(const COutBufferException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } #endif STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; } STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } CDecoder::CDecoder(): _outBufSize(1 << 16) { _inBufSizes[0] = 1 << 20; _inBufSizes[1] = 1 << 20; _inBufSizes[2] = 1 << 20; _inBufSizes[3] = 1 << 20; } HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != 4 || numOutStreams != 1) return E_INVALIDARG; if (!_mainStream.Create(_inBufSizes[0])) return E_OUTOFMEMORY; if (!_callStream.Create(_inBufSizes[1])) return E_OUTOFMEMORY; if (!_jumpStream.Create(_inBufSizes[2])) return E_OUTOFMEMORY; if (!_rc.Create(_inBufSizes[3])) return E_OUTOFMEMORY; if (!_outStream.Create(_outBufSize)) return E_OUTOFMEMORY; _mainStream.SetStream(inStreams[0]); _callStream.SetStream(inStreams[1]); _jumpStream.SetStream(inStreams[2]); _rc.SetStream(inStreams[3]); _outStream.SetStream(outStreams[0]); _mainStream.Init(); _callStream.Init(); _jumpStream.Init(); _rc.Init(); _outStream.Init(); for (unsigned i = 0; i < 256 + 2; i++) _statusDecoder[i].Init(); Byte prevByte = 0; UInt32 processedBytes = 0; for (;;) { if (processedBytes >= (1 << 20) && progress) { /* const UInt64 compressedSize = _mainStream.GetProcessedSize() + _callStream.GetProcessedSize() + _jumpStream.GetProcessedSize() + _rc.GetProcessedSize(); */ const UInt64 nowPos64 = _outStream.GetProcessedSize(); RINOK(progress->SetRatioInfo(NULL, &nowPos64)); processedBytes = 0; } UInt32 i; Byte b = 0; const UInt32 kBurstSize = (1 << 18); for (i = 0; i < kBurstSize; i++) { if (!_mainStream.ReadByte(b)) return _outStream.Flush(); _outStream.WriteByte(b); if (IsJ(prevByte, b)) break; prevByte = b; } processedBytes += i; if (i == kBurstSize) continue; unsigned index = GetIndex(prevByte, b); if (_statusDecoder[index].Decode(&_rc) == 1) { UInt32 src = 0; CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; for (unsigned i = 0; i < 4; i++) { Byte b0; if (!s.ReadByte(b0)) return S_FALSE; src <<= 8; src |= ((UInt32)b0); } UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ; _outStream.WriteByte((Byte)(dest)); _outStream.WriteByte((Byte)(dest >> 8)); _outStream.WriteByte((Byte)(dest >> 16)); _outStream.WriteByte((Byte)(dest >> 24)); prevByte = (Byte)(dest >> 24); processedBytes += 4; } else prevByte = b; } } STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) { try { return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); } catch(const CInBufferException &e) { return e.ErrorCode; } catch(const COutBufferException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.h0100777000000000000000000000401313761647206023320 0ustar00// Bcj2Coder.h #ifndef __COMPRESS_BCJ2_CODER_H #define __COMPRESS_BCJ2_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" #include "RangeCoderBit.h" namespace NCompress { namespace NBcj2 { const unsigned kNumMoveBits = 5; #ifndef EXTRACT_ONLY class CEncoder: public ICompressCoder2, public CMyUnknownImp { Byte *_buf; COutBuffer _mainStream; COutBuffer _callStream; COutBuffer _jumpStream; NRangeCoder::CEncoder _rc; NRangeCoder::CBitEncoder _statusEncoder[256 + 2]; HRESULT Flush(); public: MY_UNKNOWN_IMP HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); CEncoder(): _buf(0) {}; ~CEncoder(); }; #endif class CDecoder: public ICompressCoder2, public ICompressSetBufSize, public CMyUnknownImp { CInBuffer _mainStream; CInBuffer _callStream; CInBuffer _jumpStream; NRangeCoder::CDecoder _rc; NRangeCoder::CBitDecoder _statusDecoder[256 + 2]; COutBuffer _outStream; UInt32 _inBufSizes[4]; UInt32 _outBufSize; public: MY_UNKNOWN_IMP1(ICompressSetBufSize); HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress); STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size); STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size); CDecoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Register.cpp0100777000000000000000000000075213761647206024411 0ustar00// Bcj2Register.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "Bcj2Coder.h" static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); } #ifndef EXTRACT_ONLY static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder()); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false }; REGISTER_CODEC(BCJ2) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.cpp0100777000000000000000000000051413761647206023573 0ustar00// BcjCoder.cpp #include "StdAfx.h" #include "BcjCoder.h" UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size) { return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1); } UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size) { return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.h0100777000000000000000000000047413761647206023245 0ustar00// BcjCoder.h #ifndef __COMPRESS_BCJ_CODER_H #define __COMPRESS_BCJ_CODER_H #include "../../../C/Bra.h" #include "BranchCoder.h" struct CBranch86 { UInt32 _prevMask; void x86Init() { x86_Convert_Init(_prevMask); } }; MyClassB(BCJ_x86, 0x01, 3, CBranch86 , virtual void SubInit() { x86Init(); }) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BcjRegister.cpp0100777000000000000000000000072113761647206024323 0ustar00// BcjRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "BcjCoder.h" static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); } #ifndef EXTRACT_ONLY static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder()); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true }; REGISTER_CODEC(BCJ) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.cpp0100777000000000000000000000051713761647206024275 0ustar00// BranchCoder.cpp #include "StdAfx.h" #include "BranchCoder.h" STDMETHODIMP CBranchConverter::Init() { _bufferPos = 0; SubInit(); return S_OK; } STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size) { UInt32 processedSize = SubFilter(data, size); _bufferPos += processedSize; return processedSize; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.h0100777000000000000000000000250613761647206023742 0ustar00// BranchCoder.h #ifndef __COMPRESS_BRANCH_CODER_H #define __COMPRESS_BRANCH_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" class CBranchConverter: public ICompressFilter, public CMyUnknownImp { protected: UInt32 _bufferPos; virtual void SubInit() {} virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0; public: MY_UNKNOWN_IMP; STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; #define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \ { public: UInt32 SubFilter(Byte *data, UInt32 size); }; #define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \ { public: UInt32 SubFilter(Byte *data, UInt32 size); }; #define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; #define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; #define MyClassA(Name, id, subId) \ MyClassEncoderA(Name ## _Encoder) \ MyClassDecoderA(Name ## _Decoder) #define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \ MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \ MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.cpp0100777000000000000000000000077613761647206024143 0ustar00// BranchMisc.cpp #include "StdAfx.h" #include "../../../C/Bra.h" #include "BranchMisc.h" #define SUB_FILTER_IMP2(name, coderStr, coderNum) \ UInt32 CBC_ ## name ## coderStr::SubFilter(Byte *data, UInt32 size) \ { return (UInt32)::name ## Convert(data, size, _bufferPos, coderNum); } #define SUB_FILTER_IMP(name) \ SUB_FILTER_IMP2(name, Encoder, 1) \ SUB_FILTER_IMP2(name, Decoder, 0) \ SUB_FILTER_IMP(ARM_) SUB_FILTER_IMP(ARMT_) SUB_FILTER_IMP(PPC_) SUB_FILTER_IMP(SPARC_) SUB_FILTER_IMP(IA64_) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.h0100777000000000000000000000040213761647206023572 0ustar00// BranchMisc.h #ifndef __COMPRESS_BRANCH_MISC_H #define __COMPRESS_BRANCH_MISC_H #include "BranchCoder.h" MyClassA(BC_ARM, 0x05, 1) MyClassA(BC_ARMT, 0x07, 1) MyClassA(BC_PPC, 0x02, 5) MyClassA(BC_SPARC, 0x08, 5) MyClassA(BC_IA64, 0x04, 1) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/BranchRegister.cpp0100777000000000000000000000154313761647206025025 0ustar00// BranchRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "BranchMisc.h" #define CREATE_CODEC(x) \ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); } CREATE_CODEC(BC_PPC) CREATE_CODEC(BC_IA64) CREATE_CODEC(BC_ARM) CREATE_CODEC(BC_ARMT) CREATE_CODEC(BC_SPARC) #define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true } static CCodecInfo g_CodecsInfo[] = { METHOD_ITEM(BC_PPC, 0x02, 0x05, L"PPC"), METHOD_ITEM(BC_IA64, 0x04, 1, L"IA64"), METHOD_ITEM(BC_ARM, 0x05, 1, L"ARM"), METHOD_ITEM(BC_ARMT, 0x07, 1, L"ARMT"), METHOD_ITEM(BC_SPARC, 0x08, 0x05, L"SPARC") }; REGISTER_CODECS(Branch) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/ByteSwap.cpp0100777000000000000000000000275013761647206023662 0ustar00// ByteSwap.cpp #include "StdAfx.h" #include "../../Common/MyCom.h" #include "../ICoder.h" #include "../Common/RegisterCodec.h" class CByteSwap2: public ICompressFilter, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; class CByteSwap4: public ICompressFilter, public CMyUnknownImp { public: MY_UNKNOWN_IMP STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); }; STDMETHODIMP CByteSwap2::Init() { return S_OK; } STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size) { const UInt32 kStep = 2; UInt32 i; for (i = 0; i + kStep <= size; i += kStep) { Byte b = data[i]; data[i] = data[i + 1]; data[i + 1] = b; } return i; } STDMETHODIMP CByteSwap4::Init() { return S_OK; } STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size) { const UInt32 kStep = 4; UInt32 i; for (i = 0; i + kStep <= size; i += kStep) { Byte b0 = data[i]; Byte b1 = data[i + 1]; data[i] = data[i + 3]; data[i + 1] = data[i + 2]; data[i + 2] = b1; data[i + 3] = b0; } return i; } static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); } static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); } static CCodecInfo g_CodecsInfo[] = { { CreateCodec2, CreateCodec2, 0x020302, L"Swap2", 1, true }, { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true } }; REGISTER_CODECS(ByteSwap) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Compress.pri0100777000000000000000000000271413761647206023727 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.h \ $$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/RangeCoder.h \ $$7ZIP_BASE/CPP/7zip/Compress/RangeCoderBit.h \ $$7ZIP_BASE/CPP/7zip/Compress/StdAfx.h SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Register.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BcjRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/BranchRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/ByteSwap.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/CopyRegister.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/DeltaFilter.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Register.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.cpp \ $$7ZIP_BASE/CPP/7zip/Compress/LzmaRegister.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.cpp0100777000000000000000000000336113761647206024012 0ustar00// Compress/CopyCoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "CopyCoder.h" namespace NCompress { static const UInt32 kBufferSize = 1 << 17; CCopyCoder::~CCopyCoder() { ::MidFree(_buffer); } STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (!_buffer) { _buffer = (Byte *)::MidAlloc(kBufferSize); if (!_buffer) return E_OUTOFMEMORY; } TotalSize = 0; for (;;) { UInt32 size = kBufferSize; if (outSize && size > *outSize - TotalSize) size = (UInt32)(*outSize - TotalSize); RINOK(inStream->Read(_buffer, size, &size)); if (size == 0) break; if (outStream) { RINOK(WriteStream(outStream, _buffer, size)); } TotalSize += size; if (progress) { RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); } } return S_OK; } STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value) { *value = TotalSize; return S_OK; } HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { CMyComPtr copyCoder = new CCopyCoder; return copyCoder->Code(inStream, outStream, NULL, NULL, progress); } HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) { NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)); return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.h0100777000000000000000000000165113761647206023457 0ustar00// Compress/CopyCoder.h #ifndef __COMPRESS_COPY_CODER_H #define __COMPRESS_COPY_CODER_H #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { class CCopyCoder: public ICompressCoder, public ICompressGetInStreamProcessedSize, public CMyUnknownImp { Byte *_buffer; public: UInt64 TotalSize; CCopyCoder(): TotalSize(0), _buffer(0) {}; ~CCopyCoder(); MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); }; HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/CopyRegister.cpp0100777000000000000000000000046313761647206024542 0ustar00// CopyRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "CopyCoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); } static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodec, 0x00, L"Copy", 1, false }; REGISTER_CODEC(Copy) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/DeltaFilter.cpp0100777000000000000000000000571213761647206024324 0ustar00// DeltaFilter.cpp #include "StdAfx.h" #include "../../../C/Delta.h" #include "../Common/RegisterCodec.h" #include "BranchCoder.h" struct CDelta { unsigned _delta; Byte _state[DELTA_STATE_SIZE]; CDelta(): _delta(1) {} void DeltaInit() { Delta_Init(_state); } }; class CDeltaEncoder: public ICompressFilter, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, CDelta, public CMyUnknownImp { public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); }; class CDeltaDecoder: public ICompressFilter, public ICompressSetDecoderProperties2, CDelta, public CMyUnknownImp { public: MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) STDMETHOD(Init)(); STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); }; STDMETHODIMP CDeltaEncoder::Init() { DeltaInit(); return S_OK; } STDMETHODIMP_(UInt32) CDeltaEncoder::Filter(Byte *data, UInt32 size) { Delta_Encode(_state, _delta, data, size); return size; } STDMETHODIMP CDeltaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) { UInt32 delta = _delta; for (UInt32 i = 0; i < numProps; i++) { const PROPVARIANT &prop = props[i]; PROPID propID = propIDs[i]; if (propID >= NCoderPropID::kReduceSize) continue; if (prop.vt != VT_UI4) return E_INVALIDARG; switch (propID) { case NCoderPropID::kDefaultProp: delta = (UInt32)prop.ulVal; if (delta < 1 || delta > 256) return E_INVALIDARG; break; case NCoderPropID::kNumThreads: break; case NCoderPropID::kLevel: break; default: return E_INVALIDARG; } } _delta = delta; return S_OK; } STDMETHODIMP CDeltaEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte prop = (Byte)(_delta - 1); return outStream->Write(&prop, 1, NULL); } STDMETHODIMP CDeltaDecoder::Init() { DeltaInit(); return S_OK; } STDMETHODIMP_(UInt32) CDeltaDecoder::Filter(Byte *data, UInt32 size) { Delta_Decode(_state, _delta, data, size); return size; } STDMETHODIMP CDeltaDecoder::SetDecoderProperties2(const Byte *props, UInt32 size) { if (size != 1) return E_INVALIDARG; _delta = (unsigned)props[0] + 1; return S_OK; } #define CREATE_CODEC(x) \ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## Decoder); } \ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## Encoder); } CREATE_CODEC(Delta) #define METHOD_ITEM(x, id, name) { CreateCodec ## x, CreateCodec ## x ## Out, id, name, 1, true } static CCodecInfo g_CodecsInfo[] = { METHOD_ITEM(Delta, 3, L"Delta") }; REGISTER_CODECS(Delta) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.cpp0100777000000000000000000001157613761647206024405 0ustar00// Lzma2Decoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "Lzma2Decoder.h" static HRESULT SResToHRESULT(SRes res) { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; // case SZ_ERROR_PROGRESS: return E_ABORT; case SZ_ERROR_DATA: return S_FALSE; } return E_FAIL; } namespace NCompress { namespace NLzma2 { static const UInt32 kInBufSize = 1 << 20; CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false) { Lzma2Dec_Construct(&_state); } static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CDecoder::~CDecoder() { Lzma2Dec_Free(&_state, &g_Alloc); MyFree(_inBuf); } STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size) { if (size != 1) return SZ_ERROR_UNSUPPORTED; RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc))); if (_inBuf == 0) { _inBuf = (Byte *)MyAlloc(kInBufSize); if (_inBuf == 0) return E_OUTOFMEMORY; } return S_OK; } STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; } STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) { _outSizeDefined = (outSize != NULL); if (_outSizeDefined) _outSize = *outSize; Lzma2Dec_Init(&_state); _inPos = _inSize = 0; _inSizeProcessed = _outSizeProcessed = 0; return S_OK; } STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (_inBuf == 0) return S_FALSE; SetOutStreamSize(outSize); for (;;) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize)); } SizeT dicPos = _state.decoder.dicPos; SizeT curSize = _state.decoder.dicBufSize - dicPos; const UInt32 kStepSize = ((UInt32)1 << 22); if (curSize > kStepSize) curSize = (SizeT)kStepSize; ELzmaFinishMode finishMode = LZMA_FINISH_ANY; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < curSize) { curSize = (SizeT)rem; /* // finishMode = LZMA_FINISH_END; we can't use LZMA_FINISH_END here to allow partial decoding */ } } SizeT inSizeProcessed = _inSize - _inPos; ELzmaStatus status; SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status); _inPos += (UInt32)inSizeProcessed; _inSizeProcessed += inSizeProcessed; SizeT outSizeProcessed = _state.decoder.dicPos - dicPos; _outSizeProcessed += outSizeProcessed; bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0); bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize); if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding) { HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos); if (res != 0) return S_FALSE; RINOK(res2); if (stopDecoding) return S_OK; if (finished) return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE); } if (_state.decoder.dicPos == _state.decoder.dicBufSize) _state.decoder.dicPos = 0; if (progress != NULL) { RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed)); } } } #ifndef NO_READ_FROM_CODER STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; do { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize)); } { SizeT inProcessed = _inSize - _inPos; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < size) size = (UInt32)rem; } SizeT outProcessed = size; ELzmaStatus status; SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status); _inPos += (UInt32)inProcessed; _inSizeProcessed += inProcessed; _outSizeProcessed += outProcessed; size -= (UInt32)outProcessed; data = (Byte *)data + outProcessed; if (processedSize) *processedSize += (UInt32)outProcessed; RINOK(SResToHRESULT(res)); if (inProcessed == 0 && outProcessed == 0) return S_OK; } } while (size != 0); return S_OK; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.h0100777000000000000000000000315513761647206024044 0ustar00// Lzma2Decoder.h #ifndef __LZMA2_DECODER_H #define __LZMA2_DECODER_H #include "../../../C/Lzma2Dec.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma2 { class CDecoder: public ICompressCoder, public ICompressSetDecoderProperties2, public ICompressGetInStreamProcessedSize, #ifndef NO_READ_FROM_CODER public ICompressSetInStream, public ICompressSetOutStreamSize, public ISequentialInStream, #endif public CMyUnknownImp { CMyComPtr _inStream; Byte *_inBuf; UInt32 _inPos; UInt32 _inSize; CLzma2Dec _state; bool _outSizeDefined; UInt64 _outSize; UInt64 _inSizeProcessed; UInt64 _outSizeProcessed; public: #ifndef NO_READ_FROM_CODER MY_UNKNOWN_IMP5( ICompressSetDecoderProperties2, ICompressGetInStreamProcessedSize, ICompressSetInStream, ICompressSetOutStreamSize, ISequentialInStream) #else MY_UNKNOWN_IMP2( ICompressSetDecoderProperties2, ICompressGetInStreamProcessedSize) #endif STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *_inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(ReleaseInStream)(); STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); #ifndef NO_READ_FROM_CODER STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); #endif CDecoder(); virtual ~CDecoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.cpp0100777000000000000000000000506313761647206024411 0ustar00// Lzma2Encoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/CWrappers.h" #include "../Common/StreamUtils.h" #include "Lzma2Encoder.h" namespace NCompress { namespace NLzma { HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); } namespace NLzma2 { static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } static void SzBigFree(void *, void *address) { BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CEncoder::CEncoder() { _encoder = 0; _encoder = Lzma2Enc_Create(&g_Alloc, &g_BigAlloc); if (_encoder == 0) throw 1; } CEncoder::~CEncoder() { if (_encoder != 0) Lzma2Enc_Destroy(_encoder); } HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props) { switch (propID) { case NCoderPropID::kBlockSize: if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; break; case NCoderPropID::kNumThreads: if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break; default: RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)); } return S_OK; } STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { CLzma2EncProps lzma2Props; Lzma2EncProps_Init(&lzma2Props); for (UInt32 i = 0; i < numProps; i++) { RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props)); } return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props)); } STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte prop = Lzma2Enc_WriteProperties(_encoder); return WriteStream(outStream, &prop, 1); } STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { CSeqInStreamWrap inWrap(inStream); CSeqOutStreamWrap outWrap(outStream); CCompressProgressWrap progressWrap(progress); SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL); if (res == SZ_ERROR_READ && inWrap.Res != S_OK) return inWrap.Res; if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) return outWrap.Res; if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) return progressWrap.Res; return SResToHRESULT(res); } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.h0100777000000000000000000000152313761647206024053 0ustar00// Lzma2Encoder.h #ifndef __LZMA2_ENCODER_H #define __LZMA2_ENCODER_H #include "../../../C/Lzma2Enc.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma2 { class CEncoder: public ICompressCoder, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, public CMyUnknownImp { CLzma2EncHandle _encoder; public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); CEncoder(); virtual ~CEncoder(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Register.cpp0100777000000000000000000000100013761647206024601 0ustar00// Lzma2Register.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "Lzma2Decoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); } #ifndef EXTRACT_ONLY #include "Lzma2Encoder.h" static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CEncoder); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x21, L"LZMA2", 1, false }; REGISTER_CODEC(LZMA2) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.cpp0100777000000000000000000001577013761647206024323 0ustar00// LzmaDecoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/StreamUtils.h" #include "LzmaDecoder.h" static HRESULT SResToHRESULT(SRes res) { switch(res) { case SZ_OK: return S_OK; case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; case SZ_ERROR_DATA: return S_FALSE; } return E_FAIL; } namespace NCompress { namespace NLzma { CDecoder::CDecoder(): _inBuf(0), _propsWereSet(false), _outSizeDefined(false), _inBufSize(1 << 20), _outBufSize(1 << 22), FinishStream(false), NeedMoreInput(false) { _inSizeProcessed = 0; _inPos = _inSize = 0; LzmaDec_Construct(&_state); } static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CDecoder::~CDecoder() { LzmaDec_Free(&_state, &g_Alloc); MyFree(_inBuf); } STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; } STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } HRESULT CDecoder::CreateInputBuffer() { if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated) { MyFree(_inBuf); _inBuf = (Byte *)MyAlloc(_inBufSize); if (_inBuf == 0) return E_OUTOFMEMORY; _inBufSizeAllocated = _inBufSize; } return S_OK; } STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size) { RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc))); _propsWereSet = true; return CreateInputBuffer(); } void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize) { _outSizeDefined = (outSize != NULL); if (_outSizeDefined) _outSize = *outSize; _outSizeProcessed = 0; _wrPos = 0; LzmaDec_Init(&_state); } STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) { _inSizeProcessed = 0; _inPos = _inSize = 0; NeedMoreInput = false; SetOutStreamSizeResume(outSize); return S_OK; } HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { if (_inBuf == 0 || !_propsWereSet) return S_FALSE; UInt64 startInProgress = _inSizeProcessed; SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize); for (;;) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); } SizeT dicPos = _state.dicPos; SizeT curSize = next - dicPos; ELzmaFinishMode finishMode = LZMA_FINISH_ANY; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem <= curSize) { curSize = (SizeT)rem; if (FinishStream) finishMode = LZMA_FINISH_END; } } SizeT inSizeProcessed = _inSize - _inPos; ELzmaStatus status; SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status); _inPos += (UInt32)inSizeProcessed; _inSizeProcessed += inSizeProcessed; SizeT outSizeProcessed = _state.dicPos - dicPos; _outSizeProcessed += outSizeProcessed; bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0); bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize); if (res != 0 || _state.dicPos == next || finished || stopDecoding) { HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos); _wrPos = _state.dicPos; if (_state.dicPos == _state.dicBufSize) { _state.dicPos = 0; _wrPos = 0; } next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize); if (res != 0) return S_FALSE; RINOK(res2); if (stopDecoding) { if (status == LZMA_STATUS_NEEDS_MORE_INPUT) NeedMoreInput = true; if (FinishStream && status != LZMA_STATUS_FINISHED_WITH_MARK && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) return S_FALSE; return S_OK; } if (finished) { if (status == LZMA_STATUS_NEEDS_MORE_INPUT) NeedMoreInput = true; return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE); } } if (progress) { UInt64 inSize = _inSizeProcessed - startInProgress; RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed)); } } } STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (_inBuf == 0) return E_INVALIDARG; SetOutStreamSize(outSize); return CodeSpec(inStream, outStream, progress); } #ifndef NO_READ_FROM_CODER STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; do { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); } { SizeT inProcessed = _inSize - _inPos; if (_outSizeDefined) { const UInt64 rem = _outSize - _outSizeProcessed; if (rem < size) size = (UInt32)rem; } SizeT outProcessed = size; ELzmaStatus status; SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status); _inPos += (UInt32)inProcessed; _inSizeProcessed += inProcessed; _outSizeProcessed += outProcessed; size -= (UInt32)outProcessed; data = (Byte *)data + outProcessed; if (processedSize) *processedSize += (UInt32)outProcessed; RINOK(SResToHRESULT(res)); if (inProcessed == 0 && outProcessed == 0) return S_OK; } } while (size != 0); return S_OK; } HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) { SetOutStreamSizeResume(outSize); return CodeSpec(_inStream, outStream, progress); } HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize) { RINOK(CreateInputBuffer()); if (processedSize) *processedSize = 0; while (size > 0) { if (_inPos == _inSize) { _inPos = _inSize = 0; RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize)); if (_inSize == 0) break; } { UInt32 curSize = _inSize - _inPos; if (curSize > size) curSize = size; memcpy(data, _inBuf + _inPos, curSize); _inPos += curSize; _inSizeProcessed += curSize; size -= curSize; data = (Byte *)data + curSize; if (processedSize) *processedSize += curSize; } } return S_OK; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.h0100777000000000000000000000477313761647206023771 0ustar00// LzmaDecoder.h #ifndef __LZMA_DECODER_H #define __LZMA_DECODER_H #include "../../../C/LzmaDec.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma { class CDecoder: public ICompressCoder, public ICompressSetDecoderProperties2, public ICompressSetBufSize, #ifndef NO_READ_FROM_CODER public ICompressSetInStream, public ICompressSetOutStreamSize, public ISequentialInStream, #endif public CMyUnknownImp { CMyComPtr _inStream; Byte *_inBuf; UInt32 _inPos; UInt32 _inSize; CLzmaDec _state; bool _propsWereSet; bool _outSizeDefined; UInt64 _outSize; UInt64 _inSizeProcessed; UInt64 _outSizeProcessed; UInt32 _inBufSizeAllocated; UInt32 _inBufSize; UInt32 _outBufSize; SizeT _wrPos; HRESULT CreateInputBuffer(); HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); void SetOutStreamSizeResume(const UInt64 *outSize); public: MY_QUERYINTERFACE_BEGIN2(ICompressCoder) MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2) MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize) #ifndef NO_READ_FROM_CODER MY_QUERYINTERFACE_ENTRY(ICompressSetInStream) MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize) MY_QUERYINTERFACE_ENTRY(ISequentialInStream) #endif MY_QUERYINTERFACE_END MY_ADDREF_RELEASE STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size); STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size); #ifndef NO_READ_FROM_CODER STDMETHOD(SetInStream)(ISequentialInStream *inStream); STDMETHOD(ReleaseInStream)(); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize); UInt64 GetInputProcessedSize() const { return _inSizeProcessed; } #endif bool FinishStream; // set it before decoding, if you need to decode full LZMA stream bool NeedMoreInput; // it's set by decoder, if it needs more input data to decode stream CDecoder(); virtual ~CDecoder(); UInt64 GetOutputProcessedSize() const { return _outSizeProcessed; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.cpp0100777000000000000000000001043713761647206024330 0ustar00// LzmaEncoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../Common/CWrappers.h" #include "../Common/StreamUtils.h" #include "LzmaEncoder.h" namespace NCompress { namespace NLzma { static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } static void SzBigFree(void *, void *address) { BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } static void SzFree(void *, void *address) { MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; CEncoder::CEncoder() { _encoder = 0; _encoder = LzmaEnc_Create(&g_Alloc); if (_encoder == 0) throw 1; } CEncoder::~CEncoder() { if (_encoder != 0) LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc); } inline wchar_t GetUpperChar(wchar_t c) { if (c >= 'a' && c <= 'z') c -= 0x20; return c; } static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) { wchar_t c = GetUpperChar(*s++); if (c == L'H') { if (GetUpperChar(*s++) != L'C') return 0; int numHashBytesLoc = (int)(*s++ - L'0'); if (numHashBytesLoc < 4 || numHashBytesLoc > 4) return 0; if (*s++ != 0) return 0; *btMode = 0; *numHashBytes = numHashBytesLoc; return 1; } if (c != L'B') return 0; if (GetUpperChar(*s++) != L'T') return 0; int numHashBytesLoc = (int)(*s++ - L'0'); if (numHashBytesLoc < 2 || numHashBytesLoc > 4) return 0; c = GetUpperChar(*s++); if (c != L'\0') return 0; *btMode = 1; *numHashBytes = numHashBytesLoc; return 1; } #define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break; HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) { if (propID == NCoderPropID::kMatchFinder) { if (prop.vt != VT_BSTR) return E_INVALIDARG; return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; } if (propID > NCoderPropID::kReduceSize) return S_OK; if (propID == NCoderPropID::kReduceSize) { if (prop.vt == VT_UI8) ep.reduceSize = prop.uhVal.QuadPart; return S_OK; } if (prop.vt != VT_UI4) return E_INVALIDARG; UInt32 v = prop.ulVal; switch (propID) { case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break; SET_PROP_32(kLevel, level) SET_PROP_32(kNumFastBytes, fb) SET_PROP_32(kMatchFinderCycles, mc) SET_PROP_32(kAlgorithm, algo) SET_PROP_32(kDictionarySize, dictSize) SET_PROP_32(kPosStateBits, pb) SET_PROP_32(kLitPosBits, lp) SET_PROP_32(kLitContextBits, lc) SET_PROP_32(kNumThreads, numThreads) default: return E_INVALIDARG; } return S_OK; } STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { CLzmaEncProps props; LzmaEncProps_Init(&props); for (UInt32 i = 0; i < numProps; i++) { const PROPVARIANT &prop = coderProps[i]; PROPID propID = propIDs[i]; switch (propID) { case NCoderPropID::kEndMarker: if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break; default: RINOK(SetLzmaProp(propID, prop, props)); } } return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); } STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) { Byte props[LZMA_PROPS_SIZE]; size_t size = LZMA_PROPS_SIZE; RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)); return WriteStream(outStream, props, size); } STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { CSeqInStreamWrap inWrap(inStream); CSeqOutStreamWrap outWrap(outStream); CCompressProgressWrap progressWrap(progress); SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc); _inputProcessed = inWrap.Processed; if (res == SZ_ERROR_READ && inWrap.Res != S_OK) return inWrap.Res; if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) return outWrap.Res; if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) return progressWrap.Res; return SResToHRESULT(res); } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.h0100777000000000000000000000165213761647206023774 0ustar00// LzmaEncoder.h #ifndef __LZMA_ENCODER_H #define __LZMA_ENCODER_H #include "../../../C/LzmaEnc.h" #include "../../Common/MyCom.h" #include "../ICoder.h" namespace NCompress { namespace NLzma { class CEncoder: public ICompressCoder, public ICompressSetCoderProperties, public ICompressWriteCoderProperties, public CMyUnknownImp { CLzmaEncHandle _encoder; UInt64 _inputProcessed; public: MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); CEncoder(); virtual ~CEncoder(); UInt64 GetInputProcessedSize() const { return _inputProcessed; } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/LzmaRegister.cpp0100777000000000000000000000077513761647206024541 0ustar00// LzmaRegister.cpp #include "StdAfx.h" #include "../Common/RegisterCodec.h" #include "LzmaDecoder.h" static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); } #ifndef EXTRACT_ONLY #include "LzmaEncoder.h" static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CEncoder); } #else #define CreateCodecOut 0 #endif static CCodecInfo g_CodecInfo = { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false }; REGISTER_CODEC(LZMA) qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/RangeCoder.h0100777000000000000000000000736413761647206023610 0ustar00// Compress/RangeCoder.h // 2013-01-10 : Igor Pavlov : Public domain #ifndef __COMPRESS_RANGE_CODER_H #define __COMPRESS_RANGE_CODER_H #include "../Common/InBuffer.h" #include "../Common/OutBuffer.h" namespace NCompress { namespace NRangeCoder { const unsigned kNumTopBits = 24; const UInt32 kTopValue = (1 << kNumTopBits); class CEncoder { UInt32 _cacheSize; Byte _cache; public: UInt64 Low; UInt32 Range; COutBuffer Stream; bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); } void Init() { Stream.Init(); Low = 0; Range = 0xFFFFFFFF; _cacheSize = 1; _cache = 0; } void FlushData() { // Low += 1; for (int i = 0; i < 5; i++) ShiftLow(); } HRESULT FlushStream() { return Stream.Flush(); } void Encode(UInt32 start, UInt32 size, UInt32 total) { Low += start * (Range /= total); Range *= size; while (Range < kTopValue) { Range <<= 8; ShiftLow(); } } void ShiftLow() { if ((UInt32)Low < (UInt32)0xFF000000 || (unsigned)(Low >> 32) != 0) { Byte temp = _cache; do { Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32))); temp = 0xFF; } while (--_cacheSize != 0); _cache = (Byte)((UInt32)Low >> 24); } _cacheSize++; Low = (UInt32)Low << 8; } void EncodeDirectBits(UInt32 value, int numBits) { for (numBits--; numBits >= 0; numBits--) { Range >>= 1; Low += Range & (0 - ((value >> numBits) & 1)); if (Range < kTopValue) { Range <<= 8; ShiftLow(); } } } void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol) { UInt32 newBound = (Range >> numTotalBits) * size0; if (symbol == 0) Range = newBound; else { Low += newBound; Range -= newBound; } while (Range < kTopValue) { Range <<= 8; ShiftLow(); } } UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; } }; class CDecoder { public: CInBuffer Stream; UInt32 Range; UInt32 Code; bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } void Normalize() { while (Range < kTopValue) { Code = (Code << 8) | Stream.ReadByte(); Range <<= 8; } } void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); } void Init() { Stream.Init(); Code = 0; Range = 0xFFFFFFFF; for (int i = 0; i < 5; i++) Code = (Code << 8) | Stream.ReadByte(); } UInt32 GetThreshold(UInt32 total) { return (Code) / (Range /= total); } void Decode(UInt32 start, UInt32 size) { Code -= start * Range; Range *= size; Normalize(); } UInt32 DecodeDirectBits(int numTotalBits) { UInt32 range = Range; UInt32 code = Code; UInt32 result = 0; for (int i = numTotalBits; i != 0; i--) { range >>= 1; /* result <<= 1; if (code >= range) { code -= range; result |= 1; } */ UInt32 t = (code - range) >> 31; code -= range & (t - 1); result = (result << 1) | (1 - t); if (range < kTopValue) { code = (code << 8) | Stream.ReadByte(); range <<= 8; } } Range = range; Code = code; return result; } UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) { UInt32 newBound = (Range >> numTotalBits) * size0; UInt32 symbol; if (Code < newBound) { symbol = 0; Range = newBound; } else { symbol = 1; Code -= newBound; Range -= newBound; } Normalize(); return symbol; } UInt64 GetProcessedSize() { return Stream.GetProcessedSize(); } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/RangeCoderBit.h0100777000000000000000000000553413761647206024244 0ustar00// Compress/RangeCoderBit.h // 2013-01-10 : Igor Pavlov : Public domain #ifndef __COMPRESS_RANGE_CODER_BIT_H #define __COMPRESS_RANGE_CODER_BIT_H #include "RangeCoder.h" namespace NCompress { namespace NRangeCoder { const unsigned kNumBitModelTotalBits = 11; const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits); const unsigned kNumMoveReducingBits = 4; const unsigned kNumBitPriceShiftBits = 4; const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits; extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; template class CBitModel { public: UInt32 Prob; void UpdateModel(UInt32 symbol) { /* Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits; Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits); */ if (symbol == 0) Prob += (kBitModelTotal - Prob) >> numMoveBits; else Prob -= (Prob) >> numMoveBits; } public: void Init() { Prob = kBitModelTotal / 2; } }; template class CBitEncoder: public CBitModel { public: void Encode(CEncoder *encoder, UInt32 symbol) { /* encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol); this->UpdateModel(symbol); */ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob; if (symbol == 0) { encoder->Range = newBound; this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; } else { encoder->Low += newBound; encoder->Range -= newBound; this->Prob -= (this->Prob) >> numMoveBits; } if (encoder->Range < kTopValue) { encoder->Range <<= 8; encoder->ShiftLow(); } } UInt32 GetPrice(UInt32 symbol) const { return ProbPrices[(this->Prob ^ ((-(int)(Int32)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; } UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; } UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; } }; template class CBitDecoder: public CBitModel { public: UInt32 Decode(CDecoder *decoder) { UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob; if (decoder->Code < newBound) { decoder->Range = newBound; this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; if (decoder->Range < kTopValue) { decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); decoder->Range <<= 8; } return 0; } else { decoder->Range -= newBound; decoder->Code -= newBound; this->Prob -= (this->Prob) >> numMoveBits; if (decoder->Range < kTopValue) { decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); decoder->Range <<= 8; } return 1; } } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Compress/StdAfx.h0100777000000000000000000000013513761647206022755 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/Guid.txt0100777000000000000000000000661213761647206021257 0ustar00{23170F69-40C1-278A-0000-00yy00xx0000} 00 IProgress.h 05 IProgress 01 IFolderArchive.h // 05 IArchiveFolder // old // 06 IInFolderArchive // old 07 IFileExtractCallback.h::IFolderArchiveExtractCallback // 0A IOutFolderArchive 0B IFolderArchiveUpdateCallback 0C Agent.h::IArchiveFolderInternal 0D IArchiveFolder 0E IInFolderArchive 0F IOutFolderArchive 20 IFileExtractCallback.h::IGetProp 30 IFileExtractCallback.h::IFolderExtractToStreamCallback 03 IStream.h 01 ISequentialInStream 02 ISequentialOutStream 03 IInStream 04 IOutStream 06 IStreamGetSize 07 IOutStreamFlush 08 IStreamGetProps 09 IStreamGetProps2 04 ICoder.h 04 ICompressProgressInfo 05 ICompressCoder 18 ICompressCoder2 20 ICompressSetCoderProperties 21 ICompressSetDecoderProperties // 22 ICompressSetDecoderProperties2 23 ICompressWriteCoderProperties 24 ICompressGetInStreamProcessedSize 25 ICompressSetCoderMt 30 ICompressGetSubStreamSize 31 ICompressSetInStream 32 ICompressSetOutStream 33 ICompressSetInStreamSize 34 ICompressSetOutStreamSize 35 ICompressSetBufSize 40 ICompressFilter 60 ICompressCodecsInfo 61 ISetCompressCodecsInfo 80 ICryptoProperties 88 ICryptoResetSalt 8C ICryptoResetInitVector 90 ICryptoSetPassword A0 ICryptoSetCRC C0 IHasher C1 IHashers 05 IPassword.h 10 ICryptoGetTextPassword 11 ICryptoGetTextPassword2 06 IArchive.h 03 ISetProperties 04 IArchiveKeepModeForNextOpen 05 IArchiveAllowTail 10 IArchiveOpenCallback 20 IArchiveExtractCallback 30 IArchiveOpenVolumeCallback 40 IInArchiveGetStream 50 IArchiveOpenSetSubArchiveName 60 IInArchive 61 IArchiveOpenSeq 70 IArchiveGetRawProps 71 IArchiveGetRootProps 80 IArchiveUpdateCallback 82 IArchiveUpdateCallback2 A0 IOutArchive 08 IFolder.h 00 IFolderFolder 01 IEnumProperties 02 IFolderGetTypeID 03 IFolderGetPath 04 IFolderWasChanged 05 // IFolderReload 06 // IFolderOperations old 07 IFolderGetSystemIconIndex 08 IFolderGetItemFullSize 09 IFolderClone 0A IFolderSetFlatMode 0B IFolderOperationsExtractCallback 0C // 0D // 0E IFolderProperties 0F 10 IFolderArcProps 11 IGetFolderArcProps 12 // IFolderOperations 13 IFolderOperations 14 IFolderCalcItemFullSize 15 IFolderCompare 16 IFolderGetItemName 09 IFolder.h :: FOLDER_MANAGER_INTERFACE 00 - 04 // old IFolderManager 05 IFolderManager // 0A PluginInterface.h 00 IInitContextMenu 01 IPluginOptionsCallback 02 IPluginOptions Handler GUIDs: {23170F69-40C1-278A-1000-000110xx0000} 01 Zip 02 BZip2 03 Rar 04 Arj 05 Z 06 Lzh 07 7z 08 Cab 09 Nsis 0A lzma 0B lzma86 0C xz 0D ppmd CD IHex CE Hxs CF TE D0 UEFIc D1 UEFIs D2 SquashFS D3 CramFS D4 APM D5 Mslz D6 Flv D7 Swf D8 Swfc D9 Ntfs DA Fat DB Mbr DC Vhd DD Pe DE Elf DF Mach-O E0 Udf E1 Xar E2 Mub E3 Hfs E4 Dmg E5 Compound E6 Wim E7 Iso E8 E9 Chm EA Split EB Rpm EC Deb ED Cpio EE Tar EF GZip {23170F69-40C1-278A-1000-000100030000} CAgentArchiveHandle {23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu {23170F69-40C1-278B- old codecs clsids {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions {23170F69-40C1-2790-id} Codec Decoders {23170F69-40C1-2791-id} Codec Encoders {23170F69-40C1-2792-id} Hashers qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/ICoder.h0100777000000000000000000001223113761647206021136 0ustar00// ICoder.h #ifndef __ICODER_H #define __ICODER_H #include "IStream.h" #define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x) CODER_INTERFACE(ICompressProgressInfo, 0x04) { STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE; }; CODER_INTERFACE(ICompressCoder, 0x05) { STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) PURE; }; CODER_INTERFACE(ICompressCoder2, 0x18) { STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, ICompressProgressInfo *progress) PURE; }; namespace NCoderPropID { enum EEnum { kDefaultProp = 0, kDictionarySize, kUsedMemorySize, kOrder, kBlockSize, kPosStateBits, kLitContextBits, kLitPosBits, kNumFastBytes, kMatchFinder, kMatchFinderCycles, kNumPasses, kAlgorithm, kNumThreads, kEndMarker, kLevel, kReduceSize // estimated size of data that will be compressed. Encoder can use this value to reduce dictionary size. }; } CODER_INTERFACE(ICompressSetCoderProperties, 0x20) { STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE; }; /* CODER_INTERFACE(ICompressSetCoderProperties, 0x21) { STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE; }; */ CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22) { STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE; }; CODER_INTERFACE(ICompressWriteCoderProperties, 0x23) { STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE; }; CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24) { STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE; }; CODER_INTERFACE(ICompressSetCoderMt, 0x25) { STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE; }; CODER_INTERFACE(ICompressGetSubStreamSize, 0x30) { STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE; }; CODER_INTERFACE(ICompressSetInStream, 0x31) { STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE; STDMETHOD(ReleaseInStream)() PURE; }; CODER_INTERFACE(ICompressSetOutStream, 0x32) { STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE; STDMETHOD(ReleaseOutStream)() PURE; }; CODER_INTERFACE(ICompressSetInStreamSize, 0x33) { STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE; }; CODER_INTERFACE(ICompressSetOutStreamSize, 0x34) { STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE; }; CODER_INTERFACE(ICompressSetBufSize, 0x35) { STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE; STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE; }; CODER_INTERFACE(ICompressFilter, 0x40) { STDMETHOD(Init)() PURE; STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE; // Filter converts as most as possible bytes // Filter return outSize (UInt32) // if (outSize <= size): Filter have converted outSize bytes // if (outSize > size): Filter have not converted anything. // and it needs at least outSize bytes to convert one block // (it's for crypto block algorithms). }; CODER_INTERFACE(ICompressCodecsInfo, 0x60) { STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods) PURE; STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE; STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE; }; CODER_INTERFACE(ISetCompressCodecsInfo, 0x61) { STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE; }; CODER_INTERFACE(ICryptoProperties, 0x80) { STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE; STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE; }; /* CODER_INTERFACE(ICryptoResetSalt, 0x88) { STDMETHOD(ResetSalt)() PURE; }; */ CODER_INTERFACE(ICryptoResetInitVector, 0x8C) { STDMETHOD(ResetInitVector)() PURE; }; CODER_INTERFACE(ICryptoSetPassword, 0x90) { STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE; }; CODER_INTERFACE(ICryptoSetCRC, 0xA0) { STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE; }; ////////////////////// // It's for DLL file namespace NMethodPropID { enum EEnum { kID, kName, kDecoder, kEncoder, kInStreams, kOutStreams, kDescription, kDecoderIsAssigned, kEncoderIsAssigned, kDigestSize }; } CODER_INTERFACE(IHasher, 0xC0) { STDMETHOD_(void, Init)() PURE; STDMETHOD_(void, Update)(const void *data, UInt32 size) PURE; STDMETHOD_(void, Final)(Byte *digest) PURE; STDMETHOD_(UInt32, GetDigestSize)() PURE; }; CODER_INTERFACE(IHashers, 0xC1) { STDMETHOD_(UInt32, GetNumHashers)() PURE; STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher) PURE; }; extern "C" { typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods); typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/IDecl.h0100777000000000000000000000054013761647206020751 0ustar00// IDecl.h #ifndef __IDECL_H #define __IDECL_H #include "../Common/MyUnknown.h" #define DECL_INTERFACE_SUB(i, base, groupId, subId) \ DEFINE_GUID(IID_ ## i, \ 0x23170F69, 0x40C1, 0x278A, 0, 0, 0, (groupId), 0, (subId), 0, 0); \ struct i: public base #define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/IPassword.h0100777000000000000000000000071713761647206021712 0ustar00// IPassword.h #ifndef __IPASSWORD_H #define __IPASSWORD_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x) PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10) { STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE; }; PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11) { STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/IProgress.h0100777000000000000000000000132413761647206021707 0ustar00// Interface/IProgress.h #ifndef __IPROGRESS_H #define __IPROGRESS_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define INTERFACE_IProgress(x) \ STDMETHOD(SetTotal)(UInt64 total) x; \ STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \ DECL_INTERFACE(IProgress, 0, 5) { INTERFACE_IProgress(PURE) }; /* // {23170F69-40C1-278A-0000-000000050002} DEFINE_GUID(IID_IProgress2, 0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02); MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002") IProgress2: public IUnknown { public: STDMETHOD(SetTotal)(const UInt64 *total) PURE; STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; }; */ #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/IStream.h0100777000000000000000000000710613761647206021342 0ustar00// IStream.h #ifndef __ISTREAM_H #define __ISTREAM_H #include "../Common/MyTypes.h" #include "../Common/MyUnknown.h" #include "IDecl.h" #define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x) #define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x) STREAM_INTERFACE(ISequentialInStream, 0x01) { STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE; /* The requirement for caller: (processedSize != NULL). The callee can allow (processedSize == NULL) for compatibility reasons. if (size == 0), this function returns S_OK and (*processedSize) is set to 0. if (size != 0) { Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size), where (avail_size) is the size of remaining bytes in stream. If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0). You must call Read() in loop, if you need to read exact amount of data. } If seek pointer before Read() call was changed to position past the end of stream: if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0. ERROR CASES: If the function returns error code, then (*processedSize) is size of data written to (data) buffer (it can be data before error or data with errors). The recommended way for callee to work with reading errors: 1) write part of data before error to (data) buffer and return S_OK. 2) return error code for further calls of Read(). */ }; STREAM_INTERFACE(ISequentialOutStream, 0x02) { STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE; /* The requirement for caller: (processedSize != NULL). The callee can allow (processedSize == NULL) for compatibility reasons. if (size != 0) { Partial write is allowed: (*processedSize <= size), but this function must write at least 1 byte: (*processedSize > 0). You must call Write() in loop, if you need to write exact amount of data. } ERROR CASES: If the function returns error code, then (*processedSize) is size of data written from (data) buffer. */ }; #ifdef __HRESULT_FROM_WIN32 #define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) #else #define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) #endif /* Seek() Function If you seek before the beginning of the stream, Seek() function returns error code: Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK). or STG_E_INVALIDFUNCTION It is allowed to seek past the end of the stream. if Seek() returns error, then the value of *newPosition is undefined. */ STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; }; STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04) { STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; STDMETHOD(SetSize)(UInt64 newSize) PURE; }; STREAM_INTERFACE(IStreamGetSize, 0x06) { STDMETHOD(GetSize)(UInt64 *size) PURE; }; STREAM_INTERFACE(IOutStreamFlush, 0x07) { STDMETHOD(Flush)() PURE; }; STREAM_INTERFACE(IStreamGetProps, 0x08) { STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) PURE; }; struct CStreamFileProps { UInt64 Size; UInt64 VolID; UInt64 FileID_Low; UInt64 FileID_High; UInt32 NumLinks; UInt32 Attrib; FILETIME CTime; FILETIME ATime; FILETIME MTime; }; STREAM_INTERFACE(IStreamGetProps2, 0x09) { STDMETHOD(GetProps2)(CStreamFileProps *props) PURE; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/PropID.h0100777000000000000000000000465513761647206021141 0ustar00// PropID.h #ifndef __7ZIP_PROP_ID_H #define __7ZIP_PROP_ID_H #include "../Common/MyTypes.h" enum { kpidNoProperty = 0, kpidMainSubfile, kpidHandlerItemIndex, kpidPath, kpidName, kpidExtension, kpidIsDir, kpidSize, kpidPackSize, kpidAttrib, kpidCTime, kpidATime, kpidMTime, kpidSolid, kpidCommented, kpidEncrypted, kpidSplitBefore, kpidSplitAfter, kpidDictionarySize, kpidCRC, kpidType, kpidIsAnti, kpidMethod, kpidHostOS, kpidFileSystem, kpidUser, kpidGroup, kpidBlock, kpidComment, kpidPosition, kpidPrefix, kpidNumSubDirs, kpidNumSubFiles, kpidUnpackVer, kpidVolume, kpidIsVolume, kpidOffset, kpidLinks, kpidNumBlocks, kpidNumVolumes, kpidTimeType, kpidBit64, kpidBigEndian, kpidCpu, kpidPhySize, kpidHeadersSize, kpidChecksum, kpidCharacts, kpidVa, kpidId, kpidShortName, kpidCreatorApp, kpidSectorSize, kpidPosixAttrib, kpidSymLink, kpidError, kpidTotalSize, kpidFreeSpace, kpidClusterSize, kpidVolumeName, kpidLocalName, kpidProvider, kpidNtSecure, kpidIsAltStream, kpidIsAux, kpidIsDeleted, kpidIsTree, kpidSha1, kpidSha256, kpidErrorType, kpidNumErrors, kpidErrorFlags, kpidWarningFlags, kpidWarning, kpidNumStreams, kpidNumAltStreams, kpidAltStreamsSize, kpidVirtualSize, kpidUnpackSize, kpidTotalPhySize, kpidVolumeIndex, kpidSubType, kpidShortComment, kpidCodePage, kpidIsNotArcType, kpidPhySizeCantBeDetected, kpidZerosTailIsAllowed, kpidTailSize, kpidEmbeddedStubSize, kpidNtReparse, kpidHardLink, kpidINode, kpidStreamId, kpid_NUM_DEFINED, kpidUserDefined = 0x10000 }; extern Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0; const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1; const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2; const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3; const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4; const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5; const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6; const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7; const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8; const UInt32 kpv_ErrorFlags_DataError = 1 << 9; const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; // const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/0040777000000000000000000000000013761647206020136 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/0040777000000000000000000000000013761647206021366 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp0100777000000000000000000010660413761647206025571 0ustar00// ArchiveCommandLine.cpp #include "StdAfx.h" #undef printf #undef sprintf #ifdef _WIN32 #ifndef UNDER_CE #include #endif #endif #include #include "../../../Common/ListFileUtils.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileName.h" #ifdef _WIN32 #include "../../../Windows/FileMapping.h" #include "../../../Windows/Synchronization.h" #endif #include "ArchiveCommandLine.h" #include "EnumDirItems.h" #include "SortUtils.h" #include "Update.h" #include "UpdateAction.h" extern bool g_CaseSensitive; #ifdef UNDER_CE #define MY_IS_TERMINAL(x) false; #else #if _MSC_VER >= 1400 #define MY_isatty_fileno(x) _isatty(_fileno(x)) #else #define MY_isatty_fileno(x) isatty(fileno(x)) #endif #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); #endif using namespace NCommandLineParser; using namespace NWindows; using namespace NFile; static bool StringToUInt32(const wchar_t *s, UInt32 &v) { if (*s == 0) return false; const wchar_t *end; v = ConvertStringToUInt32(s, &end); return *end == 0; } static void AddNewLine(UString &s) { s += L'\n'; } CArcCmdLineException::CArcCmdLineException(const char *a, const wchar_t *u) { (*this) += MultiByteToUnicodeString(a); if (u) { AddNewLine(*this); (*this) += u; } } int g_CodePage = -1; namespace NKey { enum Enum { kHelp1 = 0, kHelp2, kHelp3, kDisableHeaders, kDisablePercents, kArchiveType, kYes, #ifndef _NO_CRYPTO kPassword, #endif kProperty, kOutputDir, kWorkingDir, kInclude, kExclude, kArInclude, kArExclude, kNoArName, kUpdate, kVolume, kRecursed, kSfx, kStdIn, kStdOut, kOverwrite, kEmail, kShowDialog, kLargePages, kListfileCharSet, kConsoleCharSet, kTechMode, kShareForWrite, kCaseSensitive, kHash, kArcNameMode, kDisableWildcardParsing, kElimDup, kFullPathMode, kHardLinks, kSymLinks, kNtSecurity, kAltStreams, kReplaceColonForAltStream, kWriteToAltStreamIfColon, kDeleteAfterCompressing, kSetArcMTime, kExcludedArcType }; } static const wchar_t kRecursedIDChar = 'r'; static const char *kRecursedPostCharSet = "0-"; static const char *k_ArcNameMode_PostCharSet = "sea"; static inline const EArcNameMode ParseArcNameMode(int postCharIndex) { switch (postCharIndex) { case 1: return k_ArcNameMode_Exact; case 2: return k_ArcNameMode_Add; default: return k_ArcNameMode_Smart; } } namespace NRecursedPostCharIndex { enum EEnum { kWildcardRecursionOnly = 0, kNoRecursion = 1 }; } static const char kImmediateNameID = '!'; static const char kMapNameID = '#'; static const char kFileListID = '@'; static const char kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be static const char *kOverwritePostCharSet = "asut"; NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = { NExtract::NOverwriteMode::kOverwrite, NExtract::NOverwriteMode::kSkip, NExtract::NOverwriteMode::kRename, NExtract::NOverwriteMode::kRenameExisting }; static const CSwitchForm kSwitchForms[] = { { "?" }, { "h" }, { "-help" }, { "ba" }, { "bd" }, { "t", NSwitchType::kString, false, 1 }, { "y" }, #ifndef _NO_CRYPTO { "p", NSwitchType::kString }, #endif { "m", NSwitchType::kString, true, 1 }, { "o", NSwitchType::kString, false, 1 }, { "w", NSwitchType::kString }, { "i", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "x", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize}, { "an" }, { "u", NSwitchType::kString, true, 1}, { "v", NSwitchType::kString, true, 1}, { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, { "sfx", NSwitchType::kString }, { "si", NSwitchType::kString }, { "so" }, { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, { "seml", NSwitchType::kString, false, 0}, { "ad" }, { "slp", NSwitchType::kMinus }, { "scs", NSwitchType::kString }, { "scc", NSwitchType::kString }, { "slt" }, { "ssw" }, { "ssc", NSwitchType::kMinus }, { "scrc", NSwitchType::kString, true, 0 }, { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, { "spd" }, { "spe", NSwitchType::kMinus }, { "spf", NSwitchType::kString, false, 0 }, { "snh", NSwitchType::kMinus }, { "snl", NSwitchType::kMinus }, { "sni" }, { "sns", NSwitchType::kMinus }, { "snr" }, { "snc" }, { "sdel" }, { "stl" }, { "stx", NSwitchType::kString, true, 1 } }; static const wchar_t *kUniversalWildcard = L"*"; static const int kMinNonSwitchWords = 1; static const int kCommandIndex = 0; // static const char *kUserErrorMessage = "Incorrect command line"; static const char *kCannotFindListFile = "Cannot find listfile"; static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; // static const char *kIncorrectWildcardInListFile = "Incorrect wildcard in listfile"; // static const char *kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line"; static const char *kTerminalOutError = "I won't write compressed data to a terminal"; static const char *kSameTerminalError = "I won't write data and program's messages to same terminal"; static const char *kEmptyFilePath = "Empty file path"; static const char *kCannotFindArchive = "Cannot find archive"; bool CArcCommand::IsFromExtractGroup() const { switch (CommandType) { case NCommandType::kTest: case NCommandType::kExtract: case NCommandType::kExtractFull: return true; } return false; } NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const { switch (CommandType) { case NCommandType::kTest: case NCommandType::kExtractFull: return NExtract::NPathMode::kFullPaths; } return NExtract::NPathMode::kNoPaths; } bool CArcCommand::IsFromUpdateGroup() const { switch (CommandType) { case NCommandType::kAdd: case NCommandType::kUpdate: case NCommandType::kDelete: case NCommandType::kRename: return true; } return false; } static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) { switch (index) { case NRecursedPostCharIndex::kWildcardRecursionOnly: return NRecursedType::kWildcardOnlyRecursed; case NRecursedPostCharIndex::kNoRecursion: return NRecursedType::kNonRecursed; default: return NRecursedType::kRecursed; } } static const char *g_Commands = "audtexlbih"; static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) { UString s = commandString; s.MakeLower_Ascii(); if (s.Len() == 1) { if (s[0] > 0x7F) return false; int index = FindCharPosInString(g_Commands, (char)s[0]); if (index < 0) return false; command.CommandType = (NCommandType::EEnum)index; return true; } if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n') { command.CommandType = (NCommandType::kRename); return true; } return false; } // ------------------------------------------------------------------ // filenames functions static void AddNameToCensor(NWildcard::CCensor &censor, const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching) { bool recursed = false; switch (type) { case NRecursedType::kWildcardOnlyRecursed: recursed = DoesNameContainWildcard(name); break; case NRecursedType::kRecursed: recursed = true; break; } censor.AddPreItem(include, name, recursed, wildcardMatching); } static void AddRenamePair(CObjectVector *renamePairs, const UString &oldName, const UString &newName, NRecursedType::EEnum type, bool wildcardMatching) { CRenamePair &pair = renamePairs->AddNew(); pair.OldName = oldName; pair.NewName = newName; pair.RecursedType = type; pair.WildcardParsing = wildcardMatching; if (!pair.Prepare()) { UString val; val += pair.OldName; AddNewLine(val); val += pair.NewName; AddNewLine(val); if (type == NRecursedType::kRecursed) val += L"-r"; else if (type == NRecursedType::kRecursed) val += L"-r0"; throw CArcCmdLineException("Unsupported rename command:", val); } } static void AddToCensorFromListFile( CObjectVector *renamePairs, NWildcard::CCensor &censor, LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage) { UStringVector names; if (!NFind::DoesFileExist(us2fs(fileName))) throw CArcCmdLineException(kCannotFindListFile, fileName); if (!ReadNamesFromListFile(us2fs(fileName), names, codePage)) throw CArcCmdLineException(kIncorrectListFile, fileName); if (renamePairs) { if ((names.Size() & 1) != 0) throw CArcCmdLineException(kIncorrectListFile, fileName); for (unsigned i = 0; i < names.Size(); i += 2) { // change type !!!! AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching); } } else FOR_VECTOR (i, names) AddNameToCensor(censor, names[i], include, type, wildcardMatching); } static void AddToCensorFromNonSwitchesStrings( CObjectVector *renamePairs, unsigned startIndex, NWildcard::CCensor &censor, const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, bool wildcardMatching, bool thereAreSwitchIncludes, Int32 codePage) { if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) AddNameToCensor(censor, kUniversalWildcard, true, type, true // wildcardMatching ); int oldIndex = -1; for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++) { const UString &s = nonSwitchStrings[i]; if (s.IsEmpty()) throw CArcCmdLineException(kEmptyFilePath); if (s[0] == kFileListID) AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage); else if (renamePairs) { if (oldIndex == -1) oldIndex = startIndex; else { // NRecursedType::EEnum type is used for global wildcard (-i! switches) AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching); // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); oldIndex = -1; } } else AddNameToCensor(censor, s, true, type, wildcardMatching); } if (oldIndex != -1) { throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]); } } #ifdef _WIN32 struct CEventSetEnd { UString Name; CEventSetEnd(const wchar_t *name): Name(name) {} ~CEventSetEnd() { NSynchronization::CManualResetEvent event; if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) event.Set(); } }; const char *k_IncorrectMapCommand = "Incorrect Map command"; static const char *ParseMapWithPaths( NWildcard::CCensor &censor, const UString &s2, bool include, NRecursedType::EEnum commonRecursedType, bool wildcardMatching) { UString s = s2; int pos = s.Find(L':'); if (pos < 0) return k_IncorrectMapCommand; int pos2 = s.Find(L':', pos + 1); if (pos2 < 0) return k_IncorrectMapCommand; CEventSetEnd eventSetEnd((const wchar_t *)s + (pos2 + 1)); s.DeleteFrom(pos2); UInt32 size; if (!StringToUInt32(s.Ptr(pos + 1), size) || size < sizeof(wchar_t) || size > ((UInt32)1 << 31) || size % sizeof(wchar_t) != 0) return "Unsupported Map data size"; s.DeleteFrom(pos); CFileMapping map; if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0) return "Can not open mapping"; LPVOID data = map.Map(FILE_MAP_READ, 0, size); if (!data) return "MapViewOfFile error"; CFileUnmapper unmapper(data); UString name; const wchar_t *p = (const wchar_t *)data; if (*p != 0) // data format marker return "Unsupported Map data"; UInt32 numChars = size / sizeof(wchar_t); for (UInt32 i = 1; i < numChars; i++) { wchar_t c = p[i]; if (c == 0) { // MessageBoxW(0, name, L"7-Zip", 0); AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching); name.Empty(); } else name += c; } if (!name.IsEmpty()) return "Map data error"; return NULL; } #endif static void AddSwitchWildcardsToCensor( NWildcard::CCensor &censor, const UStringVector &strings, bool include, NRecursedType::EEnum commonRecursedType, bool wildcardMatching, Int32 codePage) { const char *errorMessage = NULL; unsigned i; for (i = 0; i < strings.Size(); i++) { const UString &name = strings[i]; NRecursedType::EEnum recursedType; unsigned pos = 0; if (name.Len() < kSomeCludePostStringMinSize) { errorMessage = "Too short switch"; break; } if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar) { pos++; wchar_t c = name[pos]; int index = -1; if (c <= 0x7F) index = FindCharPosInString(kRecursedPostCharSet, (char)c); recursedType = GetRecursedTypeFromIndex(index); if (index >= 0) pos++; } else recursedType = commonRecursedType; if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) { errorMessage = "Too short switch"; break; } UString tail = name.Ptr(pos + 1); if (name[pos] == kImmediateNameID) AddNameToCensor(censor, tail, include, recursedType, wildcardMatching); else if (name[pos] == kFileListID) AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage); #ifdef _WIN32 else if (name[pos] == kMapNameID) { errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching); if (errorMessage) break; } #endif else { errorMessage = "Incorrect wildcarc type marker"; break; } } if (i != strings.Size()) throw CArcCmdLineException(errorMessage, strings[i]); } #ifdef _WIN32 // This code converts all short file names to long file names. static void ConvertToLongName(const UString &prefix, UString &name) { if (name.IsEmpty() || DoesNameContainWildcard(name)) return; NFind::CFileInfo fi; const FString path = us2fs(prefix + name); if (NFile::NName::IsDevicePath(path)) return; if (fi.Find(path)) name = fs2us(fi.Name); } static void ConvertToLongNames(const UString &prefix, CObjectVector &items) { FOR_VECTOR (i, items) { NWildcard::CItem &item = items[i]; if (item.Recursive || item.PathParts.Size() != 1) continue; if (prefix.IsEmpty() && item.IsDriveItem()) continue; ConvertToLongName(prefix, item.PathParts.Front()); } } static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) { ConvertToLongNames(prefix, node.IncludeItems); ConvertToLongNames(prefix, node.ExcludeItems); unsigned i; for (i = 0; i < node.SubNodes.Size(); i++) { UString &name = node.SubNodes[i].Name; if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name)) continue; ConvertToLongName(prefix, name); } // mix folders with same name for (i = 0; i < node.SubNodes.Size(); i++) { NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; for (unsigned j = i + 1; j < node.SubNodes.Size();) { const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; if (nextNode1.Name.IsEqualToNoCase(nextNode2.Name)) { nextNode1.IncludeItems += nextNode2.IncludeItems; nextNode1.ExcludeItems += nextNode2.ExcludeItems; node.SubNodes.Delete(j); } else j++; } } for (i = 0; i < node.SubNodes.Size(); i++) { NWildcard::CCensorNode &nextNode = node.SubNodes[i]; ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode); } } void ConvertToLongNames(NWildcard::CCensor &censor) { FOR_VECTOR (i, censor.Pairs) { NWildcard::CPair &pair = censor.Pairs[i]; ConvertToLongNames(pair.Prefix, pair.Head); } } #endif /* static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) { switch (i) { case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore; case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy; case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress; case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti; } throw 98111603; } */ static const wchar_t *kUpdatePairStateIDSet = L"pqrxyzw"; static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; static const unsigned kNumUpdatePairActions = 4; static const char *kUpdateIgnoreItselfPostStringID = "-"; static const wchar_t kUpdateNewArchivePostCharID = '!'; static bool ParseUpdateCommandString2(const UString &command, NUpdateArchive::CActionSet &actionSet, UString &postString) { for (unsigned i = 0; i < command.Len();) { wchar_t c = MyCharLower_Ascii(command[i]); int statePos = FindCharPosInString(kUpdatePairStateIDSet, c); if (statePos < 0) { postString = command.Ptr(i); return true; } i++; if (i >= command.Len()) return false; c = command[i]; if (c < '0' || c >= '0' + kNumUpdatePairActions) return false; int actionPos = c - '0'; actionSet.StateActions[statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos); if (kUpdatePairStateNotSupportedActions[statePos] == actionPos) return false; i++; } postString.Empty(); return true; } static void ParseUpdateCommandString(CUpdateOptions &options, const UStringVector &updatePostStrings, const NUpdateArchive::CActionSet &defaultActionSet) { const char *errorMessage = "incorrect update switch command"; unsigned i; for (i = 0; i < updatePostStrings.Size(); i++) { const UString &updateString = updatePostStrings[i]; if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID)) { if (options.UpdateArchiveItself) { options.UpdateArchiveItself = false; options.Commands.Delete(0); } } else { NUpdateArchive::CActionSet actionSet = defaultActionSet; UString postString; if (!ParseUpdateCommandString2(updateString, actionSet, postString)) break; if (postString.IsEmpty()) { if (options.UpdateArchiveItself) options.Commands[0].ActionSet = actionSet; } else { if (postString[0] != kUpdateNewArchivePostCharID) break; CUpdateArchiveCommand uc; UString archivePath = postString.Ptr(1); if (archivePath.IsEmpty()) break; uc.UserArchivePath = archivePath; uc.ActionSet = actionSet; options.Commands.Add(uc); } } } if (i != updatePostStrings.Size()) throw CArcCmdLineException(errorMessage, updatePostStrings[i]); } bool ParseComplexSize(const wchar_t *s, UInt64 &result); static void SetAddCommandOptions( NCommandType::EEnum commandType, const CParser &parser, CUpdateOptions &options) { NUpdateArchive::CActionSet defaultActionSet; switch (commandType) { case NCommandType::kAdd: defaultActionSet = NUpdateArchive::k_ActionSet_Add; break; case NCommandType::kDelete: defaultActionSet = NUpdateArchive::k_ActionSet_Delete; break; default: defaultActionSet = NUpdateArchive::k_ActionSet_Update; } options.UpdateArchiveItself = true; options.Commands.Clear(); CUpdateArchiveCommand updateMainCommand; updateMainCommand.ActionSet = defaultActionSet; options.Commands.Add(updateMainCommand); if (parser[NKey::kUpdate].ThereIs) ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, defaultActionSet); if (parser[NKey::kWorkingDir].ThereIs) { const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; if (postString.IsEmpty()) NDir::MyGetTempPath(options.WorkingDir); else options.WorkingDir = us2fs(postString); } options.SfxMode = parser[NKey::kSfx].ThereIs; if (options.SfxMode) options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); if (parser[NKey::kVolume].ThereIs) { const UStringVector &sv = parser[NKey::kVolume].PostStrings; FOR_VECTOR (i, sv) { UInt64 size; if (!ParseComplexSize(sv[i], size) || size == 0) throw CArcCmdLineException("Incorrect volume size:", sv[i]); options.VolumesSizes.Add(size); } } } static void SetMethodOptions(const CParser &parser, CObjectVector &properties) { if (parser[NKey::kProperty].ThereIs) { FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) { CProperty prop; prop.Name = parser[NKey::kProperty].PostStrings[i]; int index = prop.Name.Find(L'='); if (index >= 0) { prop.Value = prop.Name.Ptr(index + 1); prop.Name.DeleteFrom(index); } properties.Add(prop); } } } CArcCmdLineParser::CArcCmdLineParser(): parser(ARRAY_SIZE(kSwitchForms)) {} void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options) { if (!parser.ParseStrings(kSwitchForms, commandStrings)) throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); options.IsInTerminal = MY_IS_TERMINAL(stdin); options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); options.StdInMode = parser[NKey::kStdIn].ThereIs; options.StdOutMode = parser[NKey::kStdOut].ThereIs; options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; if (parser[NKey::kCaseSensitive].ThereIs) { g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; options.CaseSensitiveChange = true; options.CaseSensitive = g_CaseSensitive; } #ifdef _WIN32 options.LargePages = false; if (parser[NKey::kLargePages].ThereIs) { options.LargePages = !parser[NKey::kLargePages].WithMinus; } #endif } struct CCodePagePair { const char *Name; Int32 CodePage; }; static const unsigned kNumByteOnlyCodePages = 3; static CCodePagePair g_CodePagePairs[] = { { "utf-8", CP_UTF8 }, { "win", CP_ACP }, { "dos", CP_OEMCP }, { "utf-16le", MY__CP_UTF16 }, { "utf-16be", MY__CP_UTF16BE } }; static Int32 FindCharset(const NCommandLineParser::CParser &parser, int keyIndex, bool byteOnlyCodePages, Int32 defaultVal) { if (!parser[keyIndex].ThereIs) return defaultVal; UString name = parser[keyIndex].PostStrings.Back(); UInt32 v; if (StringToUInt32(name, v)) if (v < ((UInt32)1 << 16)) return (Int32)v; name.MakeLower_Ascii(); unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs); for (unsigned i = 0;; i++) { if (i == num) // to disable warnings from different compilers throw CArcCmdLineException("Unsupported charset:", name); const CCodePagePair &pair = g_CodePagePairs[i]; if (name.IsEqualTo(pair.Name)) return pair.CodePage; } } void EnumerateDirItemsAndSort( bool storeAltStreams, NWildcard::CCensor &censor, NWildcard::ECensorPathMode censorPathMode, const UString &addPathPrefix, UStringVector &sortedPaths, UStringVector &sortedFullPaths) { UStringVector paths; { CDirItems dirItems; { dirItems.ScanAltStreams = storeAltStreams; HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems, NULL); if (res != S_OK || dirItems.ErrorPaths.Size() > 0) { UString errorPath; if (dirItems.ErrorPaths.Size() > 0) errorPath = fs2us(dirItems.ErrorPaths[0]); throw CArcCmdLineException(kCannotFindArchive, dirItems.ErrorPaths.Size() > 0 ? (const wchar_t *)errorPath : NULL); } } FOR_VECTOR (i, dirItems.Items) { const CDirItem &dirItem = dirItems.Items[i]; if (!dirItem.IsDir()) paths.Add(dirItems.GetPhyPath(i)); } } if (paths.Size() == 0) throw CArcCmdLineException(kCannotFindArchive); UStringVector fullPaths; unsigned i; for (i = 0; i < paths.Size(); i++) { FString fullPath; NFile::NDir::MyGetFullPathName(us2fs(paths[i]), fullPath); fullPaths.Add(fs2us(fullPath)); } CUIntVector indices; SortFileNames(fullPaths, indices); sortedPaths.ClearAndReserve(indices.Size()); sortedFullPaths.ClearAndReserve(indices.Size()); for (i = 0; i < indices.Size(); i++) { unsigned index = indices[i]; sortedPaths.AddInReserved(paths[index]); sortedFullPaths.AddInReserved(fullPaths[index]); if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0) throw CArcCmdLineException("Duplicate archive path:", sortedFullPaths[i]); } } static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) { bp.Def = parser[switchID].ThereIs; if (bp.Def) bp.Val = !parser[switchID].WithMinus; } void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) { const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; int numNonSwitchStrings = nonSwitchStrings.Size(); if (numNonSwitchStrings < kMinNonSwitchWords) throw CArcCmdLineException("The command must be spcified"); if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); options.TechMode = parser[NKey::kTechMode].ThereIs; if (parser[NKey::kHash].ThereIs) options.HashMethods = parser[NKey::kHash].PostStrings; if (parser[NKey::kElimDup].ThereIs) { options.ExtractOptions.ElimDup.Def = true; options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; } NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; if (fullPathMode) { censorPathMode = NWildcard::k_AbsPath; const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; if (!s.IsEmpty()) { if (s == L"2") censorPathMode = NWildcard::k_FullPath; else throw CArcCmdLineException("Unsupported -spf:", s); } } NRecursedType::EEnum recursedType; if (parser[NKey::kRecursed].ThereIs) recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); else recursedType = NRecursedType::kNonRecursed; bool wildcardMatching = true; if (parser[NKey::kDisableWildcardParsing].ThereIs) wildcardMatching = false; g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1); Int32 codePage = FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8); bool thereAreSwitchIncludes = false; if (parser[NKey::kInclude].ThereIs) { thereAreSwitchIncludes = true; AddSwitchWildcardsToCensor(options.Censor, parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage); } if (parser[NKey::kExclude].ThereIs) AddSwitchWildcardsToCensor(options.Censor, parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage); int curCommandIndex = kCommandIndex + 1; bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && options.Command.CommandType != NCommandType::kBenchmark && options.Command.CommandType != NCommandType::kInfo && options.Command.CommandType != NCommandType::kHash; bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; bool isRename = options.Command.CommandType == NCommandType::kRename; if ((isExtractOrList || isRename) && options.StdInMode) thereIsArchiveName = false; if (parser[NKey::kArcNameMode].ThereIs) options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); if (thereIsArchiveName) { if (curCommandIndex >= numNonSwitchStrings) throw CArcCmdLineException("Cannot find archive name"); options.ArchiveName = nonSwitchStrings[curCommandIndex++]; if (options.ArchiveName.IsEmpty()) throw CArcCmdLineException("Archive name cannot by empty"); } AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, curCommandIndex, options.Censor, nonSwitchStrings, recursedType, wildcardMatching, thereAreSwitchIncludes, codePage); options.YesToAll = parser[NKey::kYes].ThereIs; #ifndef _NO_CRYPTO options.PasswordEnabled = parser[NKey::kPassword].ThereIs; if (options.PasswordEnabled) options.Password = parser[NKey::kPassword].PostStrings[0]; #endif options.ShowDialog = parser[NKey::kShowDialog].ThereIs; if (parser[NKey::kArchiveType].ThereIs) options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; SetMethodOptions(parser, options.Properties); options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs; if (options.EnablePercents) { if ((options.StdOutMode && !options.IsStdErrTerminal) || (!options.StdOutMode && !options.IsStdOutTerminal)) options.EnablePercents = false; } if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); if (isExtractOrList) { CExtractOptionsBase &eo = options.ExtractOptions; { CExtractNtOptions &nt = eo.NtOptions; nt.NtSecurity = options.NtSecurity; nt.AltStreams = options.AltStreams; if (!options.AltStreams.Def) nt.AltStreams.Val = true; nt.HardLinks = options.HardLinks; if (!options.HardLinks.Def) nt.HardLinks.Val = true; nt.SymLinks = options.SymLinks; if (!options.SymLinks.Def) nt.SymLinks.Val = true; nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; } options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); options.Censor.ExtendExclude(); // are there paths that look as non-relative (!Prefix.IsEmpty()) if (!options.Censor.AllAreRelative()) throw CArcCmdLineException("Cannot use absolute pathnames for this command"); NWildcard::CCensor arcCensor; if (parser[NKey::kArInclude].ThereIs) AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage); if (parser[NKey::kArExclude].ThereIs) AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage); if (thereIsArchiveName) AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching); arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); #ifdef _WIN32 ConvertToLongNames(arcCensor); #endif arcCensor.ExtendExclude(); if (options.StdInMode) { UString arcName = parser[NKey::kStdIn].PostStrings.Front(); options.ArchivePathsSorted.Add(arcName); options.ArchivePathsFullSorted.Add(arcName); } else { EnumerateDirItemsAndSort( false, // scanAltStreams arcCensor, NWildcard::k_RelatPath, UString(), // addPathPrefix options.ArchivePathsSorted, options.ArchivePathsFullSorted); } if (isExtractGroupCommand) { if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal) throw CArcCmdLineException(kSameTerminalError); if (parser[NKey::kOutputDir].ThereIs) { eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); } eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; if (parser[NKey::kOverwrite].ThereIs) { eo.OverwriteMode = k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex]; eo.OverwriteMode_Force = true; } else if (options.YesToAll) { eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; eo.OverwriteMode_Force = true; } } eo.PathMode = options.Command.GetPathMode(); if (censorPathMode == NWildcard::k_AbsPath) { eo.PathMode = NExtract::NPathMode::kAbsPaths; eo.PathMode_Force = true; } else if (censorPathMode == NWildcard::k_FullPath) { eo.PathMode = NExtract::NPathMode::kFullPaths; eo.PathMode_Force = true; } } else if (options.Command.IsFromUpdateGroup()) { if (parser[NKey::kArInclude].ThereIs) throw CArcCmdLineException("-ai switch is not supported for this command"); CUpdateOptions &updateOptions = options.UpdateOptions; SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); updateOptions.MethodMode.Properties = options.Properties; if (parser[NKey::kShareForWrite].ThereIs) updateOptions.OpenShareForWrite = true; updateOptions.PathMode = censorPathMode; updateOptions.AltStreams = options.AltStreams; updateOptions.NtSecurity = options.NtSecurity; updateOptions.HardLinks = options.HardLinks; updateOptions.SymLinks = options.SymLinks; updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; if (updateOptions.EMailMode) { updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); if (updateOptions.EMailAddress.Len() > 0) if (updateOptions.EMailAddress[0] == L'.') { updateOptions.EMailRemoveAfter = true; updateOptions.EMailAddress.Delete(0); } } updateOptions.StdOutMode = options.StdOutMode; updateOptions.StdInMode = options.StdInMode; updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; if (updateOptions.StdOutMode && updateOptions.EMailMode) throw CArcCmdLineException("stdout mode and email mode cannot be combined"); if (updateOptions.StdOutMode && options.IsStdOutTerminal) throw CArcCmdLineException(kTerminalOutError); if (updateOptions.StdInMode) updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); if (options.Command.CommandType == NCommandType::kRename) if (updateOptions.Commands.Size() != 1) throw CArcCmdLineException("Only one archive can be created with rename command"); } else if (options.Command.CommandType == NCommandType::kBenchmark) { options.NumIterations = 1; if (curCommandIndex < numNonSwitchStrings) { if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]); curCommandIndex++; } } else if (options.Command.CommandType == NCommandType::kHash) { options.Censor.AddPathsToCensor(censorPathMode); options.Censor.ExtendExclude(); CHashOptions &hashOptions = options.HashOptions; hashOptions.PathMode = censorPathMode; hashOptions.Methods = options.HashMethods; if (parser[NKey::kShareForWrite].ThereIs) hashOptions.OpenShareForWrite = true; hashOptions.StdInMode = options.StdInMode; hashOptions.AltStreamsMode = options.AltStreams.Val; } else if (options.Command.CommandType == NCommandType::kInfo) { } else throw 9815676711; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h0100777000000000000000000000444713761647206025240 0ustar00// ArchiveCommandLine.h #ifndef __ARCHIVE_COMMAND_LINE_H #define __ARCHIVE_COMMAND_LINE_H #include "../../../Common/CommandLineParser.h" #include "../../../Common/Wildcard.h" #include "Extract.h" #include "HashCalc.h" #include "Update.h" struct CArcCmdLineException: public UString { CArcCmdLineException(const char *a, const wchar_t *u = NULL); }; namespace NCommandType { enum EEnum { kAdd = 0, kUpdate, kDelete, kTest, kExtract, kExtractFull, kList, kBenchmark, kInfo, kHash, kRename };} struct CArcCommand { NCommandType::EEnum CommandType; bool IsFromExtractGroup() const; bool IsFromUpdateGroup() const; bool IsTestCommand() const { return CommandType == NCommandType::kTest; } NExtract::NPathMode::EEnum GetPathMode() const; }; struct CArcCmdLineOptions { bool HelpMode; #ifdef _WIN32 bool LargePages; #endif bool CaseSensitiveChange; bool CaseSensitive; bool IsInTerminal; bool IsStdOutTerminal; bool IsStdErrTerminal; bool StdInMode; bool StdOutMode; bool EnableHeaders; bool YesToAll; bool ShowDialog; NWildcard::CCensor Censor; CArcCommand Command; UString ArchiveName; #ifndef _NO_CRYPTO bool PasswordEnabled; UString Password; #endif bool TechMode; UStringVector HashMethods; bool AppendName; UStringVector ArchivePathsSorted; UStringVector ArchivePathsFullSorted; CObjectVector Properties; CExtractOptionsBase ExtractOptions; CBoolPair NtSecurity; CBoolPair AltStreams; CBoolPair HardLinks; CBoolPair SymLinks; CUpdateOptions UpdateOptions; CHashOptions HashOptions; UString ArcType; UStringVector ExcludedArcTypes; bool EnablePercents; // Benchmark UInt32 NumIterations; CArcCmdLineOptions(): StdInMode(false), StdOutMode(false), CaseSensitiveChange(false), CaseSensitive(false) {}; }; class CArcCmdLineParser { NCommandLineParser::CParser parser; public: CArcCmdLineParser(); void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options); void Parse2(CArcCmdLineOptions &options); }; void EnumerateDirItemsAndSort( bool storeAltStreams, NWildcard::CCensor &censor, NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, UStringVector &sortedPaths, UStringVector &sortedFullPaths); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp0100777000000000000000000007267713761647206026446 0ustar00// ArchiveExtractCallback.cpp #include "StdAfx.h" #undef sprintf #undef printf #include "../../../Common/ComTry.h" #include "../../../Common/StringConvert.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif #include "../../Common/FilePathAutoRename.h" #include "../Common/ExtractingFilePath.h" #include "../Common/PropIDUtils.h" #include "ArchiveExtractCallback.h" using namespace NWindows; using namespace NFile; using namespace NDir; static const char *kCantAutoRename = "Can not create file with auto name"; static const char *kCantRenameFile = "Can not rename existing file"; static const char *kCantDeleteOutputFile = "Can not delete output file"; static const char *kCantDeleteOutputDir = "Can not delete output folder"; #ifndef _SFX STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize) { HRESULT result = S_OK; if (_stream) result = _stream->Write(data, size, &size); if (_calculate) _hash->Update(data, size); _size += size; if (processedSize) *processedSize = size; return result; } #endif #ifdef _USE_SECURITY_CODE bool InitLocalPrivileges() { NSecurity::CAccessToken token; if (!token.OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) return false; TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) return false; if (!token.AdjustPrivileges(&tp)) return false; return (GetLastError() == ERROR_SUCCESS); } #endif #ifdef SUPPORT_LINKS int CHardLinkNode::Compare(const CHardLinkNode &a) const { if (StreamId < a.StreamId) return -1; if (StreamId > a.StreamId) return 1; return MyCompare(INode, a.INode); } HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) { h.INode = 0; h.StreamId = (UInt64)(Int64)-1; defined = false; { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidINode, &prop)); if (!ConvertPropVariantToUInt64(prop, h.INode)) return S_OK; } { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidStreamId, &prop)); ConvertPropVariantToUInt64(prop, h.StreamId); } defined = true; return S_OK; } HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector *realIndices) { _hardLinks.Clear(); if (!_arc->Ask_INode) return S_OK; IInArchive *archive = _arc->Archive; CRecordVector &hardIDs = _hardLinks.IDs; { UInt32 numItems; if (realIndices) numItems = realIndices->Size(); else { RINOK(archive->GetNumberOfItems(&numItems)); } for (UInt32 i = 0; i < numItems; i++) { CHardLinkNode h; bool defined; RINOK(Archive_Get_HardLinkNode(archive, realIndices ? (*realIndices)[i] : i, h, defined)); if (defined) hardIDs.Add(h); } } hardIDs.Sort2(); { // wee keep only items that have 2 or more items unsigned k = 0; unsigned numSame = 1; for (unsigned i = 1; i < hardIDs.Size(); i++) { if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) numSame = 1; else if (++numSame == 2) { if (i - 1 != k) hardIDs[k] = hardIDs[i - 1]; k++; } } hardIDs.DeleteFrom(k); } _hardLinks.PrepareLinks(); return S_OK; } #endif CArchiveExtractCallback::CArchiveExtractCallback(): WriteCTime(true), WriteATime(true), WriteMTime(true), _multiArchives(false) { LocalProgressSpec = new CLocalProgress(); _localProgress = LocalProgressSpec; #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } void CArchiveExtractCallback::Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, const CArc *arc, IFolderArchiveExtractCallback *extractCallback2, bool stdOutMode, bool testMode, const FString &directoryPath, const UStringVector &removePathParts, UInt64 packSize) { _extractedFolderPaths.Clear(); _extractedFolderIndices.Clear(); #ifdef SUPPORT_LINKS _hardLinks.Clear(); #endif _ntOptions = ntOptions; _wildcardCensor = wildcardCensor; _stdOutMode = stdOutMode; _testMode = testMode; _unpTotal = 1; _packTotal = packSize; _extractCallback2 = extractCallback2; _compressProgress.Release(); _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); #ifndef _SFX _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); if (ExtractToStreamCallback) { Int32 useStreams = 0; if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) useStreams = 0; if (useStreams == 0) ExtractToStreamCallback.Release(); } #endif LocalProgressSpec->Init(extractCallback2, true); LocalProgressSpec->SendProgress = false; _removePathParts = removePathParts; _baseParentFolder = (UInt32)(Int32)-1; _use_baseParentFolder_mode = false; _arc = arc; _directoryPath = directoryPath; NName::NormalizeDirPathPrefix(_directoryPath); NDir::MyGetFullPathName(directoryPath, _directoryPathFull); } STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) { COM_TRY_BEGIN _unpTotal = size; if (!_multiArchives && _extractCallback2) return _extractCallback2->SetTotal(size); return S_OK; COM_TRY_END } static void NormalizeVals(UInt64 &v1, UInt64 &v2) { const UInt64 kMax = (UInt64)1 << 31; while (v1 > kMax) { v1 >>= 1; v2 >>= 1; } } static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) { NormalizeVals(packTotal, unpTotal); NormalizeVals(unpCur, unpTotal); if (unpTotal == 0) unpTotal = 1; return unpCur * packTotal / unpTotal; } STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) { COM_TRY_BEGIN if (!_extractCallback2) return S_OK; if (_multiArchives) { if (completeValue != NULL) { UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal); return _extractCallback2->SetCompleted(&packCur); } } return _extractCallback2->SetCompleted(completeValue); COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { COM_TRY_BEGIN return _localProgress->SetRatioInfo(inSize, outSize); COM_TRY_END } #define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') static inline bool IsDriveName(const UString &s) { return s.Len() == 2 && s[1] == ':' && IS_LETTER_CHAR(s[0]); } void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) { bool isAbsPath = false; if (!dirPathParts.IsEmpty()) { const UString &s = dirPathParts[0]; if (s.IsEmpty()) isAbsPath = true; #ifdef _WIN32 else { if (dirPathParts.Size() > 1 && IsDriveName(s)) isAbsPath = true; } #endif } if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) fullPath.Empty(); else fullPath = _directoryPath; FOR_VECTOR (i, dirPathParts) { if (i > 0) fullPath += FCHAR_PATH_SEPARATOR; const UString &s = dirPathParts[i]; fullPath += us2fs(s); #ifdef _WIN32 if (_pathMode == NExtract::NPathMode::kAbsPaths) if (i == 0 && IsDriveName(s)) continue; #endif CreateDir(fullPath); } } HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) { filetimeIsDefined = false; NCOM::CPropVariant prop; RINOK(_arc->Archive->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) { filetime = prop.filetime; filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT CArchiveExtractCallback::GetUnpackSize() { return _arc->GetItemSize(_index, _curSize, _curSizeDefined); } HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) { return _extractCallback2->MessageError( UString(L"ERROR: ") + GetUnicodeString(message) + L": " + fs2us(path)); } HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2) { return _extractCallback2->MessageError( UString(L"ERROR: ") + GetUnicodeString(message) + UString(L": ") + fs2us(path1) + UString(L" : ") + fs2us(path2)); } #ifndef _SFX STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value) { if (propID == kpidName) { COM_TRY_BEGIN NCOM::CPropVariant prop = Name.Ptr(); prop.Detach(value); return S_OK; COM_TRY_END } return Arc->Archive->GetProperty(IndexInArc, propID, value); } #endif #ifdef SUPPORT_LINKS static UString GetDirPrefixOf(const UString &src) { UString s = src; if (!s.IsEmpty()) { if (s.Back() == WCHAR_PATH_SEPARATOR) s.DeleteBack(); int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR); s.DeleteFrom(pos + 1); } return s; } static bool IsSafePath(const UString &path) { UStringVector parts; SplitPathToParts(path, parts); int level = 0; FOR_VECTOR(i, parts) { const UString &s = parts[i]; if (s.IsEmpty()) continue; if (s == L".") continue; if (s == L"..") { if (level <= 0) return false; level--; } else level++; } return level > 0; } #endif STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) { COM_TRY_BEGIN *outStream = 0; #ifndef _SFX if (_hashStream) _hashStreamSpec->ReleaseStream(); _hashStreamWasUsed = false; #endif _outFileStream.Release(); _encrypted = false; _isSplit = false; _isAltStream = false; _curSize = 0; _curSizeDefined = false; _index = index; UString fullPath; IInArchive *archive = _arc->Archive; RINOK(_arc->GetItemPath(index, fullPath)); RINOK(Archive_IsItem_Folder(archive, index, _fi.IsDir)); _filePath = fullPath; { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidPosition, &prop)); if (prop.vt != VT_EMPTY) { if (prop.vt != VT_UI8) return E_FAIL; _position = prop.uhVal.QuadPart; _isSplit = true; } } #ifdef SUPPORT_LINKS bool isHardLink = false; bool isJunction = false; bool isRelative = false; UString linkPath; // RINOK(Archive_GetItemBoolProp(archive, index, kpidIsHardLink, isHardLink)); // if (isHardLink) { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidHardLink, &prop)); if (prop.vt == VT_BSTR) { isHardLink = true; linkPath = prop.bstrVal; isRelative = false; // TAR: hard links are from root folder of archive } else if (prop.vt == VT_EMPTY) { // linkPath.Empty(); } else return E_FAIL; } { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidSymLink, &prop)); if (prop.vt == VT_BSTR) { isHardLink = false; linkPath = prop.bstrVal; isRelative = true; // TAR: symbolic links are relative } else if (prop.vt == VT_EMPTY) { // linkPath.Empty(); } else return E_FAIL; } bool isOkReparse = false; if (linkPath.IsEmpty() && _arc->GetRawProps) { const void *data; UInt32 dataSize; UInt32 propType; _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); if (dataSize != 0) { if (propType != NPropDataType::kRaw) return E_FAIL; UString s; CReparseAttr reparse; isOkReparse = reparse.Parse((const Byte *)data, dataSize); if (isOkReparse) { isHardLink = false; linkPath = reparse.GetPath(); isJunction = reparse.IsMountPoint(); isRelative = reparse.IsRelative(); #ifndef _WIN32 linkPath.Replace(WCHAR_PATH_SEPARATOR, '/', ); #endif } } } if (!linkPath.IsEmpty()) { #ifdef _WIN32 linkPath.Replace('/', WCHAR_PATH_SEPARATOR); #endif for (;;) // while (NName::IsAbsolutePath(linkPath)) { unsigned n = NName::GetRootPrefixSize(linkPath); if (n == 0) break; isRelative = false; linkPath.DeleteFrontal(n); } } if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0) { UStringVector pathParts; SplitPathToParts(linkPath, pathParts); bool badPrefix = false; FOR_VECTOR (i, _removePathParts) { if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) { badPrefix = true; break; } } if (!badPrefix) pathParts.DeleteFrontal(_removePathParts.Size()); linkPath = MakePathNameFromParts(pathParts); } #endif RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)); RINOK(GetUnpackSize()); RINOK(Archive_IsItem_AltStream(archive, index, _isAltStream)); if (!_ntOptions.AltStreams.Val && _isAltStream) return S_OK; if (_wildcardCensor) { if (!_wildcardCensor->CheckPath(_isAltStream, fullPath, !_fi.IsDir)) return S_OK; } UStringVector pathParts; if (_use_baseParentFolder_mode) { int baseParent = _baseParentFolder; if (_pathMode == NExtract::NPathMode::kFullPaths || _pathMode == NExtract::NPathMode::kAbsPaths) baseParent = -1; RINOK(_arc->GetItemPathToParent(index, baseParent, pathParts)); if (_pathMode == NExtract::NPathMode::kNoPaths && !pathParts.IsEmpty()) pathParts.DeleteFrontal(pathParts.Size() - 1); } else { SplitPathToParts(fullPath, pathParts); if (pathParts.IsEmpty()) return E_FAIL; unsigned numRemovePathParts = 0; switch (_pathMode) { case NExtract::NPathMode::kCurPaths: { bool badPrefix = false; if (pathParts.Size() <= _removePathParts.Size()) badPrefix = true; else { FOR_VECTOR (i, _removePathParts) { if (!_removePathParts[i].IsEqualToNoCase(pathParts[i])) { badPrefix = true; break; } } } if (badPrefix) { if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) return E_FAIL; } else numRemovePathParts = _removePathParts.Size(); break; } case NExtract::NPathMode::kNoPaths: { numRemovePathParts = pathParts.Size() - 1; break; } /* case NExtract::NPathMode::kFullPaths: case NExtract::NPathMode::kAbsPaths: break; */ } pathParts.DeleteFrontal(numRemovePathParts); } #ifndef _SFX if (ExtractToStreamCallback) { if (!GetProp) { GetProp_Spec = new CGetProp; GetProp = GetProp_Spec; } GetProp_Spec->Arc = _arc; GetProp_Spec->IndexInArc = index; GetProp_Spec->Name = MakePathNameFromParts(pathParts); return ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, _fi.IsDir, outStream, askExtractMode, GetProp); } #endif CMyComPtr outStreamLoc; if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) { if (_stdOutMode) { outStreamLoc = new CStdOutFileStream; } else { { NCOM::CPropVariant prop; RINOK(archive->GetProperty(index, kpidAttrib, &prop)); if (prop.vt == VT_UI4) { _fi.Attrib = prop.ulVal; _fi.AttribDefined = true; } else if (prop.vt == VT_EMPTY) _fi.AttribDefined = false; else return E_FAIL; } RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); bool isAnti = false; RINOK(_arc->IsItemAnti(index, isAnti)); bool replace = _isAltStream ? _ntOptions.ReplaceColonForAltStream : !_ntOptions.WriteToAltStreamIfColon; if (_pathMode != NExtract::NPathMode::kAbsPaths) MakeCorrectPath(_directoryPath.IsEmpty(), pathParts, replace); Correct_IfEmptyLastPart(pathParts); UString processedPath = MakePathNameFromParts(pathParts); if (!isAnti) { if (!_fi.IsDir) { if (!pathParts.IsEmpty()) pathParts.DeleteBack(); } if (!pathParts.IsEmpty()) { FString fullPathNew; CreateComplexDirectory(pathParts, fullPathNew); if (_fi.IsDir) { _extractedFolderPaths.Add(fullPathNew); _extractedFolderIndices.Add(index); SetDirTime(fullPathNew, (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); } } } FString fullProcessedPath = us2fs(processedPath); if (_pathMode != NExtract::NPathMode::kAbsPaths || !NName::IsAbsolutePath(processedPath)) fullProcessedPath = _directoryPath + fullProcessedPath; if (_fi.IsDir) { _diskFilePath = fullProcessedPath; if (isAnti) RemoveDir(_diskFilePath); #ifdef SUPPORT_LINKS if (linkPath.IsEmpty()) #endif return S_OK; } else if (!_isSplit) { NFind::CFileInfo fileInfo; if (fileInfo.Find(fullProcessedPath)) { switch (_overwriteMode) { case NExtract::NOverwriteMode::kSkip: return S_OK; case NExtract::NOverwriteMode::kAsk: { int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); #ifdef _WIN32 int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); slashPos = MyMax(slashPos, slash1Pos); #endif FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name; Int32 overwiteResult; RINOK(_extractCallback2->AskOverwrite( fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, fullPath, _fi.MTimeDefined ? &_fi.MTime : NULL, _curSizeDefined ? &_curSize : NULL, &overwiteResult)) switch (overwiteResult) { case NOverwriteAnswer::kCancel: return E_ABORT; case NOverwriteAnswer::kNo: return S_OK; case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; case NOverwriteAnswer::kYes: break; case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break; case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break; default: return E_FAIL; } } } if (_overwriteMode == NExtract::NOverwriteMode::kRename) { if (!AutoRenamePath(fullProcessedPath)) { RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); return E_FAIL; } } else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) { FString existPath = fullProcessedPath; if (!AutoRenamePath(existPath)) { RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); return E_FAIL; } // MyMoveFile can raname folders. So it's OK to use it folders too if (!MyMoveFile(fullProcessedPath, existPath)) { RINOK(SendMessageError(kCantRenameFile, fullProcessedPath)); return E_FAIL; } } else { if (fileInfo.IsDir()) { // do we need to delete all files in folder? if (!RemoveDir(fullProcessedPath)) { RINOK(SendMessageError(kCantDeleteOutputDir, fullProcessedPath)); return S_OK; } } else if (!DeleteFileAlways(fullProcessedPath)) { RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath)); return S_OK; // return E_FAIL; } } } } _diskFilePath = fullProcessedPath; if (!isAnti) { #ifdef SUPPORT_LINKS if (!linkPath.IsEmpty()) { #ifndef UNDER_CE UString relatPath; if (isRelative) relatPath = GetDirPrefixOf(_filePath); relatPath += linkPath; if (!IsSafePath(relatPath)) { RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath))); } else { FString existPath; if (isHardLink || !isRelative) { if (!NName::GetFullPath(_directoryPathFull, us2fs(relatPath), existPath)) { RINOK(SendMessageError("Incorrect path", us2fs(relatPath))); } } else { existPath = us2fs(linkPath); } if (!existPath.IsEmpty()) { if (isHardLink) { if (!MyCreateHardLink(fullProcessedPath, existPath)) { RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath)); // return S_OK; } } else if (_ntOptions.SymLinks.Val) { // bool isSymLink = true; // = false for junction if (_fi.IsDir && !isRelative) { // if it's before Vista we use Junction Point // isJunction = true; // convertToAbs = true; } CByteBuffer data; if (FillLinkData(data, fs2us(existPath), !isJunction)) { CReparseAttr attr; if (!attr.Parse(data, data.Size())) { return E_FAIL; // "Internal conversion error"; } if (!NFile::NIO::SetReparseData(fullProcessedPath, _fi.IsDir, data, (DWORD)data.Size())) { RINOK(SendMessageError("Can not set reparse data", fullProcessedPath)); } } } } } #endif } else #endif // SUPPORT_LINKS { bool needWriteFile = true; #ifdef SUPPORT_LINKS if (!_hardLinks.IDs.IsEmpty()) { CHardLinkNode h; bool defined; RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); if (defined) { { int linkIndex = _hardLinks.IDs.FindInSorted2(h); if (linkIndex >= 0) { FString &hl = _hardLinks.Links[linkIndex]; if (hl.IsEmpty()) hl = fullProcessedPath; else { if (!MyCreateHardLink(fullProcessedPath, hl)) { RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, hl)); return S_OK; } needWriteFile = false; } } } } } #endif if (needWriteFile) { _outFileStreamSpec = new COutFileStream; CMyComPtr outStreamLoc(_outFileStreamSpec); if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS)) { // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) { RINOK(SendMessageError("Can not open output file ", fullProcessedPath)); return S_OK; } } if (_isSplit) { RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); } _outFileStream = outStreamLoc; } } } outStreamLoc = _outFileStream; } } #ifndef _SFX if (_hashStream) { if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || askExtractMode == NArchive::NExtract::NAskMode::kTest) { _hashStreamSpec->SetStream(outStreamLoc); outStreamLoc = _hashStream; _hashStreamSpec->Init(true); _hashStreamWasUsed = true; } } #endif if (outStreamLoc) *outStream = outStreamLoc.Detach(); return S_OK; COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) { COM_TRY_BEGIN #ifndef _SFX if (ExtractToStreamCallback) return ExtractToStreamCallback->PrepareOperation7(askExtractMode); #endif _extractMode = false; switch (askExtractMode) { case NArchive::NExtract::NAskMode::kExtract: if (_testMode) askExtractMode = NArchive::NExtract::NAskMode::kTest; else _extractMode = true; break; }; return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir, askExtractMode, _isSplit ? &_position: 0); COM_TRY_END } STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) { COM_TRY_BEGIN #ifndef _SFX if (ExtractToStreamCallback) return ExtractToStreamCallback->SetOperationResult7(operationResult, _encrypted); #endif #ifndef _SFX if (_hashStreamWasUsed) { _hashStreamSpec->_hash->Final(_fi.IsDir, _isAltStream, _filePath); _curSize = _hashStreamSpec->GetSize(); _curSizeDefined = true; _hashStreamSpec->ReleaseStream(); _hashStreamWasUsed = false; } #endif if (_outFileStream) { _outFileStreamSpec->SetTime( (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); _curSize = _outFileStreamSpec->ProcessedSize; _curSizeDefined = true; RINOK(_outFileStreamSpec->Close()); _outFileStream.Release(); } #ifdef _USE_SECURITY_CODE if (_ntOptions.NtSecurity.Val && _arc->GetRawProps) { const void *data; UInt32 dataSize; UInt32 propType; _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); if (dataSize != 0) { if (propType != NPropDataType::kRaw) return E_FAIL; if (CheckNtSecure((const Byte *)data, dataSize)) { SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; if (_saclEnabled) securInfo |= SACL_SECURITY_INFORMATION; ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data); } } } #endif if (!_curSizeDefined) GetUnpackSize(); if (_curSizeDefined) { if (_isAltStream) AltStreams_UnpackSize += _curSize; else UnpackSize += _curSize; } if (_fi.IsDir) NumFolders++; else if (_isAltStream) NumAltStreams++; else NumFiles++; if (_extractMode && _fi.AttribDefined) SetFileAttrib(_diskFilePath, _fi.Attrib); RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted)); return S_OK; COM_TRY_END } /* STDMETHODIMP CArchiveExtractCallback::GetInStream( const wchar_t *name, ISequentialInStream **inStream) { COM_TRY_BEGIN CInFileStream *inFile = new CInFileStream; CMyComPtr inStreamTemp = inFile; if (!inFile->Open(_srcDirectoryPrefix + name)) return ::GetLastError(); *inStream = inStreamTemp.Detach(); return S_OK; COM_TRY_END } */ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (!_cryptoGetTextPassword) { RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, &_cryptoGetTextPassword)); } return _cryptoGetTextPassword->CryptoGetTextPassword(password); COM_TRY_END } struct CExtrRefSortPair { int Len; int Index; int Compare(const CExtrRefSortPair &a) const; }; #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const { RINOZ(-MyCompare(Len, a.Len)); return MyCompare(Index, a.Index); } static int GetNumSlashes(const FChar *s) { for (int numSlashes = 0;;) { FChar c = *s++; if (c == 0) return numSlashes; if ( #ifdef _WIN32 c == FTEXT('\\') || #endif c == FTEXT('/')) numSlashes++; } } HRESULT CArchiveExtractCallback::SetDirsTimes() { CRecordVector pairs; pairs.ClearAndSetSize(_extractedFolderPaths.Size()); unsigned i; for (i = 0; i < _extractedFolderPaths.Size(); i++) { CExtrRefSortPair &pair = pairs[i]; pair.Index = i; pair.Len = GetNumSlashes(_extractedFolderPaths[i]); } pairs.Sort2(); for (i = 0; i < pairs.Size(); i++) { int pairIndex = pairs[i].Index; int index = _extractedFolderIndices[pairIndex]; FILETIME CTime; FILETIME ATime; FILETIME MTime; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined)); RINOK(GetTime(index, kpidATime, ATime, ATimeDefined)); RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined)); // printf("\n%S", _extractedFolderPaths[pairIndex]); SetDirTime(_extractedFolderPaths[pairIndex], (WriteCTime && CTimeDefined) ? &CTime : NULL, (WriteATime && ATimeDefined) ? &ATime : NULL, (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h0100777000000000000000000001431513761647206026074 0ustar00// ArchiveExtractCallback.h #ifndef __ARCHIVE_EXTRACT_CALLBACK_H #define __ARCHIVE_EXTRACT_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../../Common/Wildcard.h" #include "../../IPassword.h" #include "../../Common/FileStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Archive/IArchive.h" #include "ExtractMode.h" #include "IFileExtractCallback.h" #include "OpenArchive.h" #include "HashCalc.h" #ifndef _SFX class COutStreamWithHash: public ISequentialOutStream, public CMyUnknownImp { CMyComPtr _stream; UInt64 _size; bool _calculate; public: IHashCalc *_hash; MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(bool calculate = true) { InitCRC(); _size = 0; _calculate = calculate; } void EnableCalc(bool calculate) { _calculate = calculate; } void InitCRC() { _hash->InitForNewFile(); } UInt64 GetSize() const { return _size; } }; #endif struct CExtractNtOptions { CBoolPair NtSecurity; CBoolPair SymLinks; CBoolPair HardLinks; CBoolPair AltStreams; bool ReplaceColonForAltStream; bool WriteToAltStreamIfColon; CExtractNtOptions(): ReplaceColonForAltStream(false), WriteToAltStreamIfColon(false) { SymLinks.Val = true; HardLinks.Val = true; AltStreams.Val = true; } }; #ifndef _SFX class CGetProp: public IGetProp, public CMyUnknownImp { public: const CArc *Arc; UInt32 IndexInArc; UString Name; // relative path MY_UNKNOWN_IMP1(IGetProp) INTERFACE_IGetProp(;) }; #endif #ifndef _SFX #ifndef UNDER_CE #define SUPPORT_LINKS #endif #endif #ifdef SUPPORT_LINKS struct CHardLinkNode { UInt64 StreamId; UInt64 INode; int Compare(const CHardLinkNode &a) const; }; class CHardLinks { public: CRecordVector IDs; CObjectVector Links; void Clear() { IDs.Clear(); Links.Clear(); } void PrepareLinks() { while (Links.Size() < IDs.Size()) Links.AddNew(); } }; #endif class CArchiveExtractCallback: public IArchiveExtractCallback, // public IArchiveVolumeExtractCallback, public ICryptoGetTextPassword, public ICompressProgressInfo, public CMyUnknownImp { const CArc *_arc; CExtractNtOptions _ntOptions; const NWildcard::CCensorNode *_wildcardCensor; CMyComPtr _extractCallback2; CMyComPtr _compressProgress; CMyComPtr _cryptoGetTextPassword; FString _directoryPath; FString _directoryPathFull; NExtract::NPathMode::EEnum _pathMode; NExtract::NOverwriteMode::EEnum _overwriteMode; #ifndef _SFX CMyComPtr ExtractToStreamCallback; CGetProp *GetProp_Spec; CMyComPtr GetProp; #endif FString _diskFilePath; UString _filePath; UInt64 _position; bool _isSplit; bool _isAltStream; bool _extractMode; bool WriteCTime; bool WriteATime; bool WriteMTime; bool _encrypted; struct CProcessedFileInfo { FILETIME CTime; FILETIME ATime; FILETIME MTime; UInt32 Attrib; bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; bool AttribDefined; bool IsDir; } _fi; UInt32 _index; UInt64 _curSize; bool _curSizeDefined; COutFileStream *_outFileStreamSpec; CMyComPtr _outFileStream; #ifndef _SFX COutStreamWithHash *_hashStreamSpec; CMyComPtr _hashStream; bool _hashStreamWasUsed; #endif UStringVector _removePathParts; bool _use_baseParentFolder_mode; UInt32 _baseParentFolder; bool _stdOutMode; bool _testMode; bool _multiArchives; CMyComPtr _localProgress; UInt64 _packTotal; UInt64 _unpTotal; FStringVector _extractedFolderPaths; CRecordVector _extractedFolderIndices; #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) bool _saclEnabled; #endif void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); HRESULT GetUnpackSize(); HRESULT SendMessageError(const char *message, const FString &path); HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2); public: CLocalProgress *LocalProgressSpec; UInt64 NumFolders; UInt64 NumFiles; UInt64 NumAltStreams; UInt64 UnpackSize; UInt64 AltStreams_UnpackSize; MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo) // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback) INTERFACE_IArchiveExtractCallback(;) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); // IArchiveVolumeExtractCallback // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream); STDMETHOD(CryptoGetTextPassword)(BSTR *password); CArchiveExtractCallback(); void InitForMulti(bool multiArchives, NExtract::NPathMode::EEnum pathMode, NExtract::NOverwriteMode::EEnum overwriteMode) { _multiArchives = multiArchives; _pathMode = pathMode; _overwriteMode = overwriteMode; NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; } #ifndef _SFX void SetHashMethods(IHashCalc *hash) { if (!hash) return; _hashStreamSpec = new COutStreamWithHash; _hashStream = _hashStreamSpec; _hashStreamSpec->_hash = hash; } #endif void Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, const CArc *arc, IFolderArchiveExtractCallback *extractCallback2, bool stdOutMode, bool testMode, const FString &directoryPath, const UStringVector &removePathParts, UInt64 packSize); #ifdef SUPPORT_LINKS private: CHardLinks _hardLinks; public: // call PrepareHardLinks() after Init() HRESULT PrepareHardLinks(const CRecordVector *realIndices); // NULL means all items #endif // call it after Init() void SetBaseParentFolderIndex(UInt32 indexInArc) { _use_baseParentFolder_mode = true; _baseParentFolder = indexInArc; } HRESULT SetDirsTimes(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp0100777000000000000000000000614313761647206025716 0ustar00// ArchiveOpenCallback.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../Common/FileStreams.h" #include "ArchiveOpenCallback.h" using namespace NWindows; STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes) { COM_TRY_BEGIN if (ReOpenCallback) return ReOpenCallback->SetTotal(files, bytes); if (!Callback) return S_OK; return Callback->Open_SetTotal(files, bytes); COM_TRY_END } STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes) { COM_TRY_BEGIN if (ReOpenCallback) return ReOpenCallback->SetCompleted(files, bytes); if (!Callback) return S_OK; return Callback->Open_SetCompleted(files, bytes); COM_TRY_END } STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; if (_subArchiveMode) switch(propID) { case kpidName: prop = _subArchiveName; break; } else switch(propID) { case kpidName: prop = _fileInfo.Name; break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; case kpidCTime: prop = _fileInfo.CTime; break; case kpidATime: prop = _fileInfo.ATime; break; case kpidMTime: prop = _fileInfo.MTime; break; } prop.Detach(value); return S_OK; COM_TRY_END } struct CInFileStreamVol: public CInFileStream { int FileNameIndex; COpenCallbackImp *OpenCallbackImp; CMyComPtr OpenCallbackRef; ~CInFileStreamVol() { if (OpenCallbackRef) OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false; } }; STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream) { COM_TRY_BEGIN *inStream = NULL; if (_subArchiveMode) return S_FALSE; if (Callback) { RINOK(Callback->Open_CheckBreak()); } FString fullPath; if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), fullPath)) return S_FALSE; if (!_fileInfo.Find(fullPath)) return S_FALSE; if (_fileInfo.IsDir()) return S_FALSE; CInFileStreamVol *inFile = new CInFileStreamVol; CMyComPtr inStreamTemp = inFile; if (!inFile->Open(fullPath)) return ::GetLastError(); FileSizes.Add(_fileInfo.Size); FileNames.Add(name); inFile->FileNameIndex = FileNames_WasUsed.Add(true); inFile->OpenCallbackImp = this; inFile->OpenCallbackRef = this; // TotalSize += _fileInfo.Size; *inStream = inStreamTemp.Detach(); return S_OK; COM_TRY_END } #ifndef _NO_CRYPTO STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (ReOpenCallback) { CMyComPtr getTextPassword; ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); if (getTextPassword) return getTextPassword->CryptoGetTextPassword(password); } if (!Callback) return E_NOTIMPL; return Callback->Open_CryptoGetTextPassword(password); COM_TRY_END } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h0100777000000000000000000000504613761647206025364 0ustar00// ArchiveOpenCallback.h #ifndef __ARCHIVE_OPEN_CALLBACK_H #define __ARCHIVE_OPEN_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../../Windows/FileFind.h" #ifndef _NO_CRYPTO #include "../../IPassword.h" #endif #include "../../Archive/IArchive.h" #ifdef _NO_CRYPTO #define INTERFACE_IOpenCallbackUI_Crypto(x) #else #define INTERFACE_IOpenCallbackUI_Crypto(x) \ virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \ virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x; \ virtual bool Open_WasPasswordAsked() x; \ virtual void Open_ClearPasswordWasAskedFlag() x; \ #endif #define INTERFACE_IOpenCallbackUI(x) \ virtual HRESULT Open_CheckBreak() x; \ virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \ virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \ INTERFACE_IOpenCallbackUI_Crypto(x) struct IOpenCallbackUI { INTERFACE_IOpenCallbackUI(=0) }; class COpenCallbackImp: public IArchiveOpenCallback, public IArchiveOpenVolumeCallback, public IArchiveOpenSetSubArchiveName, #ifndef _NO_CRYPTO public ICryptoGetTextPassword, #endif public CMyUnknownImp { public: #ifndef _NO_CRYPTO MY_UNKNOWN_IMP3( IArchiveOpenVolumeCallback, ICryptoGetTextPassword, IArchiveOpenSetSubArchiveName ) #else MY_UNKNOWN_IMP2( IArchiveOpenVolumeCallback, IArchiveOpenSetSubArchiveName ) #endif INTERFACE_IArchiveOpenCallback(;) INTERFACE_IArchiveOpenVolumeCallback(;) #ifndef _NO_CRYPTO STDMETHOD(CryptoGetTextPassword)(BSTR *password); #endif STDMETHOD(SetSubArchiveName(const wchar_t *name)) { _subArchiveMode = true; _subArchiveName = name; // TotalSize = 0; return S_OK; } private: FString _folderPrefix; NWindows::NFile::NFind::CFileInfo _fileInfo; bool _subArchiveMode; UString _subArchiveName; public: UStringVector FileNames; CBoolVector FileNames_WasUsed; CRecordVector FileSizes; IOpenCallbackUI *Callback; CMyComPtr ReOpenCallback; // UInt64 TotalSize; COpenCallbackImp(): Callback(NULL) {} void Init(const FString &folderPrefix, const FString &fileName) { _folderPrefix = folderPrefix; if (!_fileInfo.Find(_folderPrefix + fileName)) throw 20121118; FileNames.Clear(); FileNames_WasUsed.Clear(); FileSizes.Clear(); _subArchiveMode = false; // TotalSize = 0; } bool SetSecondFileInfo(CFSTR newName) { return _fileInfo.Find(newName) && !_fileInfo.IsDir(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Common.pri0100777000000000000000000000435713761647206023343 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/DirItem.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractMode.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/IFileExtractCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Property.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/StdAfx.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/Update.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.h SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/Update.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.cpp \ $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp0100777000000000000000000000167413761647206024267 0ustar00// DefaultName.cpp #include "StdAfx.h" #include "DefaultName.h" static UString GetDefaultName3(const UString &fileName, const UString &extension, const UString &addSubExtension) { int extLength = extension.Len(); int fileNameLength = fileName.Len(); if (fileNameLength > extLength + 1) { int dotPos = fileNameLength - (extLength + 1); if (fileName[dotPos] == '.') if (extension.IsEqualToNoCase(fileName.Ptr(dotPos + 1))) return fileName.Left(dotPos) + addSubExtension; } int dotPos = fileName.ReverseFind(L'.'); if (dotPos > 0) return fileName.Left(dotPos) + addSubExtension; if (addSubExtension.IsEmpty()) return fileName + L"~"; else return fileName + addSubExtension; } UString GetDefaultName2(const UString &fileName, const UString &extension, const UString &addSubExtension) { UString name = GetDefaultName3(fileName, extension, addSubExtension); name.TrimRight(); return name; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h0100777000000000000000000000034413761647206023725 0ustar00// DefaultName.h #ifndef __DEFAULT_NAME_H #define __DEFAULT_NAME_H #include "../../../Common/MyString.h" UString GetDefaultName2(const UString &fileName, const UString &extension, const UString &addSubExtension); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h0100777000000000000000000000520313761647206023074 0ustar00// DirItem.h #ifndef __DIR_ITEM_H #define __DIR_ITEM_H #include "../../../Common/MyString.h" #include "../../../Windows/FileFind.h" #include "../../Common/UniqBlocks.h" #include "../../Archive/IArchive.h" struct CDirItem { UInt64 Size; FILETIME CTime; FILETIME ATime; FILETIME MTime; UString Name; #if defined(_WIN32) && !defined(UNDER_CE) // UString ShortName; CByteBuffer ReparseData; CByteBuffer ReparseData2; // fixed (reduced) absolute links bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } #endif UInt32 Attrib; int PhyParent; int LogParent; int SecureIndex; bool IsAltStream; CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {} bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } }; class CDirItems { UStringVector Prefixes; CIntVector PhyParents; CIntVector LogParents; UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const; void EnumerateDir(int phyParent, int logParent, const FString &phyPrefix); public: CObjectVector Items; bool SymLinks; bool ScanAltStreams; FStringVector ErrorPaths; CRecordVector ErrorCodes; UInt64 TotalSize; #ifndef UNDER_CE void SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi, const FString &phyPrefix); #endif void AddError(const FString &path, DWORD errorCode) { ErrorCodes.Add(errorCode); ErrorPaths.Add(path); } void AddError(const FString &path) { AddError(path, ::GetLastError()); } #if defined(_WIN32) && !defined(UNDER_CE) CUniqBlocks SecureBlocks; CByteBuffer TempSecureBuf; bool _saclEnabled; bool ReadSecure; void AddSecurityItem(const FString &path, int &secureIndex); #endif CDirItems(); int GetNumFolders() const { return Prefixes.Size(); } UString GetPhyPath(unsigned index) const; UString GetLogPath(unsigned index) const; unsigned AddPrefix(int phyParent, int logParent, const UString &prefix); void DeleteLastPrefix(); void EnumerateItems2( const FString &phyPrefix, const UString &logPrefix, const FStringVector &filePaths, FStringVector *requestedPaths); #if defined(_WIN32) && !defined(UNDER_CE) void FillFixedReparse(); #endif void ReserveDown(); }; struct CArcItem { UInt64 Size; FILETIME MTime; UString Name; bool IsDir; bool IsAltStream; bool SizeDefined; bool MTimeDefined; bool Censored; UInt32 IndexInServer; int TimeType; CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp0100777000000000000000000004753713761647206024457 0ustar00// EnumDirItems.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileIO.h" #include "../../../Windows/FileName.h" #if defined(_WIN32) && !defined(UNDER_CE) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif #include "EnumDirItems.h" using namespace NWindows; using namespace NFile; using namespace NName; void AddDirFileInfo(int phyParent, int logParent, int secureIndex, const NFind::CFileInfo &fi, CObjectVector &dirItems) { CDirItem di; di.Size = fi.Size; di.CTime = fi.CTime; di.ATime = fi.ATime; di.MTime = fi.MTime; di.Attrib = fi.Attrib; di.IsAltStream = fi.IsAltStream; di.PhyParent = phyParent; di.LogParent = logParent; di.SecureIndex = secureIndex; di.Name = fs2us(fi.Name); #if defined(_WIN32) && !defined(UNDER_CE) // di.ShortName = fs2us(fi.ShortName); #endif dirItems.Add(di); } UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const { UString path; unsigned len = name.Len(); int i; for (i = index; i >= 0; i = parents[i]) len += Prefixes[i].Len(); unsigned totalLen = len; wchar_t *p = path.GetBuffer(len); p[len] = 0; len -= name.Len(); memcpy(p + len, (const wchar_t *)name, name.Len() * sizeof(wchar_t)); for (i = index; i >= 0; i = parents[i]) { const UString &s = Prefixes[i]; len -= s.Len(); memcpy(p + len, (const wchar_t *)s, s.Len() * sizeof(wchar_t)); } path.ReleaseBuffer(totalLen); return path; } UString CDirItems::GetPhyPath(unsigned index) const { const CDirItem &di = Items[index]; return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); } UString CDirItems::GetLogPath(unsigned index) const { const CDirItem &di = Items[index]; return GetPrefixesPath(LogParents, di.LogParent, di.Name); } void CDirItems::ReserveDown() { Prefixes.ReserveDown(); PhyParents.ReserveDown(); LogParents.ReserveDown(); Items.ReserveDown(); } unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) { PhyParents.Add(phyParent); LogParents.Add(logParent); return Prefixes.Add(prefix); } void CDirItems::DeleteLastPrefix() { PhyParents.DeleteBack(); LogParents.DeleteBack(); Prefixes.DeleteBack(); } bool InitLocalPrivileges(); CDirItems::CDirItems(): SymLinks(false), TotalSize(0) #ifdef _USE_SECURITY_CODE , ReadSecure(false) #endif { #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } #ifdef _USE_SECURITY_CODE void CDirItems::AddSecurityItem(const FString &path, int &secureIndex) { secureIndex = -1; SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; if (_saclEnabled) securInfo |= SACL_SECURITY_INFORMATION; DWORD errorCode = 0; DWORD secureSize; BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); if (res) { if (secureSize == 0) return; if (secureSize > TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION; } else { errorCode = GetLastError(); if (errorCode == ERROR_INSUFFICIENT_BUFFER) { if (secureSize <= TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION; else { TempSecureBuf.Alloc(secureSize); res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); if (res) { if (secureSize != TempSecureBuf.Size()) errorCode = ERROR_INVALID_FUNCTION;; } else errorCode = GetLastError(); } } } if (res) { secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize); return; } if (errorCode == 0) errorCode = ERROR_INVALID_FUNCTION; AddError(path, errorCode); } #endif void CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix) { NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); for (;;) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { AddError(phyPrefix); return; } if (!found) break; int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) AddSecurityItem(phyPrefix + fi.Name, secureIndex); #endif AddDirFileInfo(phyParent, logParent, secureIndex, fi, Items); if (fi.IsDir()) { const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); EnumerateDir(parent, parent, phyPrefix + name2); } } } void CDirItems::EnumerateItems2( const FString &phyPrefix, const UString &logPrefix, const FStringVector &filePaths, FStringVector *requestedPaths) { int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix)); int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix); FOR_VECTOR (i, filePaths) { const FString &filePath = filePaths[i]; NFind::CFileInfo fi; const FString phyPath = phyPrefix + filePath; if (!fi.Find(phyPath)) { AddError(phyPath); continue; } if (requestedPaths) requestedPaths->Add(phyPath); int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR); FString phyPrefixCur; int phyParentCur = phyParent; if (delimiter >= 0) { phyPrefixCur.SetFrom(filePath, delimiter + 1); phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); } int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) AddSecurityItem(phyPath, secureIndex); #endif AddDirFileInfo(phyParentCur, logParent, secureIndex, fi, Items); if (fi.IsDir()) { const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2); } } ReserveDown(); } static HRESULT EnumerateDirItems( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback); static HRESULT EnumerateDirItems_Spec( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &curFolderName, const FString &phyPrefix, const UStringVector &addArchivePrefix, CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); unsigned numItems = dirItems.Items.Size(); HRESULT res = EnumerateDirItems( curNode, parent, parent, phyPrefix + name2, addArchivePrefix, dirItems, enterToSubFolders, callback); if (numItems == dirItems.Items.Size()) dirItems.DeleteLastPrefix(); return res; } #ifndef UNDER_CE static void EnumerateAltStreams( const NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems) { const FString fullPath = phyPrefix + fi.Name; NFind::CStreamEnumerator enumerator(fullPath); for (;;) { NFind::CStreamInfo si; bool found; if (!enumerator.Next(si, found)) { dirItems.AddError(fullPath + FTEXT(":*"), (DWORD)E_FAIL); break; } if (!found) break; if (si.IsMainStream()) continue; UStringVector addArchivePrefixNew = addArchivePrefix; UString reducedName = si.GetReducedName(); addArchivePrefixNew.Back() += reducedName; if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true)) continue; NFind::CFileInfo fi2 = fi; fi2.Name += us2fs(reducedName); fi2.Size = si.Size; fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; fi2.IsAltStream = true; AddDirFileInfo(phyParent, logParent, -1, fi2, dirItems.Items); dirItems.TotalSize += fi2.Size; } } void CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, const FString &phyPrefix) { if (!SymLinks || !fi.HasReparsePoint()) return; const FString path = phyPrefix + fi.Name; CByteBuffer &buf = dirItem.ReparseData; if (NIO::GetReparseData(path, buf)) { CReparseAttr attr; if (attr.Parse(buf, buf.Size())) return; } AddError(path); buf.Free(); } #endif static HRESULT EnumerateForItem( NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { const UString name = fs2us(fi.Name); bool enterToSubFolders2 = enterToSubFolders; UStringVector addArchivePrefixNew = addArchivePrefix; addArchivePrefixNew.Add(name); { UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) return S_OK; } int dirItemIndex = -1; if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (dirItems.ReadSecure) dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex); #endif dirItemIndex = dirItems.Items.Size(); AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); dirItems.TotalSize += fi.Size; if (fi.IsDir()) enterToSubFolders2 = true; } #ifndef UNDER_CE if (dirItems.ScanAltStreams) { EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefixNew, dirItems); } if (dirItemIndex >= 0) { CDirItem &dirItem = dirItems.Items[dirItemIndex]; dirItems.SetLinkInfo(dirItem, fi, phyPrefix); if (dirItem.ReparseData.Size() != 0) return S_OK; } #endif if (!fi.IsDir()) return S_OK; const NWildcard::CCensorNode *nextNode = 0; if (addArchivePrefix.IsEmpty()) { int index = curNode.FindSubNode(name); if (index >= 0) nextNode = &curNode.SubNodes[index]; } if (!enterToSubFolders2 && nextNode == 0) return S_OK; addArchivePrefixNew = addArchivePrefix; if (nextNode == 0) { nextNode = &curNode; addArchivePrefixNew.Add(name); } return EnumerateDirItems_Spec( *nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, enterToSubFolders2, callback); } static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode) { FOR_VECTOR (i, curNode.IncludeItems) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.Recursive || item.PathParts.Size() != 1) return false; const UString &name = item.PathParts.Front(); if (name.IsEmpty()) return false; /* Windows doesn't support file name with wildcard. but if another system supports file name with wildcard, and wildcard mode is disabled, we can ignore wildcard in name */ /* if (!item.WildcardParsing) continue; */ if (DoesNameContainWildcard(name)) return false; } return true; } static HRESULT EnumerateDirItems( const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback) { if (!enterToSubFolders) if (curNode.NeedCheckSubDirs()) enterToSubFolders = true; if (callback) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); // try direct_names case at first if (addArchivePrefix.IsEmpty() && !enterToSubFolders) { if (CanUseFsDirect(curNode)) { // all names are direct (no wildcards) // so we don't need file_system's dir enumerator CRecordVector needEnterVector; unsigned i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; const UString &name = item.PathParts.Front(); const FString fullPath = phyPrefix + us2fs(name); NFind::CFileInfo fi; #ifdef _WIN32 if (phyPrefix.IsEmpty() && item.IsDriveItem()) { fi.SetAsDir(); fi.Name = fullPath; } else #endif if (!fi.Find(fullPath)) { dirItems.AddError(fullPath); continue; } bool isDir = fi.IsDir(); if (isDir && !item.ForDir || !isDir && !item.ForFile) { dirItems.AddError(fullPath, (DWORD)E_FAIL); continue; } { UStringVector pathParts; pathParts.Add(fs2us(fi.Name)); if (curNode.CheckPathToRoot(false, pathParts, !isDir)) continue; } int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (dirItems.ReadSecure) dirItems.AddSecurityItem(fullPath, secureIndex); #endif AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); #ifndef UNDER_CE { CDirItem &dirItem = dirItems.Items.Back(); dirItems.SetLinkInfo(dirItem, fi, phyPrefix); if (dirItem.ReparseData.Size() != 0) continue; } #endif dirItems.TotalSize += fi.Size; #ifndef UNDER_CE if (dirItems.ScanAltStreams) { UStringVector pathParts; pathParts.Add(fs2us(fi.Name)); EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, pathParts, dirItems); } #endif if (!isDir) continue; UStringVector addArchivePrefixNew; const NWildcard::CCensorNode *nextNode = 0; int index = curNode.FindSubNode(name); if (index >= 0) { for (int t = needEnterVector.Size(); t <= index; t++) needEnterVector.Add(true); needEnterVector[index] = false; nextNode = &curNode.SubNodes[index]; } else { nextNode = &curNode; addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support } RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, true, callback)); } for (i = 0; i < curNode.SubNodes.Size(); i++) { if (i < needEnterVector.Size()) if (!needEnterVector[i]) continue; const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; const FString fullPath = phyPrefix + us2fs(nextNode.Name); NFind::CFileInfo fi; #ifdef _WIN32 if (phyPrefix.IsEmpty() && NWildcard::IsDriveColonName(nextNode.Name)) { fi.SetAsDir(); fi.Name = fullPath; } else #endif if (!fi.Find(fullPath)) { if (!nextNode.AreThereIncludeItems()) continue; dirItems.AddError(fullPath); continue; } if (!fi.IsDir()) { dirItems.AddError(fullPath, (DWORD)E_FAIL); continue; } RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, UStringVector(), dirItems, false, callback)); } return S_OK; } } #ifdef _WIN32 #ifndef UNDER_CE // scan drives, if wildcard is "*:\" if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0) { unsigned i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.PathParts.Size() < 1) break; const UString &name = item.PathParts.Front(); if (name.Len() != 2 || name[1] != ':') break; if (item.PathParts.Size() == 1) if (item.ForFile || !item.ForDir) break; if (NWildcard::IsDriveColonName(name)) continue; if (name[0] != '*' && name[0] != '?') break; } if (i == curNode.IncludeItems.Size()) { FStringVector driveStrings; NFind::MyGetLogicalDriveStrings(driveStrings); for (i = 0; i < driveStrings.Size(); i++) { FString driveName = driveStrings[i]; if (driveName.Len() < 3 || driveName.Back() != '\\') return E_FAIL; driveName.DeleteBack(); NFind::CFileInfo fi; fi.SetAsDir(); fi.Name = driveName; RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefix, dirItems, enterToSubFolders, callback)); } return S_OK; } } #endif #endif NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); for (unsigned ttt = 0; ; ttt++) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { dirItems.AddError(phyPrefix); break; } if (!found) break; if (callback && (ttt & 0xFF) == 0xFF) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, addArchivePrefix, dirItems, enterToSubFolders, callback)); } return S_OK; } HRESULT EnumerateItems( const NWildcard::CCensor &censor, const NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, CDirItems &dirItems, IEnumDirItemCallback *callback) { FOR_VECTOR (i, censor.Pairs) { const NWildcard::CPair &pair = censor.Pairs[i]; int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix); int logParent = -1; if (pathMode == NWildcard::k_AbsPath) logParent = phyParent; else { if (!addPathPrefix.IsEmpty()) logParent = dirItems.AddPrefix(-1, -1, addPathPrefix); } RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(), dirItems, false, // enterToSubFolders callback)); } dirItems.ReserveDown(); #if defined(_WIN32) && !defined(UNDER_CE) dirItems.FillFixedReparse(); #endif return S_OK; } #if defined(_WIN32) && !defined(UNDER_CE) void CDirItems::FillFixedReparse() { /* imagex/WIM reduces absolute pathes in links (raparse data), if we archive non root folder. We do same thing here */ if (!SymLinks) return; FOR_VECTOR(i, Items) { CDirItem &item = Items[i]; if (item.ReparseData.Size() == 0) continue; CReparseAttr attr; if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) continue; if (attr.IsRelative()) continue; const UString &link = attr.GetPath(); if (!IsDrivePath(link)) continue; // maybe we need to support networks paths also ? FString fullPathF; if (!NDir::MyGetFullPathName(us2fs(GetPhyPath(i)), fullPathF)) continue; UString fullPath = fs2us(fullPathF); const UString logPath = GetLogPath(i); if (logPath.Len() >= fullPath.Len()) continue; if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0) continue; const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len()); if (prefix.Back() != WCHAR_PATH_SEPARATOR) continue; unsigned rootPrefixSize = GetRootPrefixSize(prefix); if (rootPrefixSize == 0) continue; if (rootPrefixSize == prefix.Len()) continue; // simple case: paths are from root if (link.Len() <= prefix.Len()) continue; if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) continue; UString newLink = prefix.Left(rootPrefixSize); newLink += link.Ptr(prefix.Len()); CByteBuffer data; if (!FillLinkData(data, newLink, attr.IsSymLink())) continue; item.ReparseData2 = data; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h0100777000000000000000000000126413761647206024107 0ustar00// EnumDirItems.h #ifndef __ENUM_DIR_ITEMS_H #define __ENUM_DIR_ITEMS_H #include "../../../Common/Wildcard.h" #include "../../../Windows/FileFind.h" #include "DirItem.h" void AddDirFileInfo(int phyParent, int logParent, int secureIndex, const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector &dirItems); struct IEnumDirItemCallback { virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) = 0; }; HRESULT EnumerateItems( const NWildcard::CCensor &censor, NWildcard::ECensorPathMode pathMode, const UString &addPathPrefix, CDirItems &dirItems, IEnumDirItemCallback *callback); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp0100777000000000000000000003005313761647206023505 0ustar00// Extract.cpp #include "StdAfx.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../Common/ExtractingFilePath.h" #include "Extract.h" #include "SetProperties.h" using namespace NWindows; using namespace NFile; using namespace NDir; static HRESULT DecompressArchive( CCodecs *codecs, const CArchiveLink &arcLink, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, bool calcCrc, IExtractCallbackUI *callback, CArchiveExtractCallback *ecs, UString &errorMessage, UInt64 &stdInProcessed) { const CArc &arc = arcLink.Arcs.Back(); stdInProcessed = 0; IInArchive *archive = arc.Archive; CRecordVector realIndices; UStringVector removePathParts; FString outDir = options.OutputDir; UString replaceName = arc.DefaultName; if (arcLink.Arcs.Size() > 1) { // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". // So it extracts different archives to one folder. // We will use top level archive name const CArc &arc0 = arcLink.Arcs[0]; if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe")) replaceName = arc0.DefaultName; } outDir.Replace(FSTRING_ANY_MASK, us2fs(GetCorrectFsPath(replaceName))); bool elimIsPossible = false; UString elimPrefix; // only pure name without dir delimiter FString outDirReduced = outDir; if (options.ElimDup.Val) { UString dirPrefix; SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); if (!elimPrefix.IsEmpty()) { if (IsCharDirLimiter(elimPrefix.Back())) elimPrefix.DeleteBack(); if (!elimPrefix.IsEmpty()) { outDirReduced = us2fs(dirPrefix); elimIsPossible = true; } } } if (!options.StdInMode) { UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); UString filePath; for (UInt32 i = 0; i < numItems; i++) { RINOK(arc.GetItemPath(i, filePath)); if (elimIsPossible && options.ElimDup.Val) { if (!IsPath1PrefixedByPath2(filePath, elimPrefix)) elimIsPossible = false; else { wchar_t c = filePath[elimPrefix.Len()]; if (c != 0 && !IsCharDirLimiter(c)) elimIsPossible = false; } } bool isFolder; RINOK(Archive_IsItem_Folder(archive, i, isFolder)); bool isAltStream; RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); if (!options.NtOptions.AltStreams.Val && isAltStream) continue; if (!wildcardCensor.CheckPath(isAltStream, filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return callback->ExtractResult(S_OK); } } if (elimIsPossible) outDir = outDirReduced; #ifdef _WIN32 // GetCorrectFullFsPath doesn't like "..". // outDir.TrimRight(); // outDir = GetCorrectFullFsPath(outDir); #endif if (outDir.IsEmpty()) outDir = FString(FTEXT(".")) + FString(FSTRING_PATH_SEPARATOR); else if (!CreateComplexDir(outDir)) { HRESULT res = ::GetLastError(); if (res == S_OK) res = E_FAIL; errorMessage = ((UString)L"Can not create output directory ") + fs2us(outDir); return res; } ecs->Init( options.NtOptions, options.StdInMode ? &wildcardCensor : NULL, &arc, callback, options.StdOutMode, options.TestMode, outDir, removePathParts, packSize); #ifdef SUPPORT_LINKS if (!options.StdInMode && !options.TestMode && options.NtOptions.HardLinks.Val) { RINOK(ecs->PrepareHardLinks(&realIndices)); } #endif HRESULT result; Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; if (options.StdInMode) { result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); NCOM::CPropVariant prop; if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) ConvertPropVariantToUInt64(prop, stdInProcessed); } else result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs); if (result == S_OK && !options.StdInMode) result = ecs->SetDirsTimes(); return callback->ExtractResult(result); } /* v9.31: BUG was fixed: Sorted list for file paths was sorted with case insensitive compare function. But FindInSorted function did binary search via case sensitive compare function */ int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) { unsigned left = 0, right = fileName.Size(); while (left != right) { unsigned mid = (left + right) / 2; const UString &midValue = fileName[mid]; int compare = CompareFileNames(name, midValue); if (compare == 0) return mid; if (compare < 0) right = mid; else left = mid + 1; } return -1; } HRESULT Extract( CCodecs *codecs, const CObjectVector &types, const CIntVector &excludedFormats, UStringVector &arcPaths, UStringVector &arcPathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, #ifndef _SFX IHashCalc *hash, #endif UString &errorMessage, CDecompressStat &stat) { stat.Clear(); UInt64 totalPackSize = 0; CRecordVector arcSizes; unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); unsigned i; for (i = 0; i < numArcs; i++) { NFind::CFileInfo fi; fi.Size = 0; if (!options.StdInMode) { const FString &arcPath = us2fs(arcPaths[i]); if (!fi.Find(arcPath)) throw "there is no such archive"; if (fi.IsDir()) throw "can't decompress folder"; } arcSizes.Add(fi.Size); totalPackSize += fi.Size; } CBoolArr skipArcs(numArcs); for (i = 0; i < numArcs; i++) skipArcs[i] = false; CArchiveExtractCallback *ecs = new CArchiveExtractCallback; CMyComPtr ec(ecs); bool multi = (numArcs > 1); ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode); #ifndef _SFX ecs->SetHashMethods(hash); #endif if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } UInt64 totalPackProcessed = 0; bool thereAreNotOpenArcs = false; for (i = 0; i < numArcs; i++) { if (skipArcs[i]) continue; const UString &arcPath = arcPaths[i]; NFind::CFileInfo fi; if (options.StdInMode) { fi.Size = 0; fi.Attrib = 0; } else { if (!fi.Find(us2fs(arcPath)) || fi.IsDir()) throw "there is no such archive"; } #ifndef _NO_CRYPTO openCallback->Open_ClearPasswordWasAskedFlag(); #endif RINOK(extractCallback->BeforeOpen(arcPath)); CArchiveLink arcLink; CObjectVector types2 = types; /* #ifndef _SFX if (types.IsEmpty()) { int pos = arcPath.ReverseFind(L'.'); if (pos >= 0) { UString s = arcPath.Ptr(pos + 1); int index = codecs->FindFormatForExtension(s); if (index >= 0 && s == L"001") { s = arcPath.Left(pos); pos = s.ReverseFind(L'.'); if (pos >= 0) { int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1)); if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 { types2.Add(index2); types2.Add(index); } } } } } #endif */ COpenOptions op; #ifndef _SFX op.props = &options.Properties; #endif op.codecs = codecs; op.types = &types2; op.excludedFormats = &excludedFormats; op.stdInMode = options.StdInMode; op.stream = NULL; op.filePath = arcPath; HRESULT result = arcLink.Open2(op, openCallback); if (result == E_ABORT) return result; bool crypted = false; #ifndef _NO_CRYPTO crypted = openCallback->Open_WasPasswordAsked(); #endif if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) result = S_FALSE; // arcLink.Set_ErrorsText(); RINOK(extractCallback->OpenResult(arcPath, result, crypted)); { FOR_VECTOR (r, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[r]; const CArcErrorInfo &er = arc.ErrorInfo; if (er.IsThereErrorOrWarning()) { RINOK(extractCallback->SetError(r, arc.Path, er.GetErrorFlags(), er.ErrorMessage, er.GetWarningFlags(), er.WarningMessage)); } } } if (result != S_OK) { thereAreNotOpenArcs = true; if (!options.StdInMode) { NFind::CFileInfo fi; if (fi.Find(us2fs(arcPath))) if (!fi.IsDir()) totalPackProcessed += fi.Size; } continue; } if (!options.StdInMode) { // numVolumes += arcLink.VolumePaths.Size(); // arcLink.VolumesSize; // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); // numArcs = arcPaths.Size(); if (arcLink.VolumePaths.Size() != 0) { Int64 correctionSize = arcLink.VolumesSize; FOR_VECTOR (v, arcLink.VolumePaths) { int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); if (index >= 0) { if ((unsigned)index > i) { skipArcs[index] = true; correctionSize -= arcSizes[index]; } } } if (correctionSize != 0) { Int64 newPackSize = (Int64)totalPackSize + correctionSize; if (newPackSize < 0) newPackSize = 0; totalPackSize = newPackSize; RINOK(extractCallback->SetTotal(totalPackSize)); } } } #ifndef _NO_CRYPTO bool passwordIsDefined; UString password; RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)); if (passwordIsDefined) { RINOK(extractCallback->SetPassword(password)); } #endif FOR_VECTOR (k, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[k]; const CArcErrorInfo &er = arc.ErrorInfo; if (er.ErrorFormatIndex >= 0) { RINOK(extractCallback->OpenTypeWarning(arc.Path, codecs->GetFormatNamePtr(arc.FormatIndex), codecs->GetFormatNamePtr(er.ErrorFormatIndex))) /* UString s = L"Can not open the file as [" + codecs->Formats[arc.ErrorFormatIndex].Name + L"] archive\n"; s += L"The file is open as [" + codecs->Formats[arc.FormatIndex].Name + L"] archive"; RINOK(extractCallback->MessageError(s)); */ } { const UString &s = er.ErrorMessage; if (!s.IsEmpty()) { RINOK(extractCallback->MessageError(s)); } } } CArc &arc = arcLink.Arcs.Back(); arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); arc.MTime = fi.MTime; UInt64 packProcessed; bool calcCrc = #ifndef _SFX (hash != NULL); #else false; #endif RINOK(DecompressArchive( codecs, arcLink, fi.Size + arcLink.VolumesSize, wildcardCensor, options, calcCrc, extractCallback, ecs, errorMessage, packProcessed)); if (!options.StdInMode) packProcessed = fi.Size + arcLink.VolumesSize; totalPackProcessed += packProcessed; ecs->LocalProgressSpec->InSize += packProcessed; ecs->LocalProgressSpec->OutSize = ecs->UnpackSize; if (!errorMessage.IsEmpty()) return E_FAIL; } if (multi || thereAreNotOpenArcs) { RINOK(extractCallback->SetTotal(totalPackSize)); RINOK(extractCallback->SetCompleted(&totalPackProcessed)); } stat.NumFolders = ecs->NumFolders; stat.NumFiles = ecs->NumFiles; stat.NumAltStreams = ecs->NumAltStreams; stat.UnpackSize = ecs->UnpackSize; stat.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; stat.NumArchives = arcPaths.Size(); stat.PackSize = ecs->LocalProgressSpec->InSize; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h0100777000000000000000000000364113761647206023155 0ustar00// Extract.h #ifndef __EXTRACT_H #define __EXTRACT_H #include "../../../Windows/FileFind.h" #include "../../Archive/IArchive.h" #include "ArchiveExtractCallback.h" #include "ArchiveOpenCallback.h" #include "ExtractMode.h" #include "Property.h" #include "../Common/LoadCodecs.h" struct CExtractOptionsBase { CBoolPair ElimDup; bool PathMode_Force; bool OverwriteMode_Force; NExtract::NPathMode::EEnum PathMode; NExtract::NOverwriteMode::EEnum OverwriteMode; FString OutputDir; CExtractNtOptions NtOptions; CExtractOptionsBase(): PathMode_Force(false), OverwriteMode_Force(false), PathMode(NExtract::NPathMode::kFullPaths), OverwriteMode(NExtract::NOverwriteMode::kAsk) {} }; struct CExtractOptions: public CExtractOptionsBase { bool StdInMode; bool StdOutMode; bool YesToAll; bool TestMode; // bool ShowDialog; // bool PasswordEnabled; // UString Password; #ifndef _SFX CObjectVector Properties; #endif #ifdef EXTERNAL_CODECS CCodecs *Codecs; #endif CExtractOptions(): TestMode(false), StdInMode(false), StdOutMode(false), YesToAll(false) {} }; struct CDecompressStat { UInt64 NumArchives; UInt64 UnpackSize; UInt64 AltStreams_UnpackSize; UInt64 PackSize; UInt64 NumFolders; UInt64 NumFiles; UInt64 NumAltStreams; void Clear() { NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0; } }; HRESULT Extract( CCodecs *codecs, const CObjectVector &types, const CIntVector &excludedFormats, UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, #ifndef _SFX IHashCalc *hash, #endif UString &errorMessage, CDecompressStat &stat); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp0100777000000000000000000000775313761647206025633 0ustar00// ExtractingFilePath.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileName.h" #include "ExtractingFilePath.h" static UString ReplaceIncorrectChars(const UString &s, bool repaceColon) { #ifdef _WIN32 UString res; bool beforeColon = true; { for (unsigned i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if (beforeColon) if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"') c = '_'; if (c == ':') { if (repaceColon) c = '_'; else beforeColon = false; } res += c; } } if (beforeColon) { for (int i = res.Len() - 1; i >= 0; i--) { wchar_t c = res[i]; if (c != '.' && c != ' ') break; res.ReplaceOneCharAtPos(i, '_'); } } return res; #else return s; #endif } #ifdef _WIN32 static const wchar_t *g_ReservedNames[] = { L"CON", L"PRN", L"AUX", L"NUL" }; static bool CheckTail(const UString &name, unsigned len) { int dotPos = name.Find(L'.'); if (dotPos < 0) dotPos = name.Len(); UString s = name.Left(dotPos); s.TrimRight(); return s.Len() != len; } static bool CheckNameNum(const UString &name, const wchar_t *reservedName) { unsigned len = MyStringLen(reservedName); if (name.Len() <= len) return true; if (MyStringCompareNoCase_N(name, reservedName, len) != 0) return true; wchar_t c = name[len]; if (c < L'0' || c > L'9') return true; return CheckTail(name, len + 1); } static bool IsSupportedName(const UString &name) { for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++) { const wchar_t *reservedName = g_ReservedNames[i]; unsigned len = MyStringLen(reservedName); if (name.Len() < len) continue; if (MyStringCompareNoCase_N(name, reservedName, len) != 0) continue; if (!CheckTail(name, len)) return false; } if (!CheckNameNum(name, L"COM")) return false; return CheckNameNum(name, L"LPT"); } #endif static UString GetCorrectFileName(const UString &path, bool repaceColon) { if (path == L".." || path == L".") return UString(); return ReplaceIncorrectChars(path, repaceColon); } void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon) { for (unsigned i = 0; i < pathParts.Size();) { UString &s = pathParts[i]; #ifdef _WIN32 bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1); if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s)) { UString s2 = s[0]; s2 += L'_'; s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon); s = s2; } else s = GetCorrectFileName(s, needReplaceColon); #endif if (s.IsEmpty()) pathParts.Delete(i); else { #ifdef _WIN32 if (!IsSupportedName(s)) s = (UString)L"_" + s; #endif i++; } } } UString MakePathNameFromParts(const UStringVector &parts) { UString result; FOR_VECTOR (i, parts) { if (i != 0) result += WCHAR_PATH_SEPARATOR; result += parts[i]; } return result; } static const wchar_t *k_EmptyReplaceName = L"[]"; void Correct_IfEmptyLastPart(UStringVector &parts) { if (parts.IsEmpty()) parts.Add(k_EmptyReplaceName); else { UString &s = parts.Back(); if (s.IsEmpty()) s = k_EmptyReplaceName; } } UString GetCorrectFsPath(const UString &path) { UString res = GetCorrectFileName(path, true); #ifdef _WIN32 if (!IsSupportedName(res)) res = (UString)L"_" + res; #endif if (res.IsEmpty()) res = k_EmptyReplaceName; return res; } UString GetCorrectFullFsPath(const UString &path) { UStringVector parts; SplitPathToParts(path, parts); FOR_VECTOR (i, parts) { UString &s = parts[i]; #ifdef _WIN32 while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' ')) s.DeleteBack(); if (!IsSupportedName(s)) s.InsertAtFront(L'_'); #endif } return MakePathNameFromParts(parts); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h0100777000000000000000000000120413761647206025261 0ustar00// ExtractingFilePath.h #ifndef __EXTRACTING_FILE_PATH_H #define __EXTRACTING_FILE_PATH_H #include "../../../Common/MyString.h" UString MakePathNameFromParts(const UStringVector &parts); /* for WIN32: if (isRoot == true), and pathParts[0] contains path like "c:name", it thinks that "c:" is drive prefix (it's not ":name alt stream) and the function changes part to c_name */ void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon); UString GetCorrectFsPath(const UString &path); UString GetCorrectFullFsPath(const UString &path); void Correct_IfEmptyLastPart(UStringVector &parts); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h0100777000000000000000000000051113761647206023753 0ustar00// ExtractMode.h #ifndef __EXTRACT_MODE_H #define __EXTRACT_MODE_H namespace NExtract { namespace NPathMode { enum EEnum { kFullPaths, kCurPaths, kNoPaths, kAbsPaths }; } namespace NOverwriteMode { enum EEnum { kAsk, kOverwrite, kSkip, kRename, kRenameExisting }; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/HashCalc.cpp0100777000000000000000000002033713761647206023545 0ustar00// HashCalc.cpp #include "StdAfx.h" #include "../../../../C/Alloc.h" #include "../../../Common/StringToInt.h" #include "../../Common/FileStreams.h" #include "../../Common/StreamUtils.h" #include "EnumDirItems.h" #include "HashCalc.h" using namespace NWindows; class CHashMidBuf { void *_data; public: CHashMidBuf(): _data(0) {} operator void *() { return _data; } bool Alloc(size_t size) { if (_data != 0) return false; _data = ::MidAlloc(size); return _data != 0; } ~CHashMidBuf() { ::MidFree(_data); } }; struct CEnumDirItemCallback_Hash: public IEnumDirItemCallback { IHashCallbackUI *Callback; HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) { return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); } }; static const wchar_t *k_DefaultHashMethod = L"CRC32"; HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods) { UStringVector names = hashMethods; if (names.IsEmpty()) names.Add(k_DefaultHashMethod); CRecordVector ids; CObjectVector methods; unsigned i; for (i = 0; i < names.Size(); i++) { COneMethodInfo m; RINOK(m.ParseMethodFromString(names[i])); if (m.MethodName.IsEmpty()) m.MethodName = k_DefaultHashMethod; if (m.MethodName == L"*") { CRecordVector tempMethods; GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); methods.Clear(); ids.Clear(); FOR_VECTOR (t, tempMethods) { int index = ids.AddToUniqueSorted(tempMethods[t]); if (ids.Size() != methods.Size()) methods.Insert(index, m); } break; } else { // m.MethodName.RemoveChar(L'-'); CMethodId id; if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id)) return E_NOTIMPL; int index = ids.AddToUniqueSorted(id); if (ids.Size() != methods.Size()) methods.Insert(index, m); } } for (i = 0; i < ids.Size(); i++) { CMyComPtr hasher; UString name; RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher)); if (!hasher) throw "Can't create hasher"; const COneMethodInfo &m = methods[i]; { CMyComPtr scp; hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { RINOK(m.SetCoderProps(scp, NULL)); } } UInt32 digestSize = hasher->GetDigestSize(); if (digestSize > k_HashCalc_DigestSize_Max) return E_NOTIMPL; CHasherState &h = Hashers.AddNew(); h.Hasher = hasher; h.Name = name; h.DigestSize = digestSize; for (int i = 0; i < k_HashCalc_NumGroups; i++) memset(h.Digests[i], 0, digestSize); } return S_OK; } void CHashBundle::InitForNewFile() { CurSize = 0; FOR_VECTOR (i, Hashers) { CHasherState &h = Hashers[i]; h.Hasher->Init(); memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize); } } void CHashBundle::Update(const void *data, UInt32 size) { CurSize += size; FOR_VECTOR (i, Hashers) Hashers[i].Hasher->Update(data, size); } void CHashBundle::SetSize(UInt64 size) { CurSize = size; } static void AddDigests(Byte *dest, const Byte *src, UInt32 size) { unsigned next = 0; for (UInt32 i = 0; i < size; i++) { next += (unsigned)dest[i] + (unsigned)src[i]; dest[i] = (Byte)next; next >>= 8; } } void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) { if (isDir) NumDirs++; else if (isAltStream) { NumAltStreams++; AltStreamsSize += CurSize; } else { NumFiles++; FilesSize += CurSize; } Byte pre[16]; memset(pre, 0, sizeof(pre)); if (isDir) pre[0] = 1; FOR_VECTOR (i, Hashers) { CHasherState &h = Hashers[i]; if (!isDir) { h.Hasher->Final(h.Digests[0]); if (!isAltStream) AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize); } h.Hasher->Init(); h.Hasher->Update(pre, sizeof(pre)); h.Hasher->Update(h.Digests[0], h.DigestSize); for (unsigned k = 0; k < path.Len(); k++) { wchar_t c = path[k]; Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; h.Hasher->Update(temp, 2); } Byte tempDigest[k_HashCalc_DigestSize_Max]; h.Hasher->Final(tempDigest); if (!isAltStream) AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize); AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize); } } HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, const CHashOptions &options, UString &errorInfo, IHashCallbackUI *callback) { CDirItems dirItems; UInt64 numErrors = 0; UInt64 totalBytes = 0; if (options.StdInMode) { CDirItem di; di.Size = (UInt64)(Int64)-1; di.Attrib = 0; di.MTime.dwLowDateTime = 0; di.MTime.dwHighDateTime = 0; di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } else { CEnumDirItemCallback_Hash enumCallback; enumCallback.Callback = callback; RINOK(callback->StartScanning()); dirItems.ScanAltStreams = options.AltStreamsMode; HRESULT res = EnumerateItems(censor, options.PathMode, UString(), dirItems, &enumCallback); totalBytes = dirItems.TotalSize; FOR_VECTOR (i, dirItems.ErrorPaths) { RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); } numErrors = dirItems.ErrorPaths.Size(); if (res != S_OK) { if (res != E_ABORT) errorInfo = L"Scanning error"; return res; } RINOK(callback->FinishScanning()); } unsigned i; CHashBundle hb; RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods)); hb.Init(); hb.NumErrors = numErrors; if (options.StdInMode) { RINOK(callback->SetNumFiles(1)); } else { RINOK(callback->SetTotal(totalBytes)); } const UInt32 kBufSize = 1 << 15; CHashMidBuf buf; if (!buf.Alloc(kBufSize)) return E_OUTOFMEMORY; UInt64 completeValue = 0; RINOK(callback->BeforeFirstFile(hb)); for (i = 0; i < dirItems.Items.Size(); i++) { CMyComPtr inStream; UString path; bool isDir = false; bool isAltStream = false; if (options.StdInMode) { inStream = new CStdInFileStream; } else { CInFileStream *inStreamSpec = new CInFileStream; inStream = inStreamSpec; const CDirItem &dirItem = dirItems.Items[i]; isDir = dirItem.IsDir(); isAltStream = dirItem.IsAltStream; path = dirItems.GetLogPath(i); if (!isDir) { UString phyPath = dirItems.GetPhyPath(i); if (!inStreamSpec->OpenShared(us2fs(phyPath), options.OpenShareForWrite)) { HRESULT res = callback->OpenFileError(phyPath, ::GetLastError()); hb.NumErrors++; if (res != S_FALSE) return res; continue; } } } RINOK(callback->GetStream(path, isDir)); UInt64 fileSize = 0; hb.InitForNewFile(); if (!isDir) { for (UInt32 step = 0;; step++) { if ((step & 0xFF) == 0) RINOK(callback->SetCompleted(&completeValue)); UInt32 size; RINOK(inStream->Read(buf, kBufSize, &size)); if (size == 0) break; hb.Update(buf, size); fileSize += size; completeValue += size; } } hb.Final(isDir, isAltStream, path); RINOK(callback->SetOperationResult(fileSize, hb, !isDir)); RINOK(callback->SetCompleted(&completeValue)); } return callback->AfterLastFile(hb); } static inline char GetHex(Byte value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } void AddHashHexToString(char *dest, const Byte *data, UInt32 size) { dest[size * 2] = 0; if (!data) { for (UInt32 i = 0; i < size; i++) { dest[0] = ' '; dest[1] = ' '; dest += 2; } return; } int step = 2; if (size <= 8) { step = -2; dest += size * 2 - 2; } for (UInt32 i = 0; i < size; i++) { Byte b = data[i]; dest[0] = GetHex((Byte)((b >> 4) & 0xF)); dest[1] = GetHex((Byte)(b & 0xF)); dest += step; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/HashCalc.h0100777000000000000000000000547213761647206023215 0ustar00// HashCalc.h #ifndef __HASH_CALC_H #define __HASH_CALC_H #include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" #include "../../Common/MethodProps.h" #include "Property.h" const unsigned k_HashCalc_DigestSize_Max = 64; const unsigned k_HashCalc_NumGroups = 4; enum { k_HashCalc_Index_Current, k_HashCalc_Index_DataSum, k_HashCalc_Index_NamesSum, k_HashCalc_Index_StreamsSum }; struct CHasherState { CMyComPtr Hasher; UString Name; UInt32 DigestSize; Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max]; }; struct IHashCalc { virtual void InitForNewFile() = 0; virtual void Update(const void *data, UInt32 size) = 0; virtual void SetSize(UInt64 size) = 0; virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0; }; struct CHashBundle: public IHashCalc { CObjectVector Hashers; UInt64 NumFiles; UInt64 NumDirs; UInt64 NumAltStreams; UInt64 FilesSize; UInt64 AltStreamsSize; UInt64 NumErrors; UInt64 CurSize; HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods); void Init() { NumFiles = NumDirs = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0; } void InitForNewFile(); void Update(const void *data, UInt32 size); void SetSize(UInt64 size); void Final(bool isDir, bool isAltStream, const UString &path); }; #define INTERFACE_IHashCallbackUI(x) \ virtual HRESULT StartScanning() x; \ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT FinishScanning() x; \ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ virtual HRESULT SetTotal(UInt64 size) x; \ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ virtual HRESULT CheckBreak() x; \ virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x; \ virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x; \ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \ virtual HRESULT AfterLastFile(const CHashBundle &hb) x; \ struct IHashCallbackUI { INTERFACE_IHashCallbackUI(=0) }; struct CHashOptions { UStringVector Methods; bool OpenShareForWrite; bool StdInMode; bool AltStreamsMode; NWildcard::ECensorPathMode PathMode; CHashOptions(): StdInMode(false), OpenShareForWrite(false), AltStreamsMode(false), PathMode(NWildcard::k_RelatPath) {}; }; HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, const CHashOptions &options, UString &errorInfo, IHashCallbackUI *callback); void AddHashHexToString(char *dest, const Byte *data, UInt32 size); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h0100777000000000000000000000424413761647206025503 0ustar00// IFileExtractCallback.h #ifndef __I_FILE_EXTRACT_CALLBACK_H #define __I_FILE_EXTRACT_CALLBACK_H #include "../../../Common/MyString.h" #include "../../IDecl.h" namespace NOverwriteAnswer { enum EEnum { kYes, kYesToAll, kNo, kNoToAll, kAutoRename, kCancel }; } DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07) { public: STDMETHOD(AskOverwrite)( const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, Int32 *answer) PURE; STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE; STDMETHOD(MessageError)(const wchar_t *message) PURE; STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE; }; struct IExtractCallbackUI: IFolderArchiveExtractCallback { virtual HRESULT BeforeOpen(const wchar_t *name) = 0; virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0; virtual HRESULT SetError(int level, const wchar_t *name, UInt32 errorFlags, const wchar_t *errors, UInt32 warningFlags, const wchar_t *warnings) = 0; virtual HRESULT ThereAreNoFiles() = 0; virtual HRESULT ExtractResult(HRESULT result) = 0; virtual HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType) = 0; #ifndef _NO_CRYPTO virtual HRESULT SetPassword(const UString &password) = 0; #endif }; #define INTERFACE_IGetProp(x) \ STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \ DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20) { INTERFACE_IGetProp(PURE) }; #define INTERFACE_IFolderExtractToStreamCallback(x) \ STDMETHOD(UseExtractToStream)(Int32 *res) x; \ STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \ STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \ STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, bool encrypted) x; \ DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30) { INTERFACE_IFolderExtractToStreamCallback(PURE) }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp0100777000000000000000000005274113761647206024103 0ustar00// LoadCodecs.cpp #include "StdAfx.h" #include "../../../../C/7zVersion.h" #include "../../../Common/MyCom.h" #include "../../../Common/StringToInt.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" #include "LoadCodecs.h" using namespace NWindows; #ifdef NEW_FOLDER_INTERFACE #include "../../../Common/StringToInt.h" #endif #include "../../ICoder.h" #include "../../Common/RegisterArc.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/FileFind.h" #include "../../../Windows/DLL.h" #ifdef NEW_FOLDER_INTERFACE #include "../../../Windows/ResourceString.h" static const UINT kIconTypesResId = 100; #endif #ifdef _WIN32 #include "../../../Windows/FileName.h" #include "../../../Windows/Registry.h" #endif using namespace NFile; #ifdef _WIN32 extern HINSTANCE g_hInstance; #endif #define kCodecsFolderName FTEXT("Codecs") #define kFormatsFolderName FTEXT("Formats") static CFSTR kMainDll = FTEXT("7z.dll"); #ifdef _WIN32 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); static LPCWSTR kProgramPathValue = L"Path"; static LPCWSTR kProgramPath2Value = L"Path" #ifdef _WIN64 L"64"; #else L"32"; #endif static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) { NRegistry::CKey key; if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) { UString pathU; if (key.QueryValue(value, pathU) == ERROR_SUCCESS) { path = us2fs(pathU); NName::NormalizeDirPathPrefix(path); return NFind::DoesFileExist(path + kMainDll); } } return false; } #endif // _WIN32 #endif // EXTERNAL_CODECS static const unsigned kNumArcsMax = 48; static unsigned g_NumArcs = 0; static const CArcInfo *g_Arcs[kNumArcsMax]; void RegisterArc(const CArcInfo *arcInfo) throw() { if (g_NumArcs < kNumArcsMax) { g_Arcs[g_NumArcs] = arcInfo; g_NumArcs++; } } static void SplitString(const UString &srcString, UStringVector &destStrings) { destStrings.Clear(); UString s; unsigned len = srcString.Len(); if (len == 0) return; for (unsigned i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L' ') { if (!s.IsEmpty()) { destStrings.Add(s); s.Empty(); } } else s += c; } if (!s.IsEmpty()) destStrings.Add(s); } int CArcInfoEx::FindExtension(const UString &ext) const { FOR_VECTOR (i, Exts) if (ext.IsEqualToNoCase(Exts[i].Ext)) return i; return -1; } void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) { UStringVector exts, addExts; SplitString(ext, exts); SplitString(addExt, addExts); FOR_VECTOR (i, exts) { CArcExtInfo extInfo; extInfo.Ext = exts[i]; if (i < addExts.Size()) { extInfo.AddExt = addExts[i]; if (extInfo.AddExt == L"*") extInfo.AddExt.Empty(); } Exts.Add(extInfo); } } #ifndef _SFX static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector &signatures) { signatures.Clear(); while (size > 0) { unsigned len = *data++; size--; if (len > size) return false; signatures.AddNew().CopyFrom(data, len); data += len; size -= len; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS static FString GetBaseFolderPrefixFromRegistry() { FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); #ifdef _WIN32 if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) && !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) && !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName)) { FString path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; } #endif return moduleFolderPrefix; } static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, PROPID propId, CLSID &clsId, bool &isAssigned) { NCOM::CPropVariant prop; isAssigned = false; RINOK(getMethodProperty(index, propId, &prop)); if (prop.vt == VT_BSTR) { if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; isAssigned = true; clsId = *(const GUID *)prop.bstrVal; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT CCodecs::LoadCodecs() { CCodecLib &lib = Libs.Back(); lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty"); if (lib.GetMethodProperty) { UInt32 numMethods = 1; Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods"); if (getNumberOfMethodsFunc) { RINOK(getNumberOfMethodsFunc(&numMethods)); } for (UInt32 i = 0; i < numMethods; i++) { CDllCodecInfo info; info.LibIndex = Libs.Size() - 1; info.CodecIndex = i; RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)); RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)); Codecs.Add(info); } } Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers"); if (getHashers) { RINOK(getHashers(&lib.Hashers)); if (lib.Hashers) { UInt32 numMethods = lib.Hashers->GetNumHashers(); for (UInt32 i = 0; i < numMethods; i++) { CDllHasherInfo info; info.LibIndex = Libs.Size() - 1; info.HasherIndex = i; Hashers.Add(info); } } } return S_OK; } static HRESULT GetProp( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, NCOM::CPropVariant &prop) { if (getProp2) return getProp2(index, propID, &prop);; return getProp(propID, &prop); } static HRESULT GetProp_Bool( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, bool &res) { res = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BOOL) res = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_UInt32( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UInt32 &res, bool &defined) { res = 0; defined = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_UI4) { res = prop.ulVal; defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_String( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UString &res) { res.Empty(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) res = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_RawData( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, CByteBuffer &bb) { bb.Free(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) { UINT len = ::SysStringByteLen(prop.bstrVal); bb.CopyFrom((const Byte *)prop.bstrVal, len); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static const UInt32 kArcFlagsPars[] = { NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure }; HRESULT CCodecs::LoadFormats() { const NDLL::CLibrary &lib = Libs.Back().Lib; Func_GetHandlerProperty getProp = NULL; Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2"); Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc"); UInt32 numFormats = 1; if (getProp2) { Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats"); if (getNumberOfFormats) { RINOK(getNumberOfFormats(&numFormats)); } } else { getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty"); if (!getProp) return S_OK; } for (UInt32 i = 0; i < numFormats; i++) { CArcInfoEx item; item.LibIndex = Libs.Size() - 1; item.FormatIndex = i; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)); { NCOM::CPropVariant prop; if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) continue; if (prop.vt != VT_BSTR) continue; if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; item.ClassID = *(const GUID *)prop.bstrVal; prop.Clear(); } UString ext, addExt; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)); RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)); item.AddExts(ext, addExt); GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); bool flags_Defined = false; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)); item.NewInterface = flags_Defined; if (!flags_Defined) // && item.UpdateEnabled { // support for DLL version before 9.31: for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2) { bool val = false; GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); if (val) item.Flags |= kArcFlagsPars[j + 1]; } } CByteBuffer sig; RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); if (sig.Size() != 0) item.Signatures.Add(sig); else { RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)); ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); } bool signatureOffset_Defined; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)); // bool version_Defined; // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); if (getIsArc) getIsArc(i, &item.IsArcFunc); Formats.Add(item); } return S_OK; } #ifdef NEW_FOLDER_INTERFACE void CCodecIcons::LoadIcons(HMODULE m) { UString iconTypes; MyLoadString(m, kIconTypesResId, iconTypes); UStringVector pairs; SplitString(iconTypes, pairs); FOR_VECTOR (i, pairs) { const UString &s = pairs[i]; int pos = s.Find(L':'); CIconPair iconPair; iconPair.IconIndex = -1; if (pos < 0) pos = s.Len(); else { UString num = s.Ptr(pos + 1); if (!num.IsEmpty()) { const wchar_t *end; iconPair.IconIndex = ConvertStringToUInt32(num, &end); if (*end != 0) continue; } } iconPair.Ext = s.Left(pos); IconPairs.Add(iconPair); } } bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const { iconIndex = -1; FOR_VECTOR (i, IconPairs) { const CIconPair &pair = IconPairs[i]; if (ext.IsEqualToNoCase(pair.Ext)) { iconIndex = pair.IconIndex; return true; } } return false; } #endif // EXTERNAL_CODECS #ifdef _7ZIP_LARGE_PAGES extern "C" { extern SIZE_T g_LargePageSize; } #endif HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll) { if (needCheckDll) { NDLL::CLibrary library; if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) return S_OK; } Libs.Add(CCodecLib()); CCodecLib &lib = Libs.Back(); lib.Path = dllPath; bool used = false; HRESULT res = S_OK; if (lib.Lib.Load(dllPath)) { #ifdef NEW_FOLDER_INTERFACE lib.LoadIcons(); #endif #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0) { Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode"); if (setLargePageMode) setLargePageMode(); } #endif if (CaseSensitiveChange) { Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive"); if (setCaseSensitive) setCaseSensitive(CaseSensitive ? 1 : 0); } lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject"); if (lib.CreateObject) { unsigned startSize = Codecs.Size() + Hashers.Size(); res = LoadCodecs(); used = (startSize != Codecs.Size() + Hashers.Size()); if (res == S_OK) { startSize = Formats.Size(); res = LoadFormats(); if (startSize != Formats.Size()) used = true; } } } if (!used) Libs.DeleteBack(); return res; } HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix) { NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK); NFile::NFind::CFileInfo fi; while (enumerator.Next(fi)) { if (fi.IsDir()) continue; RINOK(LoadDll(folderPrefix + fi.Name, true)); } return S_OK; } #endif HRESULT CCodecs::Load() { #ifdef NEW_FOLDER_INTERFACE InternalIcons.LoadIcons(g_hInstance); #endif Formats.Clear(); #ifdef EXTERNAL_CODECS Codecs.Clear(); Hashers.Clear(); #endif for (UInt32 i = 0; i < g_NumArcs; i++) { const CArcInfo &arc = *g_Arcs[i]; CArcInfoEx item; item.Name.SetFromAscii(arc.Name); item.CreateInArchive = arc.CreateInArchive; item.IsArcFunc = arc.IsArc; item.Flags = arc.Flags; { UString e, ae; if (arc.Ext) e.SetFromAscii(arc.Ext); if (arc.AddExt) ae.SetFromAscii(arc.AddExt); item.AddExts(e, ae); } #ifndef _SFX item.CreateOutArchive = arc.CreateOutArchive; item.UpdateEnabled = (arc.CreateOutArchive != NULL); item.SignatureOffset = arc.SignatureOffset; // item.Version = MY_VER_MIX; item.NewInterface = true; if (arc.IsMultiSignature()) ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); else item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); #endif Formats.Add(item); } #ifdef EXTERNAL_CODECS const FString baseFolder = GetBaseFolderPrefixFromRegistry(); RINOK(LoadDll(baseFolder + kMainDll, false)); RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR)); RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR)); #endif return S_OK; } #ifndef _SFX int CCodecs::FindFormatForArchiveName(const UString &arcPath) const { int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR); int dotPos = arcPath.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos) return -1; const UString ext = arcPath.Ptr(dotPos + 1); if (ext.IsEmpty()) return -1; if (ext.IsEqualToNoCase(L"exe")) return -1; FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; /* if (!arc.UpdateEnabled) continue; */ if (arc.FindExtension(ext) >= 0) return i; } return -1; } int CCodecs::FindFormatForExtension(const UString &ext) const { if (ext.IsEmpty()) return -1; FOR_VECTOR (i, Formats) if (Formats[i].FindExtension(ext) >= 0) return i; return -1; } int CCodecs::FindFormatForArchiveType(const UString &arcType) const { FOR_VECTOR (i, Formats) if (Formats[i].Name.IsEqualToNoCase(arcType)) return i; return -1; } bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const { formatIndices.Clear(); for (unsigned pos = 0; pos < arcType.Len();) { int pos2 = arcType.Find('.', pos); if (pos2 < 0) pos2 = arcType.Len(); const UString name = arcType.Mid(pos, pos2 - pos); if (name.IsEmpty()) return false; int index = FindFormatForArchiveType(name); if (index < 0 && name != L"*") { formatIndices.Clear(); return false; } formatIndices.Add(index); pos = pos2 + 1; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS // #define EXPORT_CODECS #ifdef EXPORT_CODECS extern unsigned g_NumCodecs; STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject); STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_CODECS g_NumCodecs extern unsigned g_NumHashers; STDAPI CreateHasher(UInt32 index, IHasher **hasher); STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_HASHERS g_NumHashers #else // EXPORT_CODECS #define NUM_EXPORT_CODECS 0 #define NUM_EXPORT_HASHERS 0 #endif // EXPORT_CODECS STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods) { *numMethods = NUM_EXPORT_CODECS #ifdef EXTERNAL_CODECS + Codecs.Size() #endif ; return S_OK; } STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return GetMethodProperty(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (propID == NMethodPropID::kDecoderIsAssigned || propID == NMethodPropID::kEncoderIsAssigned) { NCOM::CPropVariant prop; prop = (propID == NMethodPropID::kDecoderIsAssigned) ? ci.DecoderIsAssigned : ci.EncoderIsAssigned; prop.Detach(value); return S_OK; } return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(false, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.DecoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(true, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.EncoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP_(UInt32) CCodecs::GetNumHashers() { return NUM_EXPORT_HASHERS #ifdef EXTERNAL_CODECS + Hashers.Size() #endif ; } STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return ::GetHasherProp(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->GetHasherProp(ci.HasherIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return CreateHasher(index, hasher); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->CreateHasher(ci.HasherIndex, hasher); #else return E_FAIL; #endif } int CCodecs::GetCodecLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return -1; #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.LibIndex; #else return -1; #endif } int CCodecs::GetHasherLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return -1; #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return ci.LibIndex; #else return -1; #endif } bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) { NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK) if (prop.vt != VT_EMPTY) return true; return false; } #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.EncoderIsAssigned; #else return false; #endif } HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id) { NCOM::CPropVariant prop; RINOK(GetProperty(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; id = prop.uhVal.QuadPart; return S_OK; } UString CCodecs::GetCodecName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt64 CCodecs::GetHasherId(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return 0; return prop.uhVal.QuadPart; } UString CCodecs::GetHasherName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt32 CCodecs::GetHasherDigestSize(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop)); if (prop.vt != VT_UI4) return 0; return prop.ulVal; } #endif // EXTERNAL_CODECS qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h0100777000000000000000000001623213761647206023543 0ustar00// LoadCodecs.h #ifndef __LOAD_CODECS_H #define __LOAD_CODECS_H #include "../../../Common/MyBuffer.h" #include "../../../Common/MyCom.h" #include "../../../Common/MyString.h" #include "../../../Common/ComTry.h" #include "../../ICoder.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/DLL.h" #endif struct CDllCodecInfo { CLSID Encoder; CLSID Decoder; bool EncoderIsAssigned; bool DecoderIsAssigned; int LibIndex; UInt32 CodecIndex; }; struct CDllHasherInfo { int LibIndex; UInt32 HasherIndex; }; #include "../../Archive/IArchive.h" struct CArcExtInfo { UString Ext; UString AddExt; CArcExtInfo() {} CArcExtInfo(const UString &ext): Ext(ext) {} CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} }; struct CArcInfoEx { UInt32 Flags; Func_CreateInArchive CreateInArchive; Func_IsArc IsArcFunc; UString Name; CObjectVector Exts; #ifndef _SFX Func_CreateOutArchive CreateOutArchive; bool UpdateEnabled; bool NewInterface; // UInt32 Version; UInt32 SignatureOffset; CObjectVector Signatures; #ifdef NEW_FOLDER_INTERFACE UStringVector AssociateExts; #endif #endif #ifdef EXTERNAL_CODECS int LibIndex; UInt32 FormatIndex; CLSID ClassID; #endif bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } UString GetMainExt() const { if (Exts.IsEmpty()) return UString(); return Exts[0].Ext; } int FindExtension(const UString &ext) const; /* UString GetAllExtensions() const { UString s; for (int i = 0; i < Exts.Size(); i++) { if (i > 0) s += ' '; s += Exts[i].Ext; } return s; } */ void AddExts(const UString &ext, const UString &addExt); bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); } // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); } CArcInfoEx(): Flags(0), CreateInArchive(NULL), IsArcFunc(NULL) #ifndef _SFX , CreateOutArchive(NULL) , UpdateEnabled(false) , NewInterface(false) // , Version(0) , SignatureOffset(0) #endif #ifdef EXTERNAL_CODECS , LibIndex(-1) #endif {} }; #ifdef EXTERNAL_CODECS #ifdef NEW_FOLDER_INTERFACE struct CCodecIcons { struct CIconPair { UString Ext; int IconIndex; }; CObjectVector IconPairs; void LoadIcons(HMODULE m); bool FindIconIndex(const UString &ext, int &iconIndex) const; }; #endif struct CCodecLib #ifdef NEW_FOLDER_INTERFACE : public CCodecIcons #endif { NWindows::NDLL::CLibrary Lib; FString Path; Func_GetMethodProperty GetMethodProperty; Func_CreateObject CreateObject; CMyComPtr Hashers; #ifdef NEW_FOLDER_INTERFACE void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); } #endif CCodecLib(): GetMethodProperty(NULL) {} }; #endif class CCodecs: #ifdef EXTERNAL_CODECS public ICompressCodecsInfo, public IHashers, #else public IUnknown, #endif public CMyUnknownImp { public: #ifdef EXTERNAL_CODECS CObjectVector Libs; CRecordVector Codecs; CRecordVector Hashers; #ifdef NEW_FOLDER_INTERFACE CCodecIcons InternalIcons; #endif HRESULT LoadCodecs(); HRESULT LoadFormats(); HRESULT LoadDll(const FString &path, bool needCheckDll); HRESULT LoadDllsFromFolder(const FString &folderPrefix); HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const { return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); } #endif public: CObjectVector Formats; bool CaseSensitiveChange; bool CaseSensitive; CCodecs(): CaseSensitiveChange(false), CaseSensitive(false) {} const wchar_t *GetFormatNamePtr(int formatIndex) { return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name; } HRESULT Load(); #ifndef _SFX int FindFormatForArchiveName(const UString &arcPath) const; int FindFormatForExtension(const UString &ext) const; int FindFormatForArchiveType(const UString &arcType) const; bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; #endif #ifdef EXTERNAL_CODECS MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers) STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods); STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder); STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, void **coder); STDMETHOD_(UInt32, GetNumHashers)(); STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher); #else MY_UNKNOWN_IMP #endif // EXTERNAL_CODECS #ifdef EXTERNAL_CODECS int GetCodecLibIndex(UInt32 index); bool GetCodecEncoderIsAssigned(UInt32 index); HRESULT GetCodecId(UInt32 index, UInt64 &id); UString GetCodecName(UInt32 index); int GetHasherLibIndex(UInt32 index); UInt64 GetHasherId(UInt32 index); UString GetHasherName(UInt32 index); UInt32 GetHasherDigestSize(UInt32 index); #endif HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateInArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, (void **)&archive, false); #endif } #ifndef _SFX HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateOutArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, (void **)&archive, true); #endif } int FindOutFormatFromName(const UString &name) const { FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; if (!arc.UpdateEnabled) continue; if (arc.Name.IsEqualToNoCase(name)) return i; } return -1; } #endif // _SFX }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp0100777000000000000000000023772213761647206024312 0ustar00// OpenArchive.cpp #include "StdAfx.h" // #define SHOW_DEBUG_INFO #ifdef SHOW_DEBUG_INFO #include #endif #include "../../../../C/CpuArch.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../Common/FileStreams.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" #include "DefaultName.h" #include "OpenArchive.h" #ifndef _SFX #include "SetProperties.h" #endif #ifdef SHOW_DEBUG_INFO #define PRF(x) x #else #define PRF(x) #endif // increase it, if you need to support larger SFX stubs static const UInt64 kMaxCheckStartPosition = 1 << 22; /* Open: - formatIndex >= 0 (exact Format) 1) Open with main type. Archive handler is allowed to use archive start finder. Warning, if there is tail. - formatIndex = -1 (Parser:0) (default) - same as #1 but doesn't return Parser - formatIndex = -2 (#1) - file has supported extension (like a.7z) Open with that main type (only starting from start of file). - open OK: - if there is no tail - return OK - if there is tail: - archive is not "Self Exe" - return OK with Warning, that there is tail - archive is "Self Exe" ignore "Self Exe" stub, and tries to open tail - tail can be open as archive - shows that archive and stub size property. - tail can't be open as archive - shows Parser ??? - open FAIL: Try to open with all other types from offset 0 only. If some open type is OK and physical archive size is uequal or larger than file size, then return that archive with warning that can not be open as [extension type]. If extension was EXE, it will try to open as unknown_extension case - file has unknown extension (like a.hhh) It tries to open via parser code. - if there is full archive or tail archive and unknown block or "Self Exe" at front, it shows tail archive and stub size property. - in another cases, if there is some archive inside file, it returns parser/ - in another cases, it retuens S_FALSE - formatIndex = -3 (#2) - same as #1, but - stub (EXE) + archive is open in Parser - formatIndex = -4 (#3) - returns only Parser. skip full file archive. And show other sub-archives - formatIndex = -5 (#4) - returns only Parser. skip full file archive. And show other sub-archives for each byte pos */ using namespace NWindows; /* #ifdef _SFX #define OPEN_PROPS_PARAM #else #define OPEN_PROPS_PARAM , props #endif */ /* CArc::~CArc() { GetRawProps.Release(); Archive.Release(); printf("\nCArc::~CArc()\n"); } */ #ifndef _SFX namespace NArchive { namespace NParser { struct CParseItem { UInt64 Offset; UInt64 Size; // UInt64 OkSize; UString Name; UString Extension; FILETIME FileTime; UString Comment; UString ArcType; bool FileTime_Defined; bool UnpackSize_Defined; bool NumSubDirs_Defined; bool NumSubFiles_Defined; bool IsSelfExe; bool IsNotArcType; UInt64 UnpackSize; UInt64 NumSubDirs; UInt64 NumSubFiles; int FormatIndex; bool LenIsUnknown; CParseItem(): LenIsUnknown(false), FileTime_Defined(false), UnpackSize_Defined(false), NumSubFiles_Defined(false), NumSubDirs_Defined(false), IsSelfExe(false), IsNotArcType(false) // OkSize(0) {} /* bool IsEqualTo(const CParseItem &item) const { return Offset == item.Offset && Size == item.Size; } */ void NormalizeOffset() { if ((Int64)Offset < 0) { Size += Offset; // OkSize += Offset; Offset = 0; } } }; class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { public: CObjectVector _items; UInt64 _maxEndOffset; CMyComPtr _stream; MY_UNKNOWN_IMP2( IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); UInt64 GetLastEnd() const { if (_items.IsEmpty()) return 0; const CParseItem &back = _items.Back(); return back.Offset + back.Size; } void AddUnknownItem(UInt64 next); int FindInsertPos(const CParseItem &item); void AddItem(const CParseItem &item); // void Init(); CHandler() { _maxEndOffset = 0; } }; int CHandler::FindInsertPos(const CParseItem &item) { unsigned left = 0, right = _items.Size(); while (left != right) { unsigned mid = (left + right) / 2; const CParseItem & midItem = _items[mid]; if (item.Offset < midItem.Offset) right = mid; else if (item.Offset > midItem.Offset) left = mid + 1; else if (item.Size < midItem.Size) right = mid; else if (item.Size > midItem.Size) left = mid + 1; else { left = mid + 1; // return -1; } } return left; } void CHandler::AddUnknownItem(UInt64 next) { /* UInt64 prevEnd = 0; if (!_items.IsEmpty()) { const CParseItem &back = _items.Back(); prevEnd = back.Offset + back.Size; } */ if (_maxEndOffset < next) { CParseItem item2; item2.Offset = _maxEndOffset; item2.Size = next - _maxEndOffset; _maxEndOffset = next; _items.Add(item2); } else if (_maxEndOffset > next && !_items.IsEmpty()) { CParseItem &back = _items.Back(); if (back.LenIsUnknown) { back.Size = next - back.Offset; _maxEndOffset = next; } } } void CHandler::AddItem(const CParseItem &item) { AddUnknownItem(item.Offset); int pos = FindInsertPos(item); if (pos >= 0) { _items.Insert(pos, item); UInt64 next = item.Offset + item.Size; if (_maxEndOffset < next) _maxEndOffset = next; } } /* static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidSize, VT_UI8}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidType, VT_BSTR}, { NULL, kpidComment, VT_BSTR}, { NULL, kpidOffset, VT_UI8}, { NULL, kpidUnpackSize, VT_UI8}, // { NULL, kpidNumSubDirs, VT_UI8}, }; */ static const Byte kProps[] = { kpidPath, kpidSize, kpidMTime, kpidType, kpidComment, kpidOffset, kpidUnpackSize }; IMP_IInArchive_Props IMP_IInArchive_ArcProps_NO STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */) { COM_TRY_BEGIN { Close(); _stream = stream; } return S_OK; COM_TRY_END } STDMETHODIMP CHandler::Close() { _items.Clear(); _stream.Release(); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _items.Size(); return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; const CParseItem &item = _items[index]; switch (propID) { case kpidPath: { wchar_t sz[32]; ConvertUInt32ToString(index + 1, sz); UString s = sz; if (!item.Name.IsEmpty()) { s += L'.'; s += item.Name; } if (!item.Extension.IsEmpty()) { s += L'.'; s += item.Extension; } prop = s; break; } case kpidSize: case kpidPackSize: prop = item.Size; break; case kpidOffset: prop = item.Offset; break; case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; } prop.Detach(value); return S_OK; COM_TRY_END } HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (_stream && numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) totalSize += _items[allFilesMode ? i : indices[i]].Size; extractCallback->SetTotal(totalSize); totalSize = 0; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr inStream(streamSpec); streamSpec->SetStream(_stream); CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; CMyComPtr outStream(outStreamSpec); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr copyCoder = copyCoderSpec; for (i = 0; i < numItems; i++) { lps->InSize = totalSize; lps->OutSize = totalSize; RINOK(lps->SetCur()); CMyComPtr realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; Int32 index = allFilesMode ? i : indices[i]; const CParseItem &item = _items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); UInt64 unpackSize = item.Size; totalSize += unpackSize; bool skipMode = false; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); outStreamSpec->SetStream(realOutStream); realOutStream.Release(); outStreamSpec->Init(skipMode ? 0 : unpackSize, true); Int32 opRes = NExtract::NOperationResult::kOK; RINOK(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(unpackSize); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); if (outStreamSpec->GetRem() != 0) opRes = NExtract::NOperationResult::kDataError; outStreamSpec->ReleaseStream(); RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN const CParseItem &item = _items[index]; return CreateLimitedInStream(_stream, item.Offset, item.Size, stream); COM_TRY_END } }} #endif HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw() { NCOM::CPropVariant prop; result = false; RINOK(arc->GetProperty(index, propID, &prop)); if (prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsDir, result); } HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsAux, result); } HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result); } HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw() { return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); } static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) { NCOM::CPropVariant prop; result = false; RINOK(arc->GetArchiveProperty(propid, &prop)); if (prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined) { defined = false; NCOM::CPropVariant prop; RINOK(arc->GetArchiveProperty(propid, &prop)); switch (prop.vt) { case VT_UI4: result = prop.ulVal; defined = true; break; case VT_I4: result = prop.lVal; defined = true; break; case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break; case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break; case VT_EMPTY: break; default: return E_FAIL; } return S_OK; } static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined) { defined = false; NCOM::CPropVariant prop; RINOK(arc->GetArchiveProperty(propid, &prop)); switch (prop.vt) { case VT_UI4: result = prop.ulVal; defined = true; break; case VT_I4: result = prop.lVal; defined = true; break; case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break; case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break; case VT_EMPTY: break; default: return E_FAIL; } return S_OK; } HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const { if (!GetRawProps) return E_FAIL; UInt32 curIndex = index; bool prevWasAltStream = false; for (;;) { UString s; #ifdef MY_CPU_LE const void *p; UInt32 size; UInt32 propType; RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)); if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) s = (const wchar_t *)p; else #endif { NCOM::CPropVariant prop; RINOK(Archive->GetProperty(curIndex, kpidName, &prop)); if (prop.vt == VT_BSTR) s = prop.bstrVal; else if (prop.vt == VT_EMPTY) s = L"[Content]"; else return E_FAIL; } if (prevWasAltStream) parts[0] = s + L":" + parts[0]; else parts.Insert(0, s); UInt32 curParent = (UInt32)(Int32)-1; UInt32 parentType = 0; RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)); if (parent == curParent) return S_OK; if (curParent == (UInt32)(Int32)-1) return E_FAIL; prevWasAltStream = (parentType == NParentType::kAltStream); curIndex = curParent; } } HRESULT CArc::GetItemPath(UInt32 index, UString &result) const { #ifdef MY_CPU_LE if (GetRawProps) { const void *p; UInt32 size; UInt32 propType; if (!IsTree) { if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK && propType == NPropDataType::kUtf16z) { unsigned len = size / 2 - 1; wchar_t *s = result.GetBuffer(len); for (unsigned i = 0; i < len; i++) { wchar_t c = GetUi16(p); p = (const void *)((const Byte *)p + 2); #if WCHAR_PATH_SEPARATOR != L'/' if (c == L'/') c = WCHAR_PATH_SEPARATOR; #endif *s++ = c; } result.ReleaseBuffer(len); if (len != 0) return S_OK; } } /* else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK && p && propType == NPropDataType::kUtf16z) { UInt32 totalSize = size; bool isOK = false; { UInt32 index2 = index; for (;;) { UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) break; if (parent == (UInt32)(Int32)-1) { isOK = true; break; } index2 = parent; UInt32 size2; const void *p2; if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) break; totalSize += size2; } } if (isOK) { wchar_t *sz = result.GetBuffer(totalSize / 2); UInt32 pos = totalSize - size; memcpy((Byte *)sz + pos, p, size - 2); UInt32 index2 = index; for (;;) { UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) break; if (parent == (UInt32)(Int32)-1) break; index2 = parent; UInt32 size2; const void *p2; if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) break; pos -= size2; memcpy((Byte *)sz + pos, p2, size2); sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':'; } result.ReleaseBuffer((totalSize - 2) / 2); #ifdef _WIN32 // result.Replace(L'/', WCHAR_PATH_SEPARATOR); #endif return S_OK; } } */ } #endif { NCOM::CPropVariant prop; RINOK(Archive->GetProperty(index, kpidPath, &prop)); if (prop.vt == VT_BSTR) result = prop.bstrVal; else if (prop.vt == VT_EMPTY) result.Empty(); else return E_FAIL; } if (result.IsEmpty()) { result = DefaultName; NCOM::CPropVariant prop; RINOK(Archive->GetProperty(index, kpidExtension, &prop)); if (prop.vt == VT_BSTR) { result += L'.'; result += prop.bstrVal; } else if (prop.vt != VT_EMPTY) return E_FAIL; } return S_OK; } HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const { RINOK(GetItemPath(index, result)); if (Ask_Deleted) { bool isDeleted = false; RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted)); if (isDeleted) result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR); } return S_OK; } #ifndef _SFX static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined) { NCOM::CPropVariant prop; defined = false; size = 0; RINOK(archive->GetProperty(index, kpidSize, &prop)); switch (prop.vt) { case VT_UI1: size = prop.bVal; break; case VT_UI2: size = prop.uiVal; break; case VT_UI4: size = prop.ulVal; break; case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; case VT_EMPTY: return S_OK; default: return E_FAIL; } defined = true; return S_OK; } #endif HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const { NCOM::CPropVariant prop; defined = false; size = 0; RINOK(Archive->GetProperty(index, kpidSize, &prop)); switch (prop.vt) { case VT_UI1: size = prop.bVal; break; case VT_UI2: size = prop.uiVal; break; case VT_UI4: size = prop.ulVal; break; case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; case VT_EMPTY: return S_OK; default: return E_FAIL; } defined = true; return S_OK; } HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const { NCOM::CPropVariant prop; defined = false; ft.dwHighDateTime = ft.dwLowDateTime = 0; RINOK(Archive->GetProperty(index, kpidMTime, &prop)); if (prop.vt == VT_FILETIME) { ft = prop.filetime; defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; else if (MTimeDefined) { ft = MTime; defined = true; } return S_OK; } #ifndef _SFX static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size) { for (size_t i = 0; i < size; i++) if (p1[i] != p2[i]) return false; return true; } static void MakeCheckOrder(CCodecs *codecs, CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, const Byte *data, size_t dataSize) { for (unsigned i = 0; i < numTypes; i++) { int index = orderIndices[i]; if (index < 0) continue; const CArcInfoEx &ai = codecs->Formats[index]; if (ai.SignatureOffset != 0) { orderIndices2.Add(index); orderIndices[i] = -1; continue; } const CObjectVector &sigs = ai.Signatures; FOR_VECTOR (k, sigs) { const CByteBuffer &sig = sigs[k]; if (sig.Size() == 0 && dataSize == 0 || sig.Size() != 0 && sig.Size() <= dataSize && TestSignature(data, sig, sig.Size())) { orderIndices2.Add(index); orderIndices[i] = -1; break; } } } } #endif #ifdef UNDER_CE static const unsigned kNumHashBytes = 1; #define HASH_VAL(buf, pos) ((buf)[pos]) #else static const unsigned kNumHashBytes = 2; #define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8)) #endif #ifndef _SFX static bool IsExeExt(const UString &ext) { return ext.IsEqualToNoCase(L"exe"); } static const char *k_PreArcFormats[] = { "pe" , "elf" , "macho" , "mub" , "te" }; static bool IsNameFromList(const UString &s, const char *names[], size_t num) { for (unsigned i = 0; i < num; i++) if (StringsAreEqualNoCase_Ascii(s, names[i])) return true; return false; } static bool IsPreArcFormat(const CArcInfoEx &ai) { if (ai.Flags_PreArc()) return true; return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats)); } static const char *k_Formats_with_simple_signuature[] = { "7z" , "xz" , "rar" , "bzip2" , "gzip" , "cab" , "wim" , "rpm" , "vhd" , "xar" }; static bool IsNewStyleSignature(const CArcInfoEx &ai) { // if (ai.Version >= 0x91F) if (ai.NewInterface) return true; return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature)); } class CArchiveOpenCallback_Offset: public IArchiveOpenCallback, #ifndef _NO_CRYPTO public ICryptoGetTextPassword, #endif public CMyUnknownImp { public: CMyComPtr Callback; UInt64 Files; UInt64 Offset; #ifndef _NO_CRYPTO CMyComPtr GetTextPassword; MY_UNKNOWN_IMP2( IArchiveOpenCallback, ICryptoGetTextPassword) #else MY_UNKNOWN_IMP1(IArchiveOpenCallback) #endif STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); #ifndef _NO_CRYPTO STDMETHOD(CryptoGetTextPassword)(BSTR *password); #endif }; #ifndef _NO_CRYPTO STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN if (GetTextPassword) return GetTextPassword->CryptoGetTextPassword(password); return E_NOTIMPL; COM_TRY_END } #endif STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) { return S_OK; } STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 * /* files */, const UInt64 *bytes) { if (!Callback) return S_OK; UInt64 value = Offset; if (bytes) value += *bytes; return Callback->SetCompleted(&Files, &value); } #endif UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) { if (isDefinedProp != NULL) *isDefinedProp = false; switch (prop.vt) { case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; case VT_EMPTY: return 0; default: throw 151199; } } void CArcErrorInfo::ClearErrors() { // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! ThereIsTail = false; UnexpecedEnd = false; IgnoreTail = false; // NonZerosTail = false; ErrorFlags_Defined = false; ErrorFlags = 0; WarningFlags = 0; TailSize = 0; ErrorMessage.Empty(); WarningMessage.Empty(); } HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) { // OkPhySize_Defined = false; PhySizeDefined = false; PhySize = 0; Offset = 0; AvailPhySize = FileSize - startPos; ErrorInfo.ClearErrors(); { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)); ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)); ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidError, &prop)); if (prop.vt != VT_EMPTY) ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidWarning, &prop)); if (prop.vt != VT_EMPTY) ErrorInfo.WarningMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown warning"; } if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) { RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); /* RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); if (!OkPhySize_Defined) { OkPhySize_Defined = PhySizeDefined; OkPhySize = PhySize; } */ bool offsetDefined; RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)); Int64 globalOffset = startPos + Offset; AvailPhySize = FileSize - globalOffset; if (PhySizeDefined) { UInt64 endPos = globalOffset + PhySize; if (endPos < FileSize) { AvailPhySize = PhySize; ErrorInfo.ThereIsTail = true; ErrorInfo.TailSize = FileSize - endPos; } else if (endPos > FileSize) ErrorInfo.UnexpecedEnd = true; } } return S_OK; } /* static PrintNumber(const char *s, int n) { char temp[100]; sprintf(temp, "%s %d", s, n); OutputDebugStringA(temp); } */ HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive) { // OutputDebugStringW(L"a1"); // PrintNumber("formatIndex", formatIndex); RINOK(op.codecs->CreateInArchive(formatIndex, archive)); // OutputDebugStringW(L"a2"); if (!archive) return S_OK; #ifdef EXTERNAL_CODECS { CMyComPtr setCompressCodecsInfo; archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)); } } #endif // OutputDebugStringW(ai.Name); // OutputDebugStringW(L"a3"); #ifndef _SFX const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.Flags_PreArc()) { /* we notify parsers that extract executables, that they don't need to open archive, if there is tail after executable (for SFX cases) */ CMyComPtr allowTail; archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); if (allowTail) allowTail->AllowTail(BoolToInt(true)); } if (op.props) { /* FOR_VECTOR (y, op.props) { const COptionalOpenProperties &optProps = (*op.props)[y]; if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) { RINOK(SetProperties(archive, optProps.Props)); break; } } */ RINOK(SetProperties(archive, *op.props)); } #endif return S_OK; } #ifndef _SFX static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) { pi.Extension = ai.GetMainExt(); pi.FileTime_Defined = false; pi.ArcType = ai.Name; RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); pi.IsSelfExe = ai.Flags_PreArc(); { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidMTime, &prop)); if (prop.vt == VT_FILETIME) { pi.FileTime_Defined = true; pi.FileTime = prop.filetime; } } if (!pi.FileTime_Defined) { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidCTime, &prop)); if (prop.vt == VT_FILETIME) { pi.FileTime_Defined = true; pi.FileTime = prop.filetime; } } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidName, &prop)); if (prop.vt == VT_BSTR) { pi.Name = prop.bstrVal; pi.Extension.Empty(); } else { RINOK(archive->GetArchiveProperty(kpidExtension, &prop)); if (prop.vt == VT_BSTR) pi.Extension = prop.bstrVal; } } { NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)); if (prop.vt == VT_BSTR) pi.Comment = prop.bstrVal; } UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); // pi.NumSubFiles = numItems; // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); // if (!pi.UnpackSize_Defined) { pi.NumSubFiles = 0; pi.NumSubDirs = 0; pi.UnpackSize = 0; for (UInt32 i = 0; i < numItems; i++) { UInt64 size = 0; bool defined = false; Archive_GetItem_Size(archive, i, size, defined); if (defined) { pi.UnpackSize_Defined = true; pi.UnpackSize += size; } bool isDir = false; Archive_IsItem_Folder(archive, i, isDir); if (isDir) pi.NumSubDirs++; else pi.NumSubFiles++; } if (pi.NumSubDirs != 0) pi.NumSubDirs_Defined = true; pi.NumSubFiles_Defined = true; } return S_OK; } #endif HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) { if (!op.stream) return S_OK; RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL)); const UInt32 kBufSize = 1 << 11; Byte buf[kBufSize]; for (;;) { UInt32 processed = 0; RINOK(op.stream->Read(buf, kBufSize, &processed)); if (processed == 0) { // ErrorInfo.NonZerosTail = false; ErrorInfo.IgnoreTail = true; return S_OK; } for (size_t i = 0; i < processed; i++) { if (buf[i] != 0) { // ErrorInfo.IgnoreTail = false; // ErrorInfo.NonZerosTail = true; return S_OK; } } } } #ifndef _SFX class CExtractCallback_To_OpenCallback: public IArchiveExtractCallback, public ICompressProgressInfo, public CMyUnknownImp { public: CMyComPtr Callback; UInt64 Files; UInt64 Offset; MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo) INTERFACE_IArchiveExtractCallback(;) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); void Init(IArchiveOpenCallback *callback) { Callback = callback; Files = 0; Offset = 0; } }; STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) { if (Callback) { UInt64 value = Offset; if (inSize) value += *inSize; return Callback->SetCompleted(&Files, &value); } return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */) { *outStream = 0; return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */) { return S_OK; } STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */) { return S_OK; } static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback, IArchiveExtractCallback *extractCallback) { /* if (needPhySize) { CMyComPtr open2; archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2); if (open2) return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); } */ RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)); if (needPhySize) { bool phySize_Defined = false; UInt64 phySize = 0; RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)); if (phySize_Defined) return S_OK; bool phySizeCantBeDetected = false;; RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); if (!phySizeCantBeDetected) { RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)); } } return S_OK; } static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) { FOR_VECTOR (i, orderIndices) if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name)) return i; return -1; } #endif HRESULT CArc::OpenStream2(const COpenOptions &op) { // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); Archive.Release(); GetRawProps.Release(); GetRootProps.Release(); ErrorInfo.ClearErrors(); ErrorInfo.ErrorFormatIndex = -1; IsParseArc = false; ArcStreamOffset = 0; // OutputDebugStringW(L"1"); // OutputDebugStringW(Path); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Ptr(dotPos + 1); } CIntVector orderIndices; bool searchMarkerInHandler = false; #ifdef _SFX searchMarkerInHandler = true; #endif CBoolArr isMainFormatArr(op.codecs->Formats.Size()); { FOR_VECTOR(i, op.codecs->Formats) isMainFormatArr[i] = false; } UInt64 maxStartOffset = op.openType.MaxStartOffset_Defined ? op.openType.MaxStartOffset : kMaxCheckStartPosition; #ifndef _SFX bool isUnknownExt = false; #endif bool isForced = false; unsigned numMainTypes = 0; int formatIndex = op.openType.FormatIndex; if (formatIndex >= 0) { isForced = true; orderIndices.Add(formatIndex); numMainTypes = 1; isMainFormatArr[formatIndex] = true; searchMarkerInHandler = true; } else { unsigned numFinded = 0; #ifndef _SFX bool isPrearcExt = false; #endif { FOR_VECTOR (i, op.codecs->Formats) { const CArcInfoEx &ai = op.codecs->Formats[i]; if (IgnoreSplit || !op.openType.CanReturnArc) if (ai.IsSplit()) continue; if (op.excludedFormats->FindInSorted(i) >= 0) continue; #ifndef _SFX if (IsPreArcFormat(ai)) isPrearcExt = true; #endif if (ai.FindExtension(extension) >= 0) { // PrintNumber("orderIndices.Insert", i); orderIndices.Insert(numFinded++, i); isMainFormatArr[i] = true; } else orderIndices.Add(i); } } if (!op.stream) { if (numFinded != 1) return E_NOTIMPL; orderIndices.DeleteFrom(1); } // PrintNumber("numFinded", numFinded ); /* if (op.openOnlySpecifiedByExtension) { if (numFinded != 0 && !IsExeExt(extension)) orderIndices.DeleteFrom(numFinded); } */ #ifndef _SFX if (op.stream && orderIndices.Size() >= 2) { RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CByteBuffer byteBuffer; CIntVector orderIndices2; if (numFinded == 0 || IsExeExt(extension)) { // signature search was here } else if (extension == L"000" || extension == L"001") { int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); if (i >= 0) { const size_t kBufSize = (1 << 10); byteBuffer.Alloc(kBufSize); size_t processedSize = kBufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize >= 16) { const Byte *buf = byteBuffer; const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) { orderIndices2.Add(orderIndices[i]); orderIndices[i] = -1; if (i >= (int)numFinded) numFinded++; } } } } else { const size_t kBufSize = (1 << 10); byteBuffer.Alloc(kBufSize); size_t processedSize = kBufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize == 0) return S_FALSE; /* check type order: 1) matched extension, no signuature 2) matched extension, matched signuature // 3) no signuature // 4) matched signuature */ MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); } FOR_VECTOR (i, orderIndices) { int val = orderIndices[i]; if (val != -1) orderIndices2.Add(val); } orderIndices = orderIndices2; } if (orderIndices.Size() >= 2) { int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); if (iUdf > iIso && iIso >= 0) { int isoIndex = orderIndices[iIso]; int udfIndex = orderIndices[iUdf]; orderIndices[iUdf] = isoIndex; orderIndices[iIso] = udfIndex; } } numMainTypes = numFinded; isUnknownExt = (numMainTypes == 0) || isPrearcExt; #else // _SFX numMainTypes = orderIndices.Size(); #endif } UInt64 fileSize = 0; if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } FileSize = fileSize; #ifndef _SFX CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); { FOR_VECTOR(i, op.codecs->Formats) skipFrontalFormat[i] = false; } #endif const COpenType &mode = op.openType; if (mode.CanReturnArc) { // ---------- OPEN main type by extenssion ---------- unsigned numCheckTypes = orderIndices.Size(); if (formatIndex >= 0) numCheckTypes = numMainTypes; for (unsigned i = 0; i < numCheckTypes; i++) { FormatIndex = orderIndices[i]; const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; // OutputDebugStringW(ai.Name); bool exactOnly = false; if (i >= numMainTypes) { if (!ai.Flags_BackwardOpen() // && !ai.Flags_PureStartOpen() ) continue; exactOnly = true; } // Some handlers do not set total bytes. So we set it here RINOK(op.callback->SetTotal(NULL, &fileSize)); if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } CMyComPtr archive; RINOK(PrepareToOpen(op, FormatIndex, archive)); if (!archive) continue; HRESULT result; if (op.stream) { UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; result = archive->Open(op.stream, &searchLimit, op.callback); } else { CMyComPtr openSeq; archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); if (!openSeq) return E_NOTIMPL; result = openSeq->OpenSeq(op.seqStream); } RINOK(ReadBasicProps(archive, 0, result)); if (result == S_FALSE) { bool isArc = ErrorInfo.IsArc_After_NonOpen(); #ifndef _SFX // if it's archive, we allow another open attempt for parser if (!mode.CanReturnParser || !isArc) skipFrontalFormat[FormatIndex] = true; #endif if (exactOnly) continue; if (i == 0 && numMainTypes == 1) { // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). ErrorInfo.ErrorFormatIndex = FormatIndex; NonOpen_ErrorInfo = ErrorInfo; if (!mode.CanReturnParser && isArc) { // if (formatIndex < 0 && !searchMarkerInHandler) { // if bad archive was detected, we don't need additional open attempts #ifndef _SFX if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) #endif return S_FALSE; } } } /* #ifndef _SFX if (IsExeExt(extension) || ai.Flags_PreArc()) { // openOnlyFullArc = false; // canReturnTailArc = true; // limitSignatureSearch = true; } #endif */ continue; } RINOK(result); #ifndef _SFX bool isMainFormat = isMainFormatArr[FormatIndex]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); bool thereIsTail = ErrorInfo.ThereIsTail; if (thereIsTail && mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, Offset + PhySize)); if (ErrorInfo.IgnoreTail) thereIsTail = false; } if (Offset > 0) { if (exactOnly || !searchMarkerInHandler || !specFlags.CanReturn_NonStart() || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) continue; } if (thereIsTail) { if (Offset > 0) { if (!specFlags.CanReturnMid) continue; } else if (!specFlags.CanReturnFrontal) continue; } if (Offset > 0 || thereIsTail) { if (formatIndex < 0) { if (IsPreArcFormat(ai)) { // openOnlyFullArc = false; // canReturnTailArc = true; /* if (mode.SkipSfxStub) limitSignatureSearch = true; */ // if (mode.SkipSfxStub) { // skipFrontalFormat[FormatIndex] = true; continue; } } } } #endif Archive = archive; return S_OK; } } #ifndef _SFX if (!op.stream) return S_FALSE; if (formatIndex >= 0 && !mode.CanReturnParser) { if (mode.MaxStartOffset_Defined) { if (mode.MaxStartOffset == 0) return S_FALSE; } else { const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.FindExtension(extension) >= 0) { const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; if (ai.Flags_FindSignature() && searchMarkerInHandler) return S_FALSE; } } } NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; CMyComPtr handler = handlerSpec; CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; CMyComPtr extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; extractCallback_To_OpenCallback_Spec->Init(op.callback); { // ---------- Check all possible START archives ---------- // this code is better for full file archives than Parser's code. CByteBuffer byteBuffer; bool endOfFile = false; size_t processedSize; { size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) if (bufSize > fileSize) { bufSize = (size_t)fileSize; endOfFile = true; } byteBuffer.Alloc(bufSize); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); processedSize = bufSize; RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); if (processedSize == 0) return S_FALSE; if (processedSize < bufSize) endOfFile = true; } CUIntVector sortedFormats; unsigned i; int splitIndex = -1; for (i = 0; i < orderIndices.Size(); i++) { unsigned form = orderIndices[i]; if (skipFrontalFormat[form]) continue; const CArcInfoEx &ai = op.codecs->Formats[form]; if (ai.IsSplit()) { splitIndex = form; continue; } if (ai.IsArcFunc) { UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); if (isArcRes == k_IsArc_Res_NO) continue; if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) continue; // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; sortedFormats.Insert(0, form); continue; } bool isNewStyleSignature = IsNewStyleSignature(ai); bool needCheck = !isNewStyleSignature || ai.Signatures.IsEmpty() || ai.Flags_PureStartOpen() || ai.Flags_StartOpen() || ai.Flags_BackwardOpen(); if (isNewStyleSignature && !ai.Signatures.IsEmpty()) { unsigned k; for (k = 0; k < ai.Signatures.Size(); k++) { const CByteBuffer &sig = ai.Signatures[k]; UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); if (processedSize < signatureEnd) { if (!endOfFile) needCheck = true; } else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0) break; } if (k != ai.Signatures.Size()) { sortedFormats.Insert(0, form); continue; } } if (needCheck) sortedFormats.Add(form); } if (splitIndex >= 0) sortedFormats.Insert(0, splitIndex); for (i = 0; i < sortedFormats.Size(); i++) { FormatIndex = sortedFormats[i]; const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; RINOK(op.callback->SetTotal(NULL, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CMyComPtr archive; RINOK(PrepareToOpen(op, FormatIndex, archive)); if (!archive) continue; PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); HRESULT result; { UInt64 searchLimit = 0; /* if (mode.CanReturnArc) result = archive->Open(op.stream, &searchLimit, op.callback); else */ result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); } if (result == S_FALSE) { skipFrontalFormat[FormatIndex] = true; // FIXME: maybe we must use LenIsUnknown. // printf(" OpenForSize Error"); continue; } RINOK(result); RINOK(ReadBasicProps(archive, 0, result)); if (Offset > 0) { continue; // good handler doesn't return such Offset > 0 // but there are some cases like false prefixed PK00 archive, when // we can support it? } NArchive::NParser::CParseItem pi; pi.Offset = Offset; pi.Size = AvailPhySize; // bool needScan = false; if (!PhySizeDefined) { // it's for Z format pi.LenIsUnknown = true; // needScan = true; // phySize = arcRem; // nextNeedCheckStartOpen = false; } /* if (OkPhySize_Defined) pi.OkSize = pi.OkPhySize; else pi.OkSize = pi.Size; */ pi.NormalizeOffset(); // printf(" phySize = %8d", (unsigned)phySize); if (mode.CanReturnArc) { bool isMainFormat = isMainFormatArr[FormatIndex]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); bool openCur = false; if (!ErrorInfo.ThereIsTail) openCur = true; else { if (mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, Offset + PhySize)); if (ErrorInfo.IgnoreTail) openCur = true; } if (!openCur) { openCur = specFlags.CanReturnFrontal; if (formatIndex < 0) // format is not forced { if (IsPreArcFormat(ai)) { // if (mode.SkipSfxStub) { openCur = false; } } } } } if (openCur) { InStream = op.stream; Archive = archive; return S_OK; } } skipFrontalFormat[FormatIndex] = true; // if (!mode.CanReturnArc) /* if (!ErrorInfo.ThereIsTail) continue; */ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) continue; // printf("\nAdd offset = %d", (int)pi.Offset); RINOK(ReadParseItemProps(archive, ai, pi)); handlerSpec->AddItem(pi); } } // ---------- PARSER ---------- CUIntVector arc2sig; // formatIndex to signatureIndex CUIntVector sig2arc; // signatureIndex to formatIndex; { unsigned sum = 0; FOR_VECTOR (i, op.codecs->Formats) { arc2sig.Add(sum); const CObjectVector &sigs = op.codecs->Formats[i].Signatures; sum += sigs.Size(); FOR_VECTOR (k, sigs) sig2arc.Add(i); } } { CArchiveOpenCallback_Offset *openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; CMyComPtr openCallback_Offset = openCallback_Offset_Spec; const size_t kBeforeSize = 1 << 16; const size_t kAfterSize = 1 << 20; const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); CByteArr hashBuffer(kNumVals); Byte *hash = hashBuffer; memset(hash, 0xFF, kNumVals); Byte prevs[256]; memset(prevs, 0xFF, sizeof(prevs)); if (sig2arc.Size() >= 0xFF) return S_FALSE; CUIntVector difficultFormats; CBoolArr difficultBools(256); { for (unsigned i = 0; i < 256; i++) difficultBools[i] = false; } bool thereAreHandlersForSearch = false; // UInt32 maxSignatureEnd = 0; FOR_VECTOR (i, orderIndices) { int index = orderIndices[i]; if (index < 0) continue; const CArcInfoEx &ai = op.codecs->Formats[index]; bool isDifficult = false; // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) if (!ai.NewInterface) isDifficult = true; else { if (ai.Flags_StartOpen()) isDifficult = true; FOR_VECTOR (k, ai.Signatures) { const CByteBuffer &sig = ai.Signatures[k]; /* UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); if (maxSignatureEnd < signatureEnd) maxSignatureEnd = signatureEnd; */ if (sig.Size() < kNumHashBytes) { isDifficult = true; continue; } thereAreHandlersForSearch = true; UInt32 v = HASH_VAL(sig, 0); unsigned sigIndex = arc2sig[index] + k; prevs[sigIndex] = hash[v]; hash[v] = (Byte)sigIndex; } } if (isDifficult) { difficultFormats.Add(index); difficultBools[index] = true; } } if (!thereAreHandlersForSearch) { // openOnlyFullArc = true; // canReturnTailArc = true; } RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; CMyComPtr limitedStream = limitedStreamSpec; limitedStreamSpec->SetStream(op.stream); openCallback_Offset_Spec->Callback = op.callback; #ifndef _NO_CRYPTO if (op.callback) { openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); } #endif RINOK(op.callback->SetTotal(NULL, &fileSize)); CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; byteBuffer.Alloc(kBufSize); UInt64 callbackPrev = 0; bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. bool endOfFile = false; UInt64 bufPhyPos = 0; size_t bytesInBuf = 0; // UInt64 prevPos = 0; // ---------- Main Scan Loop ---------- UInt64 pos = 0; if (!mode.EachPos && handlerSpec->_items.Size() == 1) { NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; if (!pi.LenIsUnknown && pi.Offset == 0) pos = pi.Size; } for (;;) { // printf("\nPos = %d", (int)pos); UInt64 posInBuf = pos - bufPhyPos; // if (pos > ((UInt64)1 << 35)) break; if (!endOfFile) { if (bytesInBuf < kBufSize) { size_t processedSize = kBufSize - bytesInBuf; // printf("\nRead ask = %d", (unsigned)processedSize); UInt64 seekPos = bufPhyPos + bytesInBuf; RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL)); RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize)); // printf(" processed = %d", (unsigned)processedSize); if (processedSize == 0) { fileSize = seekPos; endOfFile = true; } else { bytesInBuf += processedSize; limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); } continue; } if (bytesInBuf < posInBuf) { UInt64 skipSize = posInBuf - bytesInBuf; if (skipSize <= kBeforeSize) { size_t keepSize = (size_t)(kBeforeSize - skipSize); // printf("\nmemmove skip = %d", (int)keepSize); memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize); bytesInBuf = keepSize; bufPhyPos = pos - keepSize; continue; } // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); bytesInBuf = 0; bufPhyPos = pos - kBeforeSize; continue; } if (bytesInBuf - posInBuf < kAfterSize) { size_t beg = (size_t)posInBuf - kBeforeSize; // printf("\nmemmove for after beg = %d", (int)beg); memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg); bufPhyPos += beg; bytesInBuf -= beg; continue; } } if (pos >= callbackPrev + (1 << 23)) { openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); openCallback_Offset_Spec->Offset = pos; RINOK(openCallback_Offset->SetCompleted(NULL, NULL)); callbackPrev = pos; } { UInt64 endPos = bufPhyPos + bytesInBuf; if (fileSize < endPos) { FileSize = fileSize; // why ???? fileSize = endPos; } } size_t availSize = bytesInBuf - (size_t)posInBuf; if (availSize < kNumHashBytes) break; size_t scanSize = availSize - ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); { /* UInt64 scanLimit = openOnlyFullArc ? maxSignatureEnd : op.openType.ScanSize + maxSignatureEnd; */ if (!mode.CanReturnParser) { if (pos > maxStartOffset) break; UInt64 remScan = maxStartOffset - pos; if (scanSize > remScan) scanSize = (size_t)remScan; } } scanSize++; const Byte *buf = byteBuffer + (size_t)posInBuf; size_t ppp = 0; if (!needCheckStartOpen) { for (; ppp < scanSize && hash[HASH_VAL(buf, ppp)] == 0xFF; ppp++); pos += ppp; if (ppp == scanSize) continue; } UInt32 v = HASH_VAL(buf, ppp); bool nextNeedCheckStartOpen = true; unsigned i = hash[v]; unsigned indexOfDifficult = 0; // ---------- Open Loop for Current Pos ---------- bool wasOpen = false; for (;;) { unsigned index; bool isDifficult; if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) { index = difficultFormats[indexOfDifficult++]; isDifficult = true; } else { if (i == 0xFF) break; index = sig2arc[i]; unsigned sigIndex = i - arc2sig[index]; i = prevs[i]; if (needCheckStartOpen && difficultBools[index]) continue; const CArcInfoEx &ai = op.codecs->Formats[index]; if (pos < ai.SignatureOffset) continue; /* if (openOnlyFullArc) if (pos != ai.SignatureOffset) continue; */ const CByteBuffer &sig = ai.Signatures[sigIndex]; if (ppp + sig.Size() > availSize || !TestSignature(buf + ppp, sig, sig.Size())) continue; // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); // prevPos = pos; isDifficult = false; } const CArcInfoEx &ai = op.codecs->Formats[index]; if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) { // we don't check same archive second time */ if (skipFrontalFormat[index]) continue; } UInt64 startArcPos = pos; if (!isDifficult) { if (pos < ai.SignatureOffset) continue; startArcPos = pos - ai.SignatureOffset; /* // we don't need the check for Z files if (startArcPos < handlerSpec->GetLastEnd()) continue; */ } if (ai.IsArcFunc && startArcPos >= bufPhyPos) { size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); if (offsetInBuf < bytesInBuf) { UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf); if (isArcRes == k_IsArc_Res_NO) continue; if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) continue; /* if (isArcRes == k_IsArc_Res_YES_LOW_PROB) { // if (pos != ai.SignatureOffset) continue; } */ } // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); } /* if (pos == 67109888) pos = pos; */ PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); bool isMainFormat = isMainFormatArr[index]; const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); CMyComPtr archive; RINOK(PrepareToOpen(op, index, archive)); if (!archive) return E_FAIL; // OutputDebugStringW(ai.Name); UInt64 rem = fileSize - startArcPos; UInt64 arcStreamOffset = 0; if (ai.Flags_UseGlobalOffset()) { limitedStreamSpec->InitAndSeek(0, fileSize); limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL); } else { limitedStreamSpec->InitAndSeek(startArcPos, rem); arcStreamOffset = startArcPos; } UInt64 maxCheckStartPosition = 0; openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); openCallback_Offset_Spec->Offset = startArcPos; // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); extractCallback_To_OpenCallback_Spec->Files = 0; extractCallback_To_OpenCallback_Spec->Offset = startArcPos; HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition, openCallback_Offset, extractCallback_To_OpenCallback); RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)); bool isOpen = false; if (result == S_FALSE) { if (!mode.CanReturnParser) { if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) { ErrorInfo.ErrorFormatIndex = index; NonOpen_ErrorInfo = ErrorInfo; // if archive was detected, we don't need additional open attempts return S_FALSE; } continue; } if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) continue; } else { isOpen = true; RINOK(result); PRF(printf(" OK ")); } // fprintf(stderr, "\n %8X %S", startArcPos, Path); // printf("\nOpen OK: %S", ai.Name); NArchive::NParser::CParseItem pi; pi.Offset = startArcPos; if (ai.Flags_UseGlobalOffset()) pi.Offset = Offset; else if (Offset != 0) return E_FAIL; UInt64 arcRem = FileSize - pi.Offset; UInt64 phySize = arcRem; bool phySizeDefined = PhySizeDefined; if (phySizeDefined) { if (pi.Offset + PhySize > FileSize) { // ErrorInfo.ThereIsTail = true; PhySize = FileSize - pi.Offset; } phySize = PhySize; } if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) return E_FAIL; /* if (!ai.UseGlobalOffset) { if (phySize > arcRem) { ThereIsTail = true; phySize = arcRem; } } */ bool needScan = false; if (isOpen && !phySizeDefined) { // it's for Z format pi.LenIsUnknown = true; needScan = true; phySize = arcRem; nextNeedCheckStartOpen = false; } pi.Size = phySize; /* if (OkPhySize_Defined) pi.OkSize = OkPhySize; */ pi.NormalizeOffset(); // printf(" phySize = %8d", (unsigned)phySize); /* if (needSkipFullArc) if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) continue; */ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) { // it's possible for dmg archives if (!mode.CanReturnArc) continue; } if (mode.EachPos) pos++; else if (needScan) { pos++; /* if (!OkPhySize_Defined) pos++; else pos = pi.Offset + pi.OkSize; */ } else pos = pi.Offset + pi.Size; RINOK(ReadParseItemProps(archive, ai, pi)); if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) { /* It's for DMG format. This code deletes all previous items that are included to current item */ while (!handlerSpec->_items.IsEmpty()) { { const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); if (back.Offset < pi.Offset) break; if (back.Offset + back.Size > pi.Offset + pi.Size) break; } handlerSpec->_items.DeleteBack(); } } if (isOpen && mode.CanReturnArc && phySizeDefined) { // if (pi.Offset + pi.Size >= fileSize) bool openCur = false; bool thereIsTail = ErrorInfo.ThereIsTail; if (thereIsTail && mode.ZerosTailIsAllowed) { RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize)); if (ErrorInfo.IgnoreTail) thereIsTail = false; } if (pi.Offset != 0) { if (!pi.IsNotArcType) if (thereIsTail) openCur = specFlags.CanReturnMid; else openCur = specFlags.CanReturnTail; } else { if (!thereIsTail) openCur = true; else openCur = specFlags.CanReturnFrontal; if (formatIndex >= -2) openCur = true; } if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) openCur = false; // We open file as SFX, if there is front archive or first archive is "Self Executable" if (!openCur && !pi.IsSelfExe && !thereIsTail && (!pi.IsNotArcType || pi.Offset == 0)) { if (handlerSpec->_items.IsEmpty()) { if (specFlags.CanReturnTail) openCur = true; } else if (handlerSpec->_items.Size() == 1) { if (handlerSpec->_items[0].IsSelfExe) { if (mode.SpecUnknownExt.CanReturnTail) openCur = true; } } } if (openCur) { InStream = op.stream; Archive = archive; FormatIndex = index; ArcStreamOffset = arcStreamOffset; return S_OK; } } /* if (openOnlyFullArc) { ErrorInfo.ClearErrors(); return S_FALSE; } */ pi.FormatIndex = index; // printf("\nAdd offset = %d", (int)pi.Offset); handlerSpec->AddItem(pi); wasOpen = true; break; } // ---------- End of Open Loop for Current Pos ---------- if (!wasOpen) pos++; needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); } // ---------- End of Main Scan Loop ---------- /* if (handlerSpec->_items.Size() == 1) { const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; if (pi.Size == fileSize && pi.Offset == 0) { Archive = archive; FormatIndex2 = pi.FormatIndex; return S_OK; } } */ if (mode.CanReturnParser) { bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing handlerSpec->AddUnknownItem(fileSize); if (handlerSpec->_items.Size() == 0) return S_FALSE; if (returnParser || handlerSpec->_items.Size() != 1) { // return S_FALSE; handlerSpec->_stream = op.stream; Archive = handler; ErrorInfo.ClearErrors(); IsParseArc = true; FormatIndex = -1; // It's parser Offset = 0; return S_OK; } } } #endif if (!Archive) return S_FALSE; return S_OK; } HRESULT CArc::OpenStream(const COpenOptions &op) { RINOK(OpenStream2(op)); // PrintNumber("op.formatIndex 3", op.formatIndex); if (Archive) { GetRawProps.Release(); GetRootProps.Release(); Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Ptr(dotPos + 1); } DefaultName.Empty(); if (FormatIndex >= 0) { const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; if (ai.Exts.Size() == 0) DefaultName = GetDefaultName2(fileName, L"", L""); else { int subExtIndex = ai.FindExtension(extension); if (subExtIndex < 0) subExtIndex = 0; const CArcExtInfo &extInfo = ai.Exts[subExtIndex]; DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); } } } return S_OK; } #ifdef _SFX #ifdef _WIN32 static const wchar_t *k_ExeExt = L".exe"; static const unsigned k_ExeExt_Len = 4; #else static const wchar_t *k_ExeExt = L""; static const unsigned k_ExeExt_Len = 0; #endif #endif HRESULT CArc::OpenStreamOrFile(COpenOptions &op) { CMyComPtr fileStream; CMyComPtr seqStream; CInFileStream *fileStreamSpec = NULL; if (op.stdInMode) { seqStream = new CStdInFileStream; op.seqStream = seqStream; } else if (!op.stream) { fileStreamSpec = new CInFileStream; fileStream = fileStreamSpec; Path = filePath; if (!fileStreamSpec->Open(us2fs(Path))) { return GetLastError(); } op.stream = fileStream; #ifdef _SFX IgnoreSplit = true; #endif } /* if (callback) { UInt64 fileSize; RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.callback->SetTotal(NULL, &fileSize)) } */ HRESULT res = OpenStream(op); IgnoreSplit = false; #ifdef _SFX if (res != S_FALSE || !fileStreamSpec || !op.callbackSpec || NonOpen_ErrorInfo.IsArc_After_NonOpen()) return res; { if (filePath.Len() > k_ExeExt_Len && MyStringCompareNoCase(filePath.RightPtr(k_ExeExt_Len), k_ExeExt) == 0) { const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); FOR_VECTOR (i, op.codecs->Formats) { const CArcInfoEx &ai = op.codecs->Formats[i]; if (ai.IsSplit()) continue; UString path3 = path2; path3 += L"."; path3 += ai.GetMainExt(); // "7z" for SFX. Path = path3 + L".001"; bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); if (!isOk) { Path = path3; isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); } if (isOk) { if (fileStreamSpec->Open(us2fs(Path))) { op.stream = fileStream; NonOpen_ErrorInfo.ClearErrors_Full(); if (OpenStream(op) == S_OK) return S_OK; } } } } } #endif return res; } void CArchiveLink::KeepModeForNextOpen() { for (int i = Arcs.Size() - 1; i >= 0; i--) { CMyComPtr keep; Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); if (keep) keep->KeepModeForNextOpen(); } } HRESULT CArchiveLink::Close() { for (int i = Arcs.Size() - 1; i >= 0; i--) { RINOK(Arcs[i].Close()); } IsOpen = false; // ErrorsText.Empty(); return S_OK; } void CArchiveLink::Release() { // NonOpenErrorFormatIndex = -1; NonOpen_ErrorInfo.ClearErrors(); NonOpen_ArcPath.Empty(); while (!Arcs.IsEmpty()) Arcs.DeleteBack(); } /* void CArchiveLink::Set_ErrorsText() { FOR_VECTOR(i, Arcs) { const CArc &arc = Arcs[i]; if (!arc.ErrorFlagsText.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += GetUnicodeString(arc.ErrorFlagsText); } if (!arc.ErrorMessage.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += arc.ErrorMessage; } if (!arc.WarningMessage.IsEmpty()) { if (!ErrorsText.IsEmpty()) ErrorsText += L'\n'; ErrorsText += arc.WarningMessage; } } } */ HRESULT CArchiveLink::Open(COpenOptions &op) { Release(); if (op.types->Size() >= 32) return E_NOTIMPL; HRESULT resSpec; for (;;) { resSpec = S_OK; op.openType = COpenType(); if (op.types->Size() >= 1) { COpenType latest; if (Arcs.Size() < op.types->Size()) latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; else { latest = (*op.types)[0]; if (!latest.Recursive) break; } op.openType = latest; } else if (Arcs.Size() >= 32) break; /* op.formatIndex = -1; if (op.types->Size() >= 1) { int latest; if (Arcs.Size() < op.types->Size()) latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; else { latest = (*op.types)[0]; if (latest != -2 && latest != -3) break; } if (latest >= 0) op.formatIndex = latest; else if (latest == -1 || latest == -2) { // default } else if (latest == -3) op.formatIndex = -2; else op.formatIndex = latest + 2; } else if (Arcs.Size() >= 32) break; */ if (Arcs.IsEmpty()) { CArc arc; arc.filePath = op.filePath; arc.Path = op.filePath; arc.SubfileIndex = (UInt32)(Int32)-1; HRESULT result = arc.OpenStreamOrFile(op); if (result != S_OK) { if (result == S_FALSE) { NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; NonOpen_ArcPath = arc.Path; } return result; } Arcs.Add(arc); continue; } // PrintNumber("op.formatIndex 11", op.formatIndex); const CArc &arc = Arcs.Back(); if (op.types->Size() > Arcs.Size()) resSpec = E_NOTIMPL; UInt32 mainSubfile; { NCOM::CPropVariant prop; RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)); if (prop.vt == VT_UI4) mainSubfile = prop.ulVal; else break; UInt32 numItems; RINOK(arc.Archive->GetNumberOfItems(&numItems)); if (mainSubfile >= numItems) break; } CMyComPtr getStream; if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) break; CMyComPtr subSeqStream; if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) break; CMyComPtr subStream; if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) break; CArc arc2; RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); bool zerosTailIsAllowed; RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); CMyComPtr setSubArchiveName; op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); if (setSubArchiveName) setSubArchiveName->SetSubArchiveName(arc2.Path); arc2.SubfileIndex = mainSubfile; // CIntVector incl; CIntVector excl; COpenOptions op2; #ifndef _SFX op2.props = op.props; #endif op2.codecs = op.codecs; // op2.types = &incl; op2.openType = op.openType; op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; op2.excludedFormats = ! op2.stdInMode = false; op2.stream = subStream; op2.filePath = arc2.Path; op2.callback = op.callback; op2.callbackSpec = op.callbackSpec; HRESULT result = arc2.OpenStream(op2); resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); if (result == S_FALSE) { NonOpen_ErrorInfo = arc2.ErrorInfo; NonOpen_ArcPath = arc2.Path; break; } RINOK(result); RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); Arcs.Add(arc2); } IsOpen = !Arcs.IsEmpty(); return resSpec; } static void SetCallback(const FString &filePath, IOpenCallbackUI *callbackUI, IArchiveOpenCallback *reOpenCallback, CMyComPtr &callback) { COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; callback = openCallbackSpec; openCallbackSpec->Callback = callbackUI; openCallbackSpec->ReOpenCallback = reOpenCallback; FString dirPrefix, fileName; NFile::NDir::GetFullPathAndSplit(filePath, dirPrefix, fileName); openCallbackSpec->Init(dirPrefix, fileName); } HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) { VolumesSize = 0; COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; CMyComPtr callback = openCallbackSpec; openCallbackSpec->Callback = callbackUI; FString prefix, name; if (!op.stream && !op.stdInMode) { NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); openCallbackSpec->Init(prefix, name); } else { openCallbackSpec->SetSubArchiveName(op.filePath); } op.callback = callback; op.callbackSpec = openCallbackSpec; RINOK(Open(op)); // VolumePaths.Add(fs2us(prefix + name)); FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) { if (openCallbackSpec->FileNames_WasUsed[i]) { VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); VolumesSize += openCallbackSpec->FileSizes[i]; } } // VolumesSize = openCallbackSpec->TotalSize; return S_OK; } HRESULT CArc::ReOpen(const COpenOptions &op) { ErrorInfo.ClearErrors(); ErrorInfo.ErrorFormatIndex = -1; UInt64 fileSize = 0; if (op.stream) { RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); } FileSize = fileSize; CMyComPtr stream2; Int64 globalOffset = GetGlobalOffset(); if (globalOffset <= 0) stream2 = op.stream; else { CTailInStream *tailStreamSpec = new CTailInStream; stream2 = tailStreamSpec; tailStreamSpec->Stream = op.stream; tailStreamSpec->Offset = globalOffset; tailStreamSpec->Init(); RINOK(tailStreamSpec->SeekToStart()); } // There are archives with embedded STUBs (like ZIP), so we must support signature scanning // But for another archives we can use 0 here. So the code can be fixed !!! UInt64 maxStartPosition = kMaxCheckStartPosition; HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback); if (res == S_OK) { RINOK(ReadBasicProps(Archive, globalOffset, res)); ArcStreamOffset = globalOffset; if (ArcStreamOffset != 0) InStream = op.stream; } return res; } HRESULT CArchiveLink::ReOpen(COpenOptions &op) { if (Arcs.Size() > 1) return E_NOTIMPL; CObjectVector inc; CIntVector excl; op.types = &inc; op.excludedFormats = ! op.stdInMode = false; op.stream = NULL; if (Arcs.Size() == 0) // ??? return Open2(op, NULL); CMyComPtr openCallbackNew; SetCallback(us2fs(op.filePath), NULL, op.callback, openCallbackNew); CInFileStream *fileStreamSpec = new CInFileStream; CMyComPtr stream(fileStreamSpec); if (!fileStreamSpec->Open(us2fs(op.filePath))) return GetLastError(); op.stream = stream; CArc &arc = Arcs[0]; HRESULT res = arc.ReOpen(op); IsOpen = (res == S_OK); return res; } #ifndef _SFX bool ParseComplexSize(const wchar_t *s, UInt64 &result) { result = 0; const wchar_t *end; UInt64 number = ConvertStringToUInt64(s, &end); if (end == s) return false; if (*end == 0) { result = number; return true; } if (end[1] != 0) return false; unsigned numBits; switch (MyCharLower_Ascii(*end)) { case 'b': result = number; return true; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; case 't': numBits = 40; break; default: return false; } if (number >= ((UInt64)1 << (64 - numBits))) return false; result = number << numBits; return true; } static bool ParseTypeParams(const UString &s, COpenType &type) { if (s[0] == 0) return true; if (s[1] == 0) { switch ((unsigned)(Byte)s[0]) { case 'e': type.EachPos = true; return true; case 'a': type.CanReturnArc = true; return true; case 'r': type.Recursive = true; return true; } return false; } if (s[0] == 's') { UInt64 result; if (!ParseComplexSize(s.Ptr(1), result)) return false; type.MaxStartOffset = result; type.MaxStartOffset_Defined = true; return true; } return false; } bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) { int pos2 = s.Find(':'); UString name; if (pos2 < 0) { name = s; pos2 = s.Len(); } else { name = s.Left(pos2); pos2++; } int index = codecs.FindFormatForArchiveType(name); type.Recursive = false; if (index < 0) { if (name[0] == '*') { if (name[1] != 0) return false; } else if (name[0] == '#') { if (name[1] != 0) return false; type.CanReturnArc = false; type.CanReturnParser = true; } else return false; } type.FormatIndex = index; for (unsigned i = pos2; i < s.Len();) { int next = s.Find(':', i); if (next < 0) next = s.Len(); UString name = s.Mid(i, next - i); if (name.IsEmpty()) return false; if (!ParseTypeParams(name, type)) return false; i = next + 1; } return true; } bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types) { types.Clear(); for (unsigned pos = 0; pos < s.Len();) { int pos2 = s.Find('.', pos); if (pos2 < 0) pos2 = s.Len(); UString name = s.Mid(pos, pos2 - pos); if (name.IsEmpty()) return false; COpenType type; if (!ParseType(codecs, name, type)) return false; types.Add(type); pos = pos2 + 1; } return true; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h0100777000000000000000000002134713761647206023751 0ustar00// OpenArchive.h #ifndef __OPEN_ARCHIVE_H #define __OPEN_ARCHIVE_H #include "../../../Windows/PropVariant.h" #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "Property.h" HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); HRESULT Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); /* struct COptionalOpenProperties { UString FormatName; CObjectVector Props; }; */ #ifdef _SFX #define OPEN_PROPS_DECL #else #define OPEN_PROPS_DECL const CObjectVector *props; // #define OPEN_PROPS_DECL , const CObjectVector *props #endif struct COpenSpecFlags { // bool CanReturnFull; bool CanReturnFrontal; bool CanReturnTail; bool CanReturnMid; bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } COpenSpecFlags(): // CanReturnFull(true), CanReturnFrontal(false), CanReturnTail(false), CanReturnMid(false) {} }; struct COpenType { int FormatIndex; COpenSpecFlags SpecForcedType; COpenSpecFlags SpecMainType; COpenSpecFlags SpecWrongExt; COpenSpecFlags SpecUnknownExt; bool Recursive; bool CanReturnArc; bool CanReturnParser; bool EachPos; // bool SkipSfxStub; // bool ExeAsUnknown; bool ZerosTailIsAllowed; bool MaxStartOffset_Defined; UInt64 MaxStartOffset; const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const { return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); } COpenType(): FormatIndex(-1), Recursive(true), EachPos(false), CanReturnArc(true), CanReturnParser(false), // SkipSfxStub(true), // ExeAsUnknown(true), ZerosTailIsAllowed(false), MaxStartOffset_Defined(false), MaxStartOffset(0) { SpecForcedType.CanReturnFrontal = true; SpecForcedType.CanReturnTail = true; SpecForcedType.CanReturnMid = true; SpecMainType.CanReturnFrontal = true; SpecUnknownExt.CanReturnTail = true; // for sfx SpecUnknownExt.CanReturnMid = true; SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad // ZerosTailIsAllowed = true; } }; struct COpenOptions { CCodecs *codecs; COpenType openType; const CObjectVector *types; const CIntVector *excludedFormats; IInStream *stream; ISequentialInStream *seqStream; IArchiveOpenCallback *callback; COpenCallbackImp *callbackSpec; OPEN_PROPS_DECL // bool openOnlySpecifiedByExtension, bool stdInMode; UString filePath; COpenOptions(): codecs(NULL), types(NULL), excludedFormats(NULL), stream(NULL), seqStream(NULL), callback(NULL), callbackSpec(NULL), stdInMode(false) {} }; UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); struct CArcErrorInfo { bool ThereIsTail; bool UnexpecedEnd; bool IgnoreTail; // all are zeros // bool NonZerosTail; bool ErrorFlags_Defined; UInt32 ErrorFlags; UInt32 WarningFlags; int ErrorFormatIndex; // - 1 means no Error. // if FormatIndex == ErrorFormatIndex, the archive is open with offset UInt64 TailSize; /* if CArc is Open OK with some format: - ErrorFormatIndex shows error format index, if extension is incorrect - other variables show message and warnings of archive that is open */ UString ErrorMessage; UString WarningMessage; // call IsArc_After_NonOpen only if Open returns S_FALSE bool IsArc_After_NonOpen() const { return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); } CArcErrorInfo(): ThereIsTail(false), UnexpecedEnd(false), IgnoreTail(false), // NonZerosTail(false), ErrorFlags_Defined(false), ErrorFlags(0), WarningFlags(0), ErrorFormatIndex(-1), TailSize(0) {} void ClearErrors(); void ClearErrors_Full() { ErrorFormatIndex = -1; ClearErrors(); } bool IsThereErrorOrWarning() const { return ErrorFlags != 0 || WarningFlags != 0 || NeedTailWarning() || UnexpecedEnd || !ErrorMessage.IsEmpty() || !WarningMessage.IsEmpty(); } bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } UInt32 GetWarningFlags() const { UInt32 a = WarningFlags; if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) a |= kpv_ErrorFlags_DataAfterEnd; return a; } UInt32 GetErrorFlags() const { UInt32 a = ErrorFlags; if (UnexpecedEnd) a |= kpv_ErrorFlags_UnexpectedEnd; return a; } }; class CArc { HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); HRESULT OpenStream2(const COpenOptions &options); public: CMyComPtr Archive; CMyComPtr InStream; // we use InStream in 2 cases (ArcStreamOffset != 0): // 1) if we use additional cache stream // 2) we reopen sfx archive with CTailInStream CMyComPtr GetRawProps; CMyComPtr GetRootProps; CArcErrorInfo ErrorInfo; // for OK archives CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) UString Path; UString filePath; UString DefaultName; int FormatIndex; // - 1 means Parser. int SubfileIndex; FILETIME MTime; bool MTimeDefined; Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler UInt64 PhySize; // UInt64 OkPhySize; bool PhySizeDefined; // bool OkPhySize_Defined; UInt64 FileSize; UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file // bool offsetDefined; UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive // AString ErrorFlagsText; bool IsParseArc; bool IsTree; bool Ask_Deleted; bool Ask_AltStream; bool Ask_Aux; bool Ask_INode; bool IgnoreSplit; // don't try split handler // void Set_ErrorFlagsText(); CArc(): MTimeDefined(false), IsTree(false), Ask_Deleted(false), Ask_AltStream(false), Ask_Aux(false), Ask_INode(false), IgnoreSplit(false) {} HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); // ~CArc(); HRESULT Close() { InStream.Release(); return Archive->Close(); } // AltStream's name is concatenated with base file name in one string in parts.Back() HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; HRESULT GetItemPath(UInt32 index, UString &result) const; // GetItemPath2 adds [DELETED] dir prefix for deleted items. HRESULT GetItemPath2(UInt32 index, UString &result) const; HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; HRESULT IsItemAnti(UInt32 index, bool &result) const { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } HRESULT OpenStream(const COpenOptions &options); HRESULT OpenStreamOrFile(COpenOptions &options); HRESULT ReOpen(const COpenOptions &options); HRESULT CreateNewTailStream(CMyComPtr &stream); }; struct CArchiveLink { CObjectVector Arcs; UStringVector VolumePaths; UInt64 VolumesSize; bool IsOpen; // int NonOpenErrorFormatIndex; // - 1 means no Error. UString NonOpen_ArcPath; CArcErrorInfo NonOpen_ErrorInfo; // UString ErrorsText; // void Set_ErrorsText(); CArchiveLink(): VolumesSize(0), IsOpen(false) {} void KeepModeForNextOpen(); HRESULT Close(); void Release(); ~CArchiveLink() { Release(); } const CArc *GetArc() const { return &Arcs.Back(); } IInArchive *GetArchive() const { return Arcs.Back().Archive; } IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } HRESULT Open(COpenOptions &options); HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); HRESULT ReOpen(COpenOptions &options); }; bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h0100777000000000000000000000024613761647206023365 0ustar00// Property.h #ifndef __7Z_PROPERTY_H #define __7Z_PROPERTY_H #include "../../../Common/MyString.h" struct CProperty { UString Name; UString Value; }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp0100777000000000000000000002763013761647206024260 0ustar00// PropIDUtils.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileIO.h" #include "../../../Windows/PropVariantConv.h" #include "../../PropID.h" #include "PropIDUtils.h" #define Get16(x) GetUi16(x) #define Get32(x) GetUi32(x) using namespace NWindows; static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_"; /* 0 READONLY 1 HIDDEN 2 SYSTEM 4 DIRECTORY 5 ARCHIVE 6 DEVICE 7 NORMAL 8 TEMPORARY 9 SPARSE_FILE 10 REPARSE_POINT 11 COMPRESSED 12 OFFLINE 13 NOT_CONTENT_INDEXED 14 ENCRYPTED 16 VIRTUAL */ void ConvertWinAttribToString(char *s, UInt32 wa) { for (int i = 0; i < 16; i++) if ((wa & (1 << i)) && i != 7) *s++ = g_WinAttribChars[i]; *s = 0; } static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; #define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-'; void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw() { *dest = 0; if (prop.vt == VT_FILETIME) { FILETIME localFileTime; if ((prop.filetime.dwHighDateTime == 0 && prop.filetime.dwLowDateTime == 0) || !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime)) return; ConvertFileTimeToString(localFileTime, dest, true, full); return; } switch (propID) { case kpidCRC: { if (prop.vt != VT_UI4) break; ConvertUInt32ToHex8Digits(prop.ulVal, dest); return; } case kpidAttrib: { if (prop.vt != VT_UI4) break; ConvertWinAttribToString(dest, prop.ulVal); return; } case kpidPosixAttrib: { if (prop.vt != VT_UI4) break; UString res; UInt32 a = prop.ulVal; dest[0] = kPosixTypes[(a >> 12) & 0xF]; for (int i = 6; i >= 0; i -= 3) { dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); } if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S'); if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S'); if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T'); dest[10] = 0; a &= ~(UInt32)0xFFFF; if (a != 0) { dest[10] = ' '; ConvertUInt32ToHex8Digits(a, dest + 11); } return; } case kpidINode: { if (prop.vt != VT_UI8) break; ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); dest += strlen(dest); *dest++ = '-'; UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); ConvertUInt64ToString(low, dest); return; } case kpidVa: { UInt64 v = 0; if (ConvertPropVariantToUInt64(prop, v)) { dest[0] = '0'; dest[1] = 'x'; ConvertUInt64ToHex(prop.ulVal, dest + 2); return; } break; } } ConvertPropVariantToShortString(prop, dest); } void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full) { if (prop.vt == VT_BSTR) { dest = prop.bstrVal; return; } char temp[64]; ConvertPropertyToShortString(temp, prop, propID, full); int len = MyStringLen(temp); wchar_t *str = dest.GetBuffer(len); for (int i = 0; i < len; i++) str[i] = temp[i]; dest.ReleaseBuffer(len); } static inline char GetHex(Byte value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } #ifndef _SFX static inline void AddHexToString(AString &res, Byte value) { res += GetHex((Byte)(value >> 4)); res += GetHex((Byte)(value & 0xF)); res += ' '; } /* static AString Data_To_Hex(const Byte *data, size_t size) { AString s; for (size_t i = 0; i < size; i++) AddHexToString(s, data[i]); return s; } */ static const char *sidNames[] = { "0", "Dialup", "Network", "Batch", "Interactive", "Logon", // S-1-5-5-X-Y "Service", "Anonymous", "Proxy", "EnterpriseDC", "Self", "AuthenticatedUsers", "RestrictedCode", "TerminalServer", "RemoteInteractiveLogon", "ThisOrganization", "16", "IUserIIS", "LocalSystem", "LocalService", "NetworkService", "Domains" }; struct CSecID2Name { UInt32 n; const char *sz; }; const CSecID2Name sid_32_Names[] = { { 544, "Administrators" }, { 545, "Users" }, { 546, "Guests" }, { 547, "PowerUsers" }, { 548, "AccountOperators" }, { 549, "ServerOperators" }, { 550, "PrintOperators" }, { 551, "BackupOperators" }, { 552, "Replicators" }, { 553, "Backup Operators" }, { 554, "PreWindows2000CompatibleAccess" }, { 555, "RemoteDesktopUsers" }, { 556, "NetworkConfigurationOperators" }, { 557, "IncomingForestTrustBuilders" }, { 558, "PerformanceMonitorUsers" }, { 559, "PerformanceLogUsers" }, { 560, "WindowsAuthorizationAccessGroup" }, { 561, "TerminalServerLicenseServers" }, { 562, "DistributedCOMUsers" }, { 569, "CryptographicOperators" }, { 573, "EventLogReaders" }, { 574, "CertificateServiceDCOMAccess" } }; static const CSecID2Name sid_21_Names[] = { { 500, "Administrator" }, { 501, "Guest" }, { 502, "KRBTGT" }, { 512, "DomainAdmins" }, { 513, "DomainUsers" }, { 515, "DomainComputers" }, { 516, "DomainControllers" }, { 517, "CertPublishers" }, { 518, "SchemaAdmins" }, { 519, "EnterpriseAdmins" }, { 520, "GroupPolicyCreatorOwners" }, { 553, "RASandIASServers" }, { 553, "RASandIASServers" }, { 571, "AllowedRODCPasswordReplicationGroup" }, { 572, "DeniedRODCPasswordReplicationGroup" } }; struct CServicesToName { UInt32 n[5]; const char *sz; }; static const CServicesToName services_to_name[] = { { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } }; static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize) { sidSize = 0; if (lim < 8) { s += "ERROR"; return; } UInt32 rev = p[0]; if (rev != 1) { s += "UNSUPPORTED"; return; } UInt32 num = p[1]; if (8 + num * 4 > lim) { s += "ERROR"; return; } sidSize = 8 + num * 4; UInt32 authority = GetBe32(p + 4); if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) { UInt32 v0 = Get32(p + 8); if (v0 < ARRAY_SIZE(sidNames)) { s += sidNames[v0]; return; } if (v0 == 32 && num == 2) { UInt32 v1 = Get32(p + 12); for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++) if (sid_32_Names[i].n == v1) { s += sid_32_Names[i].sz; return; } } if (v0 == 21 && num == 5) { UInt32 v4 = Get32(p + 8 + 4 * 4); for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++) if (sid_21_Names[i].n == v4) { s += sid_21_Names[i].sz; return; } } if (v0 == 80 && num == 6) { for (int i = 0; i < ARRAY_SIZE(services_to_name); i++) { const CServicesToName &sn = services_to_name[i]; int j; for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); if (j == 5) { s += sn.sz; return; } } } } char sz[16]; s += "S-1-"; if (p[2] == 0 && p[3] == 0) { ConvertUInt32ToString(authority, sz); s += sz; } else { s += "0x"; for (int i = 2; i < 8; i++) AddHexToString(s, p[i]); } for (UInt32 i = 0; i < num; i++) { s += '-'; ConvertUInt32ToString(Get32(p + 8 + i * 4), sz); s += sz; } } static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos) { if (pos > size) { s += "ERROR"; return; } UInt32 sidSize = 0; ParseSid(s, p + pos, size - pos, sidSize); } static void AddUInt32ToString(AString &s, UInt32 val) { char sz[16]; ConvertUInt32ToString(val, sz); s += sz; } static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset) { UInt32 control = Get16(p + 2); if ((flags & control) == 0) return; UInt32 pos = Get32(p + offset); s += ' '; s += strName; if (pos >= size) return; p += pos; size -= pos; if (size < 8) return; if (Get16(p) != 2) // revision return; // UInt32 aclSize = Get16(p + 2); UInt32 num = Get32(p + 4); AddUInt32ToString(s, num); /* if (num >= (1 << 16)) return; if (aclSize > size) return; size = aclSize; size -= 8; p += 8; for (UInt32 i = 0 ; i < num; i++) { if (size <= 8) return; // Byte type = p[0]; // Byte flags = p[1]; // UInt32 aceSize = Get16(p + 2); // UInt32 mask = Get32(p + 4); p += 8; size -= 8; UInt32 sidSize = 0; s += ' '; s += ParseSid(p, size, sidSize); if (sidSize == 0) return; p += sidSize; size -= sidSize; } if (size != 0) s += " ERROR"; */ } #define MY_SE_OWNER_DEFAULTED (0x0001) #define MY_SE_GROUP_DEFAULTED (0x0002) #define MY_SE_DACL_PRESENT (0x0004) #define MY_SE_DACL_DEFAULTED (0x0008) #define MY_SE_SACL_PRESENT (0x0010) #define MY_SE_SACL_DEFAULTED (0x0020) #define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) #define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) #define MY_SE_DACL_AUTO_INHERITED (0x0400) #define MY_SE_SACL_AUTO_INHERITED (0x0800) #define MY_SE_DACL_PROTECTED (0x1000) #define MY_SE_SACL_PROTECTED (0x2000) #define MY_SE_RM_CONTROL_VALID (0x4000) #define MY_SE_SELF_RELATIVE (0x8000) void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s) { s.Empty(); if (size < 20 || size > (1 << 18)) { s += "ERROR"; return; } if (Get16(data) != 1) // revision { s += "UNSUPPORTED"; return; } ParseOwner(s, data, size, Get32(data + 4)); s += ' '; ParseOwner(s, data, size, Get32(data + 8)); ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); s += ' '; AddUInt32ToString(s, size); // s += '\n'; // s += Data_To_Hex(data, size); } #ifdef _WIN32 static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) { if (pos >= size) return false; size -= pos; if (size < 8) return false; UInt32 rev = data[pos]; if (rev != 1) return false; UInt32 num = data[pos + 1]; return (8 + num * 4 <= size); } static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) { UInt32 control = Get16(p + 2); if ((flags & control) == 0) return true; UInt32 pos = Get32(p + offset); if (pos >= size) return false; p += pos; size -= pos; if (size < 8) return false; UInt32 aclSize = Get16(p + 2); return (aclSize <= size); } bool CheckNtSecure(const Byte *data, UInt32 size) { if (size < 20) return false; if (Get16(data) != 1) // revision return true; // windows function can handle such error, so we allow it if (size > (1 << 18)) return false; if (!CheckSid(data, size, Get32(data + 4))) return false; if (!CheckSid(data, size, Get32(data + 8))) return false; if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; return true; } #endif bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) { s.Empty(); NFile::CReparseAttr attr; if (attr.Parse(data, size)) { if (!attr.IsSymLink()) s += L"Junction: "; s += attr.GetPath(); if (!attr.IsOkNamePair()) { s += L" : "; s += attr.PrintName; } return true; } if (size < 8) return false; UInt32 tag = Get32(data); UInt32 len = Get16(data + 4); if (len + 8 > size) return false; if (Get16(data + 6) != 0) // padding return false; char hex[16]; ConvertUInt32ToHex8Digits(tag, hex); s.AddAsciiStr(hex); s += L' '; data += 8; for (UInt32 i = 0; i < len; i++) { Byte b = ((const Byte *)data)[i]; s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF)); s += (wchar_t)GetHex((Byte)(b & 0xF)); } return true; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h0100777000000000000000000000121713761647206023716 0ustar00// PropIDUtils.h #ifndef __PROPID_UTILS_H #define __PROPID_UTILS_H #include "../../../Common/MyString.h" // provide at least 64 bytes for buffer including zero-end void ConvertPropertyToShortString(char *dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true) throw(); void ConvertPropertyToString(UString &dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true); bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s); void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s); bool CheckNtSecure(const Byte *data, UInt32 size); void ConvertWinAttribToString(char *s, UInt32 wa); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp0100777000000000000000000000363313761647206024707 0ustar00// SetProperties.cpp #include "StdAfx.h" #include "../../../Common/MyCom.h" #include "../../../Common/MyString.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/PropVariant.h" #include "../../Archive/IArchive.h" #include "SetProperties.h" using namespace NWindows; using namespace NCOM; static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) { const wchar_t *end; UInt64 result = ConvertStringToUInt64(s, &end); if (*end != 0 || s.IsEmpty()) prop = s; else if (result <= (UInt32)0xFFFFFFFF) prop = (UInt32)result; else prop = result; } HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties) { if (properties.IsEmpty()) return S_OK; CMyComPtr setProperties; unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties); if (!setProperties) return S_OK; UStringVector realNames; CPropVariant *values = new CPropVariant[properties.Size()]; try { unsigned i; for (i = 0; i < properties.Size(); i++) { const CProperty &property = properties[i]; NCOM::CPropVariant propVariant; UString name = property.Name; if (property.Value.IsEmpty()) { if (!name.IsEmpty()) { wchar_t c = name.Back(); if (c == L'-') propVariant = false; else if (c == L'+') propVariant = true; if (propVariant.vt != VT_EMPTY) name.DeleteBack(); } } else ParseNumberString(property.Value, propVariant); realNames.Add(name); values[i] = propVariant; } CRecordVector names; for (i = 0; i < realNames.Size(); i++) names.Add((const wchar_t *)realNames[i]); RINOK(setProperties->SetProperties(&names.Front(), values, names.Size())); } catch(...) { delete []values; throw; } delete []values; return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h0100777000000000000000000000027613761647206024354 0ustar00// SetProperties.h #ifndef __SETPROPERTIES_H #define __SETPROPERTIES_H #include "Property.h" HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp0100777000000000000000000000112413761647206024040 0ustar00// SortUtils.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "SortUtils.h" static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param) { const UStringVector &strings = *(const UStringVector *)param; return CompareFileNames(strings[*p1], strings[*p2]); } void SortFileNames(const UStringVector &strings, CUIntVector &indices) { unsigned numItems = strings.Size(); indices.ClearAndSetSize(numItems); unsigned *vals = &indices[0]; for (unsigned i = 0; i < numItems; i++) vals[i] = i; indices.Sort(CompareStrings, (void *)&strings); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h0100777000000000000000000000026413761647206023511 0ustar00// SortUtils.h #ifndef __SORT_UTLS_H #define __SORT_UTLS_H #include "../../../Common/MyString.h" void SortFileNames(const UStringVector &strings, CUIntVector &indices); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h0100777000000000000000000000014013761647206022723 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp0100777000000000000000000000043413761647206023763 0ustar00// TempFiles.cpp #include "StdAfx.h" #include "../../../Windows/FileDir.h" #include "TempFiles.h" using namespace NWindows; using namespace NFile; void CTempFiles::Clear() { while (!Paths.IsEmpty()) { NDir::DeleteFileAlways(Paths.Back()); Paths.DeleteBack(); } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h0100777000000000000000000000032013761647206023422 0ustar00// TempFiles.h #ifndef __TEMP_FILES_H #define __TEMP_FILES_H #include "../../../Common/MyString.h" class CTempFiles { void Clear(); public: FStringVector Paths; ~CTempFiles() { Clear(); } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp0100777000000000000000000011302613761647206023317 0ustar00// Update.cpp #include "StdAfx.h" #include "Update.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/DLL.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../../../Windows/TimeUtils.h" #include "../../Common/FileStreams.h" #include "../../Common/LimitedStreams.h" #include "../../Compress/CopyCoder.h" #include "../Common/DirItem.h" #include "../Common/EnumDirItems.h" #include "../Common/OpenArchive.h" #include "../Common/UpdateProduce.h" #include "EnumDirItems.h" #include "SetProperties.h" #include "TempFiles.h" #include "UpdateCallback.h" static const char *kUpdateIsNotSupoorted = "update operations are not supported for this archive"; using namespace NWindows; using namespace NCOM; using namespace NFile; using namespace NDir; using namespace NName; static CFSTR kTempFolderPrefix = FTEXT("7zE"); static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) { NFind::CFileInfo fileInfo; FString pathPrefix = path + FCHAR_PATH_SEPARATOR; { NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); while (enumerator.Next(fileInfo)) { if (fileInfo.IsDir()) if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) return false; } } /* // we don't need clear read-only for folders if (!MySetFileAttributes(path, 0)) return false; */ return RemoveDir(path); } using namespace NUpdateArchive; class COutMultiVolStream: public IOutStream, public CMyUnknownImp { unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; struct CAltStreamInfo { COutFileStream *StreamSpec; CMyComPtr Stream; FString Name; UInt64 Pos; UInt64 RealSize; }; CObjectVector Streams; public: // CMyComPtr VolumeCallback; CRecordVector Sizes; FString Prefix; CTempFiles *TempFiles; void Init() { _streamIndex = 0; _offsetPos = 0; _absPos = 0; _length = 0; } bool SetMTime(const FILETIME *mTime); HRESULT Close(); MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); STDMETHOD(SetSize)(UInt64 newSize); }; // static NSynchronization::CCriticalSection g_TempPathsCS; HRESULT COutMultiVolStream::Close() { HRESULT res = S_OK; FOR_VECTOR (i, Streams) { COutFileStream *s = Streams[i].StreamSpec; if (s) { HRESULT res2 = s->Close(); if (res2 != S_OK) res = res2; } } return res; } bool COutMultiVolStream::SetMTime(const FILETIME *mTime) { bool res = true; FOR_VECTOR (i, Streams) { COutFileStream *s = Streams[i].StreamSpec; if (s) if (!s->SetMTime(mTime)) res = false; } return res; } STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) *processedSize = 0; while (size > 0) { if (_streamIndex >= Streams.Size()) { CAltStreamInfo altStream; FChar temp[16]; ConvertUInt32ToString(_streamIndex + 1, temp); FString res = temp; while (res.Len() < 3) res = FString(FTEXT('0')) + res; FString name = Prefix + res; altStream.StreamSpec = new COutFileStream; altStream.Stream = altStream.StreamSpec; if (!altStream.StreamSpec->Create(name, false)) return ::GetLastError(); { // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); TempFiles->Paths.Add(name); } altStream.Pos = 0; altStream.RealSize = 0; altStream.Name = name; Streams.Add(altStream); continue; } CAltStreamInfo &altStream = Streams[_streamIndex]; unsigned index = _streamIndex; if (index >= Sizes.Size()) index = Sizes.Size() - 1; UInt64 volSize = Sizes[index]; if (_offsetPos >= volSize) { _offsetPos -= volSize; _streamIndex++; continue; } if (_offsetPos != altStream.Pos) { // CMyComPtr outStream; // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream)); RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); altStream.Pos = _offsetPos; } UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos); UInt32 realProcessed; RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); data = (void *)((Byte *)data + realProcessed); size -= realProcessed; altStream.Pos += realProcessed; _offsetPos += realProcessed; _absPos += realProcessed; if (_absPos > _length) _length = _absPos; if (_offsetPos > altStream.RealSize) altStream.RealSize = _offsetPos; if (processedSize != NULL) *processedSize += realProcessed; if (altStream.Pos == volSize) { _streamIndex++; _offsetPos = 0; } if (realProcessed == 0 && curSize != 0) return E_FAIL; break; } return S_OK; } STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; switch (seekOrigin) { case STREAM_SEEK_SET: _absPos = offset; break; case STREAM_SEEK_CUR: _absPos += offset; break; case STREAM_SEEK_END: _absPos = _length + offset; break; } _offsetPos = _absPos; if (newPosition != NULL) *newPosition = _absPos; _streamIndex = 0; return S_OK; } STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) { if (newSize < 0) return E_INVALIDARG; unsigned i = 0; while (i < Streams.Size()) { CAltStreamInfo &altStream = Streams[i++]; if ((UInt64)newSize < altStream.RealSize) { RINOK(altStream.Stream->SetSize(newSize)); altStream.RealSize = newSize; break; } newSize -= altStream.RealSize; } while (i < Streams.Size()) { { CAltStreamInfo &altStream = Streams.Back(); altStream.Stream.Release(); DeleteFileAlways(altStream.Name); } Streams.DeleteBack(); } _offsetPos = _absPos; _streamIndex = 0; _length = newSize; return S_OK; } void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) { OriginalPath = path; SplitPathToParts_2(path, Prefix, Name); if (mode == k_ArcNameMode_Add) return; if (mode == k_ArcNameMode_Exact) { BaseExtension.Empty(); return; } int dotPos = Name.ReverseFind(L'.'); if (dotPos < 0) return; if ((unsigned)dotPos == Name.Len() - 1) { Name.DeleteBack(); BaseExtension.Empty(); return; } const UString ext = Name.Ptr(dotPos + 1); if (BaseExtension.IsEqualToNoCase(ext)) { BaseExtension = ext; Name.DeleteFrom(dotPos); } else BaseExtension.Empty(); } UString CArchivePath::GetFinalPath() const { UString path = GetPathWithoutExt(); if (!BaseExtension.IsEmpty()) path += UString(L'.') + BaseExtension; return path; } UString CArchivePath::GetFinalVolPath() const { UString path = GetPathWithoutExt(); if (!BaseExtension.IsEmpty()) path += UString(L'.') + VolExtension; return path; } FString CArchivePath::GetTempPath() const { FString path = TempPrefix + us2fs(Name); if (!BaseExtension.IsEmpty()) path += FString(FTEXT('.')) + us2fs(BaseExtension); path += FTEXT(".tmp"); path += TempPostfix; return path; } static const wchar_t *kDefaultArcType = L"7z"; static const wchar_t *kDefaultArcExt = L"7z"; static const wchar_t *kSFXExtension = #ifdef _WIN32 L"exe"; #else L""; #endif bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath) { if (types.Size() > 1) return false; // int arcTypeIndex = -1; if (types.Size() != 0) { MethodMode.Type = types[0]; MethodMode.Type_Defined = true; } if (MethodMode.Type.FormatIndex < 0) { // MethodMode.Type = -1; MethodMode.Type = COpenType(); if (ArcNameMode != k_ArcNameMode_Add) { MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); if (MethodMode.Type.FormatIndex >= 0) MethodMode.Type_Defined = true; } } return true; } bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) { UString typeExt; int formatIndex = MethodMode.Type.FormatIndex; if (formatIndex < 0) { typeExt = kDefaultArcExt; } else { const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; if (!arcInfo.UpdateEnabled) return false; typeExt = arcInfo.GetMainExt(); } UString ext = typeExt; if (SfxMode) ext = kSFXExtension; ArchivePath.BaseExtension = ext; ArchivePath.VolExtension = typeExt; ArchivePath.ParseFromPath(arcPath, ArcNameMode); FOR_VECTOR (i, Commands) { CUpdateArchiveCommand &uc = Commands[i]; uc.ArchivePath.BaseExtension = ext; uc.ArchivePath.VolExtension = typeExt; uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); } return true; } /* struct CUpdateProduceCallbackImp: public IUpdateProduceCallback { const CObjectVector *_arcItems; IUpdateCallbackUI *_callback; CUpdateProduceCallbackImp(const CObjectVector *a, IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} virtual HRESULT ShowDeleteFile(int arcIndex); }; HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) { return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); } */ bool CRenamePair::Prepare() { if (RecursedType != NRecursedType::kNonRecursed) return false; if (!WildcardParsing) return true; return !DoesNameContainWildcard(OldName); } extern bool g_CaseSensitive; static int CompareTwoNames(const wchar_t *s1, const wchar_t *s2) { for (int i = 0;; i++) { wchar_t c1 = s1[i]; wchar_t c2 = s2[i]; if (c1 == 0 || c2 == 0) return i; if (c1 == c2) continue; if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) continue; if (IsCharDirLimiter(c1) && IsCharDirLimiter(c2)) continue; return i; } } bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const { int num = CompareTwoNames(OldName, src); if (OldName[num] == 0) { if (src[num] != 0 && !IsCharDirLimiter(src[num]) && num != 0 && !IsCharDirLimiter(src[num - 1])) return false; } else { // OldName[num] != 0 // OldName = "1\1a.txt" // src = "1" if (!isFolder || src[num] != 0 || !IsCharDirLimiter(OldName[num]) || OldName[num + 1] != 0) return false; } dest = NewName + src.Ptr(num); return true; } static int GetReverseSlashPos(const UString &name) { int slashPos = name.ReverseFind(L'/'); #ifdef _WIN32 int slash1Pos = name.ReverseFind(L'\\'); slashPos = MyMax(slashPos, slash1Pos); #endif return slashPos; } static HRESULT Compress( const CUpdateOptions &options, CCodecs *codecs, const CActionSet &actionSet, const CArc *arc, CArchivePath &archivePath, const CObjectVector &arcItems, Byte *processedItemsStatuses, const CDirItems &dirItems, const CDirItem *parentDirItem, CTempFiles &tempFiles, CUpdateErrorInfo &errorInfo, IUpdateCallbackUI *callback) { CMyComPtr outArchive; int formatIndex = options.MethodMode.Type.FormatIndex; if (arc) { formatIndex = arc->FormatIndex; if (formatIndex < 0) return E_NOTIMPL; CMyComPtr archive2 = arc->Archive; HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); if (result != S_OK) throw kUpdateIsNotSupoorted; } else { RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); #ifdef EXTERNAL_CODECS { CMyComPtr setCompressCodecsInfo; outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); } } #endif } if (outArchive == 0) throw kUpdateIsNotSupoorted; NFileTimeType::EEnum fileTimeType; UInt32 value; RINOK(outArchive->GetFileTimeType(&value)); switch (value) { case NFileTimeType::kWindows: case NFileTimeType::kUnix: case NFileTimeType::kDOS: fileTimeType = (NFileTimeType::EEnum)value; break; default: return E_FAIL; } { const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) return E_NOTIMPL; if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) return E_NOTIMPL; } CRecordVector updatePairs2; UStringVector newNames; if (options.RenamePairs.Size() != 0) { FOR_VECTOR (i, arcItems) { const CArcItem &ai = arcItems[i]; bool needRename = false; UString dest; if (ai.Censored) { FOR_VECTOR (j, options.RenamePairs) { const CRenamePair &rp = options.RenamePairs[j]; if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) { needRename = true; break; } if (ai.IsAltStream) { int colonPos = ai.Name.ReverseFind(':'); int slashPosPos = GetReverseSlashPos(ai.Name); if (colonPos > slashPosPos) { UString mainName = ai.Name.Left(colonPos); /* actually we must improve that code to support cases with folder renaming like: rn arc dir1\ dir2\ */ if (rp.GetNewPath(false, mainName, dest)) { needRename = true; dest += ':'; dest += ai.Name.Ptr(colonPos + 1); break; } } } } } CUpdatePair2 up2; up2.SetAs_NoChangeArcItem(ai.IndexInServer); if (needRename) { up2.NewProps = true; RINOK(arc->IsItemAnti(i, up2.IsAnti)); up2.NewNameIndex = newNames.Add(dest); } updatePairs2.Add(up2); } } else { CRecordVector updatePairs; GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! // CUpdateProduceCallbackImp upCallback(&arcItems, callback); UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */); } UInt32 numFiles = 0; FOR_VECTOR (i, updatePairs2) if (updatePairs2[i].NewData) numFiles++; RINOK(callback->SetNumFiles(numFiles)); CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; CMyComPtr updateCallback(updateCallbackSpec); updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; updateCallbackSpec->StdInMode = options.StdInMode; updateCallbackSpec->Callback = callback; if (arc) { // we set Archive to allow to transfer GetProperty requests back to DLL. updateCallbackSpec->Archive = arc->Archive; updateCallbackSpec->GetRawProps = arc->GetRawProps; updateCallbackSpec->GetRootProps = arc->GetRootProps; } updateCallbackSpec->DirItems = &dirItems; updateCallbackSpec->ParentDirItem = parentDirItem; updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; updateCallbackSpec->ArcItems = &arcItems; updateCallbackSpec->UpdatePairs = &updatePairs2; updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; if (options.RenamePairs.Size() != 0) updateCallbackSpec->NewNames = &newNames; CMyComPtr outSeekStream; CMyComPtr outStream; if (!options.StdOutMode) { FString dirPrefix; if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) throw 1417161; CreateComplexDir(dirPrefix); } COutFileStream *outStreamSpec = NULL; COutMultiVolStream *volStreamSpec = NULL; if (options.VolumesSizes.Size() == 0) { if (options.StdOutMode) outStream = new CStdOutFileStream; else { outStreamSpec = new COutFileStream; outSeekStream = outStreamSpec; outStream = outSeekStream; bool isOK = false; FString realPath; for (int i = 0; i < (1 << 16); i++) { if (archivePath.Temp) { if (i > 0) { FChar s[16]; ConvertUInt32ToString(i, s); archivePath.TempPostfix = s; } realPath = archivePath.GetTempPath(); } else realPath = us2fs(archivePath.GetFinalPath()); if (outStreamSpec->Create(realPath, false)) { tempFiles.Paths.Add(realPath); isOK = true; break; } if (::GetLastError() != ERROR_FILE_EXISTS) break; if (!archivePath.Temp) break; } if (!isOK) { errorInfo.SystemError = ::GetLastError(); errorInfo.FileName = realPath; errorInfo.Message = L"7-Zip cannot open file"; return E_FAIL; } } } else { if (options.StdOutMode) return E_FAIL; if (arc && arc->GetGlobalOffset() > 0) return E_NOTIMPL; volStreamSpec = new COutMultiVolStream; outSeekStream = volStreamSpec; outStream = outSeekStream; volStreamSpec->Sizes = options.VolumesSizes; volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath() + L"."); volStreamSpec->TempFiles = &tempFiles; volStreamSpec->Init(); /* updateCallbackSpec->VolumesSizes = volumesSizes; updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; if (!archivePath.VolExtension.IsEmpty()) updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension; */ } RINOK(SetProperties(outArchive, options.MethodMode.Properties)); if (options.SfxMode) { CInFileStream *sfxStreamSpec = new CInFileStream; CMyComPtr sfxStream(sfxStreamSpec); if (!sfxStreamSpec->Open(options.SfxModule)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot open SFX module"; errorInfo.FileName = options.SfxModule; return E_FAIL; } CMyComPtr sfxOutStream; COutFileStream *outStreamSpec = NULL; if (options.VolumesSizes.Size() == 0) sfxOutStream = outStream; else { outStreamSpec = new COutFileStream; sfxOutStream = outStreamSpec; FString realPath = us2fs(archivePath.GetFinalPath()); if (!outStreamSpec->Create(realPath, false)) { errorInfo.SystemError = ::GetLastError(); errorInfo.FileName = realPath; errorInfo.Message = L"7-Zip cannot open file"; return E_FAIL; } } RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); if (outStreamSpec) { RINOK(outStreamSpec->Close()); } } CMyComPtr tailStream; if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) tailStream = outStream; else { // Int64 globalOffset = arc->GetGlobalOffset(); RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); if (options.StdOutMode) tailStream = outStream; else { CTailOutStream *tailStreamSpec = new CTailOutStream; tailStream = tailStreamSpec; tailStreamSpec->Stream = outSeekStream; tailStreamSpec->Offset = arc->ArcStreamOffset; tailStreamSpec->Init(); } } HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); callback->Finilize(); RINOK(result); if (options.SetArcMTime) { FILETIME ft; ft.dwLowDateTime = 0; ft.dwHighDateTime = 0; FOR_VECTOR (i, updatePairs2) { CUpdatePair2 &pair2 = updatePairs2[i]; const FILETIME *ft2 = NULL; if (pair2.NewProps && pair2.DirIndex >= 0) ft2 = &dirItems.Items[pair2.DirIndex].MTime; else if (pair2.UseArcProps && pair2.ArcIndex >= 0) ft2 = &arcItems[pair2.ArcIndex].MTime; if (ft2) { if (::CompareFileTime(&ft, ft2) < 0) ft = *ft2; } } if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) { if (outStreamSpec) outStreamSpec->SetMTime(&ft); else if (volStreamSpec) volStreamSpec->SetMTime(&ft);; } } if (outStreamSpec) result = outStreamSpec->Close(); else if (volStreamSpec) result = volStreamSpec->Close(); return result; } static HRESULT EnumerateInArchiveItems( // bool storeStreamsMode, const NWildcard::CCensor &censor, const CArc &arc, CObjectVector &arcItems) { arcItems.Clear(); UInt32 numItems; IInArchive *archive = arc.Archive; RINOK(archive->GetNumberOfItems(&numItems)); arcItems.ClearAndReserve(numItems); for (UInt32 i = 0; i < numItems; i++) { CArcItem ai; RINOK(arc.GetItemPath(i, ai.Name)); RINOK(Archive_IsItem_Folder(archive, i, ai.IsDir)); RINOK(Archive_IsItem_AltStream(archive, i, ai.IsAltStream)); /* if (!storeStreamsMode && ai.IsAltStream) continue; */ ai.Censored = censor.CheckPath(ai.IsAltStream, ai.Name, !ai.IsDir); RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); { CPropVariant prop; RINOK(archive->GetProperty(i, kpidTimeType, &prop)); if (prop.vt == VT_UI4) { ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; switch (ai.TimeType) { case NFileTimeType::kWindows: case NFileTimeType::kUnix: case NFileTimeType::kDOS: break; default: return E_FAIL; } } } ai.IndexInServer = i; arcItems.AddInReserved(ai); } return S_OK; } struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback { IUpdateCallbackUI2 *Callback; HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) { return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); } }; #if defined(_WIN32) && !defined(UNDER_CE) #include #endif struct CRefSortPair { int Len; int Index; }; #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *) { RINOZ(-MyCompare(a1->Len, a2->Len)); return MyCompare(a1->Index, a2->Index); } static int GetNumSlashes(const FChar *s) { for (int numSlashes = 0;;) { FChar c = *s++; if (c == 0) return numSlashes; if ( #ifdef _WIN32 c == FTEXT('\\') || #endif c == FTEXT('/')) numSlashes++; } } #ifdef _WIN32 void ConvertToLongNames(NWildcard::CCensor &censor); #endif HRESULT UpdateArchive( CCodecs *codecs, const CObjectVector &types, const UString &cmdArcPath2, NWildcard::CCensor &censor, CUpdateOptions &options, CUpdateErrorInfo &errorInfo, IOpenCallbackUI *openCallback, IUpdateCallbackUI2 *callback, bool needSetPath) { if (options.StdOutMode && options.EMailMode) return E_FAIL; if (types.Size() > 1) return E_NOTIMPL; bool renameMode = !options.RenamePairs.IsEmpty(); if (renameMode) { if (options.Commands.Size() != 1) return E_FAIL; } if (options.DeleteAfterCompressing) { if (options.Commands.Size() != 1) return E_NOTIMPL; const CActionSet &as = options.Commands[0].ActionSet; for (int i = 2; i < NPairState::kNumValues; i++) if (as.StateActions[i] != NPairAction::kCompress) return E_NOTIMPL; } censor.AddPathsToCensor(options.PathMode); #ifdef _WIN32 ConvertToLongNames(censor); #endif censor.ExtendExclude(); if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) return E_NOTIMPL; if (options.SfxMode) { CProperty property; property.Name = L"rsfx"; property.Value = L"on"; options.MethodMode.Properties.Add(property); if (options.SfxModule.IsEmpty()) { errorInfo.Message = L"SFX file is not specified"; return E_FAIL; } bool found = false; if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) { const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule; if (NFind::DoesFileExist(fullName)) { options.SfxModule = fullName; found = true; } } if (!found) { if (!NFind::DoesFileExist(options.SfxModule)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find specified SFX module"; errorInfo.FileName = options.SfxModule; return E_FAIL; } } } CArchiveLink arcLink; if (needSetPath) { if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || !options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } UString arcPath = options.ArchivePath.GetFinalPath(); if (cmdArcPath2.IsEmpty()) { if (options.MethodMode.Type.FormatIndex < 0) throw "type of archive is not specified"; } else { NFind::CFileInfo fi; if (!fi.Find(us2fs(arcPath))) { if (renameMode) throw "can't find archive";; if (options.MethodMode.Type.FormatIndex < 0) { if (!options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } } else { if (fi.IsDir()) throw "there is no such archive"; if (fi.IsDevice) return E_NOTIMPL; if (options.VolumesSizes.Size() > 0) return E_NOTIMPL; CObjectVector types; // change it. if (options.MethodMode.Type_Defined) types.Add(options.MethodMode.Type); // We need to set Properties to open archive only in some cases (WIM archives). CIntVector excl; COpenOptions op; #ifndef _SFX op.props = &options.MethodMode.Properties; #endif op.codecs = codecs; op.types = &types; op.excludedFormats = ! op.stdInMode = false; op.stream = NULL; op.filePath = arcPath; HRESULT result = arcLink.Open2(op, openCallback); if (result == E_ABORT) return result; const wchar_t *errorArcType = NULL; if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex > 0) errorArcType = codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name; RINOK(callback->OpenResult(arcPath, result, errorArcType)); /* if (result == S_FALSE) return E_FAIL; */ RINOK(result); if (arcLink.VolumePaths.Size() > 1) { errorInfo.SystemError = (DWORD)E_NOTIMPL; errorInfo.Message = L"Updating for multivolume archives is not implemented"; return E_NOTIMPL; } CArc &arc = arcLink.Arcs.Back(); arc.MTimeDefined = !fi.IsDevice; arc.MTime = fi.MTime; if (arc.ErrorInfo.ThereIsTail) { errorInfo.SystemError = (DWORD)E_NOTIMPL; errorInfo.Message = L"There is some data block after the end of the archive"; return E_NOTIMPL; } if (options.MethodMode.Type.FormatIndex < 0) { options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; if (!options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } } } if (options.MethodMode.Type.FormatIndex < 0) { options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArcType); if (options.MethodMode.Type.FormatIndex < 0) return E_NOTIMPL; } bool thereIsInArchive = arcLink.IsOpen; if (!thereIsInArchive && renameMode) return E_FAIL; CDirItems dirItems; CDirItem parentDirItem; CDirItem *parentDirItem_Ptr = NULL; /* FStringVector requestedPaths; FStringVector *requestedPaths_Ptr = NULL; if (options.DeleteAfterCompressing) requestedPaths_Ptr = &requestedPaths; */ if (options.StdInMode) { CDirItem di; di.Name = options.StdInFileName; di.Size = (UInt64)(Int64)-1; di.Attrib = 0; NTime::GetCurUtcFileTime(di.MTime); di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } else { bool needScanning = false; if (!renameMode) FOR_VECTOR (i, options.Commands) if (options.Commands[i].ActionSet.NeedScanning()) needScanning = true; if (needScanning) { CEnumDirItemUpdateCallback enumCallback; enumCallback.Callback = callback; RINOK(callback->StartScanning()); dirItems.SymLinks = options.SymLinks.Val; #if defined(_WIN32) && !defined(UNDER_CE) dirItems.ReadSecure = options.NtSecurity.Val; #endif dirItems.ScanAltStreams = options.AltStreams.Val; HRESULT res = EnumerateItems(censor, options.PathMode, options.AddPathPrefix, dirItems, &enumCallback); FOR_VECTOR (i, dirItems.ErrorPaths) { RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); } if (res != S_OK) { if (res != E_ABORT) errorInfo.Message = L"Scanning error"; return res; } RINOK(callback->FinishScanning()); if (censor.Pairs.Size() == 1) { NFind::CFileInfo fi; FString prefix = us2fs(censor.Pairs[0].Prefix) + FTEXT("."); // UString prefix = censor.Pairs[0].Prefix; /* if (prefix.Back() == WCHAR_PATH_SEPARATOR) { prefix.DeleteBack(); } */ if (fi.Find(prefix)) if (fi.IsDir()) { parentDirItem.Size = fi.Size; parentDirItem.CTime = fi.CTime; parentDirItem.ATime = fi.ATime; parentDirItem.MTime = fi.MTime; parentDirItem.Attrib = fi.Attrib; parentDirItem_Ptr = &parentDirItem; int secureIndex = -1; #if defined(_WIN32) && !defined(UNDER_CE) if (options.NtSecurity.Val) dirItems.AddSecurityItem(prefix, secureIndex); #endif parentDirItem.SecureIndex = secureIndex; parentDirItem_Ptr = &parentDirItem; } } } } FString tempDirPrefix; bool usesTempDir = false; #ifdef _WIN32 CTempDir tempDirectory; if (options.EMailMode && options.EMailRemoveAfter) { tempDirectory.Create(kTempFolderPrefix); tempDirPrefix = tempDirectory.GetPath(); NormalizeDirPathPrefix(tempDirPrefix); usesTempDir = true; } #endif CTempFiles tempFiles; bool createTempFile = false; if (!options.StdOutMode && options.UpdateArchiveItself) { CArchivePath &ap = options.Commands[0].ArchivePath; ap = options.ArchivePath; // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) { createTempFile = true; ap.Temp = true; if (!options.WorkingDir.IsEmpty()) ap.TempPrefix = options.WorkingDir; else ap.TempPrefix = us2fs(ap.Prefix); NormalizeDirPathPrefix(ap.TempPrefix); } } unsigned i; for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; if (usesTempDir) { // Check it ap.Prefix = fs2us(tempDirPrefix); // ap.Temp = true; // ap.TempPrefix = tempDirPrefix; } if (!options.StdOutMode && (i > 0 || !createTempFile)) { const FString path = us2fs(ap.GetFinalPath()); if (NFind::DoesFileOrDirExist(path)) { errorInfo.SystemError = 0; errorInfo.Message = L"The file already exists"; errorInfo.FileName = path; return E_FAIL; } } } CObjectVector arcItems; if (thereIsInArchive) { RINOK(EnumerateInArchiveItems( // options.StoreAltStreams, censor, arcLink.Arcs.Back(), arcItems)); } /* FStringVector processedFilePaths; FStringVector *processedFilePaths_Ptr = NULL; if (options.DeleteAfterCompressing) processedFilePaths_Ptr = &processedFilePaths; */ CByteBuffer processedItems; if (options.DeleteAfterCompressing) { unsigned num = dirItems.Items.Size(); processedItems.Alloc(num); for (i = 0; i < num; i++) processedItems[i] = 0; } for (i = 0; i < options.Commands.Size(); i++) { const CArc *arc = thereIsInArchive ? arcLink.GetArc() : 0; // IInArchiveExtra *archiveExtra = thereIsInArchive ? arcLink.GetArchiveExtra() : 0; // IArchiveGetRootProps *archiveGetRootProps = thereIsInArchive ? arcLink.GetArchiveGetRootProps() : 0; CUpdateArchiveCommand &command = options.Commands[i]; UString name; bool isUpdating; if (options.StdOutMode) { name = L"stdout"; isUpdating = arc != 0; } else { name = command.ArchivePath.GetFinalPath(); isUpdating = (i == 0 && options.UpdateArchiveItself && arc != 0); } RINOK(callback->StartArchive(name, isUpdating)) RINOK(Compress(options, codecs, command.ActionSet, arc, command.ArchivePath, arcItems, options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, dirItems, parentDirItem_Ptr, tempFiles, errorInfo, callback)); RINOK(callback->FinishArchive()); } if (thereIsInArchive) { RINOK(arcLink.Close()); arcLink.Release(); } tempFiles.Paths.Clear(); if (createTempFile) { try { CArchivePath &ap = options.Commands[0].ArchivePath; const FString &tempPath = ap.GetTempPath(); if (thereIsInArchive) if (!DeleteFileAlways(us2fs(arcPath))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot delete the file"; errorInfo.FileName = us2fs(arcPath); return E_FAIL; } if (!MyMoveFile(tempPath, us2fs(arcPath))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot move the file"; errorInfo.FileName = tempPath; errorInfo.FileName2 = us2fs(arcPath); return E_FAIL; } } catch(...) { throw; } } #if defined(_WIN32) && !defined(UNDER_CE) if (options.EMailMode) { NDLL::CLibrary mapiLib; if (!mapiLib.Load(FTEXT("Mapi32.dll"))) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot load Mapi32.dll"; return E_FAIL; } /* LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); if (fnSend == 0) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function"; return E_FAIL; } */ LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); if (sendMail == 0) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"7-Zip cannot find MAPISendMail function"; return E_FAIL; } FStringVector fullPaths; unsigned i; for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; FString arcPath; if (!MyGetFullPathName(us2fs(ap.GetFinalPath()), arcPath)) { errorInfo.SystemError = ::GetLastError(); errorInfo.Message = L"GetFullPathName error"; return E_FAIL; } fullPaths.Add(arcPath); } CCurrentDirRestorer curDirRestorer; for (i = 0; i < fullPaths.Size(); i++) { UString arcPath = fs2us(fullPaths[i]); UString fileName = ExtractFileNameFromPath(arcPath); AString path = GetAnsiString(arcPath); AString name = GetAnsiString(fileName); // Warning!!! MAPISendDocuments function changes Current directory // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); MapiFileDesc f; memset(&f, 0, sizeof(f)); f.nPosition = 0xFFFFFFFF; f.lpszPathName = (char *)(const char *)path; f.lpszFileName = (char *)(const char *)name; MapiMessage m; memset(&m, 0, sizeof(m)); m.nFileCount = 1; m.lpFiles = &f; const AString addr = GetAnsiString(options.EMailAddress); MapiRecipDesc rec; if (!addr.IsEmpty()) { memset(&rec, 0, sizeof(rec)); rec.ulRecipClass = MAPI_TO; rec.lpszAddress = (char *)(const char *)addr; m.nRecipCount = 1; m.lpRecips = &rec; } sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); } } #endif if (options.DeleteAfterCompressing) { CRecordVector pairs; FStringVector foldersNames; for (i = 0; i < dirItems.Items.Size(); i++) { const CDirItem &dirItem = dirItems.Items[i]; FString phyPath = us2fs(dirItems.GetPhyPath(i)); if (dirItem.IsDir()) { CRefSortPair pair; pair.Index = i; pair.Len = GetNumSlashes(phyPath); pairs.Add(pair); } else { if (processedItems[i] != 0 || dirItem.Size == 0) { DeleteFileAlways(phyPath); } else { // file was skipped /* errorInfo.SystemError = 0; errorInfo.Message = L"file was not processed"; errorInfo.FileName = phyPath; return E_FAIL; */ } } } pairs.Sort(CompareRefSortPair, NULL); for (i = 0; i < pairs.Size(); i++) { FString phyPath = us2fs(dirItems.GetPhyPath(pairs[i].Index)); if (NFind::DoesDirExist(phyPath)) { // printf("delete %S\n", phyPath); RemoveDir(phyPath); } } } return S_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h0100777000000000000000000001032013761647206022755 0ustar00// Update.h #ifndef __COMMON_UPDATE_H #define __COMMON_UPDATE_H #include "../../../Common/Wildcard.h" #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "OpenArchive.h" #include "Property.h" #include "UpdateAction.h" #include "UpdateCallback.h" enum EArcNameMode { k_ArcNameMode_Smart, k_ArcNameMode_Exact, k_ArcNameMode_Add, }; struct CArchivePath { UString OriginalPath; UString Prefix; // path(folder) prefix including slash UString Name; // base name UString BaseExtension; // archive type extension or "exe" extension UString VolExtension; // archive type extension for volumes bool Temp; FString TempPrefix; // path(folder) for temp location FString TempPostfix; CArchivePath(): Temp(false) {}; void ParseFromPath(const UString &path, EArcNameMode mode); UString GetPathWithoutExt() const { return Prefix + Name; } UString GetFinalPath() const; UString GetFinalVolPath() const; FString GetTempPath() const; }; struct CUpdateArchiveCommand { UString UserArchivePath; CArchivePath ArchivePath; NUpdateArchive::CActionSet ActionSet; }; struct CCompressionMethodMode { bool Type_Defined; COpenType Type; CObjectVector Properties; CCompressionMethodMode(): Type_Defined(false) {} }; namespace NRecursedType { enum EEnum { kRecursed, kWildcardOnlyRecursed, kNonRecursed };} struct CRenamePair { UString OldName; UString NewName; bool WildcardParsing; NRecursedType::EEnum RecursedType; CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {} bool Prepare(); bool GetNewPath(bool isFolder, const UString &src, UString &dest) const; }; struct CUpdateOptions { CCompressionMethodMode MethodMode; CObjectVector Commands; bool UpdateArchiveItself; CArchivePath ArchivePath; EArcNameMode ArcNameMode; bool SfxMode; FString SfxModule; bool OpenShareForWrite; bool StdInMode; UString StdInFileName; bool StdOutMode; bool EMailMode; bool EMailRemoveAfter; UString EMailAddress; FString WorkingDir; NWildcard::ECensorPathMode PathMode; UString AddPathPrefix; CBoolPair NtSecurity; CBoolPair AltStreams; CBoolPair HardLinks; CBoolPair SymLinks; bool DeleteAfterCompressing; bool SetArcMTime; CObjectVector RenamePairs; bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath); bool SetArcPath(const CCodecs *codecs, const UString &arcPath); CUpdateOptions(): UpdateArchiveItself(true), SfxMode(false), StdInMode(false), StdOutMode(false), EMailMode(false), EMailRemoveAfter(false), OpenShareForWrite(false), ArcNameMode(k_ArcNameMode_Smart), PathMode(NWildcard::k_RelatPath), DeleteAfterCompressing(false), SetArcMTime(false) {}; void SetActionCommand_Add() { Commands.Clear(); CUpdateArchiveCommand c; c.ActionSet = NUpdateArchive::k_ActionSet_Add; Commands.Add(c); } CRecordVector VolumesSizes; }; struct CErrorInfo { DWORD SystemError; FString FileName; FString FileName2; UString Message; // UStringVector ErrorPaths; // CRecordVector ErrorCodes; CErrorInfo(): SystemError(0) {}; }; struct CUpdateErrorInfo: public CErrorInfo { }; #define INTERFACE_IUpdateCallbackUI2(x) \ INTERFACE_IUpdateCallbackUI(x) \ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, const wchar_t *errorArcType) x; \ virtual HRESULT StartScanning() x; \ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT FinishScanning() x; \ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \ virtual HRESULT FinishArchive() x; \ struct IUpdateCallbackUI2: public IUpdateCallbackUI { INTERFACE_IUpdateCallbackUI2(=0) }; HRESULT UpdateArchive( CCodecs *codecs, const CObjectVector &types, const UString &cmdArcPath2, NWildcard::CCensor &censor, CUpdateOptions &options, CUpdateErrorInfo &errorInfo, IOpenCallbackUI *openCallback, IUpdateCallbackUI2 *callback, bool needSetPath); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp0100777000000000000000000000220513761647206024451 0ustar00// UpdateAction.cpp #include "StdAfx.h" #include "UpdateAction.h" namespace NUpdateArchive { const CActionSet k_ActionSet_Add = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress, NPairAction::kCompress }}; const CActionSet k_ActionSet_Update = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress }}; const CActionSet k_ActionSet_Fresh = {{ NPairAction::kCopy, NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress }}; const CActionSet k_ActionSet_Sync = {{ NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, NPairAction::kCopy, NPairAction::kCompress, }}; const CActionSet k_ActionSet_Delete = {{ NPairAction::kCopy, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore, NPairAction::kIgnore }}; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h0100777000000000000000000000251213761647206024117 0ustar00// UpdateAction.h #ifndef __UPDATE_ACTION_H #define __UPDATE_ACTION_H namespace NUpdateArchive { namespace NPairState { const unsigned kNumValues = 7; enum EEnum { kNotMasked = 0, kOnlyInArchive, kOnlyOnDisk, kNewInArchive, kOldInArchive, kSameFiles, kUnknowNewerFiles }; } namespace NPairAction { enum EEnum { kIgnore = 0, kCopy, kCompress, kCompressAsAnti }; } struct CActionSet { NPairAction::EEnum StateActions[NPairState::kNumValues]; const bool IsEqualTo(const CActionSet &a) const { for (unsigned i = 0; i < NPairState::kNumValues; i++) if (StateActions[i] != a.StateActions[i]) return false; return true; } bool NeedScanning() const { unsigned i; for (i = 0; i < NPairState::kNumValues; i++) if (StateActions[i] == NPairAction::kCompress) return true; for (i = 1; i < NPairState::kNumValues; i++) if (StateActions[i] != NPairAction::kIgnore) return true; return false; } }; extern const CActionSet k_ActionSet_Add; extern const CActionSet k_ActionSet_Update; extern const CActionSet k_ActionSet_Fresh; extern const CActionSet k_ActionSet_Sync; extern const CActionSet k_ActionSet_Delete; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp0100777000000000000000000003414313761647206024736 0ustar00// UpdateCallback.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/Synchronization.h" #include "../../Common/FileStreams.h" #include "../../Common/StreamObjects.h" #include "UpdateCallback.h" #if defined(_WIN32) && !defined(UNDER_CE) #define _USE_SECURITY_CODE #include "../../../Windows/SecurityUtils.h" #endif using namespace NWindows; using namespace NFile; #ifdef _USE_SECURITY_CODE bool InitLocalPrivileges(); #endif CArchiveUpdateCallback::CArchiveUpdateCallback(): Callback(0), ShareForWrite(false), StdInMode(false), DirItems(0), ArcItems(0), UpdatePairs(0), NewNames(0), KeepOriginalItemNames(false), ProcessedItemsStatuses(NULL), ParentDirItem(NULL), StoreNtSecurity(false), StoreHardLinks(false), StoreSymLinks(false), _hardIndex_From((UInt32)(Int32)-1) { #ifdef _USE_SECURITY_CODE _saclEnabled = InitLocalPrivileges(); #endif } STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size) { COM_TRY_BEGIN return Callback->SetTotal(size); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue) { COM_TRY_BEGIN return Callback->SetCompleted(completeValue); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { COM_TRY_BEGIN return Callback->SetRatioInfo(inSize, outSize); COM_TRY_END } /* static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, { NULL, kpidSize, VT_UI8}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidAttrib, VT_UI4}, { NULL, kpidIsAnti, VT_BOOL} }; STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) { return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator); } */ STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) { COM_TRY_BEGIN RINOK(Callback->CheckBreak()); const CUpdatePair2 &up = (*UpdatePairs)[index]; if (newData) *newData = BoolToInt(up.NewData); if (newProps) *newProps = BoolToInt(up.NewProps); if (indexInArchive) { *indexInArchive = (UInt32)(Int32)-1; if (up.ExistInArchive()) *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer; } return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidIsDir: prop = true; break; case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; } prop.Detach(value); return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) { *parentType = NParentType::kDir; *parent = (UInt32)(Int32)-1; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps) { *numProps = 0; if (StoreNtSecurity) *numProps = 1; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) { *name = NULL; *propID = kpidNtSecure; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID #ifdef _USE_SECURITY_CODE propID #endif , const void **data, UInt32 *dataSize, UInt32 *propType) { *data = 0; *dataSize = 0; *propType = 0; if (!StoreNtSecurity) return S_OK; #ifdef _USE_SECURITY_CODE if (propID == kpidNtSecure) { if (StdInMode) return S_OK; if (ParentDirItem) { if (ParentDirItem->SecureIndex < 0) return S_OK; const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex]; *data = buf; *dataSize = (UInt32)buf.Size(); *propType = NPropDataType::kRaw; return S_OK; } if (GetRootProps) return GetRootProps->GetRootRawProp(propID, data, dataSize, propType); } #endif return S_OK; } // #ifdef _USE_SECURITY_CODE // #endif STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) { *data = 0; *dataSize = 0; *propType = 0; if (propID == kpidNtSecure || propID == kpidNtReparse) { if (StdInMode) return S_OK; const CUpdatePair2 &up = (*UpdatePairs)[index]; if (up.UseArcProps && up.ExistInArchive() && GetRawProps) return GetRawProps->GetRawProp( ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, data, dataSize, propType); { const CUpdatePair2 &up = (*UpdatePairs)[index]; /* if (!up.NewData) return E_FAIL; */ if (up.IsAnti) return S_OK; #ifndef UNDER_CE const CDirItem &di = DirItems->Items[up.DirIndex]; #endif #ifdef _USE_SECURITY_CODE if (propID == kpidNtSecure) { if (!StoreNtSecurity) return S_OK; if (di.SecureIndex < 0) return S_OK; const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex]; *data = buf; *dataSize = (UInt32)buf.Size(); *propType = NPropDataType::kRaw; } else #endif { // propID == kpidNtReparse if (!StoreSymLinks) return S_OK; #ifndef UNDER_CE const CByteBuffer *buf = &di.ReparseData2; if (buf->Size() == 0) buf = &di.ReparseData; if (buf->Size() != 0) { *data = *buf; *dataSize = (UInt32)buf->Size(); *propType = NPropDataType::kRaw; } #endif } return S_OK; } } return S_OK; } #ifndef UNDER_CE static UString GetRelativePath(const UString &to, const UString &from) { UStringVector partsTo, partsFrom; SplitPathToParts(to, partsTo); SplitPathToParts(from, partsFrom); unsigned i; for (i = 0;; i++) { if (i + 1 >= partsFrom.Size() || i + 1 >= partsTo.Size()) break; if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) break; } if (i == 0) { #ifdef _WIN32 if (NName::IsDrivePath(to) || NName::IsDrivePath(from)) return to; #endif } UString s; unsigned k; for (k = i + 1; k < partsFrom.Size(); k++) s += L".." WSTRING_PATH_SEPARATOR; for (k = i; k < partsTo.Size(); k++) { if (k != i) s += WCHAR_PATH_SEPARATOR; s += partsTo[k]; } return s; } #endif STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN const CUpdatePair2 &up = (*UpdatePairs)[index]; NCOM::CPropVariant prop; if (up.NewData) { /* if (propID == kpidIsHardLink) { prop = _isHardLink; prop.Detach(value); return S_OK; } */ if (propID == kpidSymLink) { if (index == _hardIndex_From) { prop.Detach(value); return S_OK; } if (up.DirIndex >= 0) { #ifndef UNDER_CE const CDirItem &di = DirItems->Items[up.DirIndex]; // if (di.IsDir()) { CReparseAttr attr; if (attr.Parse(di.ReparseData, di.ReparseData.Size())) { UString simpleName = attr.GetPath(); if (attr.IsRelative()) prop = simpleName; else { const UString phyPath = DirItems->GetPhyPath(up.DirIndex); FString fullPath; if (NDir::MyGetFullPathName(us2fs(phyPath), fullPath)) { prop = GetRelativePath(simpleName, fs2us(fullPath)); } } prop.Detach(value); return S_OK; } } #endif } } else if (propID == kpidHardLink) { if (index == _hardIndex_From) { const CKeyKeyValPair &pair = _map[_hardIndex_To]; const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; prop = DirItems->GetLogPath(up2.DirIndex); prop.Detach(value); return S_OK; } if (up.DirIndex >= 0) { prop.Detach(value); return S_OK; } } } if (up.IsAnti && propID != kpidIsDir && propID != kpidPath && propID != kpidIsAltStream) { switch (propID) { case kpidSize: prop = (UInt64)0; break; case kpidIsAnti: prop = true; break; } } else if (propID == kpidPath && up.NewNameIndex >= 0) prop = (*NewNames)[up.NewNameIndex]; else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) { // we can generate new ShortName here; } else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) && up.ExistInArchive() && Archive) return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value); else if (up.ExistOnDisk()) { const CDirItem &di = DirItems->Items[up.DirIndex]; switch (propID) { case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break; case kpidIsDir: prop = di.IsDir(); break; case kpidSize: prop = di.Size; break; case kpidAttrib: prop = di.Attrib; break; case kpidCTime: prop = di.CTime; break; case kpidATime: prop = di.ATime; break; case kpidMTime: prop = di.MTime; break; case kpidIsAltStream: prop = di.IsAltStream; break; #if defined(_WIN32) && !defined(UNDER_CE) // case kpidShortName: prop = di.ShortName; break; #endif } } prop.Detach(value); return S_OK; COM_TRY_END } static NSynchronization::CCriticalSection CS; STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) { COM_TRY_BEGIN *inStream = NULL; const CUpdatePair2 &up = (*UpdatePairs)[index]; if (!up.NewData) return E_FAIL; RINOK(Callback->CheckBreak()); RINOK(Callback->Finilize()); bool isDir = IsDir(up); if (up.IsAnti) { UString name; if (up.ArcIndex >= 0) name = (*ArcItems)[up.ArcIndex].Name; else if (up.DirIndex >= 0) name = DirItems->GetLogPath(up.DirIndex); RINOK(Callback->GetStream(name, true)); /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. so we return empty stream */ if (!isDir) { CBufInStream *inStreamSpec = new CBufInStream(); CMyComPtr inStreamLoc = inStreamSpec; inStreamSpec->Init(NULL, 0); *inStream = inStreamLoc.Detach(); } return S_OK; } RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false)); if (isDir) return S_OK; if (StdInMode) { CStdInFileStream *inStreamSpec = new CStdInFileStream; CMyComPtr inStreamLoc(inStreamSpec); *inStream = inStreamLoc.Detach(); } else { CInFileStream *inStreamSpec = new CInFileStream; CMyComPtr inStreamLoc(inStreamSpec); inStreamSpec->SupportHardLinks = StoreHardLinks; const UString path = DirItems->GetPhyPath(up.DirIndex); #if defined(_WIN32) && !defined(UNDER_CE) if (DirItems->Items[up.DirIndex].AreReparseData()) { if (!inStreamSpec->File.OpenReparse(us2fs(path))) { return Callback->OpenFileError(path, ::GetLastError()); } } else #endif if (!inStreamSpec->OpenShared(us2fs(path), ShareForWrite)) { return Callback->OpenFileError(path, ::GetLastError()); } if (StoreHardLinks) { CStreamFileProps props; if (inStreamSpec->GetProps2(&props) == S_OK) { if (props.NumLinks > 1) { CKeyKeyValPair pair; pair.Key1 = props.VolID; pair.Key2 = props.FileID_Low; pair.Value = index; unsigned numItems = _map.Size(); unsigned pairIndex = _map.AddToUniqueSorted2(pair); if (numItems == _map.Size()) { // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; _hardIndex_From = index; _hardIndex_To = pairIndex; // we could return NULL as stream, but it's better to return real stream // return S_OK; } } } } if (ProcessedItemsStatuses) { NSynchronization::CCriticalSectionLock lock(CS); ProcessedItemsStatuses[up.DirIndex] = 1; } *inStream = inStreamLoc.Detach(); } return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult) { COM_TRY_BEGIN return Callback->SetOperationResult(operationResult); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) { if (VolumesSizes.Size() == 0) return S_FALSE; if (index >= (UInt32)VolumesSizes.Size()) index = VolumesSizes.Size() - 1; *size = VolumesSizes[index]; return S_OK; } STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream) { COM_TRY_BEGIN FChar temp[16]; ConvertUInt32ToString(index + 1, temp); FString res = temp; while (res.Len() < 2) res.InsertAtFront(FTEXT('0')); FString fileName = VolName; fileName += L'.'; fileName += res; fileName += VolExt; COutFileStream *streamSpec = new COutFileStream; CMyComPtr streamLoc(streamSpec); if (!streamSpec->Create(fileName, false)) return ::GetLastError(); *volumeStream = streamLoc.Detach(); return S_OK; COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) { COM_TRY_BEGIN return Callback->CryptoGetTextPassword2(passwordIsDefined, password); COM_TRY_END } STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN return Callback->CryptoGetTextPassword(password); COM_TRY_END } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h0100777000000000000000000000614313761647206024402 0ustar00// UpdateCallback.h #ifndef __UPDATE_CALLBACK_H #define __UPDATE_CALLBACK_H #include "../../../Common/MyCom.h" #include "../../IPassword.h" #include "../../ICoder.h" #include "../Common/UpdatePair.h" #include "../Common/UpdateProduce.h" #define INTERFACE_IUpdateCallbackUI(x) \ virtual HRESULT SetTotal(UInt64 size) x; \ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \ virtual HRESULT CheckBreak() x; \ virtual HRESULT Finilize() x; \ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ virtual HRESULT SetOperationResult(Int32 operationResult) x; \ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ /* virtual HRESULT ShowDeleteFile(const wchar_t *name) x; */ \ /* virtual HRESULT CloseProgress() { return S_OK; }; */ struct IUpdateCallbackUI { INTERFACE_IUpdateCallbackUI(=0) }; struct CKeyKeyValPair { UInt64 Key1; UInt64 Key2; unsigned Value; int Compare(const CKeyKeyValPair &a) const { if (Key1 < a.Key1) return -1; if (Key1 > a.Key1) return 1; return MyCompare(Key2, a.Key2); } }; class CArchiveUpdateCallback: public IArchiveUpdateCallback2, public IArchiveGetRawProps, public IArchiveGetRootProps, public ICryptoGetTextPassword2, public ICryptoGetTextPassword, public ICompressProgressInfo, public CMyUnknownImp { #if defined(_WIN32) && !defined(UNDER_CE) bool _saclEnabled; #endif CRecordVector _map; UInt32 _hardIndex_From; UInt32 _hardIndex_To; public: MY_UNKNOWN_IMP6( IArchiveUpdateCallback2, IArchiveGetRawProps, IArchiveGetRootProps, ICryptoGetTextPassword2, ICryptoGetTextPassword, ICompressProgressInfo) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); INTERFACE_IArchiveUpdateCallback2(;) INTERFACE_IArchiveGetRawProps(;) INTERFACE_IArchiveGetRootProps(;) STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); STDMETHOD(CryptoGetTextPassword)(BSTR *password); CRecordVector VolumesSizes; FString VolName; FString VolExt; IUpdateCallbackUI *Callback; bool ShareForWrite; bool StdInMode; const CDirItems *DirItems; const CDirItem *ParentDirItem; const CObjectVector *ArcItems; const CRecordVector *UpdatePairs; const UStringVector *NewNames; CMyComPtr Archive; CMyComPtr GetRawProps; CMyComPtr GetRootProps; bool KeepOriginalItemNames; bool StoreNtSecurity; bool StoreHardLinks; bool StoreSymLinks; Byte *ProcessedItemsStatuses; CArchiveUpdateCallback(); bool IsDir(const CUpdatePair2 &up) const { if (up.DirIndex >= 0) return DirItems->Items[up.DirIndex].IsDir(); else if (up.ArcIndex >= 0) return (*ArcItems)[up.ArcIndex].IsDir; return false; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp0100777000000000000000000001407113761647206024133 0ustar00// UpdatePair.cpp #include "StdAfx.h" #include #include "../../../Common/Wildcard.h" #include "../../../Windows/TimeUtils.h" #include "SortUtils.h" #include "UpdatePair.h" using namespace NWindows; using namespace NTime; static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2) { switch (fileTimeType) { case NFileTimeType::kWindows: return ::CompareFileTime(&time1, &time2); case NFileTimeType::kUnix: { UInt32 unixTime1, unixTime2; FileTimeToUnixTime(time1, unixTime1); FileTimeToUnixTime(time2, unixTime2); return MyCompare(unixTime1, unixTime2); } case NFileTimeType::kDOS: { UInt32 dosTime1, dosTime2; FileTimeToDosTime(time1, dosTime1); FileTimeToDosTime(time2, dosTime2); return MyCompare(dosTime1, dosTime2); } } throw 4191618; } static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:"; static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:"; static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; static void ThrowError(const char *message, const UString &s1, const UString &s2) { UString m; m.SetFromAscii(message); m += L'\n'; m += s1; m += L'\n'; m += s2; throw m; } static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) { int res = CompareFileNames(ai1.Name, ai2.Name); if (res != 0) return res; if (ai1.IsDir != ai2.IsDir) return ai1.IsDir ? -1 : 1; return 0; } static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) { unsigned i1 = *p1; unsigned i2 = *p2; const CObjectVector &arcItems = *(const CObjectVector *)param; int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); if (res != 0) return res; return MyCompare(i1, i2); } void GetUpdatePairInfoList( const CDirItems &dirItems, const CObjectVector &arcItems, NFileTimeType::EEnum fileTimeType, CRecordVector &updatePairs) { CUIntVector dirIndices, arcIndices; unsigned numDirItems = dirItems.Items.Size(); unsigned numArcItems = arcItems.Size(); CIntArr duplicatedArcItem(numArcItems); { int *vals = &duplicatedArcItem[0]; for (unsigned i = 0; i < numArcItems; i++) vals[i] = 0; } { arcIndices.ClearAndSetSize(numArcItems); { unsigned *vals = &arcIndices[0]; for (unsigned i = 0; i < numArcItems; i++) vals[i] = i; } arcIndices.Sort(CompareArcItems, (void *)&arcItems); for (unsigned i = 0; i + 1 < numArcItems; i++) if (CompareArcItemsBase( arcItems[arcIndices[i]], arcItems[arcIndices[i + 1]]) == 0) { duplicatedArcItem[i] = 1; duplicatedArcItem[i + 1] = -1; } } UStringVector dirNames; { dirNames.ClearAndReserve(numDirItems); unsigned i; for (i = 0; i < numDirItems; i++) dirNames.AddInReserved(dirItems.GetLogPath(i)); SortFileNames(dirNames, dirIndices); for (i = 0; i + 1 < numDirItems; i++) { const UString &s1 = dirNames[dirIndices[i]]; const UString &s2 = dirNames[dirIndices[i + 1]]; if (CompareFileNames(s1, s2) == 0) ThrowError(k_Duplicate_inDir_Message, s1, s2); } } unsigned dirIndex = 0; unsigned arcIndex = 0; int prevHostFile = -1; const UString *prevHostName = NULL; while (dirIndex < numDirItems || arcIndex < numArcItems) { CUpdatePair pair; int dirIndex2 = -1; int arcIndex2 = -1; const CDirItem *di = NULL; const CArcItem *ai = NULL; int compareResult = -1; const UString *name = NULL; if (dirIndex < numDirItems) { dirIndex2 = dirIndices[dirIndex]; di = &dirItems.Items[dirIndex2]; } if (arcIndex < numArcItems) { arcIndex2 = arcIndices[arcIndex]; ai = &arcItems[arcIndex2]; compareResult = 1; if (dirIndex < numDirItems) { compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name); if (compareResult == 0) { if (di->IsDir() != ai->IsDir) compareResult = (ai->IsDir ? 1 : -1); } } } if (compareResult < 0) { name = &dirNames[dirIndex2]; pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; pair.DirIndex = dirIndex2; dirIndex++; } else if (compareResult > 0) { name = &ai->Name; pair.State = ai->Censored ? NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked; pair.ArcIndex = arcIndex2; arcIndex++; } else { int dupl = duplicatedArcItem[arcIndex]; if (dupl != 0) ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name); name = &dirNames[dirIndex2]; if (!ai->Censored) ThrowError(k_NotCensoredCollision_Message, *name, ai->Name); pair.DirIndex = dirIndex2; pair.ArcIndex = arcIndex2; switch (ai->MTimeDefined ? MyCompareTime( ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType, di->MTime, ai->MTime): 0) { case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; default: pair.State = (ai->SizeDefined && di->Size == ai->Size) ? NUpdateArchive::NPairState::kSameFiles : NUpdateArchive::NPairState::kUnknowNewerFiles; } dirIndex++; arcIndex++; } if ((di && di->IsAltStream) || (ai && ai->IsAltStream)) { if (prevHostName) { unsigned hostLen = prevHostName->Len(); if (name->Len() > hostLen) if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) pair.HostIndex = prevHostFile; } } else { prevHostFile = updatePairs.Size(); prevHostName = name; } updatePairs.Add(pair); } updatePairs.ReserveDown(); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h0100777000000000000000000000111213761647206023570 0ustar00// UpdatePair.h #ifndef __UPDATE_PAIR_H #define __UPDATE_PAIR_H #include "DirItem.h" #include "UpdateAction.h" #include "../../Archive/IArchive.h" struct CUpdatePair { NUpdateArchive::NPairState::EEnum State; int ArcIndex; int DirIndex; int HostIndex; // >= 0 for alt streams only, contains index of host pair CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {} }; void GetUpdatePairInfoList( const CDirItems &dirItems, const CObjectVector &arcItems, NFileTimeType::EEnum fileTimeType, CRecordVector &updatePairs); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp0100777000000000000000000000365513761647206024647 0ustar00// UpdateProduce.cpp #include "StdAfx.h" #include "UpdateProduce.h" using namespace NUpdateArchive; static const char *kUpdateActionSetCollision = "Internal collision in update action set"; void UpdateProduce( const CRecordVector &updatePairs, const CActionSet &actionSet, CRecordVector &operationChain, IUpdateProduceCallback *callback) { FOR_VECTOR (i, updatePairs) { const CUpdatePair &pair = updatePairs[i]; CUpdatePair2 up2; up2.DirIndex = pair.DirIndex; up2.ArcIndex = pair.ArcIndex; up2.NewData = up2.NewProps = true; up2.UseArcProps = false; switch (actionSet.StateActions[pair.State]) { case NPairAction::kIgnore: /* if (pair.State != NPairState::kOnlyOnDisk) IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]); // cout << "deleting"; */ if (callback) callback->ShowDeleteFile(pair.ArcIndex); continue; case NPairAction::kCopy: if (pair.State == NPairState::kOnlyOnDisk) throw kUpdateActionSetCollision; if (pair.State == NPairState::kOnlyInArchive) { if (pair.HostIndex >= 0) { /* ignore alt stream if 1) no such alt stream in Disk 2) there is Host file in disk */ if (updatePairs[pair.HostIndex].DirIndex >= 0) continue; } } up2.NewData = up2.NewProps = false; up2.UseArcProps = true; break; case NPairAction::kCompress: if (pair.State == NPairState::kOnlyInArchive || pair.State == NPairState::kNotMasked) throw kUpdateActionSetCollision; break; case NPairAction::kCompressAsAnti: up2.IsAnti = true; up2.UseArcProps = (pair.ArcIndex >= 0); break; } operationChain.Add(up2); } operationChain.ReserveDown(); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h0100777000000000000000000000224113761647206024302 0ustar00// UpdateProduce.h #ifndef __UPDATE_PRODUCE_H #define __UPDATE_PRODUCE_H #include "UpdatePair.h" struct CUpdatePair2 { bool NewData; bool NewProps; bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties. bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status int DirIndex; int ArcIndex; int NewNameIndex; bool IsMainRenameItem; void SetAs_NoChangeArcItem(int arcIndex) { NewData = NewProps = false; UseArcProps = true; IsAnti = false; ArcIndex = arcIndex; } bool ExistOnDisk() const { return DirIndex != -1; } bool ExistInArchive() const { return ArcIndex != -1; } CUpdatePair2(): NewData(false), NewProps(false), UseArcProps(false), IsAnti(false), DirIndex(-1), ArcIndex(-1), NewNameIndex(-1), IsMainRenameItem(false) {} }; struct IUpdateProduceCallback { virtual HRESULT ShowDeleteFile(int arcIndex) = 0; }; void UpdateProduce( const CRecordVector &updatePairs, const NUpdateArchive::CActionSet &actionSet, CRecordVector &operationChain, IUpdateProduceCallback *callback); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Console/0040777000000000000000000000000013761647206021540 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Console/Console.pri0100777000000000000000000000025113761647206023654 0ustar00HEADERS += $$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.h \ $$7ZIP_BASE/CPP/7zip/UI/Common/StdAfx.h SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.cpp0100777000000000000000000000411313761647206025207 0ustar00// PercentPrinter.cpp #include "StdAfx.h" #include "../../../Common/Defs.h" #include "../../../Common/IntToString.h" #include "PercentPrinter.h" static const unsigned kPaddingSize = 2; static const unsigned kPercentsSize = 4; static const unsigned kMaxExtraSize = kPaddingSize + 32 + kPercentsSize; static void ClearPrev(char *p, unsigned num) { unsigned i; for (i = 0; i < num; i++) *p++ = '\b'; for (i = 0; i < num; i++) *p++ = ' '; for (i = 0; i < num; i++) *p++ = '\b'; *p = '\0'; } void CPercentPrinter::ClosePrint() { if (m_NumExtraChars == 0) return; char s[kMaxExtraSize * 3 + 1]; ClearPrev(s, m_NumExtraChars); (*OutStream) << s; m_NumExtraChars = 0; } void CPercentPrinter::PrintString(const char *s) { ClosePrint(); (*OutStream) << s; } void CPercentPrinter::PrintString(const wchar_t *s) { ClosePrint(); (*OutStream) << s; } void CPercentPrinter::PrintNewLine() { ClosePrint(); (*OutStream) << "\n"; } void CPercentPrinter::RePrintRatio() { char s[32]; unsigned size; { char c = '%'; UInt64 value = 0; if (m_Total == (UInt64)(Int64)-1) { value = m_CurValue >> 20; c = 'M'; } else if (m_Total != 0) value = m_CurValue * 100 / m_Total; ConvertUInt64ToString(value, s); size = (unsigned)strlen(s); s[size++] = c; s[size] = '\0'; } unsigned extraSize = kPaddingSize + MyMax(size, kPercentsSize); if (extraSize < m_NumExtraChars) extraSize = m_NumExtraChars; char fullString[kMaxExtraSize * 3]; char *p = fullString; unsigned i; if (m_NumExtraChars == 0) { for (i = 0; i < extraSize; i++) *p++ = ' '; m_NumExtraChars = extraSize; } for (i = 0; i < m_NumExtraChars; i++) *p++ = '\b'; m_NumExtraChars = extraSize; for (; size < extraSize; size++) *p++ = ' '; MyStringCopy(p, s); (*OutStream) << fullString; OutStream->Flush(); m_PrevValue = m_CurValue; } void CPercentPrinter::PrintRatio() { if (m_CurValue < m_PrevValue + m_MinStepSize && m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0) return; RePrintRatio(); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.h0100777000000000000000000000136313761647206024660 0ustar00// PercentPrinter.h #ifndef __PERCENT_PRINTER_H #define __PERCENT_PRINTER_H #include "../../../Common/StdOutStream.h" class CPercentPrinter { UInt64 m_MinStepSize; UInt64 m_PrevValue; UInt64 m_CurValue; UInt64 m_Total; unsigned m_NumExtraChars; public: CStdOutStream *OutStream; CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize), m_PrevValue(0), m_CurValue(0), m_Total((UInt64)(Int64)-1), m_NumExtraChars(0) {} void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; } void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; } void PrintString(const char *s); void PrintString(const wchar_t *s); void PrintNewLine(); void ClosePrint(); void RePrintRatio(); void PrintRatio(); }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.h0100777000000000000000000000014013761647206023075 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../../../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/0040777000000000000000000000000013761647206020160 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/CommandLineParser.cpp0100777000000000000000000000732213761647206024233 0ustar00// CommandLineParser.cpp #include "StdAfx.h" #include "CommandLineParser.h" static bool IsString1PrefixedByString2_NoCase(const wchar_t *u, const char *a) { for (;;) { char c = *a; if (c == 0) return true; if (MyCharLower_Ascii(c) != MyCharLower_Ascii(*u)) return false; a++; u++; } } namespace NCommandLineParser { bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) { dest1.Empty(); dest2.Empty(); bool quoteMode = false; unsigned i; for (i = 0; i < src.Len(); i++) { wchar_t c = src[i]; if ((c == L' ' || c == L'\t') && !quoteMode) { dest2 = src.Ptr(i + 1); return i != 0; } if (c == L'\"') quoteMode = !quoteMode; else dest1 += c; } return i != 0; } void SplitCommandLine(const UString &s, UStringVector &parts) { UString sTemp = s; sTemp.Trim(); parts.Clear(); for (;;) { UString s1, s2; if (SplitCommandLine(sTemp, s1, s2)) parts.Add(s1); if (s2.IsEmpty()) break; sTemp = s2; } } static const char *kStopSwitchParsing = "--"; static bool inline IsItSwitchChar(wchar_t c) { return (c == '-'); } CParser::CParser(unsigned numSwitches): _numSwitches(numSwitches), _switches(0) { _switches = new CSwitchResult[numSwitches]; } CParser::~CParser() { delete []_switches; } // if (s) contains switch then function updates switch structures // out: true, if (s) is a switch bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms) { if (s.IsEmpty() || !IsItSwitchChar(s[0])) return false; unsigned pos = 1; unsigned switchIndex = 0; int maxLen = -1; for (unsigned i = 0; i < _numSwitches; i++) { const char *key = switchForms[i].Key; unsigned switchLen = MyStringLen(key); if ((int)switchLen <= maxLen || pos + switchLen > s.Len()) continue; if (IsString1PrefixedByString2_NoCase((const wchar_t *)s + pos, key)) { switchIndex = i; maxLen = switchLen; } } if (maxLen < 0) { ErrorMessage = "Unknown switch:"; return false; } pos += maxLen; CSwitchResult &sw = _switches[switchIndex]; const CSwitchForm &form = switchForms[switchIndex]; if (!form.Multi && sw.ThereIs) { ErrorMessage = "Multiple instances for switch:"; return false; } sw.ThereIs = true; int rem = s.Len() - pos; if (rem < form.MinLen) { ErrorMessage = "Too short switch:"; return false; } sw.WithMinus = false; sw.PostCharIndex = -1; switch (form.Type) { case NSwitchType::kMinus: if (rem != 0) { sw.WithMinus = (s[pos] == '-'); if (sw.WithMinus) pos++; } break; case NSwitchType::kChar: if (rem != 0) { wchar_t c = s[pos]; if (c <= 0x7F) { sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c); if (sw.PostCharIndex >= 0) pos++; } } break; case NSwitchType::kString: sw.PostStrings.Add((const wchar_t *)s + pos); return true; } if (pos != s.Len()) { ErrorMessage = "Too long switch:"; return false; } return true; } bool CParser::ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings) { ErrorLine.Empty(); bool stopSwitch = false; FOR_VECTOR (i, commandStrings) { const UString &s = commandStrings[i]; if (!stopSwitch) { if (s.IsEqualTo(kStopSwitchParsing)) { stopSwitch = true; continue; } if (!s.IsEmpty() && IsItSwitchChar(s[0])) { if (ParseString(s, switchForms)) continue; ErrorLine = s; return false; } } NonSwitchStrings.Add(s); } return true; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/CommandLineParser.h0100777000000000000000000000216713761647206023702 0ustar00// Common/CommandLineParser.h #ifndef __COMMON_COMMAND_LINE_PARSER_H #define __COMMON_COMMAND_LINE_PARSER_H #include "MyString.h" namespace NCommandLineParser { bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2); void SplitCommandLine(const UString &s, UStringVector &parts); namespace NSwitchType { enum EEnum { kSimple, kMinus, kString, kChar }; } struct CSwitchForm { const char *Key; Byte Type; bool Multi; Byte MinLen; // int MaxLen; const char *PostCharSet; }; struct CSwitchResult { bool ThereIs; bool WithMinus; int PostCharIndex; UStringVector PostStrings; CSwitchResult(): ThereIs(false) {}; }; class CParser { unsigned _numSwitches; CSwitchResult *_switches; bool ParseString(const UString &s, const CSwitchForm *switchForms); public: UStringVector NonSwitchStrings; AString ErrorMessage; UString ErrorLine; CParser(unsigned numSwitches); ~CParser(); bool ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings); const CSwitchResult& operator[](size_t index) const { return _switches[index]; } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/Common.h0100777000000000000000000000031413761647206021557 0ustar00// Common.h #ifndef __COMMON_COMMON_H #define __COMMON_COMMON_H #include "../../C/Compiler.h" #include "MyWindows.h" #include "NewHandler.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[1])) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/Common.pri0100777000000000000000000000265613761647206022135 0ustar00HEADERS += $$7ZIP_BASE/CPP/Common/CommandLineParser.h \ $$7ZIP_BASE/CPP/Common/ComTry.h \ $$7ZIP_BASE/CPP/Common/Common.h \ $$7ZIP_BASE/CPP/Common/Defs.h \ $$7ZIP_BASE/CPP/Common/IntToString.h \ $$7ZIP_BASE/CPP/Common/ListFileUtils.h \ $$7ZIP_BASE/CPP/Common/MyBuffer.h \ $$7ZIP_BASE/CPP/Common/MyCom.h \ $$7ZIP_BASE/CPP/Common/MyException.h \ $$7ZIP_BASE/CPP/Common/MyGuidDef.h \ $$7ZIP_BASE/CPP/Common/MyInitGuid.h \ $$7ZIP_BASE/CPP/Common/MyString.h \ $$7ZIP_BASE/CPP/Common/MyTypes.h \ $$7ZIP_BASE/CPP/Common/MyUnknown.h \ $$7ZIP_BASE/CPP/Common/MyVector.h \ $$7ZIP_BASE/CPP/Common/MyWindows.h \ $$7ZIP_BASE/CPP/Common/NewHandler.h \ $$7ZIP_BASE/CPP/Common/StdAfx.h \ $$7ZIP_BASE/CPP/Common/StdOutStream.h \ $$7ZIP_BASE/CPP/Common/StringConvert.h \ $$7ZIP_BASE/CPP/Common/StringToInt.h \ $$7ZIP_BASE/CPP/Common/UTFConvert.h \ $$7ZIP_BASE/CPP/Common/Wildcard.h SOURCES += $$7ZIP_BASE/CPP/Common/CommandLineParser.cpp \ $$7ZIP_BASE/CPP/Common/IntToString.cpp \ $$7ZIP_BASE/CPP/Common/ListFileUtils.cpp \ $$7ZIP_BASE/CPP/Common/MyString.cpp \ $$7ZIP_BASE/CPP/Common/MyWindows.cpp \ $$7ZIP_BASE/CPP/Common/NewHandler.cpp \ $$7ZIP_BASE/CPP/Common/StdOutStream.cpp \ $$7ZIP_BASE/CPP/Common/StringConvert.cpp \ $$7ZIP_BASE/CPP/Common/StringToInt.cpp \ $$7ZIP_BASE/CPP/Common/UTFConvert.cpp \ $$7ZIP_BASE/CPP/Common/Wildcard.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/ComTry.h0100777000000000000000000000060013761647206021542 0ustar00// ComTry.h #ifndef __COM_TRY_H #define __COM_TRY_H #include "MyWindows.h" // #include "Exception.h" // #include "NewHandler.h" #define COM_TRY_BEGIN try { #define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; } // catch(const CNewException &) { return E_OUTOFMEMORY; } // catch(const CSystemException &e) { return e.ErrorCode; } // catch(...) { return E_FAIL; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/Defs.h0100777000000000000000000000067113761647206021216 0ustar00// Common/Defs.h #ifndef __COMMON_DEFS_H #define __COMMON_DEFS_H template inline T MyMin(T a, T b) { return a < b ? a : b; } template inline T MyMax(T a, T b) { return a > b ? a : b; } template inline int MyCompare(T a, T b) { return a < b ? -1 : (a == b ? 0 : 1); } inline int BoolToInt(bool value) { return (value ? 1: 0); } inline bool IntToBool(int value) { return (value != 0); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/IntToString.cpp0100777000000000000000000000505213761647206023112 0ustar00// Common/IntToString.cpp #include "StdAfx.h" #include "IntToString.h" #define CONVERT_INT_TO_STR(charType, tempSize) \ unsigned char temp[tempSize]; unsigned i = 0; \ while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ *s++ = (charType)('0' + (unsigned)val); \ while (i != 0) { i--; *s++ = temp[i]; } \ *s = 0; void ConvertUInt32ToString(UInt32 val, char *s) throw() { CONVERT_INT_TO_STR(char, 16); } void ConvertUInt64ToString(UInt64 val, char *s) throw() { if (val <= (UInt32)0xFFFFFFFF) { ConvertUInt32ToString((UInt32)val, s); return; } CONVERT_INT_TO_STR(char, 24); } void ConvertUInt64ToOct(UInt64 val, char *s) throw() { UInt64 v = val; unsigned i; for (i = 1;; i++) { v >>= 3; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)(val & 0x7); val >>= 3; s[--i] = (char)('0' + t); } while (i); } void ConvertUInt32ToHex(UInt32 val, char *s) throw() { UInt32 v = val; unsigned i; for (i = 1;; i++) { v >>= 4; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)((val & 0xF)); val >>= 4; s[--i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } while (i); } void ConvertUInt64ToHex(UInt64 val, char *s) throw() { UInt64 v = val; unsigned i; for (i = 1;; i++) { v >>= 4; if (v == 0) break; } s[i] = 0; do { unsigned t = (unsigned)((val & 0xF)); val >>= 4; s[--i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } while (i); } void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw() { s[8] = 0; for (int i = 7; i >= 0; i--) { unsigned t = val & 0xF; val >>= 4; s[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } } /* void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s) { s[8] = 0; for (int i = 7; i >= 0; i--) { unsigned t = val & 0xF; val >>= 4; s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } } */ void ConvertUInt32ToString(UInt32 val, wchar_t *s) throw() { CONVERT_INT_TO_STR(wchar_t, 16); } void ConvertUInt64ToString(UInt64 val, wchar_t *s) throw() { if (val <= (UInt32)0xFFFFFFFF) { ConvertUInt32ToString((UInt32)val, s); return; } CONVERT_INT_TO_STR(wchar_t, 24); } void ConvertInt64ToString(Int64 val, char *s) throw() { if (val < 0) { *s++ = '-'; val = -val; } ConvertUInt64ToString(val, s); } void ConvertInt64ToString(Int64 val, wchar_t *s) throw() { if (val < 0) { *s++ = L'-'; val = -val; } ConvertUInt64ToString(val, s); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/IntToString.h0100777000000000000000000000142113761647206022553 0ustar00// Common/IntToString.h #ifndef __COMMON_INT_TO_STRING_H #define __COMMON_INT_TO_STRING_H #include "MyTypes.h" void ConvertUInt32ToString(UInt32 value, char *s) throw(); void ConvertUInt64ToString(UInt64 value, char *s) throw(); void ConvertUInt32ToString(UInt32 value, wchar_t *s) throw(); void ConvertUInt64ToString(UInt64 value, wchar_t *s) throw(); void ConvertUInt64ToOct(UInt64 value, char *s) throw(); void ConvertUInt32ToHex(UInt32 value, char *s) throw(); void ConvertUInt64ToHex(UInt64 value, char *s) throw(); void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw(); // void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw(); void ConvertInt64ToString(Int64 value, char *s) throw(); void ConvertInt64ToString(Int64 value, wchar_t *s) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/ListFileUtils.cpp0100777000000000000000000000475013761647206023426 0ustar00// Common/ListFileUtils.cpp #include "StdAfx.h" #include "../../C/CpuArch.h" #include "../Windows/FileIO.h" #include "ListFileUtils.h" #include "MyBuffer.h" #include "StringConvert.h" #include "UTFConvert.h" static const char kQuoteChar = '\"'; static void AddName(UStringVector &strings, UString &s) { s.Trim(); if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar) { s.DeleteBack(); s.Delete(0); } if (!s.IsEmpty()) strings.Add(s); } bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage) { NWindows::NFile::NIO::CInFile file; if (!file.Open(fileName)) return false; UInt64 fileSize; if (!file.GetLength(fileSize)) return false; if (fileSize >= ((UInt32)1 << 31) - 32) return false; UString u; if (codePage == MY__CP_UTF16 || codePage == MY__CP_UTF16BE) { if ((fileSize & 1) != 0) return false; CByteArr buf((size_t)fileSize); UInt32 processed; if (!file.Read(buf, (UInt32)fileSize, processed)) return false; if (processed != fileSize) return false; file.Close(); unsigned num = (unsigned)fileSize / 2; wchar_t *p = u.GetBuffer(num); if (codePage == MY__CP_UTF16) for (unsigned i = 0; i < num; i++) { wchar_t c = GetUi16(buf + i * 2); if (c == 0) return false; p[i] = c; } else for (unsigned i = 0; i < num; i++) { wchar_t c = (wchar_t)GetBe16(buf + i * 2); if (c == 0) return false; p[i] = c; } u.ReleaseBuffer(num); } else { AString s; char *p = s.GetBuffer((unsigned)fileSize); UInt32 processed; if (!file.Read(p, (UInt32)fileSize, processed)) return false; if (processed != fileSize) return false; file.Close(); p[processed] = 0; s.ReleaseBuffer(); if (s.Len() != processed) return false; // #ifdef CP_UTF8 if (codePage == CP_UTF8) { if (!ConvertUTF8ToUnicode(s, u)) return false; } else // #endif MultiByteToUnicodeString2(u, s, codePage); } const wchar_t kGoodBOM = 0xFEFF; const wchar_t kBadBOM = 0xFFFE; UString s; unsigned i = 0; for (; i < u.Len() && u[i] == kGoodBOM; i++); for (; i < u.Len(); i++) { wchar_t c = u[i]; if (c == kGoodBOM || c == kBadBOM) return false; if (c == L'\n' || c == 0xD) { AddName(strings, s); s.Empty(); } else s += c; } AddName(strings, s); return true; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/ListFileUtils.h0100777000000000000000000000045513761647206023071 0ustar00// Common/ListFileUtils.h #ifndef __COMMON_LIST_FILE_UTILS_H #define __COMMON_LIST_FILE_UTILS_H #include "MyString.h" #include "MyTypes.h" #define MY__CP_UTF16 1200 #define MY__CP_UTF16BE 1201 bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyBuffer.h0100777000000000000000000001115613761647206022054 0ustar00// Common/MyBuffer.h #ifndef __COMMON_MY_BUFFER_H #define __COMMON_MY_BUFFER_H #include "Defs.h" template class CBuffer { T *_items; size_t _size; void CopyToEmpty(const CBuffer &buffer) { if (buffer._size > 0) { _items = new T[buffer._size]; memcpy(_items, buffer._items, buffer._size * sizeof(T)); _size = buffer._size; } } public: void Free() { if (_items) { delete []_items; _items = 0; } _size = 0; } CBuffer(): _items(0), _size(0) {}; CBuffer(size_t size): _items(0), _size(0) { _items = new T[size]; _size = size; } CBuffer(const CBuffer &buffer): _items(0), _size(0) { CopyToEmpty(buffer); } ~CBuffer() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; size_t Size() const { return _size; } void Alloc(size_t size) { if (size != _size) { Free(); if (size != 0) { _items = new T[size]; _size = size; } } } void AllocAtLeast(size_t size) { if (size > _size) { Free(); _items = new T[size]; _size = size; } } void CopyFrom(const T *data, size_t size) { Alloc(size); memcpy(_items, data, size * sizeof(T)); } void ChangeSize_KeepData(size_t newSize, size_t keepSize) { if (newSize == _size) return; T *newBuffer = NULL; if (newSize > 0) { newBuffer = new T[newSize]; if (_size > 0) memcpy(newBuffer, _items, MyMin(MyMin(_size, keepSize), newSize) * sizeof(T)); } delete []_items; _items = newBuffer; _size = newSize; } CBuffer& operator=(const CBuffer &buffer) { Free(); CopyToEmpty(buffer); return *this; } }; template bool operator==(const CBuffer& b1, const CBuffer& b2) { size_t size1 = b1.Size(); if (size1 != b2.Size()) return false; return memcmp(b1, b2, size1 * sizeof(T)) == 0; } template bool operator!=(const CBuffer& b1, const CBuffer& b2) { size_t size1 = b1.Size(); if (size1 == b2.Size()) return false; return memcmp(b1, b2, size1 * sizeof(T)) != 0; } typedef CBuffer CCharBuffer; typedef CBuffer CWCharBuffer; typedef CBuffer CByteBuffer; template class CObjArray { protected: T *_items; private: // we disable constructors CObjArray(const CObjArray &buffer); void operator=(const CObjArray &buffer); public: void Free() { delete []_items; _items = 0; } CObjArray(size_t size): _items(0) { if (size != 0) _items = new T[size]; } CObjArray(): _items(0) {}; ~CObjArray() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; void Alloc(size_t newSize) { delete []_items; _items = 0; _items = new T[newSize]; } }; typedef CObjArray CByteArr; typedef CObjArray CBoolArr; typedef CObjArray CIntArr; // #define CRecArray CObjArray template class CObjArray2 { // protected: T *_items; unsigned _size; CObjArray2(const CObjArray2 &buffer); void operator=(const CObjArray2 &buffer); public: void Free() { delete []_items; _items = 0; _size = 0; } CObjArray2(): _items(0), _size(0) {}; /* CObjArray2(const CObjArray2 &buffer): _items(0), _size(0) { size_t newSize = buffer._size; if (newSize > 0) { T *newBuffer = new T[newSize];; _items = newBuffer; _size = newSize; const T *src = buffer; for (size_t i = 0; i < newSize; i++) newBuffer[i] = src[i]; } } */ /* CObjArray2(size_t size): _items(0), _size(0) { if (size != 0) { _items = new T[size]; _size = size; } } */ ~CObjArray2() { delete []_items; } operator T *() { return _items; }; operator const T *() const { return _items; }; unsigned Size() const { return (unsigned)_size; } bool IsEmpty() const { return _size == 0; } // SetSize doesn't keep old items. It allocates new array if size is not equal void SetSize(unsigned size) { if (size == _size) return; T *newBuffer = NULL; if (size > 0) newBuffer = new T[size]; delete []_items; _items = newBuffer; _size = size; } /* CObjArray2& operator=(const CObjArray2 &buffer) { Free(); size_t newSize = buffer._size; if (newSize > 0) { T *newBuffer = new T[newSize];; _items = newBuffer; _size = newSize; const T *src = buffer; for (size_t i = 0; i < newSize; i++) newBuffer[i] = src[i]; } return *this; } */ }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyCom.h0100777000000000000000000001427713761647206021370 0ustar00// MyCom.h #ifndef __MY_COM_H #define __MY_COM_H #include "MyWindows.h" #include "NewHandler.h" #ifndef RINOK #define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; } #endif template class CMyComPtr { T* _p; public: CMyComPtr(): _p(NULL) {} CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } CMyComPtr(const CMyComPtr& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); } ~CMyComPtr() { if (_p) _p->Release(); } void Release() { if (_p) { _p->Release(); _p = NULL; } } operator T*() const { return (T*)_p; } // T& operator*() const { return *_p; } T** operator&() { return &_p; } T* operator->() const { return _p; } T* operator=(T* p) { if (p) p->AddRef(); if (_p) _p->Release(); _p = p; return p; } T* operator=(const CMyComPtr& lp) { return (*this = lp._p); } bool operator!() const { return (_p == NULL); } // bool operator==(T* pT) const { return _p == pT; } void Attach(T* p2) { Release(); _p = p2; } T* Detach() { T* pt = _p; _p = NULL; return pt; } #ifdef _WIN32 HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) { return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); } #endif /* HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) { CLSID clsid; HRESULT hr = CLSIDFromProgID(szProgID, &clsid); ATLASSERT(_p == NULL); if (SUCCEEDED(hr)) hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); return hr; } */ template HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() { return _p->QueryInterface(iid, (void**)pp); } }; ////////////////////////////////////////////////////////// inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr) { *bstr = ::SysAllocString(src); return (*bstr != NULL) ? S_OK : E_OUTOFMEMORY; } class CMyComBSTR { BSTR m_str; public: CMyComBSTR(): m_str(NULL) {} CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); } // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } /* CMyComBSTR(REFGUID src) { LPOLESTR szGuid; StringFromCLSID(src, &szGuid); m_str = ::SysAllocString(szGuid); CoTaskMemFree(szGuid); } */ ~CMyComBSTR() { ::SysFreeString(m_str); } CMyComBSTR& operator=(const CMyComBSTR& src) { if (m_str != src.m_str) { if (m_str) ::SysFreeString(m_str); m_str = src.MyCopy(); } return *this; } CMyComBSTR& operator=(LPCOLESTR src) { ::SysFreeString(m_str); m_str = ::SysAllocString(src); return *this; } // unsigned Len() const { return ::SysStringLen(m_str); } operator BSTR() const { return m_str; } BSTR* operator&() { return &m_str; } BSTR MyCopy() const { int byteLen = ::SysStringByteLen(m_str); BSTR res = ::SysAllocStringByteLen(NULL, byteLen); memcpy(res, m_str, byteLen); return res; } /* void Attach(BSTR src) { m_str = src; } BSTR Detach() { BSTR s = m_str; m_str = NULL; return s; } */ void Empty() { ::SysFreeString(m_str); m_str = NULL; } bool operator!() const { return (m_str == NULL); } }; ////////////////////////////////////////////////////////// class CMyUnknownImp { public: ULONG __m_RefCount; CMyUnknownImp(): __m_RefCount(0) {} }; #define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \ (REFGUID iid, void **outObject) throw() { *outObject = NULL; #define MY_QUERYINTERFACE_ENTRY(i) else if (iid == IID_ ## i) \ { *outObject = (void *)(i *)this; } #define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \ { *outObject = (void *)(IUnknown *)(i *)this; } #define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ MY_QUERYINTERFACE_ENTRY(i) #define MY_QUERYINTERFACE_END else return E_NOINTERFACE; AddRef(); return S_OK; } #define MY_ADDREF_RELEASE \ STDMETHOD_(ULONG, AddRef)() throw() { return ++__m_RefCount; } \ STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \ return __m_RefCount; delete this; return 0; } #define MY_UNKNOWN_IMP_SPEC(i) \ MY_QUERYINTERFACE_BEGIN \ i \ MY_QUERYINTERFACE_END \ MY_ADDREF_RELEASE #define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \ MY_QUERYINTERFACE_END \ MY_ADDREF_RELEASE #define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ MY_QUERYINTERFACE_ENTRY(i) \ ) #define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ ) #define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ ) #define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ ) #define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ ) #define MY_UNKNOWN_IMP6(i1, i2, i3, i4, i5, i6) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ MY_QUERYINTERFACE_ENTRY(i6) \ ) #define MY_UNKNOWN_IMP7(i1, i2, i3, i4, i5, i6, i7) MY_UNKNOWN_IMP_SPEC( \ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ MY_QUERYINTERFACE_ENTRY(i1) \ MY_QUERYINTERFACE_ENTRY(i2) \ MY_QUERYINTERFACE_ENTRY(i3) \ MY_QUERYINTERFACE_ENTRY(i4) \ MY_QUERYINTERFACE_ENTRY(i5) \ MY_QUERYINTERFACE_ENTRY(i6) \ MY_QUERYINTERFACE_ENTRY(i7) \ ) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyException.h0100777000000000000000000000034313761647206022575 0ustar00// Common/Exception.h #ifndef __COMMON_EXCEPTION_H #define __COMMON_EXCEPTION_H #include "MyWindows.h" struct CSystemException { HRESULT ErrorCode; CSystemException(HRESULT errorCode): ErrorCode(errorCode) {} }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyGuidDef.h0100777000000000000000000000203413761647206022145 0ustar00// Common/MyGuidDef.h #ifndef GUID_DEFINED #define GUID_DEFINED #include "MyTypes.h" typedef struct { UInt32 Data1; UInt16 Data2; UInt16 Data3; unsigned char Data4[8]; } GUID; #ifdef __cplusplus #define REFGUID const GUID & #else #define REFGUID const GUID * #endif #define REFCLSID REFGUID #define REFIID REFGUID #ifdef __cplusplus inline int operator==(REFGUID g1, REFGUID g2) { for (int i = 0; i < (int)sizeof(g1); i++) if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i]) return 0; return 1; } inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } #endif #ifdef __cplusplus #define MY_EXTERN_C extern "C" #else #define MY_EXTERN_C extern #endif #endif #ifdef DEFINE_GUID #undef DEFINE_GUID #endif #ifdef INITGUID #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } #else #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ MY_EXTERN_C const GUID name #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyInitGuid.h0100777000000000000000000000227013761647206022354 0ustar00// Common/MyInitGuid.h #ifndef __COMMON_MY_INITGUID_H #define __COMMON_MY_INITGUID_H /* This file must be included only to one C++ file in project before declarations of COM interfaces with DEFINE_GUID macro. Each GUID must be initialized exactly once in project. There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h): - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name. - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID. Also we need IID_IUnknown that is initialized in some file for linking: MSVC: by default the linker uses some lib file that contains IID_IUnknown MinGW: add -luuid switch for linker WinCE: we define IID_IUnknown in this file Other: we define IID_IUnknown in this file */ #ifdef _WIN32 #ifdef UNDER_CE #include #endif #include #ifdef UNDER_CE DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); #endif #else #define INITGUID #include "MyGuidDef.h" DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyString.cpp0100777000000000000000000005522513761647206022451 0ustar00// Common/MyString.cpp #include "StdAfx.h" #ifdef _WIN32 #include #include #else #include #endif #if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) #include "StringConvert.h" #endif #include "MyString.h" #define MY_STRING_NEW(_T_, _size_) new _T_[_size_] // #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) /* inline const char* MyStringGetNextCharPointer(const char *p) throw() { #if defined(_WIN32) && !defined(UNDER_CE) return CharNextA(p); #else return p + 1; #endif } */ int FindCharPosInString(const char *s, char c) throw() { for (const char *p = s;; p++) { if (*p == c) return (int)(p - s); if (*p == 0) return -1; // MyStringGetNextCharPointer(p); } } int FindCharPosInString(const wchar_t *s, wchar_t c) throw() { for (const wchar_t *p = s;; p++) { if (*p == c) return (int)(p - s); if (*p == 0) return -1; } } /* void MyStringUpper_Ascii(wchar_t *s) { for (;;) { wchar_t c = *s; if (c == 0) return; *s++ = MyCharUpper_Ascii(c); } } */ void MyStringLower_Ascii(wchar_t *s) throw() { for (;;) { wchar_t c = *s; if (c == 0) return; *s++ = MyCharLower_Ascii(c); } } #ifdef _WIN32 #ifdef _UNICODE // wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } // wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } // for WinCE - FString - char // const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } #else // const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } // char * MyStringUpper(char *s) { return CharUpperA(s); } // char * MyStringLower(char *s) { return CharLowerA(s); } wchar_t MyCharUpper_WIN(wchar_t c) throw() { wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return (wchar_t)(unsigned)(UINT_PTR)res; const int kBufSize = 4; char s[kBufSize + 1]; int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); if (numChars == 0 || numChars > kBufSize) return c; s[numChars] = 0; ::CharUpperA(s); ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); return c; } /* wchar_t MyCharLower_WIN(wchar_t c) { wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return (wchar_t)(unsigned)(UINT_PTR)res; const int kBufSize = 4; char s[kBufSize + 1]; int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); if (numChars == 0 || numChars > kBufSize) return c; s[numChars] = 0; ::CharLowerA(s); ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); return c; } */ /* wchar_t * MyStringUpper(wchar_t *s) { if (s == 0) return 0; wchar_t *res = CharUpperW(s); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return res; AString a = UnicodeStringToMultiByte(s); a.MakeUpper(); MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); return s; } */ /* wchar_t * MyStringLower(wchar_t *s) { if (s == 0) return 0; wchar_t *res = CharLowerW(s); if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return res; AString a = UnicodeStringToMultiByte(s); a.MakeLower(); MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); return s; } */ #endif #endif bool IsString1PrefixedByString2(const char *s1, const char *s2) throw() { for (;;) { unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; } } bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; if (c1 == 0) return true; } } // ---------- ASCII ---------- bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() { const char *s1 = _chars; for (;;) { char c2 = *s++; if (c2 == 0) return true; char c1 = *s1++; if (MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; } } bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() { const wchar_t *s1 = _chars; for (;;) { char c2 = *s++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) return false; } } bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw() { for (;;) { unsigned char c = *a; if (c != *u) return false; if (c == 0) return true; a++; u++; } } bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw() { for (;;) { char c1 = *s1++; char c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) return true; } } bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) return true; } } bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw() { for (;;) { wchar_t c1 = *s1++; char c2 = *s2++; if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) return false; if (c1 == 0) return true; } } bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (c1 != c2) return false; } } // NTFS order: uses upper case int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw() { for (;;) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2) { wchar_t u1 = MyCharUpper(c1); wchar_t u2 = MyCharUpper(c2); if (u1 < u2) return -1; if (u1 > u2) return 1; } if (c1 == 0) return 0; } } int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw() { for (; num != 0; num--) { wchar_t c1 = *s1++; wchar_t c2 = *s2++; if (c1 != c2) { wchar_t u1 = MyCharUpper(c1); wchar_t u2 = MyCharUpper(c2); if (u1 < u2) return -1; if (u1 > u2) return 1; } if (c1 == 0) return 0; } return 0; } // ---------- AString ---------- void AString::InsertSpace(unsigned &index, unsigned size) { Grow(size); MoveItems(index + size, index); } void AString::ReAlloc(unsigned newLimit) { if (newLimit < _len || newLimit >= 0x20000000) throw 20130220; // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); char *newBuf = MY_STRING_NEW(char, newLimit + 1); memcpy(newBuf, _chars, (size_t)(_len + 1)); \ MY_STRING_DELETE(_chars); _chars = newBuf; _limit = newLimit; } void AString::SetStartLen(unsigned len) { _chars = 0; _chars = MY_STRING_NEW(char, len + 1); _len = len; _limit = len; } void AString::Grow_1() { unsigned next = _len; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } void AString::Grow(unsigned n) { unsigned freeSize = _limit - _len; if (n <= freeSize) return; unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } /* AString::AString(unsigned num, const char *s) { unsigned len = MyStringLen(s); if (num > len) num = len; SetStartLen(num); memcpy(_chars, s, num); _chars[num] = 0; } */ AString::AString(unsigned num, const AString &s) { if (num > s._len) num = s._len; SetStartLen(num); memcpy(_chars, s._chars, num); _chars[num] = 0; } AString::AString(const AString &s, char c) { SetStartLen(s.Len() + 1); char *chars = _chars; unsigned len = s.Len(); memcpy(chars, s, len); chars[len] = c; chars[len + 1] = 0; } AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2) { SetStartLen(num1 + num2); char *chars = _chars; memcpy(chars, s1, num1); memcpy(chars + num1, s2, num2 + 1); } AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); } AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); } AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); } AString::AString() { _chars = 0; _chars = MY_STRING_NEW(char, 4); _len = 0; _limit = 4 - 1; _chars[0] = 0; } AString::AString(char c) { SetStartLen(1); _chars[0] = c; _chars[1] = 0; } AString::AString(const char *s) { SetStartLen(MyStringLen(s)); MyStringCopy(_chars, s); } AString::AString(const AString &s) { SetStartLen(s._len); MyStringCopy(_chars, s._chars); } AString &AString::operator=(char c) { if (1 > _limit) { char *newBuf = MY_STRING_NEW(char, 1 + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = 1; } _len = 1; _chars[0] = c; _chars[1] = 0; return *this; } AString &AString::operator=(const char *s) { unsigned len = MyStringLen(s); if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s); return *this; } AString &AString::operator=(const AString &s) { if (&s == this) return *this; unsigned len = s._len; if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s._chars); return *this; } AString &AString::operator+=(const char *s) { unsigned len = MyStringLen(s); Grow(len); MyStringCopy(_chars + _len, s); _len += len; return *this; } AString &AString::operator+=(const AString &s) { Grow(s._len); MyStringCopy(_chars + _len, s._chars); _len += s._len; return *this; } void AString::SetFrom(const char *s, unsigned len) // no check { if (len > _limit) { char *newBuf = MY_STRING_NEW(char, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } memcpy(_chars, s, len); _chars[len] = 0; _len = len; } int AString::Find(const AString &s, unsigned startIndex) const throw() { if (s.IsEmpty()) return startIndex; for (; startIndex < _len; startIndex++) { unsigned j; for (j = 0; j < s._len && startIndex + j < _len; j++) if (_chars[startIndex + j] != s._chars[j]) break; if (j == s._len) return (int)startIndex; } return -1; } int AString::ReverseFind(char c) const throw() { if (_len == 0) return -1; const char *p = _chars + _len - 1; for (;;) { if (*p == c) return (int)(p - _chars); if (p == _chars) return -1; p--; // p = GetPrevCharPointer(_chars, p); } } void AString::TrimLeft() throw() { const char *p = _chars; for (;; p++) { char c = *p; if (c != ' ' && c != '\n' && c != '\t') break; } unsigned pos = (unsigned)(p - _chars); if (pos != 0) { MoveItems(0, pos); _len -= pos; } } void AString::TrimRight() throw() { const char *p = _chars; int i; for (i = _len - 1; i >= 0; i--) { char c = p[i]; if (c != ' ' && c != '\n' && c != '\t') break; } i++; if ((unsigned)i != _len) { _chars[i] = 0; _len = i; } } void AString::InsertAtFront(char c) { if (_limit == _len) Grow_1(); MoveItems(1, 0); _chars[0] = c; _len++; } /* void AString::Insert(unsigned index, char c) { InsertSpace(index, 1); _chars[index] = c; _len++; } */ void AString::Insert(unsigned index, const char *s) { unsigned num = MyStringLen(s); if (num != 0) { InsertSpace(index, num); memcpy(_chars + index, s, num); _len += num; } } void AString::Insert(unsigned index, const AString &s) { unsigned num = s.Len(); if (num != 0) { InsertSpace(index, num); memcpy(_chars + index, s, num); _len += num; } } void AString::RemoveChar(char ch) throw() { int pos = Find(ch); if (pos < 0) return; const char *src = _chars; char *dest = _chars + pos; pos++; unsigned len = _len; for (; (unsigned)pos < len; pos++) { char c = src[(unsigned)pos]; if (c != ch) *dest++ = c; } *dest = 0; _len = (unsigned)(dest - _chars); } // !!!!!!!!!!!!!!! test it if newChar = '\0' void AString::Replace(char oldChar, char newChar) throw() { if (oldChar == newChar) return; // 0; // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldChar, pos); if (pos < 0) break; _chars[pos] = newChar; pos++; // number++; } return; // number; } void AString::Replace(const AString &oldString, const AString &newString) { if (oldString.IsEmpty()) return; // 0; if (oldString == newString) return; // 0; unsigned oldLen = oldString.Len(); unsigned newLen = newString.Len(); // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldString, pos); if (pos < 0) break; Delete(pos, oldLen); Insert(pos, newString); pos += newLen; // number++; } // return number; } void AString::Delete(unsigned index) throw() { MoveItems(index, index + 1); _len--; } void AString::Delete(unsigned index, unsigned count) throw() { if (index + count > _len) count = _len - index; if (count > 0) { MoveItems(index, index + count); _len -= count; } } void AString::DeleteFrontal(unsigned num) throw() { if (num != 0) { MoveItems(0, num); _len -= num; } } /* AString operator+(const AString &s1, const AString &s2) { AString result(s1); result += s2; return result; } AString operator+(const AString &s, const char *chars) { AString result(s); result += chars; return result; } AString operator+(const char *chars, const AString &s) { AString result(chars); result += s; return result; } AString operator+(const AString &s, char c) { AString result(s); result += c; return result; } */ /* AString operator+(char c, const AString &s) { AString result(c); result += s; return result; } */ // ---------- UString ---------- void UString::InsertSpace(unsigned index, unsigned size) { Grow(size); MoveItems(index + size, index); } void UString::ReAlloc(unsigned newLimit) { if (newLimit < _len || newLimit >= 0x20000000) throw 20130221; // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1); wmemcpy(newBuf, _chars, _len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = newLimit; } void UString::SetStartLen(unsigned len) { _chars = 0; _chars = MY_STRING_NEW(wchar_t, len + 1); _len = len; _limit = len; } void UString::Grow_1() { unsigned next = _len; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } void UString::Grow(unsigned n) { unsigned freeSize = _limit - _len; if (n <= freeSize) return; unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; ReAlloc(next - 1); } UString::UString(unsigned num, const wchar_t *s) { unsigned len = MyStringLen(s); if (num > len) num = len; SetStartLen(num); wmemcpy(_chars, s, num); _chars[num] = 0; } UString::UString(unsigned num, const UString &s) { if (num > s._len) num = s._len; SetStartLen(num); wmemcpy(_chars, s._chars, num); _chars[num] = 0; } UString::UString(const UString &s, wchar_t c) { SetStartLen(s.Len() + 1); wchar_t *chars = _chars; unsigned len = s.Len(); wmemcpy(chars, s, len); chars[len] = c; chars[len + 1] = 0; } UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2) { SetStartLen(num1 + num2); wchar_t *chars = _chars; wmemcpy(chars, s1, num1); wmemcpy(chars + num1, s2, num2 + 1); } UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); } UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); } UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); } UString::UString() { _chars = 0; _chars = MY_STRING_NEW(wchar_t, 4); _len = 0; _limit = 4 - 1; _chars[0] = 0; } UString::UString(wchar_t c) { SetStartLen(1); _chars[0] = c; _chars[1] = 0; } UString::UString(const wchar_t *s) { SetStartLen(MyStringLen(s)); MyStringCopy(_chars, s); } UString::UString(const UString &s) { SetStartLen(s._len); MyStringCopy(_chars, s._chars); } UString &UString::operator=(wchar_t c) { if (1 > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = 1; } _len = 1; _chars[0] = c; _chars[1] = 0; return *this; } UString &UString::operator=(const wchar_t *s) { unsigned len = MyStringLen(s); if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s); return *this; } UString &UString::operator=(const UString &s) { if (&s == this) return *this; unsigned len = s._len; if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } _len = len; MyStringCopy(_chars, s._chars); return *this; } UString &UString::operator+=(const wchar_t *s) { unsigned len = MyStringLen(s); Grow(len); MyStringCopy(_chars + _len, s); _len += len; return *this; } UString &UString::operator+=(const UString &s) { Grow(s._len); MyStringCopy(_chars + _len, s._chars); _len += s._len; return *this; } void UString::SetFrom(const wchar_t *s, unsigned len) // no check { if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } wmemcpy(_chars, s, len); _chars[len] = 0; _len = len; } void UString::SetFromAscii(const char *s) { unsigned len = MyStringLen(s); if (len > _limit) { wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; } wchar_t *chars = _chars; for (unsigned i = 0; i < len; i++) chars[i] = s[i]; chars[len] = 0; _len = len; } void UString::AddAsciiStr(const char *s) { unsigned len = MyStringLen(s); Grow(len); wchar_t *chars = _chars + _len; for (unsigned i = 0; i < len; i++) chars[i] = s[i]; chars[len] = 0; _len += len; } int UString::Find(const UString &s, unsigned startIndex) const throw() { if (s.IsEmpty()) return startIndex; for (; startIndex < _len; startIndex++) { unsigned j; for (j = 0; j < s._len && startIndex + j < _len; j++) if (_chars[startIndex + j] != s._chars[j]) break; if (j == s._len) return (int)startIndex; } return -1; } int UString::ReverseFind(wchar_t c) const throw() { if (_len == 0) return -1; const wchar_t *p = _chars + _len - 1; for (;;) { if (*p == c) return (int)(p - _chars); if (p == _chars) return -1; p--; } } void UString::TrimLeft() throw() { const wchar_t *p = _chars; for (;; p++) { wchar_t c = *p; if (c != ' ' && c != '\n' && c != '\t') break; } unsigned pos = (unsigned)(p - _chars); if (pos != 0) { MoveItems(0, pos); _len -= pos; } } void UString::TrimRight() throw() { const wchar_t *p = _chars; int i; for (i = _len - 1; i >= 0; i--) { wchar_t c = p[i]; if (c != ' ' && c != '\n' && c != '\t') break; } i++; if ((unsigned)i != _len) { _chars[i] = 0; _len = i; } } void UString::InsertAtFront(wchar_t c) { if (_limit == _len) Grow_1(); MoveItems(1, 0); _chars[0] = c; _len++; } /* void UString::Insert(unsigned index, wchar_t c) { InsertSpace(index, 1); _chars[index] = c; _len++; } */ void UString::Insert(unsigned index, const wchar_t *s) { unsigned num = MyStringLen(s); if (num != 0) { InsertSpace(index, num); wmemcpy(_chars + index, s, num); _len += num; } } void UString::Insert(unsigned index, const UString &s) { unsigned num = s.Len(); if (num != 0) { InsertSpace(index, num); wmemcpy(_chars + index, s, num); _len += num; } } void UString::RemoveChar(wchar_t ch) throw() { int pos = Find(ch); if (pos < 0) return; const wchar_t *src = _chars; wchar_t *dest = _chars + pos; pos++; unsigned len = _len; for (; (unsigned)pos < len; pos++) { wchar_t c = src[(unsigned)pos]; if (c != ch) *dest++ = c; } *dest = 0; _len = (unsigned)(dest - _chars); } // !!!!!!!!!!!!!!! test it if newChar = '\0' void UString::Replace(wchar_t oldChar, wchar_t newChar) throw() { if (oldChar == newChar) return; // 0; // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldChar, pos); if (pos < 0) break; _chars[pos] = newChar; pos++; // number++; } return; // number; } void UString::Replace(const UString &oldString, const UString &newString) { if (oldString.IsEmpty()) return; // 0; if (oldString == newString) return; // 0; unsigned oldLen = oldString.Len(); unsigned newLen = newString.Len(); // unsigned number = 0; int pos = 0; while ((unsigned)pos < _len) { pos = Find(oldString, pos); if (pos < 0) break; Delete(pos, oldLen); Insert(pos, newString); pos += newLen; // number++; } // return number; } void UString::Delete(unsigned index) throw() { MoveItems(index, index + 1); _len--; } void UString::Delete(unsigned index, unsigned count) throw() { if (index + count > _len) count = _len - index; if (count > 0) { MoveItems(index, index + count); _len -= count; } } void UString::DeleteFrontal(unsigned num) throw() { if (num != 0) { MoveItems(0, num); _len -= num; } } // ---------------------------------------- /* int MyStringCompareNoCase(const char *s1, const char *s2) { return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); } */ static inline UINT GetCurrentCodePage() { #if defined(UNDER_CE) || !defined(_WIN32) return CP_ACP; #else return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; #endif } #ifdef USE_UNICODE_FSTRING #ifndef _UNICODE AString fs2fas(CFSTR s) { return UnicodeStringToMultiByte(s, GetCurrentCodePage()); } FString fas2fs(const AString &s) { return MultiByteToUnicodeString(s, GetCurrentCodePage()); } #endif #else UString fs2us(const FString &s) { return MultiByteToUnicodeString((AString)s, GetCurrentCodePage()); } FString us2fs(const wchar_t *s) { return UnicodeStringToMultiByte(s, GetCurrentCodePage()); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyString.h0100777000000000000000000003632513761647206022116 0ustar00// Common/String.h #ifndef __COMMON_STRING_H #define __COMMON_STRING_H #include #ifndef _WIN32 #include #include #endif #include "MyTypes.h" #include "MyVector.h" inline unsigned MyStringLen(const char *s) { unsigned i; for (i = 0; s[i] != 0; i++); return i; } inline void MyStringCopy(char *dest, const char *src) { while ((*dest++ = *src++) != 0); } inline char *MyStpCpy(char *dest, const char *src) { for (;;) { char c = *src; *dest = c; if (c == 0) return dest; src++; dest++; } } inline unsigned MyStringLen(const wchar_t *s) { unsigned i; for (i = 0; s[i] != 0; i++); return i; } inline void MyStringCopy(wchar_t *dest, const wchar_t *src) { while ((*dest++ = *src++) != 0); } int FindCharPosInString(const char *s, char c) throw(); int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); #ifdef _WIN32 #ifndef _UNICODE #define STRING_UNICODE_THROW #endif #endif #ifndef STRING_UNICODE_THROW #define STRING_UNICODE_THROW throw() #endif /* inline char MyCharUpper_Ascii(char c) { if (c >= 'a' && c <= 'z') return (char)(c - 0x20); return c; } inline wchar_t MyCharUpper_Ascii(wchar_t c) { if (c >= 'a' && c <= 'z') return (wchar_t)(c - 0x20); return c; } */ inline char MyCharLower_Ascii(char c) { if (c >= 'A' && c <= 'Z') return (char)(c + 0x20); return c; } inline wchar_t MyCharLower_Ascii(wchar_t c) { if (c >= 'A' && c <= 'Z') return (wchar_t)(c + 0x20); return c; } wchar_t MyCharUpper_WIN(wchar_t c) throw(); inline wchar_t MyCharUpper(wchar_t c) throw() { if (c < 'a') return c; if (c <= 'z') return (wchar_t)(c - 0x20); if (c <= 0x7F) return c; #ifdef _WIN32 #ifdef _UNICODE return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); #else return (wchar_t)MyCharUpper_WIN(c); #endif #else return (wchar_t)towupper(c); #endif } /* wchar_t MyCharLower_WIN(wchar_t c) throw(); inline wchar_t MyCharLower(wchar_t c) throw() { if (c < 'A') return c; if (c <= 'Z') return (wchar_t)(c + 0x20); if (c <= 0x7F) return c; #ifdef _WIN32 #ifdef _UNICODE return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); #else return (wchar_t)MyCharLower_WIN(c); #endif #else return (wchar_t)tolower(c); #endif } */ // char *MyStringUpper(char *s) throw(); // char *MyStringLower(char *s) throw(); // void MyStringUpper_Ascii(wchar_t *s) throw(); void MyStringLower_Ascii(wchar_t *s) throw(); // wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; // wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); // ---------- ASCII ---------- // char values in ASCII strings must be less then 128 bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); #define MY_STRING_DELETE(_p_) delete []_p_; // #define MY_STRING_DELETE(_p_) my_delete(_p_); class AString { char *_chars; unsigned _len; unsigned _limit; void MoveItems(unsigned dest, unsigned src) { memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); } void InsertSpace(unsigned &index, unsigned size); void ReAlloc(unsigned newLimit); void SetStartLen(unsigned len); void Grow_1(); void Grow(unsigned n); // AString(unsigned num, const char *s); AString(unsigned num, const AString &s); AString(const AString &s, char c); // it's for String + char AString(const char *s1, unsigned num1, const char *s2, unsigned num2); friend AString operator+(const AString &s, char c) { return AString(s, c); } ; // friend AString operator+(char c, const AString &s); // is not supported friend AString operator+(const AString &s1, const AString &s2); friend AString operator+(const AString &s1, const char *s2); friend AString operator+(const char *s1, const AString &s2); public: AString(); AString(char c); AString(const char *s); AString(const AString &s); ~AString() { MY_STRING_DELETE(_chars); } unsigned Len() const { return _len; } bool IsEmpty() const { return _len == 0; } void Empty() { _len = 0; _chars[0] = 0; } operator const char *() const { return _chars; } const char *Ptr() const { return _chars; } const char *Ptr(unsigned pos) const { return _chars + pos; } const char *RightPtr(unsigned num) const { return _chars + _len - num; } char Back() const { return _chars[_len - 1]; } void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } // The minimum size of the character buffer in characters. // This value does not include space for a null terminator. char *GetBuffer(unsigned minBufLen) { if (minBufLen > _limit) ReAlloc(minBufLen); return _chars; } void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); } void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } AString &operator=(char c); AString &operator=(const char *s); AString &operator=(const AString &s); AString &operator+=(char c) { if (_limit == _len) Grow_1(); unsigned len = _len; char *chars = _chars; chars[len++] = c; chars[len] = 0; _len = len; return *this; } AString &operator+=(const char *s); AString &operator+=(const AString &s); void SetFrom(const char *s, unsigned len); // no check // AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } AString Left(unsigned count) const { return AString(count, *this); } // void MakeUpper() { MyStringUpper(_chars); } // void MakeLower() { MyStringLower(_chars); } // int Compare(const char *s) const { return MyStringCompare(_chars, s); } // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); int Find(char c) const { return FindCharPosInString(_chars, c); } int Find(char c, unsigned startIndex) const { int pos = FindCharPosInString(_chars + startIndex, c); return pos < 0 ? -1 : (int)startIndex + pos; } int ReverseFind(char c) const throw(); int Find(const AString &s) const { return Find(s, 0); } int Find(const AString &s, unsigned startIndex) const throw(); void TrimLeft() throw(); void TrimRight() throw(); void Trim() { TrimRight(); TrimLeft(); } void InsertAtFront(char c); // void Insert(unsigned index, char c); void Insert(unsigned index, const char *s); void Insert(unsigned index, const AString &s); void RemoveChar(char ch) throw(); void Replace(char oldChar, char newChar) throw(); void Replace(const AString &oldString, const AString &newString); void Delete(unsigned index) throw(); void Delete(unsigned index, unsigned count) throw(); void DeleteFrontal(unsigned num) throw(); void DeleteBack() { _chars[--_len] = 0; } void DeleteFrom(unsigned index) { if (index < _len) { _len = index; _chars[index] = 0; } } }; bool operator<(const AString &s1, const AString &s2); bool operator>(const AString &s1, const AString &s2); /* bool operator==(const AString &s1, const AString &s2); bool operator==(const AString &s1, const char *s2); bool operator==(const char *s1, const AString &s2); bool operator!=(const AString &s1, const AString &s2); bool operator!=(const AString &s1, const char *s2); bool operator!=(const char *s1, const AString &s2); */ inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } class UString { wchar_t *_chars; unsigned _len; unsigned _limit; void MoveItems(unsigned dest, unsigned src) { memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); } void InsertSpace(unsigned index, unsigned size); void ReAlloc(unsigned newLimit); void SetStartLen(unsigned len); void Grow_1(); void Grow(unsigned n); UString(unsigned num, const wchar_t *s); // for Mid UString(unsigned num, const UString &s); // for Left UString(const UString &s, wchar_t c); // it's for String + char UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } ; // friend UString operator+(wchar_t c, const UString &s); // is not supported friend UString operator+(const UString &s1, const UString &s2); friend UString operator+(const UString &s1, const wchar_t *s2); friend UString operator+(const wchar_t *s1, const UString &s2); public: UString(); UString(wchar_t c); UString(const wchar_t *s); UString(const UString &s); ~UString() { MY_STRING_DELETE(_chars); } unsigned Len() const { return _len; } bool IsEmpty() const { return _len == 0; } void Empty() { _len = 0; _chars[0] = 0; } operator const wchar_t *() const { return _chars; } const wchar_t *Ptr() const { return _chars; } const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } wchar_t Back() const { return _chars[_len - 1]; } void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } // The minimum size of the character buffer in characters. // This value does not include space for a null terminator. wchar_t *GetBuffer(unsigned minBufLen) { if (minBufLen > _limit) ReAlloc(minBufLen); return _chars; } void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); } void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } UString &operator=(wchar_t c); UString &operator=(const wchar_t *s); UString &operator=(const UString &s); UString &operator+=(wchar_t c) { if (_limit == _len) Grow_1(); unsigned len = _len; wchar_t *chars = _chars; chars[len++] = c; chars[len] = 0; _len = len; return *this; } UString &operator+=(const wchar_t *s); UString &operator+=(const UString &s); void SetFrom(const wchar_t *s, unsigned len); // no check void SetFromAscii(const char *s); void AddAsciiStr(const char *s); UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } UString Left(unsigned count) const { return UString(count, *this); } // void MakeUpper() { MyStringUpper(_chars); } // void MakeUpper() { MyStringUpper_Ascii(_chars); } // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } bool IsEqualToNoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }; bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } int Find(wchar_t c, unsigned startIndex) const { int pos = FindCharPosInString(_chars + startIndex, c); return pos < 0 ? -1 : (int)startIndex + pos; } int Find(const UString &s) const { return Find(s, 0); } int Find(const UString &s, unsigned startIndex) const throw(); int ReverseFind(wchar_t c) const throw(); void TrimLeft() throw(); void TrimRight() throw(); void Trim() { TrimRight(); TrimLeft(); } void InsertAtFront(wchar_t c); // void Insert(unsigned index, wchar_t c); void Insert(unsigned index, const wchar_t *s); void Insert(unsigned index, const UString &s); void RemoveChar(wchar_t ch) throw(); void Replace(wchar_t oldChar, wchar_t newChar) throw(); void Replace(const UString &oldString, const UString &newString); void Delete(unsigned index) throw(); void Delete(unsigned index, unsigned count) throw(); void DeleteFrontal(unsigned num) throw(); void DeleteBack() { _chars[--_len] = 0; } void DeleteFrom(unsigned index) { if (index < _len) { _len = index; _chars[index] = 0; } } }; bool operator<(const UString &s1, const UString &s2); bool operator>(const UString &s1, const UString &s2); inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } typedef CObjectVector AStringVector; typedef CObjectVector UStringVector; #ifdef _UNICODE typedef UString CSysString; #else typedef AString CSysString; #endif typedef CObjectVector CSysStringVector; // ---------- FString ---------- #ifdef _WIN32 #define USE_UNICODE_FSTRING #endif #ifdef USE_UNICODE_FSTRING #define __FTEXT(quote) L##quote typedef wchar_t FChar; typedef UString FString; #define fs2us(_x_) (_x_) #define us2fs(_x_) (_x_) FString fas2fs(const AString &s); AString fs2fas(const FChar *s); #else #define __FTEXT(quote) quote typedef char FChar; typedef AString FString; UString fs2us(const FString &s); FString us2fs(const wchar_t *s); #define fas2fs(_x_) (_x_) #define fs2fas(_x_) (_x_) #endif #define FTEXT(quote) __FTEXT(quote) #define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) #define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) #define FCHAR_ANY_MASK FTEXT('*') #define FSTRING_ANY_MASK FTEXT("*") typedef const FChar *CFSTR; typedef CObjectVector FStringVector; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyTypes.h0100777000000000000000000000052613761647206021746 0ustar00// Common/MyTypes.h #ifndef __COMMON_MY_TYPES_H #define __COMMON_MY_TYPES_H #include "../../C/7zTypes.h" typedef int HRes; struct CBoolPair { bool Val; bool Def; CBoolPair(): Val(false), Def(false) {} void Init() { Val = false; Def = false; } void SetTrueTrue() { Val = true; Def = true; } }; #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyUnknown.h0100777000000000000000000000024313761647206022275 0ustar00// MyUnknown.h #ifndef __MY_UNKNOWN_H #define __MY_UNKNOWN_H #ifdef _WIN32 #include #include #else #include "MyWindows.h" #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyVector.h0100777000000000000000000003067113761647206022110 0ustar00// Common/MyVector.h #ifndef __COMMON_MY_VECTOR_H #define __COMMON_MY_VECTOR_H template class CRecordVector { T *_items; unsigned _size; unsigned _capacity; void MoveItems(unsigned destIndex, unsigned srcIndex) { memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * (size_t)sizeof(T)); } void ReserveOnePosition() { if (_size == _capacity) { unsigned newCapacity = _capacity + (_capacity >> 2) + 1; T *p = new T[newCapacity]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newCapacity; } } public: CRecordVector(): _items(0), _size(0), _capacity(0) {} CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0) { unsigned size = v.Size(); if (size != 0) { _items = new T[size]; _size = size; _capacity = size; memcpy(_items, v._items, (size_t)size * (size_t)sizeof(T)); } } unsigned Size() const { return _size; } bool IsEmpty() const { return _size == 0; } void ConstructReserve(unsigned size) { if (size != 0) { _items = new T[size]; _capacity = size; } } void Reserve(unsigned newCapacity) { if (newCapacity > _capacity) { T *p = new T[newCapacity]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newCapacity; } } void ClearAndReserve(unsigned newCapacity) { Clear(); if (newCapacity > _capacity) { delete []_items; _items = NULL; _capacity = 0; _items = new T[newCapacity]; _capacity = newCapacity; } } void ClearAndSetSize(unsigned newSize) { ClearAndReserve(newSize); _size = newSize; } void ChangeSize_KeepData(unsigned newSize) { if (newSize > _capacity) { T *p = new T[newSize]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); delete []_items; _items = p; _capacity = newSize; } _size = newSize; } void ReserveDown() { if (_size == _capacity) return; T *p = NULL; if (_size != 0) { p = new T[_size]; memcpy(p, _items, (size_t)_size * (size_t)sizeof(T)); } delete []_items; _items = p; _capacity = _size; } ~CRecordVector() { delete []_items; } void ClearAndFree() { delete []_items; _items = NULL; _size = 0; _capacity = 0; } void Clear() { _size = 0; } void DeleteBack() { _size--; } void DeleteFrom(unsigned index) { // if (index <= _size) _size = index; } void DeleteFrontal(unsigned num) { if (num != 0) { MoveItems(0, num); _size -= num; } } void Delete(unsigned index) { MoveItems(index, index + 1); _size -= 1; } /* void Delete(unsigned index, unsigned num) { if (num > 0) { MoveItems(index, index + num); _size -= num; } } */ CRecordVector& operator=(const CRecordVector &v) { unsigned size = v.Size(); if (size > _capacity) { delete []_items; _capacity = 0; _size = 0; _items = NULL; _items = new T[size]; _capacity = size; } _size = size; memcpy(_items, v._items, (size_t)size * (size_t)sizeof(T)); return *this; } CRecordVector& operator+=(const CRecordVector &v) { unsigned size = v.Size(); Reserve(_size + size); memcpy(_items + _size, v._items, (size_t)size * (size_t)sizeof(T)); _size += size; return *this; } unsigned Add(const T item) { ReserveOnePosition(); _items[_size] = item; return _size++; } void AddInReserved(const T item) { _items[_size++] = item; } void Insert(unsigned index, const T item) { ReserveOnePosition(); MoveItems(index + 1, index); _items[index] = item; _size++; } void MoveToFront(unsigned index) { if (index != 0) { T temp = _items[index]; memmove(_items + 1, _items, (size_t)index * (size_t)sizeof(T)); _items[0] = temp; } } const T& operator[](unsigned index) const { return _items[index]; } T& operator[](unsigned index) { return _items[index]; } const T& Front() const { return _items[0]; } T& Front() { return _items[0]; } const T& Back() const { return _items[_size - 1]; } T& Back() { return _items[_size - 1]; } /* void Swap(unsigned i, unsigned j) { T temp = _items[i]; _items[i] = _items[j]; _items[j] = temp; } */ int FindInSorted(const T item, unsigned left, unsigned right) const { while (left != right) { unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return mid; if (item < midVal) right = mid; else left = mid + 1; } return -1; } int FindInSorted2(const T &item, unsigned left, unsigned right) const { while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } return -1; } int FindInSorted(const T item) const { return FindInSorted(item, 0, _size); } int FindInSorted2(const T &item) const { return FindInSorted2(item, 0, _size); } unsigned AddToUniqueSorted(const T item) { unsigned left = 0, right = _size; while (left != right) { unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return mid; if (item < midVal) right = mid; else left = mid + 1; } Insert(right, item); return right; } unsigned AddToUniqueSorted2(const T &item) { unsigned left = 0, right = _size; while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param) { T temp = p[k]; for (;;) { unsigned s = (k << 1); if (s > size) break; if (s < size && compare(p + s + 1, p + s, param) > 0) s++; if (compare(&temp, p + s, param) >= 0) break; p[k] = p[s]; k = s; } p[k] = temp; } void Sort(int (*compare)(const T*, const T*, void *), void *param) { unsigned size = _size; if (size <= 1) return; T* p = (&Front()) - 1; { unsigned i = size >> 1; do SortRefDown(p, i, size, compare, param); while (--i != 0); } do { T temp = p[size]; p[size--] = p[1]; p[1] = temp; SortRefDown(p, 1, size, compare, param); } while (size > 1); } static void SortRefDown2(T* p, unsigned k, unsigned size) { T temp = p[k]; for (;;) { unsigned s = (k << 1); if (s > size) break; if (s < size && p[s + 1].Compare(p[s]) > 0) s++; if (temp.Compare(p[s]) >= 0) break; p[k] = p[s]; k = s; } p[k] = temp; } void Sort2() { unsigned size = _size; if (size <= 1) return; T* p = (&Front()) - 1; { unsigned i = size >> 1; do SortRefDown2(p, i, size); while (--i != 0); } do { T temp = p[size]; p[size--] = p[1]; p[1] = temp; SortRefDown2(p, 1, size); } while (size > 1); } }; typedef CRecordVector CIntVector; typedef CRecordVector CUIntVector; typedef CRecordVector CBoolVector; typedef CRecordVector CByteVector; typedef CRecordVector CPointerVector; template class CObjectVector { CPointerVector _v; public: unsigned Size() const { return _v.Size(); } bool IsEmpty() const { return _v.IsEmpty(); } void ReserveDown() { _v.ReserveDown(); } // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); } void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); } CObjectVector() {}; CObjectVector(const CObjectVector &v) { unsigned size = v.Size(); _v.ConstructReserve(size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); } CObjectVector& operator=(const CObjectVector &v) { Clear(); unsigned size = v.Size(); _v.Reserve(size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); return *this; } CObjectVector& operator+=(const CObjectVector &v) { unsigned size = v.Size(); _v.Reserve(Size() + size); for (unsigned i = 0; i < size; i++) _v.AddInReserved(new T(v[i])); return *this; } const T& operator[](unsigned index) const { return *((T *)_v[index]); } T& operator[](unsigned index) { return *((T *)_v[index]); } const T& Front() const { return operator[](0); } T& Front() { return operator[](0); } const T& Back() const { return operator[](_v.Size() - 1); } T& Back() { return operator[](_v.Size() - 1); } void MoveToFront(unsigned index) { _v.MoveToFront(index); } unsigned Add(const T& item) { return _v.Add(new T(item)); } void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); } T& AddNew() { T *p = new T; _v.Add(p); return *p; } T& AddNewInReserved() { T *p = new T; _v.AddInReserved(p); return *p; } void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); } T& InsertNew(unsigned index) { T *p = new T; _v.Insert(index, p); return *p; } ~CObjectVector() { for (unsigned i = _v.Size(); i != 0;) delete (T *)_v[--i]; } void ClearAndFree() { Clear(); _v.ClearAndFree(); } void Clear() { for (unsigned i = _v.Size(); i != 0;) delete (T *)_v[--i]; _v.Clear(); } void DeleteFrom(unsigned index) { unsigned size = _v.Size(); for (unsigned i = index; i < size; i++) delete (T *)_v[i]; _v.DeleteFrom(index); } void DeleteFrontal(unsigned num) { for (unsigned i = 0; i < num; i++) delete (T *)_v[i]; _v.DeleteFrontal(num); } void DeleteBack() { delete (T *)_v[_v.Size() - 1]; _v.DeleteBack(); } void Delete(unsigned index) { delete (T *)_v[index]; _v.Delete(index); } /* void Delete(unsigned index, unsigned num) { for (unsigned i = 0; i < num; i++) delete (T *)_v[index + i]; _v.Delete(index, num); } */ /* int Find(const T& item) const { unsigned size = Size(); for (unsigned i = 0; i < size; i++) if (item == (*this)[i]) return i; return -1; } */ int FindInSorted(const T& item) const { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } return -1; } unsigned AddToUniqueSorted(const T& item) { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } /* unsigned AddToSorted(const T& item) { unsigned left = 0, right = Size(); while (left != right) { unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; int comp = item.Compare(midVal); if (comp == 0) { right = mid + 1; break; } if (comp < 0) right = mid; else left = mid + 1; } Insert(right, item); return right; } */ void Sort(int (*compare)(void *const *, void *const *, void *), void *param) { _v.Sort(compare, param); } static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */) { return (*(*((const T **)a1))).Compare(*(*((const T **)a2))); } void Sort() { _v.Sort(CompareObjectItems, 0); } }; #define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++) #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyWindows.cpp0100777000000000000000000000672513761647206022636 0ustar00// MyWindows.cpp #include "StdAfx.h" #ifndef _WIN32 #include #include "MyWindows.h" static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } static inline void FreeForBSTR(void *pv) { ::free(pv);} /* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string. We must select CBstrSizeType for another systems (not Win32): if (CBstrSizeType is UINT32), then we support only strings smaller than 4 GB. Win32 version always has that limitation. if (CBstrSizeType is UINT), (UINT can be 16/32/64-bit) We can support strings larger than 4 GB (if UINT is 64-bit), but sizeof(UINT) can be different in parts compiled by different compilers/settings, and we can't send such BSTR strings between such parts. */ typedef UINT32 CBstrSizeType; // typedef UINT CBstrSizeType; #define k_BstrSize_Max 0xFFFFFFFF // #define k_BstrSize_Max UINT_MAX // #define k_BstrSize_Max ((UINT)(INT)-1) BSTR SysAllocStringByteLen(LPCSTR s, UINT len) { /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end. We provide also aligned null OLECHAR at the end. */ if (len >= (k_BstrSize_Max - sizeof(OLECHAR) - sizeof(OLECHAR) - sizeof(CBstrSizeType))) return NULL; UINT size = (len + sizeof(OLECHAR) + sizeof(OLECHAR) - 1) & ~(sizeof(OLECHAR) - 1); void *p = AllocateForBSTR(size + sizeof(CBstrSizeType)); if (!p) return NULL; *(CBstrSizeType *)p = (CBstrSizeType)len; BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); if (s) memcpy(bstr, s, len); for (; len < size; len++) ((Byte *)bstr)[len] = 0; return bstr; } BSTR SysAllocStringLen(const OLECHAR *s, UINT len) { if (len >= (k_BstrSize_Max - sizeof(OLECHAR) - sizeof(CBstrSizeType)) / sizeof(OLECHAR)) return NULL; UINT size = len * sizeof(OLECHAR); void *p = AllocateForBSTR(size + sizeof(CBstrSizeType) + sizeof(OLECHAR)); if (!p) return NULL; *(CBstrSizeType *)p = (CBstrSizeType)size; BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); if (s) memcpy(bstr, s, size); bstr[len] = 0; return bstr; } BSTR SysAllocString(const OLECHAR *s) { if (!s) return 0; const OLECHAR *s2 = s; while (*s2 != 0) s2++; return SysAllocStringLen(s, (UINT)(s2 - s)); } void SysFreeString(BSTR bstr) { if (bstr) FreeForBSTR((CBstrSizeType *)bstr - 1); } UINT SysStringByteLen(BSTR bstr) { if (!bstr) return 0; return *((CBstrSizeType *)bstr - 1); } UINT SysStringLen(BSTR bstr) { if (!bstr) return 0; return *((CBstrSizeType *)bstr - 1) / sizeof(OLECHAR); } HRESULT VariantClear(VARIANTARG *prop) { if (prop->vt == VT_BSTR) SysFreeString(prop->bstrVal); prop->vt = VT_EMPTY; return S_OK; } HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src) { HRESULT res = ::VariantClear(dest); if (res != S_OK) return res; if (src->vt == VT_BSTR) { dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, SysStringByteLen(src->bstrVal)); if (!dest->bstrVal) return E_OUTOFMEMORY; dest->vt = VT_BSTR; } else *dest = *src; return S_OK; } LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) { if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; return 0; } DWORD GetLastError() { return 0; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/MyWindows.h0100777000000000000000000001047613761647206022301 0ustar00// MyWindows.h #ifndef __MY_WINDOWS_H #define __MY_WINDOWS_H #ifdef _WIN32 #include #ifdef UNDER_CE #undef VARIANT_TRUE #define VARIANT_TRUE ((VARIANT_BOOL)-1) #endif #else #include // for wchar_t #include #include "MyGuidDef.h" #define WINAPI typedef char CHAR; typedef unsigned char UCHAR; #undef BYTE typedef unsigned char BYTE; typedef short SHORT; typedef unsigned short USHORT; #undef WORD typedef unsigned short WORD; typedef short VARIANT_BOOL; typedef int INT; typedef Int32 INT32; typedef unsigned int UINT; typedef UInt32 UINT32; typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit typedef UINT32 ULONG; #undef DWORD typedef UINT32 DWORD; typedef Int64 LONGLONG; typedef UInt64 ULONGLONG; typedef struct _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER; typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart; } ULARGE_INTEGER; typedef const CHAR *LPCSTR; typedef CHAR TCHAR; typedef const TCHAR *LPCTSTR; typedef wchar_t WCHAR; typedef WCHAR OLECHAR; typedef const WCHAR *LPCWSTR; typedef OLECHAR *BSTR; typedef const OLECHAR *LPCOLESTR; typedef OLECHAR *LPOLESTR; typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME; #define HRESULT LONG #define FAILED(Status) ((HRESULT)(Status)<0) typedef ULONG PROPID; typedef LONG SCODE; #define S_OK ((HRESULT)0x00000000L) #define S_FALSE ((HRESULT)0x00000001L) #define E_NOTIMPL ((HRESULT)0x80004001L) #define E_NOINTERFACE ((HRESULT)0x80004002L) #define E_ABORT ((HRESULT)0x80004004L) #define E_FAIL ((HRESULT)0x80004005L) #define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) #define E_OUTOFMEMORY ((HRESULT)0x8007000EL) #define E_INVALIDARG ((HRESULT)0x80070057L) #ifdef _MSC_VER #define STDMETHODCALLTYPE __stdcall #else #define STDMETHODCALLTYPE #endif #define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f #define STDMETHOD(f) STDMETHOD_(HRESULT, f) #define STDMETHODIMP_(type) type STDMETHODCALLTYPE #define STDMETHODIMP STDMETHODIMP_(HRESULT) #define PURE = 0 #define MIDL_INTERFACE(x) struct #ifdef __cplusplus DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); struct IUnknown { STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE; STDMETHOD_(ULONG, AddRef)() PURE; STDMETHOD_(ULONG, Release)() PURE; #ifndef _WIN32 virtual ~IUnknown() {} #endif }; typedef IUnknown *LPUNKNOWN; #endif #define VARIANT_TRUE ((VARIANT_BOOL)-1) #define VARIANT_FALSE ((VARIANT_BOOL)0) enum VARENUM { VT_EMPTY = 0, VT_NULL = 1, VT_I2 = 2, VT_I4 = 3, VT_R4 = 4, VT_R8 = 5, VT_CY = 6, VT_DATE = 7, VT_BSTR = 8, VT_DISPATCH = 9, VT_ERROR = 10, VT_BOOL = 11, VT_VARIANT = 12, VT_UNKNOWN = 13, VT_DECIMAL = 14, VT_I1 = 16, VT_UI1 = 17, VT_UI2 = 18, VT_UI4 = 19, VT_I8 = 20, VT_UI8 = 21, VT_INT = 22, VT_UINT = 23, VT_VOID = 24, VT_HRESULT = 25, VT_FILETIME = 64 }; typedef unsigned short VARTYPE; typedef WORD PROPVAR_PAD1; typedef WORD PROPVAR_PAD2; typedef WORD PROPVAR_PAD3; typedef struct tagPROPVARIANT { VARTYPE vt; PROPVAR_PAD1 wReserved1; PROPVAR_PAD2 wReserved2; PROPVAR_PAD3 wReserved3; union { CHAR cVal; UCHAR bVal; SHORT iVal; USHORT uiVal; LONG lVal; ULONG ulVal; INT intVal; UINT uintVal; LARGE_INTEGER hVal; ULARGE_INTEGER uhVal; VARIANT_BOOL boolVal; SCODE scode; FILETIME filetime; BSTR bstrVal; }; } PROPVARIANT; typedef PROPVARIANT tagVARIANT; typedef tagVARIANT VARIANT; typedef VARIANT VARIANTARG; MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop); MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src); typedef struct tagSTATPROPSTG { LPOLESTR lpwstrName; PROPID propid; VARTYPE vt; } STATPROPSTG; MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); MY_EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len); MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz); MY_EXTERN_C void SysFreeString(BSTR bstr); MY_EXTERN_C UINT SysStringByteLen(BSTR bstr); MY_EXTERN_C UINT SysStringLen(BSTR bstr); MY_EXTERN_C DWORD GetLastError(); MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); #define CP_ACP 0 #define CP_OEMCP 1 #define CP_UTF8 65001 typedef enum tagSTREAM_SEEK { STREAM_SEEK_SET = 0, STREAM_SEEK_CUR = 1, STREAM_SEEK_END = 2 } STREAM_SEEK; #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/NewHandler.cpp0100777000000000000000000000466513761647206022726 0ustar00// NewHandler.cpp #include "StdAfx.h" #include #include "NewHandler.h" // #define DEBUG_MEMORY_LEAK #ifndef DEBUG_MEMORY_LEAK #ifdef _WIN32 /* void * my_new(size_t size) { // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); void *p = ::malloc(size); if (p == 0) throw CNewException(); return p; } void my_delete(void *p) throw() { // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); ::free(p); } void * my_Realloc(void *p, size_t newSize, size_t oldSize) { void *newBuf = my_new(newSize); memcpy(newBuf, p, oldSize); my_delete(p); return newBuf; } */ void * #ifdef _MSC_VER __cdecl #endif operator new(size_t size) { // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); void *p = ::malloc(size); if (p == 0) throw CNewException(); return p; } void #ifdef _MSC_VER __cdecl #endif operator delete(void *p) throw() { // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); ::free(p); } /* void * #ifdef _MSC_VER __cdecl #endif operator new[](size_t size) { // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); void *p = ::malloc(size); if (p == 0) throw CNewException(); return p; } void #ifdef _MSC_VER __cdecl #endif operator delete[](void *p) throw() { // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); ::free(p); } */ #endif #else #include // #pragma init_seg(lib) const int kDebugSize = 1000000; static void *a[kDebugSize]; static int index = 0; static int numAllocs = 0; void * __cdecl operator new(size_t size) { numAllocs++; void *p = HeapAlloc(GetProcessHeap(), 0, size); if (index < kDebugSize) { a[index] = p; index++; } if (p == 0) throw CNewException(); printf("Alloc %6d, size = %8d\n", numAllocs, size); return p; } class CC { public: CC() { for (int i = 0; i < kDebugSize; i++) a[i] = 0; } ~CC() { for (int i = 0; i < kDebugSize; i++) if (a[i] != 0) return; } } g_CC; void __cdecl operator delete(void *p) { if (p == 0) return; /* for (int i = 0; i < index; i++) if (a[i] == p) a[i] = 0; */ HeapFree(GetProcessHeap(), 0, p); numAllocs--; printf("Free %d\n", numAllocs); } #endif /* int MemErrorVC(size_t) { throw CNewException(); // return 1; } CNewHandlerSetter::CNewHandlerSetter() { // MemErrorOldVCFunction = _set_new_handler(MemErrorVC); } CNewHandlerSetter::~CNewHandlerSetter() { // _set_new_handler(MemErrorOldVCFunction); } */ qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/NewHandler.h0100777000000000000000000000304013761647206022355 0ustar00// Common/NewHandler.h #ifndef __COMMON_NEW_HANDLER_H #define __COMMON_NEW_HANDLER_H /* This file must be included before any code that uses operators "delete" or "new". Also you must compile and link "NewHandler.cpp", if you use MSVC 6.0. The operator "new" in MSVC 6.0 doesn't throw exception "bad_alloc". So we define another version of operator "new" that throws "CNewException" on failure. If you use compiler that throws exception in "new" operator (GCC or new version of MSVC), you can compile without "NewHandler.cpp". So standard exception "bad_alloc" will be used. It's still allowed to use redefined version of operator "new" from "NewHandler.cpp" with any compiler. 7-Zip's code can work with "bad_alloc" and "CNewException" exceptions. But if you use some additional code (outside of 7-Zip's code), you must check that redefined version of operator "new" (that throws CNewException) is not problem for your code. Also we declare delete(void *p) throw() that creates smaller code. */ class CNewException {}; #ifdef WIN32 // We can compile my_new and my_delete with _fastcall /* void * my_new(size_t size); void my_delete(void *p) throw(); // void * my_Realloc(void *p, size_t newSize, size_t oldSize); */ #endif #ifdef _WIN32 void * #ifdef _MSC_VER __cdecl #endif operator new(size_t size); void #ifdef _MSC_VER __cdecl #endif operator delete(void *p) throw(); #endif /* #ifdef _WIN32 void * #ifdef _MSC_VER __cdecl #endif operator new[](size_t size); void #ifdef _MSC_VER __cdecl #endif operator delete[](void *p) throw(); #endif */ #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StdAfx.h0100777000000000000000000000012013761647206021513 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StdOutStream.cpp0100777000000000000000000000421513761647206023264 0ustar00// Common/StdOutStream.cpp #include "StdAfx.h" #include #include "IntToString.h" #include "StdOutStream.h" #include "StringConvert.h" #include "UTFConvert.h" static const char kNewLineChar = '\n'; static const char *kFileOpenMode = "wt"; extern int g_CodePage; CStdOutStream g_StdOut(stdout); CStdOutStream g_StdErr(stderr); bool CStdOutStream::Open(const char *fileName) throw() { Close(); _stream = fopen(fileName, kFileOpenMode); _streamIsOpen = (_stream != 0); return _streamIsOpen; } bool CStdOutStream::Close() throw() { if (!_streamIsOpen) return true; if (fclose(_stream) != 0) return false; _stream = 0; _streamIsOpen = false; return true; } bool CStdOutStream::Flush() throw() { return (fflush(_stream) == 0); } CStdOutStream & endl(CStdOutStream & outStream) throw() { return outStream << kNewLineChar; } CStdOutStream & CStdOutStream::operator<<(const wchar_t *s) { int codePage = g_CodePage; if (codePage == -1) codePage = CP_OEMCP; AString dest; if (codePage == CP_UTF8) ConvertUnicodeToUTF8(s, dest); else UnicodeStringToMultiByte2(dest, s, (UINT)codePage); return operator<<((const char *)dest); } void StdOut_Convert_UString_to_AString(const UString &s, AString &temp) { int codePage = g_CodePage; if (codePage == -1) codePage = CP_OEMCP; if (codePage == CP_UTF8) ConvertUnicodeToUTF8(s, temp); else UnicodeStringToMultiByte2(temp, s, (UINT)codePage); } void CStdOutStream::PrintUString(const UString &s, AString &temp) { StdOut_Convert_UString_to_AString(s, temp); *this << (const char *)temp; } CStdOutStream & CStdOutStream::operator<<(Int32 number) throw() { char s[32]; ConvertInt64ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(Int64 number) throw() { char s[32]; ConvertInt64ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw() { char s[16]; ConvertUInt32ToString(number, s); return operator<<(s); } CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw() { char s[32]; ConvertUInt64ToString(number, s); return operator<<(s); } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StdOutStream.h0100777000000000000000000000273613761647206022737 0ustar00// Common/StdOutStream.h #ifndef __COMMON_STD_OUT_STREAM_H #define __COMMON_STD_OUT_STREAM_H #include #include "MyString.h" #include "MyTypes.h" class CStdOutStream { FILE *_stream; bool _streamIsOpen; public: CStdOutStream(): _stream(0), _streamIsOpen(false) {}; CStdOutStream(FILE *stream): _stream(stream), _streamIsOpen(false) {}; ~CStdOutStream() { Close(); } // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; } // bool IsDefined() const { return _stream != NULL; } operator FILE *() { return _stream; } bool Open(const char *fileName) throw(); bool Close() throw(); bool Flush() throw(); CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &)) { (*func)(*this); return *this; } CStdOutStream & operator<<(const char *s) throw() { fputs(s, _stream); return *this; } CStdOutStream & operator<<(char c) throw() { fputc(c, _stream); return *this; } CStdOutStream & operator<<(Int32 number) throw(); CStdOutStream & operator<<(Int64 number) throw(); CStdOutStream & operator<<(UInt32 number) throw(); CStdOutStream & operator<<(UInt64 number) throw(); CStdOutStream & operator<<(const wchar_t *s); void PrintUString(const UString &s, AString &temp); }; CStdOutStream & endl(CStdOutStream & outStream) throw(); extern CStdOutStream g_StdOut; extern CStdOutStream g_StdErr; void StdOut_Convert_UString_to_AString(const UString &s, AString &temp); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StringConvert.cpp0100777000000000000000000001027313761647206023476 0ustar00// Common/StringConvert.cpp #include "StdAfx.h" #include "StringConvert.h" #ifndef _WIN32 #include #endif #ifdef _WIN32 UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) { UString resultString; if (!srcString.IsEmpty()) { int numChars = MultiByteToWideChar(codePage, 0, srcString, srcString.Len(), resultString.GetBuffer(srcString.Len()), srcString.Len() + 1); if (numChars == 0) throw 282228; resultString.ReleaseBuffer(numChars); } return resultString; } void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage) { dest.Empty(); if (!srcString.IsEmpty()) { wchar_t *destBuf = dest.GetBuffer(srcString.Len()); const char *sp = (const char *)srcString; unsigned i; for (i = 0;;) { char c = sp[i]; if ((Byte)c >= 0x80 || c == 0) break; destBuf[i++] = (wchar_t)c; } if (i != srcString.Len()) { unsigned numChars = MultiByteToWideChar(codePage, 0, sp + i, srcString.Len() - i, destBuf + i, srcString.Len() + 1 - i); if (numChars == 0) throw 282228; i += numChars; } dest.ReleaseBuffer(i); } } void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed) { dest.Empty(); defaultCharWasUsed = false; if (!s.IsEmpty()) { unsigned numRequiredBytes = s.Len() * 2; char *destBuf = dest.GetBuffer(numRequiredBytes); unsigned i; const wchar_t *sp = (const wchar_t *)s; for (i = 0;;) { wchar_t c = sp[i]; if (c >= 0x80 || c == 0) break; destBuf[i++] = (char)c; } defaultCharWasUsed = false; if (i != s.Len()) { BOOL defUsed; unsigned numChars = WideCharToMultiByte(codePage, 0, sp + i, s.Len() - i, destBuf + i, numRequiredBytes + 1 - i, &defaultChar, &defUsed); defaultCharWasUsed = (defUsed != FALSE); if (numChars == 0) throw 282229; i += numChars; } dest.ReleaseBuffer(i); } } void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage) { bool defaultCharWasUsed; UnicodeStringToMultiByte2(dest, srcString, codePage, '_', defaultCharWasUsed); } AString UnicodeStringToMultiByte(const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed) { AString dest; defaultCharWasUsed = false; if (!s.IsEmpty()) { unsigned numRequiredBytes = s.Len() * 2; BOOL defUsed; int numChars = WideCharToMultiByte(codePage, 0, s, s.Len(), dest.GetBuffer(numRequiredBytes), numRequiredBytes + 1, &defaultChar, &defUsed); defaultCharWasUsed = (defUsed != FALSE); if (numChars == 0) throw 282229; dest.ReleaseBuffer(numChars); } return dest; } AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) { bool defaultCharWasUsed; return UnicodeStringToMultiByte(srcString, codePage, '_', defaultCharWasUsed); } #ifndef UNDER_CE AString SystemStringToOemString(const CSysString &srcString) { AString result; CharToOem(srcString, result.GetBuffer(srcString.Len() * 2)); result.ReleaseBuffer(); return result; } #endif #else UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) { UString resultString; for (unsigned i = 0; i < srcString.Len(); i++) resultString += (wchar_t)srcString[i]; /* if (!srcString.IsEmpty()) { int numChars = mbstowcs(resultString.GetBuffer(srcString.Len()), srcString, srcString.Len() + 1); if (numChars < 0) throw "Your environment does not support UNICODE"; resultString.ReleaseBuffer(numChars); } */ return resultString; } AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) { AString resultString; for (unsigned i = 0; i < srcString.Len(); i++) resultString += (char)srcString[i]; /* if (!srcString.IsEmpty()) { int numRequiredBytes = srcString.Len() * 6 + 1; int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes); if (numChars < 0) throw "Your environment does not support UNICODE"; resultString.ReleaseBuffer(numChars); } */ return resultString; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StringConvert.h0100777000000000000000000000653713761647206023153 0ustar00// Common/StringConvert.h #ifndef __COMMON_STRING_CONVERT_H #define __COMMON_STRING_CONVERT_H #include "MyString.h" #include "MyWindows.h" UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP); // optimized versions that work faster for ASCII strings void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage = CP_ACP); void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed); void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage); AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage, char defaultChar, bool &defaultCharWasUsed); AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP); inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString) { return unicodeString; } inline const UString& GetUnicodeString(const UString &unicodeString) { return unicodeString; } inline UString GetUnicodeString(const AString &ansiString) { return MultiByteToUnicodeString(ansiString); } inline UString GetUnicodeString(const AString &multiByteString, UINT codePage) { return MultiByteToUnicodeString(multiByteString, codePage); } inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT) { return unicodeString; } inline const UString& GetUnicodeString(const UString &unicodeString, UINT) { return unicodeString; } inline const char* GetAnsiString(const char* ansiString) { return ansiString; } inline const AString& GetAnsiString(const AString &ansiString) { return ansiString; } inline AString GetAnsiString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString); } inline const char* GetOemString(const char* oemString) { return oemString; } inline const AString& GetOemString(const AString &oemString) { return oemString; } inline AString GetOemString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); } #ifdef _UNICODE inline const wchar_t* GetSystemString(const wchar_t* unicodeString) { return unicodeString;} inline const UString& GetSystemString(const UString &unicodeString) { return unicodeString;} inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */) { return unicodeString;} inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */) { return unicodeString;} inline UString GetSystemString(const AString &multiByteString, UINT codePage) { return MultiByteToUnicodeString(multiByteString, codePage);} inline UString GetSystemString(const AString &multiByteString) { return MultiByteToUnicodeString(multiByteString);} #else inline const char* GetSystemString(const char *ansiString) { return ansiString; } inline const AString& GetSystemString(const AString &multiByteString, UINT) { return multiByteString; } inline const char * GetSystemString(const char *multiByteString, UINT) { return multiByteString; } inline AString GetSystemString(const UString &unicodeString) { return UnicodeStringToMultiByte(unicodeString); } inline AString GetSystemString(const UString &unicodeString, UINT codePage) { return UnicodeStringToMultiByte(unicodeString, codePage); } #endif #ifndef UNDER_CE AString SystemStringToOemString(const CSysString &srcString); #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StringToInt.cpp0100777000000000000000000000606113761647206023113 0ustar00// Common/StringToInt.cpp #include "StdAfx.h" #include "StringToInt.h" static const UInt32 k_UInt32_max = 0xFFFFFFFF; static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF); // static const UInt64 k_UInt64_max = (UInt64)(Int64)-1; #define CONVERT_STRING_TO_UINT_FUNC(uintType, charType) \ uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ if (end) *end = s; \ uintType res = 0; \ for (;; s++) { \ charType c = *s; \ if (c < '0' || c > '9') { if (end) *end = s; return res; } \ if (res > (k_ ## uintType ## _max) / 10) return 0; \ res *= 10; \ unsigned v = (c - '0'); \ if (res > (k_ ## uintType ## _max) - v) return 0; \ res += v; }} CONVERT_STRING_TO_UINT_FUNC(UInt32, char) CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t) CONVERT_STRING_TO_UINT_FUNC(UInt64, char) CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t) Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() { if (end) *end = s; const wchar_t *s2 = s; if (*s == '-') s2++; if (*s2 == 0) return 0; const wchar_t *end2; UInt32 res = ConvertStringToUInt32(s2, &end2); if (*s == '-') { if (res > ((UInt32)1 << (32 - 1))) return 0; } else if ((res & ((UInt32)1 << (32 - 1))) != 0) return 0; if (end) *end = end2; if (*s == '-') return -(Int32)res; return (Int32)res; } UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw() { if (end) *end = s; UInt32 res = 0; for (;; s++) { char c = *s; if (c < '0' || c > '7') { if (end) *end = s; return res; } if ((res & (UInt32)7 << (32 - 3)) != 0) return 0; res <<= 3; res |= (unsigned)(c - '0'); } } UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw() { if (end) *end = s; UInt64 res = 0; for (;; s++) { char c = *s; if (c < '0' || c > '7') { if (end) *end = s; return res; } if ((res & (UInt64)7 << (64 - 3)) != 0) return 0; res <<= 3; res |= (unsigned)(c - '0'); } } UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw() { if (end) *end = s; UInt32 res = 0; for (;; s++) { char c = *s; unsigned v; if (c >= '0' && c <= '9') v = (c - '0'); else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); else { if (end) *end = s; return res; } if ((res & (UInt32)0xF << (32 - 4)) != 0) return 0; res <<= 4; res |= v; } } UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw() { if (end) *end = s; UInt64 res = 0; for (;; s++) { char c = *s; unsigned v; if (c >= '0' && c <= '9') v = (c - '0'); else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); else { if (end) *end = s; return res; } if ((res & (UInt64)0xF << (64 - 4)) != 0) return 0; res <<= 4; res |= v; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/StringToInt.h0100777000000000000000000000143013761647206022553 0ustar00// Common/StringToInt.h #ifndef __COMMON_STRING_TO_INT_H #define __COMMON_STRING_TO_INT_H #include "MyTypes.h" UInt32 ConvertStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertStringToUInt64(const char *s, const char **end) throw(); UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw(); UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw(); UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw(); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/UTFConvert.cpp0100777000000000000000000000724413761647206022672 0ustar00// UTFConvert.cpp #include "StdAfx.h" #include "MyTypes.h" #include "UTFConvert.h" static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; bool CheckUTF8(const char *src) throw() { for (;;) { Byte c; unsigned numAdds; c = *src++; if (c == 0) return true; if (c < 0x80) continue; if (c < 0xC0) return false; for (numAdds = 1; numAdds < 5; numAdds++) if (c < kUtf8Limits[numAdds]) break; UInt32 value = (c - kUtf8Limits[numAdds - 1]); do { Byte c2 = *src++; if (c2 < 0x80 || c2 >= 0xC0) return false; value <<= 6; value |= (c2 - 0x80); } while (--numAdds); if (value >= 0x110000) return false; } } static Bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, size_t srcLen) throw() { size_t destPos = 0, srcPos = 0; for (;;) { Byte c; unsigned numAdds; if (srcPos == srcLen) { *destLen = destPos; return True; } c = (Byte)src[srcPos++]; if (c < 0x80) { if (dest) dest[destPos] = (wchar_t)c; destPos++; continue; } if (c < 0xC0) break; for (numAdds = 1; numAdds < 5; numAdds++) if (c < kUtf8Limits[numAdds]) break; UInt32 value = (c - kUtf8Limits[numAdds - 1]); do { Byte c2; if (srcPos == srcLen) break; c2 = (Byte)src[srcPos++]; if (c2 < 0x80 || c2 >= 0xC0) break; value <<= 6; value |= (c2 - 0x80); } while (--numAdds); if (value < 0x10000) { if (dest) dest[destPos] = (wchar_t)value; destPos++; } else { value -= 0x10000; if (value >= 0x100000) break; if (dest) { dest[destPos + 0] = (wchar_t)(0xD800 + (value >> 10)); dest[destPos + 1] = (wchar_t)(0xDC00 + (value & 0x3FF)); } destPos += 2; } } *destLen = destPos; return False; } static Bool Utf16_To_Utf8(char *dest, size_t *destLen, const wchar_t *src, size_t srcLen) { size_t destPos = 0, srcPos = 0; for (;;) { unsigned numAdds; UInt32 value; if (srcPos == srcLen) { *destLen = destPos; return True; } value = src[srcPos++]; if (value < 0x80) { if (dest) dest[destPos] = (char)value; destPos++; continue; } if (value >= 0xD800 && value < 0xE000) { UInt32 c2; if (value >= 0xDC00 || srcPos == srcLen) break; c2 = src[srcPos++]; if (c2 < 0xDC00 || c2 >= 0xE000) break; value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; } for (numAdds = 1; numAdds < 5; numAdds++) if (value < (((UInt32)1) << (numAdds * 5 + 6))) break; if (dest) dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); destPos++; do { numAdds--; if (dest) dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); destPos++; } while (numAdds != 0); } *destLen = destPos; return False; } bool ConvertUTF8ToUnicode(const AString &src, UString &dest) { dest.Empty(); size_t destLen = 0; Utf8_To_Utf16(NULL, &destLen, src, src.Len()); Bool res = Utf8_To_Utf16(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len()); dest.ReleaseBuffer((unsigned)destLen); return res ? true : false; } bool ConvertUnicodeToUTF8(const UString &src, AString &dest) { dest.Empty(); size_t destLen = 0; Utf16_To_Utf8(NULL, &destLen, src, src.Len()); Bool res = Utf16_To_Utf8(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len()); dest.ReleaseBuffer((unsigned)destLen); return res ? true : false; } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/UTFConvert.h0100777000000000000000000000047313761647206022334 0ustar00// Common/UTFConvert.h #ifndef __COMMON_UTF_CONVERT_H #define __COMMON_UTF_CONVERT_H #include "MyString.h" bool CheckUTF8(const char *src) throw(); bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString); bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString); #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/Wildcard.cpp0100777000000000000000000003312313761647206022417 0ustar00// Common/Wildcard.cpp #include "StdAfx.h" #include "Wildcard.h" bool g_CaseSensitive = #ifdef _WIN32 false; #else true; #endif bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) { if (g_CaseSensitive) { for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (MyCharUpper(c1) != MyCharUpper(c2)) return false; } } for (;;) { wchar_t c2 = *s2++; if (c2 == 0) return true; wchar_t c1 = *s1++; if (c1 != c2) return false; } } int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW { if (g_CaseSensitive) return wcscmp(s1, s2); return MyStringCompareNoCase(s1, s2); } #ifndef USE_UNICODE_FSTRING int CompareFileNames(const char *s1, const char *s2) { if (g_CaseSensitive) return wcscmp(fs2us(s1), fs2us(s2)); return MyStringCompareNoCase(fs2us(s1), fs2us(s2)); } #endif // ----------------------------------------- // this function compares name with mask // ? - any char // * - any char or empty static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) { for (;;) { wchar_t m = *mask; wchar_t c = *name; if (m == 0) return (c == 0); if (m == '*') { if (EnhancedMaskTest(mask + 1, name)) return true; if (c == 0) return false; } else { if (m == '?') { if (c == 0) return false; } else if (m != c) if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) return false; mask++; } name++; } } // -------------------------------------------------- // Splits path to strings void SplitPathToParts(const UString &path, UStringVector &pathParts) { pathParts.Clear(); unsigned len = path.Len(); if (len == 0) return; UString name; unsigned prev = 0; for (unsigned i = 0; i < len; i++) if (IsCharDirLimiter(path[i])) { name.SetFrom(path.Ptr(prev), i - prev); pathParts.Add(name); prev = i + 1; } name.SetFrom(path.Ptr(prev), len - prev); pathParts.Add(name); } void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; dirPrefix.SetFrom(path, (unsigned)(p - start)); name = p; } void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); if (p != start) { if (IsCharDirLimiter(*(p - 1))) p--; for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; } dirPrefix.SetFrom(path, (unsigned)(p - start)); name = p; } UString ExtractDirPrefixFromPath(const UString &path) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; return path.Left((unsigned)(p - start)); } UString ExtractFileNameFromPath(const UString &path) { const wchar_t *start = path; const wchar_t *p = start + path.Len(); for (; p != start; p--) if (IsCharDirLimiter(*(p - 1))) break; return p; } bool DoesWildcardMatchName(const UString &mask, const UString &name) { return EnhancedMaskTest(mask, name); } bool DoesNameContainWildcard(const UString &path) { for (unsigned i = 0; i < path.Len(); i++) { wchar_t c = path[i]; if (c == '*' || c == '?') return true; } return false; } // ----------------------------------------------------------' // NWildcard namespace NWildcard { #ifdef _WIN32 bool IsDriveColonName(const wchar_t *s) { wchar_t c = s[0]; return c != 0 && s[1] == ':' && s[2] == 0 && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); } #endif /* M = MaskParts.Size(); N = TestNameParts.Size(); File Dir ForFile rec M<=N [N-M, N) - !ForDir nonrec M=N [0, M) - ForDir rec M 1) return true; } return false; } bool CCensorNode::AreThereIncludeItems() const { if (IncludeItems.Size() > 0) return true; FOR_VECTOR (i, SubNodes) if (SubNodes[i].AreThereIncludeItems()) return true; return false; } bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const { const CObjectVector &items = include ? IncludeItems : ExcludeItems; FOR_VECTOR (i, items) if (items[i].CheckPath(pathParts, isFile)) return true; return false; } bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const { if (CheckPathCurrent(false, pathParts, isFile)) { include = false; return true; } include = true; bool finded = CheckPathCurrent(true, pathParts, isFile); if (pathParts.Size() <= 1) return finded; int index = FindSubNode(pathParts.Front()); if (index >= 0) { UStringVector pathParts2 = pathParts; pathParts2.Delete(0); if (SubNodes[index].CheckPathVect(pathParts2, isFile, include)) return true; } return finded; } bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const { UStringVector pathParts; SplitPathToParts(path, pathParts); if (CheckPathVect(pathParts, isFile, include)) { if (!include || !isAltStream) return true; } if (isAltStream && !pathParts.IsEmpty()) { UString &back = pathParts.Back(); int pos = back.Find(L':'); if (pos > 0) { back.DeleteFrom(pos); return CheckPathVect(pathParts, isFile, include); } } return false; } bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const { bool include; if (CheckPath2(isAltStream, path, isFile, include)) return include; return false; } bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const { if (CheckPathCurrent(include, pathParts, isFile)) return true; if (Parent == 0) return false; pathParts.Insert(0, Name); return Parent->CheckPathToRoot(include, pathParts, isFile); } /* bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const { UStringVector pathParts; SplitPathToParts(path, pathParts); return CheckPathToRoot(include, pathParts, isFile); } */ void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching) { if (path.IsEmpty()) return; bool forFile = true; bool forFolder = true; UString path2 = path; if (IsCharDirLimiter(path.Back())) { path2.DeleteBack(); forFile = false; } AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching); } void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) { ExcludeItems += fromNodes.ExcludeItems; FOR_VECTOR (i, fromNodes.SubNodes) { const CCensorNode &node = fromNodes.SubNodes[i]; int subNodeIndex = FindSubNode(node.Name); if (subNodeIndex < 0) subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this)); SubNodes[subNodeIndex].ExtendExclude(node); } } int CCensor::FindPrefix(const UString &prefix) const { FOR_VECTOR (i, Pairs) if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) return i; return -1; } void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching) { UStringVector pathParts; if (path.IsEmpty()) throw "Empty file path"; SplitPathToParts(path, pathParts); bool forFile = true; if (pathParts.Back().IsEmpty()) { forFile = false; pathParts.DeleteBack(); } UString prefix; if (pathMode != k_AbsPath) { const UString &front = pathParts.Front(); bool isAbs = false; if (front.IsEmpty()) isAbs = true; else { #ifdef _WIN32 if (IsDriveColonName(front)) isAbs = true; else #endif FOR_VECTOR (i, pathParts) { const UString &part = pathParts[i]; if (part == L".." || part == L".") { isAbs = true; break; } } } unsigned numAbsParts = 0; if (isAbs) if (pathParts.Size() > 1) numAbsParts = pathParts.Size() - 1; else numAbsParts = 1; #ifdef _WIN32 // \\?\ case if (numAbsParts >= 3) { if (pathParts[0].IsEmpty() && pathParts[1].IsEmpty() && pathParts[2] == L"?") { prefix = WSTRING_PATH_SEPARATOR WSTRING_PATH_SEPARATOR L"?" WSTRING_PATH_SEPARATOR; numAbsParts -= 3; pathParts.DeleteFrontal(3); } } #endif if (numAbsParts > 1 && pathMode == k_FullPath) numAbsParts = 1; // We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name // if (wildcardMatching) for (unsigned i = 0; i < numAbsParts; i++) { { const UString &front = pathParts.Front(); if (DoesNameContainWildcard(front)) break; prefix += front; prefix += WCHAR_PATH_SEPARATOR; } pathParts.Delete(0); } } int index = FindPrefix(prefix); if (index < 0) index = Pairs.Add(CPair(prefix)); CItem item; item.PathParts = pathParts; item.ForDir = true; item.ForFile = forFile; item.Recursive = recursive; item.WildcardMatching = wildcardMatching; Pairs[index].Head.AddItem(include, item); } bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const { bool finded = false; FOR_VECTOR (i, Pairs) { bool include; if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) { if (!include) return false; finded = true; } } return finded; } void CCensor::ExtendExclude() { unsigned i; for (i = 0; i < Pairs.Size(); i++) if (Pairs[i].Prefix.IsEmpty()) break; if (i == Pairs.Size()) return; unsigned index = i; for (i = 0; i < Pairs.Size(); i++) if (index != i) Pairs[i].Head.ExtendExclude(Pairs[index].Head); } void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) { FOR_VECTOR(i, CensorPaths) { const CCensorPath &cp = CensorPaths[i]; AddItem(censorPathMode, cp.Include, cp.Path, cp.Recursive, cp.WildcardMatching); } CensorPaths.Clear(); } void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching) { CCensorPath &cp = CensorPaths.AddNew(); cp.Path = path; cp.Include = include; cp.Recursive = recursive; cp.WildcardMatching = wildcardMatching; } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Common/Wildcard.h0100777000000000000000000001015613761647206022065 0ustar00// Common/Wildcard.h #ifndef __COMMON_WILDCARD_H #define __COMMON_WILDCARD_H #include "MyString.h" int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW; #ifndef USE_UNICODE_FSTRING int CompareFileNames(const char *s1, const char *s2); #endif bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2); inline bool IsCharDirLimiter(wchar_t c) { return c == WCHAR_PATH_SEPARATOR #ifdef _WIN32 || c == L'/' #endif ; } void SplitPathToParts(const UString &path, UStringVector &pathParts); void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name); void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path) UString ExtractDirPrefixFromPath(const UString &path); UString ExtractFileNameFromPath(const UString &path); bool DoesNameContainWildcard(const UString &path); bool DoesWildcardMatchName(const UString &mask, const UString &name); namespace NWildcard { #ifdef _WIN32 // returns true, if name is like "a:", "c:", ... bool IsDriveColonName(const wchar_t *s); #endif struct CItem { UStringVector PathParts; bool Recursive; bool ForFile; bool ForDir; bool WildcardMatching; #ifdef _WIN32 bool IsDriveItem() const { return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]); } #endif // CItem(): WildcardMatching(true) {} bool AreAllAllowed() const; bool CheckPath(const UStringVector &pathParts, bool isFile) const; }; class CCensorNode { CCensorNode *Parent; bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; void AddItemSimple(bool include, CItem &item); bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const; public: CCensorNode(): Parent(0) { }; CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { }; UString Name; // wildcard is not allowed here CObjectVector SubNodes; CObjectVector IncludeItems; CObjectVector ExcludeItems; bool AreAllAllowed() const; int FindSubNode(const UString &path) const; void AddItem(bool include, CItem &item); void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching); void AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching); bool NeedCheckSubDirs() const; bool AreThereIncludeItems() const; bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const; bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const; // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; void ExtendExclude(const CCensorNode &fromNodes); }; struct CPair { UString Prefix; CCensorNode Head; CPair(const UString &prefix): Prefix(prefix) { }; }; enum ECensorPathMode { k_RelatPath, // absolute prefix as Prefix, remain path in Tree k_FullPath, // drive prefix as Prefix, remain path in Tree k_AbsPath // full path in Tree }; struct CCensorPath { UString Path; bool Include; bool Recursive; bool WildcardMatching; CCensorPath(): Include(true), Recursive(false), WildcardMatching(true) {} }; class CCensor { int FindPrefix(const UString &prefix) const; public: CObjectVector Pairs; CObjectVector CensorPaths; bool AllAreRelative() const { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } void AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching); bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; void ExtendExclude(); void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); void AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching); void AddPreItem(const UString &path) { AddPreItem(true, path, false, false); } void AddPreItem_Wildcard() { AddPreItem(true, L"*", false, true); } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/0040777000000000000000000000000013761647206020362 5ustar00qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Defs.h0100777000000000000000000000074613761647206021423 0ustar00// Windows/Defs.h #ifndef __WINDOWS_DEFS_H #define __WINDOWS_DEFS_H #include "../Common/MyWindows.h" #ifdef _WIN32 inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } inline bool BOOLToBool(BOOL v) { return (v != FALSE); } inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } #endif inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/DLL.cpp0100777000000000000000000000331413761647206021502 0ustar00// Windows/DLL.cpp #include "StdAfx.h" #include "DLL.h" #ifndef _UNICODE extern bool g_IsNT; #endif extern HINSTANCE g_hInstance; namespace NWindows { namespace NDLL { bool CLibrary::Free() throw() { if (_module == 0) return true; if (!::FreeLibrary(_module)) return false; _module = 0; return true; } bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw() { if (!Free()) return false; #ifndef _UNICODE if (!g_IsNT) { _module = ::LoadLibraryEx(fs2fas(path), NULL, flags); } else #endif { _module = ::LoadLibraryExW(fs2us(path), NULL, flags); } return (_module != NULL); } bool CLibrary::Load(CFSTR path) throw() { if (!Free()) return false; #ifndef _UNICODE if (!g_IsNT) { _module = ::LoadLibrary(fs2fas(path)); } else #endif { _module = ::LoadLibraryW(fs2us(path)); } return (_module != NULL); } bool MyGetModuleFileName(FString &path) { HMODULE hModule = g_hInstance; path.Empty(); #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1); if (size <= MAX_PATH && size != 0) { path = fas2fs(s); return true; } } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1); if (size <= MAX_PATH && size != 0) { path = us2fs(s); return true; } } return false; } #ifndef _SFX FString GetModuleDirPrefix() { FString s; if (MyGetModuleFileName(s)) { int pos = s.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos >= 0) { s.DeleteFrom(pos + 1); return s; } } return FTEXT(".") FSTRING_PATH_SEPARATOR; } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/DLL.h0100777000000000000000000000201413761647206021143 0ustar00// Windows/DLL.h #ifndef __WINDOWS_DLL_H #define __WINDOWS_DLL_H #include "../Common/MyString.h" namespace NWindows { namespace NDLL { #ifdef UNDER_CE #define My_GetProcAddress(module, procName) ::GetProcAddressA(module, procName) #else #define My_GetProcAddress(module, procName) ::GetProcAddress(module, procName) #endif class CLibrary { HMODULE _module; public: CLibrary(): _module(NULL) {}; ~CLibrary() { Free(); } operator HMODULE() const { return _module; } HMODULE* operator&() { return &_module; } bool IsLoaded() const { return (_module != NULL); }; void Attach(HMODULE m) { Free(); _module = m; } HMODULE Detach() { HMODULE m = _module; _module = NULL; return m; } bool Free() throw(); bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw(); bool Load(CFSTR path) throw(); FARPROC GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } }; bool MyGetModuleFileName(FString &path); FString GetModuleDirPrefix(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileDir.cpp0100777000000000000000000002755413761647206022421 0ustar00// Windows/FileDir.cpp #include "StdAfx.h" #ifndef _UNICODE #include "../Common/StringConvert.h" #endif #include "FileDir.h" #include "FileFind.h" #include "FileName.h" #ifndef _UNICODE extern bool g_IsNT; #endif using namespace NWindows; using namespace NFile; using namespace NName; namespace NWindows { namespace NFile { namespace NDir { #ifndef UNDER_CE bool GetWindowsDir(FString &path) { UINT needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetWindowsDirectory(s, MAX_PATH + 1); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1); path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } bool GetSystemDir(FString &path) { UINT needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetSystemDirectory(s, MAX_PATH + 1); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1); path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } #endif bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) { #ifndef _UNICODE if (!g_IsNT) { ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return false; } #endif HANDLE hDir = INVALID_HANDLE_VALUE; IF_USE_MAIN_PATH hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); #ifdef WIN_LONG_PATH if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) hDir = ::CreateFileW(longPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); } #endif bool res = false; if (hDir != INVALID_HANDLE_VALUE) { res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime)); ::CloseHandle(hDir); } return res; } bool SetFileAttrib(CFSTR path, DWORD attrib) { #ifndef _UNICODE if (!g_IsNT) { if (::SetFileAttributes(fs2fas(path), attrib)) return true; } else #endif { IF_USE_MAIN_PATH if (::SetFileAttributesW(fs2us(path), attrib)) return true; #ifdef WIN_LONG_PATH if (USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) return BOOLToBool(::SetFileAttributesW(longPath, attrib)); } #endif } return false; } bool RemoveDir(CFSTR path) { #ifndef _UNICODE if (!g_IsNT) { if (::RemoveDirectory(fs2fas(path))) return true; } else #endif { IF_USE_MAIN_PATH if (::RemoveDirectoryW(fs2us(path))) return true; #ifdef WIN_LONG_PATH if (USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) return BOOLToBool(::RemoveDirectoryW(longPath)); } #endif } return false; } bool MyMoveFile(CFSTR oldFile, CFSTR newFile) { #ifndef _UNICODE if (!g_IsNT) { if (::MoveFile(fs2fas(oldFile), fs2fas(newFile))) return true; } else #endif { IF_USE_MAIN_PATH_2(oldFile, newFile) if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) return true; #ifdef WIN_LONG_PATH if (USE_SUPER_PATH_2) { UString d1, d2; if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) return BOOLToBool(::MoveFileW(d1, d2)); } #endif } return false; } #ifndef UNDER_CE EXTERN_C_BEGIN typedef BOOL (WINAPI *Func_CreateHardLinkW)( LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); EXTERN_C_END bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) { #ifndef _UNICODE if (!g_IsNT) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return false; /* if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL)) return true; */ } else #endif { Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW) ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"); if (!my_CreateHardLinkW) return false; IF_USE_MAIN_PATH_2(newFileName, existFileName) if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) return true; #ifdef WIN_LONG_PATH if (USE_SUPER_PATH_2) { UString d1, d2; if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2)) return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL)); } #endif } return false; } #endif bool CreateDir(CFSTR path) { #ifndef _UNICODE if (!g_IsNT) { if (::CreateDirectory(fs2fas(path), NULL)) return true; } else #endif { IF_USE_MAIN_PATH if (::CreateDirectoryW(fs2us(path), NULL)) return true; #ifdef WIN_LONG_PATH if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) return BOOLToBool(::CreateDirectoryW(longPath, NULL)); } #endif } return false; } bool CreateComplexDir(CFSTR _aPathName) { FString pathName = _aPathName; int pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos > 0 && (unsigned)pos == pathName.Len() - 1) { if (pathName.Len() == 3 && pathName[1] == L':') return true; // Disk folder; pathName.Delete(pos); } const FString pathName2 = pathName; pos = pathName.Len(); for (;;) { if (CreateDir(pathName)) break; if (::GetLastError() == ERROR_ALREADY_EXISTS) { NFind::CFileInfo fileInfo; if (!fileInfo.Find(pathName)) // For network folders return true; if (!fileInfo.IsDir()) return false; break; } pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos < 0 || pos == 0) return false; if (pathName[pos - 1] == L':') return false; pathName.DeleteFrom(pos); } while (pos < (int)pathName2.Len()) { pos = pathName2.Find(FCHAR_PATH_SEPARATOR, pos + 1); if (pos < 0) pos = pathName2.Len(); pathName.SetFrom(pathName2, pos); if (!CreateDir(pathName)) return false; } return true; } bool DeleteFileAlways(CFSTR path) { if (!SetFileAttrib(path, 0)) return false; #ifndef _UNICODE if (!g_IsNT) { if (::DeleteFile(fs2fas(path))) return true; } else #endif { IF_USE_MAIN_PATH if (::DeleteFileW(fs2us(path))) return true; #ifdef WIN_LONG_PATH if (USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) return BOOLToBool(::DeleteFileW(longPath)); } #endif } return false; } bool RemoveDirWithSubItems(const FString &path) { bool needRemoveSubItems = true; { NFind::CFileInfo fi; if (!fi.Find(path)) return false; if (!fi.IsDir()) { ::SetLastError(ERROR_DIRECTORY); return false; } if (fi.HasReparsePoint()) needRemoveSubItems = false; } if (needRemoveSubItems) { FString s = path; s += FCHAR_PATH_SEPARATOR; unsigned prefixSize = s.Len(); s += FCHAR_ANY_MASK; NFind::CEnumerator enumerator(s); NFind::CFileInfo fi; while (enumerator.Next(fi)) { s.DeleteFrom(prefixSize); s += fi.Name; if (fi.IsDir()) { if (!RemoveDirWithSubItems(s)) return false; } else if (!DeleteFileAlways(s)) return false; } } if (!SetFileAttrib(path, 0)) return false; return RemoveDir(path); } #ifdef UNDER_CE bool MyGetFullPathName(CFSTR path, FString &resFullPath) { resFullPath = path; return true; } #else bool MyGetFullPathName(CFSTR path, FString &resFullPath) { return GetFullPath(path, resFullPath); } bool SetCurrentDir(CFSTR path) { // SetCurrentDirectory doesn't support \\?\ prefix #ifndef _UNICODE if (!g_IsNT) { return BOOLToBool(::SetCurrentDirectory(fs2fas(path))); } else #endif { return BOOLToBool(::SetCurrentDirectoryW(fs2us(path))); } } bool GetCurrentDir(FString &path) { path.Empty(); DWORD needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } #endif bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) { bool res = MyGetFullPathName(path, resDirPrefix); if (!res) resDirPrefix = path; int pos = resDirPrefix.ReverseFind(FCHAR_PATH_SEPARATOR); resFileName = resDirPrefix.Ptr(pos + 1); resDirPrefix.DeleteFrom(pos + 1); return res; } bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) { FString resFileName; return GetFullPathAndSplit(path, resDirPrefix, resFileName); } bool MyGetTempPath(FString &path) { path.Empty(); DWORD needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetTempPath(MAX_PATH + 1, s); path = fas2fs(s); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetTempPathW(MAX_PATH + 1, s);; path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); } static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile) { UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); for (unsigned i = 0; i < 100; i++) { path = prefix; if (addRandom) { FChar s[16]; UInt32 value = d; unsigned k; for (k = 0; k < 8; k++) { unsigned t = value & 0xF; value >>= 4; s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } s[k] = '\0'; if (outFile) path += FChar('.'); path += s; UInt32 step = GetTickCount() + 2; if (step == 0) step = 1; d += step; } addRandom = true; if (outFile) path += FTEXT(".tmp"); if (NFind::DoesFileOrDirExist(path)) { SetLastError(ERROR_ALREADY_EXISTS); continue; } if (outFile) { if (outFile->Create(path, false)) return true; } else { if (CreateDir(path)) return true; } DWORD error = GetLastError(); if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) break; } path.Empty(); return false; } bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) { if (!Remove()) return false; if (!CreateTempFile(prefix, false, _path, outFile)) return false; _mustBeDeleted = true; return true; } bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile) { if (!Remove()) return false; FString tempPath; if (!MyGetTempPath(tempPath)) return false; if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile)) return false; _mustBeDeleted = true; return true; } bool CTempFile::Remove() { if (!_mustBeDeleted) return true; _mustBeDeleted = !DeleteFileAlways(_path); return !_mustBeDeleted; } bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) { if (deleteDestBefore) if (NFind::DoesFileExist(name)) if (!DeleteFileAlways(name)) return false; DisableDeleting(); return MyMoveFile(_path, name); } bool CTempDir::Create(CFSTR prefix) { if (!Remove()) return false; FString tempPath; if (!MyGetTempPath(tempPath)) return false; if (!CreateTempFile(tempPath + prefix, true, _path, NULL)) return false; _mustBeDeleted = true; return true; } bool CTempDir::Remove() { if (!_mustBeDeleted) return true; _mustBeDeleted = !RemoveDirWithSubItems(_path); return !_mustBeDeleted; } }}} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileDir.h0100777000000000000000000000422613761647206022055 0ustar00// Windows/FileDir.h #ifndef __WINDOWS_FILE_DIR_H #define __WINDOWS_FILE_DIR_H #include "../Common/MyString.h" #include "FileIO.h" namespace NWindows { namespace NFile { namespace NDir { bool GetWindowsDir(FString &path); bool GetSystemDir(FString &path); bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); bool SetFileAttrib(CFSTR path, DWORD attrib); bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); #ifndef UNDER_CE bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); #endif bool RemoveDir(CFSTR path); bool CreateDir(CFSTR path); bool CreateComplexDir(CFSTR path); bool DeleteFileAlways(CFSTR name); bool RemoveDirWithSubItems(const FString &path); bool MyGetFullPathName(CFSTR path, FString &resFullPath); bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix); #ifndef UNDER_CE bool SetCurrentDir(CFSTR path); bool GetCurrentDir(FString &resultPath); #endif bool MyGetTempPath(FString &resultPath); class CTempFile { bool _mustBeDeleted; FString _path; void DisableDeleting() { _mustBeDeleted = false; } public: CTempFile(): _mustBeDeleted(false) {} ~CTempFile() { Remove(); } const FString &GetPath() const { return _path; } bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); bool Remove(); bool MoveTo(CFSTR name, bool deleteDestBefore); }; class CTempDir { bool _mustBeDeleted; FString _path; public: CTempDir(): _mustBeDeleted(false) {} ~CTempDir() { Remove(); } const FString &GetPath() const { return _path; } void DisableDeleting() { _mustBeDeleted = false; } bool Create(CFSTR namePrefix) ; bool Remove(); }; #if !defined(UNDER_CE) class CCurrentDirRestorer { FString _path; public: bool NeedRestore; CCurrentDirRestorer(): NeedRestore(true) { GetCurrentDir(_path); } ~CCurrentDirRestorer() { if (!NeedRestore) return; FString s; if (GetCurrentDir(s)) if (s != _path) SetCurrentDir(_path); } }; #endif }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileFind.cpp0100777000000000000000000003114113761647206022546 0ustar00// Windows/FileFind.cpp #include "StdAfx.h" #include "FileFind.h" #include "FileIO.h" #include "FileName.h" #ifndef _UNICODE #include "../Common/StringConvert.h" #endif #ifndef _UNICODE extern bool g_IsNT; #endif using namespace NWindows; using namespace NFile; using namespace NName; #if defined(_WIN32) && !defined(UNDER_CE) EXTERN_C_BEGIN typedef enum { My_FindStreamInfoStandard, My_FindStreamInfoMaxInfoLevel } MY_STREAM_INFO_LEVELS; typedef struct { LARGE_INTEGER StreamSize; WCHAR cStreamName[MAX_PATH + 36]; } MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, LPVOID findStreamData, DWORD flags); typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); EXTERN_C_END #endif namespace NWindows { namespace NFile { #ifdef SUPPORT_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } #endif namespace NFind { bool CFileInfo::IsDots() const throw() { if (!IsDir() || Name.IsEmpty()) return false; if (Name[0] != FTEXT('.')) return false; return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == FTEXT('.')); } #define WIN_FD_TO_MY_FI(fi, fd) \ fi.Attrib = fd.dwFileAttributes; \ fi.CTime = fd.ftCreationTime; \ fi.ATime = fd.ftLastAccessTime; \ fi.MTime = fd.ftLastWriteTime; \ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ fi.IsAltStream = false; \ fi.IsDevice = false; /* #ifdef UNDER_CE fi.ObjectID = fd.dwOID; #else fi.ReparseTag = fd.dwReserved0; #endif */ static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); fi.Name = us2fs(fd.cFileName); #if defined(_WIN32) && !defined(UNDER_CE) // fi.ShortName = us2fs(fd.cAlternateFileName); #endif } #ifndef _UNICODE static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); fi.Name = fas2fs(fd.cFileName); #if defined(_WIN32) && !defined(UNDER_CE) // fi.ShortName = fas2fs(fd.cAlternateFileName); #endif } #endif //////////////////////////////// // CFindFile bool CFindFileBase::Close() throw() { if (_handle == INVALID_HANDLE_VALUE) return true; if (!::FindClose(_handle)) return false; _handle = INVALID_HANDLE_VALUE; return true; } bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) { if (!Close()) return false; #ifndef _UNICODE if (!g_IsNT) { WIN32_FIND_DATAA fd; _handle = ::FindFirstFileA(fs2fas(path), &fd); if (_handle == INVALID_HANDLE_VALUE) return false; Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } else #endif { WIN32_FIND_DATAW fd; IF_USE_MAIN_PATH _handle = ::FindFirstFileW(fs2us(path), &fd); #ifdef WIN_LONG_PATH if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) _handle = ::FindFirstFileW(longPath, &fd); } #endif if (_handle == INVALID_HANDLE_VALUE) return false; Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } return true; } bool CFindFile::FindNext(CFileInfo &fi) { #ifndef _UNICODE if (!g_IsNT) { WIN32_FIND_DATAA fd; if (!::FindNextFileA(_handle, &fd)) return false; Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } else #endif { WIN32_FIND_DATAW fd; if (!::FindNextFileW(_handle, &fd)) return false; Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } return true; } #if defined(_WIN32) && !defined(UNDER_CE) //////////////////////////////// // AltStreams static FindFirstStreamW_Ptr g_FindFirstStreamW; static FindNextStreamW_Ptr g_FindNextStreamW; struct CFindStreamLoader { CFindStreamLoader() { g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW"); g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW"); } } g_FindStreamLoader; bool CStreamInfo::IsMainStream() const throw() { return Name == L"::$DATA"; }; UString CStreamInfo::GetReducedName() const { UString s = Name; if (s.Len() >= 6) if (wcscmp(s.RightPtr(6), L":$DATA") == 0) s.DeleteFrom(s.Len() - 6); return s; } static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) { si.Size = sd.StreamSize.QuadPart; si.Name = sd.cStreamName; } bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) { if (!Close()) return false; if (!g_FindFirstStreamW) { ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return false; } { MY_WIN32_FIND_STREAM_DATA sd; IF_USE_MAIN_PATH _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0); if (_handle == INVALID_HANDLE_VALUE) { if (::GetLastError() == ERROR_HANDLE_EOF) return false; // long name can be tricky for path like ".\dirName". #ifdef WIN_LONG_PATH if (USE_SUPER_PATH) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) _handle = g_FindFirstStreamW(longPath, My_FindStreamInfoStandard, &sd, 0); } #endif } if (_handle == INVALID_HANDLE_VALUE) return false; Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); } return true; } bool CFindStream::FindNext(CStreamInfo &si) { if (!g_FindNextStreamW) { ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return false; } { MY_WIN32_FIND_STREAM_DATA sd; if (!g_FindNextStreamW(_handle, &sd)) return false; Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); } return true; } bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) { bool res; if (_find.IsHandleAllocated()) res = _find.FindNext(si); else res = _find.FindFirst(_filePath, si); if (res) { found = true; return true; } found = false; return (::GetLastError() == ERROR_HANDLE_EOF); } #endif #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; void CFileInfoBase::Clear() throw() { Size = 0; MY_CLEAR_FILETIME(CTime); MY_CLEAR_FILETIME(ATime); MY_CLEAR_FILETIME(MTime); Attrib = 0; IsAltStream = false; IsDevice = false; } #if defined(_WIN32) && !defined(UNDER_CE) static int FindAltStreamColon(CFSTR path) { for (int i = 0;; i++) { FChar c = path[i]; if (c == 0) return -1; if (c == ':') { if (path[i + 1] == '\\') if (i == 1 || (i > 1 && path[i - 2] == '\\')) { wchar_t c0 = path[i - 1]; if (c0 >= 'a' && c0 <= 'z' || c0 >= 'A' && c0 <= 'Z') continue; } return i; } } } #endif bool CFileInfo::Find(CFSTR path) { #ifdef SUPPORT_DEVICE_FILE if (IsDevicePath(path)) { Clear(); Name = path + 4; IsDevice = true; if (/* path[0] == '\\' && path[1] == '\\' && path[2] == '.' && path[3] == '\\' && */ path[5] == ':' && path[6] == 0) { FChar drive[4] = { path[4], ':', '\\', 0 }; UInt64 clusterSize, totalSize, freeSize; if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) { Size = totalSize; return true; } } NIO::CInFile inFile; // ::OutputDebugStringW(path); if (!inFile.Open(path)) return false; // ::OutputDebugStringW(L"---"); if (inFile.SizeDefined) Size = inFile.Size; return true; } #endif #if defined(_WIN32) && !defined(UNDER_CE) int colonPos = FindAltStreamColon(path); if (colonPos >= 0) { UString streamName = fs2us(path + (unsigned)colonPos); FString filePath = path; filePath.DeleteFrom(colonPos); streamName += L":$DATA"; // change it!!!! if (Find(filePath)) { // if (IsDir()) Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; Size = 0; CStreamEnumerator enumerator(filePath); for (;;) { CStreamInfo si; bool found; if (!enumerator.Next(si, found)) return false; if (!found) { ::SetLastError(ERROR_FILE_NOT_FOUND); return false; } if (si.Name.IsEqualToNoCase(streamName)) { Name += us2fs(si.Name); Name.DeleteFrom(Name.Len() - 6); Size = si.Size; IsAltStream = true; return true; } } } } #endif CFindFile finder; if (finder.FindFirst(path, *this)) return true; #ifdef _WIN32 { DWORD lastError = GetLastError(); if (lastError == ERROR_BAD_NETPATH || lastError == ERROR_FILE_NOT_FOUND || lastError == ERROR_INVALID_NAME // for "\\SERVER\shared" paths that are translated to "\\?\UNC\SERVER\shared" ) { unsigned len = MyStringLen(path); if (len > 2 && path[0] == '\\' && path[1] == '\\') { int startPos = 2; if (len > kSuperUncPathPrefixSize && IsSuperUncPath(path)) startPos = kSuperUncPathPrefixSize; int pos = FindCharPosInString(path + startPos, FTEXT('\\')); if (pos >= 0) { pos += startPos + 1; len -= pos; int pos2 = FindCharPosInString(path + pos, FTEXT('\\')); if (pos2 < 0 || pos2 == (int)len - 1) { FString s = path; if (pos2 < 0) { pos2 = len; s += FTEXT('\\'); } s += FCHAR_ANY_MASK; if (finder.FindFirst(s, *this)) if (Name == FTEXT(".")) { Name.SetFrom(s.Ptr(pos), pos2); return true; } ::SetLastError(lastError); } } } } } #endif return false; } bool DoesFileExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && !fi.IsDir(); } bool DoesDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && fi.IsDir(); } bool DoesFileOrDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name); } bool CEnumerator::NextAny(CFileInfo &fi) { if (_findFile.IsHandleAllocated()) return _findFile.FindNext(fi); else return _findFile.FindFirst(_wildcard, fi); } bool CEnumerator::Next(CFileInfo &fi) { for (;;) { if (!NextAny(fi)) return false; if (!fi.IsDots()) return true; } } bool CEnumerator::Next(CFileInfo &fi, bool &found) { if (Next(fi)) { found = true; return true; } found = false; return (::GetLastError() == ERROR_NO_MORE_FILES); } //////////////////////////////// // CFindChangeNotification // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. bool CFindChangeNotification::Close() throw() { if (!IsHandleAllocated()) return true; if (!::FindCloseChangeNotification(_handle)) return false; _handle = INVALID_HANDLE_VALUE; return true; } HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter) { #ifndef _UNICODE if (!g_IsNT) _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter); else #endif { IF_USE_MAIN_PATH _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); #ifdef WIN_LONG_PATH if (!IsHandleAllocated()) { UString longPath; if (GetSuperPath(path, longPath, USE_MAIN_PATH)) _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); } #endif } return _handle; } #ifndef UNDER_CE bool MyGetLogicalDriveStrings(CObjectVector &driveStrings) { driveStrings.Clear(); #ifndef _UNICODE if (!g_IsNT) { driveStrings.Clear(); UINT32 size = GetLogicalDriveStrings(0, NULL); if (size == 0) return false; AString buf; UINT32 newSize = GetLogicalDriveStrings(size, buf.GetBuffer(size)); if (newSize == 0 || newSize > size) return false; AString s; for (UINT32 i = 0; i < newSize; i++) { char c = buf[i]; if (c == '\0') { driveStrings.Add(fas2fs(s)); s.Empty(); } else s += c; } return s.IsEmpty(); } else #endif { UINT32 size = GetLogicalDriveStringsW(0, NULL); if (size == 0) return false; UString buf; UINT32 newSize = GetLogicalDriveStringsW(size, buf.GetBuffer(size)); if (newSize == 0 || newSize > size) return false; UString s; for (UINT32 i = 0; i < newSize; i++) { WCHAR c = buf[i]; if (c == L'\0') { driveStrings.Add(us2fs(s)); s.Empty(); } else s += c; } return s.IsEmpty(); } } #endif }}} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileFind.h0100777000000000000000000001027713761647206022222 0ustar00// Windows/FileFind.h #ifndef __WINDOWS_FILE_FIND_H #define __WINDOWS_FILE_FIND_H #include "../Common/MyString.h" #include "Defs.h" namespace NWindows { namespace NFile { namespace NFind { namespace NAttributes { inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; } inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; } inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } } class CFileInfoBase { bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } public: UInt64 Size; FILETIME CTime; FILETIME ATime; FILETIME MTime; DWORD Attrib; bool IsAltStream; bool IsDevice; /* #ifdef UNDER_CE DWORD ObjectID; #else UINT32 ReparseTag; #endif */ CFileInfoBase() { Clear(); } void Clear() throw(); void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } }; struct CFileInfo: public CFileInfoBase { FString Name; #if defined(_WIN32) && !defined(UNDER_CE) // FString ShortName; #endif bool IsDots() const throw(); bool Find(CFSTR wildcard); }; class CFindFileBase { protected: HANDLE _handle; public: bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; } CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {} ~CFindFileBase() { Close(); } bool Close() throw(); }; class CFindFile: public CFindFileBase { public: bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo); bool FindNext(CFileInfo &fileInfo); }; #if defined(_WIN32) && !defined(UNDER_CE) struct CStreamInfo { UString Name; UInt64 Size; UString GetReducedName() const; bool IsMainStream() const throw(); }; class CFindStream: public CFindFileBase { public: bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo); bool FindNext(CStreamInfo &streamInfo); }; class CStreamEnumerator { CFindStream _find; FString _filePath; bool NextAny(CFileInfo &fileInfo); public: CStreamEnumerator(const FString &filePath): _filePath(filePath) {} bool Next(CStreamInfo &streamInfo, bool &found); }; #endif bool DoesFileExist(CFSTR name); bool DoesDirExist(CFSTR name); bool DoesFileOrDirExist(CFSTR name); class CEnumerator { CFindFile _findFile; FString _wildcard; bool NextAny(CFileInfo &fileInfo); public: CEnumerator(const FString &wildcard): _wildcard(wildcard) {} bool Next(CFileInfo &fileInfo); bool Next(CFileInfo &fileInfo, bool &found); }; class CFindChangeNotification { HANDLE _handle; public: operator HANDLE () { return _handle; } bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; } CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} ~CFindChangeNotification() { Close(); } bool Close() throw(); HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter); bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); } }; #ifndef UNDER_CE bool MyGetLogicalDriveStrings(CObjectVector &driveStrings); #endif }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileIO.cpp0100777000000000000000000002655213761647206022207 0ustar00// Windows/FileIO.cpp #include "StdAfx.h" #ifdef SUPPORT_DEVICE_FILE #include "../../C/Alloc.h" #endif #include "FileIO.h" #include "FileName.h" #ifndef _UNICODE extern bool g_IsNT; #endif using namespace NWindows; using namespace NFile; using namespace NName; namespace NWindows { namespace NFile { #ifdef SUPPORT_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } #endif namespace NIO { /* WinXP-64 CreateFile(): "" - ERROR_PATH_NOT_FOUND :stream - OK .:stream - ERROR_PATH_NOT_FOUND .\:stream - OK folder\:stream - ERROR_INVALID_NAME folder:stream - OK c:\:stream - OK c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 ) c::stream - OK, if current dir is ROOT ( c:\ ) */ bool CFileBase::Create(CFSTR path, DWORD desiredAccess, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { if (!Close()) return false; #ifdef SUPPORT_DEVICE_FILE IsDeviceFile = false; #endif #ifndef _UNICODE if (!g_IsNT) { _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode, (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); } else #endif { IF_USE_MAIN_PATH _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode, (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); #ifdef WIN_LONG_PATH if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString superPath; if (GetSuperPath(path, superPath, USE_MAIN_PATH)) _handle = ::CreateFileW(superPath, desiredAccess, shareMode, (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); } #endif } return (_handle != INVALID_HANDLE_VALUE); } bool CFileBase::Close() throw() { if (_handle == INVALID_HANDLE_VALUE) return true; if (!::CloseHandle(_handle)) return false; _handle = INVALID_HANDLE_VALUE; return true; } bool CFileBase::GetPosition(UInt64 &position) const throw() { return Seek(0, FILE_CURRENT, position); } bool CFileBase::GetLength(UInt64 &length) const throw() { #ifdef SUPPORT_DEVICE_FILE if (IsDeviceFile && SizeDefined) { length = Size; return true; } #endif DWORD sizeHigh; DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); if (sizeLow == 0xFFFFFFFF) if (::GetLastError() != NO_ERROR) return false; length = (((UInt64)sizeHigh) << 32) + sizeLow; return true; } bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw() { #ifdef SUPPORT_DEVICE_FILE if (IsDeviceFile && SizeDefined && moveMethod == FILE_END) { distanceToMove += Size; moveMethod = FILE_BEGIN; } #endif LONG high = (LONG)(distanceToMove >> 32); DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); if (low == 0xFFFFFFFF) if (::GetLastError() != NO_ERROR) return false; newPosition = (((UInt64)high) << 32) + low; return true; } bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() { return Seek(position, FILE_BEGIN, newPosition); } bool CFileBase::SeekToBegin() const throw() { UInt64 newPosition; return Seek(0, newPosition); } bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw() { return Seek(0, FILE_END, newPosition); } // ---------- CInFile --------- #ifdef SUPPORT_DEVICE_FILE void CInFile::CorrectDeviceSize() { // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail static const UInt32 kClusterSize = 1 << 14; UInt64 pos = Size & ~(UInt64)(kClusterSize - 1); UInt64 realNewPosition; if (!Seek(pos, realNewPosition)) return; Byte *buf = (Byte *)MidAlloc(kClusterSize); bool needbackward = true; for (;;) { UInt32 processed = 0; // up test is slow for "PhysicalDrive". // processed size for latest block for "PhysicalDrive0" is 0. if (!Read1(buf, kClusterSize, processed)) break; if (processed == 0) break; needbackward = false; Size = pos + processed; if (processed != kClusterSize) break; pos += kClusterSize; } if (needbackward && pos != 0) { pos -= kClusterSize; for (;;) { // break; if (!Seek(pos, realNewPosition)) break; if (!buf) { buf = (Byte *)MidAlloc(kClusterSize); if (!buf) break; } UInt32 processed = 0; // that code doesn't work for "PhysicalDrive0" if (!Read1(buf, kClusterSize, processed)) break; if (processed != 0) { Size = pos + processed; break; } if (pos == 0) break; pos -= kClusterSize; } } MidFree(buf); } void CInFile::CalcDeviceSize(CFSTR s) { SizeDefined = false; Size = 0; if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile) return; #ifdef UNDER_CE SizeDefined = true; Size = 128 << 20; #else PARTITION_INFORMATION partInfo; bool needCorrectSize = true; /* WinXP 64-bit: HDD \\.\PhysicalDrive0 (MBR): GetPartitionInfo == GeometryEx : corrrect size? (includes tail) Geometry : smaller than GeometryEx (no tail, maybe correct too?) MyGetDiskFreeSpace : FAIL Size correction is slow and block size (kClusterSize) must be small? HDD partition \\.\N: (NTFS): MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition) CD-ROM drive (ISO): MyGetDiskFreeSpace : correct size. Same size can be calculated after correction Geometry == CdRomGeometry : smaller than corrrect size GetPartitionInfo == GeometryEx : larger than corrrect size Floppy \\.\a: (FAT): Geometry : correct size. CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL correction works OK for FAT. correction works OK for non-FAT, if kClusterSize = 512. */ if (GetPartitionInfo(&partInfo)) { Size = partInfo.PartitionLength.QuadPart; SizeDefined = true; needCorrectSize = false; if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0) { FChar path[4] = { s[4], ':', '\\', 0 }; UInt64 clusterSize, totalSize, freeSize; if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize)) Size = totalSize; else needCorrectSize = true; } } if (!SizeDefined) { my_DISK_GEOMETRY_EX geomEx; SizeDefined = GetGeometryEx(&geomEx); if (SizeDefined) Size = geomEx.DiskSize.QuadPart; else { DISK_GEOMETRY geom; SizeDefined = GetGeometry(&geom); if (!SizeDefined) SizeDefined = GetCdRomGeometry(&geom); if (SizeDefined) Size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; } } if (needCorrectSize && SizeDefined && Size != 0) { CorrectDeviceSize(); SeekToBegin(); } // SeekToBegin(); #endif } // ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 && #define MY_DEVICE_EXTRA_CODE \ IsDeviceFile = IsDevicePath(fileName); \ CalcDeviceSize(fileName); #else #define MY_DEVICE_EXTRA_CODE #endif bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); MY_DEVICE_EXTRA_CODE return res; } bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite) { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } bool CInFile::Open(CFSTR fileName) { return OpenShared(fileName, false); } // ReadFile and WriteFile functions in Windows have BUG: // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES // (Insufficient system resources exist to complete the requested service). // Probably in some version of Windows there are problems with other sizes: // for 32 MB (maybe also for 16 MB). // And message can be "Network connection was lost" static UInt32 kChunkSizeMax = (1 << 22); bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw() { DWORD processedLoc = 0; bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); processedSize = (UInt32)processedLoc; return res; } bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw() { if (size > kChunkSizeMax) size = kChunkSizeMax; return Read1(data, size, processedSize); } bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw() { processedSize = 0; do { UInt32 processedLoc = 0; bool res = ReadPart(data, size, processedLoc); processedSize += processedLoc; if (!res) return false; if (processedLoc == 0) return true; data = (void *)((unsigned char *)data + processedLoc); size -= processedLoc; } while (size > 0); return true; } // ---------- COutFile --------- static inline DWORD GetCreationDisposition(bool createAlways) { return createAlways? CREATE_ALWAYS: CREATE_NEW; } bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } bool COutFile::Open(CFSTR fileName, DWORD creationDisposition) { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } bool COutFile::Create(CFSTR fileName, bool createAlways) { return Open(fileName, GetCreationDisposition(createAlways)); } bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes) { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); } bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); } bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw() { if (size > kChunkSizeMax) size = kChunkSizeMax; DWORD processedLoc = 0; bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); processedSize = (UInt32)processedLoc; return res; } bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw() { processedSize = 0; do { UInt32 processedLoc = 0; bool res = WritePart(data, size, processedLoc); processedSize += processedLoc; if (!res) return false; if (processedLoc == 0) return true; data = (const void *)((const unsigned char *)data + processedLoc); size -= processedLoc; } while (size > 0); return true; } bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); } bool COutFile::SetLength(UInt64 length) throw() { UInt64 newPosition; if (!Seek(length, newPosition)) return false; if (newPosition != length) return false; return SetEndOfFile(); } }}} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileIO.h0100777000000000000000000001374413761647206021653 0ustar00// Windows/FileIO.h #ifndef __WINDOWS_FILE_IO_H #define __WINDOWS_FILE_IO_H #if defined(_WIN32) && !defined(UNDER_CE) #include #endif #include "../Common/MyString.h" #include "../Common/MyBuffer.h" #include "Defs.h" #define _my_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) #define _my_IO_REPARSE_TAG_SYMLINK (0xA000000CL) #define _my_SYMLINK_FLAG_RELATIVE 1 #define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER #define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER namespace NWindows { namespace NFile { #if defined(_WIN32) && !defined(UNDER_CE) bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink); #endif struct CReparseShortInfo { unsigned Offset; unsigned Size; bool Parse(const Byte *p, size_t size); }; struct CReparseAttr { UInt32 Tag; UInt32 Flags; UString SubsName; UString PrintName; CReparseAttr(): Tag(0), Flags(0) {} bool Parse(const Byte *p, size_t size); bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; } bool IsRelative() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; } // bool IsVolume() const; bool IsOkNamePair() const; UString GetPath() const; }; namespace NIO { bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); class CFileBase { protected: HANDLE _handle; bool Create(CFSTR path, DWORD desiredAccess, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); public: bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const { return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize, outBuffer, outSize, bytesReturned, overlapped)); } bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const { return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); } bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const { DWORD bytesReturned; return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); } public: #ifdef SUPPORT_DEVICE_FILE bool IsDeviceFile; bool SizeDefined; UInt64 Size; // it can be larger than real available size #endif CFileBase(): _handle(INVALID_HANDLE_VALUE) {}; ~CFileBase() { Close(); } bool Close() throw(); bool GetPosition(UInt64 &position) const throw(); bool GetLength(UInt64 &length) const throw(); bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); bool Seek(UInt64 position, UInt64 &newPosition) const throw(); bool SeekToBegin() const throw(); bool SeekToEnd(UInt64 &newPosition) const throw(); bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) { NIO::CFileBase file; if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) return false; return file.GetFileInformation(info); } }; #ifndef UNDER_CE #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM #define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) // #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) // IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP #define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) struct my_DISK_GEOMETRY_EX { DISK_GEOMETRY Geometry; LARGE_INTEGER DiskSize; BYTE Data[1]; }; #endif class CInFile: public CFileBase { #ifdef SUPPORT_DEVICE_FILE #ifndef UNDER_CE bool GetGeometry(DISK_GEOMETRY *res) const { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } bool GetCdRomGeometry(DISK_GEOMETRY *res) const { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } bool GetPartitionInfo(PARTITION_INFORMATION *res) { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } #endif void CorrectDeviceSize(); void CalcDeviceSize(CFSTR name); #endif public: bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool OpenShared(CFSTR fileName, bool shareForWrite); bool Open(CFSTR fileName); #ifndef UNDER_CE bool OpenReparse(CFSTR fileName) { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); } #endif bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); }; class COutFile: public CFileBase { public: bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); bool Open(CFSTR fileName, DWORD creationDisposition); bool Create(CFSTR fileName, bool createAlways); bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes); bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); bool SetMTime(const FILETIME *mTime) throw(); bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); bool SetEndOfFile() throw(); bool SetLength(UInt64 length) throw(); }; }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileLink.cpp0100777000000000000000000002236713761647206022575 0ustar00// Windows/FileLink.cpp #include "StdAfx.h" #include "../../C/CpuArch.h" #ifdef SUPPORT_DEVICE_FILE #include "../../C/Alloc.h" #endif #include "FileDir.h" #include "FileFind.h" #include "FileIO.h" #include "FileName.h" #ifndef _UNICODE extern bool g_IsNT; #endif namespace NWindows { namespace NFile { using namespace NName; /* Reparse Points (Junctions and Symbolic Links): struct { UInt32 Tag; UInt16 Size; // not including starting 8 bytes UInt16 Reserved; // = 0 UInt16 SubstituteOffset; // offset in bytes from start of namesChars UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL UInt16 PrintOffset; // offset in bytes from start of namesChars UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL [UInt32] Flags; // for Symbolic Links only. UInt16 namesChars[] } MOUNT_POINT (Junction point): 1) there is NUL wchar after path 2) Default Order in table: Substitute Path Print Path 3) pathnames can not contain dot directory names SYMLINK: 1) there is no NUL wchar after path 2) Default Order in table: Print Path Substitute Path */ /* static const UInt32 kReparseFlags_Alias = (1 << 29); static const UInt32 kReparseFlags_HighLatency = (1 << 30); static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); #define _my_IO_REPARSE_TAG_HSM (0xC0000004L) #define _my_IO_REPARSE_TAG_HSM2 (0x80000006L) #define _my_IO_REPARSE_TAG_SIS (0x80000007L) #define _my_IO_REPARSE_TAG_WIM (0x80000008L) #define _my_IO_REPARSE_TAG_CSV (0x80000009L) #define _my_IO_REPARSE_TAG_DFS (0x8000000AL) #define _my_IO_REPARSE_TAG_DFSR (0x80000012L) */ #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Set16(p, v) SetUi16(p, v) #define Set32(p, v) SetUi32(p, v) static const wchar_t *k_LinkPrefix = L"\\??\\"; static const unsigned k_LinkPrefix_Size = 4; static const bool IsLinkPrefix(const wchar_t *s) { return IsString1PrefixedByString2(s, k_LinkPrefix); } /* static const wchar_t *k_VolumePrefix = L"Volume{"; static const bool IsVolumeName(const wchar_t *s) { return IsString1PrefixedByString2(s, k_VolumePrefix); } */ void WriteString(Byte *dest, const wchar_t *path) { for (;;) { wchar_t c = *path++; if (c == 0) return; Set16(dest, (UInt16)c); dest += 2; } } bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) { bool isAbs = IsAbsolutePath(path); if (!isAbs && !isSymLink) return false; bool needPrintName = true; if (IsSuperPath(path)) { path += kSuperPathPrefixSize; if (!IsDrivePath(path)) needPrintName = false; } const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; unsigned len2 = MyStringLen(path) * 2; const unsigned len1 = len2 + add_Prefix_Len * 2; if (!needPrintName) len2 = 0; unsigned totalNamesSize = (len1 + len2); /* some WIM imagex software uses old scheme for symbolic links. so we can old scheme for byte to byte compatibility */ bool newOrderScheme = isSymLink; // newOrderScheme = false; if (!newOrderScheme) totalNamesSize += 2 * 2; const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; dest.Alloc(size); memset(dest, 0, size); const UInt32 tag = isSymLink ? _my_IO_REPARSE_TAG_SYMLINK : _my_IO_REPARSE_TAG_MOUNT_POINT; Byte *p = dest; Set32(p, tag); Set16(p + 4, (UInt16)(size - 8)); Set16(p + 6, 0); p += 8; unsigned subOffs = 0; unsigned printOffs = 0; if (newOrderScheme) subOffs = len2; else printOffs = len1 + 2; Set16(p + 0, (UInt16)subOffs); Set16(p + 2, (UInt16)len1); Set16(p + 4, (UInt16)printOffs); Set16(p + 6, (UInt16)len2); p += 8; if (isSymLink) { UInt32 flags = isAbs ? 0 : _my_SYMLINK_FLAG_RELATIVE; Set32(p, flags); p += 4; } if (add_Prefix_Len != 0) WriteString(p + subOffs, k_LinkPrefix); WriteString(p + subOffs + add_Prefix_Len * 2, path); if (needPrintName) WriteString(p + printOffs, path); return true; } static void GetString(const Byte *p, unsigned len, UString &res) { wchar_t *s = res.GetBuffer(len); for (unsigned i = 0; i < len; i++) s[i] = Get16(p + i * 2); s[len] = 0; res.ReleaseBuffer(); } bool CReparseAttr::Parse(const Byte *p, size_t size) { if (size < 8) return false; Tag = Get32(p); UInt32 len = Get16(p + 4); if (len + 8 > size) return false; /* if ((type & kReparseFlags_Alias) == 0 || (type & kReparseFlags_Microsoft) == 0 || (type & 0xFFFF) != 3) */ if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && Tag != _my_IO_REPARSE_TAG_SYMLINK) // return true; return false; if (Get16(p + 6) != 0) // padding return false; p += 8; size -= 8; if (len != size) // do we need that check? return false; if (len < 8) return false; unsigned subOffs = Get16(p); unsigned subLen = Get16(p + 2); unsigned printOffs = Get16(p + 4); unsigned printLen = Get16(p + 6); len -= 8; p += 8; Flags = 0; if (Tag == _my_IO_REPARSE_TAG_SYMLINK) { if (len < 4) return false; Flags = Get32(p); len -= 4; p += 4; } if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) return false; if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) return false; GetString(p + subOffs, subLen >> 1, SubsName); GetString(p + printOffs, printLen >> 1, PrintName); return true; } bool CReparseShortInfo::Parse(const Byte *p, size_t size) { const Byte *start = p; Offset= 0; Size = 0; if (size < 8) return false; UInt32 Tag = Get32(p); UInt32 len = Get16(p + 4); if (len + 8 > size) return false; /* if ((type & kReparseFlags_Alias) == 0 || (type & kReparseFlags_Microsoft) == 0 || (type & 0xFFFF) != 3) */ if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && Tag != _my_IO_REPARSE_TAG_SYMLINK) // return true; return false; if (Get16(p + 6) != 0) // padding return false; p += 8; size -= 8; if (len != size) // do we need that check? return false; if (len < 8) return false; unsigned subOffs = Get16(p); unsigned subLen = Get16(p + 2); unsigned printOffs = Get16(p + 4); unsigned printLen = Get16(p + 6); len -= 8; p += 8; // UInt32 Flags = 0; if (Tag == _my_IO_REPARSE_TAG_SYMLINK) { if (len < 4) return false; // Flags = Get32(p); len -= 4; p += 4; } if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) return false; if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) return false; Offset = (unsigned)(p - start) + subOffs; Size = subLen; return true; } bool CReparseAttr::IsOkNamePair() const { if (IsLinkPrefix(SubsName)) { if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) return PrintName.IsEmpty(); if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) return true; } return wcscmp(SubsName, PrintName) == 0; } /* bool CReparseAttr::IsVolume() const { if (!IsLinkPrefix(SubsName)) return false; return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size)); } */ UString CReparseAttr::GetPath() const { UString s = SubsName; if (IsLinkPrefix(s)) { s.ReplaceOneCharAtPos(1, '\\'); if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) s.DeleteFrontal(k_LinkPrefix_Size); } return s; } #ifdef SUPPORT_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } #endif #ifndef UNDER_CE namespace NIO { bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo) { reparseData.Free(); CInFile file; if (!file.OpenReparse(path)) return false; if (fileInfo) file.GetFileInformation(fileInfo); const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; CByteArr buf(kBufSize); DWORD returnedSize; if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) return false; reparseData.CopyFrom(buf, returnedSize); return true; } static bool CreatePrefixDirOfFile(CFSTR path) { FString path2 = path; int pos = path2.ReverseFind(FCHAR_PATH_SEPARATOR); if (pos < 0) return true; #ifdef _WIN32 if (pos == 2 && path2[1] == L':') return true; // we don't create Disk folder; #endif path2.DeleteFrom(pos); return NDir::CreateComplexDir(path2); } // If there is Reprase data already, it still writes new Reparse data bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) { NFile::NFind::CFileInfo fi; if (fi.Find(path)) { if (fi.IsDir() != isDir) { ::SetLastError(ERROR_DIRECTORY); return false; } } else { if (isDir) { if (!NDir::CreateComplexDir(path)) return false; } else { CreatePrefixDirOfFile(path); COutFile file; if (!file.Create(path, CREATE_NEW)) return false; } } COutFile file; if (!file.Open(path, FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) return false; DWORD returnedSize; if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize)) return false; return true; } } #endif }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileMapping.h0100777000000000000000000000276613761647206022741 0ustar00// Windows/FileMapping.h #ifndef __WINDOWS_FILEMAPPING_H #define __WINDOWS_FILEMAPPING_H #include "../Common/MyTypes.h" #include "Handle.h" namespace NWindows { class CFileMapping: public CHandle { public: WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name) { _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name); return ::GetLastError(); } WRes Open(DWORD #ifndef UNDER_CE desiredAccess #endif , LPCTSTR name) { #ifdef UNDER_CE WRes res = Create(PAGE_READONLY, 0, name); if (res == ERROR_ALREADY_EXISTS) return 0; Close(); if (res == 0) res = ERROR_FILE_NOT_FOUND; return res; #else _handle = ::OpenFileMapping(desiredAccess, FALSE, name); if (_handle != 0) return 0; return ::GetLastError(); #endif } LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap) { return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap); } #ifndef UNDER_CE LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress) { return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress); } #endif }; class CFileUnmapper { const void *_data; public: CFileUnmapper(const void *data) : _data(data) {} ~CFileUnmapper() { ::UnmapViewOfFile(_data); } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileName.cpp0100777000000000000000000004125713761647206022557 0ustar00// Windows/FileName.cpp #include "StdAfx.h" #include "FileName.h" #ifndef _UNICODE extern bool g_IsNT; #endif namespace NWindows { namespace NFile { namespace NName { #ifndef USE_UNICODE_FSTRING void NormalizeDirPathPrefix(FString &dirPath) { if (dirPath.IsEmpty()) return; if (dirPath.Back() != FCHAR_PATH_SEPARATOR) dirPath += FCHAR_PATH_SEPARATOR; } #endif void NormalizeDirPathPrefix(UString &dirPath) { if (dirPath.IsEmpty()) return; if (dirPath.Back() != WCHAR_PATH_SEPARATOR) dirPath += WCHAR_PATH_SEPARATOR; } #ifdef _WIN32 const wchar_t *kSuperPathPrefix = L"\\\\?\\"; static const wchar_t *kSuperUncPrefix = L"\\\\?\\UNC\\"; #define IS_DEVICE_PATH(s) ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\') #define IS_SUPER_PREFIX(s) ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '?' && (s)[3] == '\\') #define IS_SUPER_OR_DEVICE_PATH(s) ((s)[0] == '\\' && (s)[1] == '\\' && ((s)[2] == '?' || (s)[2] == '.') && (s)[3] == '\\') #define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') #define IS_UNC_WITH_SLASH(s) ( \ ((s)[0] == 'U' || (s)[0] == 'u') && \ ((s)[1] == 'N' || (s)[1] == 'n') && \ ((s)[2] == 'C' || (s)[2] == 'c') && \ (s)[3] == '\\') bool IsDevicePath(CFSTR s) throw() { #ifdef UNDER_CE s = s; return false; /* // actually we don't know the way to open device file in WinCE. unsigned len = MyStringLen(s); if (len < 5 || len > 5 || memcmp(s, FTEXT("DSK"), 3 * sizeof(FChar)) != 0) return false; if (s[4] != ':') return false; // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); */ #else if (!IS_DEVICE_PATH(s)) return false; unsigned len = MyStringLen(s); if (len == 6 && s[5] == ':') return true; if (len < 18 || len > 22 || memcmp(s + kDevicePathPrefixSize, FTEXT("PhysicalDrive"), 13 * sizeof(FChar)) != 0) return false; for (unsigned i = 17; i < len; i++) if (s[i] < '0' || s[i] > '9') return false; return true; #endif } bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == '\\'; } bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } // bool IsSuperUncPath(const wchar_t *s) { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } #ifndef USE_UNICODE_FSTRING bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == '\\'; } bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } #endif // USE_UNICODE_FSTRING bool IsAbsolutePath(const wchar_t *s) throw() { return s[0] == WCHAR_PATH_SEPARATOR || IsDrivePath(s); } static const unsigned kDrivePrefixSize = 3; /* c:\ */ #ifndef USE_UNICODE_FSTRING static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) throw() { // Network path: we look "server\path\" as root prefix int pos = FindCharPosInString(s, '\\'); if (pos < 0) return 0; int pos2 = FindCharPosInString(s + pos + 1, '\\'); if (pos2 < 0) return 0; return pos + pos2 + 2; } static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) throw() { if (IsDrivePath(s)) return kDrivePrefixSize; if (s[0] != '\\' || s[1] != '\\') return 0; unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); return (size == 0) ? 0 : 2 + size; } static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) throw() { if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) { unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; } // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" int pos = FindCharPosInString(s + kSuperPathPrefixSize, FCHAR_PATH_SEPARATOR); if (pos < 0) return 0; return kSuperPathPrefixSize + pos + 1; } unsigned GetRootPrefixSize(CFSTR s) throw() { if (IS_DEVICE_PATH(s)) return kDevicePathPrefixSize; if (IsSuperPath(s)) return GetRootPrefixSize_Of_SuperPath(s); return GetRootPrefixSize_Of_SimplePath(s); } #endif // USE_UNICODE_FSTRING static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() { // Network path: we look "server\path\" as root prefix int pos = FindCharPosInString(s, L'\\'); if (pos < 0) return 0; int pos2 = FindCharPosInString(s + pos + 1, L'\\'); if (pos2 < 0) return 0; return pos + pos2 + 2; } static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() { if (IsDrivePath(s)) return kDrivePrefixSize; if (s[0] != '\\' || s[1] != '\\') return 0; unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); return (size == 0) ? 0 : 2 + size; } static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() { if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) { unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; } // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" int pos = FindCharPosInString(s + kSuperPathPrefixSize, L'\\'); if (pos < 0) return 0; return kSuperPathPrefixSize + pos + 1; } unsigned GetRootPrefixSize(const wchar_t *s) throw() { if (IS_DEVICE_PATH(s)) return kDevicePathPrefixSize; if (IsSuperPath(s)) return GetRootPrefixSize_Of_SuperPath(s); return GetRootPrefixSize_Of_SimplePath(s); } #else // _WIN32 bool IsAbsolutePath(const wchar_t *s) throw() { return s[0] == WCHAR_PATH_SEPARATOR } #ifndef USE_UNICODE_FSTRING unsigned GetRootPrefixSize(CFSTR s) throw() { return s[0] == CHAR_PATH_SEPRATOR ? 1 : 0; } #endif unsigned GetRootPrefixSize(const wchar_t *s) throw() { return s[0] == CHAR_PATH_SEPRATOR ? 1 : 0; } #endif // _WIN32 #ifndef UNDER_CE static bool GetCurDir(UString &path) { path.Empty(); DWORD needLength; #ifndef _UNICODE if (!g_IsNT) { TCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); path = fs2us(fas2fs(s)); } else #endif { WCHAR s[MAX_PATH + 2]; s[0] = 0; needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); path = s; } return (needLength > 0 && needLength <= MAX_PATH); } static bool ResolveDotsFolders(UString &s) { #ifdef _WIN32 s.Replace(L'/', WCHAR_PATH_SEPARATOR); #endif for (int i = 0;;) { wchar_t c = s[i]; if (c == 0) return true; if (c == '.' && (i == 0 || s[i - 1] == WCHAR_PATH_SEPARATOR)) { wchar_t c1 = s[i + 1]; if (c1 == '.') { wchar_t c2 = s[i + 2]; if (c2 == WCHAR_PATH_SEPARATOR || c2 == 0) { if (i == 0) return false; int k = i - 2; for (; k >= 0; k--) if (s[k] == WCHAR_PATH_SEPARATOR) break; unsigned num; if (k >= 0) { num = i + 2 - k; i = k; } else { num = (c2 == 0 ? (i + 2) : (i + 3)); i = 0; } s.Delete(i, num); continue; } } else { if (c1 == WCHAR_PATH_SEPARATOR || c1 == 0) { unsigned num = 2; if (i != 0) i--; else if (c1 == 0) num = 1; s.Delete(i, num); continue; } } } i++; } } #endif // UNDER_CE #define LONG_PATH_DOTS_FOLDERS_PARSING /* Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ To solve that problem we check such path: - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain */ #ifdef LONG_PATH_DOTS_FOLDERS_PARSING #ifndef UNDER_CE static bool AreThereDotsFolders(CFSTR s) { for (unsigned i = 0;; i++) { FChar c = s[i]; if (c == 0) return false; if (c == '.' && (i == 0 || s[i - 1] == CHAR_PATH_SEPARATOR)) { FChar c1 = s[i + 1]; if (c1 == 0 || c1 == CHAR_PATH_SEPARATOR || (c1 == '.' && (s[i + 2] == 0 || s[i + 2] == CHAR_PATH_SEPARATOR))) return true; } } } #endif #endif // LONG_PATH_DOTS_FOLDERS_PARSING #ifdef WIN_LONG_PATH /* Most of Windows versions have problems, if some file or dir name contains '.' or ' ' at the end of name (Bad Path). To solve that problem, we always use Super Path ("\\?\" prefix and full path) in such cases. Note that "." and ".." are not bad names. There are 3 cases: 1) If the path is already Super Path, we use that path 2) If the path is not Super Path : 2.1) Bad Path; we use only Super Path. 2.2) Good Path; we use Main Path. If it fails, we use Super Path. NeedToUseOriginalPath returns: kSuperPathType_UseOnlyMain : Super already kSuperPathType_UseOnlySuper : not Super, Bad Path kSuperPathType_UseMainAndSuper : not Super, Good Path */ int GetUseSuperPathType(CFSTR s) throw() { if (IsSuperOrDevicePath(s)) { #ifdef LONG_PATH_DOTS_FOLDERS_PARSING if ((s)[2] != '.') if (AreThereDotsFolders(s + kSuperPathPrefixSize)) return kSuperPathType_UseOnlySuper; #endif return kSuperPathType_UseOnlyMain; } for (unsigned i = 0;; i++) { FChar c = s[i]; if (c == 0) return kSuperPathType_UseMainAndSuper; if (c == '.' || c == ' ') { FChar c2 = s[i + 1]; if (c2 == 0 || c2 == CHAR_PATH_SEPARATOR) { // if it's "." or "..", it's not bad name. if (c == '.') { if (i == 0 || s[i - 1] == CHAR_PATH_SEPARATOR) continue; if (s[i - 1] == '.') { if (i - 1 == 0 || s[i - 2] == CHAR_PATH_SEPARATOR) continue; } } return kSuperPathType_UseOnlySuper; } } } } /* returns false in two cases: - if GetCurDir was used, and GetCurDir returned error. - if we can't resolve ".." name. if path is ".", "..", res is empty. if it's Super Path already, res is empty. for \**** , and if GetCurDir is not drive (c:\), res is empty for absolute paths, returns true, res is Super path. */ static bool GetSuperPathBase(CFSTR s, UString &res) { res.Empty(); FChar c = s[0]; if (c == 0) return true; if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) return true; if (IsSuperOrDevicePath(s)) { #ifdef LONG_PATH_DOTS_FOLDERS_PARSING if ((s)[2] == '.') return true; // we will return true here, so we will try to use these problem paths. if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) return true; UString temp = fs2us(s); unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); if (fixedSize == 0) return true; UString rem = &temp[fixedSize]; if (!ResolveDotsFolders(rem)) return true; temp.DeleteFrom(fixedSize); res += temp; res += rem; #endif return true; } if (c == CHAR_PATH_SEPARATOR) { if (s[1] == CHAR_PATH_SEPARATOR) { UString temp = fs2us(s + 2); unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); if (fixedSize == 0) // maybe we must ignore that error to allow short network paths? return false; UString rem = &temp[fixedSize]; if (!ResolveDotsFolders(rem)) return false; res += kSuperUncPrefix; temp.DeleteFrom(fixedSize); res += temp; res += rem; return true; } } else { if (IsDrivePath(s)) { UString temp = fs2us(s); UString rem = &temp[kDrivePrefixSize]; if (!ResolveDotsFolders(rem)) return true; res += kSuperPathPrefix; temp.DeleteFrom(kDrivePrefixSize); res += temp; res += rem; return true; } } UString curDir; if (!GetCurDir(curDir)) return false; if (curDir.Back() != WCHAR_PATH_SEPARATOR) curDir += WCHAR_PATH_SEPARATOR; unsigned fixedSizeStart = 0; unsigned fixedSize = 0; const wchar_t *superMarker = NULL; if (IsSuperPath(curDir)) { fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); if (fixedSize == 0) return false; } else { if (IsDrivePath(curDir)) { superMarker = kSuperPathPrefix; fixedSize = kDrivePrefixSize; } else { if (curDir[0] != CHAR_PATH_SEPARATOR || curDir[1] != CHAR_PATH_SEPARATOR) return false; fixedSizeStart = 2; fixedSize = GetRootPrefixSize_Of_NetworkPath(&curDir[2]); if (fixedSize == 0) return false; superMarker = kSuperUncPrefix; } } UString temp; if (c == CHAR_PATH_SEPARATOR) { temp = fs2us(s + 1); } else { temp += &curDir[fixedSizeStart + fixedSize]; temp += fs2us(s); } if (!ResolveDotsFolders(temp)) return false; if (superMarker) res += superMarker; res += curDir.Mid(fixedSizeStart, fixedSize); res += temp; return true; } /* In that case if GetSuperPathBase doesn't return new path, we don't need to use same path that was used as main path GetSuperPathBase superPath.IsEmpty() onlyIfNew false * * GetCurDir Error true false * use Super path true true true don't use any path, we already used mainPath true true false use main path as Super Path, we don't try mainMath That case is possible now if GetCurDir returns unknow type of path (not drive and not network) We can change that code if we want to try mainPath, if GetSuperPathBase returns error, and we didn't try mainPath still. If we want to work that way, we don't need to use GetSuperPathBase return code. */ bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) { if (GetSuperPathBase(path, superPath)) { if (superPath.IsEmpty()) { // actually the only possible when onlyIfNew == true and superPath is empty // is case when if (onlyIfNew) return false; superPath = fs2us(path); } return true; } return false; } bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) { if (!GetSuperPathBase(s1, d1) || !GetSuperPathBase(s2, d2)) return false; if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) return false; if (d1.IsEmpty()) d1 = fs2us(s1); if (d2.IsEmpty()) d2 = fs2us(s2); return true; } /* // returns true, if we need additional use with New Super path. bool GetSuperPath(CFSTR path, UString &superPath) { if (GetSuperPathBase(path, superPath)) return !superPath.IsEmpty(); return false; } */ #endif // WIN_LONG_PATH bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) { res = s; #ifdef UNDER_CE if (s[0] != CHAR_PATH_SEPARATOR) { if (!dirPrefix) return false; res = dirPrefix; res += s; } #else unsigned prefixSize = GetRootPrefixSize(s); if (prefixSize != 0) { if (!AreThereDotsFolders(s + prefixSize)) return true; UString rem = fs2us(s + prefixSize); if (!ResolveDotsFolders(rem)) return true; // maybe false; res.DeleteFrom(prefixSize); res += us2fs(rem); return true; } /* FChar c = s[0]; if (c == 0) return true; if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) return true; if (c == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) return true; if (IsDrivePath(s)) return true; */ UString curDir; if (dirPrefix) curDir = fs2us(dirPrefix); else { if (!GetCurDir(curDir)) return false; } if (!curDir.IsEmpty() && curDir.Back() != WCHAR_PATH_SEPARATOR) curDir += WCHAR_PATH_SEPARATOR; unsigned fixedSize = 0; #ifdef _WIN32 if (IsSuperPath(curDir)) { fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); if (fixedSize == 0) return false; } else { if (IsDrivePath(curDir)) fixedSize = kDrivePrefixSize; else { if (curDir[0] != WCHAR_PATH_SEPARATOR || curDir[1] != WCHAR_PATH_SEPARATOR) return false; fixedSize = GetRootPrefixSize_Of_NetworkPath(&curDir[2]); if (fixedSize == 0) return false; fixedSize += 2; } } #endif // _WIN32 UString temp; if (s[0] == CHAR_PATH_SEPARATOR) { temp = fs2us(s + 1); } else { temp += curDir.Ptr(fixedSize); temp += fs2us(s); } if (!ResolveDotsFolders(temp)) return false; curDir.DeleteFrom(fixedSize); res = us2fs(curDir); res += us2fs(temp); #endif // UNDER_CE return true; } bool GetFullPath(CFSTR path, FString &fullPath) { return GetFullPath(NULL, path, fullPath); } }}} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/FileName.h0100777000000000000000000000436513761647206022223 0ustar00// Windows/FileName.h #ifndef __WINDOWS_FILE_NAME_H #define __WINDOWS_FILE_NAME_H #include "../Common/MyString.h" namespace NWindows { namespace NFile { namespace NName { void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty void NormalizeDirPathPrefix(UString &dirPath); #ifdef _WIN32 extern const wchar_t *kSuperPathPrefix; /* \\?\ */ const unsigned kDevicePathPrefixSize = 4; const unsigned kSuperPathPrefixSize = 4; const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ bool IsSuperUncPath(CFSTR s) throw(); bool IsDrivePath(const wchar_t *s) throw(); bool IsSuperPath(const wchar_t *s) throw(); bool IsSuperOrDevicePath(const wchar_t *s) throw(); #ifndef USE_UNICODE_FSTRING bool IsDrivePath(CFSTR s) throw(); bool IsSuperPath(CFSTR s) throw(); bool IsSuperOrDevicePath(CFSTR s) throw(); #endif #endif // _WIN32 bool IsAbsolutePath(const wchar_t *s) throw(); unsigned GetRootPrefixSize(const wchar_t *s) throw(); #ifdef WIN_LONG_PATH const int kSuperPathType_UseOnlyMain = 0; const int kSuperPathType_UseOnlySuper = 1; const int kSuperPathType_UseMainAndSuper = 2; int GetUseSuperPathType(CFSTR s) throw(); bool GetSuperPath(CFSTR path, UString &longPath, bool onlyIfNew); bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew); #define USE_MAIN_PATH (__useSuperPathType != kSuperPathType_UseOnlySuper) #define USE_MAIN_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlySuper && __useSuperPathType2 != kSuperPathType_UseOnlySuper) #define USE_SUPER_PATH (__useSuperPathType != kSuperPathType_UseOnlyMain) #define USE_SUPER_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlyMain || __useSuperPathType2 != kSuperPathType_UseOnlyMain) #define IF_USE_MAIN_PATH int __useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH) #define IF_USE_MAIN_PATH_2(x1, x2) \ int __useSuperPathType1 = GetUseSuperPathType(x1); \ int __useSuperPathType2 = GetUseSuperPathType(x2); \ if (USE_MAIN_PATH_2) #else #define IF_USE_MAIN_PATH #define IF_USE_MAIN_PATH_2(x1, x2) #endif // WIN_LONG_PATH bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath); bool GetFullPath(CFSTR path, FString &fullPath); }}} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Handle.h0100777000000000000000000000115213761647206021725 0ustar00// Windows/Handle.h #ifndef __WINDOWS_HANDLE_H #define __WINDOWS_HANDLE_H namespace NWindows { class CHandle { protected: HANDLE _handle; public: operator HANDLE() { return _handle; } CHandle(): _handle(NULL) {} ~CHandle() { Close(); } bool IsCreated() const { return (_handle != NULL); } bool Close() { if (_handle == NULL) return true; if (!::CloseHandle(_handle)) return false; _handle = NULL; return true; } void Attach(HANDLE handle) { _handle = handle; } HANDLE Detach() { HANDLE handle = _handle; _handle = NULL; return handle; } }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/PropVariant.cpp0100777000000000000000000001410113761647206023330 0ustar00// Windows/PropVariant.cpp #include "StdAfx.h" #include "../Common/Defs.h" #include "PropVariant.h" namespace NWindows { namespace NCOM { HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() { p->bstrVal = ::SysAllocStringLen(0, numChars); if (!p->bstrVal) { p->vt = VT_ERROR; p->scode = E_OUTOFMEMORY; return E_OUTOFMEMORY; } p->vt = VT_BSTR; return S_OK; } HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() { UINT len = (UINT)strlen(s); p->bstrVal = ::SysAllocStringLen(0, len); if (!p->bstrVal) { p->vt = VT_ERROR; p->scode = E_OUTOFMEMORY; return E_OUTOFMEMORY; } p->vt = VT_BSTR; BSTR dest = p->bstrVal; for (UINT i = 0; i <= len; i++) dest[i] = s[i]; return S_OK; } CPropVariant::CPropVariant(const PROPVARIANT &varSrc) { vt = VT_EMPTY; InternalCopy(&varSrc); } CPropVariant::CPropVariant(const CPropVariant &varSrc) { vt = VT_EMPTY; InternalCopy(&varSrc); } CPropVariant::CPropVariant(BSTR bstrSrc) { vt = VT_EMPTY; *this = bstrSrc; } CPropVariant::CPropVariant(LPCOLESTR lpszSrc) { vt = VT_EMPTY; *this = lpszSrc; } CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) { InternalCopy(&varSrc); return *this; } CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) { InternalCopy(&varSrc); return *this; } CPropVariant& CPropVariant::operator=(BSTR bstrSrc) { *this = (LPCOLESTR)bstrSrc; return *this; } static const char *kMemException = "out of memory"; CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) { InternalClear(); vt = VT_BSTR; wReserved1 = 0; bstrVal = ::SysAllocString(lpszSrc); if (!bstrVal && lpszSrc) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } return *this; } CPropVariant& CPropVariant::operator=(const char *s) { InternalClear(); vt = VT_BSTR; wReserved1 = 0; UINT len = (UINT)strlen(s); bstrVal = ::SysAllocStringLen(0, len); if (!bstrVal) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } else { for (UINT i = 0; i <= len; i++) bstrVal[i] = s[i]; } return *this; } CPropVariant& CPropVariant::operator=(bool bSrc) throw() { if (vt != VT_BOOL) { InternalClear(); vt = VT_BOOL; } boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; return *this; } BSTR CPropVariant::AllocBstr(unsigned numChars) { if (vt != VT_EMPTY) InternalClear(); vt = VT_BSTR; wReserved1 = 0; bstrVal = ::SysAllocStringLen(0, numChars); if (!bstrVal) { throw kMemException; // vt = VT_ERROR; // scode = E_OUTOFMEMORY; } return bstrVal; } #define SET_PROP_FUNC(type, id, dest) \ CPropVariant& CPropVariant::operator=(type value) throw() \ { if (vt != id) { InternalClear(); vt = id; } \ dest = value; return *this; } SET_PROP_FUNC(Byte, VT_UI1, bVal) // SET_PROP_FUNC(Int16, VT_I2, iVal) SET_PROP_FUNC(Int32, VT_I4, lVal) SET_PROP_FUNC(UInt32, VT_UI4, ulVal) SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() { switch (prop->vt) { case VT_EMPTY: case VT_UI1: case VT_I1: case VT_I2: case VT_UI2: case VT_BOOL: case VT_I4: case VT_UI4: case VT_R4: case VT_INT: case VT_UINT: case VT_ERROR: case VT_FILETIME: case VT_UI8: case VT_R8: case VT_CY: case VT_DATE: prop->vt = VT_EMPTY; prop->wReserved1 = 0; prop->wReserved2 = 0; prop->wReserved3 = 0; prop->uhVal.QuadPart = 0; return S_OK; } return ::VariantClear((VARIANTARG *)prop); // return ::PropVariantClear(prop); // PropVariantClear can clear VT_BLOB. } HRESULT CPropVariant::Clear() throw() { if (vt == VT_EMPTY) return S_OK; return PropVariant_Clear(this); } HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() { ::VariantClear((tagVARIANT *)this); switch(pSrc->vt) { case VT_UI1: case VT_I1: case VT_I2: case VT_UI2: case VT_BOOL: case VT_I4: case VT_UI4: case VT_R4: case VT_INT: case VT_UINT: case VT_ERROR: case VT_FILETIME: case VT_UI8: case VT_R8: case VT_CY: case VT_DATE: memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); return S_OK; } return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast(pSrc)); } HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() { HRESULT hr = Clear(); if (FAILED(hr)) return hr; memcpy(this, pSrc, sizeof(PROPVARIANT)); pSrc->vt = VT_EMPTY; return S_OK; } HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() { if (pDest->vt != VT_EMPTY) { HRESULT hr = PropVariant_Clear(pDest); if (FAILED(hr)) return hr; } memcpy(pDest, this, sizeof(PROPVARIANT)); vt = VT_EMPTY; return S_OK; } HRESULT CPropVariant::InternalClear() throw() { if (vt == VT_EMPTY) return S_OK; HRESULT hr = Clear(); if (FAILED(hr)) { vt = VT_ERROR; scode = hr; } return hr; } void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) { HRESULT hr = Copy(pSrc); if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) throw kMemException; vt = VT_ERROR; scode = hr; } } int CPropVariant::Compare(const CPropVariant &a) throw() { if (vt != a.vt) return MyCompare(vt, a.vt); switch (vt) { case VT_EMPTY: return 0; // case VT_I1: return MyCompare(cVal, a.cVal); case VT_UI1: return MyCompare(bVal, a.bVal); case VT_I2: return MyCompare(iVal, a.iVal); case VT_UI2: return MyCompare(uiVal, a.uiVal); case VT_I4: return MyCompare(lVal, a.lVal); case VT_UI4: return MyCompare(ulVal, a.ulVal); // case VT_UINT: return MyCompare(uintVal, a.uintVal); case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); case VT_BOOL: return -MyCompare(boolVal, a.boolVal); case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); case VT_BSTR: return 0; // Not implemented default: return 0; } } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/PropVariant.h0100777000000000000000000000573413761647206023011 0ustar00// Windows/PropVariant.h #ifndef __WINDOWS_PROP_VARIANT_H #define __WINDOWS_PROP_VARIANT_H #include "../Common/MyTypes.h" #include "../Common/MyWindows.h" namespace NWindows { namespace NCOM { HRESULT PropVariant_Clear(PROPVARIANT *p) throw(); HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw(); HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw(); inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw() { p->vt = VT_UI4; p->ulVal = v; } inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw() { p->vt = VT_UI8; p->uhVal.QuadPart = v; } inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw() { p->vt = VT_FILETIME; p->filetime.dwLowDateTime = (DWORD)v; p->filetime.dwHighDateTime = (DWORD)(v >> 32); } inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() { p->vt = VT_BOOL; p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE); } class CPropVariant : public tagPROPVARIANT { public: CPropVariant() { vt = VT_EMPTY; wReserved1 = 0; // wReserved2 = 0; // wReserved3 = 0; // uhVal.QuadPart = 0; bstrVal = 0; } ~CPropVariant() throw() { Clear(); } CPropVariant(const PROPVARIANT &varSrc); CPropVariant(const CPropVariant &varSrc); CPropVariant(BSTR bstrSrc); CPropVariant(LPCOLESTR lpszSrc); CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }; CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } private: CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } public: CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } CPropVariant(Int64 value) { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } CPropVariant& operator=(const CPropVariant &varSrc); CPropVariant& operator=(const PROPVARIANT &varSrc); CPropVariant& operator=(BSTR bstrSrc); CPropVariant& operator=(LPCOLESTR lpszSrc); CPropVariant& operator=(const char *s); CPropVariant& operator=(bool bSrc) throw(); CPropVariant& operator=(Byte value) throw(); private: CPropVariant& operator=(Int16 value) throw(); public: CPropVariant& operator=(Int32 value) throw(); CPropVariant& operator=(UInt32 value) throw(); CPropVariant& operator=(UInt64 value) throw(); CPropVariant& operator=(Int64 value) throw(); CPropVariant& operator=(const FILETIME &value) throw(); BSTR AllocBstr(unsigned numChars); HRESULT Clear() throw(); HRESULT Copy(const PROPVARIANT *pSrc) throw(); HRESULT Attach(PROPVARIANT *pSrc) throw(); HRESULT Detach(PROPVARIANT *pDest) throw(); HRESULT InternalClear() throw(); void InternalCopy(const PROPVARIANT *pSrc); int Compare(const CPropVariant &a) throw(); }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/PropVariantConv.cpp0100777000000000000000000000643313761647206024167 0ustar00// PropVariantConvert.cpp #include "StdAfx.h" #include "../Common/IntToString.h" #include "Defs.h" #include "PropVariantConv.h" #define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds) throw() { SYSTEMTIME st; if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) { *s = 0; return false; } unsigned val = st.wYear; if (val >= 10000) { *s++ = (char)('0' + val / 10000); val %= 10000; } { s[3] = (char)('0' + val % 10); val /= 10; s[2] = (char)('0' + val % 10); val /= 10; s[1] = (char)('0' + val % 10); s[0] = (char)('0' + val / 10); s += 4; } UINT_TO_STR_2('-', st.wMonth); UINT_TO_STR_2('-', st.wDay); if (includeTime) { UINT_TO_STR_2(' ', st.wHour); UINT_TO_STR_2(':', st.wMinute); if (includeSeconds) UINT_TO_STR_2(':', st.wSecond); } *s = 0; return true; } void ConvertFileTimeToString(const FILETIME &ft, wchar_t *dest, bool includeTime, bool includeSeconds) throw() { char s[32]; ConvertFileTimeToString(ft, s, includeTime, includeSeconds); for (unsigned i = 0;; i++) { unsigned char c = s[i]; dest[i] = c; if (c == 0) return; } } void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw() { *dest = 0; switch (prop.vt) { case VT_EMPTY: return; case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; case VT_FILETIME: ConvertFileTimeToString(prop.filetime, dest, true, true); return; // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2); } } void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw() { *dest = 0; switch (prop.vt) { case VT_EMPTY: return; case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; case VT_FILETIME: ConvertFileTimeToString(prop.filetime, dest, true, true); return; // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2); } } qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/PropVariantConv.h0100777000000000000000000000210213761647206023621 0ustar00// Windows/PropVariantConv.h #ifndef __PROP_VARIANT_CONV_H #define __PROP_VARIANT_CONV_H #include "../Common/MyTypes.h" // provide at least 32 bytes for buffer including zero-end bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true) throw(); void ConvertFileTimeToString(const FILETIME &ft, wchar_t *s, bool includeTime = true, bool includeSeconds = true) throw(); // provide at least 32 bytes for buffer including zero-end // don't send VT_BSTR to these functions void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(); void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw(); inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value) { switch (prop.vt) { case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true; case VT_UI4: value = prop.ulVal; return true; case VT_UI2: value = prop.uiVal; return true; case VT_UI1: value = prop.bVal; return true; case VT_EMPTY: return false; default: throw 151199; } } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/SecurityUtils.cpp0100777000000000000000000001122313761647206023715 0ustar00// Windows/SecurityUtils.cpp #include "StdAfx.h" #include "SecurityUtils.h" namespace NWindows { namespace NSecurity { /* bool MyLookupAccountSid(LPCTSTR systemName, PSID sid, CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse) { DWORD accountNameSize = 0, domainNameSize = 0; if (!::LookupAccountSid(systemName, sid, accountName.GetBuffer(0), &accountNameSize, domainName.GetBuffer(0), &domainNameSize, sidNameUse)) { if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) return false; } bool result = BOOLToBool(::LookupAccountSid(systemName, sid, accountName.GetBuffer(accountNameSize), &accountNameSize, domainName.GetBuffer(domainNameSize), &domainNameSize, sidNameUse)); accountName.ReleaseBuffer(); domainName.ReleaseBuffer(); return result; } */ static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest) { int len = (int)wcslen(src); dest->Length = (USHORT)(len * sizeof(WCHAR)); dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR)); dest->Buffer = src; } /* static void MyLookupSids(CPolicy &policy, PSID ps) { LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL; LSA_TRANSLATED_NAME *names = NULL; NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names); int res = LsaNtStatusToWinError(nts); LsaFreeMemory(referencedDomains); LsaFreeMemory(names); } */ #ifndef _UNICODE typedef BOOL (WINAPI * LookupAccountNameWP)( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); #endif static PSID GetSid(LPWSTR accountName) { #ifndef _UNICODE HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll")); if (hModule == NULL) return NULL; LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW"); if (lookupAccountNameW == NULL) return NULL; #endif DWORD sidLen = 0, domainLen = 0; SID_NAME_USE sidNameUse; if (! #ifdef _UNICODE ::LookupAccountNameW #else lookupAccountNameW #endif (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse)) { if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen); LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR)); BOOL res = #ifdef _UNICODE ::LookupAccountNameW #else lookupAccountNameW #endif (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse); ::HeapFree(GetProcessHeap(), 0, domainName); if (res) return pSid; } } return NULL; } #define MY__SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege" bool AddLockMemoryPrivilege() { CPolicy policy; LSA_OBJECT_ATTRIBUTES attr; attr.Length = sizeof(attr); attr.RootDirectory = NULL; attr.ObjectName = NULL; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; if (policy.Open(NULL, &attr, // GENERIC_WRITE) POLICY_ALL_ACCESS) // STANDARD_RIGHTS_REQUIRED, // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES) != 0) return false; LSA_UNICODE_STRING userRights; wchar_t s[128] = MY__SE_LOCK_MEMORY_NAME; SetLsaString(s, &userRights); WCHAR userName[256 + 2]; DWORD size = 256; if (!GetUserNameW(userName, &size)) return false; PSID psid = GetSid(userName); if (psid == NULL) return false; bool res = false; /* PLSA_UNICODE_STRING userRightsArray; ULONG countOfRights; NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights); if (status != 0) return false; bool finded = false; for (ULONG i = 0; i < countOfRights; i++) { LSA_UNICODE_STRING &ur = userRightsArray[i]; if (ur.Length != s.Length() * sizeof(WCHAR)) continue; if (wcsncmp(ur.Buffer, s, s.Length()) != 0) continue; finded = true; res = true; break; } if (!finded) */ { /* LSA_ENUMERATION_INFORMATION *enums; ULONG countReturned; NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned); if (status == 0) { for (ULONG i = 0; i < countReturned; i++) MyLookupSids(policy, enums[i].Sid); if (enums) ::LsaFreeMemory(enums); res = true; } */ NTSTATUS status = policy.AddAccountRights(psid, &userRights); if (status == 0) res = true; // ULONG res = LsaNtStatusToWinError(status); } HeapFree(GetProcessHeap(), 0, psid); return res; } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/SecurityUtils.h0100777000000000000000000001144313761647206023366 0ustar00// Windows/SecurityUtils.h #ifndef __WINDOWS_SECURITY_UTILS_H #define __WINDOWS_SECURITY_UTILS_H #include #include "Defs.h" namespace NWindows { namespace NSecurity { class CAccessToken { HANDLE _handle; public: CAccessToken(): _handle(NULL) {}; ~CAccessToken() { Close(); } bool Close() { if (_handle == NULL) return true; bool res = BOOLToBool(::CloseHandle(_handle)); if (res) _handle = NULL; return res; } bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess) { Close(); return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle)); } /* bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf) { Close(); return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle)); } */ bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState, DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength) { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges), newState, bufferLength, previousState, returnLength)); } bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState) { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); } bool AdjustPrivileges(PTOKEN_PRIVILEGES newState) { return AdjustPrivileges(false, newState); } }; #ifndef _UNICODE typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName, PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle); typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle, PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); #define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) #endif struct CPolicy { protected: LSA_HANDLE _handle; #ifndef _UNICODE HMODULE hModule; #endif public: operator LSA_HANDLE() const { return _handle; } CPolicy(): _handle(NULL) { #ifndef _UNICODE hModule = GetModuleHandle(TEXT("Advapi32.dll")); #endif }; ~CPolicy() { Close(); } NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, ACCESS_MASK desiredAccess) { #ifndef _UNICODE if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy"); if (lsaOpenPolicy == NULL) return MY_STATUS_NOT_IMPLEMENTED; #endif Close(); return #ifdef _UNICODE ::LsaOpenPolicy #else lsaOpenPolicy #endif (systemName, objectAttributes, desiredAccess, &_handle); } NTSTATUS Close() { if (_handle == NULL) return 0; #ifndef _UNICODE if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose"); if (lsaClose == NULL) return MY_STATUS_NOT_IMPLEMENTED; #endif NTSTATUS res = #ifdef _UNICODE ::LsaClose #else lsaClose #endif (_handle); _handle = NULL; return res; } NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights, PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned) { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); } NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights) { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); } NTSTATUS LookupSids(ULONG count, PSID* sids, PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names) { return LsaLookupSids(_handle, count, sids, referencedDomains, names); } NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) { #ifndef _UNICODE if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights"); if (lsaAddAccountRights == NULL) return MY_STATUS_NOT_IMPLEMENTED; #endif return #ifdef _UNICODE ::LsaAddAccountRights #else lsaAddAccountRights #endif (_handle, accountSid, userRights, countOfRights); } NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) { return AddAccountRights(accountSid, userRights, 1); } NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights) { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); } }; bool AddLockMemoryPrivilege(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/StdAfx.h0100777000000000000000000000013213761647206021720 0ustar00// StdAfx.h #ifndef __STDAFX_H #define __STDAFX_H #include "../Common/Common.h" #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Synchronization.cpp0100777000000000000000000000021113761647206024261 0ustar00// Windows/Synchronization.cpp #include "StdAfx.h" #include "Synchronization.h" namespace NWindows { namespace NSynchronization { }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Synchronization.h0100777000000000000000000000773013761647206023743 0ustar00// Windows/Synchronization.h #ifndef __WINDOWS_SYNCHRONIZATION_H #define __WINDOWS_SYNCHRONIZATION_H #include "../../C/Threads.h" #include "Defs.h" #ifdef _WIN32 #include "Handle.h" #endif namespace NWindows { namespace NSynchronization { class CBaseEvent { protected: ::CEvent _object; public: bool IsCreated() { return Event_IsCreated(&_object) != 0; } operator HANDLE() { return _object; } CBaseEvent() { Event_Construct(&_object); } ~CBaseEvent() { Close(); } WRes Close() { return Event_Close(&_object); } #ifdef _WIN32 WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) { _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); if (name == NULL && _object != 0) return 0; return ::GetLastError(); } WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) { _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); if (_object != 0) return 0; return ::GetLastError(); } #endif WRes Set() { return Event_Set(&_object); } // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } WRes Reset() { return Event_Reset(&_object); } WRes Lock() { return Event_Wait(&_object); } }; class CManualResetEvent: public CBaseEvent { public: WRes Create(bool initiallyOwn = false) { return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); } WRes CreateIfNotCreated() { if (IsCreated()) return 0; return ManualResetEvent_CreateNotSignaled(&_object); } #ifdef _WIN32 WRes CreateWithName(bool initiallyOwn, LPCTSTR name) { return CBaseEvent::Create(true, initiallyOwn, name); } #endif }; class CAutoResetEvent: public CBaseEvent { public: WRes Create() { return AutoResetEvent_CreateNotSignaled(&_object); } WRes CreateIfNotCreated() { if (IsCreated()) return 0; return AutoResetEvent_CreateNotSignaled(&_object); } }; #ifdef _WIN32 class CObject: public CHandle { public: WRes Lock(DWORD timeoutInterval = INFINITE) { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } }; class CMutex: public CObject { public: WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) { _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); if (name == NULL && _handle != 0) return 0; return ::GetLastError(); } #ifndef UNDER_CE WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) { _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); if (_handle != 0) return 0; return ::GetLastError(); } #endif WRes Release() { return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); } }; class CMutexLock { CMutex *_object; public: CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } ~CMutexLock() { _object->Release(); } }; #endif class CSemaphore { ::CSemaphore _object; public: CSemaphore() { Semaphore_Construct(&_object); } ~CSemaphore() { Close(); } WRes Close() { return Semaphore_Close(&_object); } operator HANDLE() { return _object; } WRes Create(UInt32 initiallyCount, UInt32 maxCount) { return Semaphore_Create(&_object, initiallyCount, maxCount); } WRes Release() { return Semaphore_Release1(&_object); } WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } WRes Lock() { return Semaphore_Wait(&_object); } }; class CCriticalSection { ::CCriticalSection _object; public: CCriticalSection() { CriticalSection_Init(&_object); } ~CCriticalSection() { CriticalSection_Delete(&_object); } void Enter() { CriticalSection_Enter(&_object); } void Leave() { CriticalSection_Leave(&_object); } }; class CCriticalSectionLock { CCriticalSection *_object; void Unlock() { _object->Leave(); } public: CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } ~CCriticalSectionLock() { Unlock(); } }; }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/System.cpp0100777000000000000000000000304713761647206022356 0ustar00// Windows/System.cpp #include "StdAfx.h" #include "../Common/Defs.h" #include "System.h" namespace NWindows { namespace NSystem { UInt32 GetNumberOfProcessors() { SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); return (UInt32)systemInfo.dwNumberOfProcessors; } #ifndef UNDER_CE #if !defined(_WIN64) && defined(__GNUC__) typedef struct _MY_MEMORYSTATUSEX { DWORD dwLength; DWORD dwMemoryLoad; DWORDLONG ullTotalPhys; DWORDLONG ullAvailPhys; DWORDLONG ullTotalPageFile; DWORDLONG ullAvailPageFile; DWORDLONG ullTotalVirtual; DWORDLONG ullAvailVirtual; DWORDLONG ullAvailExtendedVirtual; } MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX; #else #define MY_MEMORYSTATUSEX MEMORYSTATUSEX #define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX #endif typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer); #endif UInt64 GetRamSize() { #ifndef UNDER_CE MY_MEMORYSTATUSEX stat; stat.dwLength = sizeof(stat); #endif #ifdef _WIN64 if (!::GlobalMemoryStatusEx(&stat)) return 0; return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); #else #ifndef UNDER_CE GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP) ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx"); if (globalMemoryStatusEx != 0 && globalMemoryStatusEx(&stat)) return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); #endif { MEMORYSTATUS stat; stat.dwLength = sizeof(stat); ::GlobalMemoryStatus(&stat); return MyMin(stat.dwTotalVirtual, stat.dwTotalPhys); } #endif } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/System.h0100777000000000000000000000032713761647206022021 0ustar00// Windows/System.h #ifndef __WINDOWS_SYSTEM_H #define __WINDOWS_SYSTEM_H #include "../Common/MyTypes.h" namespace NWindows { namespace NSystem { UInt32 GetNumberOfProcessors(); UInt64 GetRamSize(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Thread.h0100777000000000000000000000215513761647206021745 0ustar00// Windows/Thread.h #ifndef __WINDOWS_THREAD_H #define __WINDOWS_THREAD_H #include "../../C/Threads.h" #include "Defs.h" namespace NWindows { class CThread { ::CThread thread; public: CThread() { Thread_Construct(&thread); } ~CThread() { Close(); } bool IsCreated() { return Thread_WasCreated(&thread) != 0; } WRes Close() { return Thread_Close(&thread); } WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) { return Thread_Create(&thread, startAddress, parameter); } WRes Wait() { return Thread_Wait(&thread); } #ifdef _WIN32 operator HANDLE() { return thread; } void Attach(HANDLE handle) { thread = handle; } HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } DWORD Resume() { return ::ResumeThread(thread); } DWORD Suspend() { return ::SuspendThread(thread); } bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } int GetPriority() { return ::GetThreadPriority(thread); } bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } #endif }; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/TimeUtils.cpp0100777000000000000000000001256513761647206023016 0ustar00// Windows/TimeUtils.cpp #include "StdAfx.h" #include "Defs.h" #include "TimeUtils.h" namespace NWindows { namespace NTime { static const UInt32 kNumTimeQuantumsInSecond = 10000000; static const UInt32 kFileTimeStartYear = 1601; static const UInt32 kDosTimeStartYear = 1980; static const UInt32 kUnixTimeStartYear = 1970; static const UInt64 kUnixTimeOffset = (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() { #if defined(_WIN32) && !defined(UNDER_CE) return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); #else ft.dwLowDateTime = 0; ft.dwHighDateTime = 0; UInt64 res; if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F, (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res)) return false; res *= kNumTimeQuantumsInSecond; ft.dwLowDateTime = (UInt32)res; ft.dwHighDateTime = (UInt32)(res >> 32); return true; #endif } static const UInt32 kHighDosTime = 0xFF9FBF7D; static const UInt32 kLowDosTime = 0x210000; #define PERIOD_4 (4 * 365 + 1) #define PERIOD_100 (PERIOD_4 * 25 - 1) #define PERIOD_400 (PERIOD_100 * 4 + 1) bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() { #if defined(_WIN32) && !defined(UNDER_CE) WORD datePart, timePart; if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) { dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; return false; } dosTime = (((UInt32)datePart) << 16) + timePart; #else unsigned year, mon, day, hour, min, sec; UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; unsigned temp; UInt32 v; v64 += (kNumTimeQuantumsInSecond * 2 - 1); v64 /= kNumTimeQuantumsInSecond; sec = (unsigned)(v64 % 60); v64 /= 60; min = (unsigned)(v64 % 60); v64 /= 60; hour = (unsigned)(v64 % 24); v64 /= 24; v = (UInt32)v64; year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400); v %= PERIOD_400; temp = (unsigned)(v / PERIOD_100); if (temp == 4) temp = 3; year += temp * 100; v -= temp * PERIOD_100; temp = v / PERIOD_4; if (temp == 25) temp = 24; year += temp * 4; v -= temp * PERIOD_4; temp = v / 365; if (temp == 4) temp = 3; year += temp; v -= temp * 365; if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ms[1] = 29; for (mon = 1; mon <= 12; mon++) { unsigned s = ms[mon - 1]; if (v < s) break; v -= s; } day = (unsigned)v + 1; dosTime = kLowDosTime; if (year < kDosTimeStartYear) return false; year -= kDosTimeStartYear; dosTime = kHighDosTime; if (year >= 128) return false; dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1); #endif return true; } void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() { UInt64 v = (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; ft.dwLowDateTime = (DWORD)v; ft.dwHighDateTime = (DWORD)(v >> 32); } bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() { if (unixTime > kNumSecondsInFileTime - kUnixTimeOffset) { ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1; return false; } Int64 v = (Int64)kUnixTimeOffset + unixTime; if (v < 0) { ft.dwLowDateTime = ft.dwHighDateTime = 0; return false; } UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond; ft.dwLowDateTime = (DWORD)v2; ft.dwHighDateTime = (DWORD)(v2 >> 32); return true; } Int64 FileTimeToUnixTime64(const FILETIME &ft) throw() { UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; return (Int64)(winTime / kNumTimeQuantumsInSecond) - kUnixTimeOffset; } bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw() { UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; winTime /= kNumTimeQuantumsInSecond; if (winTime < kUnixTimeOffset) { unixTime = 0; return false; } winTime -= kUnixTimeOffset; if (winTime > 0xFFFFFFFF) { unixTime = 0xFFFFFFFF; return false; } unixTime = (UInt32)winTime; return true; } bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() { resSeconds = 0; if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) return false; UInt32 numYears = year - kFileTimeStartYear; UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400; Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ms[1] = 29; month--; for (unsigned i = 0; i < month; i++) numDays += ms[i]; numDays += day - 1; resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; return true; } void GetCurUtcFileTime(FILETIME &ft) throw() { // Both variants provide same low resolution on WinXP: about 15 ms. // But GetSystemTimeAsFileTime is much faster. #ifdef UNDER_CE SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); #else GetSystemTimeAsFileTime(&ft); #endif } }} qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/TimeUtils.h0100777000000000000000000000141213761647206022450 0ustar00// Windows/TimeUtils.h #ifndef __WINDOWS_TIME_UTILS_H #define __WINDOWS_TIME_UTILS_H #include "../Common/MyTypes.h" namespace NWindows { namespace NTime { bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw(); bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw(); bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw(); bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); Int64 FileTimeToUnixTime64(const FILETIME &ft) throw(); bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); void GetCurUtcFileTime(FILETIME &ft) throw(); }} #endif qt-installer-framework-4.0.1/src/libs/7zip/win/CPP/Windows/Windows.pri0100777000000000000000000000226213761647206022532 0ustar00HEADERS += $$7ZIP_BASE/CPP/Windows/DLL.h \ $$7ZIP_BASE/CPP/Windows/Defs.h \ $$7ZIP_BASE/CPP/Windows/FileDir.h \ $$7ZIP_BASE/CPP/Windows/FileFind.h \ $$7ZIP_BASE/CPP/Windows/FileIO.h \ $$7ZIP_BASE/CPP/Windows/FileMapping.h \ $$7ZIP_BASE/CPP/Windows/FileName.h \ $$7ZIP_BASE/CPP/Windows/Handle.h \ $$7ZIP_BASE/CPP/Windows/PropVariant.h \ $$7ZIP_BASE/CPP/Windows/PropVariantConv.h \ $$7ZIP_BASE/CPP/Windows/SecurityUtils.h \ $$7ZIP_BASE/CPP/Windows/StdAfx.h \ $$7ZIP_BASE/CPP/Windows/Synchronization.h \ $$7ZIP_BASE/CPP/Windows/System.h \ $$7ZIP_BASE/CPP/Windows/Thread.h \ $$7ZIP_BASE/CPP/Windows/TimeUtils.h SOURCES += $$7ZIP_BASE/CPP/Windows/DLL.cpp \ $$7ZIP_BASE/CPP/Windows/FileDir.cpp \ $$7ZIP_BASE/CPP/Windows/FileFind.cpp \ $$7ZIP_BASE/CPP/Windows/FileIO.cpp \ $$7ZIP_BASE/CPP/Windows/FileLink.cpp \ $$7ZIP_BASE/CPP/Windows/FileName.cpp \ $$7ZIP_BASE/CPP/Windows/PropVariant.cpp \ $$7ZIP_BASE/CPP/Windows/PropVariantConv.cpp \ $$7ZIP_BASE/CPP/Windows/SecurityUtils.cpp \ $$7ZIP_BASE/CPP/Windows/Synchronization.cpp \ $$7ZIP_BASE/CPP/Windows/System.cpp \ $$7ZIP_BASE/CPP/Windows/TimeUtils.cpp qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zCrc.c0100777000000000000000000000374613761647206017636 0ustar00/* 7zCrc.c -- CRC32 init 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #define kCrcPoly 0xEDB88320 #ifdef MY_CPU_X86_OR_AMD64 #define CRC_NUM_TABLES 8 UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #elif defined(MY_CPU_LE) #define CRC_NUM_TABLES 4 #else #define CRC_NUM_TABLES 5 #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); CRC_FUNC g_CrcUpdate; UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) { return g_CrcUpdate(v, data, size, g_CrcTable); } UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) { return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } void MY_FAST_CALL CrcGenerateTable() { UInt32 i; for (i = 0; i < 256; i++) { UInt32 r = i; unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); g_CrcTable[i] = r; } for (; i < 256 * CRC_NUM_TABLES; i++) { UInt32 r = g_CrcTable[i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } #ifdef MY_CPU_LE g_CrcUpdate = CrcUpdateT4; #if CRC_NUM_TABLES == 8 if (!CPU_Is_InOrder()) g_CrcUpdate = CrcUpdateT8; #endif #else { #ifndef MY_CPU_BE UInt32 k = 1; if (*(const Byte *)&k == 1) g_CrcUpdate = CrcUpdateT4; else #endif { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { UInt32 x = g_CrcTable[i - 256]; g_CrcTable[i] = CRC_UINT32_SWAP(x); } g_CrcUpdate = CrcUpdateT1_BeT4; } } #endif } qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zCrc.h0100777000000000000000000000114413761647206017631 0ustar00/* 7zCrc.h -- CRC32 calculation 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_CRC_H #define __7Z_CRC_H #include "7zTypes.h" EXTERN_C_BEGIN extern UInt32 g_CrcTable[]; /* Call CrcGenerateTable one time before other CRC functions */ void MY_FAST_CALL CrcGenerateTable(void); #define CRC_INIT_VAL 0xFFFFFFFF #define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) #define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zCrcOpt.c0100777000000000000000000000324213761647206020310 0ustar00/* 7zCrcOpt.c -- CRC32 calculation 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = table[0x300 + (v & 0xFF)] ^ table[0x200 + ((v >> 8) & 0xFF)] ^ table[0x100 + ((v >> 16) & 0xFF)] ^ table[0x000 + ((v >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { return CrcUpdateT4(v, data, size, table); } #endif #ifndef MY_CPU_LE #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); v = CRC_UINT32_SWAP(v); table += 0x100; for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = table[0x000 + (v & 0xFF)] ^ table[0x100 + ((v >> 8) & 0xFF)] ^ table[0x200 + ((v >> 16) & 0xFF)] ^ table[0x300 + ((v >> 24))]; } table -= 0x100; v = CRC_UINT32_SWAP(v); for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zStream.c0100777000000000000000000000766113761647206020362 0ustar00/* 7zStream.c -- 7z Stream functions 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "7zTypes.h" SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; RINOK(stream->Read(stream, buf, &processed)); if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); size -= processed; } return SZ_OK; } SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) { return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) { size_t processed = 1; RINOK(stream->Read(stream, buf, &processed)); return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; } SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) { Int64 t = offset; return stream->Seek(stream, &t, SZ_SEEK_SET); } SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) { const void *lookBuf; if (*size == 0) return SZ_OK; RINOK(stream->Look(stream, &lookBuf, size)); memcpy(buf, lookBuf, *size); return stream->Skip(stream, *size); } SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; RINOK(stream->Read(stream, buf, &processed)); if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); size -= processed; } return SZ_OK; } SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) { return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) { SRes res = SZ_OK; CLookToRead *p = (CLookToRead *)pp; size_t size2 = p->size - p->pos; if (size2 == 0 && *size > 0) { p->pos = 0; size2 = LookToRead_BUF_SIZE; res = p->realStream->Read(p->realStream, p->buf, &size2); p->size = size2; } if (size2 < *size) *size = size2; *buf = p->buf + p->pos; return res; } static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) { SRes res = SZ_OK; CLookToRead *p = (CLookToRead *)pp; size_t size2 = p->size - p->pos; if (size2 == 0 && *size > 0) { p->pos = 0; if (*size > LookToRead_BUF_SIZE) *size = LookToRead_BUF_SIZE; res = p->realStream->Read(p->realStream, p->buf, size); size2 = p->size = *size; } if (size2 < *size) *size = size2; *buf = p->buf + p->pos; return res; } static SRes LookToRead_Skip(void *pp, size_t offset) { CLookToRead *p = (CLookToRead *)pp; p->pos += offset; return SZ_OK; } static SRes LookToRead_Read(void *pp, void *buf, size_t *size) { CLookToRead *p = (CLookToRead *)pp; size_t rem = p->size - p->pos; if (rem == 0) return p->realStream->Read(p->realStream, buf, size); if (rem > *size) rem = *size; memcpy(buf, p->buf + p->pos, rem); p->pos += rem; *size = rem; return SZ_OK; } static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) { CLookToRead *p = (CLookToRead *)pp; p->pos = p->size = 0; return p->realStream->Seek(p->realStream, pos, origin); } void LookToRead_CreateVTable(CLookToRead *p, int lookahead) { p->s.Look = lookahead ? LookToRead_Look_Lookahead : LookToRead_Look_Exact; p->s.Skip = LookToRead_Skip; p->s.Read = LookToRead_Read; p->s.Seek = LookToRead_Seek; } void LookToRead_Init(CLookToRead *p) { p->pos = p->size = 0; } static SRes SecToLook_Read(void *pp, void *buf, size_t *size) { CSecToLook *p = (CSecToLook *)pp; return LookInStream_LookRead(p->realStream, buf, size); } void SecToLook_CreateVTable(CSecToLook *p) { p->s.Read = SecToLook_Read; } static SRes SecToRead_Read(void *pp, void *buf, size_t *size) { CSecToRead *p = (CSecToRead *)pp; return p->realStream->Read(p->realStream, buf, size); } void SecToRead_CreateVTable(CSecToRead *p) { p->s.Read = SecToRead_Read; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zTypes.h0100777000000000000000000001255113761647206020232 0ustar00/* 7zTypes.h -- Basic types 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H #ifdef _WIN32 /* #include */ #endif #include #ifndef EXTERN_C_BEGIN #ifdef __cplusplus #define EXTERN_C_BEGIN extern "C" { #define EXTERN_C_END } #else #define EXTERN_C_BEGIN #define EXTERN_C_END #endif #endif EXTERN_C_BEGIN #define SZ_OK 0 #define SZ_ERROR_DATA 1 #define SZ_ERROR_MEM 2 #define SZ_ERROR_CRC 3 #define SZ_ERROR_UNSUPPORTED 4 #define SZ_ERROR_PARAM 5 #define SZ_ERROR_INPUT_EOF 6 #define SZ_ERROR_OUTPUT_EOF 7 #define SZ_ERROR_READ 8 #define SZ_ERROR_WRITE 9 #define SZ_ERROR_PROGRESS 10 #define SZ_ERROR_FAIL 11 #define SZ_ERROR_THREAD 12 #define SZ_ERROR_ARCHIVE 16 #define SZ_ERROR_NO_ARCHIVE 17 typedef int SRes; #ifdef _WIN32 /* typedef DWORD WRes; */ typedef unsigned WRes; #else typedef int WRes; #endif #ifndef RINOK #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } #endif typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; #ifdef _LZMA_UINT32_IS_ULONG typedef long Int32; typedef unsigned long UInt32; #else typedef int Int32; typedef unsigned int UInt32; #endif #ifdef _SZ_NO_INT_64 /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. NOTES: Some code will work incorrectly in that case! */ typedef long Int64; typedef unsigned long UInt64; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 Int64; typedef unsigned __int64 UInt64; #define UINT64_CONST(n) n #else typedef long long int Int64; typedef unsigned long long int UInt64; #define UINT64_CONST(n) n ## ULL #endif #endif #ifdef _LZMA_NO_SYSTEM_SIZE_T typedef UInt32 SizeT; #else typedef size_t SizeT; #endif typedef int Bool; #define True 1 #define False 0 #ifdef _WIN32 #define MY_STD_CALL __stdcall #else #define MY_STD_CALL #endif #ifdef _MSC_VER #if _MSC_VER >= 1300 #define MY_NO_INLINE __declspec(noinline) #else #define MY_NO_INLINE #endif #define MY_CDECL __cdecl #define MY_FAST_CALL __fastcall #else #define MY_NO_INLINE #define MY_CDECL #define MY_FAST_CALL #endif /* The following interfaces use first parameter as pointer to structure */ typedef struct { Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ } IByteIn; typedef struct { void (*Write)(void *p, Byte b); } IByteOut; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) < input(*size)) is allowed */ } ISeqInStream; /* it can return SZ_ERROR_INPUT_EOF */ SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); typedef struct { size_t (*Write)(void *p, const void *buf, size_t size); /* Returns: result - the number of actually written bytes. (result < size) means error */ } ISeqOutStream; typedef enum { SZ_SEEK_SET = 0, SZ_SEEK_CUR = 1, SZ_SEEK_END = 2 } ESzSeek; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ISeekInStream; typedef struct { SRes (*Look)(void *p, const void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ SRes (*Skip)(void *p, size_t offset); /* offset must be <= output(*size) of Look */ SRes (*Read)(void *p, void *buf, size_t *size); /* reads directly (without buffer). It's same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ILookInStream; SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); /* reads via ILookInStream::Read */ SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); #define LookToRead_BUF_SIZE (1 << 14) typedef struct { ILookInStream s; ISeekInStream *realStream; size_t pos; size_t size; Byte buf[LookToRead_BUF_SIZE]; } CLookToRead; void LookToRead_CreateVTable(CLookToRead *p, int lookahead); void LookToRead_Init(CLookToRead *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToLook; void SecToLook_CreateVTable(CSecToLook *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToRead; void SecToRead_CreateVTable(CSecToRead *p); typedef struct { SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); /* Returns: result. (result != SZ_OK) means break. Value (UInt64)(Int64)-1 for size means unknown value. */ } ICompressProgress; typedef struct { void *(*Alloc)(void *p, size_t size); void (*Free)(void *p, void *address); /* address can be 0 */ } ISzAlloc; #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Free(p, a) (p)->Free((p), a) #ifdef _WIN32 #define CHAR_PATH_SEPARATOR '\\' #define WCHAR_PATH_SEPARATOR L'\\' #define STRING_PATH_SEPARATOR "\\" #define WSTRING_PATH_SEPARATOR L"\\" #else #define CHAR_PATH_SEPARATOR '/' #define WCHAR_PATH_SEPARATOR L'/' #define STRING_PATH_SEPARATOR "/" #define WSTRING_PATH_SEPARATOR L"/" #endif EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/7zVersion.h0100777000000000000000000000053313761647206020550 0ustar00#define MY_VER_MAJOR 9 #define MY_VER_MINOR 38 #define MY_VER_BUILD 00 #define MY_VERSION "9.38 beta" // #define MY_7ZIP_VERSION "9.38" #define MY_DATE "2015-01-03" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_COPYRIGHT ": Igor Pavlov : Public domain" #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE qt-installer-framework-4.0.1/src/libs/7zip/win/C/Alloc.c0100777000000000000000000000522213761647206017667 0ustar00/* Alloc.c -- Memory allocation functions 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #ifdef _WIN32 #include #endif #include #include "Alloc.h" /* #define _SZ_ALLOC_DEBUG */ /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ #ifdef _SZ_ALLOC_DEBUG #include int g_allocCount = 0; int g_allocCountMid = 0; int g_allocCountBig = 0; #endif void *MyAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG { void *p = malloc(size); fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p); return p; } #else return malloc(size); #endif } void MyFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address); #endif free(address); } #ifdef _WIN32 void *MidAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); #endif return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); } void MidFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); #endif if (address == 0) return; VirtualFree(address, 0, MEM_RELEASE); } #ifndef MEM_LARGE_PAGES #undef _7ZIP_LARGE_PAGES #endif #ifdef _7ZIP_LARGE_PAGES SIZE_T g_LargePageSize = 0; typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); #endif void SetLargePageSize() { #ifdef _7ZIP_LARGE_PAGES SIZE_T size = 0; GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); if (largePageMinimum == 0) return; size = largePageMinimum(); if (size == 0 || (size & (size - 1)) != 0) return; g_LargePageSize = size; #endif } void *BigAlloc(size_t size) { if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); #endif #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18)) { void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); if (res != 0) return res; } #endif return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); } void BigFree(void *address) { #ifdef _SZ_ALLOC_DEBUG if (address != 0) fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); #endif if (address == 0) return; VirtualFree(address, 0, MEM_RELEASE); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Alloc.h0100777000000000000000000000115613761647206017676 0ustar00/* Alloc.h -- Memory allocation functions 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __COMMON_ALLOC_H #define __COMMON_ALLOC_H #include #ifdef __cplusplus extern "C" { #endif void *MyAlloc(size_t size); void MyFree(void *address); #ifdef _WIN32 void SetLargePageSize(); void *MidAlloc(size_t size); void MidFree(void *address); void *BigAlloc(size_t size); void BigFree(void *address); #else #define MidAlloc(size) MyAlloc(size) #define MidFree(address) MyFree(address) #define BigAlloc(size) MyAlloc(size) #define BigFree(address) MyFree(address) #endif #ifdef __cplusplus } #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Bra.c0100777000000000000000000000610013761647206017335 0ustar00/* Bra.c -- Converters for RISC code 2010-04-16 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; ip += 8; for (i = 0; i <= size; i += 4) { if (data[i + 3] == 0xEB) { UInt32 dest; UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); src <<= 2; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 2; data[i + 2] = (Byte)(dest >> 16); data[i + 1] = (Byte)(dest >> 8); data[i + 0] = (Byte)dest; } } return i; } SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; ip += 4; for (i = 0; i <= size; i += 2) { if ((data[i + 1] & 0xF8) == 0xF0 && (data[i + 3] & 0xF8) == 0xF8) { UInt32 dest; UInt32 src = (((UInt32)data[i + 1] & 0x7) << 19) | ((UInt32)data[i + 0] << 11) | (((UInt32)data[i + 3] & 0x7) << 8) | (data[i + 2]); src <<= 1; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 1; data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); data[i + 0] = (Byte)(dest >> 11); data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); data[i + 2] = (Byte)dest; i += 2; } } return i; } SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 4) return 0; size -= 4; for (i = 0; i <= size; i += 4) { if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) { UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | ((UInt32)data[i + 1] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 3] & (~3)); UInt32 dest; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); data[i + 1] = (Byte)(dest >> 16); data[i + 2] = (Byte)(dest >> 8); data[i + 3] &= 0x3; data[i + 3] |= dest; } } return i; } SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { UInt32 i; if (size < 4) return 0; size -= 4; for (i = 0; i <= size; i += 4) { if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) { UInt32 src = ((UInt32)data[i + 0] << 24) | ((UInt32)data[i + 1] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 3]); UInt32 dest; src <<= 2; if (encoding) dest = ip + i + src; else dest = src - (ip + i); dest >>= 2; dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; data[i + 0] = (Byte)(dest >> 24); data[i + 1] = (Byte)(dest >> 16); data[i + 2] = (Byte)(dest >> 8); data[i + 3] = (Byte)dest; } } return i; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Bra.h0100777000000000000000000000347613761647206017357 0ustar00/* Bra.h -- Branch converters for executables 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __BRA_H #define __BRA_H #include "7zTypes.h" EXTERN_C_BEGIN /* These functions convert relative addresses to absolute addresses in CALL instructions to increase the compression ratio. In: data - data buffer size - size of data ip - current virtual Instruction Pinter (IP) value state - state variable for x86 converter encoding - 0 (for decoding), 1 (for encoding) Out: state - state variable for x86 converter Returns: The number of processed bytes. If you call these functions with multiple calls, you must start next call with first byte after block of processed bytes. Type Endian Alignment LookAhead x86 little 1 4 ARMT little 2 2 ARM little 4 0 PPC big 4 0 SPARC big 4 0 IA64 little 16 0 size must be >= Alignment + LookAhead, if it's not last block. If (size < Alignment + LookAhead), converter returns 0. Example: UInt32 ip = 0; for () { ; size must be >= Alignment + LookAhead, if it's not last block SizeT processed = Convert(data, size, ip, 1); data += processed; size -= processed; ip += processed; } */ #define x86_Convert_Init(state) { state = 0; } SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Bra86.c0100777000000000000000000000326513761647206017524 0ustar00/* Bra86.c -- Converter for x86 code (BCJ) 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" #define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) { SizeT pos = 0; UInt32 mask = *state & 7; if (size < 5) return 0; size -= 4; ip += 5; for (;;) { Byte *p = data + pos; const Byte *limit = data + size; for (; p < limit; p++) if ((*p & 0xFE) == 0xE8) break; { SizeT d = (SizeT)(p - data - pos); pos = (SizeT)(p - data); if (p >= limit) { *state = (d > 2 ? 0 : mask >> (unsigned)d); return pos; } if (d > 2) mask = 0; else { mask >>= (unsigned)d; if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) { mask = (mask >> 1) | 4; pos++; continue; } } } if (Test86MSByte(p[4])) { UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); UInt32 cur = ip + (UInt32)pos; pos += 5; if (encoding) v += cur; else v -= cur; if (mask != 0) { unsigned sh = (mask & 6) << 2; if (Test86MSByte((Byte)(v >> sh))) { v ^= (((UInt32)0x100 << sh) - 1); if (encoding) v += cur; else v -= cur; } mask = 0; } p[1] = (Byte)v; p[2] = (Byte)(v >> 8); p[3] = (Byte)(v >> 16); p[4] = (Byte)(0 - ((v >> 24) & 1)); } else { mask = (mask >> 1) | 4; pos++; } } } qt-installer-framework-4.0.1/src/libs/7zip/win/C/BraIA64.c0100777000000000000000000000330213761647206017722 0ustar00/* BraIA64.c -- Converter for IA-64 code 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" static const Byte kBranchTable[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { SizeT i; if (size < 16) return 0; size -= 16; for (i = 0; i <= size; i += 16) { UInt32 instrTemplate = data[i] & 0x1F; UInt32 mask = kBranchTable[instrTemplate]; UInt32 bitPos = 5; int slot; for (slot = 0; slot < 3; slot++, bitPos += 41) { UInt32 bytePos, bitRes; UInt64 instruction, instNorm; int j; if (((mask >> slot) & 1) == 0) continue; bytePos = (bitPos >> 3); bitRes = bitPos & 0x7; instruction = 0; for (j = 0; j < 6; j++) instruction += (UInt64)data[i + j + bytePos] << (8 * j); instNorm = instruction >> bitRes; if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) { UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); UInt32 dest; src |= ((UInt32)(instNorm >> 36) & 1) << 20; src <<= 4; if (encoding) dest = ip + (UInt32)i + src; else dest = src - (ip + (UInt32)i); dest >>= 4; instNorm &= ~((UInt64)(0x8FFFFF) << 13); instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); instruction &= (1 << bitRes) - 1; instruction |= (instNorm << bitRes); for (j = 0; j < 6; j++) data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); } } } return i; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/C.pri0100777000000000000000000000256013761647206017371 0ustar00HEADERS += $$7ZIP_BASE/C/7zCrc.h \ $$7ZIP_BASE/C/7zTypes.h \ $$7ZIP_BASE/C/7zVersion.h \ $$7ZIP_BASE/C/Alloc.h \ $$7ZIP_BASE/C/Bra.h \ $$7ZIP_BASE/C/Compiler.h \ $$7ZIP_BASE/C/CpuArch.h \ $$7ZIP_BASE/C/Delta.h \ $$7ZIP_BASE/C/LzFind.h \ $$7ZIP_BASE/C/LzFindMt.h \ $$7ZIP_BASE/C/LzHash.h \ $$7ZIP_BASE/C/Lzma2Dec.h \ $$7ZIP_BASE/C/Lzma2Enc.h \ $$7ZIP_BASE/C/LzmaDec.h \ $$7ZIP_BASE/C/LzmaEnc.h \ $$7ZIP_BASE/C/MtCoder.h \ $$7ZIP_BASE/C/Precomp.h \ $$7ZIP_BASE/C/RotateDefs.h \ $$7ZIP_BASE/C/Sha256.h \ $$7ZIP_BASE/C/Threads.h \ $$7ZIP_BASE/C/Xz.h \ $$7ZIP_BASE/C/XzCrc64.h \ $$7ZIP_BASE/C/XzEnc.h SOURCES += $$7ZIP_BASE/C/7zCrc.c \ $$7ZIP_BASE/C/7zCrcOpt.c \ $$7ZIP_BASE/C/7zStream.c \ $$7ZIP_BASE/C/Alloc.c \ $$7ZIP_BASE/C/Bra.c \ $$7ZIP_BASE/C/Bra86.c \ $$7ZIP_BASE/C/BraIA64.c \ $$7ZIP_BASE/C/CpuArch.c \ $$7ZIP_BASE/C/Delta.c \ $$7ZIP_BASE/C/LzFind.c \ $$7ZIP_BASE/C/LzFindMt.c \ $$7ZIP_BASE/C/Lzma2Dec.c \ $$7ZIP_BASE/C/Lzma2Enc.c \ $$7ZIP_BASE/C/LzmaDec.c \ $$7ZIP_BASE/C/LzmaEnc.c \ $$7ZIP_BASE/C/MtCoder.c \ $$7ZIP_BASE/C/Sha256.c \ $$7ZIP_BASE/C/Threads.c \ $$7ZIP_BASE/C/Xz.c \ $$7ZIP_BASE/C/XzCrc64.c \ $$7ZIP_BASE/C/XzCrc64Opt.c \ $$7ZIP_BASE/C/XzDec.c \ $$7ZIP_BASE/C/XzEnc.c \ $$7ZIP_BASE/C/XzIn.c qt-installer-framework-4.0.1/src/libs/7zip/win/C/Compiler.h0100777000000000000000000000175313761647206020421 0ustar00/* Compiler.h -- Compiler ypes 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_COMPILER_H #define __7Z_COMPILER_H #ifdef _MSC_VER #ifdef UNDER_CE #define RPC_NO_WINDOWS_H /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int #endif #if _MSC_VER >= 1300 #pragma warning(disable : 4996) // This function or variable may be unsafe #else #pragma warning(disable : 4511) // copy constructor could not be generated #pragma warning(disable : 4512) // assignment operator could not be generated #pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4710) // not inlined #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information #endif #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/CpuArch.c0100777000000000000000000000756713761647206020200 0ustar00/* CpuArch.c -- CPU specific code 2012-05-29: Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" #ifdef MY_CPU_X86_OR_AMD64 #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) #define USE_ASM #endif #if !defined(USE_ASM) && _MSC_VER >= 1500 #include #endif #if defined(USE_ASM) && !defined(MY_CPU_AMD64) static UInt32 CheckFlag(UInt32 flag) { #ifdef _MSC_VER __asm pushfd; __asm pop EAX; __asm mov EDX, EAX; __asm xor EAX, flag; __asm push EAX; __asm popfd; __asm pushfd; __asm pop EAX; __asm xor EAX, EDX; __asm push EDX; __asm popfd; __asm and flag, EAX; #else __asm__ __volatile__ ( "pushf\n\t" "pop %%EAX\n\t" "movl %%EAX,%%EDX\n\t" "xorl %0,%%EAX\n\t" "push %%EAX\n\t" "popf\n\t" "pushf\n\t" "pop %%EAX\n\t" "xorl %%EDX,%%EAX\n\t" "push %%EDX\n\t" "popf\n\t" "andl %%EAX, %0\n\t": "=c" (flag) : "c" (flag)); #endif return flag; } #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; #else #define CHECK_CPUID_IS_SUPPORTED #endif static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) { #ifdef USE_ASM #ifdef _MSC_VER UInt32 a2, b2, c2, d2; __asm xor EBX, EBX; __asm xor ECX, ECX; __asm xor EDX, EDX; __asm mov EAX, function; __asm cpuid; __asm mov a2, EAX; __asm mov b2, EBX; __asm mov c2, ECX; __asm mov d2, EDX; *a = a2; *b = b2; *c = c2; *d = d2; #else __asm__ __volatile__ ( #if defined(MY_CPU_X86) && defined(__PIC__) "mov %%ebx, %%edi;" "cpuid;" "xchgl %%ebx, %%edi;" : "=a" (*a) , "=D" (*b) , #else "cpuid" : "=a" (*a) , "=b" (*b) , #endif "=c" (*c) , "=d" (*d) : "0" (function)) ; #endif #else int CPUInfo[4]; __cpuid(CPUInfo, function); *a = CPUInfo[0]; *b = CPUInfo[1]; *c = CPUInfo[2]; *d = CPUInfo[3]; #endif } Bool x86cpuid_CheckAndRead(Cx86cpuid *p) { CHECK_CPUID_IS_SUPPORTED MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); return True; } static UInt32 kVendors[][3] = { { 0x756E6547, 0x49656E69, 0x6C65746E}, { 0x68747541, 0x69746E65, 0x444D4163}, { 0x746E6543, 0x48727561, 0x736C7561} }; int x86cpuid_GetFirm(const Cx86cpuid *p) { unsigned i; for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) { const UInt32 *v = kVendors[i]; if (v[0] == p->vendor[0] && v[1] == p->vendor[1] && v[2] == p->vendor[2]) return (int)i; } return -1; } Bool CPU_Is_InOrder() { Cx86cpuid p; int firm; UInt32 family, model; if (!x86cpuid_CheckAndRead(&p)) return True; family = x86cpuid_GetFamily(&p); model = x86cpuid_GetModel(&p); firm = x86cpuid_GetFirm(&p); switch (firm) { case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( /* Atom CPU */ model == 0x100C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ || model == 0x2006 /* 45 nm, Z6xx */ || model == 0x2007 /* 32 nm, Z2460 */ || model == 0x3005 /* 32 nm, Z2760 */ || model == 0x3006 /* 32 nm, N2xxx, D2xxx */ ))); case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); } return True; } #if !defined(MY_CPU_AMD64) && defined(_WIN32) #include static Bool CPU_Sys_Is_SSE_Supported() { OSVERSIONINFO vi; vi.dwOSVersionInfoSize = sizeof(vi); if (!GetVersionEx(&vi)) return False; return (vi.dwMajorVersion >= 5); } #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; #else #define CHECK_SYS_SSE_SUPPORT #endif Bool CPU_Is_Aes_Supported() { Cx86cpuid p; CHECK_SYS_SSE_SUPPORT if (!x86cpuid_CheckAndRead(&p)) return False; return (p.c >> 25) & 1; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/CpuArch.h0100777000000000000000000000752013761647206020172 0ustar00/* CpuArch.h -- CPU specific code 2013-11-12: Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H #include "7zTypes.h" EXTERN_C_BEGIN /* MY_CPU_LE means that CPU is LITTLE ENDIAN. If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. */ #if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) #define MY_CPU_AMD64 #endif #if defined(MY_CPU_AMD64) || defined(_M_IA64) #define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__) #define MY_CPU_X86 #endif #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) #define MY_CPU_X86_OR_AMD64 #endif #if defined(MY_CPU_X86) || defined(_M_ARM) #define MY_CPU_32BIT #endif #if defined(_WIN32) && defined(_M_ARM) #define MY_CPU_ARM_LE #endif #if defined(_WIN32) && defined(_M_IA64) #define MY_CPU_IA64_LE #endif #if defined(MY_CPU_X86_OR_AMD64) #define MY_CPU_LE_UNALIGN #endif #if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) #define MY_CPU_LE #endif #if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) #define MY_CPU_BE #endif #if defined(MY_CPU_LE) && defined(MY_CPU_BE) Stop_Compiling_Bad_Endian #endif #ifdef MY_CPU_LE_UNALIGN #define GetUi16(p) (*(const UInt16 *)(const void *)(p)) #define GetUi32(p) (*(const UInt32 *)(const void *)(p)) #define GetUi64(p) (*(const UInt64 *)(const void *)(p)) #define SetUi16(p, d) *(UInt16 *)(p) = (d); #define SetUi32(p, d) *(UInt32 *)(p) = (d); #define SetUi64(p, d) *(UInt64 *)(p) = (d); #else #define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) #define GetUi32(p) ( \ ((const Byte *)(p))[0] | \ ((UInt32)((const Byte *)(p))[1] << 8) | \ ((UInt32)((const Byte *)(p))[2] << 16) | \ ((UInt32)((const Byte *)(p))[3] << 24)) #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) #define SetUi16(p, d) { UInt32 _x_ = (d); \ ((Byte *)(p))[0] = (Byte)_x_; \ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } #define SetUi32(p, d) { UInt32 _x_ = (d); \ ((Byte *)(p))[0] = (Byte)_x_; \ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } #define SetUi64(p, d) { UInt64 _x64_ = (d); \ SetUi32(p, (UInt32)_x64_); \ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } #endif #if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) #include #pragma intrinsic(_byteswap_ulong) #pragma intrinsic(_byteswap_uint64) #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) #else #define GetBe32(p) ( \ ((UInt32)((const Byte *)(p))[0] << 24) | \ ((UInt32)((const Byte *)(p))[1] << 16) | \ ((UInt32)((const Byte *)(p))[2] << 8) | \ ((const Byte *)(p))[3] ) #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) #endif #define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])) #ifdef MY_CPU_X86_OR_AMD64 typedef struct { UInt32 maxFunc; UInt32 vendor[3]; UInt32 ver; UInt32 b; UInt32 c; UInt32 d; } Cx86cpuid; enum { CPU_FIRM_INTEL, CPU_FIRM_AMD, CPU_FIRM_VIA }; Bool x86cpuid_CheckAndRead(Cx86cpuid *p); int x86cpuid_GetFirm(const Cx86cpuid *p); #define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) #define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) #define x86cpuid_GetStepping(p) ((p)->ver & 0xF) Bool CPU_Is_InOrder(); Bool CPU_Is_Aes_Supported(); #endif EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Delta.c0100777000000000000000000000237113761647206017670 0ustar00/* Delta.c -- Delta converter 2009-05-26 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Delta.h" void Delta_Init(Byte *state) { unsigned i; for (i = 0; i < DELTA_STATE_SIZE; i++) state[i] = 0; } static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) { unsigned i; for (i = 0; i < size; i++) dest[i] = src[i]; } void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) { Byte buf[DELTA_STATE_SIZE]; unsigned j = 0; MyMemCpy(buf, state, delta); { SizeT i; for (i = 0; i < size;) { for (j = 0; j < delta && i < size; i++, j++) { Byte b = data[i]; data[i] = (Byte)(b - buf[j]); buf[j] = b; } } } if (j == delta) j = 0; MyMemCpy(state, buf + j, delta - j); MyMemCpy(state + delta - j, buf, j); } void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) { Byte buf[DELTA_STATE_SIZE]; unsigned j = 0; MyMemCpy(buf, state, delta); { SizeT i; for (i = 0; i < size;) { for (j = 0; j < delta && i < size; i++, j++) { buf[j] = data[i] = (Byte)(buf[j] + data[i]); } } } if (j == delta) j = 0; MyMemCpy(state, buf + j, delta - j); MyMemCpy(state + delta - j, buf, j); } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Delta.h0100777000000000000000000000057013761647206017674 0ustar00/* Delta.h -- Delta converter 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __DELTA_H #define __DELTA_H #include "7zTypes.h" EXTERN_C_BEGIN #define DELTA_STATE_SIZE 256 void Delta_Init(Byte *state); void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzFind.c0100777000000000000000000004642213761647206020032 0ustar00/* LzFind.c -- Match finder for LZ algorithms 2009-04-22 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "LzFind.h" #include "LzHash.h" #define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ #define kNormalizeMask (~(kNormalizeStepMin - 1)) #define kMaxHistorySize ((UInt32)3 << 30) #define kStartMaxLen 3 static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) { if (!p->directInput) { alloc->Free(alloc, p->bufferBase); p->bufferBase = 0; } } /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) { UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; if (p->directInput) { p->blockSize = blockSize; return 1; } if (p->bufferBase == 0 || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } return (p->bufferBase != 0); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) { p->posLimit -= subValue; p->pos -= subValue; p->streamPos -= subValue; } static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; if (p->directInput) { UInt32 curSize = 0xFFFFFFFF - p->streamPos; if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize; p->streamPos += curSize; if (p->directInputRem == 0) p->streamEndWasReached = 1; return; } for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return; if (size == 0) { p->streamEndWasReached = 1; return; } p->streamPos += (UInt32)size; if (p->streamPos - p->pos > p->keepSizeAfter) return; } } void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, p->buffer - p->keepSizeBefore, (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); p->buffer = p->bufferBase + p->keepSizeBefore; } int MatchFinder_NeedMove(CMatchFinder *p) { if (p->directInput) return 0; /* if (p->streamEndWasReached) return 0; */ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); } void MatchFinder_ReadIfRequired(CMatchFinder *p) { if (p->streamEndWasReached) return; if (p->keepSizeAfter >= p->streamPos - p->pos) MatchFinder_ReadBlock(p); } static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) { if (MatchFinder_NeedMove(p)) MatchFinder_MoveBlock(p); MatchFinder_ReadBlock(p); } static void MatchFinder_SetDefaultSettings(CMatchFinder *p) { p->cutValue = 32; p->btMode = 1; p->numHashBytes = 4; p->bigHash = 0; } #define kCrcPoly 0xEDB88320 void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; p->bufferBase = 0; p->directInput = 0; p->hash = 0; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; int j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r; } } static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); p->hash = 0; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) { MatchFinder_FreeThisClassMemory(p, alloc); LzInWindow_Free(p, alloc); } static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) return 0; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); } int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) { UInt32 sizeReserv; if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } sizeReserv = historySize >> 1; if (historySize > ((UInt32)2 << 30)) sizeReserv = historySize >> 2; sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1; UInt32 hs; p->matchMaxLen = matchMaxLen; { p->fixedHashSize = 0; if (p->numHashBytes == 2) hs = (1 << 16) - 1; else { hs = historySize - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); hs |= (hs >> 8); hs >>= 1; hs |= 0xFFFF; /* don't change it! It's required for Deflate */ if (hs > (1 << 24)) { if (p->numHashBytes == 3) hs = (1 << 24) - 1; else hs >>= 1; } } p->hashMask = hs; hs++; if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; hs += p->fixedHashSize; } { UInt32 prevSize = p->hashSizeSum + p->numSons; UInt32 newSize; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); newSize = p->hashSizeSum + p->numSons; if (p->hash != 0 && prevSize == newSize) return 1; MatchFinder_FreeThisClassMemory(p, alloc); p->hash = AllocRefs(newSize, alloc); if (p->hash != 0) { p->son = p->hash + p->hashSizeSum; return 1; } } } MatchFinder_Free(p, alloc); return 0; } static void MatchFinder_SetLimits(CMatchFinder *p) { UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; if (limit2 <= p->keepSizeAfter) { if (limit2 > 0) limit2 = 1; } else limit2 -= p->keepSizeAfter; if (limit2 < limit) limit = limit2; { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen) lenLimit = p->matchMaxLen; p->lenLimit = lenLimit; } p->posLimit = p->pos + limit; } void MatchFinder_Init(CMatchFinder *p) { UInt32 i; for (i = 0; i < p->hashSizeSum; i++) p->hash[i] = kEmptyHashValue; p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; MatchFinder_ReadBlock(p); MatchFinder_SetLimits(p); } static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) { UInt32 i; for (i = 0; i < numItems; i++) { UInt32 value = items[i]; if (value <= subValue) value = kEmptyHashValue; else value -= subValue; items[i] = value; } } static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); MatchFinder_ReduceOffsets(p, subValue); } static void MatchFinder_CheckLimits(CMatchFinder *p) { if (p->pos == kMaxValForNormalize) MatchFinder_Normalize(p); if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) MatchFinder_CheckAndMoveAndRead(p); if (p->cyclicBufferPos == p->cyclicBufferSize) p->cyclicBufferPos = 0; MatchFinder_SetLimits(p); } static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { son[_cyclicBufferPos] = curMatch; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) return distances; { const Byte *pb = cur - delta; curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; if (pb[maxLen] == cur[maxLen] && *pb == *cur) { UInt32 len = 0; while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) return distances; } } } } } UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return distances; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return distances; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { while (++len != lenLimit) if (pb[len] != cur[len]) break; { if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } #define MOVE_POS \ ++p->cyclicBufferPos; \ p->buffer++; \ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); #define MOVE_POS_RET MOVE_POS return offset; static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue #define GET_MATCHES_FOOTER(offset, maxLen) \ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ distances + offset, maxLen) - distances); MOVE_POS_RET; #define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) } UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, delta2, maxLen, offset; GET_MATCHES_HEADER(3) HASH3_CALC; delta2 = p->pos - p->hash[hash2Value]; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; maxLen = 2; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[0] = maxLen; distances[1] = delta2 - 1; offset = 2; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { p->son[p->cyclicBufferPos] = curMatch; MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) - (distances)); MOVE_POS_RET } UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances, 2) - (distances)); MOVE_POS_RET } static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value; SKIP_HEADER(3) HASH3_CALC; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->pos; p->hash[kFix4HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; } else if (p->numHashBytes == 2) { vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; } else if (p->numHashBytes == 3) { vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } else { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } } qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzFind.h0100777000000000000000000000626513761647206020040 0ustar00/* LzFind.h -- Match finder for LZ algorithms 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H #include "7zTypes.h" EXTERN_C_BEGIN typedef UInt32 CLzRef; typedef struct _CMatchFinder { Byte *buffer; UInt32 pos; UInt32 posLimit; UInt32 streamPos; UInt32 lenLimit; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ UInt32 matchMaxLen; CLzRef *hash; CLzRef *son; UInt32 hashMask; UInt32 cutValue; Byte *bufferBase; ISeqInStream *stream; int streamEndWasReached; UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; int directInput; size_t directInputRem; int btMode; int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; UInt32 numSons; SRes result; UInt32 crc[256]; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) #define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p); void MatchFinder_ReadIfRequired(CMatchFinder *p); void MatchFinder_Construct(CMatchFinder *p); /* Conditions: historySize <= 3 GB keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB */ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *distances, UInt32 maxLen); /* Conditions: Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. Mf_GetPointerToCurrentPos_Func's result must be used only before any other function */ typedef void (*Mf_Init_Func)(void *object); typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); typedef void (*Mf_Skip_Func)(void *object, UInt32); typedef struct _IMatchFinder { Mf_Init_Func Init; Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; Mf_Skip_Func Skip; } IMatchFinder; void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); void MatchFinder_Init(CMatchFinder *p); UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzFindMt.c0100777000000000000000000005323313761647206020331 0ustar00/* LzFindMt.c -- multithreaded Match finder for LZ algorithms 2014-12-29 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "LzHash.h" #include "LzFindMt.h" void MtSync_Construct(CMtSync *p) { p->wasCreated = False; p->csWasInitialized = False; p->csWasEntered = False; Thread_Construct(&p->thread); Event_Construct(&p->canStart); Event_Construct(&p->wasStarted); Event_Construct(&p->wasStopped); Semaphore_Construct(&p->freeSemaphore); Semaphore_Construct(&p->filledSemaphore); } void MtSync_GetNextBlock(CMtSync *p) { if (p->needStart) { p->numProcessedBlocks = 1; p->needStart = False; p->stopWriting = False; p->exit = False; Event_Reset(&p->wasStarted); Event_Reset(&p->wasStopped); Event_Set(&p->canStart); Event_Wait(&p->wasStarted); } else { CriticalSection_Leave(&p->cs); p->csWasEntered = False; p->numProcessedBlocks++; Semaphore_Release1(&p->freeSemaphore); } Semaphore_Wait(&p->filledSemaphore); CriticalSection_Enter(&p->cs); p->csWasEntered = True; } /* MtSync_StopWriting must be called if Writing was started */ void MtSync_StopWriting(CMtSync *p) { UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart) return; p->stopWriting = True; if (p->csWasEntered) { CriticalSection_Leave(&p->cs); p->csWasEntered = False; } Semaphore_Release1(&p->freeSemaphore); Event_Wait(&p->wasStopped); while (myNumBlocks++ != p->numProcessedBlocks) { Semaphore_Wait(&p->filledSemaphore); Semaphore_Release1(&p->freeSemaphore); } p->needStart = True; } void MtSync_Destruct(CMtSync *p) { if (Thread_WasCreated(&p->thread)) { MtSync_StopWriting(p); p->exit = True; if (p->needStart) Event_Set(&p->canStart); Thread_Wait(&p->thread); Thread_Close(&p->thread); } if (p->csWasInitialized) { CriticalSection_Delete(&p->cs); p->csWasInitialized = False; } Event_Close(&p->canStart); Event_Close(&p->wasStarted); Event_Close(&p->wasStopped); Semaphore_Close(&p->freeSemaphore); Semaphore_Close(&p->filledSemaphore); p->wasCreated = False; } #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { if (p->wasCreated) return SZ_OK; RINOK_THREAD(CriticalSection_Init(&p->cs)); p->csWasInitialized = True; RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); p->needStart = True; RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); p->wasCreated = True; return SZ_OK; } static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); if (res != SZ_OK) MtSync_Destruct(p); return res; } void MtSync_Init(CMtSync *p) { p->needStart = True; } #define kMtMaxValForNormalize 0xFFFFFFFF #define DEF_GetHeads2(name, v, action) \ static void GetHeads ## name(const Byte *p, UInt32 pos, \ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ { action; for (; numHeads != 0; numHeads--) { \ const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; for (;;) { UInt32 numProcessedBlocks = 0; Event_Wait(&p->canStart); Event_Set(&p->wasStarted); for (;;) { if (p->exit) return; if (p->stopWriting) { p->numProcessedBlocks = numProcessedBlocks; Event_Set(&p->wasStopped); break; } { CMatchFinder *mf = mt->MatchFinder; if (MatchFinder_NeedMove(mf)) { CriticalSection_Enter(&mt->btSync.cs); CriticalSection_Enter(&mt->hashSync.cs); { const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); const Byte *afterPtr; MatchFinder_MoveBlock(mf); afterPtr = MatchFinder_GetPointerToCurrentPos(mf); mt->pointerToCurPos -= beforePtr - afterPtr; mt->buffer -= beforePtr - afterPtr; } CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs); continue; } Semaphore_Wait(&p->freeSemaphore); MatchFinder_ReadIfRequired(mf); if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) { UInt32 subValue = (mf->pos - mf->historySize - 1); MatchFinder_ReduceOffsets(mf, subValue); MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); } { UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; UInt32 num = mf->streamPos - mf->pos; heads[0] = 2; heads[1] = num; if (num >= mf->numHashBytes) { num = num - mf->numHashBytes + 1; if (num > kMtHashBlockSize - 2) num = kMtHashBlockSize - 2; mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); heads[0] += num; } mf->pos += num; mf->buffer += num; } } Semaphore_Release1(&p->filledSemaphore); } } } void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) { MtSync_GetNextBlock(&p->hashSync); p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; p->hashNumAvail = p->hashBuf[p->hashBufPos++]; } #define kEmptyHashValue 0 /* #define MFMT_GM_INLINE */ #ifdef MFMT_GM_INLINE #define NO_INLINE MY_FAST_CALL Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) { do { UInt32 *distances = _distances + 1; UInt32 curMatch = pos - *hash++; CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; UInt32 cutValue = _cutValue; UInt32 maxLen = _maxLen; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; break; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; break; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } pos++; _cyclicBufferPos++; cur++; { UInt32 num = (UInt32)(distances - _distances); *_distances = num - 1; _distances += num; limit -= num; } } while (limit > 0 && --size != 0); *posRes = pos; return limit; } #endif void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 numProcessed = 0; UInt32 curPos = 2; UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); distances[1] = p->hashNumAvail; while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit) { MatchFinderMt_GetNextBlock_Hash(p); distances[1] = numProcessed + p->hashNumAvail; if (p->hashNumAvail >= p->numHashBytes) continue; for (; p->hashNumAvail != 0; p->hashNumAvail--) distances[curPos++] = 0; break; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos; UInt32 lenLimit = p->matchMaxLen; UInt32 pos = p->pos; UInt32 cyclicBufferPos = p->cyclicBufferPos; if (lenLimit >= p->hashNumAvail) lenLimit = p->hashNumAvail; { UInt32 size2 = p->hashNumAvail - lenLimit + 1; if (size2 < size) size = size2; size2 = p->cyclicBufferSize - cyclicBufferPos; if (size2 < size) size = size2; } #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { UInt32 *startDistances = distances + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, startDistances + 1, p->numHashBytes - 1) - startDistances); *startDistances = num - 1; curPos += num; cyclicBufferPos++; pos++; p->buffer++; } #else { UInt32 posRes; curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); p->hashBufPos += posRes - pos; cyclicBufferPos += posRes - pos; p->buffer += posRes - pos; pos = posRes; } #endif numProcessed += pos - p->pos; p->hashNumAvail -= pos - p->pos; p->pos = pos; if (cyclicBufferPos == p->cyclicBufferSize) cyclicBufferPos = 0; p->cyclicBufferPos = cyclicBufferPos; } } distances[0] = curPos; } void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; if (!sync->needStart) { CriticalSection_Enter(&sync->cs); sync->csWasEntered = True; } BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) { UInt32 subValue = p->pos - p->cyclicBufferSize; MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); p->pos -= subValue; } if (!sync->needStart) { CriticalSection_Leave(&sync->cs); sync->csWasEntered = False; } } void BtThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->btSync; for (;;) { UInt32 blockIndex = 0; Event_Wait(&p->canStart); Event_Set(&p->wasStarted); for (;;) { if (p->exit) return; if (p->stopWriting) { p->numProcessedBlocks = blockIndex; MtSync_StopWriting(&mt->hashSync); Event_Set(&p->wasStopped); break; } Semaphore_Wait(&p->freeSemaphore); BtFillBlock(mt, blockIndex++); Semaphore_Release1(&p->filledSemaphore); } } } void MatchFinderMt_Construct(CMatchFinderMt *p) { p->hashBuf = 0; MtSync_Construct(&p->hashSync); MtSync_Construct(&p->btSync); } void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hashBuf); p->hashBuf = 0; } void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) { MtSync_Destruct(&p->hashSync); MtSync_Destruct(&p->btSync); MatchFinderMt_FreeMem(p, alloc); } #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; allocaDummy[0] = 0; allocaDummy[1] = allocaDummy[0]; BtThreadFunc((CMatchFinderMt *)p); return 0; } SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) { CMatchFinder *mf = p->MatchFinder; p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; if (p->hashBuf == 0) { p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); if (p->hashBuf == 0) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; } keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); keepAddBufferAfter += kMtHashBlockSize; if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) return SZ_ERROR_MEM; RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); return SZ_OK; } /* Call it after ReleaseStream / SetStream */ void MatchFinderMt_Init(CMatchFinderMt *p) { CMatchFinder *mf = p->MatchFinder; p->btBufPos = p->btBufPosLimit = 0; p->hashBufPos = p->hashBufPosLimit = 0; MatchFinder_Init(mf); p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; p->lzPos = p->historySize + 1; p->hash = mf->hash; p->fixedHashSize = mf->fixedHashSize; p->crc = mf->crc; p->son = mf->son; p->matchMaxLen = mf->matchMaxLen; p->numHashBytes = mf->numHashBytes; p->pos = mf->pos; p->buffer = mf->buffer; p->cyclicBufferPos = mf->cyclicBufferPos; p->cyclicBufferSize = mf->cyclicBufferSize; p->cutValue = mf->cutValue; } /* ReleaseStream is required to finish multithreading */ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) { MtSync_StopWriting(&p->btSync); /* p->MatchFinder->ReleaseStream(); */ } void MatchFinderMt_Normalize(CMatchFinderMt *p) { MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); p->lzPos = p->historySize + 1; } void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { UInt32 blockIndex; MtSync_GetNextBlock(&p->btSync); blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; p->btBufPosLimit += p->btBuf[p->btBufPos++]; p->btNumAvailBytes = p->btBuf[p->btBufPos++]; if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) MatchFinderMt_Normalize(p); } const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { GET_NEXT_BLOCK_IF_REQUIRED; return p->btNumAvailBytes; } Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) { return p->pointerToCurPos[index]; } UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, curMatch2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH2_CALC curMatch2 = hash[hash2Value]; hash[hash2Value] = lzPos; if (curMatch2 >= matchMinPos) if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { *distances++ = 2; *distances++ = lzPos - curMatch2 - 1; } return distances; } UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, hash3Value, curMatch2, curMatch3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH3_CALC curMatch2 = hash[ hash2Value]; curMatch3 = hash[kFix3HashSize + hash3Value]; hash[ hash2Value] = hash[kFix3HashSize + hash3Value] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { distances[0] = 3; return distances + 2; } distances[0] = 2; distances += 2; } if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { *distances++ = 3; *distances++ = lzPos - curMatch3 - 1; } return distances; } /* UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH4_CALC curMatch2 = hash[ hash2Value]; curMatch3 = hash[kFix3HashSize + hash3Value]; curMatch4 = hash[kFix4HashSize + hash4Value]; hash[ hash2Value] = hash[kFix3HashSize + hash3Value] = hash[kFix4HashSize + hash4Value] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; return distances + 2; } distances[0] = 2; distances += 2; } if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch3 - 1; if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) { distances[0] = 4; return distances + 2; } distances[0] = 3; distances += 2; } if (curMatch4 >= matchMinPos) if ( cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] ) { *distances++ = 4; *distances++ = lzPos - curMatch4 - 1; } return distances; } */ #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; p->btBufPos += 1 + len; p->btNumAvailBytes--; { UInt32 i; for (i = 0; i < len; i += 2) { *distances++ = *btBuf++; *distances++ = *btBuf++; } } INCREASE_LZ_POS return len; } UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; p->btBufPos += 1 + len; if (len == 0) { if (p->btNumAvailBytes-- >= 4) len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); } else { /* Condition: there are matches in btBuf with length < p->numHashBytes */ UInt32 *distances2; p->btNumAvailBytes--; distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); do { *distances2++ = *btBuf++; *distances2++ = *btBuf++; } while ((len -= 2) != 0); len = (UInt32)(distances2 - (distances)); } INCREASE_LZ_POS return len; } #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER2_MT { p->btNumAvailBytes--; SKIP_FOOTER_MT } void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(2) UInt32 hash2Value; MT_HASH2_CALC hash[hash2Value] = p->lzPos; SKIP_FOOTER_MT } void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(3) UInt32 hash2Value, hash3Value; MT_HASH3_CALC hash[kFix3HashSize + hash3Value] = hash[ hash2Value] = p->lzPos; SKIP_FOOTER_MT } /* void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) UInt32 hash2Value, hash3Value, hash4Value; MT_HASH4_CALC hash[kFix4HashSize + hash4Value] = hash[kFix3HashSize + hash3Value] = hash[ hash2Value] = p->lzPos; SKIP_FOOTER_MT } */ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; switch(p->MatchFinder->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2; p->MixMatchesFunc = (Mf_Mix_Matches)0; vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; break; case 3: p->GetHeadsFunc = GetHeads3; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; break; default: /* case 4: */ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; /* p->GetHeadsFunc = GetHeads4; */ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break; /* default: p->GetHeadsFunc = GetHeads5; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; break; */ } } qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzFindMt.h0100777000000000000000000000453613761647206020340 0ustar00/* LzFindMt.h -- multithreaded Match finder for LZ algorithms 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_MT_H #define __LZ_FIND_MT_H #include "LzFind.h" #include "Threads.h" EXTERN_C_BEGIN #define kMtHashBlockSize (1 << 13) #define kMtHashNumBlocks (1 << 3) #define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) #define kMtBtBlockSize (1 << 14) #define kMtBtNumBlocks (1 << 6) #define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) typedef struct _CMtSync { Bool wasCreated; Bool needStart; Bool exit; Bool stopWriting; CThread thread; CAutoResetEvent canStart; CAutoResetEvent wasStarted; CAutoResetEvent wasStopped; CSemaphore freeSemaphore; CSemaphore filledSemaphore; Bool csWasInitialized; Bool csWasEntered; CCriticalSection cs; UInt32 numProcessedBlocks; } CMtSync; typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); /* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ #define kMtCacheLineDummy 128 typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); typedef struct _CMatchFinderMt { /* LZ */ const Byte *pointerToCurPos; UInt32 *btBuf; UInt32 btBufPos; UInt32 btBufPosLimit; UInt32 lzPos; UInt32 btNumAvailBytes; UInt32 *hash; UInt32 fixedHashSize; UInt32 historySize; const UInt32 *crc; Mf_Mix_Matches MixMatchesFunc; /* LZ + BT */ CMtSync btSync; Byte btDummy[kMtCacheLineDummy]; /* BT */ UInt32 *hashBuf; UInt32 hashBufPos; UInt32 hashBufPosLimit; UInt32 hashNumAvail; CLzRef *son; UInt32 matchMaxLen; UInt32 numHashBytes; UInt32 pos; Byte *buffer; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be historySize + 1 */ UInt32 cutValue; /* BT + Hash */ CMtSync hashSync; /* Byte hashDummy[kMtCacheLineDummy]; */ /* Hash */ Mf_GetHeads GetHeadsFunc; CMatchFinder *MatchFinder; } CMatchFinderMt; void MatchFinderMt_Construct(CMatchFinderMt *p); void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc); SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzHash.h0100777000000000000000000000365413761647206020042 0ustar00/* LzHash.h -- HASH functions for LZ algorithms 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H #define kHash2Size (1 << 10) #define kHash3Size (1 << 16) #define kHash4Size (1 << 20) #define kFix3HashSize (kHash2Size) #define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) #define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ hash4Value &= (kHash4Size - 1); } /* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ #define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Lzma2Dec.c0100777000000000000000000002306713761647206020245 0ustar00/* Lzma2Dec.c -- LZMA2 Decoder 2010-12-15 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */ #include "Precomp.h" #ifdef SHOW_DEBUG_INFO #include #endif #include #include "Lzma2Dec.h" /* 00000000 - EOS 00000001 U U - Uncompressed Reset Dic 00000010 U U - Uncompressed No Reset 100uuuuu U U P P - LZMA no reset 101uuuuu U U P P - LZMA reset state 110uuuuu U U P P S - LZMA reset state + new prop 111uuuuu U U P P S - LZMA reset state + new prop + reset dic u, U - Unpack Size P - Pack Size S - Props */ #define LZMA2_CONTROL_LZMA (1 << 7) #define LZMA2_CONTROL_COPY_NO_RESET 2 #define LZMA2_CONTROL_COPY_RESET_DIC 1 #define LZMA2_CONTROL_EOF 0 #define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) #define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) #define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) #define LZMA2_LCLP_MAX 4 #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) #ifdef SHOW_DEBUG_INFO #define PRF(x) x #else #define PRF(x) #endif typedef enum { LZMA2_STATE_CONTROL, LZMA2_STATE_UNPACK0, LZMA2_STATE_UNPACK1, LZMA2_STATE_PACK0, LZMA2_STATE_PACK1, LZMA2_STATE_PROP, LZMA2_STATE_DATA, LZMA2_STATE_DATA_CONT, LZMA2_STATE_FINISHED, LZMA2_STATE_ERROR } ELzma2State; static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) { UInt32 dicSize; if (prop > 40) return SZ_ERROR_UNSUPPORTED; dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); props[0] = (Byte)LZMA2_LCLP_MAX; props[1] = (Byte)(dicSize); props[2] = (Byte)(dicSize >> 8); props[3] = (Byte)(dicSize >> 16); props[4] = (Byte)(dicSize >> 24); return SZ_OK; } SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) { Byte props[LZMA_PROPS_SIZE]; RINOK(Lzma2Dec_GetOldProps(prop, props)); return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) { Byte props[LZMA_PROPS_SIZE]; RINOK(Lzma2Dec_GetOldProps(prop, props)); return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } void Lzma2Dec_Init(CLzma2Dec *p) { p->state = LZMA2_STATE_CONTROL; p->needInitDic = True; p->needInitState = True; p->needInitProp = True; LzmaDec_Init(&p->decoder); } static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { switch(p->state) { case LZMA2_STATE_CONTROL: p->control = b; PRF(printf("\n %4X ", p->decoder.dicPos)); PRF(printf(" %2X", b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if ((p->control & 0x7F) > 2) return LZMA2_STATE_ERROR; p->unpackSize = 0; } else p->unpackSize = (UInt32)(p->control & 0x1F) << 16; return LZMA2_STATE_UNPACK0; case LZMA2_STATE_UNPACK0: p->unpackSize |= (UInt32)b << 8; return LZMA2_STATE_UNPACK1; case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; PRF(printf(" %8d", p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: p->packSize = (UInt32)b << 8; return LZMA2_STATE_PACK1; case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; PRF(printf(" %8d", p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { int lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; b /= 9; p->decoder.prop.pb = b / 5; lp = b % 5; if (lc + lp > LZMA2_LCLP_MAX) return LZMA2_STATE_ERROR; p->decoder.prop.lc = lc; p->decoder.prop.lp = lp; p->needInitProp = False; return LZMA2_STATE_DATA; } } return LZMA2_STATE_ERROR; } static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) { memcpy(p->dic + p->dicPos, src, size); p->dicPos += size; if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) p->checkDicSize = p->prop.dicSize; p->processedPos += (UInt32)size; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState); SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); continue; } { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen; ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; if (p->unpackSize <= destSizeCur) { destSizeCur = (SizeT)p->unpackSize; curFinishMode = LZMA_FINISH_END; } if (LZMA2_IS_UNCOMPRESSED_STATE(p)) { if (*srcLen == inSize) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->state == LZMA2_STATE_DATA) { Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) return SZ_ERROR_DATA; p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); } if (srcSizeCur > destSizeCur) srcSizeCur = destSizeCur; if (srcSizeCur == 0) return SZ_ERROR_DATA; LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); src += srcSizeCur; *srcLen += srcSizeCur; p->unpackSize -= (UInt32)srcSizeCur; p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; } else { SizeT outSizeProcessed; SRes res; if (p->state == LZMA2_STATE_DATA) { int mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); Bool initState = (mode > 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) return SZ_ERROR_DATA; LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize; res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); src += srcSizeCur; *srcLen += srcSizeCur; p->packSize -= (UInt32)srcSizeCur; outSizeProcessed = p->decoder.dicPos - dicPos; p->unpackSize -= (UInt32)outSizeProcessed; RINOK(res); if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) return res; if (srcSizeCur == 0 && outSizeProcessed == 0) { if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || p->unpackSize != 0 || p->packSize != 0) return SZ_ERROR_DATA; p->state = LZMA2_STATE_CONTROL; } if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; } SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen, inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT srcSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->decoder.dicPos == p->decoder.dicBufSize) p->decoder.dicPos = 0; dicPos = p->decoder.dicPos; if (outSize > p->decoder.dicBufSize - dicPos) { outSizeCur = p->decoder.dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); src += srcSizeCur; inSize -= srcSizeCur; *srcLen += srcSizeCur; outSizeCur = p->decoder.dicPos - dicPos; memcpy(dest, p->decoder.dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzma2Dec p; SRes res; SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; Lzma2Dec_Construct(&p); RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); p.decoder.dic = dest; p.decoder.dicBufSize = outSize; Lzma2Dec_Init(&p); *srcLen = inSize; res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); *destLen = p.decoder.dicPos; if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; Lzma2Dec_FreeProbs(&p, alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Lzma2Dec.h0100777000000000000000000000416313761647206020246 0ustar00/* Lzma2Dec.h -- LZMA2 Decoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA2_DEC_H #define __LZMA2_DEC_H #include "LzmaDec.h" EXTERN_C_BEGIN /* ---------- State Interface ---------- */ typedef struct { CLzmaDec decoder; UInt32 packSize; UInt32 unpackSize; int state; Byte control; Bool needInitDic; Bool needInitState; Bool needInitProp; } CLzma2Dec; #define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) #define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); #define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); void Lzma2Dec_Init(CLzma2Dec *p); /* finishMode: It has meaning only if the decoding reaches output limit (*destLen or dicLimit). LZMA_FINISH_ANY - use smallest number of input bytes LZMA_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT SZ_ERROR_DATA - Data error */ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - use smallest number of input bytes LZMA_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Lzma2Enc.c0100777000000000000000000002747513761647206020266 0ustar00/* Lzma2Enc.c -- LZMA2 Encoder 2012-06-19 : Igor Pavlov : Public domain */ #include "Precomp.h" /* #include */ #include /* #define _7ZIP_ST */ #include "Lzma2Enc.h" #ifndef _7ZIP_ST #include "MtCoder.h" #else #define NUM_MT_CODER_THREADS_MAX 1 #endif #define LZMA2_CONTROL_LZMA (1 << 7) #define LZMA2_CONTROL_COPY_NO_RESET 2 #define LZMA2_CONTROL_COPY_RESET_DIC 1 #define LZMA2_CONTROL_EOF 0 #define LZMA2_LCLP_MAX 4 #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) #define LZMA2_PACK_SIZE_MAX (1 << 16) #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX #define LZMA2_UNPACK_SIZE_MAX (1 << 21) #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX #define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) #define PRF(x) /* x */ /* ---------- CLzma2EncInt ---------- */ typedef struct { CLzmaEncHandle enc; UInt64 srcPos; Byte props; Bool needInitState; Bool needInitProp; } CLzma2EncInt; static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props) { Byte propsEncoded[LZMA_PROPS_SIZE]; SizeT propsSize = LZMA_PROPS_SIZE; RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); p->srcPos = 0; p->props = propsEncoded[0]; p->needInitState = True; p->needInitProp = True; return SZ_OK; } SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); void LzmaEnc_Finish(CLzmaEncHandle pp); void LzmaEnc_SaveState(CLzmaEncHandle pp); void LzmaEnc_RestoreState(CLzmaEncHandle pp); static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, size_t *packSizeRes, ISeqOutStream *outStream) { size_t packSizeLimit = *packSizeRes; size_t packSize = packSizeLimit; UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); Bool useCopyBlock; SRes res; *packSizeRes = 0; if (packSize < lzHeaderSize) return SZ_ERROR_OUTPUT_EOF; packSize -= lzHeaderSize; LzmaEnc_SaveState(p->enc); res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); if (unpackSize == 0) return res; if (res == SZ_OK) useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); else { if (res != SZ_ERROR_OUTPUT_EOF) return res; res = SZ_OK; useCopyBlock = True; } if (useCopyBlock) { size_t destPos = 0; PRF(printf("################# COPY ")); while (unpackSize > 0) { UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; if (packSizeLimit - destPos < u + 3) return SZ_ERROR_OUTPUT_EOF; outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); outBuf[destPos++] = (Byte)((u - 1) >> 8); outBuf[destPos++] = (Byte)(u - 1); memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); unpackSize -= u; destPos += u; p->srcPos += u; if (outStream) { *packSizeRes += destPos; if (outStream->Write(outStream, outBuf, destPos) != destPos) return SZ_ERROR_WRITE; destPos = 0; } else *packSizeRes = destPos; /* needInitState = True; */ } LzmaEnc_RestoreState(p->enc); return SZ_OK; } { size_t destPos = 0; UInt32 u = unpackSize - 1; UInt32 pm = (UInt32)(packSize - 1); unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); PRF(printf(" ")); outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); outBuf[destPos++] = (Byte)(u >> 8); outBuf[destPos++] = (Byte)u; outBuf[destPos++] = (Byte)(pm >> 8); outBuf[destPos++] = (Byte)pm; if (p->needInitProp) outBuf[destPos++] = p->props; p->needInitProp = False; p->needInitState = False; destPos += packSize; p->srcPos += unpackSize; if (outStream) if (outStream->Write(outStream, outBuf, destPos) != destPos) return SZ_ERROR_WRITE; *packSizeRes = destPos; return SZ_OK; } } /* ---------- Lzma2 Props ---------- */ void Lzma2EncProps_Init(CLzma2EncProps *p) { LzmaEncProps_Init(&p->lzmaProps); p->numTotalThreads = -1; p->numBlockThreads = -1; p->blockSize = 0; } void Lzma2EncProps_Normalize(CLzma2EncProps *p) { int t1, t1n, t2, t3; { CLzmaEncProps lzmaProps = p->lzmaProps; LzmaEncProps_Normalize(&lzmaProps); t1n = lzmaProps.numThreads; } t1 = p->lzmaProps.numThreads; t2 = p->numBlockThreads; t3 = p->numTotalThreads; if (t2 > NUM_MT_CODER_THREADS_MAX) t2 = NUM_MT_CODER_THREADS_MAX; if (t3 <= 0) { if (t2 <= 0) t2 = 1; t3 = t1n * t2; } else if (t2 <= 0) { t2 = t3 / t1n; if (t2 == 0) { t1 = 1; t2 = t3; } if (t2 > NUM_MT_CODER_THREADS_MAX) t2 = NUM_MT_CODER_THREADS_MAX; } else if (t1 <= 0) { t1 = t3 / t2; if (t1 == 0) t1 = 1; } else t3 = t1n * t2; p->lzmaProps.numThreads = t1; LzmaEncProps_Normalize(&p->lzmaProps); if (p->blockSize == 0) { UInt32 dictSize = p->lzmaProps.dictSize; UInt64 blockSize = (UInt64)dictSize << 2; const UInt32 kMinSize = (UInt32)1 << 20; const UInt32 kMaxSize = (UInt32)1 << 28; if (blockSize < kMinSize) blockSize = kMinSize; if (blockSize > kMaxSize) blockSize = kMaxSize; if (blockSize < dictSize) blockSize = dictSize; p->blockSize = (size_t)blockSize; } if (t2 > 1) { UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1; if (temp > p->lzmaProps.reduceSize) { UInt64 numBlocks = temp / p->blockSize; if (numBlocks < t2) { t2 = (UInt32)numBlocks; t3 = t1 * t2; } } } p->numBlockThreads = t2; p->numTotalThreads = t3; } static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) { return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; } /* ---------- Lzma2 ---------- */ typedef struct { Byte propEncoded; CLzma2EncProps props; Byte *outBuf; ISzAlloc *alloc; ISzAlloc *allocBig; CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX]; #ifndef _7ZIP_ST CMtCoder mtCoder; #endif } CLzma2Enc; /* ---------- Lzma2EncThread ---------- */ static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) { UInt64 packTotal = 0; SRes res = SZ_OK; if (mainEncoder->outBuf == 0) { mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); if (mainEncoder->outBuf == 0) return SZ_ERROR_MEM; } RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE, mainEncoder->alloc, mainEncoder->allocBig)); for (;;) { size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream); if (res != SZ_OK) break; packTotal += packSize; res = Progress(progress, p->srcPos, packTotal); if (res != SZ_OK) break; if (packSize == 0) break; } LzmaEnc_Finish(p->enc); if (res == SZ_OK) { Byte b = 0; if (outStream->Write(outStream, &b, 1) != 1) return SZ_ERROR_WRITE; } return res; } #ifndef _7ZIP_ST typedef struct { IMtCoderCallback funcTable; CLzma2Enc *lzma2Enc; } CMtCallbackImp; static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize, const Byte *src, size_t srcSize, int finished) { CMtCallbackImp *imp = (CMtCallbackImp *)pp; CLzma2Enc *mainEncoder = imp->lzma2Enc; CLzma2EncInt *p = &mainEncoder->coders[index]; SRes res = SZ_OK; { size_t destLim = *destSize; *destSize = 0; if (srcSize != 0) { RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE, mainEncoder->alloc, mainEncoder->allocBig)); while (p->srcPos < srcSize) { size_t packSize = destLim - *destSize; res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL); if (res != SZ_OK) break; *destSize += packSize; if (packSize == 0) { res = SZ_ERROR_FAIL; break; } if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK) { res = SZ_ERROR_PROGRESS; break; } } LzmaEnc_Finish(p->enc); if (res != SZ_OK) return res; } if (finished) { if (*destSize == destLim) return SZ_ERROR_OUTPUT_EOF; dest[(*destSize)++] = 0; } } return res; } #endif /* ---------- Lzma2Enc ---------- */ CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig) { CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc)); if (p == 0) return NULL; Lzma2EncProps_Init(&p->props); Lzma2EncProps_Normalize(&p->props); p->outBuf = 0; p->alloc = alloc; p->allocBig = allocBig; { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) p->coders[i].enc = 0; } #ifndef _7ZIP_ST MtCoder_Construct(&p->mtCoder); #endif return p; } void Lzma2Enc_Destroy(CLzma2EncHandle pp) { CLzma2Enc *p = (CLzma2Enc *)pp; unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) { CLzma2EncInt *t = &p->coders[i]; if (t->enc) { LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); t->enc = 0; } } #ifndef _7ZIP_ST MtCoder_Destruct(&p->mtCoder); #endif IAlloc_Free(p->alloc, p->outBuf); IAlloc_Free(p->alloc, pp); } SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) { CLzma2Enc *p = (CLzma2Enc *)pp; CLzmaEncProps lzmaProps = props->lzmaProps; LzmaEncProps_Normalize(&lzmaProps); if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) return SZ_ERROR_PARAM; p->props = *props; Lzma2EncProps_Normalize(&p->props); return SZ_OK; } Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) { CLzma2Enc *p = (CLzma2Enc *)pp; unsigned i; UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); for (i = 0; i < 40; i++) if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) break; return (Byte)i; } SRes Lzma2Enc_Encode(CLzma2EncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) { CLzma2Enc *p = (CLzma2Enc *)pp; int i; for (i = 0; i < p->props.numBlockThreads; i++) { CLzma2EncInt *t = &p->coders[i]; if (t->enc == NULL) { t->enc = LzmaEnc_Create(p->alloc); if (t->enc == NULL) return SZ_ERROR_MEM; } } #ifndef _7ZIP_ST if (p->props.numBlockThreads <= 1) #endif return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); #ifndef _7ZIP_ST { CMtCallbackImp mtCallback; mtCallback.funcTable.Code = MtCallbackImp_Code; mtCallback.lzma2Enc = p; p->mtCoder.progress = progress; p->mtCoder.inStream = inStream; p->mtCoder.outStream = outStream; p->mtCoder.alloc = p->alloc; p->mtCoder.mtCallback = &mtCallback.funcTable; p->mtCoder.blockSize = p->props.blockSize; p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16; p->mtCoder.numThreads = p->props.numBlockThreads; return MtCoder_Code(&p->mtCoder); } #endif } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Lzma2Enc.h0100777000000000000000000000334513761647206020261 0ustar00/* Lzma2Enc.h -- LZMA2 Encoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA2_ENC_H #define __LZMA2_ENC_H #include "LzmaEnc.h" EXTERN_C_BEGIN typedef struct { CLzmaEncProps lzmaProps; size_t blockSize; int numBlockThreads; int numTotalThreads; } CLzma2EncProps; void Lzma2EncProps_Init(CLzma2EncProps *p); void Lzma2EncProps_Normalize(CLzma2EncProps *p); /* ---------- CLzmaEnc2Handle Interface ---------- */ /* Lzma2Enc_* functions can return the following exit codes: Returns: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater in props SZ_ERROR_WRITE - Write callback error SZ_ERROR_PROGRESS - some break from progress callback SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ typedef void * CLzma2EncHandle; CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig); void Lzma2Enc_Destroy(CLzma2EncHandle p); SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); SRes Lzma2Enc_Encode(CLzma2EncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); /* ---------- One Call Interface ---------- */ /* Lzma2Encode Return code: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater SZ_ERROR_OUTPUT_EOF - output buffer overflow SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ /* SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); */ EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzmaDec.c0100777000000000000000000006631413761647206020165 0ustar00/* LzmaDec.c -- LZMA Decoder 2015-01-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "LzmaDec.h" #include #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define RC_INIT_SIZE 5 #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ { UPDATE_0(p); i = (i + i); A0; } else \ { UPDATE_1(p); i = (i + i) + 1; A1; } #define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) #define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } #define TREE_DECODE(probs, limit, i) \ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } /* #define _LZMA_SIZE_OPT */ #ifdef _LZMA_SIZE_OPT #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) #else #define TREE_6_DECODE(probs, i) \ { i = 1; \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ i -= 0x40; } #endif #define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) #define MATCHED_LITER_DEC \ matchByte <<= 1; \ bit = (matchByte & offs); \ probLit = prob + offs + bit + symbol; \ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0_CHECK range = bound; #define UPDATE_1_CHECK range -= bound; code -= bound; #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ { UPDATE_0_CHECK; i = (i + i); A0; } else \ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) #define TREE_DECODE_CHECK(probs, limit, i) \ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } #define kNumPosBitsMax 4 #define kNumPosStatesMax (1 << kNumPosBitsMax) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define LenChoice 0 #define LenChoice2 (LenChoice + 1) #define LenLow (LenChoice2 + 1) #define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) #define kNumLenProbs (LenHigh + kLenNumHighSymbols) #define kNumStates 12 #define kNumLitStates 7 #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #define kNumPosSlotBits 6 #define kNumLenToPosStates 4 #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kMatchMinLen 2 #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define IsMatch 0 #define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) #define IsRepG0 (IsRep + kNumStates) #define IsRepG1 (IsRepG0 + kNumStates) #define IsRepG2 (IsRepG1 + kNumStates) #define IsRep0Long (IsRepG2 + kNumStates) #define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) #define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) #define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) #define LenCoder (Align + kAlignTableSize) #define RepLenCoder (LenCoder + kNumLenProbs) #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 #define LZMA_LIT_SIZE 768 #define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization Out: Result: SZ_OK - OK SZ_ERROR_DATA - Error p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished = kMatchSpecLenStart + 1 : Flush marker = kMatchSpecLenStart + 2 : State Init Marker */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { CLzmaProb *probs = p->probs; unsigned state = p->state; UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; unsigned lc = p->prop.lc; Byte *dic = p->dic; SizeT dicBufSize = p->dicBufSize; SizeT dicPos = p->dicPos; UInt32 processedPos = p->processedPos; UInt32 checkDicSize = p->checkDicSize; unsigned len = 0; const Byte *buf = p->buf; UInt32 range = p->range; UInt32 code = p->code; do { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = processedPos & pbMask; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { unsigned symbol; UPDATE_0(prob); prob = probs + Literal; if (checkDicSize != 0 || processedPos != 0) prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; #ifdef _LZMA_SIZE_OPT do { NORMAL_LITER_DEC } while (symbol < 0x100); #else NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC #endif } else { unsigned matchByte = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; #ifdef _LZMA_SIZE_OPT do { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC } while (symbol < 0x100); #else { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC } #endif } dic[dicPos++] = (Byte)symbol; processedPos++; continue; } else { UPDATE_1(prob); prob = probs + IsRep + state; IF_BIT_0(prob) { UPDATE_0(prob); state += kNumStates; prob = probs + LenCoder; } else { UPDATE_1(prob); if (checkDicSize == 0 && processedPos == 0) return SZ_ERROR_DATA; prob = probs + IsRepG0 + state; IF_BIT_0(prob) { UPDATE_0(prob); prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { UPDATE_0(prob); dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; continue; } UPDATE_1(prob); } else { UInt32 distance; UPDATE_1(prob); prob = probs + IsRepG1 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep1; } else { UPDATE_1(prob); prob = probs + IsRepG2 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep2; } else { UPDATE_1(prob); distance = rep3; rep3 = rep2; } rep2 = rep1; } rep1 = rep0; rep0 = distance; } state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = (1 << kLenNumLowBits); } else { UPDATE_1(probLen); probLen = prob + LenChoice2; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = (1 << kLenNumMidBits); } else { UPDATE_1(probLen); probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = (1 << kLenNumHighBits); } } TREE_DECODE(probLen, limit, len); len += offset; } if (state >= kNumStates) { UInt32 distance; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_6_DECODE(prob, distance); if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; int numDirectBits = (int)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { distance <<= numDirectBits; prob = probs + SpecPos + distance - posSlot - 1; { UInt32 mask = 1; unsigned i = 1; do { GET_BIT2(prob + i, i, ; , distance |= mask); mask <<= 1; } while (--numDirectBits != 0); } } else { numDirectBits -= kNumAlignBits; do { NORMALIZE range >>= 1; { UInt32 t; code -= range; t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ distance = (distance << 1) + (t + 1); code += range & t; } /* distance <<= 1; if (code >= range) { code -= range; distance |= 1; } */ } while (--numDirectBits != 0); prob = probs + Align; distance <<= kNumAlignBits; { unsigned i = 1; GET_BIT2(prob + i, i, ; , distance |= 1); GET_BIT2(prob + i, i, ; , distance |= 2); GET_BIT2(prob + i, i, ; , distance |= 4); GET_BIT2(prob + i, i, ; , distance |= 8); } if (distance == (UInt32)0xFFFFFFFF) { len += kMatchSpecLenStart; state -= kNumStates; break; } } } rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance + 1; if (checkDicSize == 0) { if (distance >= processedPos) return SZ_ERROR_DATA; } else if (distance >= checkDicSize) return SZ_ERROR_DATA; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; if (limit == dicPos) return SZ_ERROR_DATA; { SizeT rem = limit - dicPos; unsigned curLen = ((rem < len) ? (unsigned)rem : len); SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); processedPos += curLen; len -= curLen; if (pos + curLen <= dicBufSize) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; const Byte *lim = dest + curLen; dicPos += curLen; do *(dest) = (Byte)*(dest + src); while (++dest != lim); } else { do { dic[dicPos++] = dic[pos]; if (++pos == dicBufSize) pos = 0; } while (--curLen != 0); } } } } while (dicPos < limit && buf < bufLimit); NORMALIZE; p->buf = buf; p->range = range; p->code = code; p->remainLen = len; p->dicPos = dicPos; p->processedPos = processedPos; p->reps[0] = rep0; p->reps[1] = rep1; p->reps[2] = rep2; p->reps[3] = rep3; p->state = state; return SZ_OK; } static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) { if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) { Byte *dic = p->dic; SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; UInt32 rep0 = p->reps[0]; if (limit - dicPos < len) len = (unsigned)(limit - dicPos); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; p->processedPos += len; p->remainLen -= len; while (len != 0) { len--; dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; } } static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { do { SizeT limit2 = limit; if (p->checkDicSize == 0) { UInt32 rem = p->prop.dicSize - p->processedPos; if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); if (p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) { p->remainLen = kMatchSpecLenStart; } return 0; } typedef enum { DUMMY_ERROR, /* unexpected end of input stream */ DUMMY_LIT, DUMMY_MATCH, DUMMY_REP } ELzmaDummy; static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) { UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) prob += (LZMA_LIT_SIZE * ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { unsigned symbol = 1; do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); } else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) } while (symbol < 0x100); } res = DUMMY_LIT; } else { unsigned len; UPDATE_1_CHECK; prob = probs + IsRep + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; state = 0; prob = probs + LenCoder; res = DUMMY_MATCH; } else { UPDATE_1_CHECK; res = DUMMY_REP; prob = probs + IsRepG0 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; NORMALIZE_CHECK; return DUMMY_REP; } else { UPDATE_1_CHECK; } } else { UPDATE_1_CHECK; prob = probs + IsRepG1 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; prob = probs + IsRepG2 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; } } } state = kNumStates; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = 1 << kLenNumLowBits; } else { UPDATE_1_CHECK; probLen = prob + LenChoice2; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = 1 << kLenNumMidBits; } else { UPDATE_1_CHECK; probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = 1 << kLenNumHighBits; } } TREE_DECODE_CHECK(probLen, limit, len); len += offset; } if (state < 4) { unsigned posSlot; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { int numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ if (posSlot < kEndPosModelIndex) { prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; } else { numDirectBits -= kNumAlignBits; do { NORMALIZE_CHECK range >>= 1; code -= range & (((code - range) >> 31) - 1); /* if (code >= range) code -= range; */ } while (--numDirectBits != 0); prob = probs + Align; numDirectBits = kNumAlignBits; } { unsigned i = 1; do { GET_BIT_CHECK(prob + i, i); } while (--numDirectBits != 0); } } } } } NORMALIZE_CHECK; return res; } static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) { p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); p->range = 0xFFFFFFFF; p->needFlush = 0; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; p->remainLen = 0; p->tempBufSize = 0; if (initDic) { p->processedPos = 0; p->checkDicSize = 0; p->needInitState = 1; } if (initState) p->needInitState = 1; } void LzmaDec_Init(CLzmaDec *p) { p->dicPos = 0; LzmaDec_InitDicAndState(p, True, True); } static void LzmaDec_InitStateReal(CLzmaDec *p) { UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); UInt32 i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; p->state = 0; p->needInitState = 0; } SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; (*srcLen) = 0; LzmaDec_WriteRem(p, dicLimit); *status = LZMA_STATUS_NOT_SPECIFIED; while (p->remainLen != kMatchSpecLenStart) { int checkEndMarkNow; if (p->needFlush != 0) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; if (p->tempBufSize < RC_INIT_SIZE) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; LzmaDec_InitRc(p, p->tempBuf); p->tempBufSize = 0; } checkEndMarkNow = 0; if (p->dicPos >= dicLimit) { if (p->remainLen == 0 && p->code == 0) { *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; return SZ_OK; } if (finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->remainLen != 0) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } checkEndMarkNow = 1; } if (p->needInitState) LzmaDec_InitStateReal(p); if (p->tempBufSize == 0) { SizeT processed; const Byte *bufLimit; if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, src, inSize); if (dummyRes == DUMMY_ERROR) { memcpy(p->tempBuf, src, inSize); p->tempBufSize = (unsigned)inSize; (*srcLen) += inSize; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } bufLimit = src; } else bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; p->buf = src; if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) return SZ_ERROR_DATA; processed = (SizeT)(p->buf - src); (*srcLen) += processed; src += processed; inSize -= processed; } else { unsigned rem = p->tempBufSize, lookAhead = 0; while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) p->tempBuf[rem++] = src[lookAhead++]; p->tempBufSize = rem; if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); if (dummyRes == DUMMY_ERROR) { (*srcLen) += lookAhead; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } } p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; p->tempBufSize = 0; } } if (p->code == 0) *status = LZMA_STATUS_FINISHED_WITH_MARK; return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; } SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen; SizeT inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT inSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->dicPos == p->dicBufSize) p->dicPos = 0; dicPos = p->dicPos; if (outSize > p->dicBufSize - dicPos) { outSizeCur = p->dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); src += inSizeCur; inSize -= inSizeCur; *srcLen += inSizeCur; outSizeCur = p->dicPos - dicPos; memcpy(dest, p->dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); p->probs = 0; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); p->dic = 0; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) { LzmaDec_FreeProbs(p, alloc); LzmaDec_FreeDict(p, alloc); } SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) { UInt32 dicSize; Byte d; if (size < LZMA_PROPS_SIZE) return SZ_ERROR_UNSUPPORTED; else dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); if (dicSize < LZMA_DIC_MIN) dicSize = LZMA_DIC_MIN; p->dicSize = dicSize; d = data[0]; if (d >= (9 * 5 * 5)) return SZ_ERROR_UNSUPPORTED; p->lc = d % 9; d /= 9; p->pb = d / 5; p->lp = d % 5; return SZ_OK; } static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); if (p->probs == 0 || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; if (p->probs == 0) return SZ_ERROR_MEM; } return SZ_OK; } SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); p->prop = propNew; return SZ_OK; } SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); dicBufSize = propNew.dicSize; if (p->dic == 0 || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); if (p->dic == 0) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; } } p->dicBufSize = dicBufSize; p->prop = propNew; return SZ_OK; } SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzmaDec p; SRes res; SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; if (inSize < RC_INIT_SIZE) return SZ_ERROR_INPUT_EOF; LzmaDec_Construct(&p); RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); p.dic = dest; p.dicBufSize = outSize; LzmaDec_Init(&p); *srcLen = inSize; res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); *destLen = p.dicPos; if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; LzmaDec_FreeProbs(&p, alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzmaDec.h0100777000000000000000000001524613761647206020170 0ustar00/* LzmaDec.h -- LZMA Decoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H #include "7zTypes.h" EXTERN_C_BEGIN /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, but memory usage for CLzmaDec::probs will be doubled in that case */ #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif /* ---------- LZMA Properties ---------- */ #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaProps { unsigned lc, lp, pb; UInt32 dicSize; } CLzmaProps; /* LzmaProps_Decode - decodes properties Returns: SZ_OK SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); /* ---------- LZMA Decoder state ---------- */ /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ #define LZMA_REQUIRED_INPUT_MAX 20 typedef struct { CLzmaProps prop; CLzmaProb *probs; Byte *dic; const Byte *buf; UInt32 range, code; SizeT dicPos; SizeT dicBufSize; UInt32 processedPos; UInt32 checkDicSize; unsigned state; UInt32 reps[4]; unsigned remainLen; int needFlush; int needInitState; UInt32 numProbs; unsigned tempBufSize; Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } void LzmaDec_Init(CLzmaDec *p); /* There are two types of LZMA streams: 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ typedef enum { LZMA_FINISH_ANY, /* finish at any point */ LZMA_FINISH_END /* block must be finished at the end */ } ELzmaFinishMode; /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! You must use LZMA_FINISH_END, when you know that current output buffer covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, and output value of destLen will be less than output buffer size limit. You can check status result also. You can use multiple checks to test data integrity after full decompression: 1) Check Result and "status" variable. 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. You must use correct finish mode in that case. */ typedef enum { LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ } ELzmaStatus; /* ELzmaStatus is used only as output value for function call */ /* ---------- Interfaces ---------- */ /* There are 3 levels of interfaces: 1) Dictionary Interface 2) Buffer Interface 3) One Call Interface You can select any of these interfaces, but don't mix functions from different groups for same object. */ /* There are two variants to allocate state for Dictionary Interface: 1) LzmaDec_Allocate / LzmaDec_Free 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs You can use variant 2, if you set dictionary buffer manually. For Buffer Interface you must always use variant 1. LzmaDec_Allocate* can return: SZ_OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); /* ---------- Dictionary Interface ---------- */ /* You can use it, if you want to eliminate the overhead for data copying from dictionary to some other external buffer. You must work with CLzmaDec variables directly in this interface. STEPS: LzmaDec_Constr() LzmaDec_Allocate() for (each new stream) { LzmaDec_Init() while (it needs more decompression) { LzmaDec_DecodeToDic() use data from CLzmaDec::dic and update CLzmaDec::dicPos } } LzmaDec_Free() */ /* LzmaDec_DecodeToDic The decoding to internal dictionary buffer (CLzmaDec::dic). You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! finishMode: It has meaning only if the decoding reaches output limit (dicLimit). LZMA_FINISH_ANY - Decode just dicLimit bytes. LZMA_FINISH_END - Stream must be finished after dicLimit. Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error */ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- Buffer Interface ---------- */ /* It's zlib-like interface. See LzmaDec_DecodeToDic description for information about STEPS and return results, but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need to work with CLzmaDec variables manually. finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). */ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* LzmaDecode finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzmaEnc.c0100777000000000000000000017235013761647206020175 0ustar00/* LzmaEnc.c -- LZMA Encoder 2014-12-29 : Igor Pavlov : Public domain */ #include "Precomp.h" #include /* #define SHOW_STAT */ /* #define SHOW_STAT2 */ #if defined(SHOW_STAT) || defined(SHOW_STAT2) #include #endif #include "LzmaEnc.h" #include "LzFind.h" #ifndef _7ZIP_ST #include "LzFindMt.h" #endif #ifdef SHOW_STAT static unsigned g_STAT_OFFSET = 0; #endif #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) #define kBlockSize (9 << 10) #define kUnpackBlockSize (1 << 18) #define kMatchArraySize (1 << 21) #define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) #define kNumMaxDirectBits (31) #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define kProbInitValue (kBitModelTotal >> 1) #define kNumMoveReducingBits 4 #define kNumBitPriceShiftBits 4 #define kBitPrice (1 << kNumBitPriceShiftBits) void LzmaEncProps_Init(CLzmaEncProps *p) { p->level = 5; p->dictSize = p->mc = 0; p->reduceSize = (UInt64)(Int64)-1; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; p->writeEndMark = 0; } void LzmaEncProps_Normalize(CLzmaEncProps *p) { int level = p->level; if (level < 0) level = 5; p->level = level; if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->dictSize > p->reduceSize) { unsigned i; for (i = 11; i <= 30; i++) { if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } } } if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST ((p->btMode && p->algo) ? 2 : 1); #else 1; #endif } UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) { CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); return props.dictSize; } /* #define LZMA_LOG_BSR */ /* Define it for Intel's CPU */ #ifdef LZMA_LOG_BSR #define kDicLogSizeMaxCompress 30 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res); return res; } #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } #else #define kNumLogBits (9 + (int)sizeof(size_t) / 2) #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) void LzmaEnc_FastPosInit(Byte *g_FastPos) { int c = 2, slotFast; g_FastPos[0] = 0; g_FastPos[1] = 1; for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) { UInt32 k = (1 << ((slotFast >> 1) - 1)); UInt32 j; for (j = 0; j < k; j++, c++) g_FastPos[c] = (Byte)slotFast; } } #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } */ #define GetPosSlot1(pos) p->g_FastPos[pos] #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } #endif #define LZMA_NUM_REPS 4 typedef unsigned CState; typedef struct { UInt32 price; CState state; int prev1IsChar; int prev2; UInt32 posPrev2; UInt32 backPrev2; UInt32 posPrev; UInt32 backPrev; UInt32 backs[LZMA_NUM_REPS]; } COptimal; #define kNumOpts (1 << 12) #define kNumLenToPosStates 4 #define kNumPosSlotBits 6 #define kDicLogSizeMin 0 #define kDicLogSizeMax 32 #define kDistTableSizeMax (kDicLogSizeMax * 2) #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kAlignMask (kAlignTableSize - 1) #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif #define LZMA_PB_MAX 4 #define LZMA_LC_MAX 8 #define LZMA_LP_MAX 4 #define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define LZMA_MATCH_LEN_MIN 2 #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) #define kNumStates 12 typedef struct { CLzmaProb choice; CLzmaProb choice2; CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; typedef struct { CLenEnc p; UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; typedef struct { UInt32 range; Byte cache; UInt64 low; UInt64 cacheSize; Byte *buf; Byte *bufLim; Byte *bufBase; ISeqOutStream *outStream; UInt64 processed; SRes res; } CRangeEnc; typedef struct { CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; } CSaveState; typedef struct { IMatchFinder matchFinder; void *matchFinderObj; #ifndef _7ZIP_ST Bool mtMode; CMatchFinderMt matchFinderMt; #endif CMatchFinder matchFinderBase; #ifndef _7ZIP_ST Byte pad[128]; #endif UInt32 optimumEndIndex; UInt32 optimumCurrentIndex; UInt32 longestMatchLength; UInt32 numPairs; UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR Byte g_FastPos[1 << kNumLogBits]; #endif UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; UInt32 numFastBytes; UInt32 additionalOffset; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; UInt32 alignPriceCount; UInt32 distTableSize; unsigned lc, lp, pb; unsigned lpMask, pbMask; CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; unsigned lclp; Bool fastMode; CRangeEnc rc; Bool writeEndMark; UInt64 nowPos64; UInt32 matchPriceCount; Bool finished; Bool multiThread; SRes result; UInt32 dictSize; int needInit; CSaveState saveState; } CLzmaEnc; void LzmaEnc_SaveState(CLzmaEncHandle pp) { CLzmaEnc *p = (CLzmaEnc *)pp; CSaveState *dest = &p->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp) { CLzmaEnc *dest = (CLzmaEnc *)pp; const CSaveState *p = &dest->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) { CLzmaEnc *p = (CLzmaEnc *)pp; CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30)) return SZ_ERROR_PARAM; p->dictSize = props.dictSize; { unsigned fb = props.fb; if (fb < 5) fb = 5; if (fb > LZMA_MATCH_LEN_MAX) fb = LZMA_MATCH_LEN_MAX; p->numFastBytes = fb; } p->lc = props.lc; p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); p->matchFinderBase.btMode = props.btMode; { UInt32 numHashBytes = 4; if (props.btMode) { if (props.numHashBytes < 2) numHashBytes = 2; else if (props.numHashBytes < 4) numHashBytes = props.numHashBytes; } p->matchFinderBase.numHashBytes = numHashBytes; } p->matchFinderBase.cutValue = props.mc; p->writeEndMark = props.writeEndMark; #ifndef _7ZIP_ST /* if (newMultiThread != _multiThread) { ReleaseMatchFinder(); _multiThread = newMultiThread; } */ p->multiThread = (props.numThreads > 1); #endif return SZ_OK; } static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; #define IsCharState(s) ((s) < 7) #define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) #define kInfinityPrice (1 << 30) static void RangeEnc_Construct(CRangeEnc *p) { p->outStream = 0; p->bufBase = 0; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) #define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { if (p->bufBase == 0) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); if (p->bufBase == 0) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; } return 1; } static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->bufBase); p->bufBase = 0; } static void RangeEnc_Init(CRangeEnc *p) { /* Stream.Init(); */ p->low = 0; p->range = 0xFFFFFFFF; p->cacheSize = 1; p->cache = 0; p->buf = p->bufBase; p->processed = 0; p->res = SZ_OK; } static void RangeEnc_FlushStream(CRangeEnc *p) { size_t num; if (p->res != SZ_OK) return; num = p->buf - p->bufBase; if (num != p->outStream->Write(p->outStream, p->bufBase, num)) p->res = SZ_ERROR_WRITE; p->processed += num; p->buf = p->bufBase; } static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) { if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0) { Byte temp = p->cache; do { Byte *buf = p->buf; *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); p->buf = buf; if (buf == p->bufLim) RangeEnc_FlushStream(p); temp = 0xFF; } while (--p->cacheSize != 0); p->cache = (Byte)((UInt32)p->low >> 24); } p->cacheSize++; p->low = (UInt32)p->low << 8; } static void RangeEnc_FlushData(CRangeEnc *p) { int i; for (i = 0; i < 5; i++) RangeEnc_ShiftLow(p); } static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits) { do { p->range >>= 1; p->low += p->range & (0 - ((value >> --numBits) & 1)); if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } while (numBits != 0); } static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) { UInt32 ttt = *prob; UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; if (symbol == 0) { p->range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } else { p->low += newBound; p->range -= newBound; ttt -= ttt >> kNumMoveBits; } *prob = (CLzmaProb)ttt; if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) { symbol |= 0x100; do { RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); } static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) { UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); } void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) { const int kCyclesBits = kNumBitPriceShiftBits; UInt32 w = i; UInt32 bitCount = 0; int j; for (j = 0; j < kCyclesBits; j++) { w = w * w; bitCount <<= 1; while (w >= ((UInt32)1 << 16)) { w >>= 1; bitCount++; } } ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); } } #define GET_PRICE(prob, symbol) \ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICEa(prob, symbol) \ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100; do { price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); return price; } static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); return price; } static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = numBitLevels; i != 0;) { UInt32 bit; i--; bit = (symbol >> i) & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; } } static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = 0; i < numBitLevels; i++) { UInt32 bit = symbol & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; symbol >>= 1; } } static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels); while (symbol != 1) { price += GET_PRICEa(probs[symbol >> 1], symbol & 1); symbol >>= 1; } return price; } static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1; int i; for (i = numBitLevels; i != 0; i--) { UInt32 bit = symbol & 1; symbol >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) | bit; } return price; } static void LenEnc_Init(CLenEnc *p) { unsigned i; p->choice = p->choice2 = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) p->low[i] = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) p->mid[i] = kProbInitValue; for (i = 0; i < kLenNumHighSymbols; i++) p->high[i] = kProbInitValue; } static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) { if (symbol < kLenNumLowSymbols) { RangeEnc_EncodeBit(rc, &p->choice, 0); RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); } else { RangeEnc_EncodeBit(rc, &p->choice, 1); if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) { RangeEnc_EncodeBit(rc, &p->choice2, 0); RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); } else { RangeEnc_EncodeBit(rc, &p->choice2, 1); RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); } } } static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice); UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); UInt32 i = 0; for (i = 0; i < kLenNumLowSymbols; i++) { if (i >= numSymbols) return; prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); } for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) { if (i >= numSymbols) return; prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); } for (; i < numSymbols; i++) prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice) if (--p->counters[posState] == 0) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void MovePos(CLzmaEnc *p, UInt32 num) { #ifdef SHOW_STAT g_STAT_OFFSET += num; printf("\n MovePos %d", num); #endif if (num != 0) { p->additionalOffset += num; p->matchFinder.Skip(p->matchFinderObj, num); } } static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) { UInt32 lenRes = 0, numPairs; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); #ifdef SHOW_STAT printf("\n i = %d numPairs = %d ", g_STAT_OFFSET, numPairs / 2); g_STAT_OFFSET++; { UInt32 i; for (i = 0; i < numPairs; i += 2) printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); } #endif if (numPairs > 0) { lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { const Byte *pby2 = pby - distance; for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); } } } p->additionalOffset++; *numDistancePairsRes = numPairs; return lenRes; } #define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; #define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; #define IsShortRep(p) ((p)->backPrev == 0) static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) { return GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]); } static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) { UInt32 price; if (repIndex == 0) { price = GET_PRICE_0(p->isRepG0[state]); price += GET_PRICE_1(p->isRep0Long[state][posState]); } else { price = GET_PRICE_1(p->isRepG0[state]); if (repIndex == 1) price += GET_PRICE_0(p->isRepG1[state]); else { price += GET_PRICE_1(p->isRepG1[state]); price += GET_PRICE(p->isRepG2[state], repIndex - 2); } } return price; } static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) { return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + GetPureRepPrice(p, repIndex, state, posState); } static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) { UInt32 posMem = p->opt[cur].posPrev; UInt32 backMem = p->opt[cur].backPrev; p->optimumEndIndex = cur; do { if (p->opt[cur].prev1IsChar) { MakeAsChar(&p->opt[posMem]) p->opt[posMem].posPrev = posMem - 1; if (p->opt[cur].prev2) { p->opt[posMem - 1].prev1IsChar = False; p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; } } { UInt32 posPrev = posMem; UInt32 backCur = backMem; backMem = p->opt[posPrev].backPrev; posMem = p->opt[posPrev].posPrev; p->opt[posPrev].backPrev = backCur; p->opt[posPrev].posPrev = cur; cur = posPrev; } } while (cur != 0); *backRes = p->opt[0].backPrev; p->optimumCurrentIndex = p->opt[0].posPrev; return p->optimumCurrentIndex; } #define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; UInt32 matchPrice, repMatchPrice, normalMatchPrice; UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; UInt32 *matches; const Byte *data; Byte curByte, matchByte; if (p->optimumEndIndex != p->optimumCurrentIndex) { const COptimal *opt = &p->opt[p->optimumCurrentIndex]; UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; *backRes = opt->backPrev; p->optimumCurrentIndex = opt->posPrev; return lenRes; } p->optimumCurrentIndex = p->optimumEndIndex = 0; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; if (numAvail < 2) { *backRes = (UInt32)(-1); return 1; } if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repMaxIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; data2 = data - (reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; continue; } for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); repLens[i] = lenTest; if (lenTest > repLens[repMaxIndex]) repMaxIndex = i; } if (repLens[repMaxIndex] >= p->numFastBytes) { UInt32 lenRes; *backRes = repMaxIndex; lenRes = repLens[repMaxIndex]; MovePos(p, lenRes - 1); return lenRes; } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } curByte = *data; matchByte = *(data - (reps[0] + 1)); if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) { *backRes = (UInt32)-1; return 1; } p->opt[0].state = (CState)p->state; posState = (position & p->pbMask); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + (!IsCharState(p->state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } MakeAsChar(&p->opt[1]); matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); if (matchByte == curByte) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); if (shortRepPrice < p->opt[1].price) { p->opt[1].price = shortRepPrice; MakeAsShortRep(&p->opt[1]); } } lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); if (lenEnd < 2) { *backRes = p->opt[1].backPrev; return 1; } p->opt[1].posPrev = 0; for (i = 0; i < LZMA_NUM_REPS; i++) p->opt[0].backs[i] = reps[i]; len = lenEnd; do p->opt[len--].price = kInfinityPrice; while (len >= 2); for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 repLen = repLens[i]; UInt32 price; if (repLen < 2) continue; price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; COptimal *opt = &p->opt[repLen]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = i; opt->prev1IsChar = False; } } while (--repLen >= 2); } normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); if (len <= mainLen) { UInt32 offs = 0; while (len > matches[offs]) offs += 2; for (; ; len++) { COptimal *opt; UInt32 distance = matches[offs + 1]; UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(len); if (distance < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][distance]; else { UInt32 slot; GetPosSlot2(distance, slot); curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; } opt = &p->opt[len]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = distance + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (len == matches[offs]) { offs += 2; if (offs == numPairs) break; } } } cur = 0; #ifdef SHOW_STAT2 if (position >= 0) { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); } #endif for (;;) { UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; Bool nextIsChar; Byte curByte, matchByte; const Byte *data; COptimal *curOpt; COptimal *nextOpt; cur++; if (cur == lenEnd) return Backward(p, backRes, cur); newLen = ReadMatchDistances(p, &numPairs); if (newLen >= p->numFastBytes) { p->numPairs = numPairs; p->longestMatchLength = newLen; return Backward(p, backRes, cur); } position++; curOpt = &p->opt[cur]; posPrev = curOpt->posPrev; if (curOpt->prev1IsChar) { posPrev--; if (curOpt->prev2) { state = p->opt[curOpt->posPrev2].state; if (curOpt->backPrev2 < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } else state = p->opt[posPrev].state; state = kLiteralNextStates[state]; } else state = p->opt[posPrev].state; if (posPrev == cur - 1) { if (IsShortRep(curOpt)) state = kShortRepNextStates[state]; else state = kLiteralNextStates[state]; } else { UInt32 pos; const COptimal *prevOpt; if (curOpt->prev1IsChar && curOpt->prev2) { posPrev = curOpt->posPrev2; pos = curOpt->backPrev2; state = kRepNextStates[state]; } else { pos = curOpt->backPrev; if (pos < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } prevOpt = &p->opt[posPrev]; if (pos < LZMA_NUM_REPS) { UInt32 i; reps[0] = prevOpt->backs[pos]; for (i = 1; i <= pos; i++) reps[i] = prevOpt->backs[i - 1]; for (; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i]; } else { UInt32 i; reps[0] = (pos - LZMA_NUM_REPS); for (i = 1; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i - 1]; } } curOpt->state = (CState)state; curOpt->backs[0] = reps[0]; curOpt->backs[1] = reps[1]; curOpt->backs[2] = reps[2]; curOpt->backs[3] = reps[3]; curPrice = curOpt->price; nextIsChar = False; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; curByte = *data; matchByte = *(data - (reps[0] + 1)); posState = (position & p->pbMask); curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); curAnd1Price += (!IsCharState(state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } nextOpt = &p->opt[cur + 1]; if (curAnd1Price < nextOpt->price) { nextOpt->price = curAnd1Price; nextOpt->posPrev = cur; MakeAsChar(nextOpt); nextIsChar = True; } matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); if (shortRepPrice <= nextOpt->price) { nextOpt->price = shortRepPrice; nextOpt->posPrev = cur; MakeAsShortRep(nextOpt); nextIsChar = True; } } numAvailFull = p->numAvail; { UInt32 temp = kNumOpts - 1 - cur; if (temp < numAvailFull) numAvailFull = temp; } if (numAvailFull < 2) continue; numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); if (!nextIsChar && matchByte != curByte) /* speed optimization */ { /* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; const Byte *data2 = data - (reps[0] + 1); UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); lenTest2 = temp - 1; if (lenTest2 >= 2) { UInt32 state2 = kLiteralNextStates[state]; UInt32 posStateNext = (position + 1) & p->pbMask; UInt32 nextRepMatchPrice = curAnd1Price + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = False; } } } } startLen = 2; /* speed optimization */ { UInt32 repIndex; for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) { UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; const Byte *data2 = data - (reps[repIndex] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); while (lenEnd < cur + lenTest) p->opt[++lenEnd].price = kInfinityPrice; lenTestTemp = lenTest; price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; COptimal *opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = repIndex; opt->prev1IsChar = False; } } while (--lenTest >= 2); lenTest = lenTestTemp; if (repIndex == 0) startLen = lenTest + 1; /* if (_maxMode) */ { UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = price + p->repLenEnc.prices[posState][lenTest - 2] + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (position + lenTest + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + lenTest + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = repIndex; } } } } } } /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ if (newLen > numAvail) { newLen = numAvail; for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); matches[numPairs] = newLen; numPairs += 2; } if (newLen >= startLen) { UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); UInt32 offs, curBack, posSlot; UInt32 lenTest; while (lenEnd < cur + newLen) p->opt[++lenEnd].price = kInfinityPrice; offs = 0; while (startLen > matches[offs]) offs += 2; curBack = matches[offs + 1]; GetPosSlot2(curBack, posSlot); for (lenTest = /*2*/ startLen; ; lenTest++) { UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(lenTest); COptimal *opt; if (curBack < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; else curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = curBack + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ const Byte *data2 = data - (curBack + 1); UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (posStateNext + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 offset = cur + lenTest + 1 + lenTest2; UInt32 curAndLenPrice; COptimal *opt; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = curBack + LZMA_NUM_REPS; } } } offs += 2; if (offs == numPairs) break; curBack = matches[offs + 1]; if (curBack >= kNumFullDistances) GetPosSlot2(curBack, posSlot); } } } } } #define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) { UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; const Byte *data; const UInt32 *matches; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; *backRes = (UInt32)-1; if (numAvail < 2) return 1; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repLen = repIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++); if (len >= p->numFastBytes) { *backRes = i; MovePos(p, len - 1); return len; } if (len > repLen) { repIndex = i; repLen = len; } } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } mainDist = 0; /* for GCC */ if (mainLen >= 2) { mainDist = matches[numPairs - 1]; while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) { if (!ChangePair(matches[numPairs - 3], mainDist)) break; numPairs -= 2; mainLen = matches[numPairs - 2]; mainDist = matches[numPairs - 1]; } if (mainLen == 2 && mainDist >= 0x80) mainLen = 1; } if (repLen >= 2 && ( (repLen + 1 >= mainLen) || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) { *backRes = repIndex; MovePos(p, repLen - 1); return repLen; } if (mainLen < 2 || numAvail <= 2) return 1; p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); if (p->longestMatchLength >= 2) { UInt32 newDistance = matches[p->numPairs - 1]; if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || (p->longestMatchLength > mainLen + 1) || (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) return 1; } data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1; for (len = 2; len < limit && data[len] == data2[len]; len++); if (len >= limit) return 1; } *backRes = mainDist + LZMA_NUM_REPS; MovePos(p, mainLen - 2); return mainLen; } static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) { UInt32 len; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; len = LZMA_MATCH_LEN_MIN; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); } static SRes CheckErrors(CLzmaEnc *p) { if (p->result != SZ_OK) return p->result; if (p->rc.res != SZ_OK) p->result = SZ_ERROR_WRITE; if (p->matchFinderBase.result != SZ_OK) p->result = SZ_ERROR_READ; if (p->result != SZ_OK) p->finished = True; return p->result; } static SRes Flush(CLzmaEnc *p, UInt32 nowPos) { /* ReleaseMFStream(); */ p->finished = True; if (p->writeEndMark) WriteEndMarker(p, nowPos & p->pbMask); RangeEnc_FlushData(&p->rc); RangeEnc_FlushStream(&p->rc); return CheckErrors(p); } static void FillAlignPrices(CLzmaEnc *p) { UInt32 i; for (i = 0; i < kAlignTableSize; i++) p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); p->alignPriceCount = 0; } static void FillDistancesPrices(CLzmaEnc *p) { UInt32 tempPrices[kNumFullDistances]; UInt32 i, lenToPosState; for (i = kStartPosModelIndex; i < kNumFullDistances; i++) { UInt32 posSlot = GetPosSlot1(i); UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); } for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) { UInt32 posSlot; const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; for (posSlot = 0; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); { UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; UInt32 i; for (i = 0; i < kStartPosModelIndex; i++) distancesPrices[i] = posSlotPrices[i]; for (; i < kNumFullDistances; i++) distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; } } p->matchPriceCount = 0; } void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase; #endif { CLzmaEncProps props; LzmaEncProps_Init(&props); LzmaEnc_SetProps(p, &props); } #ifndef LZMA_LOG_BSR LzmaEnc_FastPosInit(p->g_FastPos); #endif LzmaEnc_InitPriceTables(p->ProbPrices); p->litProbs = 0; p->saveState.litProbs = 0; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); if (p != 0) LzmaEnc_Construct((CLzmaEnc *)p); return p; } void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); p->litProbs = 0; p->saveState.litProbs = 0; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) { #ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); } void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) { LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); alloc->Free(alloc, p); } static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) { UInt32 nowPos32, startPos32; if (p->needInit) { p->matchFinder.Init(p->matchFinderObj); p->needInit = 0; } if (p->finished) return p->result; RINOK(CheckErrors(p)); nowPos32 = (UInt32)p->nowPos64; startPos32 = nowPos32; if (p->nowPos64 == 0) { UInt32 numPairs; Byte curByte; if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) return Flush(p, nowPos32); ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++; } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) for (;;) { UInt32 pos, len, posState; if (p->fastMode) len = GetOptimumFast(p, &pos); else len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask; if (len == 1 && pos == (UInt32)-1) { Byte curByte; CLzmaProb *probs; const Byte *data; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; curByte = *data; probs = LIT_PROBS(nowPos32, *(data - 1)); if (IsCharState(p->state)) LitEnc_Encode(&p->rc, probs, curByte); else LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); p->state = kLiteralNextStates[p->state]; } else { RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); if (pos < LZMA_NUM_REPS) { RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); if (pos == 0) { RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); } else { UInt32 distance = p->reps[pos]; RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); if (pos == 1) RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); else { RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); if (pos == 3) p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; } p->reps[1] = p->reps[0]; p->reps[0] = distance; } if (len == 1) p->state = kShortRepNextStates[p->state]; else { LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); p->state = kRepNextStates[p->state]; } } else { UInt32 posSlot; RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); pos -= LZMA_NUM_REPS; GetPosSlot(pos, posSlot); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); UInt32 posReduced = pos - base; if (posSlot < kEndPosModelIndex) RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); else { RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); p->alignPriceCount++; } } p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; p->reps[1] = p->reps[0]; p->reps[0] = pos; p->matchPriceCount++; } } p->additionalOffset -= len; nowPos32 += len; if (p->additionalOffset == 0) { UInt32 processed; if (!p->fastMode) { if (p->matchPriceCount >= (1 << 7)) FillDistancesPrices(p); if (p->alignPriceCount >= kAlignTableSize) FillAlignPrices(p); } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) break; processed = nowPos32 - startPos32; if (useLimits) { if (processed + kNumOpts + 300 >= maxUnpackSize || RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } else if (processed >= (1 << 15)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p); } } } p->nowPos64 += nowPos32 - startPos32; return Flush(p, nowPos32); } #define kBigHashDicLimit ((UInt32)1 << 24) static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; #ifndef _7ZIP_ST p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); #endif { unsigned lclp = p->lc + p->lp; if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); if (p->litProbs == 0 || p->saveState.litProbs == 0) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM; } p->lclp = lclp; } } p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize; #ifndef _7ZIP_ST if (p->mtMode) { RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); p->matchFinderObj = &p->matchFinderMt; MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); } else #endif { if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) return SZ_ERROR_MEM; p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } return SZ_OK; } void LzmaEnc_Init(CLzmaEnc *p) { UInt32 i; p->state = 0; for (i = 0 ; i < LZMA_NUM_REPS; i++) p->reps[i] = 0; RangeEnc_Init(&p->rc); for (i = 0; i < kNumStates; i++) { UInt32 j; for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) { p->isMatch[i][j] = kProbInitValue; p->isRep0Long[i][j] = kProbInitValue; } p->isRep[i] = kProbInitValue; p->isRepG0[i] = kProbInitValue; p->isRepG1[i] = kProbInitValue; p->isRepG2[i] = kProbInitValue; } { UInt32 num = 0x300 << (p->lp + p->lc); for (i = 0; i < num; i++) p->litProbs[i] = kProbInitValue; } { for (i = 0; i < kNumLenToPosStates; i++) { CLzmaProb *probs = p->posSlotEncoder[i]; UInt32 j; for (j = 0; j < (1 << kNumPosSlotBits); j++) probs[j] = kProbInitValue; } } { for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) p->posEncoders[i] = kProbInitValue; } LenEnc_Init(&p->lenEnc.p); LenEnc_Init(&p->repLenEnc.p); for (i = 0; i < (1 << kNumAlignBits); i++) p->posAlignEncoder[i] = kProbInitValue; p->optimumEndIndex = 0; p->optimumCurrentIndex = 0; p->additionalOffset = 0; p->pbMask = (1 << p->pb) - 1; p->lpMask = (1 << p->lp) - 1; } void LzmaEnc_InitPrices(CLzmaEnc *p) { if (!p->fastMode) { FillDistancesPrices(p); FillAlignPrices(p); } p->lenEnc.tableSize = p->repLenEnc.tableSize = p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); } static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 i; for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) if (p->dictSize <= ((UInt32)1 << i)) break; p->distTableSize = i * 2; p->finished = False; p->result = SZ_OK; RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); LzmaEnc_Init(p); LzmaEnc_InitPrices(p); p->nowPos64 = 0; return SZ_OK; } static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; p->rc.outStream = outStream; return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); } SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) { p->matchFinderBase.directInput = 1; p->matchFinderBase.bufferBase = (Byte *)src; p->matchFinderBase.directInputRem = srcLen; } SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; LzmaEnc_SetInputBuf(p, src, srcLen); p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } void LzmaEnc_Finish(CLzmaEncHandle pp) { #ifndef _7ZIP_ST CLzmaEnc *p = (CLzmaEnc *)pp; if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else pp = pp; #endif } typedef struct { ISeqOutStream funcTable; Byte *data; SizeT rem; Bool overflow; } CSeqOutStreamBuf; static size_t MyWrite(void *pp, const void *data, size_t size) { CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; if (p->rem < size) { size = p->rem; p->overflow = True; } memcpy(p->data, data, size); p->rem -= size; p->data += size; return size; } UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { CLzmaEnc *p = (CLzmaEnc *)pp; UInt64 nowPos64; SRes res; CSeqOutStreamBuf outStream; outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = False; p->finished = False; p->result = SZ_OK; if (reInit) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); p->rc.outStream = &outStream.funcTable; res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); *unpackSize = (UInt32)(p->nowPos64 - nowPos64); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK; #ifndef _7ZIP_ST Byte allocaDummy[0x300]; allocaDummy[0] = 0; allocaDummy[1] = allocaDummy[0]; #endif for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); if (res != SZ_OK || p->finished != 0) break; if (progress != 0) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK) { res = SZ_ERROR_PROGRESS; break; } } } LzmaEnc_Finish(p); return res; } SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; int i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); for (i = 11; i <= 30; i++) { if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) props[1 + i] = (Byte)(dictSize >> (8 * i)); return SZ_OK; } SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { SRes res; CLzmaEnc *p = (CLzmaEnc *)pp; CSeqOutStreamBuf outStream; LzmaEnc_SetInputBuf(p, src, srcLen); outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; p->rc.outStream = &outStream.funcTable; res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); if (res == SZ_OK) res = LzmaEnc_Encode2(p, progress); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; if (p == 0) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props); if (res == SZ_OK) { res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); if (res == SZ_OK) res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, writeEndMark, progress, alloc, allocBig); } LzmaEnc_Destroy(p, alloc, allocBig); return res; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/LzmaEnc.h0100777000000000000000000000573713761647206020206 0ustar00/* LzmaEnc.h -- LZMA Encoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_ENC_H #define __LZMA_ENC_H #include "7zTypes.h" EXTERN_C_BEGIN #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaEncProps { int level; /* 0 <= level <= 9 */ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version (1 << 12) <= dictSize <= (1 << 30) for 64-bit version default = (1 << 24) */ UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. Encoder uses this value to reduce dictionary size */ int lc; /* 0 <= lc <= 8, default = 3 */ int lp; /* 0 <= lp <= 4, default = 0 */ int pb; /* 0 <= pb <= 4, default = 2 */ int algo; /* 0 - fast, 1 - normal, default = 1 */ int fb; /* 5 <= fb <= 273, default = 32 */ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ int numHashBytes; /* 2, 3 or 4, default = 4 */ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ int numThreads; /* 1 or 2, default = 2 */ } CLzmaEncProps; void LzmaEncProps_Init(CLzmaEncProps *p); void LzmaEncProps_Normalize(CLzmaEncProps *p); UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); /* ---------- CLzmaEncHandle Interface ---------- */ /* LzmaEnc_* functions can return the following exit codes: Returns: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater in props SZ_ERROR_WRITE - Write callback error. SZ_ERROR_PROGRESS - some break from progress callback SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ typedef void * CLzmaEncHandle; CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); /* ---------- One Call Interface ---------- */ /* LzmaEncode Return code: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater SZ_ERROR_OUTPUT_EOF - output buffer overflow SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/MtCoder.c0100777000000000000000000001750513761647206020201 0ustar00/* MtCoder.c -- Multi-thread Coder 2010-09-24 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "MtCoder.h" void LoopThread_Construct(CLoopThread *p) { Thread_Construct(&p->thread); Event_Construct(&p->startEvent); Event_Construct(&p->finishedEvent); } void LoopThread_Close(CLoopThread *p) { Thread_Close(&p->thread); Event_Close(&p->startEvent); Event_Close(&p->finishedEvent); } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp) { CLoopThread *p = (CLoopThread *)pp; for (;;) { if (Event_Wait(&p->startEvent) != 0) return SZ_ERROR_THREAD; if (p->stop) return 0; p->res = p->func(p->param); if (Event_Set(&p->finishedEvent) != 0) return SZ_ERROR_THREAD; } } WRes LoopThread_Create(CLoopThread *p) { p->stop = 0; RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent)); RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent)); return Thread_Create(&p->thread, LoopThreadFunc, p); } WRes LoopThread_StopAndWait(CLoopThread *p) { p->stop = 1; if (Event_Set(&p->startEvent) != 0) return SZ_ERROR_THREAD; return Thread_Wait(&p->thread); } WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); } WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); } static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) { return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; } static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) p->inSizes[i] = p->outSizes[i] = 0; p->totalInSize = p->totalOutSize = 0; p->progress = progress; p->res = SZ_OK; } static void MtProgress_Reinit(CMtProgress *p, unsigned index) { p->inSizes[index] = 0; p->outSizes[index] = 0; } #define UPDATE_PROGRESS(size, prev, total) \ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; } SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize) { SRes res; CriticalSection_Enter(&p->cs); UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize) UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize) if (p->res == SZ_OK) p->res = Progress(p->progress, p->totalInSize, p->totalOutSize); res = p->res; CriticalSection_Leave(&p->cs); return res; } static void MtProgress_SetError(CMtProgress *p, SRes res) { CriticalSection_Enter(&p->cs); if (p->res == SZ_OK) p->res = res; CriticalSection_Leave(&p->cs); } static void MtCoder_SetError(CMtCoder* p, SRes res) { CriticalSection_Enter(&p->cs); if (p->res == SZ_OK) p->res = res; CriticalSection_Leave(&p->cs); } /* ---------- MtThread ---------- */ void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder) { p->mtCoder = mtCoder; p->outBuf = 0; p->inBuf = 0; Event_Construct(&p->canRead); Event_Construct(&p->canWrite); LoopThread_Construct(&p->thread); } #define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; } static void CMtThread_CloseEvents(CMtThread *p) { Event_Close(&p->canRead); Event_Close(&p->canWrite); } static void CMtThread_Destruct(CMtThread *p) { CMtThread_CloseEvents(p); if (Thread_WasCreated(&p->thread.thread)) { LoopThread_StopAndWait(&p->thread); LoopThread_Close(&p->thread); } if (p->mtCoder->alloc) IAlloc_Free(p->mtCoder->alloc, p->outBuf); p->outBuf = 0; if (p->mtCoder->alloc) IAlloc_Free(p->mtCoder->alloc, p->inBuf); p->inBuf = 0; } #define MY_BUF_ALLOC(buf, size, newSize) \ if (buf == 0 || size != newSize) \ { IAlloc_Free(p->mtCoder->alloc, buf); \ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \ if (buf == 0) return SZ_ERROR_MEM; } static SRes CMtThread_Prepare(CMtThread *p) { MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize) MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize) p->stopReading = False; p->stopWriting = False; RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead)); RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite)); return SZ_OK; } static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) { size_t size = *processedSize; *processedSize = 0; while (size != 0) { size_t curSize = size; SRes res = stream->Read(stream, data, &curSize); *processedSize += curSize; data += curSize; size -= curSize; RINOK(res); if (curSize == 0) return SZ_OK; } return SZ_OK; } #define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1] static SRes MtThread_Process(CMtThread *p, Bool *stop) { CMtThread *next; *stop = True; if (Event_Wait(&p->canRead) != 0) return SZ_ERROR_THREAD; next = GET_NEXT_THREAD(p); if (p->stopReading) { next->stopReading = True; return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD; } { size_t size = p->mtCoder->blockSize; size_t destSize = p->outBufSize; RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size)); next->stopReading = *stop = (size != p->mtCoder->blockSize); if (Event_Set(&next->canRead) != 0) return SZ_ERROR_THREAD; RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index, p->outBuf, &destSize, p->inBuf, size, *stop)); MtProgress_Reinit(&p->mtCoder->mtProgress, p->index); if (Event_Wait(&p->canWrite) != 0) return SZ_ERROR_THREAD; if (p->stopWriting) return SZ_ERROR_FAIL; if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize) return SZ_ERROR_WRITE; return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD; } } static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) { CMtThread *p = (CMtThread *)pp; for (;;) { Bool stop; CMtThread *next = GET_NEXT_THREAD(p); SRes res = MtThread_Process(p, &stop); if (res != SZ_OK) { MtCoder_SetError(p->mtCoder, res); MtProgress_SetError(&p->mtCoder->mtProgress, res); next->stopReading = True; next->stopWriting = True; Event_Set(&next->canRead); Event_Set(&next->canWrite); return res; } if (stop) return 0; } } void MtCoder_Construct(CMtCoder* p) { unsigned i; p->alloc = 0; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) { CMtThread *t = &p->threads[i]; t->index = i; CMtThread_Construct(t, p); } CriticalSection_Init(&p->cs); CriticalSection_Init(&p->mtProgress.cs); } void MtCoder_Destruct(CMtCoder* p) { unsigned i; for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) CMtThread_Destruct(&p->threads[i]); CriticalSection_Delete(&p->cs); CriticalSection_Delete(&p->mtProgress.cs); } SRes MtCoder_Code(CMtCoder *p) { unsigned i, numThreads = p->numThreads; SRes res = SZ_OK; p->res = SZ_OK; MtProgress_Init(&p->mtProgress, p->progress); for (i = 0; i < numThreads; i++) { RINOK(CMtThread_Prepare(&p->threads[i])); } for (i = 0; i < numThreads; i++) { CMtThread *t = &p->threads[i]; CLoopThread *lt = &t->thread; if (!Thread_WasCreated(<->thread)) { lt->func = ThreadFunc; lt->param = t; if (LoopThread_Create(lt) != SZ_OK) { res = SZ_ERROR_THREAD; break; } } } if (res == SZ_OK) { unsigned j; for (i = 0; i < numThreads; i++) { CMtThread *t = &p->threads[i]; if (LoopThread_StartSubThread(&t->thread) != SZ_OK) { res = SZ_ERROR_THREAD; p->threads[0].stopReading = True; break; } } Event_Set(&p->threads[0].canWrite); Event_Set(&p->threads[0].canRead); for (j = 0; j < i; j++) LoopThread_WaitSubThread(&p->threads[j].thread); } for (i = 0; i < numThreads; i++) CMtThread_CloseEvents(&p->threads[i]); return (res == SZ_OK) ? p->res : res; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/MtCoder.h0100777000000000000000000000366213761647206020205 0ustar00/* MtCoder.h -- Multi-thread Coder 2009-11-19 : Igor Pavlov : Public domain */ #ifndef __MT_CODER_H #define __MT_CODER_H #include "Threads.h" EXTERN_C_BEGIN typedef struct { CThread thread; CAutoResetEvent startEvent; CAutoResetEvent finishedEvent; int stop; THREAD_FUNC_TYPE func; LPVOID param; THREAD_FUNC_RET_TYPE res; } CLoopThread; void LoopThread_Construct(CLoopThread *p); void LoopThread_Close(CLoopThread *p); WRes LoopThread_Create(CLoopThread *p); WRes LoopThread_StopAndWait(CLoopThread *p); WRes LoopThread_StartSubThread(CLoopThread *p); WRes LoopThread_WaitSubThread(CLoopThread *p); #ifndef _7ZIP_ST #define NUM_MT_CODER_THREADS_MAX 32 #else #define NUM_MT_CODER_THREADS_MAX 1 #endif typedef struct { UInt64 totalInSize; UInt64 totalOutSize; ICompressProgress *progress; SRes res; CCriticalSection cs; UInt64 inSizes[NUM_MT_CODER_THREADS_MAX]; UInt64 outSizes[NUM_MT_CODER_THREADS_MAX]; } CMtProgress; SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize); struct _CMtCoder; typedef struct { struct _CMtCoder *mtCoder; Byte *outBuf; size_t outBufSize; Byte *inBuf; size_t inBufSize; unsigned index; CLoopThread thread; Bool stopReading; Bool stopWriting; CAutoResetEvent canRead; CAutoResetEvent canWrite; } CMtThread; typedef struct { SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize, const Byte *src, size_t srcSize, int finished); } IMtCoderCallback; typedef struct _CMtCoder { size_t blockSize; size_t destBlockSize; unsigned numThreads; ISeqInStream *inStream; ISeqOutStream *outStream; ICompressProgress *progress; ISzAlloc *alloc; IMtCoderCallback *mtCallback; CCriticalSection cs; SRes res; CMtProgress mtProgress; CMtThread threads[NUM_MT_CODER_THREADS_MAX]; } CMtCoder; void MtCoder_Construct(CMtCoder* p); void MtCoder_Destruct(CMtCoder* p); SRes MtCoder_Code(CMtCoder *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Precomp.h0100777000000000000000000000025413761647206020247 0ustar00/* Precomp.h -- StdAfx 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_PRECOMP_H #define __7Z_PRECOMP_H #include "Compiler.h" /* #include "7zTypes.h" */ #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/RotateDefs.h0100777000000000000000000000074113761647206020703 0ustar00/* RotateDefs.h -- Rotate functions 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __ROTATE_DEFS_H #define __ROTATE_DEFS_H #ifdef _MSC_VER #include // #if (_MSC_VER >= 1200) #pragma intrinsic(_rotl) #pragma intrinsic(_rotr) // #endif #define rotlFixed(x, n) _rotl((x), (n)) #define rotrFixed(x, n) _rotr((x), (n)) #else #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) #endif #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Sha256.c0100777000000000000000000001163213761647206017607 0ustar00/* Crypto/Sha256.c -- SHA-256 Hash 2010-06-11 : Igor Pavlov : Public domain This code is based on public domain code from Wei Dai's Crypto++ library. */ #include "Precomp.h" #include "RotateDefs.h" #include "Sha256.h" /* define it for speed optimization */ /* #define _SHA256_UNROLL */ /* #define _SHA256_UNROLL2 */ void Sha256_Init(CSha256 *p) { p->state[0] = 0x6a09e667; p->state[1] = 0xbb67ae85; p->state[2] = 0x3c6ef372; p->state[3] = 0xa54ff53a; p->state[4] = 0x510e527f; p->state[5] = 0x9b05688c; p->state[6] = 0x1f83d9ab; p->state[7] = 0x5be0cd19; p->count = 0; } #define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) #define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) #define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) #define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) #define blk0(i) (W[i] = data[i]) #define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) #define Ch(x,y,z) (z^(x&(y^z))) #define Maj(x,y,z) ((x&y)|(z&(x|y))) #define a(i) T[(0-(i))&7] #define b(i) T[(1-(i))&7] #define c(i) T[(2-(i))&7] #define d(i) T[(3-(i))&7] #define e(i) T[(4-(i))&7] #define f(i) T[(5-(i))&7] #define g(i) T[(6-(i))&7] #define h(i) T[(7-(i))&7] #ifdef _SHA256_UNROLL2 #define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ d += h; h += S0(a) + Maj(a, b, c) #define RX_8(i) \ R(a,b,c,d,e,f,g,h, i); \ R(h,a,b,c,d,e,f,g, i+1); \ R(g,h,a,b,c,d,e,f, i+2); \ R(f,g,h,a,b,c,d,e, i+3); \ R(e,f,g,h,a,b,c,d, i+4); \ R(d,e,f,g,h,a,b,c, i+5); \ R(c,d,e,f,g,h,a,b, i+6); \ R(b,c,d,e,f,g,h,a, i+7) #else #define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) #ifdef _SHA256_UNROLL #define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); #endif #endif static const UInt32 K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; static void Sha256_Transform(UInt32 *state, const UInt32 *data) { UInt32 W[16]; unsigned j; #ifdef _SHA256_UNROLL2 UInt32 a,b,c,d,e,f,g,h; a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; #else UInt32 T[8]; for (j = 0; j < 8; j++) T[j] = state[j]; #endif for (j = 0; j < 64; j += 16) { #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) RX_8(0); RX_8(8); #else unsigned i; for (i = 0; i < 16; i++) { R(i); } #endif } #ifdef _SHA256_UNROLL2 state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; #else for (j = 0; j < 8; j++) state[j] += T[j]; #endif /* Wipe variables */ /* memset(W, 0, sizeof(W)); */ /* memset(T, 0, sizeof(T)); */ } #undef S0 #undef S1 #undef s0 #undef s1 static void Sha256_WriteByteBlock(CSha256 *p) { UInt32 data32[16]; unsigned i; for (i = 0; i < 16; i++) data32[i] = ((UInt32)(p->buffer[i * 4 ]) << 24) + ((UInt32)(p->buffer[i * 4 + 1]) << 16) + ((UInt32)(p->buffer[i * 4 + 2]) << 8) + ((UInt32)(p->buffer[i * 4 + 3])); Sha256_Transform(p->state, data32); } void Sha256_Update(CSha256 *p, const Byte *data, size_t size) { UInt32 curBufferPos = (UInt32)p->count & 0x3F; while (size > 0) { p->buffer[curBufferPos++] = *data++; p->count++; size--; if (curBufferPos == 64) { curBufferPos = 0; Sha256_WriteByteBlock(p); } } } void Sha256_Final(CSha256 *p, Byte *digest) { UInt64 lenInBits = (p->count << 3); UInt32 curBufferPos = (UInt32)p->count & 0x3F; unsigned i; p->buffer[curBufferPos++] = 0x80; while (curBufferPos != (64 - 8)) { curBufferPos &= 0x3F; if (curBufferPos == 0) Sha256_WriteByteBlock(p); p->buffer[curBufferPos++] = 0; } for (i = 0; i < 8; i++) { p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56); lenInBits <<= 8; } Sha256_WriteByteBlock(p); for (i = 0; i < 8; i++) { *digest++ = (Byte)(p->state[i] >> 24); *digest++ = (Byte)(p->state[i] >> 16); *digest++ = (Byte)(p->state[i] >> 8); *digest++ = (Byte)(p->state[i]); } Sha256_Init(p); } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Sha256.h0100777000000000000000000000066613761647206017621 0ustar00/* Sha256.h -- SHA-256 Hash 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __CRYPTO_SHA256_H #define __CRYPTO_SHA256_H #include "7zTypes.h" EXTERN_C_BEGIN #define SHA256_DIGEST_SIZE 32 typedef struct { UInt32 state[8]; UInt64 count; Byte buffer[64]; } CSha256; void Sha256_Init(CSha256 *p); void Sha256_Update(CSha256 *p, const Byte *data, size_t size); void Sha256_Final(CSha256 *p, Byte *digest); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Threads.c0100777000000000000000000000515313761647206020232 0ustar00/* Threads.c -- multithreading library 2013-11-12 : Igor Pavlov : Public domain */ #include "Precomp.h" #ifndef _WIN32_WCE #include #endif #include "Threads.h" static WRes GetError() { DWORD res = GetLastError(); return (res) ? (WRes)(res) : 1; } WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); } WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } WRes HandlePtr_Close(HANDLE *p) { if (*p != NULL) if (!CloseHandle(*p)) return GetError(); *p = NULL; return 0; } WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ #ifdef UNDER_CE DWORD threadId; *p = CreateThread(0, 0, func, param, 0, &threadId); #else unsigned threadId; *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); #endif /* maybe we must use errno here, but probably GetLastError() is also OK. */ return HandleToWRes(*p); } WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) { *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); return HandleToWRes(*p); } WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); return HandleToWRes(*p); } static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) { return Semaphore_Release(p, (LONG)num, NULL); } WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } WRes CriticalSection_Init(CCriticalSection *p) { /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ #ifdef _MSC_VER __try #endif { InitializeCriticalSection(p); /* InitializeCriticalSectionAndSpinCount(p, 0); */ } #ifdef _MSC_VER __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } #endif return 0; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Threads.h0100777000000000000000000000372413761647206020241 0ustar00/* Threads.h -- multithreading library 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_THREADS_H #define __7Z_THREADS_H #ifdef _WIN32 #include #endif #include "7zTypes.h" EXTERN_C_BEGIN WRes HandlePtr_Close(HANDLE *h); WRes Handle_WaitObject(HANDLE h); typedef HANDLE CThread; #define Thread_Construct(p) *(p) = NULL #define Thread_WasCreated(p) (*(p) != NULL) #define Thread_Close(p) HandlePtr_Close(p) #define Thread_Wait(p) Handle_WaitObject(*(p)) typedef #ifdef UNDER_CE DWORD #else unsigned #endif THREAD_FUNC_RET_TYPE; #define THREAD_FUNC_CALL_TYPE MY_STD_CALL #define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); typedef HANDLE CEvent; typedef CEvent CAutoResetEvent; typedef CEvent CManualResetEvent; #define Event_Construct(p) *(p) = NULL #define Event_IsCreated(p) (*(p) != NULL) #define Event_Close(p) HandlePtr_Close(p) #define Event_Wait(p) Handle_WaitObject(*(p)) WRes Event_Set(CEvent *p); WRes Event_Reset(CEvent *p); WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); typedef HANDLE CSemaphore; #define Semaphore_Construct(p) (*p) = NULL #define Semaphore_Close(p) HandlePtr_Close(p) #define Semaphore_Wait(p) Handle_WaitObject(*(p)) WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); WRes Semaphore_Release1(CSemaphore *p); typedef CRITICAL_SECTION CCriticalSection; WRes CriticalSection_Init(CCriticalSection *p); #define CriticalSection_Delete(p) DeleteCriticalSection(p) #define CriticalSection_Enter(p) EnterCriticalSection(p) #define CriticalSection_Leave(p) LeaveCriticalSection(p) EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/Xz.c0100777000000000000000000000355613761647206017246 0ustar00/* Xz.c - Xz 2009-04-15 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #include "Xz.h" #include "XzCrc64.h" Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) { unsigned i = 0; do { buf[i++] = (Byte)((v & 0x7F) | 0x80); v >>= 7; } while (v != 0); buf[i - 1] &= 0x7F; return i; } void Xz_Construct(CXzStream *p) { p->numBlocks = p->numBlocksAllocated = 0; p->blocks = 0; p->flags = 0; } void Xz_Free(CXzStream *p, ISzAlloc *alloc) { alloc->Free(alloc, p->blocks); p->numBlocks = p->numBlocksAllocated = 0; p->blocks = 0; } unsigned XzFlags_GetCheckSize(CXzStreamFlags f) { int t = XzFlags_GetCheckType(f); return (t == 0) ? 0 : (4 << ((t - 1) / 3)); } void XzCheck_Init(CXzCheck *p, int mode) { p->mode = mode; switch (mode) { case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; } } void XzCheck_Update(CXzCheck *p, const void *data, size_t size) { switch (p->mode) { case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; } } int XzCheck_Final(CXzCheck *p, Byte *digest) { switch (p->mode) { case XZ_CHECK_CRC32: SetUi32(digest, CRC_GET_DIGEST(p->crc)); break; case XZ_CHECK_CRC64: { int i; UInt64 v = CRC64_GET_DIGEST(p->crc64); for (i = 0; i < 8; i++, v >>= 8) digest[i] = (Byte)(v & 0xFF); break; } case XZ_CHECK_SHA256: Sha256_Final(&p->sha, digest); break; default: return 0; } return 1; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/Xz.h0100777000000000000000000001633313761647206017250 0ustar00/* Xz.h - Xz interface 2014-12-30 : Igor Pavlov : Public domain */ #ifndef __XZ_H #define __XZ_H #include "Sha256.h" EXTERN_C_BEGIN #define XZ_ID_Subblock 1 #define XZ_ID_Delta 3 #define XZ_ID_X86 4 #define XZ_ID_PPC 5 #define XZ_ID_IA64 6 #define XZ_ID_ARM 7 #define XZ_ID_ARMT 8 #define XZ_ID_SPARC 9 #define XZ_ID_LZMA2 0x21 unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); /* ---------- xz block ---------- */ #define XZ_BLOCK_HEADER_SIZE_MAX 1024 #define XZ_NUM_FILTERS_MAX 4 #define XZ_BF_NUM_FILTERS_MASK 3 #define XZ_BF_PACK_SIZE (1 << 6) #define XZ_BF_UNPACK_SIZE (1 << 7) #define XZ_FILTER_PROPS_SIZE_MAX 20 typedef struct { UInt64 id; UInt32 propsSize; Byte props[XZ_FILTER_PROPS_SIZE_MAX]; } CXzFilter; typedef struct { UInt64 packSize; UInt64 unpackSize; Byte flags; CXzFilter filters[XZ_NUM_FILTERS_MAX]; } CXzBlock; #define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) #define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) #define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) SRes XzBlock_Parse(CXzBlock *p, const Byte *header); SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes); /* ---------- xz stream ---------- */ #define XZ_SIG_SIZE 6 #define XZ_FOOTER_SIG_SIZE 2 extern Byte XZ_SIG[XZ_SIG_SIZE]; extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; #define XZ_STREAM_FLAGS_SIZE 2 #define XZ_STREAM_CRC_SIZE 4 #define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) #define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) #define XZ_CHECK_MASK 0xF #define XZ_CHECK_NO 0 #define XZ_CHECK_CRC32 1 #define XZ_CHECK_CRC64 4 #define XZ_CHECK_SHA256 10 typedef struct { int mode; UInt32 crc; UInt64 crc64; CSha256 sha; } CXzCheck; void XzCheck_Init(CXzCheck *p, int mode); void XzCheck_Update(CXzCheck *p, const void *data, size_t size); int XzCheck_Final(CXzCheck *p, Byte *digest); typedef UInt16 CXzStreamFlags; #define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) #define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) #define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) unsigned XzFlags_GetCheckSize(CXzStreamFlags f); SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); typedef struct { UInt64 unpackSize; UInt64 totalSize; } CXzBlockSizes; typedef struct { CXzStreamFlags flags; size_t numBlocks; size_t numBlocksAllocated; CXzBlockSizes *blocks; UInt64 startOffset; } CXzStream; void Xz_Construct(CXzStream *p); void Xz_Free(CXzStream *p, ISzAlloc *alloc); #define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) UInt64 Xz_GetUnpackSize(const CXzStream *p); UInt64 Xz_GetPackSize(const CXzStream *p); typedef struct { size_t num; size_t numAllocated; CXzStream *streams; } CXzs; void Xzs_Construct(CXzs *p); void Xzs_Free(CXzs *p, ISzAlloc *alloc); SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc); UInt64 Xzs_GetNumBlocks(const CXzs *p); UInt64 Xzs_GetUnpackSize(const CXzs *p); typedef enum { CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ CODER_STATUS_NOT_FINISHED, /* stream was not finished */ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ } ECoderStatus; typedef enum { CODER_FINISH_ANY, /* finish at any point */ CODER_FINISH_END /* block must be finished at the end */ } ECoderFinishMode; typedef struct _IStateCoder { void *p; void (*Free)(void *p, ISzAlloc *alloc); SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc); void (*Init)(void *p); SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished); } IStateCoder; #define MIXCODER_NUM_FILTERS_MAX 4 typedef struct { ISzAlloc *alloc; Byte *buf; int numCoders; int finished[MIXCODER_NUM_FILTERS_MAX - 1]; size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; } CMixCoder; void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc); void MixCoder_Free(CMixCoder *p); void MixCoder_Init(CMixCoder *p); SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId); SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, ECoderStatus *status); typedef enum { XZ_STATE_STREAM_HEADER, XZ_STATE_STREAM_INDEX, XZ_STATE_STREAM_INDEX_CRC, XZ_STATE_STREAM_FOOTER, XZ_STATE_STREAM_PADDING, XZ_STATE_BLOCK_HEADER, XZ_STATE_BLOCK, XZ_STATE_BLOCK_FOOTER } EXzState; typedef struct { EXzState state; UInt32 pos; unsigned alignPos; unsigned indexPreSize; CXzStreamFlags streamFlags; UInt32 blockHeaderSize; UInt64 packSize; UInt64 unpackSize; UInt64 numBlocks; UInt64 indexSize; UInt64 indexPos; UInt64 padSize; UInt64 numStartedStreams; UInt64 numFinishedStreams; UInt64 numTotalBlocks; UInt32 crc; CMixCoder decoder; CXzBlock block; CXzCheck check; CSha256 sha; Byte shaDigest[SHA256_DIGEST_SIZE]; Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; } CXzUnpacker; void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc); void XzUnpacker_Init(CXzUnpacker *p); void XzUnpacker_Free(CXzUnpacker *p); /* finishMode: It has meaning only if the decoding reaches output limit (*destLen). CODER_FINISH_ANY - use smallest number of input bytes CODER_FINISH_END - read EndOfStream marker after decoding Returns: SZ_OK status: CODER_STATUS_NOT_FINISHED, CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams, call XzUnpacker_IsStreamWasFinished to check that current stream was finished SZ_ERROR_MEM - Memory allocation error SZ_ERROR_DATA - Data error SZ_ERROR_UNSUPPORTED - Unsupported method or method properties SZ_ERROR_CRC - CRC error // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: - xz Stream Signature failure - CRC32 of xz Stream Header is failed - The size of Stream padding is not multiple of four bytes. It's possible to get that error, if xz stream was finished and the stream contains some another data. In that case you can call XzUnpacker_GetExtraSize() function to get real size of xz stream. */ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status); Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p); /* Call XzUnpacker_GetExtraSize after XzUnpacker_Code function to detect real size of xz stream in two cases: XzUnpacker_Code() returns: res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT res == SZ_ERROR_NO_ARCHIVE */ UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzCrc64.c0100777000000000000000000000405113761647206020037 0ustar00/* XzCrc64.c -- CRC64 calculation 2011-06-28 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "XzCrc64.h" #include "CpuArch.h" #define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) #ifdef MY_CPU_LE #define CRC_NUM_TABLES 4 #else #define CRC_NUM_TABLES 5 #define CRC_UINT64_SWAP(v) \ ((v >> 56) | \ ((v >> 40) & ((UInt64)0xFF << 8)) | \ ((v >> 24) & ((UInt64)0xFF << 16)) | \ ((v >> 8) & ((UInt64)0xFF << 24)) | \ ((v << 8) & ((UInt64)0xFF << 32)) | \ ((v << 24) & ((UInt64)0xFF << 40)) | \ ((v << 40) & ((UInt64)0xFF << 48)) | \ (v << 56)) UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); #endif #ifndef MY_CPU_BE UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); #endif typedef UInt64 (MY_FAST_CALL *CRC_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); static CRC_FUNC g_Crc64Update; UInt64 g_Crc64Table[256 * CRC_NUM_TABLES]; UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) { return g_Crc64Update(v, data, size, g_Crc64Table); } UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) { return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; } void MY_FAST_CALL Crc64GenerateTable() { UInt32 i; for (i = 0; i < 256; i++) { UInt64 r = i; unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrc64Poly & ~((r & 1) - 1)); g_Crc64Table[i] = r; } for (; i < 256 * CRC_NUM_TABLES; i++) { UInt64 r = g_Crc64Table[i - 256]; g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); } #ifdef MY_CPU_LE g_Crc64Update = XzCrc64UpdateT4; #else { #ifndef MY_CPU_BE UInt32 k = 1; if (*(const Byte *)&k == 1) g_Crc64Update = XzCrc64UpdateT4; else #endif { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { UInt64 x = g_Crc64Table[i - 256]; g_Crc64Table[i] = CRC_UINT64_SWAP(x); } g_Crc64Update = XzCrc64UpdateT1_BeT4; } } #endif } qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzCrc64.h0100777000000000000000000000114713761647206020047 0ustar00/* XzCrc64.h -- CRC64 calculation 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __XZ_CRC64_H #define __XZ_CRC64_H #include #include "7zTypes.h" EXTERN_C_BEGIN extern UInt64 g_Crc64Table[]; void MY_FAST_CALL Crc64GenerateTable(void); #define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) #define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzCrc64Opt.c0100777000000000000000000000350413761647206020524 0ustar00/* XzCrc64Opt.c -- CRC64 calculation 2011-06-28 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #ifndef MY_CPU_BE UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)v ^ *(const UInt32 *)p; v = (v >> 32) ^ table[0x300 + ((d ) & 0xFF)] ^ table[0x200 + ((d >> 8) & 0xFF)] ^ table[0x100 + ((d >> 16) & 0xFF)] ^ table[0x000 + ((d >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif #ifndef MY_CPU_LE #define CRC_UINT64_SWAP(v) \ ((v >> 56) | \ ((v >> 40) & ((UInt64)0xFF << 8)) | \ ((v >> 24) & ((UInt64)0xFF << 16)) | \ ((v >> 8) & ((UInt64)0xFF << 24)) | \ ((v << 8) & ((UInt64)0xFF << 32)) | \ ((v << 24) & ((UInt64)0xFF << 40)) | \ ((v << 40) & ((UInt64)0xFF << 48)) | \ (v << 56)) UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); v = CRC_UINT64_SWAP(v); table += 0x100; for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p; v = (v << 32) ^ table[0x000 + ((d ) & 0xFF)] ^ table[0x100 + ((d >> 8) & 0xFF)] ^ table[0x200 + ((d >> 16) & 0xFF)] ^ table[0x300 + ((d >> 24))]; } table -= 0x100; v = CRC_UINT64_SWAP(v); for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); return v; } #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzDec.c0100777000000000000000000005366213761647206017665 0ustar00/* XzDec.c -- Xz Decode 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" /* #define XZ_DUMP */ #ifdef XZ_DUMP #include #endif #include #include #include "7zCrc.h" #include "Alloc.h" #include "Bra.h" #include "CpuArch.h" #include "Delta.h" #include "Lzma2Dec.h" #ifdef USE_SUBBLOCK #include "Bcj3Dec.c" #include "SbDec.c" #endif #include "Xz.h" #define XZ_CHECK_SIZE_MAX 64 #define CODER_BUF_SIZE (1 << 17) unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) { int i, limit; *value = 0; limit = (maxSize > 9) ? 9 : (int)maxSize; for (i = 0; i < limit;) { Byte b = p[i]; *value |= (UInt64)(b & 0x7F) << (7 * i++); if ((b & 0x80) == 0) return (b == 0 && i != 1) ? 0 : i; } return 0; } /* ---------- BraState ---------- */ #define BRA_BUF_SIZE (1 << 14) typedef struct { size_t bufPos; size_t bufConv; size_t bufTotal; UInt32 methodId; int encodeMode; UInt32 delta; UInt32 ip; UInt32 x86State; Byte deltaState[DELTA_STATE_SIZE]; Byte buf[BRA_BUF_SIZE]; } CBraState; void BraState_Free(void *pp, ISzAlloc *alloc) { alloc->Free(alloc, pp); } SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { CBraState *p = ((CBraState *)pp); alloc = alloc; p->ip = 0; if (p->methodId == XZ_ID_Delta) { if (propSize != 1) return SZ_ERROR_UNSUPPORTED; p->delta = (unsigned)props[0] + 1; } else { if (propSize == 4) { UInt32 v = GetUi32(props); switch(p->methodId) { case XZ_ID_PPC: case XZ_ID_ARM: case XZ_ID_SPARC: if ((v & 3) != 0) return SZ_ERROR_UNSUPPORTED; break; case XZ_ID_ARMT: if ((v & 1) != 0) return SZ_ERROR_UNSUPPORTED; break; case XZ_ID_IA64: if ((v & 0xF) != 0) return SZ_ERROR_UNSUPPORTED; break; } p->ip = v; } else if (propSize != 0) return SZ_ERROR_UNSUPPORTED; } return SZ_OK; } void BraState_Init(void *pp) { CBraState *p = ((CBraState *)pp); p->bufPos = p->bufConv = p->bufTotal = 0; x86_Convert_Init(p->x86State); if (p->methodId == XZ_ID_Delta) Delta_Init(p->deltaState); } #define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break; static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { CBraState *p = ((CBraState *)pp); SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; *destLen = 0; *srcLen = 0; finishMode = finishMode; *wasFinished = 0; while (destLenOrig > 0) { if (p->bufPos != p->bufConv) { size_t curSize = p->bufConv - p->bufPos; if (curSize > destLenOrig) curSize = destLenOrig; memcpy(dest, p->buf + p->bufPos, curSize); p->bufPos += curSize; *destLen += curSize; dest += curSize; destLenOrig -= curSize; continue; } p->bufTotal -= p->bufPos; memmove(p->buf, p->buf + p->bufPos, p->bufTotal); p->bufPos = 0; p->bufConv = 0; { size_t curSize = BRA_BUF_SIZE - p->bufTotal; if (curSize > srcLenOrig) curSize = srcLenOrig; memcpy(p->buf + p->bufTotal, src, curSize); *srcLen += curSize; src += curSize; srcLenOrig -= curSize; p->bufTotal += curSize; } if (p->bufTotal == 0) break; switch(p->methodId) { case XZ_ID_Delta: if (p->encodeMode) Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal); else Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal); p->bufConv = p->bufTotal; break; case XZ_ID_X86: p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode); break; CASE_BRA_CONV(PPC) CASE_BRA_CONV(IA64) CASE_BRA_CONV(ARM) CASE_BRA_CONV(ARMT) CASE_BRA_CONV(SPARC) default: return SZ_ERROR_UNSUPPORTED; } p->ip += (UInt32)p->bufConv; if (p->bufConv == 0) { if (!srcWasFinished) break; p->bufConv = p->bufTotal; } } if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished) *wasFinished = 1; return SZ_OK; } SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc) { CBraState *decoder; if (id != XZ_ID_Delta && id != XZ_ID_X86 && id != XZ_ID_PPC && id != XZ_ID_IA64 && id != XZ_ID_ARM && id != XZ_ID_ARMT && id != XZ_ID_SPARC) return SZ_ERROR_UNSUPPORTED; p->p = 0; decoder = (CBraState *)alloc->Alloc(alloc, sizeof(CBraState)); if (decoder == 0) return SZ_ERROR_MEM; decoder->methodId = (UInt32)id; decoder->encodeMode = encodeMode; p->p = decoder; p->Free = BraState_Free; p->SetProps = BraState_SetProps; p->Init = BraState_Init; p->Code = BraState_Code; return SZ_OK; } /* ---------- SbState ---------- */ #ifdef USE_SUBBLOCK static void SbState_Free(void *pp, ISzAlloc *alloc) { CSbDec *p = (CSbDec *)pp; SbDec_Free(p); alloc->Free(alloc, pp); } static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { pp = pp; props = props; alloc = alloc; return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; } static void SbState_Init(void *pp) { SbDec_Init((CSbDec *)pp); } static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { CSbDec *p = (CSbDec *)pp; SRes res; srcWasFinished = srcWasFinished; p->dest = dest; p->destLen = *destLen; p->src = src; p->srcLen = *srcLen; p->finish = finishMode; /* change it */ res = SbDec_Decode((CSbDec *)pp); *destLen -= p->destLen; *srcLen -= p->srcLen; *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ return res; } SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) { CSbDec *decoder; p->p = 0; decoder = alloc->Alloc(alloc, sizeof(CSbDec)); if (decoder == 0) return SZ_ERROR_MEM; p->p = decoder; p->Free = SbState_Free; p->SetProps = SbState_SetProps; p->Init = SbState_Init; p->Code = SbState_Code; SbDec_Construct(decoder); SbDec_SetAlloc(decoder, alloc); return SZ_OK; } #endif /* ---------- Lzma2State ---------- */ static void Lzma2State_Free(void *pp, ISzAlloc *alloc) { Lzma2Dec_Free((CLzma2Dec *)pp, alloc); alloc->Free(alloc, pp); } static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { if (propSize != 1) return SZ_ERROR_UNSUPPORTED; return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc); } static void Lzma2State_Init(void *pp) { Lzma2Dec_Init((CLzma2Dec *)pp); } static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished) { ELzmaStatus status; /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status); srcWasFinished = srcWasFinished; *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK); return res; } static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc) { CLzma2Dec *decoder = (CLzma2Dec *)alloc->Alloc(alloc, sizeof(CLzma2Dec)); p->p = decoder; if (decoder == 0) return SZ_ERROR_MEM; p->Free = Lzma2State_Free; p->SetProps = Lzma2State_SetProps; p->Init = Lzma2State_Init; p->Code = Lzma2State_Code; Lzma2Dec_Construct(decoder); return SZ_OK; } void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc) { int i; p->alloc = alloc; p->buf = 0; p->numCoders = 0; for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) p->coders[i].p = NULL; } void MixCoder_Free(CMixCoder *p) { int i; for (i = 0; i < p->numCoders; i++) { IStateCoder *sc = &p->coders[i]; if (p->alloc && sc->p) sc->Free(sc->p, p->alloc); } p->numCoders = 0; if (p->buf) { p->alloc->Free(p->alloc, p->buf); p->buf = 0; /* 9.31: the BUG was fixed */ } } void MixCoder_Init(CMixCoder *p) { int i; for (i = 0; i < p->numCoders - 1; i++) { p->size[i] = 0; p->pos[i] = 0; p->finished[i] = 0; } for (i = 0; i < p->numCoders; i++) { IStateCoder *coder = &p->coders[i]; coder->Init(coder->p); } } SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId) { IStateCoder *sc = &p->coders[coderIndex]; p->ids[coderIndex] = methodId; switch(methodId) { case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc); #ifdef USE_SUBBLOCK case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); #endif } if (coderIndex == 0) return SZ_ERROR_UNSUPPORTED; return BraState_SetFromMethod(sc, methodId, 0, p->alloc); } SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, ECoderStatus *status) { SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; Bool allFinished = True; *destLen = 0; *srcLen = 0; *status = CODER_STATUS_NOT_FINISHED; if (p->buf == 0) { p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); if (p->buf == 0) return SZ_ERROR_MEM; } if (p->numCoders != 1) finishMode = CODER_FINISH_ANY; for (;;) { Bool processed = False; int i; /* if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) break; */ for (i = 0; i < p->numCoders; i++) { SRes res; IStateCoder *coder = &p->coders[i]; Byte *destCur; SizeT destLenCur, srcLenCur; const Byte *srcCur; int srcFinishedCur; int encodingWasFinished; if (i == 0) { srcCur = src; srcLenCur = srcLenOrig - *srcLen; srcFinishedCur = srcWasFinished; } else { srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1]; srcLenCur = p->size[i - 1] - p->pos[i - 1]; srcFinishedCur = p->finished[i - 1]; } if (i == p->numCoders - 1) { destCur = dest; destLenCur = destLenOrig - *destLen; } else { if (p->pos[i] != p->size[i]) continue; destCur = p->buf + (CODER_BUF_SIZE * i); destLenCur = CODER_BUF_SIZE; } res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished); if (!encodingWasFinished) allFinished = False; if (i == 0) { *srcLen += srcLenCur; src += srcLenCur; } else { p->pos[i - 1] += srcLenCur; } if (i == p->numCoders - 1) { *destLen += destLenCur; dest += destLenCur; } else { p->size[i] = destLenCur; p->pos[i] = 0; p->finished[i] = encodingWasFinished; } if (res != SZ_OK) return res; if (destLenCur != 0 || srcLenCur != 0) processed = True; } if (!processed) break; } if (allFinished) *status = CODER_STATUS_FINISHED_WITH_MARK; return SZ_OK; } SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) { *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) return SZ_ERROR_NO_ARCHIVE; return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; } static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) { return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) && (GetUi32(buf) == CrcCalc(buf + 4, 6) && flags == GetBe16(buf + 8) && memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0); } #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } SRes XzBlock_Parse(CXzBlock *p, const Byte *header) { unsigned pos; int numFilters, i; UInt32 headerSize = (UInt32)header[0] << 2; if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) return SZ_ERROR_ARCHIVE; pos = 1; if (pos == headerSize) return SZ_ERROR_ARCHIVE; p->flags = header[pos++]; if (XzBlock_HasPackSize(p)) { READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) return SZ_ERROR_ARCHIVE; } if (XzBlock_HasUnpackSize(p)) READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); numFilters = XzBlock_GetNumFilters(p); for (i = 0; i < numFilters; i++) { CXzFilter *filter = p->filters + i; UInt64 size; READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); READ_VARINT_AND_CHECK(header, pos, headerSize, &size); if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) return SZ_ERROR_ARCHIVE; filter->propsSize = (UInt32)size; memcpy(filter->props, header + pos, (size_t)size); pos += (unsigned)size; #ifdef XZ_DUMP printf("\nf[%d] = %2X: ", i, filter->id); { int i; for (i = 0; i < size; i++) printf(" %2X", filter->props[i]); } #endif } while (pos < headerSize) if (header[pos++] != 0) return SZ_ERROR_ARCHIVE; return SZ_OK; } SRes XzDec_Init(CMixCoder *p, const CXzBlock *block) { int i; Bool needReInit = True; int numFilters = XzBlock_GetNumFilters(block); if (numFilters == p->numCoders) { for (i = 0; i < numFilters; i++) if (p->ids[i] != block->filters[numFilters - 1 - i].id) break; needReInit = (i != numFilters); } if (needReInit) { MixCoder_Free(p); p->numCoders = numFilters; for (i = 0; i < numFilters; i++) { const CXzFilter *f = &block->filters[numFilters - 1 - i]; RINOK(MixCoder_SetFromMethod(p, i, f->id)); } } for (i = 0; i < numFilters; i++) { const CXzFilter *f = &block->filters[numFilters - 1 - i]; IStateCoder *sc = &p->coders[i]; RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); } MixCoder_Init(p); return SZ_OK; } void XzUnpacker_Init(CXzUnpacker *p) { p->state = XZ_STATE_STREAM_HEADER; p->pos = 0; p->numStartedStreams = 0; p->numFinishedStreams = 0; p->numTotalBlocks = 0; p->padSize = 0; } void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc) { MixCoder_Construct(&p->decoder, alloc); XzUnpacker_Init(p); } void XzUnpacker_Free(CXzUnpacker *p) { MixCoder_Free(&p->decoder); } SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status) { SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; *destLen = 0; *srcLen = 0; *status = CODER_STATUS_NOT_SPECIFIED; for (;;) { SizeT srcRem = srcLenOrig - *srcLen; if (p->state == XZ_STATE_BLOCK) { SizeT destLen2 = destLenOrig - *destLen; SizeT srcLen2 = srcLenOrig - *srcLen; SRes res; if (srcLen2 == 0 && destLen2 == 0) { *status = CODER_STATUS_NOT_FINISHED; return SZ_OK; } res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status); XzCheck_Update(&p->check, dest, destLen2); (*srcLen) += srcLen2; src += srcLen2; p->packSize += srcLen2; (*destLen) += destLen2; dest += destLen2; p->unpackSize += destLen2; RINOK(res); if (*status == CODER_STATUS_FINISHED_WITH_MARK) { Byte temp[32]; unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags)); num += Xz_WriteVarInt(temp + num, p->unpackSize); Sha256_Update(&p->sha, temp, num); p->indexSize += num; p->numBlocks++; p->state = XZ_STATE_BLOCK_FOOTER; p->pos = 0; p->alignPos = 0; } else if (srcLen2 == 0 && destLen2 == 0) return SZ_OK; continue; } if (srcRem == 0) { *status = CODER_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } switch (p->state) { case XZ_STATE_STREAM_HEADER: { if (p->pos < XZ_STREAM_HEADER_SIZE) { if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) return SZ_ERROR_NO_ARCHIVE; p->buf[p->pos++] = *src++; (*srcLen)++; } else { RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); p->numStartedStreams++; p->state = XZ_STATE_BLOCK_HEADER; Sha256_Init(&p->sha); p->indexSize = 0; p->numBlocks = 0; p->pos = 0; } break; } case XZ_STATE_BLOCK_HEADER: { if (p->pos == 0) { p->buf[p->pos++] = *src++; (*srcLen)++; if (p->buf[0] == 0) { p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); p->indexPos = p->indexPreSize; p->indexSize += p->indexPreSize; Sha256_Final(&p->sha, p->shaDigest); Sha256_Init(&p->sha); p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); p->state = XZ_STATE_STREAM_INDEX; } p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; } else if (p->pos != p->blockHeaderSize) { UInt32 cur = p->blockHeaderSize - p->pos; if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; } else { RINOK(XzBlock_Parse(&p->block, p->buf)); p->numTotalBlocks++; p->state = XZ_STATE_BLOCK; p->packSize = 0; p->unpackSize = 0; XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); RINOK(XzDec_Init(&p->decoder, &p->block)); } break; } case XZ_STATE_BLOCK_FOOTER: { if (((p->packSize + p->alignPos) & 3) != 0) { (*srcLen)++; p->alignPos++; if (*src++ != 0) return SZ_ERROR_CRC; } else { UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); UInt32 cur = checkSize - p->pos; if (cur != 0) { if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; } else { Byte digest[XZ_CHECK_SIZE_MAX]; p->state = XZ_STATE_BLOCK_HEADER; p->pos = 0; if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) return SZ_ERROR_CRC; } } break; } case XZ_STATE_STREAM_INDEX: { if (p->pos < p->indexPreSize) { (*srcLen)++; if (*src++ != p->buf[p->pos++]) return SZ_ERROR_CRC; } else { if (p->indexPos < p->indexSize) { UInt64 cur = p->indexSize - p->indexPos; if (srcRem > cur) srcRem = (SizeT)cur; p->crc = CrcUpdate(p->crc, src, srcRem); Sha256_Update(&p->sha, src, srcRem); (*srcLen) += srcRem; src += srcRem; p->indexPos += srcRem; } else if ((p->indexPos & 3) != 0) { Byte b = *src++; p->crc = CRC_UPDATE_BYTE(p->crc, b); (*srcLen)++; p->indexPos++; p->indexSize++; if (b != 0) return SZ_ERROR_CRC; } else { Byte digest[SHA256_DIGEST_SIZE]; p->state = XZ_STATE_STREAM_INDEX_CRC; p->indexSize += 4; p->pos = 0; Sha256_Final(&p->sha, digest); if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) return SZ_ERROR_CRC; } } break; } case XZ_STATE_STREAM_INDEX_CRC: { if (p->pos < 4) { (*srcLen)++; p->buf[p->pos++] = *src++; } else { p->state = XZ_STATE_STREAM_FOOTER; p->pos = 0; if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf)) return SZ_ERROR_CRC; } break; } case XZ_STATE_STREAM_FOOTER: { UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; if (cur > srcRem) cur = (UInt32)srcRem; memcpy(p->buf + p->pos, src, cur); p->pos += cur; (*srcLen) += cur; src += cur; if (p->pos == XZ_STREAM_FOOTER_SIZE) { p->state = XZ_STATE_STREAM_PADDING; p->numFinishedStreams++; p->padSize = 0; if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) return SZ_ERROR_CRC; } break; } case XZ_STATE_STREAM_PADDING: { if (*src != 0) { if (((UInt32)p->padSize & 3) != 0) return SZ_ERROR_NO_ARCHIVE; p->pos = 0; p->state = XZ_STATE_STREAM_HEADER; } else { (*srcLen)++; src++; p->padSize++; } break; } case XZ_STATE_BLOCK: break; /* to disable GCC warning */ } } /* if (p->state == XZ_STATE_FINISHED) *status = CODER_STATUS_FINISHED_WITH_MARK; return SZ_OK; */ } Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p) { return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); } UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p) { UInt64 num = 0; if (p->state == XZ_STATE_STREAM_PADDING) num += p->padSize; else if (p->state == XZ_STATE_STREAM_HEADER) num += p->padSize + p->pos; return num; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzEnc.c0100777000000000000000000003154513761647206017673 0ustar00/* XzEnc.c -- Xz Encode 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include #include "7zCrc.h" #include "Alloc.h" #include "Bra.h" #include "CpuArch.h" #ifdef USE_SUBBLOCK #include "Bcj3Enc.c" #include "SbFind.c" #include "SbEnc.c" #endif #include "XzEnc.h" static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); } static void SzBigFree(void *p, void *address) { p = p; BigFree(address); } static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } static void SzFree(void *p, void *address) { p = p; MyFree(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; #define XzBlock_ClearFlags(p) (p)->flags = 0; #define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1); #define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size) { return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; } static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc) { *crc = CrcUpdate(*crc, buf, size); return WriteBytes(s, buf, size); } SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) { UInt32 crc; Byte header[XZ_STREAM_HEADER_SIZE]; memcpy(header, XZ_SIG, XZ_SIG_SIZE); header[XZ_SIG_SIZE] = (Byte)(f >> 8); header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); } SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) { Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; unsigned pos = 1; int numFilters, i; header[pos++] = p->flags; if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); numFilters = XzBlock_GetNumFilters(p); for (i = 0; i < numFilters; i++) { const CXzFilter *f = &p->filters[i]; pos += Xz_WriteVarInt(header + pos, f->id); pos += Xz_WriteVarInt(header + pos, f->propsSize); memcpy(header + pos, f->props, f->propsSize); pos += f->propsSize; } while((pos & 3) != 0) header[pos++] = 0; header[0] = (Byte)(pos >> 2); SetUi32(header + pos, CrcCalc(header, pos)); return WriteBytes(s, header, pos + 4); } SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s) { Byte buf[32]; UInt64 globalPos; { UInt32 crc = CRC_INIT_VAL; unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); size_t i; globalPos = pos; buf[0] = 0; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); for (i = 0; i < p->numBlocks; i++) { const CXzBlockSizes *block = &p->blocks[i]; pos = Xz_WriteVarInt(buf, block->totalSize); pos += Xz_WriteVarInt(buf + pos, block->unpackSize); globalPos += pos; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); } pos = ((unsigned)globalPos & 3); if (pos != 0) { buf[0] = buf[1] = buf[2] = 0; RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc)); globalPos += 4 - pos; } { SetUi32(buf, CRC_GET_DIGEST(crc)); RINOK(WriteBytes(s, buf, 4)); globalPos += 4; } } { UInt32 indexSize = (UInt32)((globalPos >> 2) - 1); SetUi32(buf + 4, indexSize); buf[8] = (Byte)(p->flags >> 8); buf[9] = (Byte)(p->flags & 0xFF); SetUi32(buf, CrcCalc(buf + 4, 6)); memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE); return WriteBytes(s, buf, 12); } } SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc) { if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks) { size_t num = (p->numBlocks + 1) * 2; size_t newSize = sizeof(CXzBlockSizes) * num; CXzBlockSizes *blocks; if (newSize / sizeof(CXzBlockSizes) != num) return SZ_ERROR_MEM; blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize); if (blocks == 0) return SZ_ERROR_MEM; if (p->numBlocks != 0) { memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes)); Xz_Free(p, alloc); } p->blocks = blocks; p->numBlocksAllocated = num; } { CXzBlockSizes *block = &p->blocks[p->numBlocks++]; block->totalSize = totalSize; block->unpackSize = unpackSize; } return SZ_OK; } /* ---------- CSeqCheckInStream ---------- */ typedef struct { ISeqInStream p; ISeqInStream *realStream; UInt64 processed; CXzCheck check; } CSeqCheckInStream; void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode) { p->processed = 0; XzCheck_Init(&p->check, mode); } void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) { XzCheck_Final(&p->check, digest); } static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size) { CSeqCheckInStream *p = (CSeqCheckInStream *)pp; SRes res = p->realStream->Read(p->realStream, data, size); XzCheck_Update(&p->check, data, *size); p->processed += *size; return res; } /* ---------- CSeqSizeOutStream ---------- */ typedef struct { ISeqOutStream p; ISeqOutStream *realStream; UInt64 processed; } CSeqSizeOutStream; static size_t MyWrite(void *pp, const void *data, size_t size) { CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp; size = p->realStream->Write(p->realStream, data, size); p->processed += size; return size; } /* ---------- CSeqInFilter ---------- */ #define FILTER_BUF_SIZE (1 << 20) typedef struct { ISeqInStream p; ISeqInStream *realStream; IStateCoder StateCoder; Byte *buf; size_t curPos; size_t endPos; int srcWasFinished; } CSeqInFilter; static SRes SeqInFilter_Read(void *pp, void *data, size_t *size) { CSeqInFilter *p = (CSeqInFilter *)pp; size_t sizeOriginal = *size; if (sizeOriginal == 0) return SZ_OK; *size = 0; for (;;) { if (!p->srcWasFinished && p->curPos == p->endPos) { p->curPos = 0; p->endPos = FILTER_BUF_SIZE; RINOK(p->realStream->Read(p->realStream, p->buf, &p->endPos)); if (p->endPos == 0) p->srcWasFinished = 1; } { SizeT srcLen = p->endPos - p->curPos; int wasFinished; SRes res; *size = sizeOriginal; res = p->StateCoder.Code(p->StateCoder.p, data, size, p->buf + p->curPos, &srcLen, p->srcWasFinished, CODER_FINISH_ANY, &wasFinished); p->curPos += srcLen; if (*size != 0 || srcLen == 0 || res != 0) return res; } } } static void SeqInFilter_Construct(CSeqInFilter *p) { p->buf = NULL; p->p.Read = SeqInFilter_Read; } static void SeqInFilter_Free(CSeqInFilter *p) { if (p->buf) { g_Alloc.Free(&g_Alloc, p->buf); p->buf = NULL; } } SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc); static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props) { if (!p->buf) { p->buf = g_Alloc.Alloc(&g_Alloc, FILTER_BUF_SIZE); if (!p->buf) return SZ_ERROR_MEM; } p->curPos = p->endPos = 0; p->srcWasFinished = 0; RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, &g_Alloc)); RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, &g_Alloc)); p->StateCoder.Init(p->StateCoder.p); return SZ_OK; } /* ---------- CSbEncInStream ---------- */ #ifdef USE_SUBBLOCK typedef struct { ISeqInStream p; ISeqInStream *inStream; CSbEnc enc; } CSbEncInStream; static SRes SbEncInStream_Read(void *pp, void *data, size_t *size) { CSbEncInStream *p = (CSbEncInStream *)pp; size_t sizeOriginal = *size; if (sizeOriginal == 0) return S_OK; for (;;) { if (p->enc.needRead && !p->enc.readWasFinished) { size_t processed = p->enc.needReadSizeMax; RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); p->enc.readPos += processed; if (processed == 0) { p->enc.readWasFinished = True; p->enc.isFinalFinished = True; } p->enc.needRead = False; } *size = sizeOriginal; RINOK(SbEnc_Read(&p->enc, data, size)); if (*size != 0 || !p->enc.needRead) return S_OK; } } void SbEncInStream_Construct(CSbEncInStream *p, ISzAlloc *alloc) { SbEnc_Construct(&p->enc, alloc); p->p.Read = SbEncInStream_Read; } SRes SbEncInStream_Init(CSbEncInStream *p) { return SbEnc_Init(&p->enc); } void SbEncInStream_Free(CSbEncInStream *p) { SbEnc_Free(&p->enc); } #endif typedef struct { CLzma2EncHandle lzma2; #ifdef USE_SUBBLOCK CSbEncInStream sb; #endif CSeqInFilter filter; ISzAlloc *alloc; ISzAlloc *bigAlloc; } CLzma2WithFilters; static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc) { p->alloc = alloc; p->bigAlloc = bigAlloc; p->lzma2 = NULL; #ifdef USE_SUBBLOCK SbEncInStream_Construct(&p->sb, alloc); #endif SeqInFilter_Construct(&p->filter); } static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p) { p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc); if (p->lzma2 == 0) return SZ_ERROR_MEM; return SZ_OK; } static void Lzma2WithFilters_Free(CLzma2WithFilters *p) { SeqInFilter_Free(&p->filter); #ifdef USE_SUBBLOCK SbEncInStream_Free(&p->sb); #endif if (p->lzma2) { Lzma2Enc_Destroy(p->lzma2); p->lzma2 = NULL; } } void XzProps_Init(CXzProps *p) { p->lzma2Props = 0; p->filterProps = 0; p->checkId = XZ_CHECK_CRC32; } void XzFilterProps_Init(CXzFilterProps *p) { p->id = 0; p->delta = 0; p->ip= 0; p->ipDefined = False; } static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf, ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress) { xz->flags = (Byte)props->checkId; RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, props->lzma2Props)); RINOK(Xz_WriteHeader(xz->flags, outStream)); { CSeqCheckInStream checkInStream; CSeqSizeOutStream seqSizeOutStream; CXzBlock block; int filterIndex = 0; CXzFilter *filter = NULL; const CXzFilterProps *fp = props->filterProps; XzBlock_ClearFlags(&block); XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); if (fp) { filter = &block.filters[filterIndex++]; filter->id = fp->id; filter->propsSize = 0; if (fp->id == XZ_ID_Delta) { filter->props[0] = (Byte)(fp->delta - 1); filter->propsSize = 1; } else if (fp->ipDefined) { SetUi32(filter->props, fp->ip); filter->propsSize = 4; } } { CXzFilter *f = &block.filters[filterIndex++]; f->id = XZ_ID_LZMA2; f->propsSize = 1; f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); } seqSizeOutStream.p.Write = MyWrite; seqSizeOutStream.realStream = outStream; seqSizeOutStream.processed = 0; RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p)); checkInStream.p.Read = SeqCheckInStream_Read; checkInStream.realStream = inStream; SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags)); if (fp) { #ifdef USE_SUBBLOCK if (fp->id == XZ_ID_Subblock) { lzmaf->sb.inStream = &checkInStream.p; RINOK(SbEncInStream_Init(&lzmaf->sb)); } else #endif { lzmaf->filter.realStream = &checkInStream.p; RINOK(SeqInFilter_Init(&lzmaf->filter, filter)); } } { UInt64 packPos = seqSizeOutStream.processed; SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p, fp ? #ifdef USE_SUBBLOCK (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p: #endif &lzmaf->filter.p: &checkInStream.p, progress); RINOK(res); block.unpackSize = checkInStream.processed; block.packSize = seqSizeOutStream.processed - packPos; } { unsigned padSize = 0; Byte buf[128]; while((((unsigned)block.packSize + padSize) & 3) != 0) buf[padSize++] = 0; SeqCheckInStream_GetDigest(&checkInStream, buf + padSize); RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags))); RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc)); } } return Xz_WriteFooter(xz, outStream); } SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress) { SRes res; CXzStream xz; CLzma2WithFilters lzmaf; Xz_Construct(&xz); Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc); res = Lzma2WithFilters_Create(&lzmaf); if (res == SZ_OK) res = Xz_Compress(&xz, &lzmaf, outStream, inStream, props, progress); Lzma2WithFilters_Free(&lzmaf); Xz_Free(&xz, &g_Alloc); return res; } SRes Xz_EncodeEmpty(ISeqOutStream *outStream) { SRes res; CXzStream xz; Xz_Construct(&xz); res = Xz_WriteHeader(xz.flags, outStream); if (res == SZ_OK) res = Xz_WriteFooter(&xz, outStream); Xz_Free(&xz, &g_Alloc); return res; } qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzEnc.h0100777000000000000000000000121413761647206017666 0ustar00/* XzEnc.h -- Xz Encode 2011-02-07 : Igor Pavlov : Public domain */ #ifndef __XZ_ENC_H #define __XZ_ENC_H #include "Lzma2Enc.h" #include "Xz.h" EXTERN_C_BEGIN typedef struct { UInt32 id; UInt32 delta; UInt32 ip; int ipDefined; } CXzFilterProps; void XzFilterProps_Init(CXzFilterProps *p); typedef struct { const CLzma2EncProps *lzma2Props; const CXzFilterProps *filterProps; unsigned checkId; } CXzProps; void XzProps_Init(CXzProps *p); SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress); SRes Xz_EncodeEmpty(ISeqOutStream *outStream); EXTERN_C_END #endif qt-installer-framework-4.0.1/src/libs/7zip/win/C/XzIn.c0100777000000000000000000002016113761647206017524 0ustar00/* XzIn.c - Xz input 2014-12-30 : Igor Pavlov : Public domain */ #include "Precomp.h" #include #include "7zCrc.h" #include "CpuArch.h" #include "Xz.h" SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) { Byte sig[XZ_STREAM_HEADER_SIZE]; RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) return SZ_ERROR_NO_ARCHIVE; return Xz_ParseHeader(p, sig); } #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes) { Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; unsigned headerSize; *headerSizeRes = 0; RINOK(SeqInStream_ReadByte(inStream, &header[0])); headerSize = ((unsigned)header[0] << 2) + 4; if (headerSize == 0) { *headerSizeRes = 1; *isIndex = True; return SZ_OK; } *isIndex = False; *headerSizeRes = headerSize; RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); return XzBlock_Parse(p, header); } #define ADD_SIZE_CHECH(size, val) \ { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } UInt64 Xz_GetUnpackSize(const CXzStream *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->numBlocks; i++) ADD_SIZE_CHECH(size, p->blocks[i].unpackSize); return size; } UInt64 Xz_GetPackSize(const CXzStream *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->numBlocks; i++) ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); return size; } /* SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) { return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); } */ static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc) { size_t i, numBlocks, pos = 1; UInt32 crc; if (size < 5 || buf[0] != 0) return SZ_ERROR_ARCHIVE; size -= 4; crc = CrcCalc(buf, size); if (crc != GetUi32(buf + size)) return SZ_ERROR_ARCHIVE; { UInt64 numBlocks64; READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); numBlocks = (size_t)numBlocks64; if (numBlocks != numBlocks64 || numBlocks * 2 > size) return SZ_ERROR_ARCHIVE; } Xz_Free(p, alloc); if (numBlocks != 0) { p->numBlocks = numBlocks; p->numBlocksAllocated = numBlocks; p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); if (p->blocks == 0) return SZ_ERROR_MEM; for (i = 0; i < numBlocks; i++) { CXzBlockSizes *block = &p->blocks[i]; READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); if (block->totalSize == 0) return SZ_ERROR_ARCHIVE; } } while ((pos & 3) != 0) if (buf[pos++] != 0) return SZ_ERROR_ARCHIVE; return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; } static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc) { SRes res; size_t size; Byte *buf; if (indexSize > ((UInt32)1 << 31)) return SZ_ERROR_UNSUPPORTED; size = (size_t)indexSize; if (size != indexSize) return SZ_ERROR_UNSUPPORTED; buf = alloc->Alloc(alloc, size); if (buf == 0) return SZ_ERROR_MEM; res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); if (res == SZ_OK) res = Xz_ReadIndex2(p, buf, size, alloc); alloc->Free(alloc, buf); return res; } static SRes SeekFromCur(ILookInStream *inStream, Int64 *res) { return inStream->Seek(inStream, res, SZ_SEEK_CUR); } static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc) { UInt64 indexSize; Byte buf[XZ_STREAM_FOOTER_SIZE]; if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; *startOffset = -XZ_STREAM_FOOTER_SIZE; RINOK(SeekFromCur(stream, startOffset)); RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) { UInt32 total = 0; *startOffset += XZ_STREAM_FOOTER_SIZE; for (;;) { size_t i; #define TEMP_BUF_SIZE (1 << 10) Byte tempBuf[TEMP_BUF_SIZE]; if (*startOffset < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) return SZ_ERROR_NO_ARCHIVE; i = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset; total += (UInt32)i; *startOffset = -(Int64)i; RINOK(SeekFromCur(stream, startOffset)); RINOK(LookInStream_Read2(stream, tempBuf, i, SZ_ERROR_NO_ARCHIVE)); for (; i != 0; i--) if (tempBuf[i - 1] != 0) break; if (i != 0) { if ((i & 3) != 0) return SZ_ERROR_NO_ARCHIVE; *startOffset += i; break; } } if (*startOffset < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; *startOffset -= XZ_STREAM_FOOTER_SIZE; RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) return SZ_ERROR_NO_ARCHIVE; } p->flags = (CXzStreamFlags)GetBe16(buf + 8); if (!XzFlags_IsSupported(p->flags)) return SZ_ERROR_UNSUPPORTED; if (GetUi32(buf) != CrcCalc(buf + 4, 6)) return SZ_ERROR_ARCHIVE; indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE); RINOK(SeekFromCur(stream, startOffset)); RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); { UInt64 totalSize = Xz_GetPackSize(p); UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize; if (totalSize == XZ_SIZE_OVERFLOW || sum >= ((UInt64)1 << 63) || totalSize >= ((UInt64)1 << 63)) return SZ_ERROR_ARCHIVE; *startOffset = -(Int64)sum; RINOK(SeekFromCur(stream, startOffset)); } { CXzStreamFlags headerFlags; CSecToRead secToRead; SecToRead_CreateVTable(&secToRead); secToRead.realStream = stream; RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s)); return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; } } /* ---------- Xz Streams ---------- */ void Xzs_Construct(CXzs *p) { p->num = p->numAllocated = 0; p->streams = 0; } void Xzs_Free(CXzs *p, ISzAlloc *alloc) { size_t i; for (i = 0; i < p->num; i++) Xz_Free(&p->streams[i], alloc); alloc->Free(alloc, p->streams); p->num = p->numAllocated = 0; p->streams = 0; } UInt64 Xzs_GetNumBlocks(const CXzs *p) { UInt64 num = 0; size_t i; for (i = 0; i < p->num; i++) num += p->streams[i].numBlocks; return num; } UInt64 Xzs_GetUnpackSize(const CXzs *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->num; i++) ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i])); return size; } /* UInt64 Xzs_GetPackSize(const CXzs *p) { UInt64 size = 0; size_t i; for (i = 0; i < p->num; i++) ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i])); return size; } */ SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc) { Int64 endOffset = 0; RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END)); *startOffset = endOffset; for (;;) { CXzStream st; SRes res; Xz_Construct(&st); res = Xz_ReadBackward(&st, stream, startOffset, alloc); st.startOffset = *startOffset; RINOK(res); if (p->num == p->numAllocated) { size_t newNum = p->num + p->num / 4 + 1; Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream)); if (data == 0) return SZ_ERROR_MEM; p->numAllocated = newNum; if (p->num != 0) memcpy(data, p->streams, p->num * sizeof(CXzStream)); alloc->Free(alloc, p->streams); p->streams = (CXzStream *)data; } p->streams[p->num++] = st; if (*startOffset == 0) break; RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) return SZ_ERROR_PROGRESS; } return SZ_OK; } qt-installer-framework-4.0.1/src/libs/7zip/win/win.pri0100777000000000000000000000057613761647206017627 0ustar00include(C/C.pri) include(CPP/7zip/7zip.pri) include(CPP/7zip/Archive/7z/7z.pri) include(CPP/7zip/Archive/Archive.pri) include(CPP/7zip/Archive/Common/Common.pri) include(CPP/7zip/Common/Common.pri) include(CPP/7zip/Compress/Compress.pri) include(CPP/7zip/UI/Common/Common.pri) include(CPP/7zip/UI/Console/Console.pri) include(CPP/Common/Common.pri) include(CPP/Windows/Windows.pri) qt-installer-framework-4.0.1/src/libs/installer/0040777000000000000000000000000013761647206016615 5ustar00qt-installer-framework-4.0.1/src/libs/installer/abstractfiletask.cpp0100777000000000000000000001331213761647206022647 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "abstractfiletask.h" namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::AbstractFileTask \brief The AbstractFileTask class is the base class of file related tasks. The class is not usable as a standalone class but provides common functionality when subclassed. */ /*! \inmodule QtInstallerFramework \namespace TaskRole \brief Contains identifiers for tasks. */ /*! \enum TaskRole::TaskRole \value Checksum \value TaskItem \value SourceFile \value TargetFile \value Name \value ChecksumMismatch \value UserRole The first role that can be used for user-specific purposes. */ /*! \inmodule QtInstallerFramework \class QInstaller::FileTaskItem \brief The FileTaskItem class represents an item in a file task object. */ /*! \fn QInstaller::FileTaskItem::FileTaskItem() Creates a file task item. */ /*! \fn QInstaller::FileTaskItem::FileTaskItem(const QString &s) Creates a file task item using the source specified by \a s. */ /*! \fn QInstaller::FileTaskItem::FileTaskItem(const QString &s, const QString &t) Creates a file task item using the source specified by \a s and target specified by \a t. */ /*! \fn QInstaller::FileTaskItem::source() const Returns the source file of the file task item. */ /*! \fn QInstaller::FileTaskItem::target() const Returns the target file of the file task item. */ /*! \inmodule QtInstallerFramework \class QInstaller::FileTaskResult \brief The FileTaskResult class represents the results of a file task. */ /*! \fn QInstaller::FileTaskResult::FileTaskResult() Creates file task results. */ /*! \fn QInstaller::FileTaskResult::FileTaskResult(const QString &t, const QByteArray &c, const FileTaskItem &i, bool checksumMismatch) Creates file task results using the target file specified by \a t, checksum specified by \a c, file task item specified by \a i, and checksum mismatch specified by \a checksumMismatch. */ /*! \fn QInstaller::FileTaskResult::target() const Returns the target file of the task result. */ /*! \fn QInstaller::FileTaskResult::checkSum() const Returns the checksum of the task result. */ /*! \fn QInstaller::FileTaskResult::taskItem() const Returns file task items. */ /*! \fn QInstaller::FileTaskResult::checksumMismatch() const Returns \c true if checksum mismatch is detected otherwise returns \c false. */ /*! Constructs an empty abstract file task object. */ AbstractFileTask::AbstractFileTask() { registerMetaTypes(); } /*! \fn QInstaller::AbstractFileTask::~AbstractFileTask() Destroys the abstract file task object. */ /*! Constructs a new abstract file task object with \a source. */ AbstractFileTask::AbstractFileTask(const QString &source) { registerMetaTypes(); setTaskItem(FileTaskItem(source)); } /*! Constructs a new abstract file task object with \a item. */ AbstractFileTask::AbstractFileTask(const FileTaskItem &item) { registerMetaTypes(); setTaskItem(item); } /*! Constructs a new abstract file task object with \a source and \a target. */ AbstractFileTask::AbstractFileTask(const QString &source, const QString &target) { registerMetaTypes(); setTaskItem(FileTaskItem(source, target)); } /*! Returns a list of file task items this task is working on. */ QList AbstractFileTask::taskItems() const { QReadLocker _(&m_lock); return m_items; } /*! Sets a file task \a item this task is working on. */ void AbstractFileTask::setTaskItem(const FileTaskItem &item) { clearTaskItems(); addTaskItem(item); } // -- protected /*! \internal */ void AbstractFileTask::clearTaskItems() { QWriteLocker _(&m_lock); m_items.clear(); } /*! \internal */ void AbstractFileTask::addTaskItem(const FileTaskItem &item) { QWriteLocker _(&m_lock); m_items.append(item); } /*! \internal */ void AbstractFileTask::setTaskItems(const QList &items) { clearTaskItems(); addTaskItems(items); } /*! \internal */ void AbstractFileTask::addTaskItems(const QList &items) { QWriteLocker _(&m_lock); m_items.append(items); } // -- private /*! \internal */ void AbstractFileTask::registerMetaTypes() { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/abstractfiletask.h0100777000000000000000000000735413761647206022325 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ABSTRACTFILETASK_H #define ABSTRACTFILETASK_H #include "abstracttask.h" #include "installer_global.h" #include #include namespace QInstaller { namespace TaskRole { enum TaskRole { Checksum, TaskItem, SourceFile, TargetFile, Name, ChecksumMismatch, UserRole = 1000 }; } class FileTaskItem : public AbstractTaskData { public: FileTaskItem() {} explicit FileTaskItem(const QString &s) { insert(TaskRole::SourceFile, s); } FileTaskItem(const QString &s, const QString &t) { insert(TaskRole::SourceFile, s); insert(TaskRole::TargetFile, t); } QString source() const { return value(TaskRole::SourceFile).toString(); } QString target() const { return value(TaskRole::TargetFile).toString(); } }; class FileTaskResult : public AbstractTaskData { public: FileTaskResult() {} FileTaskResult(const QString &t, const QByteArray &c, const FileTaskItem &i, bool checksumMismatch) { insert(TaskRole::Checksum, c); insert(TaskRole::TargetFile, t); insert(TaskRole::TaskItem, QVariant::fromValue(i)); insert(TaskRole::ChecksumMismatch, checksumMismatch); } QString target() const { return value(TaskRole::TargetFile).toString(); } QByteArray checkSum() const { return value(TaskRole::Checksum).toByteArray(); } FileTaskItem taskItem() const { return value(TaskRole::TaskItem).value(); } bool checksumMismatch() const { return value(TaskRole::ChecksumMismatch).toBool(); } }; class INSTALLER_EXPORT AbstractFileTask : public AbstractTask { Q_OBJECT Q_DISABLE_COPY(AbstractFileTask) public: AbstractFileTask(); virtual ~AbstractFileTask() {} explicit AbstractFileTask(const QString &source); explicit AbstractFileTask(const FileTaskItem &item); AbstractFileTask(const QString &source, const QString &target); QList taskItems() const; void setTaskItem(const FileTaskItem &item); protected: void clearTaskItems(); void addTaskItem(const FileTaskItem &item); void setTaskItems(const QList &items); void addTaskItems(const QList &items); private: void registerMetaTypes(); private: QList m_items; mutable QReadWriteLock m_lock; }; } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::FileTaskItem) Q_DECLARE_METATYPE(QInstaller::FileTaskResult) Q_DECLARE_METATYPE(QInstaller::TaskException) #endif // ABSTRACTFILETASK_H qt-installer-framework-4.0.1/src/libs/installer/abstracttask.cpp0100777000000000000000000000304413761647206022010 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "abstracttask.h" /*! \inmodule QtInstallerFramework \class QInstaller::AbstractTask \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::AbstractTaskData \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::TaskException \internal */ qt-installer-framework-4.0.1/src/libs/installer/abstracttask.h0100777000000000000000000000453613761647206021464 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ABSTRACTTASK_H #define ABSTRACTTASK_H #include "runextensions.h" #include namespace QInstaller { class AbstractTaskData { public: AbstractTaskData() {} virtual ~AbstractTaskData() = 0; QVariant value(int role) const { return m_data.value(role); } void insert(int key, const QVariant &value) { m_data.insert(key, value); } private: QHash m_data; }; inline AbstractTaskData::~AbstractTaskData() {} class TaskException : public QException { public: TaskException() {} ~TaskException() throw() {} explicit TaskException(const QString &message) : m_message(message) {} void raise() const { throw *this; } QString message() const { return m_message; } TaskException *clone() const { return new TaskException(*this); } private: QString m_message; }; template class AbstractTask : public QObject { Q_DISABLE_COPY(AbstractTask) public: AbstractTask() {} virtual ~AbstractTask() {} virtual void doTask(QFutureInterface &futureInterface) = 0; }; } // namespace QInstaller #endif // ABSTRACTTASK_H qt-installer-framework-4.0.1/src/libs/installer/adminauthorization.h0100777000000000000000000000307113761647206022700 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ADMINAUTHORIZATION_H #define ADMINAUTHORIZATION_H #include namespace QInstaller { class AdminAuthorization { public: static bool hasAdminRights(); static bool execute(QWidget *parent, const QString &programs, const QStringList &arguments); }; } // namespace QInstaller #endif // ADMINAUTHORIZATION_H qt-installer-framework-4.0.1/src/libs/installer/adminauthorization_mac.cpp0100777000000000000000000000556213761647206024062 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "adminauthorization.h" #include #include #include #include #include namespace QInstaller { bool AdminAuthorization::execute(QWidget *, const QString &program, const QStringList &arguments) { AuthorizationRef authorizationRef; OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); if (status != errAuthorizationSuccess) return false; AuthorizationItem item = { kAuthorizationRightExecute, 0, 0, 0 }; AuthorizationRights rights = { 1, &item }; const AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; status = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment, flags, 0); if (status != errAuthorizationSuccess) return false; QVector args; QVector utf8Args; foreach (const QString &argument, arguments) { utf8Args.push_back(argument.toUtf8()); args.push_back(utf8Args.last().data()); } args.push_back(0); const QByteArray utf8Program = program.toUtf8(); status = AuthorizationExecuteWithPrivileges(authorizationRef, utf8Program.data(), kAuthorizationFlagDefaults, args.data(), 0); AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights); return status == errAuthorizationSuccess; } bool AdminAuthorization::hasAdminRights() { return geteuid() == 0; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/adminauthorization_win.cpp0100777000000000000000000001036213761647206024111 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "adminauthorization.h" #include "utils.h" #include #include #include #include #include "globals.h" #ifdef Q_CC_MINGW # ifndef SEE_MASK_NOASYNC # define SEE_MASK_NOASYNC 0x00000100 # endif #endif namespace QInstaller { struct DeCoInitializer { DeCoInitializer() : neededCoInit(CoInitialize(NULL) == S_OK) { } ~DeCoInitializer() { if (neededCoInit) CoUninitialize(); } bool neededCoInit; }; bool AdminAuthorization::hasAdminRights() { SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; PSID adminGroup; // Initialize SID. if (!AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &adminGroup)) return false; BOOL isInAdminGroup = FALSE; if (!CheckTokenMembership(0, adminGroup, &isInAdminGroup)) isInAdminGroup = FALSE; FreeSid(adminGroup); return isInAdminGroup; } bool AdminAuthorization::execute(QWidget *, const QString &program, const QStringList &arguments) { DeCoInitializer _; // AdminAuthorization::execute uses UAC to ask for admin privileges. If the user is no // administrator yet and the computer's policies are set to not use UAC (which is the case // in some corporate networks), the call to execute() will simply succeed and not at all // launch the child process. To avoid this, we detect this situation here and return early. if (!hasAdminRights()) { QLatin1String key("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" "Policies\\System"); QSettings registry(key, QSettings::NativeFormat); const QVariant enableLUA = registry.value(QLatin1String("EnableLUA")); if ((enableLUA.type() == QVariant::Int) && (enableLUA.toInt() == 0)) return false; } const QString file = QDir::toNativeSeparators(program); const QString args = QInstaller::createCommandline(QString(), arguments); SHELLEXECUTEINFOW shellExecuteInfo = { 0 }; shellExecuteInfo.nShow = SW_HIDE; shellExecuteInfo.lpVerb = L"runas"; shellExecuteInfo.lpFile = (wchar_t *)file.utf16(); shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFOW); shellExecuteInfo.lpParameters = (wchar_t *)args.utf16(); shellExecuteInfo.fMask = SEE_MASK_NOASYNC; qCDebug(QInstaller::lcServer) << "Starting elevated process" << file << "with arguments" << args; if (ShellExecuteExW(&shellExecuteInfo)) { qCDebug(QInstaller::lcServer) << "Finished starting elevated process."; return true; } else { qCWarning(QInstaller::lcServer) << "Error while starting elevated process" << program << ":" << QInstaller::windowsErrorString(GetLastError()); } return false; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/adminauthorization_x11.cpp0100777000000000000000000002100213761647206023716 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "adminauthorization.h" #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_LINUX #include #include #else #ifdef Q_OS_FREEBSD #include #include #else #include #endif #endif #include #include #include #include #include #include "globals.h" #define SU_COMMAND "/usr/bin/sudo" //#define SU_COMMAND "/bin/echo" namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::AdminAuthorization \internal */ static QString getPassword(QWidget *parent) { if (qobject_cast (qApp) != 0) { bool ok = false; const QString result = QInputDialog::getText(parent, QObject::tr("Authorization required"), QObject::tr("Enter your password to authorize for sudo:"), QLineEdit::Password, QString(), &ok); return ok ? result : QString(); } else { std::cout << QObject::tr("Authorization required").toStdString() << std::endl; std::cout << QObject::tr("Enter your password to authorize for sudo:").toStdString() << std::endl; std::string password; std::cin >> password; return QString::fromStdString(password); } } static void printError(QWidget *parent, const QString &value) { if (qobject_cast (qApp) != 0) { QMessageBox::critical(parent, QObject::tr( "Error acquiring admin rights" ), value, QMessageBox::Ok, QMessageBox::Ok); } else { std::cout << value.toStdString() << std::endl; } } bool AdminAuthorization::execute(QWidget *parent, const QString &program, const QStringList &arguments) { const QString fallback = program + QLatin1String(" ") + arguments.join(QLatin1String(" ")); qCDebug(QInstaller::lcServer) << "Fallback:" << fallback; // as we cannot pipe the password to su in QProcess, we need to setup a pseudo-terminal for it int masterFD = -1; int slaveFD = -1; char ptsn[ PATH_MAX ]; if (::openpty(&masterFD, &slaveFD, ptsn, 0, 0)) return false; masterFD = ::posix_openpt(O_RDWR | O_NOCTTY); if (masterFD < 0) return false; const QByteArray ttyName = ::ptsname(masterFD); if (::grantpt(masterFD)) { ::close(masterFD); return false; } ::revoke(ttyName); ::unlockpt(masterFD); slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY); if (slaveFD < 0) { ::close(masterFD); return false; } ::fcntl(masterFD, F_SETFD, FD_CLOEXEC); ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC); int pipedData[2]; if (pipe(pipedData) != 0) return false; int flags = ::fcntl(pipedData[0], F_GETFL); if (flags != -1) ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK); flags = ::fcntl(masterFD, F_GETFL); if (flags != -1) ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK); pid_t child = fork(); if (child < -1) { ::close(masterFD); ::close(slaveFD); ::close(pipedData[0]); ::close(pipedData[1]); return false; } // parent process else if (child > 0) { ::close(slaveFD); //close writing end of pipe ::close(pipedData[1]); QRegExp re(QLatin1String("[Pp]assword.*:")); QByteArray data; QByteArray errData; int bytes = 0; int errBytes = 0; char buf[1024]; char errBuf[1024]; int status; bool statusValid = false; while (bytes >= 0) { const pid_t waitResult = ::waitpid(child, &status, WNOHANG); if (waitResult == -1) { break; } if (waitResult == child) { statusValid = true; break; } bytes = ::read(masterFD, buf, 1023); if (bytes == -1 && errno == EAGAIN) bytes = 0; else if (bytes > 0) data.append(buf, bytes); errBytes = ::read(pipedData[0], errBuf, 1023); if (errBytes > 0) { errData.append(errBuf, errBytes); errBytes=0; } if (bytes > 0) { const QString line = QString::fromLatin1(data); if (re.indexIn(line) != -1) { const QString password = getPassword(parent); if (password.isEmpty()) { QByteArray pwd = password.toLatin1(); for (int i = 0; i < 3; ++i) { ::write(masterFD, pwd.data(), pwd.length()); ::write(masterFD, "\n", 1); } return false; } QByteArray pwd = password.toLatin1(); ::write(masterFD, pwd.data(), pwd.length()); ::write(masterFD, "\n", 1); ::read(masterFD, buf, pwd.length() + 1); } } if (bytes == 0) ::usleep(100000); } while (true) { errBytes = ::read(pipedData[0], errBuf, 1023); if (errBytes == -1 && errno == EAGAIN) { ::usleep(100000); continue; } if (errBytes <= 0) break; errData.append(errBuf, errBytes); } const bool success = statusValid && WIFEXITED(status) && WEXITSTATUS(status) == 0; if (!success && !errData.isEmpty()) { printError(parent, QString::fromLocal8Bit(errData.constData())); } ::close(pipedData[0]); return success; } // child process else { ::close(pipedData[0]); // Reset signal handlers for (int sig = 1; sig < NSIG; ++sig) signal(sig, SIG_DFL); signal(SIGHUP, SIG_IGN); ::setsid(); ::ioctl(slaveFD, TIOCSCTTY, 1); int pgrp = ::getpid(); ::tcsetpgrp(slaveFD, pgrp); ::dup2(slaveFD, 0); ::dup2(slaveFD, 1); ::dup2(pipedData[1], 2); // close all file descriptors struct rlimit rlp; getrlimit(RLIMIT_NOFILE, &rlp); for (int i = 3; i < static_cast(rlp.rlim_cur); ++i) ::close(i); char **argp = (char **) ::malloc((arguments.count() + 4) * sizeof(char *)); QList args; args.push_back(SU_COMMAND); args.push_back("-b"); args.push_back(program.toLocal8Bit()); for (QStringList::const_iterator it = arguments.begin(); it != arguments.end(); ++it) args.push_back(it->toLocal8Bit()); int i = 0; for (QList::iterator it = args.begin(); it != args.end(); ++it, ++i) argp[i] = it->data(); argp[i] = 0; ::unsetenv("LANG"); ::unsetenv("LC_ALL"); int exitStatus = 0; if (::execv(SU_COMMAND, argp) == -1) exitStatus = -errno; _exit(exitStatus); return false; } } // has no guarantee to work bool AdminAuthorization::hasAdminRights() { return getuid() == 0; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/aspectratiolabel.cpp0100777000000000000000000000526213761647206022644 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "aspectratiolabel.h" using namespace QInstaller; /*! \class QInstaller::AspectRatioLabel \inmodule QtInstallerFramework \brief The AspectRatioLabel class provides a label for displaying a pixmap that maintains its original aspect ratio when resized. */ /*! Constructs the label with \a parent as parent. */ AspectRatioLabel::AspectRatioLabel(QWidget *parent) : QLabel(parent) { setMinimumSize(1, 1); setScaledContents(false); } /*! Sets the \a pixmap shown on the label. Setting a new pixmap clears the previous content. */ void AspectRatioLabel::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; QLabel::setPixmap(scaledPixmap()); } /*! \reimp */ int AspectRatioLabel::heightForWidth(int w) const { return m_pixmap.isNull() ? height() : m_pixmap.height() * w / m_pixmap.width(); } /*! \reimp */ QSize AspectRatioLabel::sizeHint() const { const int w = width(); return QSize(w, heightForWidth(w)); } /*! Returns the currently set pixmap scaled to the label size, while preserving the original aspect ratio. */ QPixmap AspectRatioLabel::scaledPixmap() const { return m_pixmap.isNull() ? QPixmap() : m_pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } /*! \reimp */ void AspectRatioLabel::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); if (!m_pixmap.isNull()) QLabel::setPixmap(scaledPixmap()); } qt-installer-framework-4.0.1/src/libs/installer/aspectratiolabel.h0100777000000000000000000000352413761647206022310 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ASPECTRATIOLABEL_H #define ASPECTRATIOLABEL_H #include "installer_global.h" #include #include #include namespace QInstaller { class INSTALLER_EXPORT AspectRatioLabel : public QLabel { Q_OBJECT public: explicit AspectRatioLabel(QWidget *parent = nullptr); int heightForWidth(int w) const; QSize sizeHint() const; public slots: void setPixmap (const QPixmap &pixmap); void resizeEvent(QResizeEvent *event); private: QPixmap scaledPixmap() const; private: QPixmap m_pixmap; }; } // namespace QInstaller #endif // ASPECTRATIOLABEL_H qt-installer-framework-4.0.1/src/libs/installer/binarycontent.cpp0100777000000000000000000003006213761647206022201 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binarycontent.h" #include "binarylayout.h" #include "errors.h" #include "fileio.h" #include "fileutils.h" namespace QInstaller { /*! \class QInstaller::BinaryContent \inmodule QtInstallerFramework \brief The BinaryContent class handles binary information embedded into executables. The following types of binary information can be embedded into executable files: Qt resources, performed operations, and resource collections. The magic marker is a \c quint64 that identifies the kind of the binary: \c installer or \c uninstaller (maintenance tool). The magic cookie is a \c quint64 describing whether the binary is the file holding just data or whether it includes the executable as well. */ /*! Searches for the given magic cookie \a magicCookie starting from the end of the file \a in. Returns the position of the magic cookie inside the binary. Throws Error on failure. \note Searches through up to 1MB of data, if smaller, through the whole file. */ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie) { Q_ASSERT(in); Q_ASSERT(in->isOpen()); Q_ASSERT(in->isReadable()); const qint64 fileSize = in->size(); const size_t markerSize = sizeof(qint64); const qint64 maxSearch = qMin((1024LL * 1024LL), fileSize); QByteArray data(maxSearch, Qt::Uninitialized); uchar *const mapped = in->map(fileSize - maxSearch, maxSearch); if (!mapped) { // Fallback to read the file content in case we can't map it. // Note: Failing to map the file can happen for example while having a remote connection // established to the privileged server process and we do not support map over the socket. const int pos = in->pos(); try { in->seek(fileSize - maxSearch); QInstaller::blockingRead(in, data.data(), maxSearch); in->seek(pos); } catch (const Error &error) { in->seek(pos); throw error; } } else { // map does not change QFile::pos() data = QByteArray((const char*) mapped, maxSearch); in->unmap(mapped); } qint64 searched = maxSearch - markerSize; while (searched >= 0) { if (memcmp(&magicCookie, (data.data() + searched), markerSize) == 0) return (fileSize - maxSearch) + searched; --searched; } throw Error(QCoreApplication::translate("QInstaller", "No marker found, stopped after %1.") .arg(humanReadableSize(maxSearch))); return -1; // never reached } /*! Tries to read the binary layout of the file \a file. It starts searching from the end of the file \a file for the given \a magicCookie using findMagicCookie(). If the cookie was found, it fills a BinaryLayout structure and returns it. Throws Error on failure. */ BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie) { BinaryLayout layout; layout.endOfBinaryContent = BinaryContent::findMagicCookie(file, magicCookie) + sizeof(qint64); const qint64 posOfMetaDataCount = layout.endOfBinaryContent - (4 * sizeof(qint64)); if (!file->seek(posOfMetaDataCount)) { throw QInstaller::Error(QCoreApplication::translate("BinaryLayout", "Cannot seek to %1 to read the embedded meta data count.").arg(posOfMetaDataCount)); } // read the meta resources count const qint64 metaResourcesCount = QInstaller::retrieveInt64(file); const qint64 posOfResourceCollectionsSegment = layout.endOfBinaryContent - ((metaResourcesCount * (2 * sizeof(qint64))) // minus the size of the meta data segments + (8 * sizeof(qint64))); // meta count, offset/length collection index, marker, cookie... if (!file->seek(posOfResourceCollectionsSegment)) { throw Error(QCoreApplication::translate("BinaryLayout", "Cannot seek to %1 to read the resource collection segment.") .arg(posOfResourceCollectionsSegment)); } // read the resource collection index offset and length layout.resourceCollectionsSegment = QInstaller::retrieveInt64Range(file); // read the meta data resource segments for (int i = 0; i < metaResourcesCount; ++i) layout.metaResourceSegments.append(QInstaller::retrieveInt64Range(file)); if (metaResourcesCount != layout.metaResourceSegments.count()) { throw Error(QCoreApplication::translate("BinaryLayout", "Unexpected mismatch of meta resources. Read %1, expected: %2.") .arg(layout.metaResourceSegments.count()).arg(metaResourcesCount)); } // read the operations offset and length layout.operationsSegment = QInstaller::retrieveInt64Range(file); // resources count Q_UNUSED(QInstaller::retrieveInt64(file)) // read it, but deliberately not used // read the binary content size layout.binaryContentSize = QInstaller::retrieveInt64(file); layout.endOfExectuable = layout.endOfBinaryContent - layout.binaryContentSize; layout.magicMarker = QInstaller::retrieveInt64(file); layout.magicCookie = QInstaller::retrieveInt64(file); // adjust the offsets to match the actual binary for (int i = 0; i < layout.metaResourceSegments.count(); ++i) layout.metaResourceSegments[i].move(layout.endOfExectuable); layout.metaResourcesSegment = Range::fromStartAndEnd(layout.metaResourceSegments .first().start(), layout.metaResourceSegments.last().end()); layout.operationsSegment.move(layout.endOfExectuable); layout.resourceCollectionsSegment.move(layout.endOfExectuable); return layout; } /*! Reads the binary content of the given file \a file. It starts by reading the binary layout of the file using binaryLayout() using \a magicCookie. Throws Error on failure. If \a operations is not 0, it is set to the performed operations from a previous run of for example the maintenance tool. If \a manager is not 0, it is first cleared and then set to the resource collections embedded into the binary. If \a magicMarker is not 0, it is set to the magic marker found in the binary. */ void BinaryContent::readBinaryContent(QFile *file, QList *operations, ResourceCollectionManager *manager, qint64 *magicMarker, quint64 magicCookie) { const BinaryLayout layout = BinaryContent::binaryLayout(file, magicCookie); if (manager) manager->clear(); if (manager) { // append the meta resources ResourceCollection metaResources("QResources"); foreach (const Range &segment, layout.metaResourceSegments) { metaResources.appendResource(QSharedPointer(new Resource(file->fileName(), segment))); } manager->insertCollection(metaResources); } if (operations) { const qint64 posOfOperationsBlock = layout.operationsSegment.start(); if (!file->seek(posOfOperationsBlock)) { throw Error(QCoreApplication::translate("BinaryContent", "Cannot seek to %1 to read the operation data.").arg(posOfOperationsBlock)); } // read the operations count qint64 operationsCount = QInstaller::retrieveInt64(file); // read the operations for (int i = 0; i < operationsCount; ++i) { const QString name = QInstaller::retrieveString(file); const QString xml = QInstaller::retrieveString(file); operations->append(OperationBlob(name, xml)); } // operations count Q_UNUSED(QInstaller::retrieveInt64(file)) // read it, but deliberately not used } if (manager) { // read the collection index and data const qint64 posOfResourceCollectionBlock = layout.resourceCollectionsSegment.start(); if (!file->seek(posOfResourceCollectionBlock)) { throw Error(QCoreApplication::translate("BinaryContent", "Cannot seek to %1 to " "read the resource collection block.").arg(posOfResourceCollectionBlock)); } manager->read(file, layout.endOfExectuable); } if (magicMarker) *magicMarker = layout.magicMarker; } /*! Writes the binary content to the given file \a out. Throws Error on failure. The binary content is written in the following order: \list \li Meta resources \a manager \li Operations \a operations \li Resource collections \a manager \li Magic marker \a magicMarker \li Magic cookie \a magicCookie \endlist For more information see the BinaryLayout documentation. */ void BinaryContent::writeBinaryContent(QFile *out, const QList &operations, const ResourceCollectionManager &manager, qint64 magicMarker, quint64 magicCookie) { const qint64 endOfBinary = out->pos(); ResourceCollectionManager localManager = manager; // resources qint64 pos = out->pos(); QVector > metaResourceSegments; const ResourceCollection collection = localManager.collectionByName("QResources"); foreach (const QSharedPointer &resource, collection.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) { throw Error(QCoreApplication::translate("BinaryContent", "Cannot open meta resource %1.").arg(resource->errorString())); } resource->seek(0); resource->copyData(out); metaResourceSegments.append(Range::fromStartAndEnd(pos, out->pos())); pos = out->pos(); if (!isOpen) // If we reach that point, either the resource was opened already... resource->close(); // or we did open it and have to close it again. } localManager.removeCollection("QResources"); // operations QInstaller::appendInt64(out, operations.count()); foreach (const OperationBlob &operation, operations) { QInstaller::appendString(out, operation.name); QInstaller::appendString(out, operation.xml); } QInstaller::appendInt64(out, operations.count()); const Range operationsSegment = Range::fromStartAndEnd(pos, out->pos()); // resource collections data and index const Range resourceCollectionsSegment = localManager.write(out, -endOfBinary); QInstaller::appendInt64Range(out, resourceCollectionsSegment.moved(-endOfBinary)); // meta resource segments foreach (const Range &segment, metaResourceSegments) QInstaller::appendInt64Range(out, segment.moved(-endOfBinary)); // operations segment QInstaller::appendInt64Range(out, operationsSegment.moved(-endOfBinary)); // resources count QInstaller::appendInt64(out, metaResourceSegments.count()); const qint64 binaryContentSize = (out->pos() + (3 * sizeof(qint64))) - endOfBinary; QInstaller::appendInt64(out, binaryContentSize); QInstaller::appendInt64(out, magicMarker); QInstaller::appendInt64(out, magicCookie); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/binarycontent.h0100777000000000000000000000531613761647206021652 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYCONTENT_H #define BINARYCONTENT_H #include "binaryformat.h" #include "binarylayout.h" QT_BEGIN_NAMESPACE class QFile; QT_END_NAMESPACE namespace QInstaller { class INSTALLER_EXPORT BinaryContent { public: // the marker to distinguish what kind of binary static const qint64 MagicInstallerMarker = 0x12023233UL; static const qint64 MagicUninstallerMarker = 0x12023234UL; static const qint64 MagicUpdaterMarker = 0x12023235UL; static const qint64 MagicPackageManagerMarker = 0x12023236UL; // the cookie put at the end of the file static const quint64 MagicCookie = 0xc2630a1c99d668f8LL; // binary static const quint64 MagicCookieDat = 0xc2630a1c99d668f9LL; // data static qint64 findMagicCookie(QFile *file, quint64 magicCookie); static BinaryLayout binaryLayout(QFile *file, quint64 magicCookie); static void readBinaryContent(QFile *file, QList *operations, ResourceCollectionManager *manager, qint64 *magicMarker, quint64 magicCookie); static void writeBinaryContent(QFile *out, const QList &operations, const ResourceCollectionManager &manager, qint64 magicMarker, quint64 magicCookie); }; } // namespace QInstaller #endif // BINARYCONTENT_H qt-installer-framework-4.0.1/src/libs/installer/binaryformat.cpp0100777000000000000000000003214013761647206022016 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binaryformat.h" #include "errors.h" #include "fileio.h" #include #include #include namespace QInstaller { /*! \class QInstaller::OperationBlob \inmodule QtInstallerFramework \brief The OperationBlob class is a textual representation of an operation that can be instantiated and executed by the Qt Installer Framework. */ /*! \fn QInstaller::OperationBlob::OperationBlob(const QString &n, const QString &x) Constructs the operation blob with the given arguments, while \a n stands for the name part and \a x for the XML representation of the operation. */ /*! \variable QInstaller::OperationBlob::name \brief The name of the operation. */ /*! \variable QInstaller::OperationBlob::xml \brief The XML representation of the operation. */ /*! \class QInstaller::Resource \inmodule QtInstallerFramework \brief The Resource class is an interface for wrapping a file as read only device. Resource is an interface for reading inside a file, but is not supposed to write to the file it wraps. The \c Resource class is created by passing a path to an existing binary (such as a zipped archive or a Qt resource file). The resource name can be set at any time using setName() or during construction. The segment supplied during construction represents the offset and size of the resource inside the file. */ /*! \fn Range QInstaller::Resource::segment() const Returns the range inside the file this resource represents. */ /*! \fn void QInstaller::Resource::setSegment(const Range &segment) Sets the range to the \a segment of the file that this resource represents. */ /*! Creates a resource providing the data in \a path. */ Resource::Resource(const QString &path) : m_file(path) , m_name(QFileInfo(path).fileName().toUtf8()) , m_segment(Range::fromStartAndLength(0, m_file.size())) { } /*! Creates a resource providing the data in \a path identified by \a name. */ Resource::Resource(const QString &path, const QByteArray &name) : m_file(path) , m_name(name) , m_segment(Range::fromStartAndLength(0, m_file.size())) { } /*! Creates a resource providing the data in \a path limited to \a segment. */ Resource::Resource(const QString &path, const Range &segment) : m_file(path) , m_name(QFileInfo(path).fileName().toUtf8()) , m_segment(segment) { } /*! Destroys the resource. Calls close() if necessary before destroying the resource. */ Resource::~Resource() { if (isOpen()) close(); } /*! \reimp */ bool Resource::seek(qint64 pos) { return QIODevice::seek(pos); } /*! Returns the name of the resource. */ QByteArray Resource::name() const { return m_name; } /*! Sets the name of the resource to \a name. */ void Resource::setName(const QByteArray &name) { m_name = name; } /*! Opens a resource in QIODevice::ReadOnly mode. The function returns \c true if successful. */ bool Resource::open() { if (isOpen()) return false; if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { setErrorString(m_file.errorString()); return false; } if (!QIODevice::open(QIODevice::ReadOnly)) { setErrorString(tr("Cannot open resource %1 for reading.").arg(QString::fromUtf8(m_name))); return false; } return true; } /*! \reimp */ void Resource::close() { m_file.close(); QIODevice::close(); } /*! \reimp */ qint64 Resource::size() const { return m_segment.length(); } /*! \reimp */ qint64 Resource::readData(char* data, qint64 maxSize) { // check if there is anything left to read maxSize = qMin(maxSize, m_segment.length() - pos()); if (maxSize <= 0) return 0; const qint64 p = m_file.pos(); m_file.seek(m_segment.start() + pos()); const qint64 amountRead = m_file.read(data, maxSize); m_file.seek(p); return amountRead; } /*! \reimp */ qint64 Resource::writeData(const char* data, qint64 maxSize) { Q_UNUSED(data); Q_UNUSED(maxSize); // should never be called, as we're read only return -1; } /*! \fn void QInstaller::Resource::copyData(QFileDevice *out) Copies the resource data to a file called \a out. Throws Error on failure. */ /*! \overload Copies the resource data of \a resource to a file called \a out. Throws Error on failure. */ void Resource::copyData(Resource *resource, QFileDevice *out) { qint64 left = resource->size(); char data[4096]; while (left > 0) { const qint64 len = qMin(left, 4096); const qint64 bytesRead = resource->read(data, len); if (bytesRead != len) { throw QInstaller::Error(tr("Read failed after %1 bytes: %2") .arg(QString::number(resource->size() - left), resource->errorString())); } const qint64 bytesWritten = out->write(data, len); if (bytesWritten != len) { throw QInstaller::Error(tr("Write failed after %1 bytes: %2") .arg(QString::number(resource->size() - left), out->errorString())); } left -= len; } } /*! \class QInstaller::ResourceCollection \inmodule QtInstallerFramework \brief The ResourceCollection class is an abstraction that groups together a number of resources. The resources are supposed to be sequential, so the collection keeps them ordered once a new resource is added. The name can be set at any time using setName(). */ /*! The class constructor creates an empty resource collection. By default the collection gets a unique name assigned using QUuid. */ ResourceCollection::ResourceCollection() : m_name(QUuid::createUuid().toByteArray()) { } /*! The class constructor creates an empty resource collection with a name set to \a name. */ ResourceCollection::ResourceCollection(const QByteArray &name) : m_name(name) {} /*! Returns the name of the resource collection. */ QByteArray ResourceCollection::name() const { return m_name; } /*! Sets the name of the resource collection to \a name. */ void ResourceCollection::setName(const QByteArray &name) { m_name = name; } /*! Appends \a resource to this collection. The collection takes ownership of \a resource. */ void ResourceCollection::appendResource(const QSharedPointer& resource) { Q_ASSERT(resource); resource->setParent(nullptr); m_resources.append(resource); } /*! Appends a list of \a resources to this collection. The collection takes ownership of \a resources. */ void ResourceCollection::appendResources(const QList > &resources) { foreach (const QSharedPointer &resource, resources) appendResource(resource); } /*! Returns the resources associated with this collection. */ QList > ResourceCollection::resources() const { return m_resources; } /*! Returns the resource associated with the name \a name. */ QSharedPointer ResourceCollection::resourceByName(const QByteArray &name) const { foreach (const QSharedPointer& i, m_resources) { if (i->name() == name) return i; } return QSharedPointer(); } /*! \class QInstaller::ResourceCollectionManager \inmodule QtInstallerFramework \brief The ResourceCollectionManager class is an abstraction that groups together a number of resource collections. The resource collections it groups can be written to and read from a QFileDevice. */ /*! Reads the resource collection from the file \a dev. The \a offset argument is used to set the collection's resources segment information. */ void ResourceCollectionManager::read(QFileDevice *dev, qint64 offset) { const qint64 size = QInstaller::retrieveInt64(dev); for (int i = 0; i < size; ++i) { ResourceCollection collection(QInstaller::retrieveByteArray(dev)); const Range segment = QInstaller::retrieveInt64Range(dev).moved(offset); const qint64 pos = dev->pos(); dev->seek(segment.start()); const qint64 count = QInstaller::retrieveInt64(dev); for (int i = 0; i < count; ++i) { QSharedPointer resource(new Resource(dev->fileName())); resource->setName(QInstaller::retrieveByteArray(dev)); resource->setSegment(QInstaller::retrieveInt64Range(dev).moved(offset)); collection.appendResource(resource); } dev->seek(pos); insertCollection(collection); } } /*! Writes the resource collection to the file \a out. The \a offset argument is used to set the collection's segment information. */ Range ResourceCollectionManager::write(QFileDevice *out, qint64 offset) const { QHash < QByteArray, Range > table; QInstaller::appendInt64(out, collectionCount()); foreach (const ResourceCollection &collection, m_collections) { const qint64 dataBegin = out->pos(); QInstaller::appendInt64(out, collection.resources().count()); qint64 start = out->pos() + offset; foreach (const QSharedPointer &resource, collection.resources()) { start += (sizeof(qint64)) // the number of bytes that get written and the + resource->name().size() // resource name (see QInstaller::appendByteArray) + (2 * sizeof(qint64)); // the resource range (see QInstaller::appendInt64Range) } foreach (const QSharedPointer &resource, collection.resources()) { QInstaller::appendByteArray(out, resource->name()); QInstaller::appendInt64Range(out, Range::fromStartAndLength(start, resource->size())); // the actual range once the table has been written start += resource->size(); // adjust for next resource data } foreach (const QSharedPointer &resource, collection.resources()) { if (!resource->open()) { throw QInstaller::Error(tr("Cannot open resource %1: %2") .arg(QString::fromUtf8(resource->name()), resource->errorString())); } resource->copyData(out); } table.insert(collection.name(), Range::fromStartAndEnd(dataBegin, out->pos()) .moved(offset)); } const qint64 start = out->pos(); // Q: why do we write the size twice? // A: for us to be able to read it beginning from the end of the file as well QInstaller::appendInt64(out, collectionCount()); foreach (const QByteArray &name, table.keys()) { QInstaller::appendByteArray(out, name); QInstaller::appendInt64Range(out, table.value(name)); } QInstaller::appendInt64(out, collectionCount()); return Range::fromStartAndEnd(start, out->pos()); } /*! Returns the collection associated with the name \a name. */ ResourceCollection ResourceCollectionManager::collectionByName(const QByteArray &name) const { return m_collections.value(name); } /*! Inserts the \a collection into the collection manager. */ void ResourceCollectionManager::insertCollection(const ResourceCollection& collection) { m_collections.insert(collection.name(), collection); } /*! Removes all occurrences of \a name from the collection manager. */ void ResourceCollectionManager::removeCollection(const QByteArray &name) { m_collections.remove(name); } /*! Returns the collections the collection manager contains. */ QList ResourceCollectionManager::collections() const { return m_collections.values(); } /*! Clears the contents of the collection manager. */ void ResourceCollectionManager::clear() { m_collections.clear(); } /*! Returns the number of collections in the collection manager. */ int ResourceCollectionManager::collectionCount() const { return m_collections.count(); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/binaryformat.h0100777000000000000000000000756113761647206021474 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYFORMAT_H #define BINARYFORMAT_H #include "installer_global.h" #include "range.h" #include #include #include #include namespace QInstaller { struct OperationBlob { OperationBlob(const QString &n, const QString &x) : name(n), xml(x) {} QString name; QString xml; }; class INSTALLER_EXPORT Resource : public QIODevice { Q_OBJECT Q_DISABLE_COPY(Resource) public: explicit Resource(const QString &path); Resource(const QString &path, const QByteArray &name); Resource(const QString &path, const Range &segment); ~Resource(); bool open(); void close(); bool seek(qint64 pos); qint64 size() const; QByteArray name() const; void setName(const QByteArray &name); Range segment() const { return m_segment; } void setSegment(const Range &segment) { m_segment = segment; } void copyData(QFileDevice *out) { copyData(this, out); } static void copyData(Resource *archive, QFileDevice *out); private: qint64 readData(char *data, qint64 maxSize); qint64 writeData(const char *data, qint64 maxSize); bool open(OpenMode mode) { return QIODevice::open(mode); } void setOpenMode(OpenMode mode) { QIODevice::setOpenMode(mode); } private: QFSFileEngine m_file; QByteArray m_name; Range m_segment; }; class INSTALLER_EXPORT ResourceCollection { Q_DECLARE_TR_FUNCTIONS(ResourceCollection) public: ResourceCollection(); explicit ResourceCollection(const QByteArray &name); QByteArray name() const; void setName(const QByteArray &ba); QList > resources() const; QSharedPointer resourceByName(const QByteArray &name) const; void appendResource(const QSharedPointer &resource); void appendResources(const QList > &resources); private: QByteArray m_name; QList > m_resources; }; class INSTALLER_EXPORT ResourceCollectionManager { Q_DECLARE_TR_FUNCTIONS(ResourceCollectionManager) public: void read(QFileDevice *dev, qint64 offset); Range write(QFileDevice *dev, qint64 offset) const; void clear(); int collectionCount() const; QList collections() const; ResourceCollection collectionByName(const QByteArray &name) const; void removeCollection(const QByteArray &name); void insertCollection(const ResourceCollection &collection); private: QHash m_collections; }; } // namespace QInstaller #endif // BINARYFORMAT_H qt-installer-framework-4.0.1/src/libs/installer/binaryformatengine.cpp0100777000000000000000000001700613761647206023210 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binaryformatengine.h" #include namespace { class StringListIterator : public QAbstractFileEngineIterator { public: StringListIterator( const QStringList &list, QDir::Filters filters, const QStringList &nameFilters) : QAbstractFileEngineIterator(filters, nameFilters) , list(list) , index(-1) { } bool hasNext() const { return index < list.size() - 1; } QString next() { if(!hasNext()) return QString(); ++index; return currentFilePath(); } QString currentFileName() const { return index < 0 ? QString() : list[index]; } private: const QStringList list; int index; }; } // anon namespace namespace QInstaller { /*! \class QInstaller::BinaryFormatEngine \inmodule QtInstallerFramework \brief The BinaryFormatEngine class is the default file engine for accessing resource collections and resource files. */ /*! Constructs a new binary format engine with \a collections and \a fileName. */ BinaryFormatEngine::BinaryFormatEngine(const QHash &collections, const QString &fileName) : m_resource(nullptr) , m_collections(collections) { setFileName(fileName); } /*! \internal Sets the file engine's file name to \a file. This is the file that the rest of the virtual functions will operate on. */ void BinaryFormatEngine::setFileName(const QString &file) { m_fileNamePath = file; static const QChar sep = QLatin1Char('/'); static const QString prefix = QLatin1String("installer://"); Q_ASSERT(m_fileNamePath.toLower().startsWith(prefix)); // cut the prefix QString path = m_fileNamePath.mid(prefix.length()); while (path.endsWith(sep)) path.chop(1); m_collection = m_collections.value(path.section(sep, 0, 0).toUtf8()); m_collection.setName(path.section(sep, 0, 0).toUtf8()); m_resource = m_collection.resourceByName(path.section(sep, 1, 1).toUtf8()); } /*! \internal */ bool BinaryFormatEngine::close() { if (m_resource.isNull()) return false; const bool result = m_resource->isOpen(); m_resource->close(); return result; } /*! \internal */ bool BinaryFormatEngine::open(QIODevice::OpenMode mode) { Q_UNUSED(mode) return m_resource.isNull() ? false : m_resource->open(); } /*! \internal */ qint64 BinaryFormatEngine::pos() const { return m_resource.isNull() ? 0 : m_resource->pos(); } /*! \internal */ qint64 BinaryFormatEngine::read(char *data, qint64 maxlen) { return m_resource.isNull() ? -1 : m_resource->read(data, maxlen); } /*! \internal */ bool BinaryFormatEngine::seek(qint64 offset) { return m_resource.isNull() ? false : m_resource->seek(offset); } /*! \internal */ QString BinaryFormatEngine::fileName(FileName file) const { static const QChar sep = QLatin1Char('/'); switch(file) { case BaseName: return m_fileNamePath.section(sep, -1, -1, QString::SectionSkipEmpty); case PathName: case AbsolutePathName: case CanonicalPathName: return m_fileNamePath.section(sep, 0, -2, QString::SectionSkipEmpty); case DefaultName: case AbsoluteName: case CanonicalName: return m_fileNamePath; default: return QString(); } } /*! \internal */ bool BinaryFormatEngine::copy(const QString &newName) { if (QFile::exists(newName)) return false; QFile target(newName); if (!target.open(QIODevice::WriteOnly)) return false; qint64 bytesLeft = size(); if (!open(QIODevice::ReadOnly)) return false; char data[4096]; while(bytesLeft > 0) { const qint64 len = qMin(bytesLeft, 4096); const qint64 bytesRead = read(data, len); if (bytesRead != len) { close(); return false; } const qint64 bytesWritten = target.write(data, len); if (bytesWritten != len) { close(); return false; } bytesLeft -= len; } close(); return true; } /*! \internal */ QAbstractFileEngine::FileFlags BinaryFormatEngine::fileFlags(FileFlags type) const { FileFlags result; if ((type & FileType) && (!m_resource.isNull())) result |= FileType; if ((type & DirectoryType) && m_resource.isNull()) result |= DirectoryType; if ((type & ExistsFlag) && (!m_resource.isNull())) result |= ExistsFlag; if ((type & ExistsFlag) && m_resource.isNull() && (!m_collection.name().isEmpty())) result |= ExistsFlag; return result; } /*! \internal */ QAbstractFileEngineIterator *BinaryFormatEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) { const QStringList entries = entryList(filters, filterNames); return new StringListIterator(entries, filters, filterNames); } /*! \internal */ QStringList BinaryFormatEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const { if (!m_resource.isNull()) return QStringList(); QStringList result; if ((!m_collection.name().isEmpty()) && (filters & QDir::Files)) { foreach (const QSharedPointer &resource, m_collection.resources()) result.append(QString::fromUtf8(resource->name())); } else if (m_collection.name().isEmpty() && (filters & QDir::Dirs)) { foreach (const ResourceCollection &collection, m_collections) result.append(QString::fromUtf8(collection.name())); } result.removeAll(QString()); // Remove empty names, will crash while using directory iterator. if (filterNames.isEmpty()) return result; QList regexps; foreach (const QString &i, filterNames) regexps.append(QRegExp(i, Qt::CaseInsensitive, QRegExp::Wildcard)); QStringList entries; foreach (const QString &i, result) { bool matched = false; foreach (const QRegExp ®, regexps) { matched = reg.exactMatch(i); if (matched) break; } if (matched) entries.append(i); } return entries; } /*! \internal */ qint64 BinaryFormatEngine::size() const { return m_resource.isNull() ? 0 : m_resource->size(); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/binaryformatengine.h0100777000000000000000000000460013761647206022651 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYFORMATENGINE_H #define BINARYFORMATENGINE_H #include "binaryformat.h" #include namespace QInstaller { class BinaryFormatEngine : public QAbstractFileEngine { Q_DISABLE_COPY(BinaryFormatEngine) public: BinaryFormatEngine(const QHash &collections, const QString &fileName); void setFileName(const QString &file); bool copy(const QString &newName); bool close(); bool open(QIODevice::OpenMode mode); qint64 pos() const; qint64 read(char *data, qint64 maxlen); bool seek(qint64 offset); qint64 size() const; QString fileName(FileName file = DefaultName) const; FileFlags fileFlags(FileFlags type = FileInfoAll) const; Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames); QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const; private: QString m_fileNamePath; ResourceCollection m_collection; QSharedPointer m_resource; QHash m_collections; }; } // namespace QInstaller #endif // BINARYFORMATENGINE_H qt-installer-framework-4.0.1/src/libs/installer/binaryformatenginehandler.cpp0100777000000000000000000000767113761647206024555 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binaryformatengine.h" #include "binaryformatenginehandler.h" #include "productkeycheck.h" namespace QInstaller { /*! \class QInstaller::BinaryFormatEngineHandler \inmodule QtInstallerFramework \brief The BinaryFormatEngineHandler class provides a way to register resource collections and resource files. */ /*! Creates a file engine for the file specified by \a fileName. To be able to create a file engine, the file name needs to be prefixed with \c {installer://}. Returns 0 if the engine cannot handle \a fileName. */ QAbstractFileEngine *BinaryFormatEngineHandler::create(const QString &fileName) const { return fileName.startsWith(QLatin1String("installer://"), Qt::CaseInsensitive ) ? new BinaryFormatEngine(m_resources, fileName) : nullptr; } /*! Clears the contents of the binary format engine. */ void BinaryFormatEngineHandler::clear() { m_resources.clear(); } /*! Returns the active instance of the engine. */ BinaryFormatEngineHandler *BinaryFormatEngineHandler::instance() { static BinaryFormatEngineHandler instance; return &instance; } /*! Registers the given resource collections \a collections in the engine. */ void BinaryFormatEngineHandler::registerResources(const QList &collections) { foreach (const ResourceCollection &collection, collections) { if (ProductKeyCheck::instance()->isValidPackage(QString::fromUtf8(collection.name()))) m_resources.insert(collection.name(), collection); } } /*! Registers the resource specified by \a resourcePath in a resource collection specified by \a fileName. The file name \a fileName must be in the form of \c {installer://}, followed by the collection name and resource name separated by a forward slash. A valid file name looks like this: installer://collectionName/resourceName */ void BinaryFormatEngineHandler::registerResource(const QString &fileName, const QString &resourcePath) { static const QChar sep = QChar::fromLatin1('/'); static const QString prefix = QString::fromLatin1("installer://"); Q_ASSERT(fileName.toLower().startsWith(prefix)); // cut the prefix QString path = fileName.mid(prefix.length()); while (path.endsWith(sep)) path.chop(1); const QByteArray resourceName = path.section(sep, 1, 1).toUtf8(); const QByteArray collectionName = path.section(sep, 0, 0).toUtf8(); if (!ProductKeyCheck::instance()->isValidPackage(QString::fromUtf8(collectionName))) return; m_resources[collectionName].setName(collectionName); m_resources[collectionName].appendResource(QSharedPointer(new Resource(resourcePath, resourceName))); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/binaryformatenginehandler.h0100777000000000000000000000404313761647206024210 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYFORMATENGINEHANDLER_H #define BINARYFORMATENGINEHANDLER_H #include "binaryformat.h" #include namespace QInstaller { class INSTALLER_EXPORT BinaryFormatEngineHandler : public QAbstractFileEngineHandler { Q_DISABLE_COPY(BinaryFormatEngineHandler) public: QAbstractFileEngine *create(const QString &fileName) const; void clear(); static BinaryFormatEngineHandler *instance(); void registerResources(const QList &collections); void registerResource(const QString &fileName, const QString &resourcePath); private: BinaryFormatEngineHandler() {} ~BinaryFormatEngineHandler() {} private: QHash m_resources; }; } // namespace QInstaller #endif // BINARYFORMATENGINEHANDLER_H qt-installer-framework-4.0.1/src/libs/installer/binarylayout.cpp0100777000000000000000000000647413761647206022056 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ /*! \class QInstaller::BinaryLayout \inmodule QtInstallerFramework \brief The BinaryLayout class describes the binary content appended to a file. Explanation of the binary content at the end of the installer or the separate data file: \code Meta data entry [1 ... n] [Format] Plain data (QResource) [Format] ---------------------------------------------------------- Operation count (qint64) Operation entry [1 ... n] [Format] Name (qint64, QString) XML (qint64, QString) [Format] Operation count (qint64) ---------------------------------------------------------- Collection count Collection data entry [1 ... n] [Format] Archive count (qint64), Name entry [1 ... n] [Format] Name (qint64, QByteArray), Offset (qint64), Length (qint64), [Format] Archive data entry [1 ... n] [Format] Plain data [Format] [Format] ---------------------------------------------------------- Collection count (qint64) Collection index entry [1 ... n] [Format] Name (qint64, QByteArray) Offset (qint64) Length (qint64) [Format] Collection count (qint64) ---------------------------------------------------------- Collection index block [Offset (qint64)] Collection index block [Length (qint64)] ---------------------------------------------------------- Resource segments [1 ... n] [Format] Offset (qint64) Length (qint64) [Format] ---------------------------------------------------------- Operations information block [Offset (qint64)] Operations information block [Length (qint64)] ---------------------------------------------------------- Meta data count (qint64) ---------------------------------------------------------- Binary content size [Including Marker and Cookie (qint64)] ---------------------------------------------------------- Magic marker (qint64) Magic cookie (qint64) \endcode */ qt-installer-framework-4.0.1/src/libs/installer/binarylayout.h0100777000000000000000000000334413761647206021514 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYLAYOUT_H #define BINARYLAYOUT_H #include "range.h" #include namespace QInstaller { struct BinaryLayout { qint64 endOfExectuable; QVector > metaResourceSegments; Range metaResourcesSegment; Range operationsSegment; Range resourceCollectionsSegment; qint64 binaryContentSize; qint64 magicMarker; quint64 magicCookie; qint64 endOfBinaryContent; }; } // namespace QInstaller #endif // BINARYLAYOUT qt-installer-framework-4.0.1/src/libs/installer/commandlineparser.cpp0100777000000000000000000003535113761647206023033 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "commandlineparser.h" #include "constants.h" #include "globals.h" namespace CommandLineOptions { static const QLatin1String scCommand("Command"); static const QLatin1String scArguments("Args"); static const QLatin1String scInstallerValue("InstallerValue"); } // namespace CommandLineOptions CommandLineParser::CommandLineParser() : d(new CommandLineParserPrivate()) { static const QLatin1String indent(" "); static const QString preformatted = QLatin1String("\nQt Installer Framework supports both GUI and " "headless mode. The installation operations can be invoked with the following commands and " "options. Note that the options marked with \"CLI\" are available in the headless mode only.\n") + QLatin1String("\nCommands:\n") + indent + QString::fromLatin1("%1, %2 - install default or selected packages - \n") .arg(CommandLineOptions::scInstallShort, CommandLineOptions::scInstallLong) + indent + QString::fromLatin1("%1, %2 - show available updates information on maintenance tool\n") .arg(CommandLineOptions::scCheckUpdatesShort, CommandLineOptions::scCheckUpdatesLong) + indent + QString::fromLatin1("%1, %2 - update all or selected packages - \n") .arg(CommandLineOptions::scUpdateShort, CommandLineOptions::scUpdateLong) + indent + QString::fromLatin1("%1, %2 - uninstall packages and their child components - \n") .arg(CommandLineOptions::scRemoveShort, CommandLineOptions::scRemoveLong) + indent + QString::fromLatin1("%1, %2 - list currently installed packages\n") .arg(CommandLineOptions::scListShort, CommandLineOptions::scListLong) + indent + QString::fromLatin1("%1, %2 - search available packages - \n") .arg(CommandLineOptions::scSearchShort, CommandLineOptions::scSearchLong) + indent + QString::fromLatin1("%1, %2 - uninstall all packages and remove entire program directory") .arg(CommandLineOptions::scPurgeShort, CommandLineOptions::scPurgeLong); m_parser.setApplicationDescription(preformatted); // Help & version information m_parser.addHelpOption(); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scVersionShort << CommandLineOptions::scVersionLong, QLatin1String("Displays version information."))); // Output related options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scVerboseShort << CommandLineOptions::scVerboseLong, QString::fromLatin1("Verbose mode. Prints out more information. Adding -%1 or --%2 more " "than once increases verbosity.").arg(CommandLineOptions::scVerboseShort, CommandLineOptions::scVerboseLong))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scLoggingRulesShort << CommandLineOptions::scLoggingRulesLong, QLatin1String("Enables logging according to passed rules. Comma separated logging rules " "have the following syntax: loggingCategory=true/false. Passing empty logging " "rules enables all logging categories. The following rules enable a single " "category: ifw.*=false, ifw.category=true. The following logging categories " "are available:\n") + QInstaller::loggingCategories().join(QLatin1Char('\n')), QLatin1String("rules"))); // Repository management options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scAddRepositoryShort << CommandLineOptions::scAddRepositoryLong, QLatin1String("Add a local or remote repository to the list of user defined repositories."), QLatin1String("URI,..."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scAddTmpRepositoryShort << CommandLineOptions::scAddTmpRepositoryLong, QLatin1String("Add a local or remote repository to the list of temporary available repositories."), QLatin1String("URI,..."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scSetTmpRepositoryShort << CommandLineOptions::scSetTmpRepositoryLong, QLatin1String("Set a local or remote repository as temporary repository, it is the only " "one used during fetch.\nNote: URI must be prefixed with the protocol, i.e. " "file:///, https://, http:// or ftp://."), QLatin1String("URI,..."))); // Proxy options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scSystemProxyShort << CommandLineOptions::scSystemProxyLong, QLatin1String("Use system proxy on Windows and Linux. This option has no effect on macOS. (Default)"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scNoProxyShort << CommandLineOptions::scNoProxyLong, QLatin1String("Do not use system proxy."))); // Starting mode options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scStartUpdaterShort << CommandLineOptions::scStartUpdaterLong, QLatin1String("Start application in updater mode. This will override the internal " "marker that is used to distinguish which kind of binary is currently running."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scStartPackageManagerShort << CommandLineOptions::scStartPackageManagerLong, QLatin1String("Start application in package manager mode. This will override the internal " "marker that is used to distinguish which kind of binary is currently running."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scStartUninstallerShort << CommandLineOptions::scStartUninstallerLong, QLatin1String("Start application in uninstaller mode. This will override the internal " "marker that is used to distinguish which kind of binary is currently running."))); // Misc installation options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scRootShort << CommandLineOptions::scRootLong, QLatin1String("[CLI] Set installation root directory."), QLatin1String("directory"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scPlatformShort << CommandLineOptions::scPlatformLong, QLatin1String("Use the specified platform plugin."), QLatin1String("plugin"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scNoForceInstallationShort << CommandLineOptions::scNoForceInstallationLong, QLatin1String("Allow deselecting components that are marked as forced."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scNoDefaultInstallationShort << CommandLineOptions::scNoDefaultInstallationLong, QLatin1String("Deselects components that are marked as default."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scNoSizeCheckingShort << CommandLineOptions::scNoSizeCheckingLong, QLatin1String("Disable checking of free space for installation target."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scShowVirtualComponentsShort << CommandLineOptions::scShowVirtualComponentsLong, QLatin1String("Show virtual components in installer and package manager."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scInstallCompressedRepositoryShort << CommandLineOptions::scInstallCompressedRepositoryLong, QLatin1String("Installs QBSP or 7z file. The QBSP (Board Support Package) file must be a .7z " "file which contains a valid repository."), QLatin1String("URI,..."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scCreateLocalRepositoryShort << CommandLineOptions::scCreateLocalRepositoryLong, QLatin1String("Create a local repository inside the installation directory. This option " "has no effect on online installers."))); // Message query options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptMessageQueryShort << CommandLineOptions::scAcceptMessageQueryLong, QLatin1String("[CLI] Accepts all message queries without user input."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scRejectMessageQueryShort << CommandLineOptions::scRejectMessageQueryLong, QLatin1String("[CLI] Rejects all message queries without user input."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scMessageAutomaticAnswerShort << CommandLineOptions::scMessageAutomaticAnswerLong, QLatin1String("[CLI] Automatically answers the message queries with the message identifier and button value. " "Several identifier=value pairs can be given separated with comma, " "for example --auto-answer message.id=Ok,message.id2=Cancel."), QLatin1String("identifier=value"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scMessageDefaultAnswerShort << CommandLineOptions::scMessageDefaultAnswerLong, QLatin1String("[CLI] Automatically answers to message queries with their default values."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptLicensesShort << CommandLineOptions::scAcceptLicensesLong, QLatin1String("[CLI] Accepts all licenses without user input."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scFileDialogAutomaticAnswer, QLatin1String("[CLI] Automatically sets the QFileDialog values getExistingDirectory() or getOpenFileName() " "requested by install script. " "Several identifier=value pairs can be given separated with comma, " "for example --file-query filedialog.id=C:\Temp,filedialog.id2=C:\Temp2"), QLatin1String("identifier=value"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scConfirmCommandShort << CommandLineOptions::scConfirmCommandLong, QLatin1String("[CLI] Confirms starting of " "installation, update or removal of components without user input."))); // Developer options m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scScriptShort << CommandLineOptions::scScriptLong, QLatin1String("Execute the script given as argument."), QLatin1String("file"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scStartServerShort << CommandLineOptions::scStartServerLong, QLatin1String("Starts the application as headless process waiting for commands to execute. Mode " "can be DEBUG or PRODUCTION. In DEBUG mode, the option values can be omitted. Note: " "The server will not shutdown on his own, you need to quit the process by hand."), QLatin1String("mode, socketname, key"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scStartClientShort << CommandLineOptions::scStartClientLong, QLatin1String("Starts the application to debug the client-server communication. If a value is " "omitted, the client will use a default instead. Note: The server process is not " "started by the client application in that case, you need to start it on your own."), QLatin1String("socketname, key"))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scSquishPortShort << CommandLineOptions::scSquishPortLong, QLatin1String("Give a port where Squish can connect to. If no port is given, default port 11233 is " "used. Note: To enable Squish support you first need to build IFW with SQUISH_PATH " "parameter where SQUISH_PATH is pointing to your Squish installation folder: " "/bin/qmake -r SQUISH_PATH="), QLatin1String("port number"))); // Deprecated options QCommandLineOption deprecatedUpdater(CommandLineOptions::scDeprecatedUpdater); deprecatedUpdater.setHidden(true); m_parser.addOption(deprecatedUpdater); QCommandLineOption deprecatedCheckUpdates(CommandLineOptions::scDeprecatedCheckUpdates); deprecatedCheckUpdates.setHidden(true); m_parser.addOption(deprecatedCheckUpdates); // Behaves like check-updates but does not default to verbose output // Custom extension options m_parser.addOptions(d->extensionsOptions()); // Positional arguments m_parser.addPositionalArgument(CommandLineOptions::scCommand, QLatin1String("Command to be run by installer. Note that this feature may be disabled by vendor."), QLatin1String("command")); m_parser.addPositionalArgument(CommandLineOptions::scArguments, QLatin1String("Extra arguments for command, each separated by space."), QLatin1String("")); m_parser.addPositionalArgument(CommandLineOptions::scInstallerValue, QLatin1String("Key-value pair to be set internally by the framework."), QLatin1String("")); } CommandLineParser::~CommandLineParser() { delete d; } qt-installer-framework-4.0.1/src/libs/installer/commandlineparser.h0100777000000000000000000000412413761647206022472 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMMANDLINEPARSER_H #define COMMANDLINEPARSER_H #include "commandlineparser_p.h" #include class CommandLineParser { public: CommandLineParser(); ~CommandLineParser(); QString helpText() const { return m_parser.helpText(); } bool isSet(const QString &option) { return m_parser.isSet(option); } QStringList unknownOptionNames() const { return m_parser.unknownOptionNames(); } QStringList positionalArguments() const { return m_parser.positionalArguments(); } bool parse(const QStringList &argumens) { return m_parser.parse(argumens); } QString value(const QString &option) const { return m_parser.value(option); } QStringList optionNames() const { return m_parser.optionNames(); } private: QCommandLineParser m_parser; class CommandLineParserPrivate *const d; }; #endif // COMMANDLINEPARSER_H qt-installer-framework-4.0.1/src/libs/installer/commandlineparser_p.cpp0100777000000000000000000000251113761647206023342 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "commandlineparser_p.h" CommandLineParserPrivate::CommandLineParserPrivate() { } qt-installer-framework-4.0.1/src/libs/installer/commandlineparser_p.h0100777000000000000000000000312613761647206023012 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMMANDLINEPARSER_P_H #define COMMANDLINEPARSER_P_H #include class CommandLineParserPrivate { public: CommandLineParserPrivate(); QList &extensionsOptions() { return m_extensionOptions; } private: QList m_extensionOptions; }; #endif // COMMANDLINEPARSER_P_H qt-installer-framework-4.0.1/src/libs/installer/component.cpp0100777000000000000000000015125313761647206021332 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "component.h" #include "scriptengine.h" #include "errors.h" #include "fileutils.h" #include "globals.h" #include "lib7z_facade.h" #include "messageboxhandler.h" #include "packagemanagercore.h" #include "remoteclient.h" #include "settings.h" #include "utils.h" #include "updateoperationfactory.h" #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5,14,0) #include #else #include #endif #include #include #include using namespace QInstaller; static const QLatin1String scScriptTag("Script"); static const QLatin1String scVirtual("Virtual"); static const QLatin1String scInstalled("Installed"); static const QLatin1String scUpdateText("UpdateText"); static const QLatin1String scUninstalled("Uninstalled"); static const QLatin1String scCurrentState("CurrentState"); static const QLatin1String scForcedInstallation("ForcedInstallation"); static const QLatin1String scCheckable("Checkable"); static const QLatin1String scExpandedByDefault("ExpandedByDefault"); static const QLatin1String scUnstable("Unstable"); /*! \enum QInstaller::Component::UnstableError This enum type holds the component unstable error reason: \value DepencyToUnstable Component has a dependency to an unstable component. \value ShaMismatch Component has packages with non-matching SHA values. \value ScriptLoadingFailed Component script has errors or loading fails. \value MissingDependency Component has dependencies to missing components. */ /*! \inmodule QtInstallerFramework \class QInstaller::Component::SortingPriorityLessThan \brief The SortingPriorityLessThan class sets an increasing sorting order for child components. If the component contains several children and has this sorting priority set, the child list is sorted so that the child component with the lowest priority is placed on top. */ /*! \fn QInstaller::Component::SortingPriorityLessThan::operator() (const Component *lhs, const Component *rhs) const Returns \c true if \a lhs is less than \a rhs; otherwise returns \c false. */ /*! \inmodule QtInstallerFramework \class QInstaller::Component::SortingPriorityGreaterThan \brief The SortingPriorityGreaterThan class sets a decreasing sorting priority for child components. If the component contains several children and has this sorting priority set, the child list is sorted so that the child component with the highest priority is placed on top. */ /*! \fn QInstaller::Component::SortingPriorityGreaterThan::operator() (const Component *lhs, const Component *rhs) const Returns \c true if \a lhs is greater than \a rhs; otherwise returns \c false. */ /*! \inmodule QtInstallerFramework \class QInstaller::Component \brief The Component class represents the current component. */ /*! \property QInstaller::Component::name \brief The name of the component as set in the \c tag of the package information file. */ /*! \property QInstaller::Component::displayName \brief The name of the component as shown in the user interface. */ /*! \property QInstaller::Component::autoCreateOperations \brief Whether some standard operations for the component should be automatically created when the installation starts. The default is \c true. */ /*! \property QInstaller::Component::archives \brief The list of archive URLs registered for the component. The URLs are prefixed with \c {installer://}. \sa addDownloadableArchive(), removeDownloadableArchive() */ /*! \property QInstaller::Component::dependencies \brief The components this component depends on. This is a read-only property. */ /*! \property QInstaller::Component::autoDependencies \brief The value of the \c element in the package information file. */ /*! \property QInstaller::Component::fromOnlineRepository \brief Whether this component has been loaded from an online repository. */ /*! \property QInstaller::Component::repositoryUrl \brief The repository URL the component is downloaded from. If this component is not downloaded from an online repository, returns an empty QUrl. */ /*! \property QInstaller::Component::default \brief Whether the component is a default one. This is a read-only property. \note Always \c false for virtual components. */ /*! \property QInstaller::Component::installed \brief Whether the component is installed. This is a read-only property. */ /*! \property QInstaller::Component::enabled \brief Whether the component is currently enabled. The property is both readable and writable. */ /*! \property QInstaller::Component::unstable \brief Whether the component is unstable. This is a read-only property. \note Unstable components cannot be selected for installation. */ /*! \fn QInstaller::Component::loaded() \sa {component::loaded}{component.loaded} */ /*! \fn QInstaller::Component::valueChanged(const QString &key, const QString &value) Emitted when the value of the variable with the name \a key changes to \a value. \sa {component::valueChanged}{component.valueChanged}, setValue() */ /*! \fn QInstaller::Component::virtualStateChanged() \sa {component::virtualStateChanged}{component.virtualStateChanged} */ /*! Creates a new component in the package manager specified by \a core. */ Component::Component(PackageManagerCore *core) : d(new ComponentPrivate(core, this)) { setPrivate(d); connect(this, &Component::valueChanged, this, &Component::updateModelData); qRegisterMetaType >("QList"); } /*! Destroys the component. */ Component::~Component() { if (parentComponent() != 0) d->m_parentComponent->d->m_allChildComponents.removeAll(this); //why can we delete all create operations if the component gets destroyed if (!d->m_newlyInstalled) qDeleteAll(d->m_operations); //we need to copy the list, because we are changing it with removeAll at top //(this made the iterators broken in the past) QList copiedChildrenList = d->m_allChildComponents; copiedChildrenList.detach(); //this makes it a real copy qDeleteAll(copiedChildrenList); delete d; d = 0; } /*! Sets variables according to the values set in the package.xml file of a local \a package. */ void Component::loadDataFromPackage(const KDUpdater::LocalPackage &package) { setValue(scName, package.name); setValue(scDisplayName, package.title); setValue(scDescription, package.description); setValue(scVersion, package.version); setValue(scInheritVersion, package.inheritVersionFrom); setValue(scInstalledVersion, package.version); setValue(QLatin1String("LastUpdateDate"), package.lastUpdateDate.toString()); setValue(QLatin1String("InstallDate"), package.installDate.toString()); setValue(scUncompressedSize, QString::number(package.uncompressedSize)); setValue(scDependencies, package.dependencies.join(QLatin1String(","))); setValue(scAutoDependOn, package.autoDependencies.join(QLatin1String(","))); setValue(scForcedInstallation, package.forcedInstallation ? scTrue : scFalse); if (package.forcedInstallation & !PackageManagerCore::noForceInstallation()) { setCheckable(false); setCheckState(Qt::Checked); } setValue(scVirtual, package.virtualComp ? scTrue : scFalse); setValue(scCurrentState, scInstalled); setValue(scCheckable, package.checkable ? scTrue : scFalse); setValue(scExpandedByDefault, package.expandedByDefault ? scTrue : scFalse); } /*! Sets variables according to the values set in the package.xml file of \a package. Also loads UI files, licenses and translations if they are referenced in the package.xml. */ void Component::loadDataFromPackage(const Package &package) { Q_ASSERT(&package); setValue(scName, package.data(scName).toString()); setValue(scDisplayName, package.data(scDisplayName).toString()); setValue(scDescription, package.data(scDescription).toString()); setValue(scDefault, package.data(scDefault).toString()); setValue(scAutoDependOn, package.data(scAutoDependOn).toString()); setValue(scCompressedSize, package.data(scCompressedSize).toString()); setValue(scUncompressedSize, package.data(scUncompressedSize).toString()); setValue(scVersion, package.data(scVersion).toString()); setValue(scInheritVersion, package.data(scInheritVersion).toString()); setValue(scDependencies, package.data(scDependencies).toString()); setValue(scDownloadableArchives, package.data(scDownloadableArchives).toString()); setValue(scVirtual, package.data(scVirtual).toString()); setValue(scSortingPriority, package.data(scSortingPriority).toString()); setValue(scEssential, package.data(scEssential).toString()); setValue(scUpdateText, package.data(scUpdateText).toString()); setValue(scNewComponent, package.data(scNewComponent).toString()); setValue(scRequiresAdminRights, package.data(scRequiresAdminRights).toString()); setValue(scScriptTag, package.data(scScriptTag).toString()); setValue(scReplaces, package.data(scReplaces).toString()); setValue(scReleaseDate, package.data(scReleaseDate).toString()); setValue(scCheckable, package.data(scCheckable).toString()); setValue(scExpandedByDefault, package.data(scExpandedByDefault).toString()); QString forced = package.data(scForcedInstallation, scFalse).toString().toLower(); if (PackageManagerCore::noForceInstallation()) forced = scFalse; setValue(scForcedInstallation, forced); if (forced == scTrue) { setCheckable(false); setCheckState(Qt::Checked); } setLocalTempPath(QInstaller::pathFromUrl(package.packageSource().url)); const QStringList uis = package.data(QLatin1String("UserInterfaces")).toString() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (!uis.isEmpty()) loadUserInterfaces(QDir(QString::fromLatin1("%1/%2").arg(localTempPath(), name())), uis); #ifndef IFW_DISABLE_TRANSLATIONS const QStringList qms = package.data(QLatin1String("Translations")).toString() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (!qms.isEmpty()) loadTranslations(QDir(QString::fromLatin1("%1/%2").arg(localTempPath(), name())), qms); #endif QHash licenseHash = package.data(QLatin1String("Licenses")).toHash(); if (!licenseHash.isEmpty()) loadLicenses(QString::fromLatin1("%1/%2/").arg(localTempPath(), name()), licenseHash); } /*! Returns the size of a compressed archive. */ quint64 Component::updateUncompressedSize() { quint64 size = 0; if (installAction() == ComponentModelHelper::Install || installAction() == ComponentModelHelper::KeepInstalled) { size = d->m_vars.value(scUncompressedSize).toLongLong(); } foreach (Component* comp, d->m_allChildComponents) size += comp->updateUncompressedSize(); setValue(scUncompressedSizeSum, QString::number(size)); setData(humanReadableSize(size), UncompressedSize); return size; } /*! Marks the component as installed. */ void Component::markAsPerformedInstallation() { d->m_newlyInstalled = true; } /*! Returns a key and value based hash of all variables set for this component. */ QHash Component::variables() const { return d->m_vars; } /*! Returns the value of variable name \a key. If \a key is not known yet, \a defaultValue is returned. \note If a component is virtual and you ask for the component value with the key \c Default, it will always return \c false. */ QString Component::value(const QString &key, const QString &defaultValue) const { if (key == scDefault) return isDefault() ? scTrue : scFalse; return d->m_vars.value(key, defaultValue); } /*! Sets the value of the variable with \a key to \a value. \sa {component::setValue}{component.setValue} */ void Component::setValue(const QString &key, const QString &value) { QString normalizedValue = d->m_core->replaceVariables(value); if (d->m_vars.value(key) == normalizedValue) return; if (key == scDefault && d->m_core->noDefaultInstallation()) normalizedValue = scFalse; if (key == scName) d->m_componentName = normalizedValue; if (key == scCheckable) this->setCheckable(normalizedValue.toLower() == scTrue); if (key == scExpandedByDefault) this->setExpandedByDefault(normalizedValue.toLower() == scTrue); d->m_vars[key] = normalizedValue; emit valueChanged(key, normalizedValue); } /*! Returns the installer this component belongs to. */ PackageManagerCore *Component::packageManagerCore() const { return d->m_core; } /*! Returns the parent of this component. For example, the parent of a component called \c org.qt-project.sdk.qt is \c org.qt-project.sdk if it exists. */ Component *Component::parentComponent() const { return d->m_parentComponent; } /*! Appends \a component as a child of this component. If \a component already has a parent, it is removed from the previous parent. If the \a component contains several children and has the SortingPriorityGreaterThan() sorting priority set, the child list is sorted so that the child component with the highest priority is placed on top. */ void Component::appendComponent(Component *component) { if (d->m_core->isUpdater()) throw Error(tr("Components cannot have children in updater mode.")); if (!component->isVirtual()) { const QList virtualChildComponents = d->m_allChildComponents.mid(d->m_childComponents.count()); d->m_childComponents.append(component); std::sort(d->m_childComponents.begin(), d->m_childComponents.end(), SortingPriorityGreaterThan()); d->m_allChildComponents = d->m_childComponents + virtualChildComponents; } else { d->m_allChildComponents.append(component); } if (Component *parent = component->parentComponent()) parent->removeComponent(component); component->d->m_parentComponent = this; setTristate(d->m_childComponents.count() > 0); } /*! Removes \a component if it is a child of this component. The component object still exists after the function returns. It is up to the caller to delete the passed \a component. */ void Component::removeComponent(Component *component) { if (component->parentComponent() == this) { component->d->m_parentComponent = 0; d->m_childComponents.removeAll(component); d->m_allChildComponents.removeAll(component); } } /*! Returns a list of child components, including all descendants of the component's children. \note The returned list does include all children; non-virtual components as well as virtual components. */ QList Component::descendantComponents() const { if (d->m_core->isUpdater()) return QList(); QList result = d->m_allChildComponents; foreach (Component *component, d->m_allChildComponents) result += component->descendantComponents(); return result; } /*! Contains the unique identifier of this component. */ QString Component::name() const { return d->m_componentName; } /*! Contains this component's display name as visible to the user. */ QString Component::displayName() const { return d->m_vars.value(scDisplayName); } /*! Loads the component script into the script engine. */ void Component::loadComponentScript() { const QString script = d->m_vars.value(scScriptTag); if (!localTempPath().isEmpty() && !script.isEmpty()) loadComponentScript(QString::fromLatin1("%1/%2/%3").arg(localTempPath(), name(), script)); } /*! Loads the script at \a fileName into the script engine. The installer and all its components as well as other useful things are being exported into the script. For more information, see \l{Component Scripting}. Throws an error when either the script at \a fileName could not be opened, or QScriptEngine could not evaluate the script. */ void Component::loadComponentScript(const QString &fileName) { // introduce the component object as javascript value and call the name to check that it // was successful try { d->m_scriptContext = d->scriptEngine()->loadInContext(QLatin1String("Component"), fileName, QString::fromLatin1("var component = installer.componentByName('%1'); component.name;") .arg(name())); if (packageManagerCore()->settings().allowUnstableComponents()) { // Check if component has dependency to a broken component. Dependencies to broken // components are checked if error is thrown but if dependency to a broken // component is added in script, the script might not be loaded yet foreach (QString dependency, dependencies()) { Component *dependencyComponent = packageManagerCore()->componentByName (PackageManagerCore::checkableName(dependency)); if (dependencyComponent && dependencyComponent->isUnstable()) setUnstable(Component::UnstableError::DepencyToUnstable, QLatin1String("Dependent on unstable component")); } } } catch (const Error &error) { if (packageManagerCore()->settings().allowUnstableComponents()) { setUnstable(Component::UnstableError::ScriptLoadingFailed, error.message()); qCWarning(QInstaller::lcDeveloperBuild) << error.message(); } else { throw error; } } emit loaded(); languageChanged(); } /*! \internal Calls the script method retranslateUi(), if any. This is done whenever a QTranslator file is being loaded. */ void Component::languageChanged() { d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("retranslateUi")); } /*! Loads the translations matching the name filters \a qms inside \a directory. Only translations with a base name matching the current locale's name are loaded. For more information, see \l{Translating Pages}. */ void Component::loadTranslations(const QDir &directory, const QStringList &qms) { QDirIterator it(directory.path(), qms, QDir::Files); const QStringList translations = d->m_core->settings().translations(); const QString uiLanguage = QLocale().uiLanguages().value(0, QLatin1String("en")); while (it.hasNext()) { const QString filename = it.next(); const QString basename = QFileInfo(filename).baseName(); if (!uiLanguage.startsWith(QFileInfo(filename).baseName(), Qt::CaseInsensitive)) continue; // do not load the file if it does not match the UI language if (!translations.isEmpty()) { bool found = false; foreach (const QString &translation, translations) found |= translation.startsWith(basename, Qt::CaseInsensitive); if (!found) // don't load the file if it does match the UI language but is not allowed to be used continue; } QScopedPointer translator(new QTranslator(this)); if (translator->load(filename)) { // Do not throw if translator returns false as it may just be an intentionally // empty file. See also QTBUG-31031 qApp->installTranslator(translator.take()); } } } /*! Loads the user interface files matching the name filters \a uis inside \a directory. The loaded interface can be accessed via userInterfaces() by using the class name set in the UI file. */ void Component::loadUserInterfaces(const QDir &directory, const QStringList &uis) { if (qobject_cast (qApp) == 0) return; QDirIterator it(directory.path(), uis, QDir::Files); while (it.hasNext()) { QFile file(it.next()); if (!file.open(QIODevice::ReadOnly)) { throw Error(tr("Cannot open the requested UI file \"%1\": %2").arg( it.fileName(), file.errorString())); } static QUiLoader loader; loader.setTranslationEnabled(true); loader.setLanguageChangeEnabled(true); QWidget *const widget = loader.load(&file, 0); if (!widget) { throw Error(tr("Cannot load the requested UI file \"%1\": %2").arg( it.fileName(), loader.errorString())); } d->scriptEngine()->newQObject(widget); d->m_userInterfaces.insert(widget->objectName(), widget); } } /*! Loads the text of the licenses contained in \a licenseHash from \a directory. This is saved into a new hash containing the filename and the text of that file. */ void Component::loadLicenses(const QString &directory, const QHash &licenseHash) { QHash::const_iterator it; for (it = licenseHash.begin(); it != licenseHash.end(); ++it) { const QString &fileName = it.value().toString(); if (!ProductKeyCheck::instance()->isValidLicenseTextFile(fileName)) continue; QFileInfo fileInfo(directory, fileName); foreach (const QString &lang, QLocale().uiLanguages()) { if (QLocale(lang).language() == QLocale::English) // we assume English is the default language break; QList fileCandidates; foreach (const QString &locale, QInstaller::localeCandidates(lang.toLower())) { fileCandidates << QFileInfo(QString::fromLatin1("%1%2_%3.%4").arg( directory, fileInfo.baseName(), locale, fileInfo.completeSuffix())); } auto fInfo = std::find_if(fileCandidates.constBegin(), fileCandidates.constEnd(), [](const QFileInfo &file) { return file.exists(); }); if (fInfo != fileCandidates.constEnd()) { fileInfo = *fInfo; break; } } QFile file(fileInfo.filePath()); if (!file.open(QIODevice::ReadOnly)) { throw Error(tr("Cannot open the requested license file \"%1\": %2").arg( file.fileName(), file.errorString())); } QTextStream stream(&file); stream.setCodec("UTF-8"); d->m_licenses.insert(it.key(), qMakePair(fileName, stream.readAll())); } } /*! \property QInstaller::Component::userInterfaces \brief A list of all user interface class names known to this component. */ QStringList Component::userInterfaces() const { return d->m_userInterfaces.keys(); } /*! Returns a hash that contains the file names and text of license files for the component. */ QHash > Component::licenses() const { return d->m_licenses; } /*! Returns the QWidget created for \a name or \c 0 if the widget has been deleted or cannot be found. \sa {component::userInterface}{component.userInterface} */ QWidget *Component::userInterface(const QString &name) const { return d->m_userInterfaces.value(name).data(); } /*! Creates all operations needed to install this component's \a path. \a path is a fully qualified filename including the component's name. This method gets called from createOperationsForArchive. You can override it by providing a method with the same name in the component script. \note RSA signature files are omitted by this method. \note If you call this method from a script, it will not call the script's method with the same name. The default implementation is recursively creating Copy and Mkdir operations for all files and folders within \a path. \sa {component::createOperationsForPath}{component.createOperationsForPath} */ void Component::createOperationsForPath(const QString &path) { const QFileInfo fi(path); // don't copy over a checksum file if (fi.suffix() == QLatin1String("sha1") && QFileInfo(fi.dir(), fi.completeBaseName()).exists()) return; // the script can override this method if (!d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("createOperationsForPath"), QJSValueList() << path).isUndefined()) { return; } QString target; static const QString prefix = QString::fromLatin1("installer://"); target = QString::fromLatin1("@TargetDir@%1").arg(path.mid(prefix.length() + name().length())); if (fi.isFile()) { static const QString copy = QString::fromLatin1("Copy"); addOperation(copy, QStringList() << fi.filePath() << target); } else if (fi.isDir()) { qApp->processEvents(); static const QString mkdir = QString::fromLatin1("Mkdir"); addOperation(mkdir, QStringList(target)); QDirIterator it(fi.filePath()); while (it.hasNext()) createOperationsForPath(it.next()); } } /*! Creates all operations needed to install this component's \a archive. This method gets called from createOperations. You can override this method by providing a method with the same name in the component script. \note If you call this method from a script, it will not call the script's method with the same name. The default implementation calls createOperationsForPath for everything contained in the archive. If \a archive is a compressed archive known to the installer system, an Extract operation is created, instead. \sa {component::createOperationsForArchive}{component.createOperationsForArchive} */ void Component::createOperationsForArchive(const QString &archive) { const QFileInfo fi(archive); // don't do anything with sha1 files if (fi.suffix() == QLatin1String("sha1") && QFileInfo(fi.dir(), fi.completeBaseName()).exists()) return; // the script can override this method if (!d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("createOperationsForArchive"), QJSValueList() << archive).isUndefined()) { return; } const bool isZip = Lib7z::isSupportedArchive(archive); if (isZip) { // archives get completely extracted per default (if the script isn't doing other stuff) addOperation(QLatin1String("Extract"), QStringList() << archive << QLatin1String("@TargetDir@")); } else { createOperationsForPath(archive); } } /*! \sa {component::beginInstallation}{component.beginInstallation} */ void Component::beginInstallation() { // the script can override this method d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("beginInstallation")); } /*! \sa {component::createOperations}{component.createOperations} \sa createOperationsForArchive() */ void Component::createOperations() { // the script can override this method if (!d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("createOperations")) .isUndefined()) { d->m_operationsCreated = true; return; } foreach (const QString &archive, archives()) createOperationsForArchive(archive); d->m_operationsCreated = true; } /*! Registers the file or directory at \a path for being removed when this component gets uninstalled. In case of a directory, this will be recursive. If \a wipe is set to \c true, the directory will also be deleted if it contains changes made by the user after installation. \sa {component::registerPathForUninstallation}{component.registerPathForUninstallation} */ void Component::registerPathForUninstallation(const QString &path, bool wipe) { d->m_pathsForUninstallation.append(qMakePair(path, wipe)); } /*! Returns the list of paths previously registered for uninstallation with registerPathForUninstallation(). */ QList > Component::pathsForUninstallation() const { return d->m_pathsForUninstallation; } /*! Contains the names of all archives known to this component. Even downloaded archives are mapped to the \c{installer://} URL through the used QFileEngineHandler during the download process. */ QStringList Component::archives() const { QString pathString = QString::fromLatin1("installer://%1/").arg(name()); QStringList archivesNameList = QDir(pathString).entryList(); //RegExp "^" means line beginning archivesNameList.replaceInStrings(QRegExp(QLatin1String("^")), pathString); return archivesNameList; } /*! Adds the archive \a path to this component. This can only be called if this component was downloaded from an online repository. When adding \a path, it will be downloaded from the repository when the installation starts. \sa {component::addDownloadableArchive}{component.addDownloadableArchive} \sa removeDownloadableArchive(), fromOnlineRepository, archives */ void Component::addDownloadableArchive(const QString &path) { Q_ASSERT(isFromOnlineRepository()); qCDebug(QInstaller::lcDeveloperBuild) << "addDownloadable" << path; d->m_downloadableArchives.append(d->m_vars.value(scVersion) + path); } /*! Removes the archive \a path previously added via addDownloadableArchive() from this component. This can only be called if this component was downloaded from an online repository. \sa {component::removeDownloadableArchive}{component.removeDownloadableArchive} \sa addDownloadableArchive(), fromOnlineRepository, archives */ void Component::removeDownloadableArchive(const QString &path) { Q_ASSERT(isFromOnlineRepository()); d->m_downloadableArchives.removeAll(path); } /*! Returns the archives to be downloaded from the online repository before installation. */ QStringList Component::downloadableArchives() const { return d->m_downloadableArchives; } /*! Adds a request for quitting the process \a process before installing, updating, or uninstalling the component. \sa {component::addStopProcessForUpdateRequest}{component.addStopProcessForUpdateRequest} */ void Component::addStopProcessForUpdateRequest(const QString &process) { d->m_stopProcessForUpdateRequests.append(process); } /*! Removes the request for quitting the process \a process again. \sa {component::removeStopProcessForUpdateRequest}{component.removeStopProcessForUpdateRequest} */ void Component::removeStopProcessForUpdateRequest(const QString &process) { d->m_stopProcessForUpdateRequests.removeAll(process); } /*! A convenience function for adding or removing the request for stopping \a process depending on whether \a requested is \c true (add) or \c false (remove). \sa {component::setStopProcessForUpdateRequest}{component.addStopProcessForUpdateReques} */ void Component::setStopProcessForUpdateRequest(const QString &process, bool requested) { if (requested) addStopProcessForUpdateRequest(process); else removeStopProcessForUpdateRequest(process); } /*! The list of processes that need to be closed before installing, updating, or uninstalling this component. */ QStringList Component::stopProcessForUpdateRequests() const { return d->m_stopProcessForUpdateRequests; } /*! Returns the operations needed to install this component. If autoCreateOperations() is \c true, createOperations() is called if no operations have been automatically created yet. */ OperationList Component::operations() const { if (d->m_autoCreateOperations && !d->m_operationsCreated) { const_cast(this)->createOperations(); if (!d->m_minimumProgressOperation) { d->m_minimumProgressOperation = KDUpdater::UpdateOperationFactory::instance() .create(QLatin1String("MinimumProgress"), d->m_core); d->m_minimumProgressOperation->setValue(QLatin1String("component"), name()); d->m_operations.append(d->m_minimumProgressOperation); } if (!d->m_licenses.isEmpty()) { d->m_licenseOperation = KDUpdater::UpdateOperationFactory::instance() .create(QLatin1String("License"), d->m_core); d->m_licenseOperation->setValue(QLatin1String("component"), name()); QVariantMap licenses; const QList > values = d->m_licenses.values(); for (int i = 0; i < values.count(); ++i) licenses.insert(values.at(i).first, values.at(i).second); d->m_licenseOperation->setValue(QLatin1String("licenses"), licenses); d->m_operations.append(d->m_licenseOperation); } } return d->m_operations; } /*! Adds \a operation to the list of operations needed to install this component. */ void Component::addOperation(Operation *operation) { d->m_operations.append(operation); if (RemoteClient::instance().isActive()) operation->setValue(QLatin1String("admin"), true); } /*! Adds \a operation to the list of operations needed to install this component. \a operation is executed with elevated rights. */ void Component::addElevatedOperation(Operation *operation) { addOperation(operation); operation->setValue(QLatin1String("admin"), true); } /*! Returns whether the operations needed to install this component were created successfully. */ bool Component::operationsCreatedSuccessfully() const { return d->m_operationsCreatedSuccessfully; } Operation *Component::createOperation(const QString &operationName, const QString ¶meter1, const QString ¶meter2, const QString ¶meter3, const QString ¶meter4, const QString ¶meter5, const QString ¶meter6, const QString ¶meter7, const QString ¶meter8, const QString ¶meter9, const QString ¶meter10) { QStringList arguments; if (!parameter1.isNull()) arguments.append(parameter1); if (!parameter2.isNull()) arguments.append(parameter2); if (!parameter3.isNull()) arguments.append(parameter3); if (!parameter4.isNull()) arguments.append(parameter4); if (!parameter5.isNull()) arguments.append(parameter5); if (!parameter6.isNull()) arguments.append(parameter6); if (!parameter7.isNull()) arguments.append(parameter7); if (!parameter8.isNull()) arguments.append(parameter8); if (!parameter9.isNull()) arguments.append(parameter9); if (!parameter10.isNull()) arguments.append(parameter10); return createOperation(operationName, arguments); } Operation *Component::createOperation(const QString &operationName, const QStringList ¶meters) { Operation *operation = KDUpdater::UpdateOperationFactory::instance().create(operationName, d->m_core); if (operation == 0) { const QMessageBox::StandardButton button = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("OperationDoesNotExistError"), tr("Error"), tr("Error: Operation %1 does not exist.") .arg(operationName), QMessageBox::Abort | QMessageBox::Ignore, QMessageBox::Abort); if (button == QMessageBox::Abort) d->m_operationsCreatedSuccessfully = false; return operation; } if (operation->name() == QLatin1String("Delete")) operation->setValue(QLatin1String("performUndo"), false); operation->setArguments(d->m_core->replaceVariables(parameters)); operation->setValue(QLatin1String("component"), name()); return operation; } void Component::markComponentUnstable() { setValue(scDefault, scFalse); // Mark unstable component unchecked if: // 1. Installer, so the unstable component won't be installed // 2. Maintenancetool, when component is not installed. // 3. Updater, we don't want to update unstable components // Mark unstable component checked if: // 1. Maintenancetool, if component is installed and // unstable so it won't get uninstalled. if (d->m_core->isInstaller() || !isInstalled() || d->m_core->isUpdater()) setCheckState(Qt::Unchecked); setValue(scUnstable, scTrue); } namespace { inline bool convert(QQmlV4Function *func, QStringList *toArgs) { if (func->length() < 2) return false; QV4::Scope scope(func->v4engine()); QV4::ScopedValue val(scope); val = (*func)[0]; *toArgs << val->toQString(); for (int i = 1; i < func->length(); i++) { val = (*func)[i]; if (val->isObject() && val->as()->isArrayObject()) { QV4::ScopedValue valtmp(scope); QV4::Object *array = val->as(); uint length = array->getLength(); for (uint ii = 0; ii < length; ++ii) { valtmp = array->getIndexed(ii); *toArgs << valtmp->toQStringNoThrow(); } } else { *toArgs << val->toQString(); } } return true; } } /*! \internal */ bool Component::addOperation(QQmlV4Function *func) { QStringList args; if (convert(func, &args)) return addOperation(args[0], args.mid(1)); return false; } /*! Creates and adds an installation operation for \a operation. Add any number of \a parameters. The variables that the parameters contain, such as \c @TargetDir@, are replaced with their values. Returns \c true if the operation is created; otherwise returns \c false. \sa {component::addOperation}{component.addOperation} */ bool Component::addOperation(const QString &operation, const QStringList ¶meters) { if (Operation *op = createOperation(operation, parameters)) { addOperation(op); return true; } return false; } /*! \internal */ bool Component::addElevatedOperation(QQmlV4Function *func) { QStringList args; if (convert(func, &args)) return addElevatedOperation(args[0], args.mid(1)); return false; } /*! Creates and adds the installation operation \a operation. Add any number of \a parameters. The variables that the parameters contain, such as \c @TargetDir@, are replaced with their values. The operation is executed with elevated rights. Returns \c true if the operation is created; otherwise returns \c false. \sa {component::addElevatedOperation}{component.addElevatedOperation} */ bool Component::addElevatedOperation(const QString &operation, const QStringList ¶meters) { if (Operation *op = createOperation(operation, parameters)) { addElevatedOperation(op); return true; } return false; } /*! Specifies whether operations should be automatically created when the installation starts. This would be done by calling createOperations(). If you set this to \c false, it is completely up to the component's script to create all operations. Returns \c false when component's script will create all operations; otherwise returns \c true. \sa {component::autoCreateOperations}{component.autoCreateOperations} */ bool Component::autoCreateOperations() const { return d->m_autoCreateOperations; } void Component::setAutoCreateOperations(bool autoCreateOperations) { d->m_autoCreateOperations = autoCreateOperations; } /*! Returns whether this component is virtual. */ bool Component::isVirtual() const { return d->m_vars.value(scVirtual, scFalse).toLower() == scTrue; } /*! Returns whether the component is selected. */ bool Component::isSelected() const { return checkState() != Qt::Unchecked; } /*! Returns whether this component should always be installed. */ bool Component::forcedInstallation() const { return d->m_vars.value(scForcedInstallation, scFalse).toLower() == scTrue; } /*! Sets the validator callback name to \a name. */ void Component::setValidatorCallbackName(const QString &name) { validatorCallbackName = name; } /*! Calls the script method with the validator callback name. Returns \c true if the method returns \c true. Always returns \c true if the validator callback name is empty. */ bool Component::validatePage() { if (!validatorCallbackName.isEmpty()) return d->scriptEngine()->callScriptMethod(d->m_scriptContext, validatorCallbackName).toBool(); return true; } /*! Adds the component specified by \a newDependency to the list of dependencies. \sa {component::addDependency}{component.addDependency} \sa dependencies */ void Component::addDependency(const QString &newDependency) { QString oldDependencies = d->m_vars.value(scDependencies); if (oldDependencies.isEmpty()) setValue(scDependencies, newDependency); else setValue(scDependencies, oldDependencies + QLatin1String(", ") + newDependency); } QStringList Component::dependencies() const { return d->m_vars.value(scDependencies).split(QInstaller::commaRegExp(), QString::SkipEmptyParts); } /*! Adds the component specified by \a newDependOn to the automatic depend-on list. \sa {component::addAutoDependOn}{component.addAutoDependOn} \sa autoDependencies */ void Component::addAutoDependOn(const QString &newDependOn) { QString oldDependOn = d->m_vars.value(scAutoDependOn); if (oldDependOn.isEmpty()) setValue(scAutoDependOn, newDependOn); else setValue(scAutoDependOn, oldDependOn + QLatin1String(", ") + newDependOn); } QStringList Component::autoDependencies() const { return d->m_vars.value(scAutoDependOn).split(QInstaller::commaRegExp(), QString::SkipEmptyParts); } /*! \sa {component::setInstalled}{component.setInstalled} */ void Component::setInstalled() { setValue(scCurrentState, scInstalled); } /*! Determines whether the component comes as an auto dependency. Returns \c true if all components in \a componentsToInstall are already installed or selected for installation and this component thus needs to be installed as well. \sa {component::isAutoDependOn}{component.isAutoDependOn} */ bool Component::isAutoDependOn(const QSet &componentsToInstall) const { // If there is no auto depend on value or the value is empty, we have nothing todo. The component does // not need to be installed as an auto dependency. QStringList autoDependOnList = autoDependencies(); if (autoDependOnList.isEmpty()) return false; // If there is an essential update and autodepend on is not for essential // update component, do not add the autodependency to an installed component as // essential updates needs to be installed first, otherwise non-essential components // will be installed if (packageManagerCore()->foundEssentialUpdate()) { const QSet autoDependOnSet = autoDependOnList.toSet(); if (componentsToInstall.contains(autoDependOnSet)) { foreach (const QString &autoDep, autoDependOnSet) { Component *component = packageManagerCore()->componentByName(autoDep); if (component->value(scEssential, scFalse).toLower() == scTrue) return true; } } return false; } QSet components = componentsToInstall; const QStringList installedPackages = d->m_core->localInstalledPackages().keys(); foreach (const QString &name, installedPackages) components.insert(name); foreach (const QString &component, components) { autoDependOnList.removeAll(component); if (autoDependOnList.isEmpty()) { // If all components in the isAutoDependOn field are already installed or selected for // installation, this component needs to be installed as well. return true; } } return false; } bool Component::isDefault() const { if (isVirtual()) return false; // the script can override this method if (d->m_vars.value(scDefault).compare(scScript, Qt::CaseInsensitive) == 0) { QJSValue valueFromScript; try { valueFromScript = d->scriptEngine()->callScriptMethod(d->m_scriptContext, QLatin1String("isDefault")); } catch (const Error &error) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("isDefaultError"), tr("Cannot resolve isDefault in %1").arg(name()), error.message()); return false; } if (!valueFromScript.isError()) return valueFromScript.toBool(); qCWarning(QInstaller::lcDeveloperBuild) << "Value from script is not valid." << (valueFromScript.toString().isEmpty() ? QString::fromLatin1("Unknown error.") : valueFromScript.toString()); return false; } return d->m_vars.value(scDefault).compare(scTrue, Qt::CaseInsensitive) == 0; } bool Component::isInstalled(const QString &version) const { if (version.isEmpty()) { return scInstalled == d->m_vars.value(scCurrentState); } else { return d->m_vars.value(scInstalledVersion) == version; } } /*! Returns whether the user wants to install the component. \sa {component::installationRequested}{component.installationRequested} */ bool Component::installationRequested() const { return installAction() == Install; } /*! Returns whether the component is selected for installation. */ bool Component::isSelectedForInstallation() const { return !isInstalled() && isSelected(); } /*! Sets the \a isUpdateAvailable flag to \c true to indicate that the core found an update. \sa {component::setUpdateAvailable}{component.setUpdateAvailable} */ void Component::setUpdateAvailable(bool isUpdateAvailable) { d->m_updateIsAvailable = isUpdateAvailable; } /*! Returns whether the user wants to install the update for this component. \sa {component::updateRequested}{component.updateRequested} */ bool Component::updateRequested() { return d->m_updateIsAvailable && isSelected() && !isUnstable(); } /*! Returns \c true if that component will be changed (update, installation, or uninstallation). \sa {component::componentChangeRequested}{component.componentChangeRequested} */ bool Component::componentChangeRequested() { return updateRequested() || isSelectedForInstallation() || uninstallationRequested(); } /*! \sa {component::setUninstalled}{component.setUninstalled} */ void Component::setUninstalled() { setValue(scCurrentState, scUninstalled); } /*! Returns whether the component is uninstalled. \sa {component::isUninstalled}{component.isUninstalled} */ bool Component::isUninstalled() const { return scUninstalled == d->m_vars.value(scCurrentState); } /*! Returns \c true if this component is unstable. */ bool Component::isUnstable() const { return scTrue == d->m_vars.value(scUnstable); } /*! Sets this component, all its child components and all the components depending on this component unstable with the error code \a error and message \a errorMessage. */ void Component::setUnstable(Component::UnstableError error, const QString &errorMessage) { QList dependencies = d->m_core->dependees(this); // Mark this component unstable markComponentUnstable(); // Marks all components unstable that depend on the unstable component foreach (Component *dependency, dependencies) { dependency->markComponentUnstable(); foreach (Component *descendant, dependency->descendantComponents()) { descendant->markComponentUnstable(); } } // Marks all child components unstable foreach (Component *descendant, this->descendantComponents()) { descendant->markComponentUnstable(); } QMetaEnum metaEnum = QMetaEnum::fromType(); emit packageManagerCore()->unstableComponentFound(QLatin1String(metaEnum.valueToKey(error)), errorMessage, this->name()); } /*! Returns whether the user wants to uninstall the component. \sa {component::uninstallationRequested}{component.uninstallationRequested} */ bool Component::uninstallationRequested() const { if (packageManagerCore()->isUpdater()) return false; return isInstalled() && !isSelected(); } /*! Returns whether this component has been loaded from an online repository. \sa {component::isFromOnlineRepository}{component.isFromOnlineRepository} \sa addDownloadableArchive(), fromOnlineRepository */ bool Component::isFromOnlineRepository() const { return !repositoryUrl().isEmpty(); } /*! Contains the repository URL this component is downloaded from. If this component is not downloaded from an online repository, returns an empty QUrl. */ QUrl Component::repositoryUrl() const { return d->m_repositoryUrl; } /*! Sets this component's repository URL as \a url. */ void Component::setRepositoryUrl(const QUrl &url) { d->m_repositoryUrl = url; } /*! Returns the path to the local directory where the component is temporarily stored. */ QString Component::localTempPath() const { return d->m_localTempPath; } void Component::setLocalTempPath(const QString &tempLocalPath) { d->m_localTempPath = tempLocalPath; } void Component::updateModelData(const QString &key, const QString &data) { if (key == scVirtual) { setData(data.toLower() == scTrue ? d->m_core->virtualComponentsFont() : QFont(), Qt::FontRole); if (Component *const parent = parentComponent()) { parent->removeComponent(this); parent->appendComponent(this); } emit virtualStateChanged(); } if (key == scRemoteDisplayVersion) setData(data, RemoteDisplayVersion); if (key == scDisplayName) setData(data, Qt::DisplayRole); if (key == scDisplayVersion) setData(data, LocalDisplayVersion); if (key == scReleaseDate) setData(data, ReleaseDate); if (key == scUncompressedSize) { quint64 size = d->m_vars.value(scUncompressedSizeSum).toLongLong(); setData(humanReadableSize(size), UncompressedSize); } const QString &updateInfo = d->m_vars.value(scUpdateText); if (!d->m_core->isUpdater() || updateInfo.isEmpty()) { QString tooltipText = QString::fromLatin1("%1").arg(d->m_vars.value(scDescription)); if (isUnstable()) { tooltipText += QLatin1String("
") + tr("There was an error loading the selected component. " "This component can not be installed."); } setData(tooltipText, Qt::ToolTipRole); } else { QString tooltipText = d->m_vars.value(scDescription) + QLatin1String("

") + tr("Update Info: ") + updateInfo; if (isUnstable()) { tooltipText += QLatin1String("
") + tr("There was an error loading the selected component. " "This component can not be updated."); } setData(tooltipText, Qt::ToolTipRole); } } /*! Returns the debugging output stream, \a dbg, for the component \a component. */ QDebug QInstaller::operator<<(QDebug dbg, Component *component) { dbg << "component: " << component->name() << "\n"; dbg << "\tisSelected: \t" << component->isSelected() << "\n"; dbg << "\tisInstalled: \t" << component->isInstalled() << "\n"; dbg << "\tisUninstalled: \t" << component->isUninstalled() << "\n"; dbg << "\tupdateRequested: \t" << component->updateRequested() << "\n"; dbg << "\tinstallationRequested: \t" << component->installationRequested() << "\n"; dbg << "\tuninstallationRequested: \t" << component->uninstallationRequested() << "\n"; return dbg; } qt-installer-framework-4.0.1/src/libs/installer/component.h0100777000000000000000000002125013761647206020770 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMPONENT_H #define COMPONENT_H #include "constants.h" #include "component_p.h" #include "qinstallerglobal.h" #include "packagemanagercore.h" #include #include #include #include QT_FORWARD_DECLARE_CLASS(QDebug) QT_FORWARD_DECLARE_CLASS(QQmlV4Function) namespace QInstaller { class INSTALLER_EXPORT Component : public QObject, public ComponentModelHelper { Q_OBJECT Q_DISABLE_COPY(Component) Q_PROPERTY(QString name READ name) Q_PROPERTY(QString displayName READ displayName) Q_PROPERTY(bool autoCreateOperations READ autoCreateOperations WRITE setAutoCreateOperations) Q_PROPERTY(QStringList archives READ archives) Q_PROPERTY(QStringList userInterfaces READ userInterfaces) Q_PROPERTY(QStringList dependencies READ dependencies) Q_PROPERTY(QStringList autoDependencies READ autoDependencies) Q_PROPERTY(bool fromOnlineRepository READ isFromOnlineRepository) Q_PROPERTY(QUrl repositoryUrl READ repositoryUrl) Q_PROPERTY(bool default READ isDefault) Q_PROPERTY(bool installed READ isInstalled) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(bool unstable READ isUnstable) public: explicit Component(PackageManagerCore *core); ~Component(); enum UnstableError { DepencyToUnstable = 0, ShaMismatch, ScriptLoadingFailed, MissingDependency }; Q_ENUM(UnstableError) struct SortingPriorityLessThan { bool operator() (const Component *lhs, const Component *rhs) const { const int lhsPriority = lhs->value(scSortingPriority).toInt(); const int rhsPriority = rhs->value(scSortingPriority).toInt(); if (lhsPriority == rhsPriority) return lhs->displayName() > rhs->displayName(); return lhsPriority < rhsPriority; } }; struct SortingPriorityGreaterThan { bool operator() (const Component *lhs, const Component *rhs) const { const int lhsPriority = lhs->value(scSortingPriority).toInt(); const int rhsPriority = rhs->value(scSortingPriority).toInt(); if (lhsPriority == rhsPriority) return lhs->displayName() < rhs->displayName(); return lhsPriority > rhsPriority; } }; void loadDataFromPackage(const Package &package); void loadDataFromPackage(const KDUpdater::LocalPackage &package); QHash variables() const; Q_INVOKABLE void setValue(const QString &key, const QString &value); Q_INVOKABLE QString value(const QString &key, const QString &defaultValue = QString()) const; QStringList archives() const; PackageManagerCore *packageManagerCore() const; Component *parentComponent() const; void appendComponent(Component *component); void removeComponent(Component *component); QList descendantComponents() const; void loadComponentScript(); //move this to private void loadComponentScript(const QString &fileName); void loadTranslations(const QDir &directory, const QStringList &qms); void loadUserInterfaces(const QDir &directory, const QStringList &uis); void loadLicenses(const QString &directory, const QHash &hash); void markAsPerformedInstallation(); QStringList userInterfaces() const; QHash > licenses() const; Q_INVOKABLE QWidget *userInterface(const QString &name) const; Q_INVOKABLE virtual void beginInstallation(); Q_INVOKABLE virtual void createOperations(); Q_INVOKABLE virtual void createOperationsForArchive(const QString &archive); Q_INVOKABLE virtual void createOperationsForPath(const QString &path); QList > pathsForUninstallation() const; Q_INVOKABLE void registerPathForUninstallation(const QString &path, bool wipe = false); OperationList operations() const; void addOperation(Operation *operation); Q_INVOKABLE bool addOperation(QQmlV4Function *args); bool addOperation(const QString &operation, const QStringList ¶meters); void addElevatedOperation(Operation *operation); Q_INVOKABLE bool addElevatedOperation(QQmlV4Function *args); bool addElevatedOperation(const QString &operation, const QStringList ¶meters); QStringList downloadableArchives() const; Q_INVOKABLE void addDownloadableArchive(const QString &path); Q_INVOKABLE void removeDownloadableArchive(const QString &path); QStringList stopProcessForUpdateRequests() const; Q_INVOKABLE void addStopProcessForUpdateRequest(const QString &process); Q_INVOKABLE void removeStopProcessForUpdateRequest(const QString &process); Q_INVOKABLE void setStopProcessForUpdateRequest(const QString &process, bool requested); QString name() const; QString displayName() const; quint64 updateUncompressedSize(); QUrl repositoryUrl() const; void setRepositoryUrl(const QUrl &url); Q_INVOKABLE void addDependency(const QString &newDependency); QStringList dependencies() const; Q_INVOKABLE void addAutoDependOn(const QString &newDependOn); QStringList autoDependencies() const; void languageChanged(); QString localTempPath() const; bool autoCreateOperations() const; bool operationsCreatedSuccessfully() const; Q_INVOKABLE bool isDefault() const; Q_INVOKABLE bool isAutoDependOn(const QSet &componentsToInstall) const; Q_INVOKABLE void setInstalled(); Q_INVOKABLE bool isInstalled(const QString &version = QString()) const; Q_INVOKABLE bool installationRequested() const; bool isSelectedForInstallation() const; Q_INVOKABLE void setUninstalled(); Q_INVOKABLE bool isUninstalled() const; Q_INVOKABLE bool uninstallationRequested() const; Q_INVOKABLE bool isFromOnlineRepository() const; Q_INVOKABLE void setUpdateAvailable(bool isUpdateAvailable); Q_INVOKABLE bool updateRequested(); Q_INVOKABLE bool componentChangeRequested(); bool isUnstable() const; void setUnstable(Component::UnstableError error, const QString &errorMessage = QString()); bool isVirtual() const; bool isSelected() const; bool forcedInstallation() const; void setValidatorCallbackName(const QString &name); bool validatePage(); public Q_SLOTS: void setAutoCreateOperations(bool autoCreateOperations); Q_SIGNALS: void loaded(); void virtualStateChanged(); void valueChanged(const QString &key, const QString &value); private Q_SLOTS: void updateModelData(const QString &key, const QString &value); private: void setLocalTempPath(const QString &tempPath); Operation *createOperation(const QString &operationName, const QString ¶meter1 = QString(), const QString ¶meter2 = QString(), const QString ¶meter3 = QString(), const QString ¶meter4 = QString(), const QString ¶meter5 = QString(), const QString ¶meter6 = QString(), const QString ¶meter7 = QString(), const QString ¶meter8 = QString(), const QString ¶meter9 = QString(), const QString ¶meter10 = QString()); Operation *createOperation(const QString &operationName, const QStringList ¶meters); void markComponentUnstable(); private: QString validatorCallbackName; ComponentPrivate *d; }; QDebug operator<<(QDebug dbg, Component *component); } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::Component*) #endif // COMPONENT_H qt-installer-framework-4.0.1/src/libs/installer/componentchecker.cpp0100777000000000000000000001714713761647206022662 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "componentchecker.h" #include "component.h" #include "constants.h" #include "packagemanagercore.h" #include "globals.h" namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::ComponentChecker \internal */ QStringList ComponentChecker::checkComponent(Component *component) { QStringList checkResult; if (!component) return checkResult; PackageManagerCore *core = component->packageManagerCore(); if (!core) return checkResult; if (component->childCount() && !component->archives().isEmpty()) { checkResult << QString::fromLatin1("Component %1 contains data to be installed " "while having child components. This may not work properly.") .arg(component->name()); } const bool defaultPropertyScriptValue = component->variables().value(scDefault).compare(scScript, Qt::CaseInsensitive) == 0; const bool defaultPropertyValue = component->variables().value(scDefault).compare(scTrue, Qt::CaseInsensitive) == 0; const QStringList autoDependencies = component->autoDependencies(); const QList allComponents = core->components(PackageManagerCore::ComponentType::All); if (!autoDependencies.isEmpty()) { if (component->forcedInstallation()) { checkResult << QString::fromLatin1("Component %1 specifies \"ForcedInstallation\" property " "together with \"AutoDependOn\" list. This combination of states may not work properly.") .arg(component->name()); } if (defaultPropertyScriptValue) { checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " "property together with \"AutoDependOn\" list. This combination of states may not " "work properly.").arg(component->name()); } if (defaultPropertyValue) { checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property together " "with \"AutoDependOn\" list. This combination of states may not work properly.") .arg(component->name()); } if (!core->dependees(component).isEmpty()) { checkResult << QString::fromLatin1("Other components depend on auto dependent " "component %1. This may not work properly.") .arg(component->name()); } } if (component->packageManagerCore()->isInstaller()) { if (component->isTristate()) { if (defaultPropertyScriptValue) { checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " "property while not being a leaf node. The \"Default\" property will get a " "\"false\" value.").arg(component->name()); } if (defaultPropertyValue) { checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property " "while not being a leaf node. The \"Default\" property will get a \"false\" value.") .arg(component->name()); } } if (!component->isCheckable()) { if (defaultPropertyScriptValue) { checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " "property while being not checkable. The \"Default\" property will get a \"false\" " "value.").arg(component->name()); } if (defaultPropertyValue) { checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property " "while being not checkable. The \"Default\" property will get a \"false\" value.") .arg(component->name()); } } if (component->childCount()) { if (!autoDependencies.isEmpty()) { /* Use case: A (depends on C) A.B C Let's say we installed everything. Running maintenance tool and unselecting C will mark A for uninstallation too, while A.B stays marked as installed. After running maintenance tool again, it will check A automatically (since its child is selected), this will also mark C for installation (dependecy). Moreover, the "Next" button will be disabled. */ checkResult << QString::fromLatin1("Component %1 auto depends on other components " "while having child components. This will not work properly.") .arg(component->name()); } if (!component->dependencies().isEmpty()) { checkResult << QString::fromLatin1("Component %1 depends on other components " "while having child components. This will not work properly.") .arg(component->name()); } if (!core->dependees(component).isEmpty()) { /* Use case: A A.B C (depends on A) Selecting C marks A for installation too, A.B is not marked for installation. So after installation, A and C are installed, while A.B is not. Maintenance tool will uncheck A automatically (since none of its children are installed) this will also mark C for uninstallation (dependency). Moreover, the "Next" button will be disabled. */ checkResult << QString::fromLatin1("Other components depend on component %1 " "which has child components. This will not work properly.") .arg(component->name()); } } foreach (const QString &autoDependency, autoDependencies) { Component *autoDependencyComponent = PackageManagerCore::componentByName( autoDependency, allComponents); if (autoDependencyComponent && autoDependencyComponent->childCount()) { checkResult << QString::fromLatin1("Component %1 auto depends on component %2 " "which has children components. This will not work properly.") .arg(component->name(), autoDependencyComponent->name()); } } } return checkResult; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/componentchecker.h0100777000000000000000000000315713761647206022323 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMPONENTCHECKER_H #define COMPONENTCHECKER_H #include "installer_global.h" #include namespace QInstaller { class Component; class INSTALLER_EXPORT ComponentChecker { Q_DECLARE_TR_FUNCTIONS(ComponentChecker) public: static QStringList checkComponent(Component *component); private: ComponentChecker(); }; } #endif // INSTALLERCALCULATOR_H qt-installer-framework-4.0.1/src/libs/installer/componentmodel.cpp0100777000000000000000000005227713761647206022361 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "componentmodel.h" #include "component.h" #include "packagemanagercore.h" #include namespace QInstaller { /*! \class QInstaller::ComponentModel \inmodule QtInstallerFramework \brief The ComponentModel class holds a data model for visual representation of available components to install. */ /*! \enum ComponentModel::ModelStateFlag This enum value holds the checked state of the components available for installation. \value AllChecked All components are checked. \value AllUnchecked No components are checked. \value DefaultChecked The components to be installed by default are checked. \value PartiallyChecked Some components are checked. */ /*! \fn void QInstaller::ComponentModel::checkStateChanged(const QModelIndex &index) This signal is emitted whenever the checked state of a component is changed. The \a index value indicates the QModelIndex representation of the component as seen from the model. */ /*! \fn void QInstaller::ComponentModel::checkStateChanged(QInstaller::ComponentModel::ModelState state) This signal is emitted whenever the checked state of a model is changed after all state calculations have taken place. The \a state is a combination of \c ModelStateFlag values indicating whether the model has its default checked state, all components are checked or unchecked, or some individual component's checked state has changed. */ class IconCache { public: IconCache() { m_icons.insert(ComponentModelHelper::Install, QIcon(QLatin1String(":/install.png"))); m_icons.insert(ComponentModelHelper::Uninstall, QIcon(QLatin1String(":/uninstall.png"))); m_icons.insert(ComponentModelHelper::KeepInstalled, QIcon(QLatin1String(":/keepinstalled.png"))); m_icons.insert(ComponentModelHelper::KeepUninstalled, QIcon(QLatin1String(":/keepuninstalled.png"))); } QIcon icon(ComponentModelHelper::InstallAction action) const { return m_icons.value(action); } private: QMap m_icons; }; Q_GLOBAL_STATIC(IconCache, iconCache) /*! Constructs a component model with the given number of \a columns and \a core as parent. */ ComponentModel::ComponentModel(int columns, PackageManagerCore *core) : QAbstractItemModel(core) , m_core(core) , m_modelState(DefaultChecked) { m_headerData.insert(0, columns, QVariant()); connect(this, &QAbstractItemModel::modelReset, this, &ComponentModel::slotModelReset); } /*! Destroys the component model. */ ComponentModel::~ComponentModel() { } /*! Returns the item flags for the given \a index. Returns a combination of flags that enables the item (Qt::ItemIsEnabled) and allows it to be selected (Qt::ItemIsSelectable) and to be checked (Qt::ItemIsUserCheckable). */ Qt::ItemFlags ComponentModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; if (Component *component = componentFromIndex(index)) return component->flags(); return Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); } /*! Returns the number of items under the given \a parent. When the parent index is invalid, the returned value is the root item count. */ int ComponentModel::rowCount(const QModelIndex &parent) const { if (Component *component = componentFromIndex(parent)) return component->childCount(); return m_rootComponentList.count(); } /*! Returns the number of columns of the given \a parent. */ int ComponentModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_headerData.size(); } /*! Returns the parent item of the given \a child. If the item has no parent, an invalid QModelIndex is returned. */ QModelIndex ComponentModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); if (Component *childComponent = componentFromIndex(child)) { if (Component *parent = childComponent->parentComponent()) return indexFromComponentName(parent->name()); } return QModelIndex(); } /*! Returns the index of the item in the model specified by the given \a row, \a column, and \a parent index. */ QModelIndex ComponentModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() && (row >= rowCount(parent) || column >= columnCount())) return QModelIndex(); if (Component *parentComponent = componentFromIndex(parent)) { if (Component *childComponent = parentComponent->childAt(row)) return createIndex(row, column, childComponent); } else if (row < m_rootComponentList.count()) { return createIndex(row, column, m_rootComponentList.at(row)); } return QModelIndex(); } /*! Returns the data stored under the given \a role for the item referred to by the \a index. \note An \e invalid QVariant is returned if the given index is invalid. Qt::CheckStateRole is only supported for the first column of the model. Qt::EditRole, Qt::DisplayRole and Qt::ToolTipRole are specifically handled for columns greater than the first column and translate to \c {Qt::UserRole + index.column()}. */ QVariant ComponentModel::data(const QModelIndex &index, int role) const { if (Component *component = componentFromIndex(index)) { if (index.column() > 0) { if (role == Qt::CheckStateRole) return QVariant(); if (index.column() == ComponentModelHelper::ActionColumn) { if (role == Qt::DecorationRole) return iconCache->icon(component->installAction()); if (role == Qt::ToolTipRole) { switch (component->installAction()) { case ComponentModelHelper::Install: return tr("Component is marked for installation."); case ComponentModelHelper::Uninstall: return tr("Component is marked for uninstallation."); case ComponentModelHelper::KeepInstalled: return tr("Component is installed."); case ComponentModelHelper::KeepUninstalled: return tr("Component is not installed."); default: return QString(); } } return QVariant(); } if (role == Qt::EditRole || role == Qt::DisplayRole || role == Qt::ToolTipRole) return component->data(Qt::UserRole + index.column()); } if (role == Qt::CheckStateRole) { if (!component->isCheckable() || !component->autoDependencies().isEmpty() || component->isUnstable()) return QVariant(); } if (role == ComponentModelHelper::ExpandedByDefault) { return component->isExpandedByDefault(); } if (component->isUnstable() && role == Qt::ForegroundRole) { return QVariant(QColor(Qt::darkGray)); } return component->data(role); } return QVariant(); } /*! Sets the \a role data for the item at \a index to \a value. Returns true if successful; otherwise returns false. The dataChanged() signal is emitted if the data was successfully set. The checkStateChanged() signals are emitted in addition if the checked state of the item is set. */ bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; Component *component = componentFromIndex(index); if (!component) return false; if (role == Qt::CheckStateRole) { if (index.column() != 0) return false; ComponentSet nodes = component->childItems().toSet(); Qt::CheckState newValue = Qt::CheckState(value.toInt()); if (newValue == Qt::PartiallyChecked) { const Qt::CheckState oldValue = component->checkState(); newValue = (oldValue == Qt::Checked) ? Qt::Unchecked : Qt::Checked; } QSet changed = updateCheckedState(nodes << component, newValue); foreach (const QModelIndex &index, changed) { emit dataChanged(index, index); emit checkStateChanged(index); } updateAndEmitModelState(); // update the internal state } else { component->setData(value, role); emit dataChanged(index, index); } return true; } /*! Returns the data for the given \a role and \a section in the header with the specified \a orientation. An \e invalid QVariant is returned if \a section is out of bounds, \a orientation is not Qt::Horizontal or \a role is anything else than Qt::DisplayRole. */ QVariant ComponentModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section >= 0 && section < columnCount() && orientation == Qt::Horizontal && role == Qt::DisplayRole) return m_headerData.at(section); return QVariant(); } /*! Sets the data for the given \a role and \a section in the header with the specified \a orientation to the \a value supplied. Returns \c true if the header's data was updated; otherwise returns \c false. The headerDataChanged() signal is emitted if the data was successfully set. \note Only Qt::Horizontal orientation is supported. */ bool ComponentModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if (section >= 0 && section < columnCount() && orientation == Qt::Horizontal && (role == Qt::DisplayRole || role == Qt::EditRole)) { m_headerData.replace(section, value); emit headerDataChanged(orientation, section, section); return true; } return false; } /*! Returns a list of checked components. */ QSet ComponentModel::checked() const { return m_currentCheckedState[Qt::Checked]; } /*! Returns a list of partially checked components. */ QSet ComponentModel::partially() const { return m_currentCheckedState[Qt::PartiallyChecked]; } /*! Returns a list of unchecked components. */ QSet ComponentModel::unchecked() const { return m_currentCheckedState[Qt::Unchecked]; } /*! Returns a list of components whose checked state cannot be changed. If package manager core is run with no forced installation argument, the list will always be empty. */ QSet ComponentModel::uncheckable() const { return m_uncheckable; } /*! Returns a pointer to the PackageManagerCore this model belongs to. */ PackageManagerCore *ComponentModel::core() const { return m_core; } /*! Returns the current checked state of the model. */ ComponentModel::ModelState ComponentModel::checkedState() const { return m_modelState; } /*! Translates between a given component \a name and its associated QModelIndex. Returns the QModelIndex that represents the component or an invalid QModelIndex if the component does not exist in the model. */ QModelIndex ComponentModel::indexFromComponentName(const QString &name) const { if (m_indexByNameCache.isEmpty()) { for (int i = 0; i < m_rootComponentList.count(); ++i) collectComponents(m_rootComponentList.at(i), index(i, 0, QModelIndex())); } return m_indexByNameCache.value(name, QModelIndex()); } /*! Translates between a given QModelIndex \a index and its associated Component. Returns the component if the index is valid or \c 0 if an invalid QModelIndex is given. */ Component *ComponentModel::componentFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); return nullptr; } // -- public slots /*! Sets \a rootComponents to be the list of currently shown components. The model is repopulated and the individual component's checked state is used to show the check mark in front of the visual component representation. The modelAboutToBeReset() and modelReset() signals are emitted. */ void ComponentModel::setRootComponents(QList rootComponents) { beginResetModel(); m_uncheckable.clear(); m_indexByNameCache.clear(); m_rootComponentList.clear(); m_modelState = DefaultChecked; // Initialize these with an empty set for every possible state, cause we compare the hashes later in // updateAndEmitModelState(). The comparison than might lead to wrong results if one of the checked // states is absent initially. m_initialCheckedState[Qt::Checked] = ComponentSet(); m_initialCheckedState[Qt::Unchecked] = ComponentSet(); m_initialCheckedState[Qt::PartiallyChecked] = ComponentSet(); m_currentCheckedState = m_initialCheckedState; // both should be equal // show virtual components only in case we run as updater or if the core engine is set to show them const bool showVirtuals = m_core->isUpdater() || m_core->virtualComponentsVisible(); foreach (Component *const component, rootComponents) { connect(component, &Component::virtualStateChanged, this, &ComponentModel::onVirtualStateChanged); if ((!showVirtuals) && component->isVirtual()) continue; m_rootComponentList.append(component); } endResetModel(); } /*! Sets the checked state of every component in the model to be \a state. The ComponentModel::PartiallyChecked flag is ignored by this function. Note that components are not changed if they are not checkable. The dataChanged() and checkStateChanged() signals are emitted. */ void ComponentModel::setCheckedState(QInstaller::ComponentModel::ModelStateFlag state) { QSet changed; switch (state) { case AllChecked: changed = updateCheckedState(m_currentCheckedState[Qt::Unchecked], Qt::Checked); break; case AllUnchecked: changed = updateCheckedState(m_currentCheckedState[Qt::Checked], Qt::Unchecked); break; case DefaultChecked: // record all changes, to be able to update the UI properly changed = updateCheckedState(m_currentCheckedState[Qt::Checked], Qt::Unchecked); changed += updateCheckedState(m_initialCheckedState[Qt::Checked], Qt::Checked); break; default: break; } if (changed.isEmpty()) return; // notify about changes done to the model foreach (const QModelIndex &index, changed) { emit dataChanged(index, index); emit checkStateChanged(index); } updateAndEmitModelState(); // update the internal state } // -- private slots void ComponentModel::slotModelReset() { ComponentList components = m_rootComponentList; if (!m_core->isUpdater()) { foreach (Component *const component, m_rootComponentList) components += component->childItems(); } ComponentSet checked; foreach (Component *const component, components) { if (component->checkState() == Qt::Checked) checked.insert(component); connect(component, &Component::virtualStateChanged, this, &ComponentModel::onVirtualStateChanged); } updateCheckedState(checked, Qt::Checked); foreach (Component *const component, components) { if (!component->isCheckable()) m_uncheckable.insert(component); m_initialCheckedState[component->checkState()].insert(component); } m_currentCheckedState = m_initialCheckedState; updateAndEmitModelState(); // update the internal state } void ComponentModel::onVirtualStateChanged() { // If the virtual state of a component changes, force a reset of the component model. setRootComponents(m_core->components(PackageManagerCore::ComponentType::Root)); } // -- private void ComponentModel::updateAndEmitModelState() { m_modelState = ComponentModel::DefaultChecked; if (m_initialCheckedState != m_currentCheckedState) m_modelState = ComponentModel::PartiallyChecked; if (checked().count() == 0 && partially().count() == 0) { m_modelState |= ComponentModel::AllUnchecked; m_modelState &= ~ComponentModel::PartiallyChecked; } if (unchecked().count() == 0 && partially().count() == 0) { m_modelState |= ComponentModel::AllChecked; m_modelState &= ~ComponentModel::PartiallyChecked; } emit checkStateChanged(m_modelState); foreach (const Component *component, m_rootComponentList) { emit dataChanged(indexFromComponentName(component->name()), indexFromComponentName(component->name())); QList children = component->childItems(); foreach (const Component *child, children) emit dataChanged(indexFromComponentName(child->name()), indexFromComponentName(child->name())); } } void ComponentModel::collectComponents(Component *const component, const QModelIndex &parent) const { m_indexByNameCache.insert(component->name(), parent); for (int i = 0; i < component->childCount(); ++i) collectComponents(component->childAt(i), index(i, 0, parent)); } namespace ComponentModelPrivate { static Qt::CheckState verifyPartiallyChecked(Component *component) { bool anyChecked = false; bool anyUnchecked = false; const int count = component->childCount(); for (int i = 0; i < count; ++i) { switch (component->childAt(i)->checkState()) { case Qt::Checked: { anyChecked = true; } break; case Qt::Unchecked: { anyUnchecked = true; } break; default: return Qt::PartiallyChecked; } if (anyChecked && anyUnchecked) return Qt::PartiallyChecked; } if (anyChecked) return Qt::Checked; if (anyUnchecked) return Qt::Unchecked; return Qt::PartiallyChecked; // never hit here } } // namespace ComponentModelPrivate QSet ComponentModel::updateCheckedState(const ComponentSet &components, Qt::CheckState state) { // get all parent nodes for the components we're going to update QMap sortedNodesMap; foreach (Component *component, components) { while (component && !sortedNodesMap.values(component->name()).contains(component)) { sortedNodesMap.insertMulti(component->name(), component); component = component->parentComponent(); } } QSet changed; const ComponentList sortedNodes = sortedNodesMap.values(); // we can start in descending order to check node and tri-state nodes properly for (int i = sortedNodes.count(); i > 0; i--) { Component * const node = sortedNodes.at(i - 1); bool checkable = true; if (node->value(scCheckable, scTrue).toLower() == scFalse) { checkable = false; } if ((!node->isCheckable() && checkable) || !node->isEnabled() || !node->autoDependencies().isEmpty() || node->isUnstable()) continue; Qt::CheckState newState = state; const Qt::CheckState recentState = node->checkState(); if (node->isTristate()) newState = ComponentModelPrivate::verifyPartiallyChecked(node); if (recentState == newState) continue; node->setCheckState(newState); changed.insert(indexFromComponentName(node->name())); m_currentCheckedState[Qt::Checked].remove(node); m_currentCheckedState[Qt::Unchecked].remove(node); m_currentCheckedState[Qt::PartiallyChecked].remove(node); switch (newState) { case Qt::Checked: m_currentCheckedState[Qt::Checked].insert(node); break; case Qt::Unchecked: m_currentCheckedState[Qt::Unchecked].insert(node); break; case Qt::PartiallyChecked: m_currentCheckedState[Qt::PartiallyChecked].insert(node); break; } } return changed; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/componentmodel.h0100777000000000000000000001042313761647206022011 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMPONENTMODEL_H #define COMPONENTMODEL_H #include "qinstallerglobal.h" #include #include #include #include namespace QInstaller { class Component; class PackageManagerCore; class INSTALLER_EXPORT ComponentModel : public QAbstractItemModel { Q_OBJECT typedef QSet ComponentSet; typedef QList ComponentList; public: enum ModelStateFlag { AllChecked = 0x01, AllUnchecked = 0x02, DefaultChecked = 0x04, PartiallyChecked = 0x08 }; Q_DECLARE_FLAGS(ModelState, ModelStateFlag); explicit ComponentModel(int columns, PackageManagerCore *core = 0); ~ComponentModel(); Qt::ItemFlags flags(const QModelIndex &index) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole); QSet checked() const; QSet partially() const; QSet unchecked() const; QSet uncheckable() const; PackageManagerCore *core() const; ComponentModel::ModelState checkedState() const; QModelIndex indexFromComponentName(const QString &name) const; Component* componentFromIndex(const QModelIndex &index) const; public Q_SLOTS: void setRootComponents(QList rootComponents); void setCheckedState(QInstaller::ComponentModel::ModelStateFlag state); Q_SIGNALS: void checkStateChanged(const QModelIndex &index); void checkStateChanged(QInstaller::ComponentModel::ModelState state); private Q_SLOTS: void slotModelReset(); void onVirtualStateChanged(); private: void updateAndEmitModelState(); void collectComponents(Component *const component, const QModelIndex &parent) const; QSet updateCheckedState(const ComponentSet &components, Qt::CheckState state); private: PackageManagerCore *m_core; ModelState m_modelState; ComponentSet m_uncheckable; QVector m_headerData; ComponentList m_rootComponentList; QHash m_initialCheckedState; QHash m_currentCheckedState; mutable QHash m_indexByNameCache; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ComponentModel::ModelState); } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::ComponentModel::ModelState); Q_DECLARE_METATYPE(QInstaller::ComponentModel::ModelStateFlag); #endif // COMPONENTMODEL_H qt-installer-framework-4.0.1/src/libs/installer/componentselectionpage_p.cpp0100777000000000000000000004730613761647206024417 0ustar00/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "componentselectionpage_p.h" #include "packagemanagergui.h" #include "componentmodel.h" #include "settings.h" #include "component.h" #include "fileutils.h" #include "messageboxhandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::ComponentSelectionPagePrivate \internal */ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionPage *qq, PackageManagerCore *core) : q(qq) , m_core(core) , m_treeView(new QTreeView(q)) , m_allModel(m_core->defaultComponentModel()) , m_updaterModel(m_core->updaterComponentModel()) , m_currentModel(m_allModel) , m_allowCompressedRepositoryInstall(false) , m_categoryWidget(Q_NULLPTR) { m_treeView->setObjectName(QLatin1String("ComponentsTreeView")); QVBoxLayout *descriptionVLayout = new QVBoxLayout; descriptionVLayout->setObjectName(QLatin1String("DescriptionLayout")); QScrollArea *descriptionScrollArea = new QScrollArea(q); descriptionScrollArea->setWidgetResizable(true); descriptionScrollArea->setFrameShape(QFrame::NoFrame); descriptionScrollArea->setObjectName(QLatin1String("DescriptionScrollArea")); m_descriptionLabel = new QLabel(q); m_descriptionLabel->setWordWrap(true); m_descriptionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); m_descriptionLabel->setOpenExternalLinks(true); m_descriptionLabel->setObjectName(QLatin1String("ComponentDescriptionLabel")); m_descriptionLabel->setAlignment(Qt::AlignTop); descriptionScrollArea->setWidget(m_descriptionLabel); descriptionVLayout->addWidget(descriptionScrollArea); m_sizeLabel = new QLabel(q); m_sizeLabel->setMargin(5); m_sizeLabel->setWordWrap(true); m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel")); descriptionVLayout->addWidget(m_sizeLabel); QHBoxLayout *buttonHLayout = new QHBoxLayout; m_checkDefault = new QPushButton; connect(m_checkDefault, &QAbstractButton::clicked, this, &ComponentSelectionPagePrivate::selectDefault); if (m_core->isInstaller()) { m_checkDefault->setObjectName(QLatin1String("SelectDefaultComponentsButton")); m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+A", "select default components"))); m_checkDefault->setText(ComponentSelectionPage::tr("Def&ault")); } else { m_checkDefault->setEnabled(false); m_checkDefault->setObjectName(QLatin1String("ResetComponentsButton")); m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+R", "reset to already installed components"))); m_checkDefault->setText(ComponentSelectionPage::tr("&Reset")); } buttonHLayout->addWidget(m_checkDefault); m_checkAll = new QPushButton; connect(m_checkAll, &QAbstractButton::clicked, this, &ComponentSelectionPagePrivate::selectAll); m_checkAll->setObjectName(QLatin1String("SelectAllComponentsButton")); m_checkAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+S", "select all components"))); m_checkAll->setText(ComponentSelectionPage::tr("&Select All")); buttonHLayout->addWidget(m_checkAll); m_uncheckAll = new QPushButton; connect(m_uncheckAll, &QAbstractButton::clicked, this, &ComponentSelectionPagePrivate::deselectAll); m_uncheckAll->setObjectName(QLatin1String("DeselectAllComponentsButton")); m_uncheckAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+D", "deselect all components"))); m_uncheckAll->setText(ComponentSelectionPage::tr("&Deselect All")); buttonHLayout->addWidget(m_uncheckAll); QWidget *progressStackedWidget = new QWidget(); QVBoxLayout *metaLayout = new QVBoxLayout(progressStackedWidget); m_metadataProgressLabel = new QLabel(progressStackedWidget); m_progressBar = new QProgressBar(progressStackedWidget); m_progressBar->setRange(0, 0); m_progressBar->setObjectName(QLatin1String("CompressedInstallProgressBar")); metaLayout->addSpacing(20); metaLayout->addWidget(m_metadataProgressLabel); metaLayout->addWidget(m_progressBar); metaLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding)); QVBoxLayout *treeViewVLayout = new QVBoxLayout; treeViewVLayout->setObjectName(QLatin1String("TreeviewLayout")); treeViewVLayout->addWidget(m_treeView, 3); QWidget *mainStackedWidget = new QWidget(); m_mainGLayout = new QGridLayout(mainStackedWidget); m_mainGLayout->addLayout(buttonHLayout, 0, 1); m_mainGLayout->addLayout(treeViewVLayout, 1, 1); m_mainGLayout->addLayout(descriptionVLayout, 1, 2); m_mainGLayout->setColumnStretch(1, 3); m_mainGLayout->setColumnStretch(2, 2); m_stackedLayout = new QStackedLayout(q); m_stackedLayout->addWidget(mainStackedWidget); m_stackedLayout->addWidget(progressStackedWidget); m_stackedLayout->setCurrentIndex(0); connect(m_allModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState))); connect(m_updaterModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState))); connect(m_core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int))); connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString))); connect(m_core, &PackageManagerCore::metaJobTotalProgress, this, &ComponentSelectionPagePrivate::setTotalProgress); // force a recalculation of components to install to keep the state correct connect(q, &ComponentSelectionPage::left, m_core, &PackageManagerCore::clearComponentsToInstallCalculated); #ifdef INSTALLCOMPRESSED allowCompressedRepositoryInstall(); #endif } ComponentSelectionPagePrivate::~ComponentSelectionPagePrivate() { } void ComponentSelectionPagePrivate::allowCompressedRepositoryInstall() { m_allowCompressedRepositoryInstall = true; } void ComponentSelectionPagePrivate::showCompressedRepositoryButton() { QWizard *wizard = qobject_cast(m_core->guiObject()); if (wizard && !(wizard->options() & QWizard::HaveCustomButton2) && m_allowCompressedRepositoryInstall) { wizard->setOption(QWizard::HaveCustomButton2, true); wizard->setButtonText(QWizard::CustomButton2, ComponentSelectionPage::tr("&Browse QBSP files")); connect(wizard, &QWizard::customButtonClicked, this, &ComponentSelectionPagePrivate::customButtonClicked); q->gui()->updateButtonLayout(); } } void ComponentSelectionPagePrivate::hideCompressedRepositoryButton() { QWizard *wizard = qobject_cast(m_core->guiObject()); if (wizard && (wizard->options() & QWizard::HaveCustomButton2)) { wizard->setOption(QWizard::HaveCustomButton2, false); disconnect(wizard, &QWizard::customButtonClicked, this, &ComponentSelectionPagePrivate::customButtonClicked); q->gui()->updateButtonLayout(); } } void ComponentSelectionPagePrivate::setupCategoryLayout() { if (m_categoryWidget) return; m_categoryWidget = new QWidget(); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->setContentsMargins(0, 0, 0, 0); m_categoryWidget->setLayout(vLayout); m_categoryGroupBox = new QGroupBox(q); m_categoryGroupBox->setTitle(m_core->settings().repositoryCategoryDisplayName()); m_categoryGroupBox->setObjectName(QLatin1String("CategoryGroupBox")); QVBoxLayout *categoryLayout = new QVBoxLayout(m_categoryGroupBox); QPushButton *fetchCategoryButton = new QPushButton(tr("Filter")); fetchCategoryButton->setObjectName(QLatin1String("FetchCategoryButton")); connect(fetchCategoryButton, &QPushButton::clicked, this, &ComponentSelectionPagePrivate::fetchRepositoryCategories); foreach (RepositoryCategory repository, m_core->settings().organizedRepositoryCategories()) { QCheckBox *checkBox = new QCheckBox; checkBox->setObjectName(repository.displayname()); checkBox->setChecked(repository.isEnabled()); connect(checkBox, &QCheckBox::stateChanged, this, &ComponentSelectionPagePrivate::checkboxStateChanged); checkBox->setText(repository.displayname()); checkBox->setToolTip(repository.tooltip()); categoryLayout->addWidget(checkBox); } categoryLayout->addWidget(fetchCategoryButton); vLayout->addWidget(m_categoryGroupBox); vLayout->addStretch(); m_mainGLayout->addWidget(m_categoryWidget, 1, 0); } void ComponentSelectionPagePrivate::showCategoryLayout(bool show) { if (show) { setupCategoryLayout(); } if (m_categoryWidget) m_categoryWidget->setVisible(show); } void ComponentSelectionPagePrivate::updateTreeView() { m_checkDefault->setVisible(m_core->isInstaller() || m_core->isPackageManager()); if (m_treeView->selectionModel()) { disconnect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ComponentSelectionPagePrivate::currentSelectedChanged); } m_currentModel = m_core->isUpdater() ? m_updaterModel : m_allModel; m_treeView->setModel(m_currentModel); m_treeView->setExpanded(m_currentModel->index(0, 0), true); foreach (Component *component, m_core->components(PackageManagerCore::ComponentType::All)) { if (component->isExpandedByDefault()) { const QModelIndex index = m_currentModel->indexFromComponentName(component->name()); m_treeView->setExpanded(index, true); } } const bool installActionColumnVisible = m_core->settings().installActionColumnVisible(); if (!installActionColumnVisible) m_treeView->hideColumn(ComponentModelHelper::ActionColumn); m_treeView->header()->setSectionResizeMode( ComponentModelHelper::NameColumn, QHeaderView::ResizeToContents); if (m_core->isInstaller()) { m_treeView->setHeaderHidden(true); for (int i = ComponentModelHelper::InstalledVersionColumn; i < m_currentModel->columnCount(); ++i) m_treeView->hideColumn(i); if (installActionColumnVisible) { m_treeView->header()->setStretchLastSection(false); m_treeView->header()->setSectionResizeMode( ComponentModelHelper::NameColumn, QHeaderView::Stretch); m_treeView->header()->setSectionResizeMode( ComponentModelHelper::ActionColumn, QHeaderView::ResizeToContents); } } else { m_treeView->header()->setStretchLastSection(true); if (installActionColumnVisible) { m_treeView->header()->setSectionResizeMode( ComponentModelHelper::NameColumn, QHeaderView::Interactive); m_treeView->header()->setSectionResizeMode( ComponentModelHelper::ActionColumn, QHeaderView::Interactive); } for (int i = 0; i < m_currentModel->columnCount(); ++i) m_treeView->resizeColumnToContents(i); } bool hasChildren = false; const int rowCount = m_currentModel->rowCount(); for (int row = 0; row < rowCount && !hasChildren; ++row) hasChildren = m_currentModel->hasChildren(m_currentModel->index(row, 0)); m_treeView->setRootIsDecorated(hasChildren); connect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ComponentSelectionPagePrivate::currentSelectedChanged); m_treeView->setCurrentIndex(m_currentModel->index(0, 0)); } void ComponentSelectionPagePrivate::currentSelectedChanged(const QModelIndex ¤t) { if (!current.isValid()) return; m_sizeLabel->setText(QString()); QString description = m_currentModel->data(m_currentModel->index(current.row(), ComponentModelHelper::NameColumn, current.parent()), Qt::ToolTipRole).toString(); // replace {external-link}='' fields in component description with proper link tags description.replace(QRegularExpression(QLatin1String("{external-link}='(.*?)'")), QLatin1String("\\1")); m_descriptionLabel->setText(description); Component *component = m_currentModel->componentFromIndex(current); if ((m_core->isUninstaller()) || (!component)) return; if (component->isSelected() && (component->value(scUncompressedSizeSum).toLongLong() > 0)) { m_sizeLabel->setText(ComponentSelectionPage::tr("This component " "will occupy approximately %1 on your hard disk drive.") .arg(humanReadableSize(component->value(scUncompressedSizeSum).toLongLong()))); } } void ComponentSelectionPagePrivate::selectAll() { m_currentModel->setCheckedState(ComponentModel::AllChecked); } void ComponentSelectionPagePrivate::deselectAll() { m_currentModel->setCheckedState(ComponentModel::AllUnchecked); } void ComponentSelectionPagePrivate::checkboxStateChanged() { QList checkboxes = m_categoryGroupBox->findChildren(); bool enableFetchButton = false; foreach (QCheckBox *checkbox, checkboxes) { if (checkbox->isChecked()) { enableFetchButton = true; break; } } } void ComponentSelectionPagePrivate::enableRepositoryCategory(const QString &repositoryName, bool enable) { QMap organizedRepositoryCategories = m_core->settings().organizedRepositoryCategories(); QMap::iterator i = organizedRepositoryCategories.find(repositoryName); RepositoryCategory repoCategory; while (i != organizedRepositoryCategories.end() && i.key() == repositoryName) { repoCategory = i.value(); i++; } RepositoryCategory replacement = repoCategory; replacement.setEnabled(enable); QSet tmpRepoCategories = m_core->settings().repositoryCategories(); if (tmpRepoCategories.contains(repoCategory)) { tmpRepoCategories.remove(repoCategory); tmpRepoCategories.insert(replacement); m_core->settings().addRepositoryCategories(tmpRepoCategories); } } void ComponentSelectionPagePrivate::updateWidgetVisibility(bool show) { if (show) m_stackedLayout->setCurrentIndex(1); else m_stackedLayout->setCurrentIndex(0); if (QAbstractButton *bspButton = q->gui()->button(QWizard::CustomButton2)) bspButton->setEnabled(!show); // In macOS 10.12 the widgets are not hidden if those are not updated immediately #ifdef Q_OS_MACOS q->repaint(); #endif } void ComponentSelectionPagePrivate::fetchRepositoryCategories() { updateWidgetVisibility(true); QCheckBox *checkbox; QList checkboxes = m_categoryGroupBox->findChildren(); for (int i = 0; i < checkboxes.count(); i++) { checkbox = checkboxes.at(i); enableRepositoryCategory(checkbox->objectName(), checkbox->isChecked()); } if (!m_core->fetchRemotePackagesTree()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("FailToFetchPackages"), tr("Error"), m_core->error()); } updateWidgetVisibility(false); } void ComponentSelectionPagePrivate::customButtonClicked(int which) { if (QWizard::WizardButton(which) == QWizard::CustomButton2) { QString defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, ComponentSelectionPage::tr("Open File"),defaultDownloadDirectory, QLatin1String("QBSP or 7z Files (*.qbsp *.7z)")); QSet set; foreach (QString fileName, fileNames) { Repository repository = Repository::fromUserInput(fileName, true); repository.setEnabled(true); set.insert(repository); } if (set.count() > 0) { updateWidgetVisibility(true); m_core->settings().addTemporaryRepositories(set, false); if (!m_core->fetchCompressedPackagesTree()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("FailToFetchPackages"), tr("Error"), m_core->error()); } } updateWidgetVisibility(false); } } /*! Updates the value of \a progress on the progress bar. */ void ComponentSelectionPagePrivate::onProgressChanged(int progress) { m_progressBar->setValue(progress); } /*! Displays the message \a msg on the page. */ void ComponentSelectionPagePrivate::setMessage(const QString &msg) { QWizardPage *page = q->gui()->currentPage(); if (m_metadataProgressLabel && page && page->objectName() == QLatin1String("ComponentSelectionPage")) m_metadataProgressLabel->setText(msg); } void ComponentSelectionPagePrivate::setTotalProgress(int totalProgress) { if (m_progressBar) m_progressBar->setRange(0, totalProgress); } void ComponentSelectionPagePrivate::selectDefault() { m_currentModel->setCheckedState(ComponentModel::DefaultChecked); } void ComponentSelectionPagePrivate::onModelStateChanged(QInstaller::ComponentModel::ModelState state) { q->setModified(state.testFlag(ComponentModel::DefaultChecked) == false); // If all components in the checked list are only checkable when run without forced // installation, set ComponentModel::AllUnchecked as well, as we cannot uncheck anything. // Helps to keep the UI correct. if ((!m_core->noForceInstallation()) && (m_currentModel->checked() == m_currentModel->uncheckable())) { state |= ComponentModel::AllUnchecked; } // enable the button if the corresponding flag is not set m_checkAll->setEnabled(state.testFlag(ComponentModel::AllChecked) == false); m_uncheckAll->setEnabled(state.testFlag(ComponentModel::AllUnchecked) == false); m_checkDefault->setEnabled(state.testFlag(ComponentModel::DefaultChecked) == false); // update the current selected node (important to reflect possible sub-node changes) if (m_treeView->selectionModel()) currentSelectedChanged(m_treeView->selectionModel()->currentIndex()); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/componentselectionpage_p.h0100777000000000000000000000672413761647206024063 0ustar00/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMPONENTSELECTIONPAGE_P_H #define COMPONENTSELECTIONPAGE_P_H #include #include #include "componentmodel.h" #include "packagemanagergui.h" class QTreeView; class QLabel; class QScrollArea; class QPushButton; class QGroupBox; class QListWidgetItem; class QProgressBar; class QVBoxLayout; class QHBoxLayout; class QGridLayout; class QStackedLayout; namespace QInstaller { class PackageManagerCore; class ComponentModel; class ComponentSelectionPage; class ComponentSelectionPagePrivate : public QObject { Q_OBJECT friend class ComponentSelectionPage; Q_DISABLE_COPY(ComponentSelectionPagePrivate) public: explicit ComponentSelectionPagePrivate(ComponentSelectionPage *qq, PackageManagerCore *core); ~ComponentSelectionPagePrivate(); void allowCompressedRepositoryInstall(); void showCompressedRepositoryButton(); void hideCompressedRepositoryButton(); void setupCategoryLayout(); void showCategoryLayout(bool show); void updateTreeView(); public slots: void currentSelectedChanged(const QModelIndex ¤t); void selectAll(); void deselectAll(); void checkboxStateChanged(); void enableRepositoryCategory(const QString &repositoryName, bool enable); void updateWidgetVisibility(bool show); void fetchRepositoryCategories(); void customButtonClicked(int which); void onProgressChanged(int progress); void setMessage(const QString &msg); void setTotalProgress(int totalProgress); void selectDefault(); void onModelStateChanged(QInstaller::ComponentModel::ModelState state); private: ComponentSelectionPage *q; PackageManagerCore *m_core; QTreeView *m_treeView; QLabel *m_sizeLabel; QLabel *m_descriptionLabel; QPushButton *m_checkAll; QPushButton *m_uncheckAll; QPushButton *m_checkDefault; QWidget *m_categoryWidget; QGroupBox *m_categoryGroupBox; QLabel *m_metadataProgressLabel; QProgressBar *m_progressBar; QGridLayout *m_mainGLayout; bool m_allowCompressedRepositoryInstall; ComponentModel *m_allModel; ComponentModel *m_updaterModel; ComponentModel *m_currentModel; QStackedLayout *m_stackedLayout; }; } // namespace QInstaller #endif // COMPONENTSELECTIONPAGE_P_H qt-installer-framework-4.0.1/src/libs/installer/component_p.cpp0100777000000000000000000002264213761647206021650 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "component_p.h" #include "component.h" #include "packagemanagercore.h" #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::ComponentPrivate \internal */ // -- ComponentPrivate ComponentPrivate::ComponentPrivate(PackageManagerCore *core, Component *qq) : q(qq) , m_core(core) , m_parentComponent(nullptr) , m_licenseOperation(nullptr) , m_minimumProgressOperation(nullptr) , m_newlyInstalled (false) , m_operationsCreated(false) , m_autoCreateOperations(true) , m_operationsCreatedSuccessfully(true) , m_updateIsAvailable(false) { } ComponentPrivate::~ComponentPrivate() { // Before we can delete the added widgets, they need to be removed from the wizard first. foreach (const QString &widgetName, m_userInterfaces.keys()) { m_core->removeWizardPage(q, widgetName); m_core->removeWizardPageItem(q, widgetName); } // Use QPointer here instead of raw pointers. This is a requirement that needs to be met cause possible // Ui elements get added during component script run and might be destroyed by the package manager gui // before the actual component gets destroyed. Avoids a possible delete call on a dangling pointer. foreach (const QPointer widget, m_userInterfaces) delete widget.data(); } ScriptEngine *ComponentPrivate::scriptEngine() const { return m_core->componentScriptEngine(); } // -- ComponentModelHelper ComponentModelHelper::ComponentModelHelper() { setCheckState(Qt::Unchecked); setFlags(Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable)); } /*! Returns the number of child components. Depending if virtual components are visible or not, the count might differ from what one will get if calling Component::childComponents(...).count(). */ int ComponentModelHelper::childCount() const { if (m_componentPrivate->m_core->virtualComponentsVisible()) return m_componentPrivate->m_allChildComponents.count(); return m_componentPrivate->m_childComponents.count(); } /*! Returns the component at \a index position in the list. Index must be a valid position in the list, for example \c{index >= 0 && index < childCount()}. Otherwise it returns 0. */ Component *ComponentModelHelper::childAt(int index) const { if (index < 0 && index >= childCount()) return nullptr; if (m_componentPrivate->m_core->virtualComponentsVisible()) return m_componentPrivate->m_allChildComponents.value(index, nullptr); return m_componentPrivate->m_childComponents.value(index, nullptr); } /*! Returns all descendants of this component depending if virtual components are visible or not. */ QList ComponentModelHelper::childItems() const { QList *components = &m_componentPrivate->m_childComponents; if (m_componentPrivate->m_core->virtualComponentsVisible()) components = &m_componentPrivate->m_allChildComponents; QList result; foreach (Component *const component, *components) { result.append(component); result += component->childItems(); } return result; } /*! Determines if the installation status of the component can be changed. The default return value is \c true. */ bool ComponentModelHelper::isEnabled() const { return (flags() & Qt::ItemIsEnabled) != 0; } /*! Enables or disables the ability to change the installation status of the components based on \a enabled. */ void ComponentModelHelper::setEnabled(bool enabled) { changeFlags(enabled, Qt::ItemIsEnabled); } /*! Returns whether the component is tri-state; that is, if it's checkable with three separate states. The default value is \c false. */ bool ComponentModelHelper::isTristate() const { return (flags() & Qt::ItemIsTristate) != 0; } /*! Sets whether the component is tri-state based on \a tristate . If tri-state is \c true, the component is checkable with three separate states; otherwise, the component is checkable with two states. Note: this also requires that the component is checkable. \sa isCheckable() */ void ComponentModelHelper::setTristate(bool tristate) { changeFlags(tristate, Qt::ItemIsTristate); } /*! Returns whether the component is user-checkable. The default value is \c true. */ bool ComponentModelHelper::isCheckable() const { return (flags() & Qt::ItemIsUserCheckable) != 0; } /*! Sets whether the component is user-checkable. If \a checkable is \c true, the component can be checked by the user; otherwise, the user cannot check the component. The delegate will render a checkable component with a check box next to the component's text. */ void ComponentModelHelper::setCheckable(bool checkable) { if (checkable && !isCheckable()) { // make sure there's data for the check state role if (!data(Qt::CheckStateRole).isValid()) setData(Qt::Unchecked, Qt::CheckStateRole); } changeFlags(checkable, Qt::ItemIsUserCheckable); } /*! Returns whether the component is selectable by the user. The default value is \c true. */ bool ComponentModelHelper::isSelectable() const { return (flags() & Qt::ItemIsSelectable) != 0; } /*! Sets whether the component is selectable. If \a selectable is \c true, the component can be selected by the user; otherwise, the user cannot select the component. */ void ComponentModelHelper::setSelectable(bool selectable) { changeFlags(selectable, Qt::ItemIsSelectable); } /*! Returns whether the component is expanded by default. The default value is \c false. */ bool ComponentModelHelper::isExpandedByDefault() const { return data(ComponentModelHelper::ExpandedByDefault).value(); } /*! Sets whether the component is expanded by default based on \a expandedByDefault. The default value is \c false. */ void ComponentModelHelper::setExpandedByDefault(bool expandedByDefault) { setData(QVariant::fromValue(expandedByDefault), ComponentModelHelper::ExpandedByDefault); } ComponentModelHelper::InstallAction ComponentModelHelper::installAction() const { return data(ComponentModelHelper::Action).value(); } void ComponentModelHelper::setInstallAction(ComponentModelHelper::InstallAction action) { setData(QVariant::fromValue(action), ComponentModelHelper::Action); } /*! Returns the item flags for the component. The item flags determine how the user can interact with the component. */ Qt::ItemFlags ComponentModelHelper::flags() const { QVariant variant = data(Qt::UserRole - 1); if (!variant.isValid()) return Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); return Qt::ItemFlags(variant.toInt()); } /*! Sets the item flags for the component to \a flags. The item flags determine how the user can interact with the component. This is often used to disable an component. */ void ComponentModelHelper::setFlags(Qt::ItemFlags flags) { setData(int(flags), Qt::UserRole - 1); } /*! Returns the checked state of the component. */ Qt::CheckState ComponentModelHelper::checkState() const { return Qt::CheckState(qvariant_cast(data(Qt::CheckStateRole))); } /*! Sets the check state of the component to be \a state. */ void ComponentModelHelper::setCheckState(Qt::CheckState state) { setData(state, Qt::CheckStateRole); } /*! Returns the component's data for the given \a role, or an invalid QVariant if there is no data for role. */ QVariant ComponentModelHelper::data(int role) const { return m_values.value((role == Qt::EditRole ? Qt::DisplayRole : role), QVariant()); } /*! Sets the component's data for the given \a role to the specified \a value. */ void ComponentModelHelper::setData(const QVariant &value, int role) { m_values.insert((role == Qt::EditRole ? Qt::DisplayRole : role), value); } // -- protected void ComponentModelHelper::setPrivate(ComponentPrivate *componentPrivate) { m_componentPrivate = componentPrivate; } // -- private void ComponentModelHelper::changeFlags(bool enable, Qt::ItemFlags itemFlags) { setFlags(enable ? flags() |= itemFlags : flags() &= ~itemFlags); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/component_p.h0100777000000000000000000001063413761647206021313 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMPONENT_P_H #define COMPONENT_P_H #include "qinstallerglobal.h" #include #include #include #include namespace QInstaller { class Component; class PackageManagerCore; class ScriptEngine; class ComponentPrivate { QInstaller::Component* const q; public: explicit ComponentPrivate(PackageManagerCore *core, Component *qq); ~ComponentPrivate(); ScriptEngine *scriptEngine() const; PackageManagerCore *m_core; Component *m_parentComponent; OperationList m_operations; Operation *m_licenseOperation; Operation *m_minimumProgressOperation; bool m_newlyInstalled; bool m_operationsCreated; bool m_autoCreateOperations; bool m_operationsCreatedSuccessfully; bool m_updateIsAvailable; bool m_unstable; QString m_componentName; QUrl m_repositoryUrl; QString m_localTempPath; QJSValue m_scriptContext; QHash m_vars; QList m_childComponents; QList m_allChildComponents; QStringList m_downloadableArchives; QStringList m_stopProcessForUpdateRequests; QHash > m_userInterfaces; // < display name, < file name, file content > > QHash > m_licenses; QList > m_pathsForUninstallation; }; // -- ComponentModelHelper class INSTALLER_EXPORT ComponentModelHelper { public: enum Roles { Action = Qt::UserRole + 1, LocalDisplayVersion, RemoteDisplayVersion, ReleaseDate, UncompressedSize, ExpandedByDefault }; enum InstallAction { Install, Uninstall, KeepInstalled, KeepUninstalled, AutodependUninstallation }; enum Column { NameColumn = 0, ActionColumn, InstalledVersionColumn, NewVersionColumn, ReleaseDateColumn, UncompressedSizeColumn, LastColumn }; explicit ComponentModelHelper(); int childCount() const; Component* childAt(int index) const; QList childItems() const; bool isEnabled() const; void setEnabled(bool enabled); bool isTristate() const; void setTristate(bool tristate); bool isCheckable() const; void setCheckable(bool checkable); bool isSelectable() const; void setSelectable(bool selectable); bool isExpandedByDefault() const; void setExpandedByDefault(bool expandedByDefault); InstallAction installAction() const; void setInstallAction(InstallAction action); Qt::ItemFlags flags() const; void setFlags(Qt::ItemFlags flags); Qt::CheckState checkState() const; void setCheckState(Qt::CheckState state); QVariant data(int role = Qt::UserRole + 1) const; void setData(const QVariant &value, int role = Qt::UserRole + 1); protected: void setPrivate(ComponentPrivate *componentPrivate); private: void changeFlags(bool enable, Qt::ItemFlags itemFlags); private: QHash m_values; ComponentPrivate *m_componentPrivate; }; } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::ComponentModelHelper::InstallAction) #endif // COMPONENT_P_H qt-installer-framework-4.0.1/src/libs/installer/constants.h0100777000000000000000000002471013761647206021006 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CONSTANTS_H #define CONSTANTS_H #include #include namespace QInstaller { // constants used throughout several classes static const QLatin1String scTrue("true"); static const QLatin1String scFalse("false"); static const QLatin1String scScript("script"); static const QLatin1String scAllUsersStartMenuProgramsPath("AllUsersStartMenuProgramsPath"); static const QLatin1String scUserStartMenuProgramsPath("UserStartMenuProgramsPath"); static const QLatin1String scName("Name"); static const QLatin1String scVersion("Version"); static const QLatin1String scDefault("Default"); static const QLatin1String scDisplayVersion("DisplayVersion"); static const QLatin1String scRemoteDisplayVersion("RemoteDisplayVersion"); static const QLatin1String scInheritVersion("inheritVersionFrom"); static const QLatin1String scReplaces("Replaces"); static const QLatin1String scDownloadableArchives("DownloadableArchives"); static const QLatin1String scEssential("Essential"); static const QLatin1String scTargetDir("TargetDir"); static const QLatin1String scReleaseDate("ReleaseDate"); static const QLatin1String scDescription("Description"); static const QLatin1String scDisplayName("DisplayName"); static const QLatin1String scDependencies("Dependencies"); static const QLatin1String scAutoDependOn("AutoDependOn"); static const QLatin1String scNewComponent("NewComponent"); static const QLatin1String scRepositories("Repositories"); static const QLatin1String scCompressedSize("CompressedSize"); static const QLatin1String scInstalledVersion("InstalledVersion"); static const QLatin1String scUncompressedSize("UncompressedSize"); static const QLatin1String scUncompressedSizeSum("UncompressedSizeSum"); static const QLatin1String scRequiresAdminRights("RequiresAdminRights"); static const QLatin1String scSHA1("SHA1"); // constants used throughout the components class static const QLatin1String scVirtual("Virtual"); static const QLatin1String scSortingPriority("SortingPriority"); static const QLatin1String scCheckable("Checkable"); // constants used throughout the settings and package manager core class static const QLatin1String scTitle("Title"); static const QLatin1String scPublisher("Publisher"); static const QLatin1String scRunProgram("RunProgram"); static const QLatin1String scRunProgramArguments("RunProgramArguments"); static const QLatin1String scStartMenuDir("StartMenuDir"); static const QLatin1String scRemoveTargetDir("RemoveTargetDir"); static const QLatin1String scRunProgramDescription("RunProgramDescription"); static const QLatin1String scTargetConfigurationFile("TargetConfigurationFile"); static const QLatin1String scAllowNonAsciiCharacters("AllowNonAsciiCharacters"); static const QLatin1String scDisableAuthorizationFallback("DisableAuthorizationFallback"); static const QLatin1String scDisableCommandLineInterface("DisableCommandLineInterface"); static const QLatin1String scRepositorySettingsPageVisible("RepositorySettingsPageVisible"); static const QLatin1String scAllowSpaceInPath("AllowSpaceInPath"); static const QLatin1String scWizardStyle("WizardStyle"); static const QLatin1String scStyleSheet("StyleSheet"); static const QLatin1String scTitleColor("TitleColor"); static const QLatin1String scWizardDefaultWidth("WizardDefaultWidth"); static const QLatin1String scWizardDefaultHeight("WizardDefaultHeight"); static const QLatin1String scWizardShowPageList("WizardShowPageList"); static const QLatin1String scProductImages("ProductImages"); static const QLatin1String scUrlQueryString("UrlQueryString"); static const QLatin1String scProductUUID("ProductUUID"); static const QLatin1String scAllUsers("AllUsers"); static const QLatin1String scSupportsModify("SupportsModify"); static const QLatin1String scAllowUnstableComponents("AllowUnstableComponents"); static const QLatin1String scSaveDefaultRepositories("SaveDefaultRepositories"); static const QLatin1String scRepositoryCategoryDisplayName("RepositoryCategoryDisplayName"); const char scRelocatable[] = "@RELOCATABLE_PATH@"; } namespace CommandLineOptions { // Help & version information static const QLatin1String scHelpShort("h"); static const QLatin1String scHelpLong("help"); static const QLatin1String scVersionShort("v"); static const QLatin1String scVersionLong("version"); // Output related options static const QLatin1String scVerboseShort("d"); static const QLatin1String scVerboseLong("verbose"); static const QLatin1String scLoggingRulesShort("g"); static const QLatin1String scLoggingRulesLong("logging-rules"); // Consumer commands static const QLatin1String scInstallShort("in"); static const QLatin1String scInstallLong("install"); static const QLatin1String scCheckUpdatesShort("ch"); static const QLatin1String scCheckUpdatesLong("check-updates"); static const QLatin1String scUpdateShort("up"); static const QLatin1String scUpdateLong("update"); static const QLatin1String scRemoveShort("rm"); static const QLatin1String scRemoveLong("remove"); static const QLatin1String scListShort("li"); static const QLatin1String scListLong("list"); static const QLatin1String scSearchShort("se"); static const QLatin1String scSearchLong("search"); static const QLatin1String scPurgeShort("pr"); static const QLatin1String scPurgeLong("purge"); // Repository management options static const QLatin1String scAddRepositoryShort("ar"); static const QLatin1String scAddRepositoryLong("add-repository"); static const QLatin1String scAddTmpRepositoryShort("at"); static const QLatin1String scAddTmpRepositoryLong("add-temp-repository"); static const QLatin1String scSetTmpRepositoryShort("st"); static const QLatin1String scSetTmpRepositoryLong("set-temp-repository"); // Proxy options static const QLatin1String scSystemProxyShort("sp"); static const QLatin1String scSystemProxyLong("system-proxy"); static const QLatin1String scNoProxyShort("np"); static const QLatin1String scNoProxyLong("no-proxy"); // Starting mode options static const QLatin1String scStartUpdaterShort("su"); static const QLatin1String scStartUpdaterLong("start-updater"); static const QLatin1String scStartPackageManagerShort("sm"); static const QLatin1String scStartPackageManagerLong("start-package-manager"); static const QLatin1String scStartUninstallerShort("sr"); static const QLatin1String scStartUninstallerLong("start-uninstaller"); // Message acceptance options static const QLatin1String scAcceptMessageQueryShort("am"); static const QLatin1String scAcceptMessageQueryLong("accept-messages"); static const QLatin1String scRejectMessageQueryShort("rm"); static const QLatin1String scRejectMessageQueryLong("reject-messages"); static const QLatin1String scMessageAutomaticAnswerShort("aa"); static const QLatin1String scMessageAutomaticAnswerLong("auto-answer"); static const QLatin1String scMessageDefaultAnswerShort("da"); static const QLatin1String scMessageDefaultAnswerLong("default-answer"); static const QLatin1String scAcceptLicensesShort("al"); static const QLatin1String scAcceptLicensesLong("accept-licenses"); static const QLatin1String scFileDialogAutomaticAnswer("file-query"); static const QLatin1String scConfirmCommandShort("c"); static const QLatin1String scConfirmCommandLong("confirm-command"); // Misc installation options static const QLatin1String scRootShort("t"); static const QLatin1String scRootLong("root"); static const QLatin1String scPlatformShort("p"); static const QLatin1String scPlatformLong("platform"); static const QLatin1String scNoForceInstallationShort("nf"); static const QLatin1String scNoForceInstallationLong("no-force-installations"); static const QLatin1String scNoSizeCheckingShort("ns"); static const QLatin1String scNoSizeCheckingLong("no-size-checking"); static const QLatin1String scShowVirtualComponentsShort("sv"); static const QLatin1String scShowVirtualComponentsLong("show-virtual-components"); static const QLatin1String scInstallCompressedRepositoryShort("i"); static const QLatin1String scInstallCompressedRepositoryLong("install-compressed-repository"); static const QLatin1String scCreateLocalRepositoryShort("cl"); static const QLatin1String scCreateLocalRepositoryLong("create-local-repository"); static const QLatin1String scNoDefaultInstallationShort("nd"); static const QLatin1String scNoDefaultInstallationLong("no-default-installations"); // Developer options static const QLatin1String scScriptShort("s"); static const QLatin1String scScriptLong("script"); static const QLatin1String scStartServerShort("ss"); static const QLatin1String scStartServerLong("start-server"); static const QLatin1String scStartClientShort("sc"); static const QLatin1String scStartClientLong("start-client"); static const QLatin1String scSquishPortShort("q"); static const QLatin1String scSquishPortLong("squish-port"); // Deprecated options, provided only for backward compatibility static const QLatin1String scDeprecatedUpdater("updater"); static const QLatin1String scDeprecatedCheckUpdates("checkupdates"); // Options supposed to be used without graphical interface static const QStringList scCommandLineInterfaceOptions = { scInstallShort, scInstallLong, scCheckUpdatesShort, scCheckUpdatesLong, scUpdateShort, scUpdateLong, scRemoveShort, scRemoveLong, scListShort, scListLong, scSearchShort, scSearchLong, scPurgeShort, scPurgeLong }; } // namespace CommandLineOptions #endif // CONSTANTS_H qt-installer-framework-4.0.1/src/libs/installer/consumeoutputoperation.cpp0100777000000000000000000001230513761647206024175 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "consumeoutputoperation.h" #include "packagemanagercore.h" #include "utils.h" #include "globals.h" #include #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::ConsumeOutputOperation \internal */ ConsumeOutputOperation::ConsumeOutputOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("ConsumeOutput")); } void ConsumeOutputOperation::backup() { } bool ConsumeOutputOperation::performOperation() { // Arguments: // 1. key where the output will be saved // 2. executable path // 3. argument for the executable // 4. more arguments possible ... if (!checkArgumentCount(2, INT_MAX, tr(" " " [argument1] [argument2] [...]"))) return false; PackageManagerCore *const core = packageManager(); if (!core) { setError(UserDefinedError); setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); return false; } const QString installerKeyName = arguments().at(0); if (installerKeyName.isEmpty()) { setError(UserDefinedError); setErrorString(tr("Cannot save the output of \"%1\" to an empty installer key value.").arg( QDir::toNativeSeparators(arguments().at(1)))); return false; } QString executablePath = arguments().at(1); QFileInfo executable(executablePath); #ifdef Q_OS_WIN if (!executable.exists() && executable.suffix().isEmpty()) executable = QFileInfo(executablePath + QLatin1String(".exe")); #endif if (!executable.exists() || !executable.isExecutable()) { setError(UserDefinedError); setErrorString(tr("File \"%1\" does not exist or is not an executable binary.").arg( QDir::toNativeSeparators(executable.absoluteFilePath()))); return false; } QByteArray executableOutput; const QStringList processArguments = arguments().mid(2); // in some cases it is not runable, because another process is blocking it(filewatcher ...) int waitCount = 0; while (executableOutput.isEmpty() && waitCount < 3) { QProcess process; process.start(executable.absoluteFilePath(), processArguments, QIODevice::ReadOnly); if (process.waitForFinished(10000)) { if (process.exitStatus() == QProcess::CrashExit) { qCWarning(QInstaller::lcInstallerInstallLog) << executable.absoluteFilePath() << processArguments << "crashed with exit code" << process.exitCode() << "standard output: " << process.readAllStandardOutput() << "error output: " << process.readAllStandardError(); setError(UserDefinedError); setErrorString(tr("Running \"%1\" resulted in a crash.").arg( QDir::toNativeSeparators(executable.absoluteFilePath()))); return false; } executableOutput.append(process.readAllStandardOutput()); } if (executableOutput.isEmpty()) { ++waitCount; static const int waitTimeInMilliSeconds = 500; uiDetachedWait(waitTimeInMilliSeconds); } if (process.state() > QProcess::NotRunning ) { qCWarning(QInstaller::lcInstallerInstallLog) << executable.absoluteFilePath() << "process is still running, need to kill it."; process.kill(); } } if (executableOutput.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot get any query output from executable" << executable.absoluteFilePath(); } core->setValue(installerKeyName, QString::fromLocal8Bit(executableOutput)); return true; } bool ConsumeOutputOperation::undoOperation() { return true; } bool ConsumeOutputOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/consumeoutputoperation.h0100777000000000000000000000334213761647206023643 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CONSUMEOUTPUTOPERATION_H #define CONSUMEOUTPUTOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT ConsumeOutputOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::ConsumeOutputOperation) public: explicit ConsumeOutputOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); private: }; } // namespace QInstaller #endif // CONSUMEOUTPUTOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/copydirectoryoperation.cpp0100777000000000000000000001503213761647206024142 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "copydirectoryoperation.h" #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::CopyDirectoryOperation \internal */ class AutoPush { public: AutoPush(CopyDirectoryOperation *op) : m_op(op) {} ~AutoPush() { m_op->setValue(QLatin1String("files"), m_files); } QStringList m_files; CopyDirectoryOperation *m_op; }; CopyDirectoryOperation::CopyDirectoryOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("CopyDirectory")); } void CopyDirectoryOperation::backup() { } bool CopyDirectoryOperation::performOperation() { if (!checkArgumentCount(2, 3, tr(" [\"forceOverwrite\"]"))) return false; const QStringList args = arguments(); const QString sourcePath = args.at(0); const QString targetPath = args.at(1); bool overwrite = false; if (args.count() > 2) { const QString overwriteStr = args.at(2); if (overwriteStr == QLatin1String("forceOverwrite")) { overwrite = true; } else { setError(InvalidArguments); setErrorString(tr("Invalid argument in %1: Third argument needs to be forceOverwrite, " "if specified.").arg(name())); return false; } } const QFileInfo sourceInfo(sourcePath); const QFileInfo targetInfo(targetPath); foreach (const QFileInfo &dir, QList() << sourceInfo << targetInfo) { if (!dir.exists() || !dir.isDir()) { setError(InvalidArguments); setErrorString(tr("Invalid argument in %1: Directory \"%2\" is invalid.").arg(name()) .arg(QDir::toNativeSeparators(dir.absolutePath()))); return false; } } const QDir sourceDir = sourceInfo.absoluteDir(); const QDir targetDir = targetInfo.absoluteDir(); AutoPush autoPush(this); QDirIterator it(sourceInfo.absoluteFilePath(), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden, QDirIterator::Subdirectories); while (it.hasNext()) { const QString itemName = it.next(); const QFileInfo itemInfo(sourceDir.absoluteFilePath(itemName)); const QString relativePath = sourceDir.relativeFilePath(itemName); if (itemInfo.isSymLink()) { // Check if symlink target is inside copied directory const QString linkTarget = itemInfo.symLinkTarget(); if (linkTarget.startsWith(sourceDir.absolutePath())) { // create symlink to copied location const QString linkTargetRelative = sourceDir.relativeFilePath(linkTarget); QFile(targetDir.absoluteFilePath(linkTargetRelative)) .link(targetDir.absoluteFilePath(relativePath)); } else { // create symlink pointing to original location QFile(linkTarget).link(targetDir.absoluteFilePath(relativePath)); } // add file entry autoPush.m_files.prepend(targetDir.absoluteFilePath(relativePath)); emit outputTextChanged(autoPush.m_files.first()); } else if (itemInfo.isDir()) { if (!targetDir.mkpath(targetDir.absoluteFilePath(relativePath))) { setError(InvalidArguments); setErrorString(tr("Cannot create directory \"%1\".").arg( QDir::toNativeSeparators(targetDir.absoluteFilePath(relativePath)))); return false; } } else { const QString absolutePath = targetDir.absoluteFilePath(relativePath); if (overwrite && QFile::exists(absolutePath) && !deleteFileNowOrLater(absolutePath)) { setError(UserDefinedError); setErrorString(tr("Failed to overwrite \"%1\".").arg(QDir::toNativeSeparators(absolutePath))); return false; } QFile file(sourceDir.absoluteFilePath(itemName)); if (!file.copy(absolutePath)) { setError(UserDefinedError); setErrorString(tr("Cannot copy file \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(sourceDir.absoluteFilePath(itemName)), QDir::toNativeSeparators(targetDir.absoluteFilePath(relativePath)), file.errorString())); return false; } autoPush.m_files.prepend(targetDir.absoluteFilePath(relativePath)); emit outputTextChanged(autoPush.m_files.first()); } } return true; } bool CopyDirectoryOperation::undoOperation() { Q_ASSERT(arguments().count() == 2); QDir dir; const QStringList files = value(QLatin1String("files")).toStringList(); foreach (const QString &file, files) { if (!QFile::remove(file)) { setError(InvalidArguments); setErrorString(tr("Cannot remove file \"%1\".").arg(QDir::toNativeSeparators(file))); return false; } dir.rmdir(QFileInfo(file).absolutePath()); emit outputTextChanged(file); } setValue(QLatin1String("files"), QStringList()); return true; } bool CopyDirectoryOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/copydirectoryoperation.h0100777000000000000000000000333713761647206023614 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COPYDIRECTORYOPERATION_H #define COPYDIRECTORYOPERATION_H #include "qinstallerglobal.h" #include namespace QInstaller { class INSTALLER_EXPORT CopyDirectoryOperation : public QObject, public Operation { Q_OBJECT public: explicit CopyDirectoryOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); Q_SIGNALS: void outputTextChanged(const QString &progress); }; } #endif qt-installer-framework-4.0.1/src/libs/installer/copyfiletask.cpp0100777000000000000000000001021013761647206022010 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "copyfiletask.h" #include "observer.h" #include #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::CopyFileTask \internal */ CopyFileTask::CopyFileTask(const FileTaskItem &item) : AbstractFileTask(item) { } CopyFileTask::CopyFileTask(const QString &source) : AbstractFileTask(source) { } CopyFileTask::CopyFileTask(const QString &source, const QString &target) : AbstractFileTask(source, target) { } void CopyFileTask::doTask(QFutureInterface &fi) { fi.reportStarted(); fi.setExpectedResultCount(1); if (taskItems().isEmpty()) { fi.reportException(TaskException(tr("Invalid task item count."))); fi.reportFinished(); return; // error } const FileTaskItem item = taskItems().first(); FileTaskObserver observer(QCryptographicHash::Sha1); QFile source(item.source()); if (!source.open(QIODevice::ReadOnly)) { fi.reportException(TaskException(tr("Cannot open file \"%1\" for reading: %2") .arg(QDir::toNativeSeparators(source.fileName()), source.errorString()))); fi.reportFinished(); return; // error } observer.setBytesToTransfer(source.size()); QScopedPointer file; const QString target = item.target(); if (target.isEmpty()) { QTemporaryFile *tmp = new QTemporaryFile; tmp->setAutoRemove(false); file.reset(tmp); } else { file.reset(new QFile(target)); } if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { fi.reportException(TaskException(tr("Cannot open file \"%1\" for writing: %2") .arg(QDir::toNativeSeparators(file->fileName()), file->errorString()))); fi.reportFinished(); return; // error } QByteArray buffer(32768, Qt::Uninitialized); while (!source.atEnd() && source.error() == QFile::NoError) { if (fi.isCanceled()) break; if (fi.isPaused()) fi.waitForResume(); const qint64 read = source.read(buffer.data(), buffer.size()); qint64 written = 0; while (written < read) { const qint64 toWrite = file->write(buffer.constData() + written, read - written); if (toWrite < 0) { fi.reportException(TaskException(tr("Writing to file \"%1\" failed: %2") .arg(QDir::toNativeSeparators(file->fileName()), file->errorString()))); } written += toWrite; } observer.addSample(read); observer.timerEvent(nullptr); observer.addBytesTransfered(read); observer.addCheckSumData(buffer.data(), read); fi.setProgressValueAndText(observer.progressValue(), observer.progressText()); } fi.reportResult(FileTaskResult(file->fileName(), observer.checkSum(), item, false), 0); fi.reportFinished(); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/copyfiletask.h0100777000000000000000000000337313761647206021471 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COPYFILETASK_H #define COPYFILETASK_H #include "abstractfiletask.h" namespace QInstaller { class INSTALLER_EXPORT CopyFileTask : public AbstractFileTask { Q_OBJECT Q_DISABLE_COPY(CopyFileTask) public: CopyFileTask() {} explicit CopyFileTask(const FileTaskItem &item); explicit CopyFileTask(const QString &source); CopyFileTask(const QString &source, const QString &target); void doTask(QFutureInterface &fi); }; } // namespace QInstaller #endif // COPYFILETASK_H qt-installer-framework-4.0.1/src/libs/installer/createdesktopentryoperation.cpp0100777000000000000000000001442313761647206025165 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "createdesktopentryoperation.h" #include "errors.h" #include "fileutils.h" #include "globals.h" #include #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::CreateDesktopEntryOperation \internal */ QString CreateDesktopEntryOperation::absoluteFileName() { const QString filename = arguments().first(); // give filename is already absolute if (QFileInfo(filename).isAbsolute()) return filename; // we're not searching for the first time, let's re-use the old value if (hasValue(QLatin1String("directory"))) return QDir(value(QLatin1String("directory")).toString()).absoluteFilePath(filename); QStringList XDG_DATA_HOME = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")) .split(QLatin1Char(':'), QString::SkipEmptyParts); XDG_DATA_HOME.push_back(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); // default path const QStringList directories = XDG_DATA_HOME; QString directory; for (QStringList::const_iterator it = directories.begin(); it != directories.end(); ++it) { if (it->isEmpty()) continue; directory = QDir(*it).absoluteFilePath(QLatin1String("applications")); QDir dir(directory); // let's see whether this dir exists or we're able to create it if (!dir.exists() && !QDir().mkpath(directory)) continue; // we just try whether we're able to open the file in ReadWrite QFile file(QDir(directory).absoluteFilePath(filename)); const bool existed = file.exists(); if (!file.open(QIODevice::ReadWrite)) continue; file.close(); if (!existed) file.remove(); break; } if (!QDir(directory).exists()) QDir().mkpath(directory); setValue(QLatin1String("directory"), directory); return QDir(directory).absoluteFilePath(filename); } CreateDesktopEntryOperation::CreateDesktopEntryOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("CreateDesktopEntry")); } CreateDesktopEntryOperation::~CreateDesktopEntryOperation() { } void CreateDesktopEntryOperation::backup() { const QString filename = absoluteFileName(); QFile file(filename); if (!file.exists()) return; try { setValue(QLatin1String("backupOfExistingDesktopEntry"), generateTemporaryFileName(filename)); } catch (const QInstaller::Error &e) { setErrorString(e.message()); return; } if (!file.copy(value(QLatin1String("backupOfExistingDesktopEntry")).toString())) setErrorString(tr("Cannot backup file \"%1\": %2").arg(QDir::toNativeSeparators(filename), file.errorString())); } bool CreateDesktopEntryOperation::performOperation() { if (!checkArgumentCount(2)) return false; const QString filename = absoluteFileName(); const QString &values = arguments().at(1); QFile file(filename); if (file.exists() && !file.remove()) { setError(UserDefinedError); setErrorString(tr("Failed to overwrite file \"%1\".").arg(QDir::toNativeSeparators(filename))); return false; } if(!file.open(QIODevice::WriteOnly)) { setError(UserDefinedError); setErrorString(tr("Cannot write desktop entry to \"%1\".").arg(QDir::toNativeSeparators(filename))); return false; } setDefaultFilePermissions(filename, DefaultFilePermissions::Executable); QTextStream stream(&file); stream.setCodec("UTF-8"); stream << QLatin1String("[Desktop Entry]") << endl; // Type=Application\nExec=qtcreator\nPath=... const QStringList pairs = values.split(QLatin1Char('\n')); for (QStringList::const_iterator it = pairs.begin(); it != pairs.end(); ++it) stream << *it << endl; return true; } bool CreateDesktopEntryOperation::undoOperation() { const QString filename = absoluteFileName(); // first remove the link QFile file(filename); if (file.exists() && !file.remove()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot delete file" << filename << ":" << file.errorString(); return true; } if (!hasValue(QLatin1String("backupOfExistingDesktopEntry"))) return true; QFile backupFile(value(QLatin1String("backupOfExistingDesktopEntry")).toString()); if (!backupFile.exists()) { // do not treat this as a real error: The backup file might have been just nuked by the user. qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot restore original desktop entry at" << filename << ": Backup file" << backupFile.fileName() << "does not exist anymore."; return true; } if (!backupFile.rename(filename)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot restore the file" << filename << ":" << backupFile.errorString(); } return true; } bool CreateDesktopEntryOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/createdesktopentryoperation.h0100777000000000000000000000340213761647206024625 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CREATEDESKTOPENTRYOPERATION_H #define CREATEDESKTOPENTRYOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT CreateDesktopEntryOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::CreateDesktopEntryOperation) public: explicit CreateDesktopEntryOperation(PackageManagerCore *core); ~CreateDesktopEntryOperation(); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); QString absoluteFileName(); }; } #endif qt-installer-framework-4.0.1/src/libs/installer/createlinkoperation.cpp0100777000000000000000000000546313761647206023373 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "createlinkoperation.h" #include "link.h" #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::CreateLinkOperation \internal */ CreateLinkOperation::CreateLinkOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("CreateLink")); } void CreateLinkOperation::backup() { } bool CreateLinkOperation::performOperation() { if (!checkArgumentCount(2)) return false; const QStringList args = arguments(); const QString& linkPath = args.at(0); const QString& targetPath = args.at(1); Link link = Link::create(linkPath, targetPath); if (!link.exists()) { setError(UserDefinedError); setErrorString(tr("Cannot create link from \"%1\" to \"%2\".").arg( QDir::toNativeSeparators(linkPath), QDir::toNativeSeparators(targetPath))); return false; } return true; } bool CreateLinkOperation::undoOperation() { QStringList args = arguments(); const QString& linkPath = args.at(0); const QString& targetPath = args.at(1); Link link = Link(linkPath); if (!link.exists()) { return true; } if (!link.remove()) { setError(UserDefinedError); setErrorString(tr("Cannot remove link from \"%1\" to \"%2\".").arg( QDir::toNativeSeparators(linkPath), QDir::toNativeSeparators(targetPath))); return false; } return !QFileInfo(linkPath).exists(); } bool CreateLinkOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/createlinkoperation.h0100777000000000000000000000322513761647206023032 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CREATELINKOPERATION_H #define CREATELINKOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT CreateLinkOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::CreateLinkOperation) public: explicit CreateLinkOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } #endif qt-installer-framework-4.0.1/src/libs/installer/createlocalrepositoryoperation.cpp0100777000000000000000000004016413761647206025665 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "createlocalrepositoryoperation.h" #include "binarycontent.h" #include "binaryformat.h" #include "errors.h" #include "fileio.h" #include "fileutils.h" #include "copydirectoryoperation.h" #include "lib7z_create.h" #include "lib7z_facade.h" #include "packagemanagercore.h" #include "productkeycheck.h" #include "constants.h" #include "remoteclient.h" #include "updateoperations.h" #include #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::CreateLocalRepositoryOperation \internal */ // -- AutoHelper struct AutoHelper { public: AutoHelper(CreateLocalRepositoryOperation *op) : m_op(op) { } ~AutoHelper() { m_op->emitFullProgress(); m_op->setValue(QLatin1String("files"), m_files); } QStringList m_files; CreateLocalRepositoryOperation *m_op; }; // statics namespace Static { static void fixPermissions(const QString &repoPath) { QDirIterator it(repoPath, QDirIterator::Subdirectories); while (it.hasNext() && !it.next().isEmpty()) { if (!it.fileInfo().isFile()) continue; if (!setDefaultFilePermissions(it.filePath(), DefaultFilePermissions::NonExecutable)) { throw Error(CreateLocalRepositoryOperation::tr("Cannot set permissions for file \"%1\".") .arg(QDir::toNativeSeparators(it.filePath()))); } } } static void removeDirectory(const QString &path, AutoHelper *const helper) { QInstaller::removeDirectory(path); QStringList files = helper->m_files.filter(path); foreach (const QString &file, files) helper->m_files.removeAll(file); } static void removeFiles(const QString &path, AutoHelper *const helper) { const QFileInfoList entries = QDir(path).entryInfoList(QDir::AllEntries | QDir::Hidden); foreach (const QFileInfo &fi, entries) { if (fi.isSymLink() || fi.isFile()) { QFile f(fi.filePath()); if (!f.remove()) { throw Error(CreateLocalRepositoryOperation::tr("Cannot remove file \"%1\": %2") .arg(QDir::toNativeSeparators(f.fileName()), f.errorString())); } helper->m_files.removeAll(f.fileName()); } } } static QString createArchive(const QString repoPath, const QString &sourceDir, const QString &version , AutoHelper *const helper) { const QString fileName = QString::fromLatin1("/%1meta.7z").arg(version); QFile archive(repoPath + fileName); QInstaller::openForWrite(&archive); Lib7z::createArchive(&archive, QStringList() << sourceDir); removeFiles(sourceDir, helper); // cleanup the files we compressed if (!archive.rename(sourceDir + fileName)) { throw Error(CreateLocalRepositoryOperation::tr("Cannot move file \"%1\" to \"%2\": %3") .arg(QDir::toNativeSeparators(archive.fileName()), QDir::toNativeSeparators(sourceDir + fileName), archive.errorString())); } return archive.fileName(); } } // namespace Statics // -- CreateLocalRepositoryOperation CreateLocalRepositoryOperation::CreateLocalRepositoryOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("CreateLocalRepository")); } void CreateLocalRepositoryOperation::backup() { } bool CreateLocalRepositoryOperation::performOperation() { AutoHelper helper(this); emit progressChanged(0.0); if (!checkArgumentCount(2)) return false; try { const QStringList args = arguments(); const QString binaryPath = QFileInfo(args.at(0)).absoluteFilePath(); // Note the "/" at the end, important to make copy directory operation behave well const QString repoPath = QFileInfo(args.at(1)).absoluteFilePath() + QLatin1Char('/'); // check if this is an offline version, otherwise there will be no binary data PackageManagerCore *const core = packageManager(); if (core && !core->isOfflineOnly()) { throw QInstaller::Error(tr("Installer at \"%1\" needs to be an offline one.") .arg(QDir::toNativeSeparators(binaryPath))); } // if we're running as installer and install into an existing target, remove possible previous repos if (QFile::exists(repoPath)) { Static::fixPermissions(repoPath); QInstaller::removeDirectory(repoPath); } // create the local repository target dir KDUpdater::MkdirOperation mkDirOp; mkDirOp.setArguments(QStringList() << repoPath); mkDirOp.backup(); if (!mkDirOp.performOperation()) { setError(mkDirOp.error()); setErrorString(mkDirOp.errorString()); return false; } setValue(QLatin1String("createddir"), mkDirOp.value(QLatin1String("createddir"))); // Internal changes to QTemporaryFile break copying Qt resources through // QInstaller::RemoteFileEngine. We do not register resources to be handled by // RemoteFileEngine, instead copying using 5.9 succeeded because QFile::copy() // creates a QTemporaryFile object internally that is handled by the remote engine. // // This will not work with Qt 5.10 and above as QTemporaryFile introduced a new // rename() implementation that explicitly uses its own QTemporaryFileEngine. // // During elevated installation, first dump the resources to a writable directory // as a normal user, then do the real copy work. We will drop admin rights temporarily. QString metaSource = QLatin1String(":/metadata/"); QDir metaSourceDir; bool createdMetaDir = false; if (RemoteClient::instance().isActive()) { core->dropAdminRights(); metaSource = generateTemporaryFileName() + QDir::separator(); metaSourceDir.setPath(metaSource); if (!metaSourceDir.mkpath(metaSource)) { setError(UserDefinedError); setErrorString(tr("Cannot create path \"%1\".") .arg(QDir::toNativeSeparators(metaSource))); return false; } createdMetaDir = true; CopyDirectoryOperation copyMetadata(nullptr); copyMetadata.setArguments(QStringList() << QLatin1String(":/metadata/") << metaSource); if (!copyMetadata.performOperation()) { setError(copyMetadata.error()); setErrorString(copyMetadata.errorString()); return false; } core->gainAdminRights(); } // copy the whole meta data into local repository CopyDirectoryOperation copyDirOp(core); copyDirOp.setArguments(QStringList() << metaSource << repoPath); connect(©DirOp, &CopyDirectoryOperation::outputTextChanged, this, &CreateLocalRepositoryOperation::outputTextChanged); const bool success = copyDirOp.performOperation(); helper.m_files = copyDirOp.value(QLatin1String("files")).toStringList(); if (createdMetaDir && !metaSourceDir.removeRecursively()) { setError(UserDefinedError); setErrorString(tr("Cannot remove directory \"%1\".") .arg(QDir::toNativeSeparators(metaSourceDir.absolutePath()))); return false; } if (!success) { setError(copyDirOp.error()); setErrorString(copyDirOp.errorString()); return false; } emit progressChanged(0.25); // we need to fix the folder and file permissions here, as copying from read only resource file // systems sets all permissions to a completely bogus value... Static::fixPermissions(repoPath); // open the updates xml file we previously copied QFile updatesXml(repoPath + QLatin1String("Updates.xml")); if (!updatesXml.exists() || !updatesXml.open(QIODevice::ReadOnly)) throw QInstaller::Error(tr("Cannot open file \"%1\" for reading.").arg( QDir::toNativeSeparators(updatesXml.fileName()))); // read the content of the updates xml QString error; QDomDocument doc; if (!doc.setContent(&updatesXml, &error)) throw QInstaller::Error(tr("Cannot read file \"%1\": %2").arg( QDir::toNativeSeparators(updatesXml.fileName()), error)); // build for each available package a name - version mapping QHash nameVersionHash; const QDomElement root = doc.documentElement(); const QDomNodeList rootChildNodes = root.childNodes(); for (int i = 0; i < rootChildNodes.count(); ++i) { const QDomElement element = rootChildNodes.at(i).toElement(); if (element.isNull()) continue; QString name, version; if (element.tagName() == QLatin1String("PackageUpdate")) { const QDomNodeList elementChildNodes = element.childNodes(); for (int j = 0; j < elementChildNodes.count(); ++j) { const QDomElement e = elementChildNodes.at(j).toElement(); if (e.tagName() == QLatin1String("Name")) name = e.text(); else if (e.tagName() == QLatin1String("Version")) version = e.text(); } if (ProductKeyCheck::instance()->isValidPackage(name)) nameVersionHash.insert(name, version); } } emit progressChanged(0.50); QFile file(binaryPath); if (!file.open(QIODevice::ReadOnly)) { throw QInstaller::Error(tr("Cannot open file \"%1\" for reading: %2").arg( QDir::toNativeSeparators(file.fileName()), file.errorString())); } // start to read the binary layout ResourceCollectionManager manager; BinaryContent::readBinaryContent(&file, nullptr, &manager, 0, BinaryContent::MagicCookie); emit progressChanged(0.65); QDir repo(repoPath); if (!nameVersionHash.isEmpty()) { // extract meta and binary data const QStringList names = nameVersionHash.keys(); for (int i = 0; i < names.count(); ++i) { const QString name = names.at(i); if (!repo.mkpath(name)) { throw QInstaller::Error(tr("Cannot create target directory: \"%1\".") .arg(QDir::toNativeSeparators(repo.filePath(name)))); } // zip the meta files that come with the offline installer helper.m_files.prepend(Static::createArchive(repoPath, repo.filePath(name), nameVersionHash.value(name), &helper)); emit outputTextChanged(helper.m_files.first()); // copy the 7z files that are inside the component index into the target const ResourceCollection collection = manager.collectionByName(name.toUtf8()); foreach (const QSharedPointer &resource, collection.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) continue; QFile target(repo.filePath(name) + QDir::separator() + QString::fromUtf8(resource->name())); QInstaller::openForWrite(&target); resource->copyData(&target); helper.m_files.prepend(target.fileName()); emit outputTextChanged(helper.m_files.first()); if (!isOpen) // If we reach that point, either the resource was opened already. resource->close(); // or we did open it and have to close it again. } emit progressChanged(.65f + ((double(i) / double(names.count())) * .25f)); } } emit progressChanged(0.95); try { // remove these, if we fail it doesn't hurt Static::removeDirectory(QDir::cleanPath(repoPath + QLatin1String("/installer-config")), &helper); Static::removeDirectory(QDir::cleanPath(repoPath + QLatin1String("/config")), &helper); const QStringList files = repo.entryList(QStringList() << QLatin1String("*.qrc"), QDir::Files); foreach (const QString &file, files) { if (repo.remove(file)) helper.m_files.removeAll(QDir::cleanPath(repoPath + file)); } } catch (...) {} setValue(QLatin1String("local-repo"), repoPath); } catch (const Lib7z::SevenZipException &e) { setError(UserDefinedError); setErrorString(e.message()); return false; } catch (const QInstaller::Error &e) { setError(UserDefinedError); setErrorString(e.message()); return false; } catch (...) { setError(UserDefinedError); setErrorString(tr("Unknown exception caught: %1.").arg(QLatin1String(Q_FUNC_INFO))); return false; } return true; } bool CreateLocalRepositoryOperation::undoOperation() { Q_ASSERT(arguments().count() == 2); AutoHelper _(this); emit progressChanged(0.0); QDir dir; const QStringList files = value(QLatin1String("files")).toStringList(); foreach (const QString &file, files) { emit outputTextChanged(tr("Removing file \"%1\".").arg(QDir::toNativeSeparators(file))); if (!QFile::remove(file)) { setError(InvalidArguments); setErrorString(tr("Cannot remove file \"%1\".").arg(QDir::toNativeSeparators(file))); return false; } dir.rmpath(QFileInfo(file).absolutePath()); } setValue(QLatin1String("files"), QStringList()); QDir createdDir = QDir(value(QLatin1String("createddir")).toString()); if (createdDir == QDir::root() || !createdDir.exists()) return true; QInstaller::removeSystemGeneratedFiles(createdDir.path()); errno = 0; const bool result = QDir::root().rmdir(createdDir.path()); if (!result) { #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW) char msg[128]; if (strerror_s(msg, sizeof msg, errno) != 0) { setError(UserDefinedError, tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(createdDir.path()), QString::fromLocal8Bit(msg))); } #else setError(UserDefinedError, tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(createdDir.path()), QString::fromLocal8Bit(strerror(errno)))); #endif } setValue(QLatin1String("files"), QStringList()); return result; } bool CreateLocalRepositoryOperation::testOperation() { return true; } void CreateLocalRepositoryOperation::emitFullProgress() { emit progressChanged(1.0); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/createlocalrepositoryoperation.h0100777000000000000000000000365013761647206025331 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CREATELOCALREPOSITORYOPERATION_H #define CREATELOCALREPOSITORYOPERATION_H #include "qinstallerglobal.h" #include namespace QInstaller { class INSTALLER_EXPORT CreateLocalRepositoryOperation : public QObject, public Operation { Q_OBJECT friend struct AutoHelper; public: explicit CreateLocalRepositoryOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); signals: void progressChanged(double progress); void outputTextChanged(const QString &message); private: void emitFullProgress(); }; } // namespace QInstaller #endif // CREATELOCALREPOSITORYOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/createshortcutoperation.cpp0100777000000000000000000002511313761647206024303 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "createshortcutoperation.h" #include "fileutils.h" #include "utils.h" #include "globals.h" #include #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::CreateShortcutOperation \internal */ #ifdef Q_OS_WIN #include #include #include #ifndef PIDLIST_ABSOLUTE typedef ITEMIDLIST *PIDLIST_ABSOLUTE; #endif struct DeCoInitializer { DeCoInitializer() : neededCoInit(CoInitialize(nullptr) == S_OK) { } ~DeCoInitializer() { if (neededCoInit) CoUninitialize(); } bool neededCoInit; }; #endif struct StartsWith { StartsWith(const QString &searchTerm) : m_searchTerm(searchTerm) {} bool operator()(const QString &searchString) { return searchString.startsWith(m_searchTerm); } QString m_searchTerm; }; static QString parentDirectory(const QString ¤t) { return current.mid(0, current.lastIndexOf(QLatin1Char('/'))); } static QString takeArgument(const QString &argument, QStringList *arguments) { // if the arguments contain an option in the form "argument=...", find it and consume it QStringList::iterator it = std::find_if(arguments->begin(), arguments->end(), StartsWith(argument)); if (it == arguments->end()) return QString(); const QString value = it->mid(argument.size()); arguments->erase(it); return value; } static bool createLink(const QString &fileName, const QString &linkName, QString &workingDir, const QString &arguments = QString(), const QString &iconPath = QString(), const QString &iconId = QString(), const QString &description = QString()) { #ifdef Q_OS_WIN // CoInitialize cleanup object DeCoInitializer _; IUnknown *iunkn = nullptr; if (fileName.toLower().startsWith(QLatin1String("http:")) || fileName.toLower().startsWith(QLatin1String("ftp:"))) { IUniformResourceLocator *iurl = nullptr; if (FAILED(CoCreateInstance(CLSID_InternetShortcut, nullptr, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&iurl))) { return false; } if (FAILED(iurl->SetURL((wchar_t *)fileName.utf16(), IURL_SETURL_FL_GUESS_PROTOCOL))) { iurl->Release(); return false; } iunkn = iurl; } else { bool success = QFile::link(fileName, linkName); if (!success) { return success; } if (workingDir.isEmpty()) workingDir = QFileInfo(fileName).absolutePath(); workingDir = QDir::toNativeSeparators(workingDir); IShellLink *psl = NULL; if (FAILED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl))) { return success; } // TODO: implement this server side, since there's not Qt equivalent to set working dir and arguments psl->SetPath((wchar_t *)QDir::toNativeSeparators(fileName).utf16()); psl->SetWorkingDirectory((wchar_t *)workingDir.utf16()); if (!arguments.isNull()) psl->SetArguments((wchar_t*)arguments.utf16()); if (!iconPath.isNull()) psl->SetIconLocation((wchar_t*)(iconPath.utf16()), iconId.toInt()); if (!description.isNull()) psl->SetDescription((wchar_t*)(description.utf16())); iunkn = psl; } IPersistFile *ppf = NULL; if (SUCCEEDED(iunkn->QueryInterface(IID_IPersistFile, (void **)&ppf))) { ppf->Save((wchar_t*)QDir::toNativeSeparators(linkName).utf16(), true); ppf->Release(); } iunkn->Release(); PIDLIST_ABSOLUTE pidl; // Force start menu cache update if (SUCCEEDED(SHGetFolderLocation(0, CSIDL_STARTMENU, 0, 0, &pidl))) { SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, 0); CoTaskMemFree(pidl); } if (SUCCEEDED(SHGetFolderLocation(0, CSIDL_COMMON_STARTMENU, 0, 0, &pidl))) { SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, 0); CoTaskMemFree(pidl); } return true; #else Q_UNUSED(arguments) Q_UNUSED(workingDir) Q_UNUSED(fileName) Q_UNUSED(linkName) Q_UNUSED(iconPath) Q_UNUSED(iconId) return true; #endif } // -- CreateShortcutOperation CreateShortcutOperation::CreateShortcutOperation(PackageManagerCore *core) : UpdateOperation(core) , m_optionalArgumentsRead(false) { setName(QLatin1String("CreateShortcut")); } void CreateShortcutOperation::backup() { ensureOptionalArgumentsRead(); QDir linkPath(QFileInfo(arguments().at(1)).absolutePath()); QStringList directoriesToCreate; while (!linkPath.exists() && linkPath != QDir::root()) { const QString absolutePath = linkPath.absolutePath(); directoriesToCreate.append(absolutePath); linkPath = parentDirectory(absolutePath); } setValue(QLatin1String("createddirs"), directoriesToCreate); } void CreateShortcutOperation::ensureOptionalArgumentsRead() { if (m_optionalArgumentsRead) return; m_optionalArgumentsRead = true; QStringList args = arguments(); m_iconId = takeArgument(QString::fromLatin1("iconId="), &args); m_iconPath = takeArgument(QString::fromLatin1("iconPath="), &args); m_workingDir = takeArgument(QString::fromLatin1("workingDirectory="), &args); m_description = takeArgument(QString::fromLatin1("description="), &args); setArguments(args); } bool CreateShortcutOperation::performOperation() { ensureOptionalArgumentsRead(); if (!checkArgumentCount(2, 3, tr(" [target arguments] " "[\"workingDirectory=...\"] [\"iconPath=...\"] [\"iconId=...\"] " "[\"description=...\"]"))) { return false; } QStringList args = arguments(); const QString linkTarget = args.at(0); const QString linkLocation = args.at(1); const QString targetArguments = args.value(2); // value() used since it's optional const QString linkPath = QFileInfo(linkLocation).absolutePath().trimmed(); const bool created = QDir(linkPath).exists() || QDir::root().mkpath(linkPath); if (!created) { setError(UserDefinedError); #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW) char msg[128]; if (strerror_s(msg, sizeof msg, errno) != 0) { setErrorString(tr("Cannot create directory \"%1\": %2").arg(QDir::toNativeSeparators(linkPath), QString::fromLocal8Bit(msg))); } #else setErrorString(tr("Cannot create directory \"%1\": %2").arg(QDir::toNativeSeparators(linkPath), QString::fromLocal8Bit(strerror(errno)))); #endif return false; } //remove a possible existing older one QString errorString; if (QFile::exists(linkLocation) && !deleteFileNowOrLater(linkLocation, &errorString)) { setError(UserDefinedError); setErrorString(tr("Failed to overwrite \"%1\": %2").arg(QDir::toNativeSeparators(linkLocation), errorString)); return false; } const bool linked = createLink(linkTarget, linkLocation, m_workingDir, targetArguments, m_iconPath, m_iconId, m_description); if (!linked) { setError(UserDefinedError); setErrorString(tr("Cannot create link \"%1\": %2").arg(QDir::toNativeSeparators(linkLocation), qt_error_string())); return false; } return true; } bool CreateShortcutOperation::undoOperation() { ensureOptionalArgumentsRead(); const QString &linkLocation = arguments().at(1); if (!deleteFileNowOrLater(linkLocation) ) qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot delete:" << linkLocation; QDir dir; // remove all directories we created const QStringList directoriesToDelete = value(QLatin1String("createddirs")).toStringList(); foreach (const QString &directory, directoriesToDelete) { QInstaller::removeSystemGeneratedFiles(directory); if (!dir.rmdir(directory)) break; } #ifdef Q_OS_WIN // special case on windows, multiple installations might leave empty folder inside the start menu QSettings user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\" "Explorer\\User Shell Folders"), QSettings::NativeFormat); QSettings system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\" "Explorer\\Shell Folders"), QSettings::NativeFormat); const QString userStartMenu = QDir::fromNativeSeparators(replaceWindowsEnvironmentVariables(user .value(QLatin1String("Programs"), QString()).toString())).toLower(); const QString systemStartMenu = QDir::fromNativeSeparators(system.value(QLatin1String("Common Programs")) .toString()).toLower(); // try to remove every empty folder until we fail QString linkPath = QFileInfo(linkLocation).absolutePath().toLower(); if (linkPath.startsWith(userStartMenu) || linkPath.startsWith(systemStartMenu)) { QInstaller::removeSystemGeneratedFiles(linkPath); while (QDir().rmdir(linkPath)) { linkPath = parentDirectory(linkPath); QInstaller::removeSystemGeneratedFiles(linkPath); } } #endif return true; } bool CreateShortcutOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/createshortcutoperation.h0100777000000000000000000000355313761647206023754 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef CREATESHORTCUTOPERATION_H #define CREATESHORTCUTOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT CreateShortcutOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::CreateShortcutOperation) public: explicit CreateShortcutOperation(PackageManagerCore *core = nullptr); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); private: void ensureOptionalArgumentsRead(); bool m_optionalArgumentsRead; QString m_iconId; QString m_iconPath; QString m_workingDir; QString m_description; }; } #endif qt-installer-framework-4.0.1/src/libs/installer/downloadarchivesjob.cpp0100777000000000000000000002533313761647206023356 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "downloadarchivesjob.h" #include "binaryformatenginehandler.h" #include "component.h" #include "messageboxhandler.h" #include "packagemanagercore.h" #include "utils.h" #include "filedownloader.h" #include "filedownloaderfactory.h" #include #include using namespace QInstaller; using namespace KDUpdater; /*! Creates a new DownloadArchivesJob with parent \a core. */ DownloadArchivesJob::DownloadArchivesJob(PackageManagerCore *core) : Job(core) , m_core(core) , m_downloader(nullptr) , m_archivesDownloaded(0) , m_archivesToDownloadCount(0) , m_canceled(false) , m_lastFileProgress(0) , m_progressChangedTimerId(0) { setCapabilities(Cancelable); } /*! Destroys the DownloadArchivesJob. */ DownloadArchivesJob::~DownloadArchivesJob() { if (m_downloader) m_downloader->deleteLater(); } /*! Sets the \a archives to download. The first value of each pair contains the file name to register the file in the installer's internal file system, the second one the source url. */ void DownloadArchivesJob::setArchivesToDownload(const QList > &archives) { m_archivesToDownload = archives; m_archivesToDownloadCount = archives.count(); } /*! \reimp */ void DownloadArchivesJob::doStart() { m_archivesDownloaded = 0; fetchNextArchiveHash(); } /*! \reimp */ void DownloadArchivesJob::doCancel() { m_canceled = true; if (m_downloader != nullptr) m_downloader->cancelDownload(); } void DownloadArchivesJob::fetchNextArchiveHash() { if (m_core->testChecksum()) { if (m_canceled) { finishWithError(tr("Canceled")); return; } if (m_archivesToDownload.isEmpty()) { emitFinished(); return; } if (m_downloader) m_downloader->deleteLater(); m_downloader = setupDownloader(QLatin1String(".sha1")); if (!m_downloader) { m_archivesToDownload.removeFirst(); QMetaObject::invokeMethod(this, "fetchNextArchiveHash", Qt::QueuedConnection); return; } connect(m_downloader, &FileDownloader::downloadCompleted, this, &DownloadArchivesJob::finishedHashDownload, Qt::QueuedConnection); m_downloader->download(); } else { QMetaObject::invokeMethod(this, "fetchNextArchive", Qt::QueuedConnection); } } void DownloadArchivesJob::finishedHashDownload() { Q_ASSERT(m_downloader != nullptr); QFile sha1HashFile(m_downloader->downloadedFileName()); if (sha1HashFile.open(QFile::ReadOnly)) { m_currentHash = sha1HashFile.readAll(); fetchNextArchive(); } else { finishWithError(tr("Downloading hash signature failed.")); } } /*! Fetches the next archive and registers it in the installer. */ void DownloadArchivesJob::fetchNextArchive() { if (m_canceled) { finishWithError(tr("Canceled")); return; } if (m_archivesToDownload.isEmpty()) { emitFinished(); return; } if (m_downloader != nullptr) m_downloader->deleteLater(); m_downloader = setupDownloader(QString(), m_core->value(scUrlQueryString)); if (!m_downloader) { m_archivesToDownload.removeFirst(); QMetaObject::invokeMethod(this, "fetchNextArchiveHash", Qt::QueuedConnection); return; } emit progressChanged(double(m_archivesDownloaded) / m_archivesToDownloadCount); connect(m_downloader, SIGNAL(downloadProgress(double)), this, SLOT(emitDownloadProgress(double))); connect(m_downloader, &FileDownloader::downloadCompleted, this, &DownloadArchivesJob::registerFile, Qt::QueuedConnection); m_downloader->download(); } /*! Emits the global download \a progress during a single download in a lazy way (uses a timer to reduce to much processChanged). */ void DownloadArchivesJob::emitDownloadProgress(double progress) { m_lastFileProgress = progress; if (!m_progressChangedTimerId) m_progressChangedTimerId = startTimer(5); } /*! This is used to reduce the \c progressChanged signals for \a event. */ void DownloadArchivesJob::timerEvent(QTimerEvent *event) { if (event->timerId() == m_progressChangedTimerId) { killTimer(m_progressChangedTimerId); m_progressChangedTimerId = 0; emit progressChanged((double(m_archivesDownloaded) + m_lastFileProgress) / m_archivesToDownloadCount); } } /*! Registers the just downloaded file in the installer's file system. */ void DownloadArchivesJob::registerFile() { Q_ASSERT(m_downloader != nullptr); if (m_canceled) return; if (m_core->testChecksum() && m_currentHash != m_downloader->sha1Sum().toHex()) { //TODO: Maybe we should try to download the file again automatically const QMessageBox::Button res = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("DownloadError"), tr("Download Error"), tr("Hash verification while " "downloading failed. This is a temporary error, please retry."), QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel); // If run from command line instance, do not continue if hash verification failed. // Same download is tried again and again causing infinite loop if hash not // fixed to repositories. if (res == QMessageBox::Cancel || m_core->isCommandLineInstance()) { finishWithError(tr("Cannot verify Hash")); return; } } else { ++m_archivesDownloaded; if (m_progressChangedTimerId) { killTimer(m_progressChangedTimerId); m_progressChangedTimerId = 0; emit progressChanged(double(m_archivesDownloaded) / m_archivesToDownloadCount); } const QPair pair = m_archivesToDownload.takeFirst(); BinaryFormatEngineHandler::instance()->registerResource(pair.first, m_downloader->downloadedFileName()); } fetchNextArchiveHash(); } void DownloadArchivesJob::downloadCanceled() { emitFinishedWithError(Job::Canceled, m_downloader->errorString()); } void DownloadArchivesJob::downloadFailed(const QString &error) { if (m_canceled) return; const QMessageBox::StandardButton b = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("archiveDownloadError"), tr("Download Error"), tr("Cannot download archive %1: %2") .arg(m_archivesToDownload.first().second, error), QMessageBox::Retry | QMessageBox::Cancel); // Do not call fetchNextArchiveHash when using command line instance, // installer tries to download the same archive causing infinite loop if (b == QMessageBox::Retry && !m_core->isCommandLineInstance()) QMetaObject::invokeMethod(this, "fetchNextArchiveHash", Qt::QueuedConnection); else downloadCanceled(); } void DownloadArchivesJob::finishWithError(const QString &error) { const FileDownloader *const dl = qobject_cast (sender()); const QString msg = tr("Cannot fetch archives: %1\nError while loading %2"); if (dl != nullptr) emitFinishedWithError(QInstaller::DownloadError, msg.arg(error, dl->url().toString())); else emitFinishedWithError(QInstaller::DownloadError, msg.arg(error, m_downloader->url().toString())); } KDUpdater::FileDownloader *DownloadArchivesJob::setupDownloader(const QString &suffix, const QString &queryString) { KDUpdater::FileDownloader *downloader = nullptr; const QFileInfo fi = QFileInfo(m_archivesToDownload.first().first); const Component *const component = m_core->componentByName(PackageManagerCore::checkableName(QFileInfo(fi.path()).fileName())); if (component) { QString fullQueryString; if (!queryString.isEmpty()) fullQueryString = QLatin1String("?") + queryString; const QUrl url(m_archivesToDownload.first().second + suffix + fullQueryString); const QString &scheme = url.scheme(); downloader = FileDownloaderFactory::instance().create(scheme, this); if (downloader) { downloader->setUrl(url); downloader->setAutoRemoveDownloadedFile(false); QAuthenticator auth; auth.setUser(component->value(QLatin1String("username"))); auth.setPassword(component->value(QLatin1String("password"))); downloader->setAuthenticator(auth); connect(downloader, &FileDownloader::downloadCanceled, this, &DownloadArchivesJob::downloadCanceled); connect(downloader, &FileDownloader::downloadAborted, this, &DownloadArchivesJob::downloadFailed, Qt::QueuedConnection); connect(downloader, &FileDownloader::downloadStatus, this, &DownloadArchivesJob::downloadStatusChanged); if (FileDownloaderFactory::isSupportedScheme(scheme)) { downloader->setDownloadedFileName(component->localTempPath() + QLatin1Char('/') + component->name() + QLatin1Char('/') + fi.fileName() + suffix); } emit outputTextChanged(tr("Downloading archive \"%1\" for component %2.") .arg(fi.fileName() + suffix, component->displayName())); } else { emit outputTextChanged(tr("Scheme %1 not supported (URL: %2).").arg(scheme, url.toString())); } } else { emit outputTextChanged(tr("Cannot find component for %1.").arg(QFileInfo(fi.path()).fileName())); } return downloader; } qt-installer-framework-4.0.1/src/libs/installer/downloadarchivesjob.h0100777000000000000000000000557713761647206023033 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef DOWNLOADARCHIVESJOB_H #define DOWNLOADARCHIVESJOB_H #include "job.h" #include QT_BEGIN_NAMESPACE class QTimerEvent; QT_END_NAMESPACE namespace KDUpdater { class FileDownloader; } namespace QInstaller { class MessageBoxHandler; class PackageManagerCore; class DownloadArchivesJob : public Job { Q_OBJECT public: explicit DownloadArchivesJob(PackageManagerCore *core); ~DownloadArchivesJob(); int numberOfDownloads() const { return m_archivesDownloaded; } void setArchivesToDownload(const QList > &archives); Q_SIGNALS: void progressChanged(double progress); void outputTextChanged(const QString &progress); void downloadStatusChanged(const QString &status); protected: void doStart(); void doCancel(); void timerEvent(QTimerEvent *event); protected Q_SLOTS: void registerFile(); void downloadCanceled(); void downloadFailed(const QString &error); void finishWithError(const QString &error); void fetchNextArchive(); void fetchNextArchiveHash(); void finishedHashDownload(); void emitDownloadProgress(double progress); private: KDUpdater::FileDownloader *setupDownloader(const QString &suffix = QString(), const QString &queryString = QString()); private: PackageManagerCore *m_core; KDUpdater::FileDownloader *m_downloader; int m_archivesDownloaded; int m_archivesToDownloadCount; QList > m_archivesToDownload; bool m_canceled; QByteArray m_currentHash; double m_lastFileProgress; int m_progressChangedTimerId; }; } // namespace QInstaller #endif // DOWNLOADARCHIVESJOB_H qt-installer-framework-4.0.1/src/libs/installer/downloadfiletask.cpp0100777000000000000000000004031313761647206022654 0ustar00 /************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "downloadfiletask.h" #include "downloadfiletask_p.h" #include "globals.h" #include #include #include #include #include #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::DownloadFileTask \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::Downloader \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::AuthenticationRequiredException \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::Data \internal */ AuthenticationRequiredException::AuthenticationRequiredException(Type type, const QString &message) : TaskException(message) , m_type(type) { } Downloader::Downloader() : m_finished(0) { connect(&m_timer, &QTimer::timeout, this, &Downloader::onTimeout); connect(&m_nam, &QNetworkAccessManager::finished, this, &Downloader::onFinished); } Downloader::~Downloader() { m_nam.disconnect(); for (const auto &pair : m_downloads) { pair.first->disconnect(); pair.first->abort(); pair.first->deleteLater(); } } void Downloader::download(QFutureInterface &fi, const QList &items, QNetworkProxyFactory *networkProxyFactory) { m_items = items; m_futureInterface = &fi; fi.reportStarted(); fi.setExpectedResultCount(items.count()); m_nam.setProxyFactory(networkProxyFactory); connect(&m_nam, &QNetworkAccessManager::authenticationRequired, this, &Downloader::onAuthenticationRequired); connect(&m_nam, &QNetworkAccessManager::proxyAuthenticationRequired, this, &Downloader::onProxyAuthenticationRequired); QTimer::singleShot(0, this, &Downloader::doDownload); } void Downloader::doDownload() { m_timer.start(1000); // Use a timer to check for canceled downloads. foreach (const FileTaskItem &item, m_items) { if (!startDownload(item)) break; } if (m_items.isEmpty() || m_futureInterface->isCanceled()) { m_futureInterface->reportFinished(); emit finished(); // emit finished, so the event loop can shutdown } } // -- private slots void Downloader::onReadyRead() { if (testCanceled()) { m_futureInterface->reportFinished(); emit finished(); return; // error } QNetworkReply *const reply = qobject_cast(sender()); if (!reply) return; Data &data = *m_downloads[reply]; if (!data.file) { std::unique_ptr file = Q_NULLPTR; const QString target = data.taskItem.target(); if (target.isEmpty()) { std::unique_ptr tmp(new QTemporaryFile); tmp->setAutoRemove(false); file = std::move(tmp); } else { std::unique_ptr tmp(new QFile(target)); file = std::move(tmp); } if (file->exists() && (!QFileInfo(file->fileName()).isFile())) { m_futureInterface->reportException(TaskException(tr("Target file \"%1\" already exists " "but is not a file.").arg(file->fileName()))); return; } if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { //: %2 is a sentence describing the error m_futureInterface->reportException( TaskException(tr("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(file->fileName()), file->errorString()))); return; } data.file = std::move(file); } if (!data.file->isOpen()) { //: %2 is a sentence describing the error. m_futureInterface->reportException( TaskException(tr("File \"%1\" not open for writing: %2").arg( QDir::toNativeSeparators(data.file->fileName()), data.file->errorString()))); return; } QByteArray buffer(32768, Qt::Uninitialized); while (reply->bytesAvailable()) { if (testCanceled()) { m_futureInterface->reportFinished(); emit finished(); return; // error } const qint64 read = reply->read(buffer.data(), buffer.size()); qint64 written = 0; while (written < read) { const qint64 toWrite = data.file->write(buffer.constData() + written, read - written); if (toWrite < 0) { //: %2 is a sentence describing the error. m_futureInterface->reportException( TaskException(tr("Writing to file \"%1\" failed: %2").arg( QDir::toNativeSeparators(data.file->fileName()), data.file->errorString()))); return; } written += toWrite; } data.observer->addSample(read); data.observer->addBytesTransfered(read); data.observer->addCheckSumData(buffer.data(), read); int progress = m_finished * 100; for (const auto &pair : m_downloads) progress += pair.second->observer->progressValue(); if (!reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) { m_futureInterface->setProgressValueAndText(progress / m_items.count(), data.observer->progressText()); } } } void Downloader::onFinished(QNetworkReply *reply) { Data &data = *m_downloads[reply]; const QString filename = data.file ? data.file->fileName() : QString(); if (!m_futureInterface->isCanceled()) { if (reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) { const QUrl url = reply->url() .resolved(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()); const QList redirects = m_redirects.values(reply); if (!redirects.contains(url)) { if (data.file) data.file->remove(); FileTaskItem taskItem = data.taskItem; taskItem.insert(TaskRole::SourceFile, url.toString()); QNetworkReply *const redirectReply = startDownload(taskItem); foreach (const QUrl &redirect, redirects) m_redirects.insertMulti(redirectReply, redirect); m_redirects.insertMulti(redirectReply, url); m_downloads.erase(reply); m_redirects.remove(reply); reply->deleteLater(); return; } else { m_futureInterface->reportException(TaskException(tr("Redirect loop detected for \"%1\".") .arg(url.toString()))); return; } } } const QByteArray ba = reply->readAll(); if (!ba.isEmpty()) { data.observer->addSample(ba.size()); data.observer->addBytesTransfered(ba.size()); data.observer->addCheckSumData(ba.data(), ba.size()); } const QByteArray expectedCheckSum = data.taskItem.value(TaskRole::Checksum).toByteArray(); bool checksumMismatch = false; if (!expectedCheckSum.isEmpty()) { if (expectedCheckSum != data.observer->checkSum().toHex()) checksumMismatch = true; } m_futureInterface->reportResult(FileTaskResult(filename, data.observer->checkSum(), data.taskItem, checksumMismatch)); m_downloads.erase(reply); m_redirects.remove(reply); reply->deleteLater(); m_finished++; if (m_downloads.empty() || m_futureInterface->isCanceled()) { m_futureInterface->reportFinished(); emit finished(); // emit finished, so the event loop can shutdown } } void Downloader::onError(QNetworkReply::NetworkError error) { QNetworkReply *const reply = qobject_cast(sender()); if (error == QNetworkReply::ProxyAuthenticationRequiredError) return; // already handled by onProxyAuthenticationRequired if (error == QNetworkReply::AuthenticationRequiredError) return; // already handled by onAuthenticationRequired if (reply) { const Data &data = *m_downloads[reply]; //Do not throw error if Updates.xml not found. The repository might be removed //with RepositoryUpdate in Updates.xml later. //: %2 is a sentence describing the error if (data.taskItem.source().contains(QLatin1String("Updates.xml"), Qt::CaseInsensitive)) { qCWarning(QInstaller::lcServer) << QString::fromLatin1("Network error while downloading '%1': %2.").arg( data.taskItem.source(), reply->errorString()); } else { m_futureInterface->reportException( TaskException(tr("Network error while downloading '%1': %2.").arg( data.taskItem.source(), reply->errorString()))); } } else { //: %1 is a sentence describing the error m_futureInterface->reportException( TaskException(tr("Unknown network error while downloading \"%1\".").arg(error))); } } void Downloader::onSslErrors(const QList &sslErrors) { #ifdef QT_NO_SSL Q_UNUSED(sslErrors); #else foreach (const QSslError &error, sslErrors) qCWarning(QInstaller::lcServer) << "SSL error:" << error.errorString(); #endif } void Downloader::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { Q_UNUSED(bytesReceived) QNetworkReply *const reply = qobject_cast(sender()); if (reply) { const Data &data = *m_downloads[reply]; data.observer->setBytesToTransfer(bytesTotal); } } void Downloader::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { if (!authenticator || !reply || m_downloads.find(reply) == m_downloads.cend()) return; FileTaskItem *item = &m_downloads[reply]->taskItem; const QAuthenticator auth = item->value(TaskRole::Authenticator).value(); if (auth.user().isEmpty()) { AuthenticationRequiredException e(AuthenticationRequiredException::Type::Server, QCoreApplication::translate("AuthenticationRequiredException", "%1 at %2") .arg(authenticator->realm(), reply->url().host())); item->insert(TaskRole::Authenticator, QVariant::fromValue(QAuthenticator(*authenticator))); e.setFileTaskItem(*item); m_futureInterface->reportException(e); } else { authenticator->setUser(auth.user()); authenticator->setPassword(auth.password()); item->insert(TaskRole::Authenticator, QVariant()); // clear so we fail on next call } } void Downloader::onProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *) { // Report to GUI thread. // (MetadataJob will ask for username/password, and restart the download ...) AuthenticationRequiredException e(AuthenticationRequiredException::Type::Proxy, QCoreApplication::translate("AuthenticationRequiredException", "Proxy requires authentication.")); e.setProxy(proxy); m_futureInterface->reportException(e); } /*! \internal Canceling from the outside will not get noticed if we are waiting on a connection that does not create any events. QNam will drop after 45 seconds, though the user might have canceled the download before. In that case we block until the QNam timeout is reached, worst case resulting in deadlock while the application is shutting down at the same time. */ void Downloader::onTimeout() { if (testCanceled()) { // Inject exception, we can't use QFuturInterface::reportException() as the exception // store is "frozen" once cancel was called. On the other hand, client code could use // QFutureWatcherBase::isCanceled() or QFuture::isCanceled() to check for canceled futures. m_futureInterface->exceptionStore() .setException(TaskException(tr("Network transfers canceled."))); m_futureInterface->reportFinished(); emit finished(); } } // -- private bool Downloader::testCanceled() { // TODO: figure out how to implement pause and resume if (m_futureInterface->isPaused()) { m_futureInterface->togglePaused(); // Note: this will trigger cancel m_futureInterface->reportException( TaskException(tr("Pause and resume not supported by network transfers."))); } return m_futureInterface->isCanceled(); } QNetworkReply *Downloader::startDownload(const FileTaskItem &item) { QUrl const source = item.source(); if (!source.isValid()) { //: %2 is a sentence describing the error m_futureInterface->reportException(TaskException(tr("Invalid source URL \"%1\": %2") .arg(source.toString(), source.errorString()))); return 0; } QNetworkReply *reply = m_nam.get(QNetworkRequest(source)); std::unique_ptr data(new Data(item)); m_downloads[reply] = std::move(data); connect(reply, &QIODevice::readyRead, this, &Downloader::onReadyRead); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError))); #ifndef QT_NO_SSL connect(reply, &QNetworkReply::sslErrors, this, &Downloader::onSslErrors); #endif connect(reply, &QNetworkReply::downloadProgress, this, &Downloader::onDownloadProgress); return reply; } // -- DownloadFileTask DownloadFileTask::DownloadFileTask(const QList &items) : AbstractFileTask() { setTaskItems(items); } void DownloadFileTask::setTaskItem(const FileTaskItem &item) { AbstractFileTask::setTaskItem(item); } void DownloadFileTask::addTaskItem(const FileTaskItem &item) { AbstractFileTask::addTaskItem(item); } void DownloadFileTask::setTaskItems(const QList &items) { AbstractFileTask::setTaskItems(items); } void DownloadFileTask::addTaskItems(const QList &items) { AbstractFileTask::addTaskItems(items); } void DownloadFileTask::setAuthenticator(const QAuthenticator &authenticator) { m_authenticator = authenticator; } void DownloadFileTask::setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory) { m_proxyFactory.reset(factory); } void DownloadFileTask::doTask(QFutureInterface &fi) { QEventLoop el; Downloader downloader; connect(&downloader, &Downloader::finished, &el, &QEventLoop::quit); QList items = taskItems(); if (!m_authenticator.isNull()) { for (int i = 0; i < items.count(); ++i) { if (items.at(i).value(TaskRole::Authenticator).isNull()) items[i].insert(TaskRole::Authenticator, QVariant::fromValue(m_authenticator)); } } downloader.download(fi, items, (m_proxyFactory.isNull() ? 0 : m_proxyFactory->clone())); el.exec(); // That's tricky here, we need to run our own event loop to keep QNAM working. } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/downloadfiletask.h0100777000000000000000000000664713761647206022335 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef DOWNLOADFILETASK_H #define DOWNLOADFILETASK_H #include "abstractfiletask.h" #include "filedownloaderfactory.h" #include Q_DECLARE_METATYPE(QAuthenticator) namespace QInstaller { namespace TaskRole { enum { Authenticator = TaskRole::TargetFile + 10 }; } class AuthenticationRequiredException : public TaskException { public: enum struct Type { Proxy, Server }; explicit AuthenticationRequiredException(Type type, const QString &message); ~AuthenticationRequiredException() throw() {} Type type() const { return m_type; } QNetworkProxy proxy() const { return m_proxy; } void setProxy(const QNetworkProxy &proxy) { m_proxy = proxy; } FileTaskItem taskItem() const { return m_fileTaskItem; } void setFileTaskItem(const FileTaskItem &item) { m_fileTaskItem = item; } void raise() const { throw *this; } AuthenticationRequiredException *clone() const { return new AuthenticationRequiredException(*this); } private: Type m_type; QNetworkProxy m_proxy; FileTaskItem m_fileTaskItem; }; class INSTALLER_EXPORT DownloadFileTask : public AbstractFileTask { Q_OBJECT Q_DISABLE_COPY(DownloadFileTask) public: DownloadFileTask() {} explicit DownloadFileTask(const FileTaskItem &item) : AbstractFileTask(item) {} explicit DownloadFileTask(const QList &items); explicit DownloadFileTask(const QString &source) : AbstractFileTask(source) {} DownloadFileTask(const QString &source, const QString &target) : AbstractFileTask(source, target) {} void addTaskItem(const FileTaskItem &items); void addTaskItems(const QList &items); void setTaskItem(const FileTaskItem &items); void setTaskItems(const QList &items); void setAuthenticator(const QAuthenticator &authenticator); void setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory); void doTask(QFutureInterface &fi); private: friend class Downloader; QAuthenticator m_authenticator; QScopedPointer m_proxyFactory; }; } // namespace QInstaller #endif // DOWNLOADFILETASK_H qt-installer-framework-4.0.1/src/libs/installer/downloadfiletask_p.h0100777000000000000000000000627013761647206022644 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef DOWNLOADFILETASK_P_H #define DOWNLOADFILETASK_P_H #include "downloadfiletask.h" #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QSslError; QT_END_NAMESPACE namespace QInstaller { struct Data { Q_DISABLE_COPY(Data) Data() : file(Q_NULLPTR) , observer(Q_NULLPTR) {} Data(const FileTaskItem &fti) : taskItem(fti) , file(Q_NULLPTR) , observer(new FileTaskObserver(QCryptographicHash::Sha1)) {} FileTaskItem taskItem; std::unique_ptr file; std::unique_ptr observer; }; class Downloader : public QObject { Q_OBJECT Q_DISABLE_COPY(Downloader) public: Downloader(); ~Downloader(); void download(QFutureInterface &fi, const QList &items, QNetworkProxyFactory *networkProxyFactory); signals: void finished(); private slots: void doDownload(); void onReadyRead(); void onFinished(QNetworkReply *reply); void onError(QNetworkReply::NetworkError error); void onSslErrors(const QList &sslErrors); void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator); void onProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); void onTimeout(); private: bool testCanceled(); QNetworkReply *startDownload(const FileTaskItem &item); private: QFutureInterface *m_futureInterface; QTimer m_timer; int m_finished; QNetworkAccessManager m_nam; QList m_items; QMultiHash m_redirects; std::unordered_map> m_downloads; }; } // namespace QInstaller #endif // DOWNLOADFILETASK_P_H qt-installer-framework-4.0.1/src/libs/installer/elevatedexecuteoperation.cpp0100777000000000000000000002315413761647206024423 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "elevatedexecuteoperation.h" #include "environment.h" #include "qprocesswrapper.h" #include "globals.h" #include #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::ElevatedExecuteOperation \internal */ class ElevatedExecuteOperation::Private { public: explicit Private(ElevatedExecuteOperation *qq) : q(qq) , process(nullptr) , showStandardError(false) { } private: ElevatedExecuteOperation *const q; public: void readProcessOutput(); bool run(const QStringList &arguments); QProcessWrapper *process; bool showStandardError; }; ElevatedExecuteOperation::ElevatedExecuteOperation(PackageManagerCore *core) : UpdateOperation(core) , d(new Private(this)) { // this operation has to "overwrite" the Execute operation from KDUpdater setName(QLatin1String("Execute")); } ElevatedExecuteOperation::~ElevatedExecuteOperation() { delete d; } bool ElevatedExecuteOperation::performOperation() { // This operation receives only one argument. It is the complete // command line of the external program to execute. if (!checkArgumentCount(1, INT_MAX)) return false; QStringList args; foreach (const QString &argument, arguments()) { if (argument!=QLatin1String("UNDOEXECUTE")) args.append(argument); else break; //we don't need the UNDOEXECUTE args here } return d->run(args); } bool ElevatedExecuteOperation::Private::run(const QStringList &arguments) { QStringList args = arguments; QString workingDirectory; QStringList filteredWorkingDirectoryArgs = args.filter(QLatin1String("workingdirectory="), Qt::CaseInsensitive); if (!filteredWorkingDirectoryArgs.isEmpty()) { QString workingDirectoryArgument = filteredWorkingDirectoryArgs.at(0); workingDirectory = workingDirectoryArgument; workingDirectory.replace(QLatin1String("workingdirectory="), QString(), Qt::CaseInsensitive); args.removeAll(workingDirectoryArgument); } QString customErrorMessage; QStringList filteredCustomErrorMessage = args.filter(QLatin1String("errormessage="), Qt::CaseInsensitive); if (!filteredCustomErrorMessage.isEmpty()) { QString customErrorMessageArgument = filteredCustomErrorMessage.at(0); customErrorMessage = customErrorMessageArgument; customErrorMessage.replace(QLatin1String("errormessage="), QString(), Qt::CaseInsensitive); args.removeAll(customErrorMessageArgument); } if (args.last().endsWith(QLatin1String("showStandardError"))) { showStandardError = true; args.pop_back(); } QList< int > allowedExitCodes; QRegExp re(QLatin1String("^\\{((-?\\d+,)*-?\\d+)\\}$")); if (re.exactMatch(args.first())) { const QStringList numbers = re.cap(1).split(QLatin1Char(',')); for(QStringList::const_iterator it = numbers.constBegin(); it != numbers.constEnd(); ++it) allowedExitCodes.push_back(it->toInt()); args.pop_front(); } else { allowedExitCodes.push_back(0); } const QString callstr = args.join(QLatin1String(" ")); // unix style: when there's an ampersand after the command, it's started detached if (args.count() >= 2 && args.last() == QLatin1String("&")) { args.pop_back(); const bool success = QProcessWrapper::startDetached(args.front(), args.mid(1)); if (!success) { q->setError(UserDefinedError); q->setErrorString(tr("Cannot start detached: \"%1\"").arg(callstr)); } return success; } process = new QProcessWrapper(); if (!workingDirectory.isEmpty()) { process->setWorkingDirectory(workingDirectory); qCDebug(QInstaller::lcInstallerInstallLog) << "ElevatedExecuteOperation setWorkingDirectory:" << workingDirectory; } QProcessEnvironment penv; // there is no way to serialize a QProcessEnvironment properly other than per mangled QStringList: // (i.e. no other way to list all keys) process->setEnvironment(KDUpdater::Environment::instance().applyTo(penv).toStringList()); if (showStandardError) process->setProcessChannelMode(QProcessWrapper::MergedChannels); connect(q, &ElevatedExecuteOperation::cancelProcess, process, &QProcessWrapper::cancel); //we still like the none blocking possibility to perform this operation without threads QEventLoop loop; if (QThread::currentThread() == qApp->thread()) { QObject::connect(process, &QProcessWrapper::finished, &loop, &QEventLoop::quit); } //readProcessOutput should only called from this current Thread -> Qt::DirectConnection QObject::connect(process, SIGNAL(readyRead()), q, SLOT(readProcessOutput()), Qt::DirectConnection); process->start(args.front(), args.mid(1)); qCDebug(QInstaller::lcInstallerInstallLog) << args.front() << "started, arguments:" << QStringList(args.mid(1)).join(QLatin1String(" ")); bool success = false; //we still like the none blocking possibility to perform this operation without threads if (QThread::currentThread() == qApp->thread()) { success = process->waitForStarted(); } else { success = process->waitForFinished(-1); } bool returnValue = true; if (!success) { q->setError(UserDefinedError); //TODO: pass errorString() through the wrapper */ q->setErrorString(tr("Cannot start: \"%1\": %2").arg(callstr, process->errorString())); returnValue = false; } if (QThread::currentThread() == qApp->thread()) { if (process->state() != QProcessWrapper::NotRunning) { loop.exec(); } readProcessOutput(); } q->setValue(QLatin1String("ExitCode"), process->exitCode()); if (process->exitStatus() == QProcessWrapper::CrashExit) { q->setError(UserDefinedError); q->setErrorString(tr("Program crashed: \"%1\"").arg(callstr)); returnValue = false; } if (!allowedExitCodes.contains(process->exitCode())) { q->setError(UserDefinedError); if (customErrorMessage.isEmpty()) { q->setErrorString(tr("Execution failed (Unexpected exit code: %1): \"%2\"") .arg(QString::number(process->exitCode()), callstr)); } else { q->setErrorString(customErrorMessage); } QByteArray standardErrorOutput = process->readAllStandardError(); // in error case it would be useful to see something in verbose output if (!standardErrorOutput.isEmpty()) qCWarning(QInstaller::lcInstallerInstallLog).noquote() << standardErrorOutput; returnValue = false; } Q_ASSERT(process); Q_ASSERT(process->state() == QProcessWrapper::NotRunning); delete process; process = nullptr; return returnValue; } /*! Cancels the ElevatedExecuteOperation. This methods tries to terminate the process gracefully by calling QProcessWrapper::terminate. After 10 seconds, the process gets killed. */ void ElevatedExecuteOperation::cancelOperation() { emit cancelProcess(); } void ElevatedExecuteOperation::Private::readProcessOutput() { Q_ASSERT(process); Q_ASSERT(QThread::currentThread() == process->thread()); if (QThread::currentThread() != process->thread()) { qCDebug(QInstaller::lcInstallerInstallLog) << Q_FUNC_INFO << "can only be called from the " "same thread as the process is."; } const QByteArray output = process->readAll(); if (!output.isEmpty()) { if (q->error() == UserDefinedError) qCWarning(QInstaller::lcInstallerInstallLog)<< output; else qCDebug(QInstaller::lcInstallerInstallLog) << output; emit q->outputTextChanged(QString::fromLocal8Bit(output)); } } bool ElevatedExecuteOperation::undoOperation() { QStringList args; bool found = false; foreach (const QString &argument, arguments()) { if (found) args.append(argument); else found = argument == QLatin1String("UNDOEXECUTE"); } if (args.isEmpty()) return true; return d->run(args); } bool ElevatedExecuteOperation::testOperation() { // TODO return true; } void ElevatedExecuteOperation::backup() { } #include "moc_elevatedexecuteoperation.cpp" qt-installer-framework-4.0.1/src/libs/installer/elevatedexecuteoperation.h0100777000000000000000000000373313761647206024071 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ELEVATEDEXECUTEOPERATION_H #define ELEVATEDEXECUTEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT ElevatedExecuteOperation : public QObject, public Operation { Q_OBJECT public: explicit ElevatedExecuteOperation(PackageManagerCore *core); ~ElevatedExecuteOperation(); void backup() Q_DECL_OVERRIDE; bool performOperation() Q_DECL_OVERRIDE; bool undoOperation() Q_DECL_OVERRIDE; bool testOperation() Q_DECL_OVERRIDE; Q_SIGNALS: void cancelProcess(); void outputTextChanged(const QString &text); public Q_SLOTS: void cancelOperation(); private: Q_PRIVATE_SLOT(d, void readProcessOutput()) class Private; Private *d; }; } // namespace #endif qt-installer-framework-4.0.1/src/libs/installer/environmentvariablesoperation.cpp0100777000000000000000000002277313761647206025512 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "environmentvariablesoperation.h" #include "qsettingswrapper.h" #include #include "environment.h" #include "globals.h" #ifdef Q_OS_WIN # include #endif using namespace QInstaller; using namespace KDUpdater; /*! \inmodule QtInstallerFramework \class QInstaller::EnvironmentVariableOperation \internal */ EnvironmentVariableOperation::EnvironmentVariableOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("EnvironmentVariable")); } void EnvironmentVariableOperation::backup() { } #ifdef Q_OS_WIN static void broadcastEnvironmentChange() { // Use SendMessageTimeout to Broadcast a message to the whole system to update settings of all // running applications. This is needed to activate the changes done above without logout+login. DWORD_PTR aResult = 0; LRESULT sendresult = SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) L"Environment", SMTO_BLOCK | SMTO_ABORTIFHUNG, 5000, &aResult); if (sendresult == 0 || aResult != 0) qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to broadcast the WM_SETTINGCHANGE message."; } #endif namespace { bool handleRegExpandSz(const QString ®Path, const QString &name, const QString &value, QString *errorString, bool *error) { bool setAsExpandSZ = false; #ifdef Q_OS_WIN // Account for when it is originally REG_EXPAND_SZ as we don't want // to lose this setting (see Path environment variable) const bool isLocalKey = regPath.startsWith(QStringLiteral("HKEY_LOCAL")); HKEY hkey = isLocalKey ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; // Drop the HKEY...\\ part const QString keyPath = regPath.mid(isLocalKey ? 19 : 18, -1); HKEY handle; LONG res = RegOpenKeyEx(hkey, reinterpret_cast(keyPath.utf16()), 0, KEY_READ, &handle); if (res == ERROR_SUCCESS) { DWORD dataType; DWORD dataSize; res = RegQueryValueEx(handle, reinterpret_cast(name.utf16()), nullptr, &dataType, nullptr, &dataSize); setAsExpandSZ = (res == ERROR_SUCCESS) && (dataType == REG_EXPAND_SZ); if (setAsExpandSZ) { RegCloseKey(handle); res = RegOpenKeyEx(hkey, reinterpret_cast(keyPath.utf16()), 0, KEY_SET_VALUE, &handle); if (res == ERROR_SUCCESS) { const QByteArray data(reinterpret_cast(value.utf16()), (value.length() + 1) * 2); res = RegSetValueEx(handle, reinterpret_cast(name.utf16()), 0, REG_EXPAND_SZ, reinterpret_cast(data.constData()), data.size()); RegCloseKey(handle); } if (res != ERROR_SUCCESS) { *errorString = UpdateOperation::tr("Cannot write to registry path %1.").arg(regPath); *error = true; } } } #endif return setAsExpandSZ; } template UpdateOperation::Error writeSetting(const QString ®Path, const QString &name, const QString &value, QString *errorString, QString *oldValue) { oldValue->clear(); SettingsType registry(regPath, QSettingsWrapper::NativeFormat); if (!registry.isWritable()) { *errorString = UpdateOperation::tr("Registry path %1 is not writable.").arg(regPath); return UpdateOperation::UserDefinedError; } // remember old value for undo *oldValue = registry.value(name).toString(); bool error = false; if (handleRegExpandSz(regPath, name, value, errorString, &error)) return error ? UpdateOperation::UserDefinedError : UpdateOperation::NoError; // set the new value registry.setValue(name, value); registry.sync(); if (registry.status() != QSettingsWrapper::NoError) { *errorString = UpdateOperation::tr("Cannot write to registry path %1.").arg(regPath); return UpdateOperation::UserDefinedError; } return UpdateOperation::NoError; } template UpdateOperation::Error undoSetting(const QString ®Path, const QString &name, const QString &value, const QString &oldValue, QString *errorString) { QString actual; { SettingsType registry(regPath, QSettingsWrapper::NativeFormat); actual = registry.value(name).toString(); } if (actual != value) { //For unknown reason paths with @TargetDir@ variable get modified //so that Windows file separators get replaced with unix style separators, //fix separators before matching to actual value in register QString tempValue = value; QString fixedValue = tempValue.replace(QLatin1Char('/'), QLatin1Char('\\')); if (actual != fixedValue) //key changed, don't undo return UpdateOperation::UserDefinedError; } bool error = false; if (handleRegExpandSz(regPath, name, oldValue, errorString, &error)) return error ? UpdateOperation::UserDefinedError : UpdateOperation::NoError; QString dontcare; return writeSetting(regPath, name, oldValue, errorString, &dontcare); } } // namespace bool EnvironmentVariableOperation::performOperation() { if (!checkArgumentCount(2, 4)) return false; const QStringList args = arguments(); const QString name = args.at(0); const QString value = args.at(1); #ifdef Q_OS_WIN const bool isPersistent = arguments().count() > 2 ? arguments().at(2) == QLatin1String("true") : true; const bool isSystemWide = arguments().count() > 3 ? arguments().at(3) == QLatin1String("true") : false; QString oldvalue; if (isPersistent) { const QString regPath = isSystemWide ? QLatin1String("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" "\\Control\\Session Manager\\Environment") : QLatin1String("HKEY_CURRENT_USER\\Environment"); // write the name=value pair to the global environment QString errorString; Error err = NoError; err = writeSetting(regPath, name, value, &errorString, &oldvalue); if (err != NoError) { setError(err); setErrorString(errorString); return false; } broadcastEnvironmentChange(); setValue(QLatin1String("oldvalue"), oldvalue); return true; } Q_ASSERT(!isPersistent); #endif setValue(QLatin1String("oldvalue"), Environment::instance().value(name)); Environment::instance().setTemporaryValue(name, value); return true; } bool EnvironmentVariableOperation::undoOperation() { if (arguments().count() < 2 || arguments().count() > 4) return false; const QString name = arguments().at(0); const QString value = arguments().at(1); const QString oldvalue = this->value(QLatin1String("oldvalue")).toString(); #ifdef Q_OS_WIN const bool isPersistent = arguments().count() >= 3 ? arguments().at(2) == QLatin1String("true") : true; #else const bool isPersistent = false; #endif if (!isPersistent) { const QString actual = Environment::instance().value(name); const bool doUndo = actual == value; if (doUndo) Environment::instance().setTemporaryValue(name, oldvalue); return true; } #ifdef Q_OS_WIN const bool isSystemWide = arguments().count() >= 4 ? arguments().at(3) == QLatin1String("true") : false; const QString regPath = isSystemWide ? QLatin1String("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\" "Control\\Session Manager\\Environment") : QLatin1String("HKEY_CURRENT_USER\\Environment"); QString errorString; const Error err = undoSetting(regPath, name, value, oldvalue, &errorString); if (err != NoError) { setError(err); setErrorString(errorString); return false; } #endif return true; } bool EnvironmentVariableOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/environmentvariablesoperation.h0100777000000000000000000000330413761647206025144 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ENVIRONMENTVARIABLESOPERATION_H #define ENVIRONMENTVARIABLESOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT EnvironmentVariableOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::EnvironmentVariableOperation) public: explicit EnvironmentVariableOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } #endif qt-installer-framework-4.0.1/src/libs/installer/errors.cpp0100777000000000000000000000253013761647206020635 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "errors.h" /*! \inmodule QtInstallerFramework \class QInstaller::Error \internal */ qt-installer-framework-4.0.1/src/libs/installer/errors.h0100777000000000000000000000322713761647206020306 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef ERRORS_H #define ERRORS_H #include #include #include namespace QInstaller { class Error : public std::exception { public: Error() {} explicit Error(const QString &message) : m_message(message) {} virtual ~Error() throw() {} QString message() const { return m_message; } private: QString m_message; }; } #endif // ERRORS_H qt-installer-framework-4.0.1/src/libs/installer/extractarchiveoperation.cpp0100777000000000000000000002207413761647206024263 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "extractarchiveoperation_p.h" #include "constants.h" #include "globals.h" #include #include #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::ExtractArchiveOperation \internal */ /*! \typedef QInstaller::Backup Synonym for QPair. Contains a pair of an original and a generated backup filename for a file. */ /*! \typedef QInstaller::BackupFiles Synonym for QVector. */ /*! \inmodule QtInstallerFramework \class QInstaller::WorkerThread \internal */ ExtractArchiveOperation::ExtractArchiveOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Extract")); } void ExtractArchiveOperation::backup() { // we need to backup on the fly... } bool ExtractArchiveOperation::performOperation() { if (!checkArgumentCount(2)) return false; const QStringList args = arguments(); const QString archivePath = args.at(0); const QString targetDir = args.at(1); Receiver receiver; Callback callback; connect(&callback, &Callback::progressChanged, this, &ExtractArchiveOperation::progressChanged); if (PackageManagerCore *core = packageManager()) { connect(core, &PackageManagerCore::statusChanged, &callback, &Callback::statusChanged); } Runnable *runnable = new Runnable(archivePath, targetDir, &callback); connect(runnable, &Runnable::finished, &receiver, &Receiver::runnableFinished, Qt::QueuedConnection); QFileInfo fileInfo(archivePath); emit outputTextChanged(tr("Extracting \"%1\"").arg(fileInfo.fileName())); QEventLoop loop; connect(&receiver, &Receiver::finished, &loop, &QEventLoop::quit); if (QThreadPool::globalInstance()->tryStart(runnable)) { loop.exec(); } else { // HACK: In case there is no availabe thread we should call it directly. runnable->run(); receiver.runnableFinished(true, QString()); } // Write all file names which belongs to a package to a separate file and only the separate // filename to a .dat file. There can be enormous amount of files in a package, which makes // the dat file very slow to read and write. The .dat file is read into memory in startup, // writing the file names to a separate file we don't need to load all the file names into // memory as we need those only in uninstall. This will save a lot of memory. // Parse a file and directorory structure using archivepath syntax // installer:///.7z Resulting structure is: // -installerResources (dir) // - (dir) // -.txt (file) QStringList files = callback.extractedFiles(); const QString resourcesPath = targetDir + QLatin1Char('/') + QLatin1String("installerResources"); QString fileDirectory = resourcesPath + QLatin1Char('/') + archivePath.section(QLatin1Char('/'), 1, 1, QString::SectionSkipEmpty) + QLatin1Char('/'); QString archiveFileName = archivePath.section(QLatin1Char('/'), 2, 2, QString::SectionSkipEmpty); QFileInfo fileInfo2(archiveFileName); QString suffix = fileInfo2.suffix(); archiveFileName.chop(suffix.length() + 1); // removes suffix (e.g. '.7z') from archive filename QString fileName = archiveFileName + QLatin1String(".txt"); QFileInfo targetDirectoryInfo(fileDirectory); QDir dir(targetDirectoryInfo.absolutePath()); if (!dir.exists()) { dir.mkpath(targetDirectoryInfo.absolutePath()); } setDefaultFilePermissions(resourcesPath, DefaultFilePermissions::Executable); setDefaultFilePermissions(targetDirectoryInfo.absolutePath(), DefaultFilePermissions::Executable); QFile file(targetDirectoryInfo.absolutePath() + QLatin1Char('/') + fileName); if (file.open(QIODevice::WriteOnly)) { setDefaultFilePermissions(file.fileName(), DefaultFilePermissions::NonExecutable); QDataStream out (&file); for (int i = 0; i < files.count(); ++i) { files[i] = replacePath(files.at(i), targetDir, QLatin1String(scRelocatable)); } out << files; setValue(QLatin1String("files"), file.fileName()); file.close(); } else { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open file for writing " << file.fileName() << ":" << file.errorString(); } // TODO: Use backups for rollback, too? Doesn't work for uninstallation though. // delete all backups we can delete right now, remember the rest foreach (const Backup &i, callback.backupFiles()) deleteFileNowOrLater(i.second); if (!receiver.success()) { setError(UserDefinedError); setErrorString(receiver.errorString()); return false; } return true; } bool ExtractArchiveOperation::undoOperation() { Q_ASSERT(arguments().count() == 2); // For backward compatibility, check if "files" can be converted to QStringList. // If yes, files are listed in .dat instead of in a separate file. bool useStringListType(value(QLatin1String("files")).type() == QVariant::StringList); QString targetDir = arguments().at(1); QStringList files; if (useStringListType) { files = value(QLatin1String("files")).toStringList(); } else { if (!readDataFileContents(targetDir, &files)) return false; } startUndoProcess(files); if (!useStringListType) deleteDataFile(m_relocatedDataFileName); return true; } void ExtractArchiveOperation::startUndoProcess(const QStringList &files) { WorkerThread *const thread = new WorkerThread(this, files); connect(thread, &WorkerThread::currentFileChanged, this, &ExtractArchiveOperation::outputTextChanged); connect(thread, &WorkerThread::progressChanged, this, &ExtractArchiveOperation::progressChanged); QEventLoop loop; connect(thread, &QThread::finished, &loop, &QEventLoop::quit, Qt::QueuedConnection); thread->start(); loop.exec(); thread->deleteLater(); } void ExtractArchiveOperation::deleteDataFile(const QString &fileName) { if (fileName.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog) << Q_FUNC_INFO << "data file name cannot be empty."; return; } QFile file(fileName); QFileInfo fileInfo(file); if (file.remove()) { QDir directory(fileInfo.absoluteDir()); if (directory.exists() && directory.isEmpty()) directory.rmdir(directory.path()); } else { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot remove data file" << file.fileName(); } } bool ExtractArchiveOperation::testOperation() { return true; } bool ExtractArchiveOperation::readDataFileContents(QString &targetDir, QStringList *resultList) { const QString filePath = value(QLatin1String("files")).toString(); // Does not change target on non macOS platforms. if (QInstaller::isInBundle(targetDir, &targetDir)) targetDir = QDir::cleanPath(targetDir + QLatin1String("/..")); m_relocatedDataFileName = replacePath(filePath, QLatin1String(scRelocatable), targetDir); QFile file(m_relocatedDataFileName); if (file.open(QIODevice::ReadOnly)) { QDataStream in(&file); in >> *resultList; for (int i = 0; i < resultList->count(); ++i) resultList->replace(i, replacePath(resultList->at(i), QLatin1String(scRelocatable), targetDir)); } else { // We should not be here. Either user has manually deleted the installer related // files or same component is installed several times. qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open file " << file.fileName() << " for reading:" << file.errorString() << ". Component is already uninstalled " << "or file is manually deleted."; } return true; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/extractarchiveoperation.h0100777000000000000000000000412713761647206023727 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef EXTRACTARCHIVEOPERATION_H #define EXTRACTARCHIVEOPERATION_H #include "qinstallerglobal.h" #include namespace QInstaller { class INSTALLER_EXPORT ExtractArchiveOperation : public QObject, public Operation { Q_OBJECT friend class WorkerThread; public: explicit ExtractArchiveOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); bool readDataFileContents(QString &targetDir, QStringList *resultList); Q_SIGNALS: void outputTextChanged(const QString &progress); void progressChanged(double); private: void startUndoProcess(const QStringList &files); void deleteDataFile(const QString &fileName); private: QString m_relocatedDataFileName; private: class Callback; class Runnable; class Receiver; }; } #endif qt-installer-framework-4.0.1/src/libs/installer/extractarchiveoperation_p.h0100777000000000000000000001504313761647206024245 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef EXTRACTARCHIVEOPERATION_P_H #define EXTRACTARCHIVEOPERATION_P_H #include "extractarchiveoperation.h" #include "fileutils.h" #include "lib7z_extract.h" #include "lib7z_facade.h" #include "packagemanagercore.h" #include #include namespace QInstaller { class WorkerThread : public QThread { Q_OBJECT Q_DISABLE_COPY(WorkerThread) public: WorkerThread(ExtractArchiveOperation *op, const QStringList &files) : m_files(files) , m_op(op) { setObjectName(QLatin1String("ExtractArchive")); } void run() { Q_ASSERT(m_op != 0); int removedCounter = 0; foreach (const QString &file, m_files) { removedCounter++; const QFileInfo fi(file); emit currentFileChanged(QDir::toNativeSeparators(file)); emit progressChanged(double(removedCounter) / m_files.count()); if (fi.isFile() || fi.isSymLink()) { m_op->deleteFileNowOrLater(fi.absoluteFilePath()); } else if (fi.isDir()) { removeSystemGeneratedFiles(file); fi.dir().rmdir(file); // directory may not exist } } } signals: void currentFileChanged(const QString &filename); void progressChanged(double); private: QStringList m_files; ExtractArchiveOperation *m_op; }; typedef QPair Backup; typedef QVector BackupFiles; class ExtractArchiveOperation::Callback : public QObject, public Lib7z::ExtractCallback { Q_OBJECT Q_DISABLE_COPY(Callback) public: Callback() = default; BackupFiles backupFiles() const { return m_backupFiles; } QStringList extractedFiles() const { return m_extractedFiles; } public slots: void statusChanged(QInstaller::PackageManagerCore::Status status) { switch(status) { case PackageManagerCore::Canceled: m_state = E_ABORT; break; case PackageManagerCore::Failure: m_state = E_FAIL; break; default: // ignore all other status values break; } } signals: void progressChanged(double progress); private: void setCurrentFile(const QString &filename) Q_DECL_OVERRIDE { m_extractedFiles.prepend(QDir::toNativeSeparators(filename)); } static QString generateBackupName(const QString &fn) { const QString bfn = fn + QLatin1String(".tmpUpdate"); QString res = bfn; int i = 0; while (QFile::exists(res)) res = bfn + QString::fromLatin1(".%1").arg(i++); return res; } bool prepareForFile(const QString &filename) Q_DECL_OVERRIDE { if (!QFile::exists(filename)) return true; const QString backup = generateBackupName(filename); QFile f(filename); const bool renamed = f.rename(backup); if (f.exists() && !renamed) { qCritical("Cannot rename %s to %s: %s", qPrintable(filename), qPrintable(backup), qPrintable(f.errorString())); return false; } m_backupFiles.append(qMakePair(filename, backup)); return true; } HRESULT setCompleted(quint64 completed, quint64 total) Q_DECL_OVERRIDE { emit progressChanged(double(completed) / total); return m_state; } private: HRESULT m_state = S_OK; BackupFiles m_backupFiles; QStringList m_extractedFiles; }; class ExtractArchiveOperation::Runnable : public QObject, public QRunnable { Q_OBJECT Q_DISABLE_COPY(Runnable) public: Runnable(const QString &archivePath, const QString &targetDir, ExtractArchiveOperation::Callback *callback) : m_archivePath(archivePath) , m_targetDir(targetDir) , m_callback(callback) {} void run() { QFile archive(m_archivePath); if (!archive.open(QIODevice::ReadOnly)) { emit finished(false, tr("Cannot open archive \"%1\" for reading: %2").arg(m_archivePath, archive.errorString())); return; } try { Lib7z::extractArchive(&archive, m_targetDir, m_callback); emit finished(true, QString()); } catch (const Lib7z::SevenZipException& e) { emit finished(false, tr("Error while extracting archive \"%1\": %2").arg(m_archivePath, e.message())); } catch (...) { emit finished(false, tr("Unknown exception caught while extracting \"%1\".") .arg(m_archivePath)); } } signals: void finished(bool success, const QString &errorString); private: QString m_archivePath; QString m_targetDir; ExtractArchiveOperation::Callback *m_callback; }; class ExtractArchiveOperation::Receiver : public QObject { Q_OBJECT Q_DISABLE_COPY(Receiver) public: Receiver() = default; bool success() const { return m_success; } QString errorString() const { return m_errorString; } public slots: void runnableFinished(bool ok, const QString &msg) { m_success = ok; m_errorString = msg; emit finished(); } signals: void finished(); private: bool m_success = false; QString m_errorString; }; } #endif // EXTRACTARCHIVEOPERATION_P_H qt-installer-framework-4.0.1/src/libs/installer/fakestopprocessforupdateoperation.cpp0100777000000000000000000000603313761647206026371 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "fakestopprocessforupdateoperation.h" #include "messageboxhandler.h" #include "packagemanagercore.h" using namespace KDUpdater; using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::FakeStopProcessForUpdateOperation \internal */ FakeStopProcessForUpdateOperation::FakeStopProcessForUpdateOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("FakeStopProcessForUpdate")); } void FakeStopProcessForUpdateOperation::backup() { } bool FakeStopProcessForUpdateOperation::performOperation() { return true; } bool FakeStopProcessForUpdateOperation::undoOperation() { setError(KDUpdater::UpdateOperation::NoError); if (!checkArgumentCount(1)) return false; PackageManagerCore *const core = packageManager(); if (!core) { setError(KDUpdater::UpdateOperation::UserDefinedError, tr("Cannot get package manager " "core.")); return false; } QStringList processes = arguments().at(0).split(QLatin1Char(','), QString::SkipEmptyParts); for (int i = processes.count() - 1; i >= 0; --i) { if (!core->isProcessRunning(processes.at(i))) processes.removeAt(i); } if (processes.isEmpty()) return true; if (processes.count() == 1) { setError(UpdateOperation::UserDefinedError, tr("This process should be stopped before " "continuing: %1").arg(processes.first())); } else { const QString sep = QString::fromWCharArray(L"\n \u2022 "); // Unicode bullet setError(UpdateOperation::UserDefinedError, tr("These processes should be stopped before " "continuing: %1").arg(sep + processes.join(sep))); } return false; } bool FakeStopProcessForUpdateOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/fakestopprocessforupdateoperation.h0100777000000000000000000000332613761647206026040 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef FAKESTOPPROCESSFORUPDATEOPERATION_H #define FAKESTOPPROCESSFORUPDATEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT FakeStopProcessForUpdateOperation : public QObject, public Operation { Q_OBJECT public: explicit FakeStopProcessForUpdateOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } #endif // FAKESTOPPROCESSFORUPDATEOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/fileio.cpp0100777000000000000000000001411113761647206020566 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "fileio.h" #include "errors.h" #include "range.h" #include #include #include #include #include /*! \internal */ qint64 QInstaller::retrieveInt64(QFileDevice *in) { qint64 n = 0; QInstaller::blockingRead(in, reinterpret_cast(&n), sizeof(n)); return n; } /*! \internal */ void QInstaller::appendInt64(QFileDevice *out, qint64 n) { QInstaller::blockingWrite(out, reinterpret_cast(&n), sizeof(n)); } /*! \internal */ Range QInstaller::retrieveInt64Range(QFileDevice *in) { const quint64 start = QInstaller::retrieveInt64(in); const quint64 length = QInstaller::retrieveInt64(in); return Range::fromStartAndLength(start, length); } /*! \internal */ void QInstaller::appendInt64Range(QFileDevice *out, const Range &r) { QInstaller::appendInt64(out, r.start()); QInstaller::appendInt64(out, r.length()); } /*! \internal */ QString QInstaller::retrieveString(QFileDevice *in) { return QString::fromUtf8(QInstaller::retrieveByteArray(in)); } /*! \internal */ void QInstaller::appendString(QFileDevice *out, const QString &str) { QInstaller::appendByteArray(out, str.toUtf8()); } /*! \internal */ QByteArray QInstaller::retrieveByteArray(QFileDevice *in) { QByteArray ba(QInstaller::retrieveInt64(in), '\0'); QInstaller::blockingRead(in, ba.data(), ba.size()); return ba; } /*! \internal */ void QInstaller::appendByteArray(QFileDevice *out, const QByteArray &ba) { QInstaller::appendInt64(out, ba.size()); QInstaller::blockingWrite(out, ba.constData(), ba.size()); } /*! \internal */ QByteArray QInstaller::retrieveData(QFileDevice *in, qint64 size) { QByteArray ba(size, '\0'); QInstaller::blockingRead(in, ba.data(), size); return ba; } /*! \internal */ void QInstaller::appendData(QFileDevice *out, QFileDevice *in, qint64 size) { Q_ASSERT(!in->isSequential()); QInstaller::blockingCopy(in, out, size); } /*! \internal */ void QInstaller::openForRead(QFileDevice *dev) { Q_ASSERT(dev); if (!dev->open(QIODevice::ReadOnly)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot open file \"%1\" for reading: %2").arg( QDir::toNativeSeparators(dev->fileName()), dev->errorString())); } } /*! \internal */ void QInstaller::openForWrite(QFileDevice *dev) { Q_ASSERT(dev); if (!dev->open(QIODevice::WriteOnly)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(dev->fileName()), dev->errorString())); } } /*! \internal */ void QInstaller::openForAppend(QFileDevice *dev) { Q_ASSERT(dev); if (!dev->open(QIODevice::WriteOnly | QIODevice::Append)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(dev->fileName()), dev->errorString())); } } /*! \internal */ qint64 QInstaller::blockingRead(QFileDevice *in, char *buffer, qint64 size) { if (in->atEnd()) return 0; qint64 left = size; while (left > 0) { const qint64 n = in->read(buffer, left); if (n < 0) { throw Error(QCoreApplication::translate("QInstaller", "Read failed after %1 bytes: %2").arg(QString::number(size - left), in->errorString())); } left -= n; buffer += n; } return size; } /*! \internal */ qint64 QInstaller::blockingCopy(QFileDevice *in, QFileDevice *out, qint64 size) { static const qint64 blockSize = 4096; QByteArray ba(blockSize, '\0'); qint64 actual = qMin(blockSize, size); while (actual > 0) { try { QInstaller::blockingRead(in, ba.data(), actual); QInstaller::blockingWrite(out, ba.constData(), actual); size -= actual; actual = qMin(blockSize, size); } catch (const Error &error) { throw Error(QCoreApplication::translate("QInstaller", "Copy failed: %1") .arg(error.message())); } } return size; } /*! \internal */ qint64 QInstaller::blockingWrite(QFileDevice *out, const QByteArray &data) { return QInstaller::blockingWrite(out, data.constData(), data.size()); } /*! \internal */ qint64 QInstaller::blockingWrite(QFileDevice *out, const char *data, qint64 size) { qint64 left = size; while (left > 0) { const qint64 n = out->write(data, left); if (n < 0) { throw Error(QCoreApplication::translate("QInstaller", "Write failed after %1 bytes: %2").arg(QString::number(size - left), out->errorString())); } left -= n; } return size; } qt-installer-framework-4.0.1/src/libs/installer/fileio.h0100777000000000000000000000525013761647206020237 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef FILEIO_H #define FILEIO_H #include "installer_global.h" QT_BEGIN_NAMESPACE class QByteArray; class QFileDevice; class QString; QT_END_NAMESPACE template class Range; namespace QInstaller { qint64 INSTALLER_EXPORT retrieveInt64(QFileDevice *in); void INSTALLER_EXPORT appendInt64(QFileDevice *out, qint64 n); Range INSTALLER_EXPORT retrieveInt64Range(QFileDevice *in); void INSTALLER_EXPORT appendInt64Range(QFileDevice *out, const Range &r); QString INSTALLER_EXPORT retrieveString(QFileDevice *in); void INSTALLER_EXPORT appendString(QFileDevice *out, const QString &str); QByteArray INSTALLER_EXPORT retrieveByteArray(QFileDevice *in); void INSTALLER_EXPORT appendByteArray(QFileDevice *out, const QByteArray &ba); QByteArray INSTALLER_EXPORT retrieveData(QFileDevice *in, qint64 size); void INSTALLER_EXPORT appendData(QFileDevice *out, QFileDevice *in, qint64 size); void INSTALLER_EXPORT openForRead(QFileDevice *dev); void INSTALLER_EXPORT openForWrite(QFileDevice *dev); void INSTALLER_EXPORT openForAppend(QFileDevice *dev); qint64 INSTALLER_EXPORT blockingRead(QFileDevice *in, char *buffer, qint64 size); qint64 INSTALLER_EXPORT blockingCopy(QFileDevice *in, QFileDevice *out, qint64 size); qint64 INSTALLER_EXPORT blockingWrite(QFileDevice *out, const QByteArray &data); qint64 INSTALLER_EXPORT blockingWrite(QFileDevice *out, const char *data, qint64 size); } // namespace QInstaller #endif // FILEIO_H qt-installer-framework-4.0.1/src/libs/installer/fileutils.cpp0100777000000000000000000005453013761647206021330 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "fileutils.h" #include "globals.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #include #include #endif using namespace QInstaller; /*! \enum QInstaller::DefaultFilePermissions \value NonExecutable Default permissions for a non-executable file. \value Executable Default permissions for an executable file. */ /*! \inmodule QtInstallerFramework \class QInstaller::TempDirDeleter \internal */ // -- TempDirDeleter TempDirDeleter::TempDirDeleter(const QString &path) { m_paths.insert(path); } TempDirDeleter::TempDirDeleter(const QStringList &paths) : m_paths(paths.toSet()) { } TempDirDeleter::~TempDirDeleter() { releaseAndDeleteAll(); } QStringList TempDirDeleter::paths() const { return m_paths.toList(); } void TempDirDeleter::add(const QString &path) { m_paths.insert(path); } void TempDirDeleter::add(const QStringList &paths) { m_paths += paths.toSet(); } void TempDirDeleter::releaseAll() { m_paths.clear(); } void TempDirDeleter::release(const QString &path) { m_paths.remove(path); } void TempDirDeleter::passAndReleaseAll(TempDirDeleter &tdd) { tdd.m_paths = m_paths; releaseAll(); } void TempDirDeleter::passAndRelease(TempDirDeleter &tdd, const QString &path) { tdd.add(path); release(path); } void TempDirDeleter::releaseAndDeleteAll() { foreach (const QString &path, m_paths) releaseAndDelete(path); } void TempDirDeleter::releaseAndDelete(const QString &path) { if (m_paths.contains(path)) { try { m_paths.remove(path); removeDirectory(path); } catch (const Error &e) { qCritical() << Q_FUNC_INFO << "Exception caught:" << e.message(); } catch (...) { qCritical() << Q_FUNC_INFO << "Unknown exception caught."; } } } /*! Returns the given \a size in a measuring unit suffixed human readable format, with \a precision marking the number of shown decimals. */ QString QInstaller::humanReadableSize(const qint64 &size, int precision) { double sizeAsDouble = size; static QStringList measures; if (measures.isEmpty()) measures << QCoreApplication::translate("QInstaller", "bytes") << QCoreApplication::translate("QInstaller", "KB") << QCoreApplication::translate("QInstaller", "MB") << QCoreApplication::translate("QInstaller", "GB") << QCoreApplication::translate("QInstaller", "TB") << QCoreApplication::translate("QInstaller", "PB") << QCoreApplication::translate("QInstaller", "EB") << QCoreApplication::translate("QInstaller", "ZB") << QCoreApplication::translate("QInstaller", "YB"); QStringListIterator it(measures); QString measure(it.next()); while (sizeAsDouble >= 1024.0 && it.hasNext()) { measure = it.next(); sizeAsDouble /= 1024.0; } return QString::fromLatin1("%1 %2").arg(sizeAsDouble, 0, 'f', precision).arg(measure); } // -- read, write operations /*! \internal */ bool QInstaller::isLocalUrl(const QUrl &url) { return url.scheme().isEmpty() || url.scheme().toLower() == QLatin1String("file"); } /*! \internal */ QString QInstaller::pathFromUrl(const QUrl &url) { if (isLocalUrl(url)) return url.toLocalFile(); const QString str = url.toString(); if (url.scheme() == QLatin1String("resource")) return str.mid(QString::fromLatin1("resource").length()); return str; } /*! \internal */ void QInstaller::removeFiles(const QString &path, bool ignoreErrors) { const QFileInfoList entries = QDir(path).entryInfoList(QDir::AllEntries | QDir::Hidden); foreach (const QFileInfo &fi, entries) { if (fi.isSymLink() || fi.isFile()) { QString filePath = fi.filePath(); QFile f(filePath); bool ok = f.remove(); if (!ok) { //ReadOnly can prevent removing in Windows. Change permission and try again. const QFile::Permissions permissions = f.permissions(); if (!(permissions & QFile::WriteUser)) { ok = f.setPermissions(filePath, permissions | QFile::WriteUser) && f.remove(filePath); } if (!ok) { const QString errorMessage = QCoreApplication::translate("QInstaller", "Cannot remove file \"%1\": %2").arg( QDir::toNativeSeparators(f.fileName()), f.errorString()); if (!ignoreErrors) throw Error(errorMessage); qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; } } } } } static QString errnoToQString(int error) { #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW) char msg[128]; if (strerror_s(msg, sizeof msg, error) != 0) return QString::fromLocal8Bit(msg); return QString(); #else return QString::fromLocal8Bit(strerror(error)); #endif } /*! \internal Removes the directory at \a path recursively. @param path The directory to remove @param ignoreErrors if @p true, errors will be silently ignored. Otherwise an exception will be thrown if removing fails. @throws QInstaller::Error if the directory cannot be removed and ignoreErrors is @p false */ void QInstaller::removeDirectory(const QString &path, bool ignoreErrors) { if (path.isEmpty()) // QDir("") points to the working directory! We never want to remove that one. return; QStringList dirs; QDirIterator it(path, QDir::NoDotAndDotDot | QDir::Dirs | QDir::NoSymLinks | QDir::Hidden, QDirIterator::Subdirectories); while (it.hasNext()) { dirs.prepend(it.next()); removeFiles(dirs.at(0), ignoreErrors); } QDir d; dirs.append(path); removeFiles(path, ignoreErrors); foreach (const QString &dir, dirs) { errno = 0; if (d.exists(path) && !d.rmdir(dir)) { const QString errorMessage = QCoreApplication::translate("QInstaller", "Cannot remove directory \"%1\": %2").arg(QDir::toNativeSeparators(dir), errnoToQString(errno)); if (!ignoreErrors) throw Error(errorMessage); qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; } } } class RemoveDirectoryThread : public QThread { public: explicit RemoveDirectoryThread(const QString &path, bool ignoreErrors = false, QObject *parent = nullptr) : QThread(parent) , p(path) , ignore(ignoreErrors) { setObjectName(QLatin1String("RemoveDirectory")); } const QString &error() const { return err; } protected: /* \reimp */ void run() { try { removeDirectory(p, ignore); } catch (const Error &e) { err = e.message(); } } private: QString err; const QString p; const bool ignore; }; /*! \internal */ void QInstaller::removeDirectoryThreaded(const QString &path, bool ignoreErrors) { RemoveDirectoryThread thread(path, ignoreErrors); QEventLoop loop; QObject::connect(&thread, &RemoveDirectoryThread::finished, &loop, &QEventLoop::quit); thread.start(); loop.exec(); if (!thread.error().isEmpty()) throw Error(thread.error()); } /*! Removes system generated files from \a path on Windows and macOS. Does nothing on Linux. */ void QInstaller::removeSystemGeneratedFiles(const QString &path) { if (path.isEmpty()) return; #if defined Q_OS_MACOS QFile::remove(path + QLatin1String("/.DS_Store")); #elif defined Q_OS_WIN QFile::remove(path + QLatin1String("/Thumbs.db")); #endif } /*! Sets permissions of file or directory specified by \a fileName to \c 644 or \c 755 based by the value of \a permissions. Returns \c true on success, \c false otherwise. */ bool QInstaller::setDefaultFilePermissions(const QString &fileName, DefaultFilePermissions permissions) { QFile file(fileName); return setDefaultFilePermissions(&file, permissions); } /*! Sets permissions of file or directory specified by \a file to \c 644 or \c 755 based by the value of \a permissions. This is effective only on Unix platforms as \c setPermissions() does not manipulate ACLs. On Windows NTFS volumes this only unsets the legacy read-only flag regardless of the value of \a permissions. Returns \c true on success, \c false otherwise. */ bool QInstaller::setDefaultFilePermissions(QFile *file, DefaultFilePermissions permissions) { if (!file->exists()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Target" << file->fileName() << "does not exists."; return false; } if (file->permissions() == static_cast(permissions)) return true; if (!file->setPermissions(static_cast(permissions))) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot set default permissions for target" << file->fileName() << ":" << file->errorString(); return false; } return true; } /*! \internal */ void QInstaller::copyDirectoryContents(const QString &sourceDir, const QString &targetDir) { Q_ASSERT(QFileInfo(sourceDir).isDir()); Q_ASSERT(!QFileInfo(targetDir).exists() || QFileInfo(targetDir).isDir()); if (!QDir().mkpath(targetDir)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot create directory \"%1\".") .arg(QDir::toNativeSeparators(targetDir))); } QDirIterator it(sourceDir, QDir::NoDotAndDotDot | QDir::AllEntries); while (it.hasNext()) { const QFileInfo i(it.next()); if (i.isDir()) { copyDirectoryContents(QDir(sourceDir).absoluteFilePath(i.fileName()), QDir(targetDir).absoluteFilePath(i.fileName())); } else { QFile f(i.filePath()); const QString target = QDir(targetDir).absoluteFilePath(i.fileName()); if (!f.copy(target)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot copy file from \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(f.fileName()), QDir::toNativeSeparators(target), f.errorString())); } } } } /*! \internal */ void QInstaller::moveDirectoryContents(const QString &sourceDir, const QString &targetDir) { Q_ASSERT(QFileInfo(sourceDir).isDir()); Q_ASSERT(!QFileInfo(targetDir).exists() || QFileInfo(targetDir).isDir()); if (!QDir().mkpath(targetDir)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot create directory \"%1\".") .arg(QDir::toNativeSeparators(targetDir))); } QDirIterator it(sourceDir, QDir::NoDotAndDotDot | QDir::AllEntries); while (it.hasNext()) { const QFileInfo i(it.next()); if (i.isDir()) { // only copy directories that are not the target to avoid loop dir creations QString newSource = QDir(sourceDir).absoluteFilePath(i.fileName()); if (QDir(newSource) != QDir(targetDir)) { moveDirectoryContents(newSource, QDir(targetDir).absoluteFilePath(i.fileName())); } } else { QFile f(i.filePath()); const QString target = QDir(targetDir).absoluteFilePath(i.fileName()); if (!f.rename(target)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot move file from \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(f.fileName()), QDir::toNativeSeparators(target), f.errorString())); } } } } /*! \internal */ void QInstaller::mkdir(const QString &path) { errno = 0; if (!QDir().mkdir(QFileInfo(path).absoluteFilePath())) { throw Error(QCoreApplication::translate("QInstaller", "Cannot create directory \"%1\": %2") .arg(QDir::toNativeSeparators(path), errnoToQString(errno))); } } /*! \internal */ void QInstaller::mkpath(const QString &path) { errno = 0; if (!QDir().mkpath(QFileInfo(path).absoluteFilePath())) { throw Error(QCoreApplication::translate("QInstaller", "Cannot create directory \"%1\": %2") .arg(QDir::toNativeSeparators(path), errnoToQString(errno))); } } /*! \internal Generates and returns a temporary file name. The name can start with a template \a templ. */ QString QInstaller::generateTemporaryFileName(const QString &templ) { if (templ.isEmpty()) { QTemporaryFile f; if (!f.open()) { throw Error(QCoreApplication::translate("QInstaller", "Cannot open temporary file: %1").arg(f.errorString())); } return f.fileName(); } static const QString characters = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); QString suffix; qsrand(qrand() * QDateTime::currentDateTime().toTime_t()); for (int i = 0; i < 5; ++i) suffix += characters[qrand() % characters.length()]; const QString tmp = QLatin1String("%1.tmp.%2.%3"); int count = 1; while (QFile::exists(tmp.arg(templ, suffix).arg(count))) ++count; QFile f(tmp.arg(templ, suffix).arg(count)); if (!f.open(QIODevice::WriteOnly)) { throw Error(QCoreApplication::translate("QInstaller", "Cannot open temporary file for template %1: %2").arg(templ, f.errorString())); } f.remove(); return f.fileName(); } #ifdef Q_OS_WIN #include /*! \internal */ QString QInstaller::getShortPathName(const QString &name) { if (name.isEmpty()) return name; // Determine length, then convert. const LPCTSTR nameC = reinterpret_cast(name.utf16()); // MinGW const DWORD length = GetShortPathName(nameC, nullptr, 0); if (length == 0) return name; QScopedArrayPointer buffer(new TCHAR[length]); GetShortPathName(nameC, buffer.data(), length); const QString rc = QString::fromUtf16(reinterpret_cast(buffer.data()), length - 1); return rc; } /*! \internal */ QString QInstaller::getLongPathName(const QString &name) { if (name.isEmpty()) return name; // Determine length, then convert. const LPCTSTR nameC = reinterpret_cast(name.utf16()); // MinGW const DWORD length = GetLongPathName(nameC, nullptr, 0); if (length == 0) return name; QScopedArrayPointer buffer(new TCHAR[length]); GetLongPathName(nameC, buffer.data(), length); const QString rc = QString::fromUtf16(reinterpret_cast(buffer.data()), length - 1); return rc; } /*! \internal Makes sure that capitalization of directory specified by \a name is canonical. */ QString QInstaller::normalizePathName(const QString &name) { QString canonicalName = getShortPathName(name); if (canonicalName.isEmpty()) return name; canonicalName = getLongPathName(canonicalName); if (canonicalName.isEmpty()) return name; // Upper case drive letter if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':')) canonicalName[0] = canonicalName.at(0).toUpper(); return canonicalName; } #pragma pack(push) #pragma pack(2) typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if >=8bpp) BYTE bReserved; // Reserved WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // how many bytes in this resource? DWORD dwImageOffset; // the ID } ICONDIRENTRY; typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource type (1 for icons) WORD idCount; // How many images? ICONDIRENTRY idEntries[1]; // The entries for each image } ICONDIR; typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if >=8bpp) BYTE bReserved; // Reserved WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // how many bytes in this resource? WORD nID; // the ID } GRPICONDIRENTRY, *LPGRPICONDIRENTRY; typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource type (1 for icons) WORD idCount; // How many images? GRPICONDIRENTRY idEntries[1]; // The entries for each image } GRPICONDIR, *LPGRPICONDIR; #pragma pack(pop) /*! \internal Sets the .ico file at \a icon as application icon for \a application. */ void QInstaller::setApplicationIcon(const QString &application, const QString &icon) { QFile iconFile(icon); if (!iconFile.open(QIODevice::ReadOnly)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot use" << icon << "as an application icon:" << iconFile.errorString(); return; } if (QImageReader::imageFormat(icon) != "ico") { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot use" << icon << "as an application icon, " "unsupported format" << QImageReader::imageFormat(icon).constData(); return; } QByteArray temp = iconFile.readAll(); ICONDIR* ig = reinterpret_cast (temp.data()); DWORD newSize = sizeof(GRPICONDIR) + sizeof(GRPICONDIRENTRY) * (ig->idCount - 1); GRPICONDIR* newDir = reinterpret_cast< GRPICONDIR* >(new char[newSize]); newDir->idReserved = ig->idReserved; newDir->idType = ig->idType; newDir->idCount = ig->idCount; HANDLE updateRes = BeginUpdateResourceW((wchar_t*)QDir::toNativeSeparators(application).utf16(), false); for (int i = 0; i < ig->idCount; ++i) { char* temp1 = temp.data() + ig->idEntries[i].dwImageOffset; DWORD size1 = ig->idEntries[i].dwBytesInRes; newDir->idEntries[i].bWidth = ig->idEntries[i].bWidth; newDir->idEntries[i].bHeight = ig->idEntries[i].bHeight; newDir->idEntries[i].bColorCount = ig->idEntries[i].bColorCount; newDir->idEntries[i].bReserved = ig->idEntries[i].bReserved; newDir->idEntries[i].wPlanes = ig->idEntries[i].wPlanes; newDir->idEntries[i].wBitCount = ig->idEntries[i].wBitCount; newDir->idEntries[i].dwBytesInRes = ig->idEntries[i].dwBytesInRes; newDir->idEntries[i].nID = i + 1; UpdateResourceW(updateRes, RT_ICON, MAKEINTRESOURCE(i + 1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), temp1, size1); } UpdateResourceW(updateRes, RT_GROUP_ICON, L"IDI_ICON1", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newDir, newSize); delete [] newDir; EndUpdateResourceW(updateRes, false); } static quint64 symlinkSizeWin(const QString &path) { WIN32_FILE_ATTRIBUTE_DATA fileAttributeData; if (GetFileAttributesEx((wchar_t*)(path.utf16()), GetFileExInfoStandard, &fileAttributeData) == FALSE) return quint64(0); LARGE_INTEGER size; size.LowPart = fileAttributeData.nFileSizeLow; size.HighPart = fileAttributeData.nFileSizeHigh; return quint64(size.QuadPart); } #endif /*! \internal */ quint64 QInstaller::fileSize(const QFileInfo &info) { if (!info.isSymLink()) return info.size(); #ifndef Q_OS_WIN struct stat buffer; if (lstat(qPrintable(info.absoluteFilePath()), &buffer) != 0) return quint64(0); return quint64(buffer.st_size); #else return symlinkSizeWin(info.absoluteFilePath()); #endif } /*! \internal Returns \c true if a file specified by \a path points to a bundle. The absolute path for the bundle can be retrieved with \a bundlePath. Works only on macOS. */ bool QInstaller::isInBundle(const QString &path, QString *bundlePath) { #ifdef Q_OS_MACOS QFileInfo fi = QFileInfo(path).absoluteFilePath(); while (!fi.isRoot()) { if (fi.isBundle()) { if (bundlePath) *bundlePath = fi.absoluteFilePath(); return true; } fi.setFile(fi.path()); } #else Q_UNUSED(path) Q_UNUSED(bundlePath) #endif return false; } /*! Replaces the path \a before with the path \a after at the beginning of \a path and returns the replaced path. If \a before cannot be found in \a path, the original value is returned. */ QString QInstaller::replacePath(const QString &path, const QString &before, const QString &after) { if (path.isEmpty() || before.isEmpty()) return path; QString pathToPatch = QDir::cleanPath(path); const QString pathToReplace = QDir::cleanPath(before); if (pathToPatch.startsWith(pathToReplace)) return QDir::cleanPath(after) + pathToPatch.mid(pathToReplace.size()); return path; } qt-installer-framework-4.0.1/src/libs/installer/fileutils.h0100777000000000000000000000771213761647206020775 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_FILEUTILS_H #define QINSTALLER_FILEUTILS_H #include "installer_global.h" #include #include #include QT_BEGIN_NAMESPACE class QFileInfo; class QFile; class QUrl; QT_END_NAMESPACE namespace QInstaller { enum DefaultFilePermissions { NonExecutable = 0x6644, Executable = 0x7755 }; class INSTALLER_EXPORT TempDirDeleter { public: explicit TempDirDeleter(const QString &path); explicit TempDirDeleter(const QStringList &paths = QStringList()); ~TempDirDeleter(); QStringList paths() const; void add(const QString &path); void add(const QStringList &paths); void releaseAll(); void release(const QString &path); void passAndReleaseAll(TempDirDeleter &tdd); void passAndRelease(TempDirDeleter &tdd, const QString &path); void releaseAndDeleteAll(); void releaseAndDelete(const QString &path); private: Q_DISABLE_COPY(TempDirDeleter) QSet m_paths; }; QString INSTALLER_EXPORT humanReadableSize(const qint64 &size, int precision = 2); void INSTALLER_EXPORT removeFiles(const QString &path, bool ignoreErrors = false); void INSTALLER_EXPORT removeDirectory(const QString &path, bool ignoreErrors = false); void INSTALLER_EXPORT removeDirectoryThreaded(const QString &path, bool ignoreErrors = false); void INSTALLER_EXPORT removeSystemGeneratedFiles(const QString &path); bool INSTALLER_EXPORT setDefaultFilePermissions(const QString &fileName, DefaultFilePermissions permissions); bool INSTALLER_EXPORT setDefaultFilePermissions(QFile *file, DefaultFilePermissions permissions); QString INSTALLER_EXPORT generateTemporaryFileName(const QString &templ=QString()); void INSTALLER_EXPORT moveDirectoryContents(const QString &sourceDir, const QString &targetDir); void INSTALLER_EXPORT copyDirectoryContents(const QString &sourceDir, const QString &targetDir); bool INSTALLER_EXPORT isLocalUrl(const QUrl &url); QString INSTALLER_EXPORT pathFromUrl(const QUrl &url); void INSTALLER_EXPORT mkdir(const QString &path); void INSTALLER_EXPORT mkpath(const QString &path); quint64 INSTALLER_EXPORT fileSize(const QFileInfo &info); bool INSTALLER_EXPORT isInBundle(const QString &path, QString *bundlePath = 0); QString replacePath(const QString &path, const QString &pathBefore, const QString &pathAfter); #ifdef Q_OS_WIN QString INSTALLER_EXPORT getLongPathName(const QString &name); QString INSTALLER_EXPORT getShortPathName(const QString &name); QString INSTALLER_EXPORT normalizePathName(const QString &name); void INSTALLER_EXPORT setApplicationIcon(const QString &application, const QString &icon); #endif } #endif // QINSTALLER_FILEUTILS_H qt-installer-framework-4.0.1/src/libs/installer/globals.cpp0100777000000000000000000002137013761647206020747 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include "globals.h" const char IFW_SERVER[] = "ifw.server"; const char IFW_PACKAGE_DISPLAYNAME[] = "ifw.package.displayname"; const char IFW_PACKAGE_DESCRIPTION[] = "ifw.package.description"; const char IFW_PACKAGE_VERSION[] = "ifw.package.version"; const char IFW_PACKAGE_INSTALLEDVERSION[] = "ifw.package.installedversion"; const char IFW_PACKAGE_RELEASEDATE[] = "ifw.package.releasedate"; const char IFW_PACKAGE_INSTALLDATE[] = "ifw.package.installdate"; const char IFW_PACKAGE_UPDATEDATE[] = "ifw.package.updatedate"; const char IFW_PACKAGE_NAME[] = "ifw.package.name"; const char IFW_PACKAGE_DEPENDENCIES[] = "ifw.package.dependencies"; const char IFW_PACKAGE_AUTODEPENDON[] = "ifw.package.autodependon"; const char IFW_PACKAGE_VIRTUAL[] = "ifw.package.virtual"; const char IFW_PACKAGE_SORTINGPRIORITY[] = "ifw.package.sortingpriority"; const char IFW_PACKAGE_SCRIPT[] = "ifw.package.script"; const char IFW_PACKAGE_DEFAULT[] = "ifw.package.default"; const char IFW_PACKAGE_ESSETIAL[] = "ifw.package.essential"; const char IFW_PACKAGE_FORCEDINSTALLATION[] = "ifw.package.forcedinstallation"; const char IFW_PACKAGE_REPLACES[] = "ifw.package.replaces"; const char IFW_PACKAGE_DOWNLOADABLEARCHIVES[] = "ifw.package.downloadablearchives"; const char IFW_PACKAGE_REQUIRESADMINRIGHTS[] = "ifw.package.requiresadminrights"; const char IFW_PACKAGE_CHECKABLE[] = "ifw.package.checkable"; const char IFW_PACKAGE_LICENSES[] = "ifw.package.licenses"; const char IFW_PACKAGE_COMPRESSEDSIZE[] = "ifw.package.compressedsize"; const char IFW_PACKAGE_UNCOMPRESSEDSIZE[] = "ifw.package.uncompressedsize"; const char IFW_INSTALLER_INSTALLLOG[] = "ifw.installer.installlog"; const char IFW_DEVELOPER_BUILD[] = "ifw.developer.build"; // Internal-only, hidden in --help text const char IFW_PROGRESS_INDICATOR[] = "ifw.progress.indicator"; namespace QInstaller { /*! \fn QInstaller::lcServer() \internal */ /*! \fn QInstaller::lcPackageDisplayname() \internal */ /*! \fn QInstaller::lcPackageDescription() \internal */ /*! \fn QInstaller::lcPackageVersion() \internal */ /*! \fn QInstaller::lcPackageInstalledVersion() \internal */ /*! \fn QInstaller::lcPackageReleasedate() \internal */ /*! \fn QInstaller::lcPackageInstallDate() \internal */ /*! \fn QInstaller::lcPackageUpdateDate() \internal */ /*! \fn QInstaller::lcPackageName() \internal */ /*! \fn QInstaller::lcPackageDependencies() \internal */ /*! \fn QInstaller::lcPackageAutodependon() \internal */ /*! \fn QInstaller::lcPackageVirtual() \internal */ /*! \fn QInstaller::lcPackageSortingpriority() \internal */ /*! \fn QInstaller::lcPackageScript() \internal */ /*! \fn QInstaller::lcPackageDefault() \internal */ /*! \fn QInstaller::lcPackageEssential() \internal */ /*! \fn QInstaller::lcPackageForcedinstallation() \internal */ /*! \fn QInstaller::lcPackageReplaces() \internal */ /*! \fn QInstaller::lcPackageDownloadableArchives() \internal */ /*! \fn QInstaller::lcPackageRequiresAdminRights() \internal */ /*! \fn QInstaller::lcPackageCheckable() \internal */ /*! \fn QInstaller::lcPackageLicenses() \internal */ /*! \fn QInstaller::lcPackageUncompressedSize() \internal */ /*! \fn QInstaller::lcPackageCompressedSize() \internal */ /*! \fn QInstaller::lcInstallerInstallLog() \internal */ /*! \fn QInstaller::lcProgressIndicator() \internal */ /*! \fn QInstaller::lcDeveloperBuild() \internal */ Q_LOGGING_CATEGORY(lcServer, IFW_SERVER) Q_LOGGING_CATEGORY(lcPackageDisplayname, IFW_PACKAGE_DISPLAYNAME); Q_LOGGING_CATEGORY(lcPackageDescription, IFW_PACKAGE_DESCRIPTION) Q_LOGGING_CATEGORY(lcPackageVersion, IFW_PACKAGE_VERSION) Q_LOGGING_CATEGORY(lcPackageInstalledVersion, IFW_PACKAGE_INSTALLEDVERSION) Q_LOGGING_CATEGORY(lcPackageReleasedate, IFW_PACKAGE_RELEASEDATE) Q_LOGGING_CATEGORY(lcPackageInstallDate, IFW_PACKAGE_INSTALLDATE) Q_LOGGING_CATEGORY(lcPackageUpdateDate, IFW_PACKAGE_UPDATEDATE) Q_LOGGING_CATEGORY(lcPackageName, IFW_PACKAGE_NAME) Q_LOGGING_CATEGORY(lcPackageDependencies, IFW_PACKAGE_DEPENDENCIES) Q_LOGGING_CATEGORY(lcPackageAutodependon, IFW_PACKAGE_AUTODEPENDON) Q_LOGGING_CATEGORY(lcPackageVirtual, IFW_PACKAGE_VIRTUAL) Q_LOGGING_CATEGORY(lcPackageSortingpriority, IFW_PACKAGE_SORTINGPRIORITY) Q_LOGGING_CATEGORY(lcPackageScript, IFW_PACKAGE_SCRIPT) Q_LOGGING_CATEGORY(lcPackageDefault, IFW_PACKAGE_DEFAULT) Q_LOGGING_CATEGORY(lcPackageEssential, IFW_PACKAGE_ESSETIAL) Q_LOGGING_CATEGORY(lcPackageForcedinstallation, IFW_PACKAGE_FORCEDINSTALLATION) Q_LOGGING_CATEGORY(lcPackageReplaces, IFW_PACKAGE_REPLACES) Q_LOGGING_CATEGORY(lcPackageDownloadableArchives, IFW_PACKAGE_DOWNLOADABLEARCHIVES) Q_LOGGING_CATEGORY(lcPackageRequiresAdminRights, IFW_PACKAGE_REQUIRESADMINRIGHTS) Q_LOGGING_CATEGORY(lcPackageCheckable, IFW_PACKAGE_CHECKABLE) Q_LOGGING_CATEGORY(lcPackageLicenses, IFW_PACKAGE_LICENSES) Q_LOGGING_CATEGORY(lcPackageUncompressedSize, IFW_PACKAGE_UNCOMPRESSEDSIZE) Q_LOGGING_CATEGORY(lcPackageCompressedSize, IFW_PACKAGE_COMPRESSEDSIZE) Q_LOGGING_CATEGORY(lcInstallerInstallLog, IFW_INSTALLER_INSTALLLOG) Q_LOGGING_CATEGORY(lcProgressIndicator, IFW_PROGRESS_INDICATOR) Q_LOGGING_CATEGORY(lcDeveloperBuild, IFW_DEVELOPER_BUILD) /*! Returns available logging categories. */ QStringList loggingCategories() { static QStringList categories = QStringList() << QLatin1String(IFW_PACKAGE_DISPLAYNAME) << QLatin1String(IFW_PACKAGE_DESCRIPTION) << QLatin1String(IFW_PACKAGE_VERSION) << QLatin1String(IFW_PACKAGE_INSTALLEDVERSION) << QLatin1String(IFW_PACKAGE_RELEASEDATE) << QLatin1String(IFW_PACKAGE_INSTALLDATE) << QLatin1String(IFW_PACKAGE_UPDATEDATE) << QLatin1String(IFW_PACKAGE_NAME) << QLatin1String(IFW_PACKAGE_DEPENDENCIES) << QLatin1String(IFW_PACKAGE_AUTODEPENDON) << QLatin1String(IFW_PACKAGE_VIRTUAL) << QLatin1String(IFW_PACKAGE_SORTINGPRIORITY) << QLatin1String(IFW_PACKAGE_SCRIPT) << QLatin1String(IFW_PACKAGE_DEFAULT) << QLatin1String(IFW_PACKAGE_ESSETIAL) << QLatin1String(IFW_PACKAGE_FORCEDINSTALLATION) << QLatin1String(IFW_PACKAGE_REPLACES) << QLatin1String(IFW_PACKAGE_DOWNLOADABLEARCHIVES) << QLatin1String(IFW_PACKAGE_REQUIRESADMINRIGHTS) << QLatin1String(IFW_PACKAGE_CHECKABLE) << QLatin1String(IFW_PACKAGE_LICENSES) << QLatin1String(IFW_PACKAGE_UNCOMPRESSEDSIZE) << QLatin1String(IFW_PACKAGE_COMPRESSEDSIZE) << QLatin1String(IFW_INSTALLER_INSTALLLOG) << QLatin1String(IFW_SERVER); return categories; } Q_GLOBAL_STATIC_WITH_ARGS(QRegExp, staticCommaRegExp, (QLatin1String("(, |,)"))); /*! \internal */ QRegExp commaRegExp() { return *staticCommaRegExp(); } /*! Converts and returns a string \a html containing an HTML document as a plain text. */ QString htmlToString(const QString &html) { QTextDocument doc; doc.setHtml(html); return doc.toPlainText(); } /*! \internal */ QString enumToString(const QMetaObject& metaObject, const char *enumerator, int key) { QString value = QString(); int enumIndex = metaObject.indexOfEnumerator(enumerator); if (enumIndex != -1) { QMetaEnum en = metaObject.enumerator(enumIndex); value = QLatin1String(en.valueToKey(key)); } return value; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/globals.h0100777000000000000000000000655713761647206020426 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef GLOBALS_H #define GLOBALS_H #include "installer_global.h" #include #include namespace QInstaller { INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcServer) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcInstallerInstallLog) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageDisplayname) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageDescription) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageVersion) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageInstalledVersion) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageReleasedate) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageInstallDate) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageUpdateDate) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageName) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageDependencies) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageAutodependon) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageVirtual) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageSortingpriority) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageScript) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageDefault) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageEssential) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageForcedinstallation) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageReplaces) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageDownloadableArchives) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageRequiresAdminRights) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageCheckable) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageLicenses) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageUncompressedSize) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageCompressedSize) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcProgressIndicator) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcDeveloperBuild) QStringList INSTALLER_EXPORT loggingCategories(); QRegExp INSTALLER_EXPORT commaRegExp(); QString htmlToString(const QString &html); QString enumToString(const QMetaObject& metaObject, const char *enumerator, int key); } // QInstaller #endif // GLOBALS_H qt-installer-framework-4.0.1/src/libs/installer/globalsettingsoperation.cpp0100777000000000000000000001011613761647206024262 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "globalsettingsoperation.h" #include "qsettingswrapper.h" using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::GlobalSettingsOperation \internal */ GlobalSettingsOperation::GlobalSettingsOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("GlobalConfig")); } void GlobalSettingsOperation::backup() { } bool GlobalSettingsOperation::performOperation() { QString key, value; QScopedPointer settings(setup(&key, &value, arguments())); if (settings.isNull()) return false; if (!settings->isWritable()) { setError(UserDefinedError); setErrorString(tr("Settings are not writable.")); return false; } const QVariant oldValue = settings->value(key); settings->setValue(key, value); settings->sync(); if (settings->status() != QSettingsWrapper::NoError) { setError(UserDefinedError); setErrorString(tr("Failed to write settings.")); return false; } setValue(QLatin1String("oldvalue"), oldValue); return true; } bool GlobalSettingsOperation::undoOperation() { QString key, val; QScopedPointer settings(setup(&key, &val, arguments())); if (settings.isNull()) return false; // be sure it's still our value and nobody changed it in between const QVariant oldValue = value(QLatin1String("oldvalue")); if (settings->value(key) == val) { // restore the previous state if (oldValue.isNull()) settings->remove(key); else settings->setValue(key, oldValue); } return true; } bool GlobalSettingsOperation::testOperation() { return true; } QSettingsWrapper *GlobalSettingsOperation::setup(QString *key, QString *value, const QStringList &arguments) { if (!checkArgumentCount(3, 5)) return nullptr; if (arguments.count() == 5) { QSettingsWrapper::Scope scope = QSettingsWrapper::UserScope; if (arguments.at(0) == QLatin1String("SystemScope")) scope = QSettingsWrapper::SystemScope; const QString &company = arguments.at(1); const QString &application = arguments.at(2); *key = arguments.at(3); *value = arguments.at(4); return new QSettingsWrapper(scope, company, application); } else if (arguments.count() == 4) { const QString &company = arguments.at(0); const QString &application = arguments.at(1); *key = arguments.at(2); *value = arguments.at(3); return new QSettingsWrapper(company, application); } else if (arguments.count() == 3) { const QString &filename = arguments.at(0); *key = arguments.at(1); *value = arguments.at(2); return new QSettingsWrapper(filename, QSettingsWrapper::NativeFormat); } return nullptr; } qt-installer-framework-4.0.1/src/libs/installer/globalsettingsoperation.h0100777000000000000000000000352413761647206023734 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef GLOBALSETTINGSOPERATION_H #define GLOBALSETTINGSOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class QSettingsWrapper; class INSTALLER_EXPORT GlobalSettingsOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::GlobalSettingsOperation) public: explicit GlobalSettingsOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); private: QSettingsWrapper *setup(QString *key, QString *value, const QStringList &args); }; } // namespace QInstaller #endif // GLOBALSETTINGSOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/graph.cpp0100777000000000000000000000252713761647206020430 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "graph.h" /*! \inmodule QtInstallerFramework \class QInstaller::Graph \internal */ qt-installer-framework-4.0.1/src/libs/installer/graph.h0100777000000000000000000000723013761647206020071 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef GRAPH_H #define GRAPH_H #include #include #include #include namespace QInstaller { template class Graph { public: inline Graph() {} explicit Graph(const QList &nodes) { addNodes(nodes); } const QList nodes() const { return m_graph.keys(); } void addNode(const T &node) { m_graph.insert(node, QSet()); } void addNodes(const QList &nodes) { foreach (const T &node, nodes) addNode(node); } QList edges(const T &node) const { return m_graph.value(node).toList(); } void addEdge(const T &node, const T &edge) { m_graph[node].insert(edge); } void addEdges(const T &node, const QList &edges) { foreach (const T &edge, edges) addEdge(node, edge); } bool hasCycle() const { return m_hasCycle; } QPair cycle() const { return m_cycle; } QList sort() const { QSet visitedNodes; QList resolvedNodes; m_hasCycle = false; m_cycle = qMakePair(T(), T()); foreach (const T &node, nodes()) visit(node, &resolvedNodes, &visitedNodes); return resolvedNodes; } QList sortReverse() const { QList result = sort(); std::reverse(result.begin(), result.end()); return result; } private: void visit(const T &node, QList *const resolvedNodes, QSet *const visitedNodes) const { if (m_hasCycle) return; // if we visited this node already if (visitedNodes->contains(node)) { // and if the node is already in the ordered list if (resolvedNodes->contains(node)) return; m_hasCycle = true; m_cycle.second = node; return; // if not yet in the ordered list, we detected a cycle } // mark this node as visited visitedNodes->insert(node); m_cycle.first = node; // recursively visit all adjacency foreach (const T &adjacency, edges(node)) visit(adjacency, resolvedNodes, visitedNodes); // append this node to the ordered list resolvedNodes->append(node); } private: mutable bool m_hasCycle; QHash > m_graph; mutable QPair m_cycle; }; } #endif // GRAPH_H qt-installer-framework-4.0.1/src/libs/installer/init.cpp0100777000000000000000000001577613761647206020304 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "init.h" #include "createshortcutoperation.h" #include "createdesktopentryoperation.h" #include "createlocalrepositoryoperation.h" #include "extractarchiveoperation.h" #include "globalsettingsoperation.h" #include "environmentvariablesoperation.h" #include "registerfiletypeoperation.h" #include "selfrestartoperation.h" #include "installiconsoperation.h" #include "elevatedexecuteoperation.h" #include "fakestopprocessforupdateoperation.h" #include "createlinkoperation.h" #include "simplemovefileoperation.h" #include "copydirectoryoperation.h" #include "replaceoperation.h" #include "linereplaceoperation.h" #include "minimumprogressoperation.h" #include "licenseoperation.h" #include "settingsoperation.h" #include "consumeoutputoperation.h" #include "globals.h" #include "lib7z_facade.h" #include "utils.h" #include "updateoperationfactory.h" #include "filedownloaderfactory.h" #include #include #include #if defined(Q_OS_UNIX) #include #elif defined(Q_OS_WIN) #include #endif using namespace KDUpdater; using namespace QInstaller; #if defined(QT_STATIC) static void initResources() { Q_INIT_RESOURCE(installer); } #endif static bool s_outputRedirected = false; static QString trimAndPrepend(QtMsgType type, const QString &msg) { QString ba(msg); // last character is a space from qDebug if (ba.endsWith(QLatin1Char(' '))) ba.chop(1); // remove quotes if the whole message is surrounded with them if (ba.startsWith(QLatin1Char('"')) && ba.endsWith(QLatin1Char('"'))) ba = ba.mid(1, ba.length() - 2); // prepend the message type, skip QtDebugMsg switch (type) { case QtWarningMsg: ba.prepend(QStringLiteral("Warning: ")); break; case QtCriticalMsg: ba.prepend(QStringLiteral("Critical: ")); break; case QtFatalMsg: ba.prepend(QStringLiteral("Fatal: ")); break; default: break; } return ba; } // start timer on construction (so we can use it as static member) class Uptime : public QElapsedTimer { public: Uptime() { start(); } }; void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { // suppress warning from QPA minimal plugin if (msg.contains(QLatin1String("This plugin does not support propagateSizeHints"))) return; if (context.category == lcProgressIndicator().categoryName()) { if (!s_outputRedirected) std::cout << msg.toStdString() << "\r" << std::flush; return; } static Uptime uptime; QString ba = QLatin1Char('[') + QString::number(uptime.elapsed()) + QStringLiteral("] ") + trimAndPrepend(type, msg); if (type != QtDebugMsg && context.file) { ba += QString(QStringLiteral(" (%1:%2, %3)")).arg( QString::fromLatin1(context.file)).arg(context.line).arg( QString::fromLatin1(context.function)); } if (VerboseWriter *log = VerboseWriter::instance()) log->appendLine(ba); if (type != QtDebugMsg || isVerbose()) std::cout << qPrintable(ba) << std::endl; if (type == QtFatalMsg) { QtMessageHandler oldMsgHandler = qInstallMessageHandler(nullptr); qt_message_output(type, context, msg); qInstallMessageHandler(oldMsgHandler); } } /*! Initializes the 7z library and installer resources. Registers custom operations and installs a custom message handler. */ void QInstaller::init() { Lib7z::initSevenZ(); #if defined(QT_STATIC) ::initResources(); #endif UpdateOperationFactory &factory = UpdateOperationFactory::instance(); factory.registerUpdateOperation(QLatin1String("CreateShortcut")); factory.registerUpdateOperation(QLatin1String("CreateDesktopEntry")); factory.registerUpdateOperation(QLatin1String("CreateLocalRepository")); factory.registerUpdateOperation(QLatin1String("Extract")); factory.registerUpdateOperation(QLatin1String("GlobalConfig")); factory.registerUpdateOperation(QLatin1String("EnvironmentVariable")); factory.registerUpdateOperation(QLatin1String("RegisterFileType")); factory.registerUpdateOperation(QLatin1String("SelfRestart")); factory.registerUpdateOperation(QLatin1String("InstallIcons")); factory.registerUpdateOperation(QLatin1String("Execute")); factory.registerUpdateOperation(QLatin1String("FakeStopProcessForUpdate")); factory.registerUpdateOperation(QLatin1String("CreateLink")); factory.registerUpdateOperation(QLatin1String("SimpleMoveFile")); factory.registerUpdateOperation(QLatin1String("CopyDirectory")); factory.registerUpdateOperation(QLatin1String("Replace")); factory.registerUpdateOperation(QLatin1String("LineReplace")); factory.registerUpdateOperation(QLatin1String("MinimumProgress")); factory.registerUpdateOperation(QLatin1String("License")); factory.registerUpdateOperation(QLatin1String("ConsumeOutput")); factory.registerUpdateOperation(QLatin1String("Settings")); FileDownloaderFactory::setFollowRedirects(true); #if defined(Q_OS_UNIX) s_outputRedirected = !isatty(fileno(stdout)); #elif defined(Q_OS_WIN) s_outputRedirected = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_DISK); #endif qInstallMessageHandler(messageHandler); } qt-installer-framework-4.0.1/src/libs/installer/init.h0100777000000000000000000000263013761647206017732 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_INIT_H #define QINSTALLER_INIT_H #include "installer_global.h" namespace QInstaller { void INSTALLER_EXPORT init(); } #endif // QINSTALLER_INIT_H qt-installer-framework-4.0.1/src/libs/installer/installer.pro0100777000000000000000000001414113761647206021335 0ustar00TEMPLATE = lib TARGET = installer INCLUDEPATH += . .. CONFIG += staticlib include(../7zip/7zip.pri) include(../kdtools/kdtools.pri) include(../../../installerfw.pri) # productkeycheck API # call qmake "PRODUCTKEYCHECK_PRI_FILE=" # content of that pri file needs to be: # SOURCES += $$PWD/productkeycheck.cpp # ... # your files if needed HEADERS += productkeycheck.h !isEmpty(PRODUCTKEYCHECK_PRI_FILE) { # use undocumented no_batch config which disable the implicit rules on msvc compilers # this fixes the problem that same cpp files in different directories are overwritting # each other CONFIG += no_batch include($$PRODUCTKEYCHECK_PRI_FILE) } else { SOURCES += productkeycheck.cpp SOURCES += commandlineparser_p.cpp } DESTDIR = $$IFW_LIB_PATH DLLDESTDIR = $$IFW_APP_PATH DEFINES += BUILD_LIB_INSTALLER QT += \ qml \ network \ xml \ concurrent \ widgets \ core-private \ qml-private win32:QT += winextras HEADERS += packagemanagercore.h \ aspectratiolabel.h \ packagemanagercore_p.h \ packagemanagergui.h \ binaryformat.h \ binaryformatengine.h \ binaryformatenginehandler.h \ repository.h \ utils.h \ errors.h \ component.h \ scriptengine.h \ componentmodel.h \ qinstallerglobal.h \ qtpatch.h \ consumeoutputoperation.h \ replaceoperation.h \ linereplaceoperation.h \ copydirectoryoperation.h \ simplemovefileoperation.h \ extractarchiveoperation.h \ extractarchiveoperation_p.h \ globalsettingsoperation.h \ createshortcutoperation.h \ createdesktopentryoperation.h \ registerfiletypeoperation.h \ environmentvariablesoperation.h \ installiconsoperation.h \ selfrestartoperation.h \ settings.h \ permissionsettings.h \ downloadarchivesjob.h \ init.h \ adminauthorization.h \ elevatedexecuteoperation.h \ fakestopprocessforupdateoperation.h \ lazyplaintextedit.h \ progresscoordinator.h \ minimumprogressoperation.h \ performinstallationform.h \ messageboxhandler.h \ licenseoperation.h \ component_p.h \ qprocesswrapper.h \ qsettingswrapper.h \ constants.h \ packagemanagerproxyfactory.h \ createlocalrepositoryoperation.h \ lib7z_facade.h \ link.h \ createlinkoperation.h \ packagemanagercoredata.h \ globals.h \ graph.h \ settingsoperation.h \ testrepository.h \ packagemanagerpagefactory.h \ abstracttask.h\ abstractfiletask.h \ copyfiletask.h \ downloadfiletask.h \ downloadfiletask_p.h \ unziptask.h \ observer.h \ runextensions.h \ metadatajob.h \ metadatajob_p.h \ installer_global.h \ scriptengine_p.h \ protocol.h \ remoteobject.h \ remoteclient.h \ remoteserver.h \ remoteclient_p.h \ remoteserver_p.h \ remotefileengine.h \ remoteserverconnection.h \ remoteserverconnection_p.h \ fileio.h \ binarycontent.h \ binarylayout.h \ installercalculator.h \ uninstallercalculator.h \ componentchecker.h \ proxycredentialsdialog.h \ serverauthenticationdialog.h \ keepaliveobject.h \ systeminfo.h \ packagesource.h \ lib7z_guid.h \ lib7z_create.h \ lib7z_extract.h \ lib7z_list.h \ repositorycategory.h \ componentselectionpage_p.h \ commandlineparser.h \ commandlineparser_p.h SOURCES += packagemanagercore.cpp \ aspectratiolabel.cpp \ packagemanagercore_p.cpp \ packagemanagergui.cpp \ binaryformat.cpp \ binaryformatengine.cpp \ binaryformatenginehandler.cpp \ repository.cpp \ fileutils.cpp \ utils.cpp \ component.cpp \ scriptengine.cpp \ componentmodel.cpp \ qtpatch.cpp \ consumeoutputoperation.cpp \ replaceoperation.cpp \ linereplaceoperation.cpp \ copydirectoryoperation.cpp \ simplemovefileoperation.cpp \ extractarchiveoperation.cpp \ globalsettingsoperation.cpp \ createshortcutoperation.cpp \ createdesktopentryoperation.cpp \ registerfiletypeoperation.cpp \ environmentvariablesoperation.cpp \ installiconsoperation.cpp \ selfrestartoperation.cpp \ downloadarchivesjob.cpp \ init.cpp \ elevatedexecuteoperation.cpp \ fakestopprocessforupdateoperation.cpp \ lazyplaintextedit.cpp \ progresscoordinator.cpp \ minimumprogressoperation.cpp \ performinstallationform.cpp \ messageboxhandler.cpp \ licenseoperation.cpp \ component_p.cpp \ qprocesswrapper.cpp \ qsettingswrapper.cpp \ settings.cpp \ permissionsettings.cpp \ packagemanagerproxyfactory.cpp \ createlocalrepositoryoperation.cpp \ lib7z_facade.cpp \ link.cpp \ createlinkoperation.cpp \ packagemanagercoredata.cpp \ globals.cpp \ settingsoperation.cpp \ testrepository.cpp \ packagemanagerpagefactory.cpp \ abstractfiletask.cpp \ copyfiletask.cpp \ downloadfiletask.cpp \ unziptask.cpp \ observer.cpp \ metadatajob.cpp \ protocol.cpp \ remoteobject.cpp \ remoteclient.cpp \ remoteserver.cpp \ remotefileengine.cpp \ remoteserverconnection.cpp \ fileio.cpp \ binarycontent.cpp \ binarylayout.cpp \ installercalculator.cpp \ uninstallercalculator.cpp \ componentchecker.cpp \ proxycredentialsdialog.cpp \ serverauthenticationdialog.cpp \ keepaliveobject.cpp \ systeminfo.cpp \ packagesource.cpp \ repositorycategory.cpp \ componentselectionpage_p.cpp \ commandlineparser.cpp FORMS += proxycredentialsdialog.ui \ serverauthenticationdialog.ui RESOURCES += resources/installer.qrc unix { osx: SOURCES += adminauthorization_mac.cpp else: SOURCES += adminauthorization_x11.cpp } LIBS += -l7z win32 { SOURCES += adminauthorization_win.cpp sysinfo_win.cpp LIBS += -loleaut32 -luser32 # 7zip LIBS += -ladvapi32 -lpsapi # kdtools LIBS += -lole32 -lshell32 # createshortcutoperation win32-g++*:LIBS += -lmpr -luuid win32-g++*:QMAKE_CXXFLAGS += -Wno-missing-field-initializers } target.path = $$[QT_INSTALL_LIBS] INSTALLS += target qt-installer-framework-4.0.1/src/libs/installer/installercalculator.cpp0100777000000000000000000002402413761647206023372 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "installercalculator.h" #include "component.h" #include "packagemanagercore.h" #include "settings.h" #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::InstallerCalculator \internal */ InstallerCalculator::InstallerCalculator(const QList &allComponents) : m_allComponents(allComponents) { } void InstallerCalculator::insertInstallReason(Component *component, InstallReasonType installReason, const QString &referencedComponentName) { // keep the first reason if (m_toInstallComponentIdReasonHash.contains(component->name())) return; m_toInstallComponentIdReasonHash.insert(component->name(), qMakePair(installReason, referencedComponentName)); } InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(Component *c) const { return m_toInstallComponentIdReasonHash.value(c->name(), qMakePair(InstallerCalculator::Selected, QString())).first; } QString InstallerCalculator::installReasonReferencedComponent(Component *component) const { return m_toInstallComponentIdReasonHash.value(component->name(), qMakePair(InstallerCalculator::Selected, QString())).second; } QString InstallerCalculator::installReason(Component *component) const { InstallerCalculator::InstallReasonType reason = installReasonType(component); switch (reason) { case Automatic: return QCoreApplication::translate("InstallerCalculator", "Components added as automatic dependencies:"); case Dependent: return QCoreApplication::translate("InstallerCalculator", "Components added as " "dependency for \"%1\":").arg(installReasonReferencedComponent(component)); case Resolved: return QCoreApplication::translate("InstallerCalculator", "Components that have resolved dependencies:"); case Selected: return QCoreApplication::translate("InstallerCalculator", "Selected components without dependencies:"); } return QString(); } QList InstallerCalculator::orderedComponentsToInstall() const { return m_orderedComponentsToInstall; } QString InstallerCalculator::componentsToInstallError() const { return m_componentsToInstallError; } void InstallerCalculator::realAppendToInstallComponents(Component *component, const QString &version) { if (!component->isInstalled(version) || component->updateRequested()) { m_orderedComponentsToInstall.append(component); m_toInstallComponentIds.insert(component->name()); } } QString InstallerCalculator::recursionError(Component *component) { return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component \"%1\" " "already added with reason: \"%2\"").arg(component->name(), installReason(component)); } bool InstallerCalculator::appendComponentsToInstall(const QList &components) { if (components.isEmpty()) return true; QList notAppendedComponents; // for example components with unresolved dependencies foreach (Component *component, components){ if (m_toInstallComponentIds.contains(component->name())) { const QString errorMessage = recursionError(component); qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; m_componentsToInstallError.append(errorMessage); Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO, qPrintable(errorMessage)); return false; } if (component->dependencies().isEmpty()) realAppendToInstallComponents(component); else notAppendedComponents.append(component); } foreach (Component *component, notAppendedComponents) { if (!appendComponentToInstall(component)) return false; } QList foundAutoDependOnList; // All regular dependencies are resolved. Now we are looking for auto depend on components. foreach (Component *component, m_allComponents) { // If a components is already installed or is scheduled for installation, no need to check // for auto depend installation. if ((!component->isInstalled() || component->updateRequested()) && !m_toInstallComponentIds.contains(component->name())) { // If we figure out a component requests auto installation, keep it to resolve // their dependencies as well. if (component->isAutoDependOn(m_toInstallComponentIds)) { foundAutoDependOnList.append(component); insertInstallReason(component, InstallerCalculator::Automatic); } } } if (!foundAutoDependOnList.isEmpty()) return appendComponentsToInstall(foundAutoDependOnList); return true; } bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version) { QSet allDependencies = component->dependencies().toSet(); QString requiredDependencyVersion = version; foreach (const QString &dependencyComponentName, allDependencies) { // PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a // version which is not available Component *dependencyComponent = PackageManagerCore::componentByName(dependencyComponentName, m_allComponents); if (!dependencyComponent) { const QString errorMessage = QCoreApplication::translate("InstallerCalculator", "Cannot find missing dependency \"%1\" for \"%2\".").arg(dependencyComponentName, component->name()); qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; m_componentsToInstallError.append(errorMessage); if (component->packageManagerCore()->settings().allowUnstableComponents()) { component->setUnstable(Component::UnstableError::MissingDependency, errorMessage); continue; } else { return false; } } //Check if component requires higher version than what might be already installed bool isUpdateRequired = false; QString requiredName; QString requiredVersion; PackageManagerCore::parseNameAndVersion(dependencyComponentName, &requiredName, &requiredVersion); if (!requiredVersion.isEmpty() && !dependencyComponent->value(scInstalledVersion).isEmpty()) { QRegExp compEx(QLatin1String("([<=>]+)(.*)")); const QString installedVersion = compEx.exactMatch(dependencyComponent->value(scInstalledVersion)) ? compEx.cap(2) : dependencyComponent->value(scInstalledVersion); requiredVersion = compEx.exactMatch(requiredVersion) ? compEx.cap(2) : requiredVersion; if (KDUpdater::compareVersion(requiredVersion, installedVersion) >= 1 ) { isUpdateRequired = true; requiredDependencyVersion = requiredVersion; } } //Check dependencies only if //- Dependency is not installed or update requested, nor newer version of dependency component required //- And dependency component is not already added for install //- And component is not already added for install, then dependencies are already resolved if (((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested()) || isUpdateRequired) && (!m_toInstallComponentIds.contains(dependencyComponent->name()) && !m_toInstallComponentIds.contains(component->name()))) { if (m_visitedComponents.value(component).contains(dependencyComponent)) { const QString errorMessage = recursionError(component); qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; m_componentsToInstallError = errorMessage; Q_ASSERT_X(!m_visitedComponents.value(component).contains(dependencyComponent), Q_FUNC_INFO, qPrintable(errorMessage)); return false; } m_visitedComponents[component].insert(dependencyComponent); // add needed dependency components to the next run insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, component->name()); if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion)) return false; } } if (!m_toInstallComponentIds.contains(component->name())) { realAppendToInstallComponents(component, requiredDependencyVersion); insertInstallReason(component, InstallerCalculator::Resolved); } return true; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/installercalculator.h0100777000000000000000000000630313761647206023037 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef INSTALLERCALCULATOR_H #define INSTALLERCALCULATOR_H #include "installer_global.h" #include #include #include #include namespace QInstaller { class Component; class INSTALLER_EXPORT InstallerCalculator { public: InstallerCalculator(const QList &allComponents); enum InstallReasonType { Automatic, // "Component(s) added as automatic dependencies" Dependent, // "Added as dependency for %1." Resolved, // "Component(s) that have resolved Dependencies" Selected // "Selected Component(s) without Dependencies" }; InstallReasonType installReasonType(Component *component) const; QString installReasonReferencedComponent(Component *component) const; QString installReason(Component *component) const; QList orderedComponentsToInstall() const; QString componentsToInstallError() const; bool appendComponentsToInstall(const QList &components); private: void insertInstallReason(Component *component, InstallReasonType installReasonType, const QString &referencedComponentName = QString()); void realAppendToInstallComponents(Component *component, const QString &version = QString()); bool appendComponentToInstall(Component *components, const QString &version = QString()); QString recursionError(Component *component); QList m_allComponents; QHash > m_visitedComponents; QSet m_toInstallComponentIds; //for faster lookups QString m_componentsToInstallError; //calculate installation order variables QList m_orderedComponentsToInstall; //we can't use this reason hash as component id hash, because some reasons are ready before //the component is added QHash > m_toInstallComponentIdReasonHash; }; } #endif // INSTALLERCALCULATOR_H qt-installer-framework-4.0.1/src/libs/installer/installer_global.h0100777000000000000000000000303313761647206022302 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef INSTALLER_GLOBAL_H #define INSTALLER_GLOBAL_H #include #ifndef QT_STATIC # ifdef BUILD_LIB_INSTALLER # define INSTALLER_EXPORT Q_DECL_EXPORT # else # define INSTALLER_EXPORT Q_DECL_IMPORT # endif #else # define INSTALLER_EXPORT #endif #endif //INSTALLER_GLOBAL_H qt-installer-framework-4.0.1/src/libs/installer/installiconsoperation.cpp0100777000000000000000000002407713761647206023756 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "installiconsoperation.h" #include "fileutils.h" #include "packagemanagercore.h" #include "globals.h" #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::InstallIconsOperation \internal */ QString InstallIconsOperation::targetDirectory() { // we're not searching for the first time, let's re-use the old value if (hasValue(QLatin1String("directory"))) return value(QLatin1String("directory")).toString(); QStringList XDG_DATA_HOME = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")) .split(QLatin1Char(':'), QString::SkipEmptyParts); XDG_DATA_HOME.push_back(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); // default path QString directory; const QStringList& directories = XDG_DATA_HOME; for (QStringList::const_iterator it = directories.begin(); it != directories.end(); ++it) { if (it->isEmpty()) continue; directory = QDir(*it).absoluteFilePath(QLatin1String("icons")); QDir dir(directory); // let's see if this dir exists or we're able to create it if (!dir.exists() && !QDir().mkpath(directory)) continue; // we just try if we're able to open the file in ReadWrite QFile file(QDir(directory).absoluteFilePath(QLatin1String("tmpfile"))); const bool existed = file.exists(); if (!file.open(QIODevice::ReadWrite)) continue; file.close(); if (!existed) file.remove(); break; } if (!QDir(directory).exists()) QDir().mkpath(directory); setValue(QLatin1String("directory"), directory); return directory; } InstallIconsOperation::InstallIconsOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("InstallIcons")); } void InstallIconsOperation::backup() { // we backup on the fly } bool InstallIconsOperation::performOperation() { if (!checkArgumentCount(1, 2, tr(" [vendor prefix]"))) return false; const QStringList args = arguments(); const QString source = args.at(0); const QString vendor = args.value(1); // value() used since it's optional if (source.isEmpty()) { setError(InvalidArguments); setErrorString(tr("Invalid Argument: source directory must not be empty.")); return false; } const QDir sourceDir = QDir(source); const QDir targetDir = QDir(targetDirectory()); QStringList files; QStringList backupFiles; QStringList createdDirectories; PackageManagerCore *const core = packageManager(); // iterate a second time to get the actual work done QDirIterator it(sourceDir.path(), QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (it.hasNext()) { const int status = core->status(); if (status == PackageManagerCore::Canceled || status == PackageManagerCore::Failure) return true; const QString &source = it.next(); QString target = targetDir.absoluteFilePath(sourceDir.relativeFilePath(source)); emit outputTextChanged(target); const QFileInfo fi = it.fileInfo(); if (!fi.isDir()) { // exchange prefix with vendor if vendor is set if (!vendor.isEmpty()) { // path of the target file const QString targetPath = QFileInfo(target).absolutePath() + QLatin1String("/"); // filename with replaced vendor string const QString targetFile = vendor + fi.baseName().section(QLatin1Char('-'), 1, -1, QString::SectionIncludeLeadingSep) + QLatin1String(".") + fi.completeSuffix(); // target is the file with full path and replaced vendor string target = targetPath + targetFile; } if (QFile(target).exists()) { // first backup... const QString backup = generateTemporaryFileName(target); QFile bf(target); if (!bf.copy(backup)) { setError(UserDefinedError); setErrorString(tr("Cannot backup file \"%1\": %2").arg( QDir::toNativeSeparators(target), bf.errorString())); undoOperation(); return false; } backupFiles.push_back(target); backupFiles.push_back(backup); setValue(QLatin1String("backupfiles"), backupFiles); // then delete it QString errStr; if (!deleteFileNowOrLater(target, &errStr)) { setError(UserDefinedError); setErrorString(tr("Failed to overwrite \"%1\": %2").arg( QDir::toNativeSeparators(target), errStr)); undoOperation(); return false; } } // copy the file to its new location QFile cf(source); if (!cf.copy(target)) { setError(UserDefinedError); setErrorString(tr("Failed to copy file \"%1\": %2").arg( QDir::toNativeSeparators(target), cf.errorString())); undoOperation(); return false; } deleteFileNowOrLater(source); files.push_back(source); files.push_back(target); setValue(QLatin1String("files"), files); } else if (fi.isDir() && !QDir(target).exists()) { if (!QDir().mkpath(target)) { setErrorString(tr("Cannot create directory \"%1\": %2").arg( QDir::toNativeSeparators(target), qt_error_string())); undoOperation(); return false; } createdDirectories.push_front(target); setValue(QLatin1String("createddirectories"), createdDirectories); } } // this should work now if not, it's not _that_ problematic... try { removeDirectory(source); } catch(...) { } return true; } bool InstallIconsOperation::undoOperation() { QStringList warningMessages; // first copy back all files to their origin const QStringList files = value(QLatin1String("files")).toStringList(); for (QStringList::const_iterator it = files.begin(); it != files.end(); it += 2) { const QString& source = *it; const QString& target = *(it + 1); // first make sure the "source" path is valid QDir().mkpath(QFileInfo(source).absolutePath()); QFile installedTarget(target); if (installedTarget.exists() && !(installedTarget.copy(source) && installedTarget.remove())) { warningMessages << QString::fromLatin1("Cannot move file from \"%1\" to \"%2\": %3)").arg( target, source, installedTarget.errorString()); } } // then copy back and remove all backuped files const QStringList backupFiles = value(QLatin1String("backupfiles")).toStringList(); for (QStringList::const_iterator it = backupFiles.begin(); it != backupFiles.end(); it += 2) { const QString& target = *it; const QString& backup = *(it + 1); // remove the target if (QFile::exists(target)) deleteFileNowOrLater(target); // then copy the backup onto the target if (!QFile::copy(backup, target)) { warningMessages << QString::fromLatin1("Cannot restore the backup \"%1\" to \"%2\".").arg( backup, target); } // finally remove the backp if (!deleteFileNowOrLater(backup)) warningMessages << QString::fromLatin1("Cannot remove the backup \"%1\".").arg(backup); } // then remove all directories created by us const QStringList createdDirectories = value(QLatin1String("createddirectories")).toStringList(); for (QStringList::const_iterator it = createdDirectories.begin(); it != createdDirectories.end(); ++it) { const QDir dir(*it); removeSystemGeneratedFiles(dir.absolutePath()); if (dir.exists() && !QDir::root().rmdir(dir.path())) warningMessages << QString::fromLatin1("Cannot remove directory \"%1\".").arg(dir.path()); } if (!warningMessages.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Undo of operation" << name() << "with arguments" << arguments().join(QLatin1String(", ")) << "had some problems."; foreach (const QString &message, warningMessages) { qCWarning(QInstaller::lcInstallerInstallLog).noquote() << message; } } return true; } bool InstallIconsOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/installiconsoperation.h0100777000000000000000000000340313761647206023411 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef INSTALLICONSOPERATION_H #define INSTALLICONSOPERATION_H #include "qinstallerglobal.h" #include namespace QInstaller { class INSTALLER_EXPORT InstallIconsOperation : public QObject, public Operation { Q_OBJECT public: explicit InstallIconsOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); Q_SIGNALS: void outputTextChanged(const QString &progress); private: QString targetDirectory(); }; } #endif qt-installer-framework-4.0.1/src/libs/installer/keepaliveobject.cpp0100777000000000000000000000402413761647206022455 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "keepaliveobject.h" #include "remoteclient.h" #include #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::KeepAliveObject \internal */ KeepAliveObject::KeepAliveObject() : m_timer(nullptr) , m_socket(nullptr) { } void KeepAliveObject::start() { m_timer = new QTimer(this); m_socket = new QLocalSocket(this); connect(m_timer, &QTimer::timeout, [this]() { if (m_socket->state() != QLocalSocket::UnconnectedState) return; m_socket->connectToServer(RemoteClient::instance().socketName()); }); connect(m_socket, &QLocalSocket::connected, [this]() { m_socket->close(); }); m_timer->setInterval(5000); m_timer->start(); } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/keepaliveobject.h0100777000000000000000000000324713761647206022130 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef KEEPALIVEOBJECT_H #define KEEPALIVEOBJECT_H #include QT_BEGIN_NAMESPACE class QTimer; class QLocalSocket; QT_END_NAMESPACE namespace QInstaller { class KeepAliveObject : public QObject { Q_OBJECT Q_DISABLE_COPY(KeepAliveObject) public: KeepAliveObject(); public slots: void start(); private: QTimer *m_timer; QLocalSocket *m_socket; }; } // namespace QInstaller #endif // KEEPALIVEOBJECT_H qt-installer-framework-4.0.1/src/libs/installer/lazyplaintextedit.cpp0100777000000000000000000000616113761647206023103 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "lazyplaintextedit.h" #include const int INTERVAL = 20; LazyPlainTextEdit::LazyPlainTextEdit(QWidget *parent) : QPlainTextEdit(parent) , m_timerId(0) { } void LazyPlainTextEdit::timerEvent(QTimerEvent *event) { if (event->timerId() == m_timerId) { killTimer(m_timerId); m_timerId = 0; m_cachedOutput.chop(1); //removes the last \n if (!m_cachedOutput.isEmpty()) { appendPlainText(m_cachedOutput); updateCursor(TextCursorPosition::Keep); horizontalScrollBar()->setValue(0); m_cachedOutput.clear(); } } } void LazyPlainTextEdit::append(const QString &text) { m_cachedOutput.append(text + QLatin1String("\n")); if (isVisible() && m_timerId == 0) m_timerId = startTimer(INTERVAL); } void LazyPlainTextEdit::clear() { if (m_timerId) { killTimer(m_timerId); m_timerId = 0; m_cachedOutput.clear(); } QPlainTextEdit::clear(); } void LazyPlainTextEdit::setVisible(bool visible) { if (m_timerId) { killTimer(m_timerId); m_timerId = 0; } if (visible) m_timerId = startTimer(INTERVAL); QPlainTextEdit::setVisible(visible); updateCursor(TextCursorPosition::Keep); } void LazyPlainTextEdit::updateCursor(TextCursorPosition position) { QTextCursor cursor = textCursor(); if ((position == TextCursorPosition::ForceEnd) || cursor.atEnd()) { // Workaround for height calculation issue if scrollbar is set to Qt::ScrollBarAsNeeded. Qt::ScrollBarPolicy policy = horizontalScrollBarPolicy(); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // enforce always on cursor.movePosition(QTextCursor::End); setTextCursor(cursor); ensureCursorVisible(); setHorizontalScrollBarPolicy(policy); // but reset once we updated the cursor position } } qt-installer-framework-4.0.1/src/libs/installer/lazyplaintextedit.h0100777000000000000000000000351013761647206022543 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LAZYPLAINTEXTEDIT_H #define LAZYPLAINTEXTEDIT_H #include class LazyPlainTextEdit : public QPlainTextEdit { Q_OBJECT public: enum struct TextCursorPosition { Keep, ForceEnd }; explicit LazyPlainTextEdit(QWidget *parent = 0); void updateCursor(TextCursorPosition position); public slots: void append(const QString &text); virtual void clear(); virtual void setVisible ( bool visible ); protected: void timerEvent(QTimerEvent *event); private: int m_timerId; QString m_cachedOutput; }; #endif // LAZYPLAINTEXTEDIT_H qt-installer-framework-4.0.1/src/libs/installer/lib7z_create.h0100777000000000000000000000455013761647206021344 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LIB7Z_CREATE_H #define LIB7Z_CREATE_H #include "installer_global.h" #include #include <7zip/UI/Common/Update.h> QT_BEGIN_NAMESPACE class QFileDevice; class QStringList; QT_END_NAMESPACE namespace Lib7z { enum struct TmpFile { No, Yes }; enum struct Compression { Non = 0, Fastest = 1, Fast = 3, Normal = 5, Maximum = 7, Ultra = 9 }; class INSTALLER_EXPORT UpdateCallback : public IUpdateCallbackUI2, public CMyUnknownImp { Q_DISABLE_COPY(UpdateCallback) public: UpdateCallback() = default; virtual ~UpdateCallback() {} MY_UNKNOWN_IMP INTERFACE_IUpdateCallbackUI2(;) }; void INSTALLER_EXPORT createArchive(QFileDevice *archive, const QStringList &sources, Compression level = Compression::Normal, UpdateCallback *callback = 0); void INSTALLER_EXPORT createArchive(const QString &archive, const QStringList &sources, TmpFile mode, Compression level = Compression::Normal, UpdateCallback *callback = 0); } // namespace Lib7z #endif // LIB7Z_CREATE_H qt-installer-framework-4.0.1/src/libs/installer/lib7z_extract.h0100777000000000000000000000621113761647206021547 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LIB7Z_EXTRACT_H #define LIB7Z_EXTRACT_H #include "installer_global.h" #include #include <7zip/Archive/IArchive.h> #include class CArc; QT_BEGIN_NAMESPACE class QFileDevice; QT_END_NAMESPACE namespace Lib7z { class INSTALLER_EXPORT ExtractCallback : public IArchiveExtractCallback, public CMyUnknownImp { Q_DISABLE_COPY(ExtractCallback) public: ExtractCallback() = default; virtual ~ExtractCallback() = default; void setArchive(CArc *carc) { arc = carc; } void setTarget(const QString &dir) { targetDir = dir; } MY_UNKNOWN_IMP INTERFACE_IArchiveExtractCallback(;) protected: virtual bool prepareForFile(const QString & /*filename*/) { return true; } virtual void setCurrentFile(const QString &filename) { Q_UNUSED(filename) } virtual HRESULT setCompleted(quint64 /*completed*/, quint64 /*total*/) { return S_OK; } private: CArc *arc = 0; QString targetDir; quint64 total = 0; quint64 completed = 0; quint32 currentIndex = 0; }; void INSTALLER_EXPORT extractArchive(QFileDevice *archive, const QString &targetDirectory, ExtractCallback *callback = 0); } // namespace Lib7z #endif // LIB7Z_EXTRACT_H qt-installer-framework-4.0.1/src/libs/installer/lib7z_facade.cpp0100777000000000000000000011271113761647206021636 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "lib7z_facade.h" #include "errors.h" #include "fileio.h" #include "lib7z_create.h" #include "lib7z_extract.h" #include "lib7z_list.h" #include "lib7z_guid.h" #include "globals.h" #ifndef Q_OS_WIN # include "StdAfx.h" #endif #include <7zCrc.h> #include <7zip/Archive/IArchive.h> #include <7zip/UI/Common/ArchiveCommandLine.h> #include <7zip/UI/Common/OpenArchive.h> #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN HINSTANCE g_hInstance = nullptr; # define S_IFMT 00170000 # define S_IFLNK 0120000 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) # define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ # if !defined(Q_CC_MINGW) # include // for localtime_s # endif #else extern "C" int global_use_utf16_conversion; #include #include #endif namespace NArchive { namespace N7z { void registerArcDec7z(); } namespace NXz { void registerArcxz(); } namespace NSplit { void registerArcSplit(); } namespace NLzma { namespace NLzmaAr { void registerArcLzma(); } namespace NLzma86Ar { void registerArcLzma86(); } } } using namespace NWindows; void registerCodecBCJ(); void registerCodecBCJ2(); void registerCodecLZMA(); void registerCodecLZMA2(); void registerCodecCopy(); void registerCodecDelta(); void registerCodecBranch(); void registerCodecByteSwap(); namespace Lib7z { /*! \fn void Lib7z::PercentPrinter::PrintRatio() Prints ratio. */ /*! \fn void Lib7z::PercentPrinter::ClosePrint() Closes print. */ /*! \fn void Lib7z::PercentPrinter::RePrintRatio() Reprints ratio. */ /*! \fn void Lib7z::PercentPrinter::PrintNewLine() Prints new line. */ /*! \fn void Lib7z::PercentPrinter::PrintString(const char *s) Prints string \a s. */ /*! \fn void Lib7z::PercentPrinter::PrintString(const wchar_t *s) Prints string \a s. */ /*! \fn bool Lib7z::operator==(const File &lhs, const File &rhs); Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false. */ // -- 7z init codecs, archives std::once_flag gOnceFlag; void initSevenZ() { std::call_once(gOnceFlag, [] { CrcGenerateTable(); registerCodecBCJ(); registerCodecBCJ2(); registerCodecLZMA(); registerCodecLZMA2(); registerCodecCopy(); registerCodecDelta(); registerCodecBranch(); registerCodecByteSwap(); NArchive::N7z::registerArcDec7z(); NArchive::NXz::registerArcxz(); NArchive::NSplit::registerArcSplit(); NArchive::NLzma::NLzmaAr::registerArcLzma(); NArchive::NLzma::NLzma86Ar::registerArcLzma86(); #ifndef Q_OS_WIN # ifdef ENV_HAVE_LOCALE const QByteArray locale = qgetenv("LC_ALL").toUpper(); if (!locale.isEmpty() && (locale != "C") && (locale != "POSIX")) global_use_utf16_conversion = 1; # elif defined(LOCALE_IS_UTF8) global_use_utf16_conversion = 1; # else global_use_utf16_conversion = 0; # endif #endif }); } // -- error handling Q_GLOBAL_STATIC(QString, getLastErrorString) Q_GLOBAL_STATIC(QReadWriteLock, lastErrorReadWriteLock) QString lastError() { QReadLocker locker(lastErrorReadWriteLock()); Q_UNUSED(locker) return *getLastErrorString(); } void setLastError(const QString &errorString) { QWriteLocker locker(lastErrorReadWriteLock()); Q_UNUSED(locker) *getLastErrorString() = errorString; } QString errorMessageFrom7zResult(const LONG &extractResult) { if (!lastError().isEmpty()) return lastError(); QString errorMessage = QCoreApplication::translate("Lib7z", "internal code: %1"); switch (extractResult) { case S_OK: qFatal("S_OK value is not a valid error code."); break; case E_NOTIMPL: errorMessage = errorMessage.arg(QLatin1String("E_NOTIMPL")); break; case E_NOINTERFACE: errorMessage = errorMessage.arg(QLatin1String("E_NOINTERFACE")); break; case E_ABORT: errorMessage = errorMessage.arg(QLatin1String("E_ABORT")); break; case E_FAIL: errorMessage = errorMessage.arg(QLatin1String("E_FAIL")); break; case STG_E_INVALIDFUNCTION: errorMessage = errorMessage.arg(QLatin1String("STG_E_INVALIDFUNCTION")); break; case E_OUTOFMEMORY: errorMessage = QCoreApplication::translate("Lib7z", "not enough memory"); break; case E_INVALIDARG: errorMessage = errorMessage.arg(QLatin1String("E_INVALIDARG")); break; default: errorMessage = QCoreApplication::translate("Lib7z", "Error: %1").arg(extractResult); break; } return errorMessage; } /* RAII class to create a directory (tryCreate()) and delete it on destruction unless released. */ struct DirectoryGuard { explicit DirectoryGuard(const QString &path) : m_path(path) , m_created(false) , m_released(false) { m_path.replace(QLatin1Char('\\'), QLatin1Char('/')); } ~DirectoryGuard() { if (!m_created || m_released) return; QDir dir(m_path); if (!dir.rmdir(m_path)) qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot delete directory " << m_path; } /* Tries to create the directory structure. Returns a list of every directory created. */ QStringList tryCreate() { if (m_path.isEmpty()) return QStringList(); const QFileInfo fi(m_path); if (fi.exists() && fi.isDir()) return QStringList(); if (fi.exists() && !fi.isDir()) { throw SevenZipException(QCoreApplication::translate("DirectoryGuard", "Path \"%1\" exists but is not a directory.").arg(QDir::toNativeSeparators(m_path))); } QStringList created; QDir toCreate(m_path); while (!toCreate.exists()) { QString p = toCreate.absolutePath(); created.push_front(p); p = p.section(QLatin1Char('/'), 0, -2); toCreate = QDir(p); } QDir dir(m_path); m_created = dir.mkpath(m_path); if (!m_created) { throw SevenZipException(QCoreApplication::translate("DirectoryGuard", "Cannot create directory \"%1\".").arg(QDir::toNativeSeparators(m_path))); } return created; } void release() { m_released = true; } QString m_path; bool m_created; bool m_released; }; static UString QString2UString(const QString &str) { return str.toStdWString().c_str(); } static QString UString2QString(const UString& str) { return QString::fromStdWString(static_cast(str)); } static NCOM::CPropVariant readProperty(IInArchive *archive, int index, int propId) { NCOM::CPropVariant prop; if (archive->GetProperty(index, propId, &prop) != S_OK) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot retrieve property %1 for item %2.").arg(QString::number(propId), QString::number(index))); } return prop; } static bool IsFileTimeZero(const FILETIME *lpFileTime) { return (lpFileTime->dwLowDateTime == 0) && (lpFileTime->dwHighDateTime == 0); } static bool getFileTimeFromProperty(IInArchive* archive, int index, int propId, FILETIME *ft) { const NCOM::CPropVariant prop = readProperty(archive, index, propId); if (prop.vt != VT_FILETIME) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Property %1 for item %2 not of type VT_FILETIME but %3.").arg(QString::number(propId), QString::number(index), QString::number(prop.vt))); } *ft = prop.filetime; return !IsFileTimeZero(ft); } static bool getDateTimeProperty(IInArchive *arc, int index, int id, QDateTime *value) { FILETIME ft7z; if (!getFileTimeFromProperty(arc, index, id, &ft7z)) return false; SYSTEMTIME st; if (!BOOLToBool(FileTimeToSystemTime(&ft7z, &st))) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot convert UTC file time to system time.")); } *value = QDateTime(QDate(st.wYear, st.wMonth, st.wDay), QTime(st.wHour, st.wMinute, st.wSecond), Qt::UTC); return value->isValid(); } static quint64 getUInt64Property(IInArchive *archive, int index, int propId, quint64 defaultValue) { UInt64 value; if (ConvertPropVariantToUInt64(readProperty(archive, index, propId), value)) return value; return defaultValue; } static quint32 getUInt32Property(IInArchive *archive, int index, int propId, quint32 defaultValue) { const NCOM::CPropVariant prop = readProperty(archive, index, propId); if (prop.vt == VT_EMPTY) return defaultValue; return static_cast(prop.ulVal); } static QFile::Permissions getPermissions(IInArchive *archive, int index, bool *hasPermissions) { quint32 attributes = getUInt32Property(archive, index, kpidAttrib, 0); QFile::Permissions permissions = nullptr; if (attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) { if (hasPermissions != nullptr) *hasPermissions = true; // filter the Unix permissions attributes = (attributes >> 16) & 0777; permissions |= static_cast((attributes & 0700) << 2); // owner rights permissions |= static_cast((attributes & 0070) << 1); // group permissions |= static_cast((attributes & 0007) << 0); // and world rights } else if (hasPermissions != nullptr) { *hasPermissions = false; } return permissions; } #define LIB7Z_ASSERTS(X, MODE) \ Q_ASSERT(X); \ Q_ASSERT(X->isOpen()); \ Q_ASSERT(X->is ## MODE()); \ Q_ASSERT(!X->isSequential()); class QIODeviceSequentialOutStream : public ISequentialOutStream, public CMyUnknownImp { Q_DISABLE_COPY(QIODeviceSequentialOutStream) public: MY_UNKNOWN_IMP explicit QIODeviceSequentialOutStream(std::unique_ptr device) : ISequentialOutStream() , m_device(std::move(device)) { LIB7Z_ASSERTS(m_device, Writable) } QString errorString() const { return m_errorString; } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; const qint64 written = m_device->write(reinterpret_cast(data), size); if (written == -1) { m_errorString = m_device->errorString(); return E_FAIL; } if (processedSize) *processedSize = written; m_errorString.clear(); return S_OK; } private: QString m_errorString; std::unique_ptr m_device; }; class QIODeviceInStream : public IInStream, public CMyUnknownImp { Q_DISABLE_COPY(QIODeviceInStream) public: MY_UNKNOWN_IMP explicit QIODeviceInStream(QIODevice *device) : IInStream() , CMyUnknownImp() , m_device(device) { LIB7Z_ASSERTS(m_device, Readable) } STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) { if (m_device.isNull()) return E_FAIL; const qint64 actual = m_device->read(reinterpret_cast(data), size); Q_ASSERT(actual != 0 || m_device->atEnd()); if (processedSize) *processedSize = actual; return actual >= 0 ? S_OK : E_FAIL; } STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { if (m_device.isNull()) return E_FAIL; if (seekOrigin > STREAM_SEEK_END) return STG_E_INVALIDFUNCTION; UInt64 np = 0; switch (seekOrigin) { case STREAM_SEEK_SET: np = offset; break; case STREAM_SEEK_CUR: np = m_device->pos() + offset; break; case STREAM_SEEK_END: np = m_device->size() + offset; break; default: return STG_E_INVALIDFUNCTION; } np = qBound(static_cast(0), np, static_cast(m_device->size())); const bool ok = m_device->seek(np); if (newPosition) *newPosition = np; return ok ? S_OK : E_FAIL; } private: QPointer m_device; }; bool operator==(const File &lhs, const File &rhs) { return lhs.path == rhs.path && lhs.utcTime == rhs.utcTime && lhs.isDirectory == rhs.isDirectory && lhs.compressedSize == rhs.compressedSize && lhs.uncompressedSize == rhs.uncompressedSize && (lhs.permissions == rhs.permissions || lhs.permissions == static_cast(-1) || rhs.permissions == static_cast(-1)); } QVector listArchive(QFileDevice *archive) { LIB7Z_ASSERTS(archive, Readable) const qint64 initialPos = archive->pos(); try { CCodecs codecs; if (codecs.Load() != S_OK) throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot load codecs.")); COpenOptions op; op.codecs = &codecs; CObjectVector types; op.types = &types; // Empty, because we use a stream. CIntVector excluded; op.excludedFormats = &excluded; const CMyComPtr stream = new QIODeviceInStream(archive); op.stream = stream; // CMyComPtr is needed, otherwise it crashes in OpenStream(). CObjectVector properties; op.props = &properties; CArchiveLink archiveLink; if (archiveLink.Open2(op, nullptr) != S_OK) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot open archive \"%1\".").arg(archive->fileName())); } QVector flat; for (unsigned i = 0; i < archiveLink.Arcs.Size(); ++i) { IInArchive *const arch = archiveLink.Arcs[i].Archive; UInt32 numItems = 0; if (arch->GetNumberOfItems(&numItems) != S_OK) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot retrieve number of items in archive.")); } flat.reserve(flat.size() + numItems); for (uint item = 0; item < numItems; ++item) { UString s; if (archiveLink.Arcs[i].GetItemPath(item, s) != S_OK) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot retrieve path of archive item \"%1\".").arg(item)); } File f; f.archiveIndex.setX(i); f.archiveIndex.setY(item); f.path = UString2QString(s).replace(QLatin1Char('\\'), QLatin1Char('/')); Archive_IsItem_Folder(arch, item, f.isDirectory); f.permissions = getPermissions(arch, item, nullptr); getDateTimeProperty(arch, item, kpidMTime, &(f.utcTime)); f.uncompressedSize = getUInt64Property(arch, item, kpidSize, 0); f.compressedSize = getUInt64Property(arch, item, kpidPackSize, 0); flat.append(f); } } return flat; } catch (const char *err) { archive->seek(initialPos); throw SevenZipException(err); } catch (const SevenZipException &e) { archive->seek(initialPos); throw e; // re-throw unmodified } catch (...) { archive->seek(initialPos); throw SevenZipException(QCoreApplication::translate("Lib7z", "Unknown exception caught (%1).").arg(QString::fromLatin1(Q_FUNC_INFO))); } return QVector(); // never reached } // -- ExtractCallback STDMETHODIMP ExtractCallback::SetTotal(UInt64 t) { total = t; return S_OK; } STDMETHODIMP ExtractCallback::SetCompleted(const UInt64 *c) { completed = *c; if (total > 0) return setCompleted(completed, total); return S_OK; } // this method will be called by CFolderOutStream::OpenFile to stream via // CDecoder::CodeSpec extracted content to an output stream. STDMETHODIMP ExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 /*askExtractMode*/) { *outStream = nullptr; if (targetDir.isEmpty()) return E_FAIL; Q_ASSERT(arc); currentIndex = index; UString s; if (arc->GetItemPath(index, s) != S_OK) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot retrieve path of archive item %1.").arg(index)); return E_FAIL; } const QFileInfo fi(QString::fromLatin1("%1/%2").arg(targetDir, UString2QString(s))); DirectoryGuard guard(fi.absolutePath()); const QStringList directories = guard.tryCreate(); bool isDir = false; Archive_IsItem_Folder(arc->Archive, index, isDir); if (isDir) QDir(fi.absolutePath()).mkdir(fi.fileName()); // this makes sure that all directories created get removed as well foreach (const QString &directory, directories) setCurrentFile(directory); if (!isDir && !prepareForFile(fi.absoluteFilePath())) return E_FAIL; setCurrentFile(fi.absoluteFilePath()); if (!isDir) { #ifndef Q_OS_WIN // do not follow symlinks, so we need to remove an existing one if (fi.isSymLink() && (!QFile::remove(fi.absoluteFilePath()))) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot remove already existing symlink %1.").arg(fi.absoluteFilePath())); return E_FAIL; } #endif std::unique_ptr file(new QFile(fi.absoluteFilePath())); if (!file->open(QIODevice::WriteOnly)) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(fi.absoluteFilePath()), file->errorString())); return E_FAIL; } CMyComPtr stream = new QIODeviceSequentialOutStream(std::move(file)); *outStream = stream.Detach(); // CMyComPtr is needed, otherwise it crashes in Write(). } guard.release(); return S_OK; } STDMETHODIMP ExtractCallback::PrepareOperation(Int32 /*askExtractMode*/) { return S_OK; } STDMETHODIMP ExtractCallback::SetOperationResult(Int32 /*resultEOperationResult*/) { if (targetDir.isEmpty()) return S_OK; UString s; if (arc->GetItemPath(currentIndex, s) != S_OK) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot retrieve path of archive item %1.").arg(currentIndex)); return E_FAIL; } const QString absFilePath = QFileInfo(QString::fromLatin1("%1/%2").arg(targetDir, UString2QString(s).replace(QLatin1Char('\\'), QLatin1Char('/')))).absoluteFilePath(); // do we have a symlink? const quint32 attributes = getUInt32Property(arc->Archive, currentIndex, kpidAttrib, 0); struct stat stat_info; stat_info.st_mode = attributes >> 16; if (S_ISLNK(stat_info.st_mode)) { #ifdef Q_OS_WIN qFatal(QString::fromLatin1("Creating a link from archive is not implemented for " "windows. Link filename: %1").arg(absFilePath).toLatin1()); // TODO //if (!NFile::NDir::MyCreateHardLink(CFSTR(QDir::toNativeSeparators(absFilePath).utf16()), // CFSTR(QDir::toNativeSeparators(symlinkTarget).utf16())) { // return S_FALSE; //} #else QFileInfo symlinkPlaceHolderFileInfo(absFilePath); if (symlinkPlaceHolderFileInfo.isSymLink()) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot create symlink at \"%1\". Another one is already existing.") .arg(absFilePath)); return E_FAIL; } QFile symlinkPlaceHolderFile(absFilePath); if (!symlinkPlaceHolderFile.open(QIODevice::ReadOnly)) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot read symlink target from file \"%1\".").arg(absFilePath)); return E_FAIL; } const QByteArray symlinkTarget = symlinkPlaceHolderFile.readAll(); symlinkPlaceHolderFile.close(); symlinkPlaceHolderFile.remove(); QFile targetFile(QString::fromLatin1(symlinkTarget)); if (!targetFile.link(absFilePath)) { setLastError(QCoreApplication::translate("ExtractCallbackImpl", "Cannot create symlink at %1: %2").arg(absFilePath, targetFile.errorString())); return E_FAIL; } return S_OK; #endif } try { // Note: This part might also fail while running a elevated installation. if (!absFilePath.isEmpty()) { // This might fail for archives without all properties, we can only be sure // about modification time, as it's always stored by default in 7z archives. // Also note that we restore modification time on Unix only, as access time // and change time are supposed to be set to the time of installation. FILETIME mTime; const UString fileName = QString2UString(absFilePath); if (getFileTimeFromProperty(arc->Archive, currentIndex, kpidMTime, &mTime)) { NWindows::NFile::NIO::COutFile file; if (file.Open(fileName, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL)) file.SetTime(&mTime, &mTime, &mTime); } #ifdef Q_OS_WIN FILETIME cTime, aTime; if (getFileTimeFromProperty(arc->Archive, currentIndex, kpidCTime, &cTime) && getFileTimeFromProperty(arc->Archive, currentIndex, kpidATime, &aTime)) { NWindows::NFile::NIO::COutFile file; if (file.Open(fileName, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL)) file.SetTime(&cTime, &aTime, &mTime); } #endif } } catch (...) {} bool hasPerm = false; const QFile::Permissions permissions = getPermissions(arc->Archive, currentIndex, &hasPerm); if (hasPerm) QFile::setPermissions(absFilePath, permissions); return S_OK; } /*! \enum Lib7z::TmpFile This enum type holds the temp file mode: \value No File is not a temporary file. \value Yes File is a tmp file. */ /*! \enum Lib7z::Compression This enum specifies the compression ratio of an archive: \value Non \value Fastest \value Fast \value Normal \value Maximum \value Ultra */ /*! \namespace Lib7z \inmodule QtInstallerFramework \brief The Lib7z namespace contains miscellaneous identifiers used throughout the Lib7z library. */ /*! \fn virtual bool Lib7z::ExtractCallback::prepareForFile(const QString &filename) Implement to prepare for file \a filename to be extracted, e.g. by renaming existing files. Return \c true if the preparation was successful and extraction can be continued. If \c false is returned, the extraction will be aborted. The default implementation returns \c true. */ /*! \fn bool Lib7z::ExtractCallback::setArchive(CArc *carc) Sets \a carc as archive. */ /*! \fn void Lib7z::ExtractCallback::setTarget(const QString &dir) Sets the target directory to \a dir. */ /*! \fn void Lib7z::ExtractCallback::setCurrentFile(const QString &filename) Sets the current file to \a filename. */ /*! \fn virtual Lib7z::ExtractCallback::setCompleted(quint64 completed, quint64 total) Always returns \c true. \c completed and \c total are unused. */ // -- UpdateCallback HRESULT UpdateCallback::SetTotal(UInt64) { return S_OK; } HRESULT UpdateCallback::SetCompleted(const UInt64*) { return S_OK; } HRESULT UpdateCallback::SetRatioInfo(const UInt64*, const UInt64*) { return S_OK; } HRESULT UpdateCallback::CheckBreak() { return S_OK; } HRESULT UpdateCallback::Finilize() { return S_OK; } HRESULT UpdateCallback::SetNumFiles(UInt64) { return S_OK; } HRESULT UpdateCallback::GetStream(const wchar_t*, bool) { return S_OK; } HRESULT UpdateCallback::OpenFileError(const wchar_t*, DWORD) { return S_OK; } HRESULT UpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) { *password = nullptr; *passwordIsDefined = false; return S_OK; } HRESULT UpdateCallback::CryptoGetTextPassword(BSTR *password) { *password = nullptr; return E_NOTIMPL; } HRESULT UpdateCallback::OpenResult(const wchar_t*, HRESULT, const wchar_t*) { return S_OK; } HRESULT UpdateCallback::StartScanning() { return S_OK; } HRESULT UpdateCallback::ScanProgress(UInt64, UInt64, UInt64, const wchar_t*, bool) { return S_OK; } HRESULT UpdateCallback::CanNotFindError(const wchar_t*, DWORD) { return S_OK; } HRESULT UpdateCallback::FinishScanning() { return S_OK; } HRESULT UpdateCallback::StartArchive(const wchar_t*, bool) { return S_OK; } HRESULT UpdateCallback::FinishArchive() { return S_OK; } HRESULT UpdateCallback::SetOperationResult(Int32) { return S_OK; } /* Function to create an empty 7z container. Using a temporary file only is not working, since 7z checks the output file for a valid signature, otherwise it rejects overwriting the file. */ static QString createTmp7z() { QTemporaryFile file; if (!file.open()) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot create " "temporary file: %1").arg(file.errorString())); } file.write(QByteArray::fromHex("377A.BCAF.271C" // Signature. ".0003.8D9B.D50F.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000" // Crc + Data. )); file.setAutoRemove(false); return file.fileName(); } /*! Creates an archive using the given file device \a archive. \a sources can contain one or more files, one or more directories or a combination of files and folders. Also, \c * wildcard is supported. The value of \a level specifies the compression ratio, the default is set to \c 5 (Normal compression). The \a callback can be used to get information about the archive creation process. If no \a callback is given, an empty implementation is used. \note Throws SevenZipException on error. \note Filenames are stored case-sensitive with UTF-8 encoding. \note The ownership of \a callback is transferred to the function and gets delete on exit. */ void INSTALLER_EXPORT createArchive(QFileDevice *archive, const QStringList &sources, Compression level, UpdateCallback *callback) { LIB7Z_ASSERTS(archive, Writable) const QString tmpArchive = createTmp7z(); Lib7z::createArchive(tmpArchive, sources, TmpFile::No, level, callback); try { QFile source(tmpArchive); QInstaller::openForRead(&source); QInstaller::blockingCopy(&source, archive, source.size()); } catch (const QInstaller::Error &error) { throw SevenZipException(error.message()); } } /*! Creates an archive with the given filename \a archive. \a sources can contain one or more files, one or more directories or a combination of files and folders. Also, \c * wildcard is supported. To be able to use the function during an elevated installation, set \a mode to \c TmpFile::Yes. The value of \a level specifies the compression ratio, the default is set to \c 5 (Normal compression). The \a callback can be used to get information about the archive creation process. If no \a callback is given, an empty implementation is used. \note Throws SevenZipException on error. \note If \a archive exists, it will be overwritten. \note Filenames are stored case-sensitive with UTF-8 encoding. \note The ownership of \a callback is transferred to the function and gets delete on exit. */ void createArchive(const QString &archive, const QStringList &sources, TmpFile mode, Compression level, UpdateCallback *callback) { try { QString target = archive; if (mode == TmpFile::Yes) target = createTmp7z(); CArcCmdLineOptions options; try { UStringVector commandStrings; commandStrings.Add(L"a"); // mode: add commandStrings.Add(L"-t7z"); // type: 7z commandStrings.Add(L"-mtm=on"); // time: modeifier|creation|access commandStrings.Add(L"-mtc=on"); commandStrings.Add(L"-mta=on"); commandStrings.Add(L"-mmt=on"); // threads: multi-threaded #ifdef Q_OS_WIN commandStrings.Add(L"-sccUTF-8"); // files: case-sensitive|UTF8 #endif commandStrings.Add(QString2UString(QString::fromLatin1("-mx=%1").arg(int(level)))); // compression: level commandStrings.Add(QString2UString(QDir::toNativeSeparators(target))); foreach (const QString &source, sources) commandStrings.Add(QString2UString(source)); CArcCmdLineParser parser; parser.Parse1(commandStrings, options); parser.Parse2(options); } catch (const CArcCmdLineException &e) { throw SevenZipException(UString2QString(e)); } CCodecs codecs; if (codecs.Load() != S_OK) throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot load codecs.")); CObjectVector types; if (!ParseOpenTypes(codecs, options.ArcType, types)) throw SevenZipException(QCoreApplication::translate("Lib7z", "Unsupported archive type.")); CUpdateErrorInfo errorInfo; CMyComPtr comCallback = callback == 0 ? new UpdateCallback : callback; const HRESULT res = UpdateArchive(&codecs, types, options.ArchiveName, options.Censor, options.UpdateOptions, errorInfo, nullptr, comCallback, true); const QFile tempFile(UString2QString(options.ArchiveName)); if (res != S_OK || !tempFile.exists()) { QString errorMsg; if (res == S_OK) { errorMsg = QCoreApplication::translate("Lib7z", "Cannot create archive \"%1\"") .arg(QDir::toNativeSeparators(tempFile.fileName())); } else { errorMsg = QCoreApplication::translate("Lib7z", "Cannot create archive \"%1\": %2") .arg(QDir::toNativeSeparators(tempFile.fileName()), errorMessageFrom7zResult(res)); } throw SevenZipException(errorMsg); } if (mode == TmpFile::Yes) { QFile org(archive); if (org.exists() && !org.remove()) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot remove " "old archive \"%1\": %2").arg(QDir::toNativeSeparators(org.fileName()), org.errorString())); } QFile arc(UString2QString(options.ArchiveName)); if(!arc.rename(archive)) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot rename " "temporary archive \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(arc.fileName()), QDir::toNativeSeparators(archive), arc.errorString())); } } } catch (const char *err) { throw SevenZipException(err); } catch (SevenZipException &e) { throw e; // re-throw unmodified } catch (const QInstaller::Error &err) { throw SevenZipException(err.message()); } catch (...) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Unknown exception caught (%1)").arg(QString::fromLatin1(Q_FUNC_INFO))); } } /*! Extracts the given \a archive content into target directory \a directory using the provided extract callback \a callback. The output filenames are deduced from the \a archive content. \note Throws SevenZipException on error. \note The ownership of \a callback is not transferred to the function. */ void extractArchive(QFileDevice *archive, const QString &directory, ExtractCallback *callback) { LIB7Z_ASSERTS(archive, Readable) // Guard a given object against unwanted delete. CMyComPtr externCallback = callback; CMyComPtr localCallback; if (!externCallback) { callback = new ExtractCallback; localCallback = callback; } DirectoryGuard outDir(QFileInfo(directory).absolutePath()); try { outDir.tryCreate(); CCodecs codecs; if (codecs.Load() != S_OK) throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot load codecs.")); COpenOptions op; op.codecs = &codecs; CObjectVector types; op.types = &types; // Empty, because we use a stream. CIntVector excluded; op.excludedFormats = &excluded; const CMyComPtr stream = new QIODeviceInStream(archive); op.stream = stream; // CMyComPtr is needed, otherwise it crashes in OpenStream(). CObjectVector properties; op.props = &properties; CArchiveLink archiveLink; if (archiveLink.Open2(op, nullptr) != S_OK) { throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot open archive \"%1\".").arg(archive->fileName())); } callback->setTarget(directory); for (unsigned a = 0; a < archiveLink.Arcs.Size(); ++a) { callback->setArchive(&archiveLink.Arcs[a]); IInArchive *const arch = archiveLink.Arcs[a].Archive; const LONG result = arch->Extract(0, static_cast(-1), false, callback); if (result != S_OK) throw SevenZipException(errorMessageFrom7zResult(result)); } } catch (const SevenZipException &e) { externCallback.Detach(); throw e; // re-throw unmodified } catch (...) { externCallback.Detach(); throw SevenZipException(QCoreApplication::translate("Lib7z", "Unknown exception caught (%1).").arg(QString::fromLatin1(Q_FUNC_INFO))); } outDir.release(); externCallback.Detach(); } /*! Returns \c true if the given \a archive is supported; otherwise returns \c false. \note Throws SevenZipException on error. */ bool isSupportedArchive(QFileDevice *archive) { LIB7Z_ASSERTS(archive, Readable) const qint64 initialPos = archive->pos(); try { CCodecs codecs; if (codecs.Load() != S_OK) throw SevenZipException(QCoreApplication::translate("Lib7z", "Cannot load codecs.")); COpenOptions op; op.codecs = &codecs; CObjectVector types; op.types = &types; // Empty, because we use a stream. CIntVector excluded; op.excludedFormats = &excluded; const CMyComPtr stream = new QIODeviceInStream(archive); op.stream = stream; // CMyComPtr is needed, otherwise it crashes in OpenStream(). CObjectVector properties; op.props = &properties; CArchiveLink archiveLink; const HRESULT result = archiveLink.Open2(op, nullptr); archive->seek(initialPos); return result == S_OK; } catch (const char *err) { archive->seek(initialPos); throw SevenZipException(err); } catch (const SevenZipException &e) { archive->seek(initialPos); throw e; // re-throw unmodified } catch (...) { archive->seek(initialPos); throw SevenZipException(QCoreApplication::translate("Lib7z", "Unknown exception caught (%1).").arg(QString::fromLatin1(Q_FUNC_INFO))); } return false; // never reached } /*! Returns \c true if the given \a archive is supported; otherwise returns \c false. \note Throws SevenZipException on error. */ bool isSupportedArchive(const QString &archive) { QFile file(archive); if (!file.open(QIODevice::ReadOnly)) return false; return isSupportedArchive(&file); } } // namespace Lib7z qt-installer-framework-4.0.1/src/libs/installer/lib7z_facade.h0100777000000000000000000000514613761647206021306 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LIB7Z_FACADE_H #define LIB7Z_FACADE_H #include "installer_global.h" #include "errors.h" #include #include <7zip/UI/Console/PercentPrinter.h> QT_BEGIN_NAMESPACE class QFileDevice; QT_END_NAMESPACE namespace Lib7z { void INSTALLER_EXPORT initSevenZ(); bool INSTALLER_EXPORT isSupportedArchive(QFileDevice *archive); bool INSTALLER_EXPORT isSupportedArchive(const QString &archive); class INSTALLER_EXPORT SevenZipException : public QInstaller::Error { public: explicit SevenZipException(const QString &msg) : QInstaller::Error(msg) {} explicit SevenZipException(const char *msg) : QInstaller::Error(QString::fromLocal8Bit(msg)) {} }; class INSTALLER_EXPORT PercentPrinter : public CPercentPrinter { public: PercentPrinter() : CPercentPrinter(1 << 16) { OutStream = &g_StdOut; } void PrintRatio() { CPercentPrinter::PrintRatio(); } void ClosePrint() { CPercentPrinter::ClosePrint(); } void RePrintRatio() { CPercentPrinter::RePrintRatio(); } void PrintNewLine() { CPercentPrinter::PrintNewLine(); } void PrintString(const char *s) { CPercentPrinter::PrintString(s); } void PrintString(const wchar_t *s) { CPercentPrinter::PrintString(s); } }; } // namespace Lib7z #endif // LIB7Z_FACADE_H qt-installer-framework-4.0.1/src/libs/installer/lib7z_guid.h0100777000000000000000000001165613761647206021036 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LIB7Z_GUID_H #define LIB7Z_GUID_H #include #ifdef __cplusplus #define DEFINE_7Z_GUID(name, b4, b5, b6) extern "C" const GUID IID_ ## name = { 0x23170F69, \ 0x40C1, 0x278A, { 0x00, 0x00, 0x00, b4, b5, b6, 0x00, 0x00 } } #else #define DEFINE_7Z_GUID(name, b4, b5, b6) extern const GUID IID_ ## name = { 0x23170F69, \ 0x40C1, 0x278A, { 0x00, 0x00, 0x00, b4, b5, b6, 0x00, 0x00 } } #endif DEFINE_7Z_GUID(IInArchiveGetStream, 0x06, 0x00, 0x40); DEFINE_7Z_GUID(IInArchive, 0x06, 0x00, 0x60); DEFINE_7Z_GUID(IOutStream, 0x03, 0x00, 0x04); DEFINE_7Z_GUID(IOutStreamFlush, 0x03, 0x00, 0x07); DEFINE_7Z_GUID(IOutArchive, 0x06, 0x00, 0xA0); DEFINE_7Z_GUID(IInStream, 0x03, 0x00, 0x03); DEFINE_7Z_GUID(ISetProperties, 0x06, 0x00, 0x03); DEFINE_7Z_GUID(ISequentialInStream, 0x03, 0x00, 0x01); DEFINE_7Z_GUID(ISequentialOutStream, 0x03, 0x00, 0x02); DEFINE_7Z_GUID(IStreamGetSize, 0x03, 0x00, 0x06); DEFINE_7Z_GUID(IStreamGetProps, 0x03, 0x00, 0x08); DEFINE_7Z_GUID(IStreamGetProps2, 0x03, 0x00, 0x09); DEFINE_7Z_GUID(IArchiveKeepModeForNextOpen, 0x06, 0x00, 0x04); DEFINE_7Z_GUID(IArchiveAllowTail, 0x06, 0x00, 0x05); DEFINE_7Z_GUID(IArchiveOpenCallback, 0x06, 0x00, 0x10); DEFINE_7Z_GUID(IArchiveExtractCallback, 0x06, 0x00, 0x20); DEFINE_7Z_GUID(IArchiveOpenVolumeCallback, 0x06, 0x00, 0x30); DEFINE_7Z_GUID(IArchiveOpenSetSubArchiveName, 0x06, 0x00, 0x50); DEFINE_7Z_GUID(IArchiveOpenSeq, 0x06, 0x00, 0x61); DEFINE_7Z_GUID(IArchiveGetRawProps, 0x06, 0x00, 0x70); DEFINE_7Z_GUID(IArchiveGetRootProps, 0x06, 0x00, 0x71); DEFINE_7Z_GUID(IArchiveUpdateCallback, 0x06, 0x00, 0x80); DEFINE_7Z_GUID(IArchiveUpdateCallback2, 0x06, 0x00, 0x82); DEFINE_7Z_GUID(ICompressProgressInfo, 0x04, 0x00, 0x04); DEFINE_7Z_GUID(ICompressCoder, 0x04, 0x00, 0x05); DEFINE_7Z_GUID(ICompressSetCoderProperties, 0x04, 0x00, 0x20); DEFINE_7Z_GUID(ICompressSetDecoderProperties2, 0x04, 0x00, 0x22); DEFINE_7Z_GUID(ICompressWriteCoderProperties, 0x04, 0x00, 0x23); DEFINE_7Z_GUID(ICompressGetInStreamProcessedSize, 0x04, 0x00, 0x24); DEFINE_7Z_GUID(ICompressSetCoderMt, 0x04, 0x00, 0x25); DEFINE_7Z_GUID(ICompressSetOutStream, 0x04, 0x00, 0x32); DEFINE_7Z_GUID(ICompressSetInStream, 0x04, 0x00, 0x31); DEFINE_7Z_GUID(ICompressSetOutStreamSize, 0x04, 0x00, 0x34); DEFINE_7Z_GUID(ICompressSetBufSize, 0x04, 0x00, 0x35); DEFINE_7Z_GUID(ICompressGetSubStreamSize, 0x04, 0x00, 0x30); DEFINE_7Z_GUID(ICryptoResetInitVector, 0x04, 0x00, 0x8C); DEFINE_7Z_GUID(ICryptoSetPassword, 0x04, 0x00, 0x90); DEFINE_7Z_GUID(ICryptoGetTextPassword, 0x05, 0x00, 0x10); DEFINE_7Z_GUID(ICryptoGetTextPassword2, 0x05, 0x00, 0x11); #undef DEFINE_7Z_GUID #endif // LIB7Z_GUID_H qt-installer-framework-4.0.1/src/libs/installer/lib7z_list.h0100777000000000000000000000474513761647206021062 0ustar00/************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LIB7Z_LIST_H #define LIB7Z_LIST_H #include "installer_global.h" #include #include #include namespace Lib7z { struct INSTALLER_EXPORT File { public: QString path; QDateTime utcTime; QPoint archiveIndex; bool isDirectory = false; quint64 compressedSize = 0; quint64 uncompressedSize = 0; QFile::Permissions permissions = 0; }; INSTALLER_EXPORT bool operator==(const File &lhs, const File &rhs); QVector INSTALLER_EXPORT listArchive(QFileDevice *archive); } // namespace Lib7z #endif // LIB7Z_LIST_H qt-installer-framework-4.0.1/src/libs/installer/licenseoperation.cpp0100777000000000000000000000715513761647206022674 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "licenseoperation.h" #include "packagemanagercore.h" #include "settings.h" #include "fileutils.h" #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::LicenseOperation \internal */ LicenseOperation::LicenseOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("License")); } void LicenseOperation::backup() { } bool LicenseOperation::performOperation() { QVariantMap licenses = value(QLatin1String("licenses")).toMap(); if (licenses.isEmpty()) { setError(UserDefinedError); setErrorString(tr("No license files found to copy.")); return false; } PackageManagerCore *const core = packageManager(); if (!core) { setError( UserDefinedError ); setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); return false; } QString targetDir = QString::fromLatin1("%1%2%3").arg(core->value(scTargetDir), QDir::separator(), QLatin1String("Licenses")); QDir dir; dir.mkpath(targetDir); setDefaultFilePermissions(targetDir, DefaultFilePermissions::Executable); setArguments(QStringList(targetDir)); for (QVariantMap::const_iterator it = licenses.constBegin(); it != licenses.constEnd(); ++it) { QFile file(targetDir + QLatin1Char('/') + it.key()); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { setError(UserDefinedError); setErrorString(tr("Can not write license file \"%1\".").arg(QDir::toNativeSeparators(file.fileName()))); return false; } QTextStream stream(&file); stream << it.value().toString(); } return true; } bool LicenseOperation::undoOperation() { const QVariantMap licenses = value(QLatin1String("licenses")).toMap(); if (licenses.isEmpty()) { setError(UserDefinedError); setErrorString(tr("No license files found to delete.")); return false; } QString targetDir = arguments().value(0); for (QVariantMap::const_iterator it = licenses.begin(); it != licenses.end(); ++it) QFile::remove(targetDir + QDir::separator() + it.key()); QDir dir; dir.rmdir(targetDir); return true; } bool LicenseOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/licenseoperation.h0100777000000000000000000000326513761647206022337 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LICENSEOPERATION_H #define LICENSEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT LicenseOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::LicenseOperation) public: explicit LicenseOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } // namespace QInstaller #endif //LICENSEOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/linereplaceoperation.cpp0100777000000000000000000000661413761647206023534 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "linereplaceoperation.h" #include #include #include using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::LineReplaceOperation \internal */ LineReplaceOperation::LineReplaceOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("LineReplace")); } void LineReplaceOperation::backup() { } bool LineReplaceOperation::performOperation() { // Arguments: // 1. filename // 2. startsWith Search-String // 3. Replace-Line-String if (!checkArgumentCount(3)) return false; const QStringList args = arguments(); const QString fileName = args.at(0); const QString searchString = args.at(1); const QString replaceString = args.at(2); if (searchString.isEmpty()) { setError(InvalidArguments); setErrorString(tr("Invalid argument in %1: Empty search " "argument is not supported.").arg(name())); return false; } QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for reading: %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); return false; } QString replacement; QTextStream stream(&file); while (!stream.atEnd()) { const QString line = stream.readLine(); if (line.trimmed().startsWith(searchString)) replacement.append(replaceString + QLatin1String("\n")); else replacement.append(line + QLatin1String("\n")); } file.close(); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); return false; } stream.setDevice(&file); stream << replacement; file.close(); return true; } bool LineReplaceOperation::undoOperation() { return true; } bool LineReplaceOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/linereplaceoperation.h0100777000000000000000000000330113761647206023167 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LINEREPLACEOPERATION_H #define LINEREPLACEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT LineReplaceOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::LineReplaceOperation) public: explicit LineReplaceOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } // namespace #endif // LINEREPLACEOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/link.cpp0100777000000000000000000002445413761647206020267 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "link.h" #include "utils.h" #include "globals.h" #include #include #include #ifdef Q_OS_UNIX #include #endif #ifdef Q_OS_WIN #include #include #ifndef Q_CC_MINGW # include #endif #if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) #endif class FileHandleWrapper { public: FileHandleWrapper(const QString &path) : m_dirHandle(INVALID_HANDLE_VALUE) { QString normalizedPath = QString(path).replace(QLatin1Char('/'), QLatin1Char('\\')); m_dirHandle = CreateFile((wchar_t*)normalizedPath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (m_dirHandle == INVALID_HANDLE_VALUE) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open" << path << ":" << QInstaller::windowsErrorString(GetLastError()); } } ~FileHandleWrapper() { if (m_dirHandle != INVALID_HANDLE_VALUE) CloseHandle(m_dirHandle); } HANDLE handle() { return m_dirHandle; } private: HANDLE m_dirHandle; }; QString readWindowsSymLink(const QString &path) { QString result; FileHandleWrapper dirHandle(path); if (dirHandle.handle() != INVALID_HANDLE_VALUE) { REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); DWORD bytesReturned = 0; if (::DeviceIoControl(dirHandle.handle(), FSCTL_GET_REPARSE_POINT, nullptr, 0, reparseStructData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, 0)) { if (reparseStructData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { int length = reparseStructData->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); int offset = reparseStructData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); const wchar_t* PathBuffer = &reparseStructData->MountPointReparseBuffer.PathBuffer[offset]; result = QString::fromWCharArray(PathBuffer, length); } else if (reparseStructData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { int length = reparseStructData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); int offset = reparseStructData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); const wchar_t* PathBuffer = &reparseStructData->SymbolicLinkReparseBuffer.PathBuffer[offset]; result = QString::fromWCharArray(PathBuffer, length); } // cut-off "//?/" and "/??/" if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) result = result.mid(4); } free(reparseStructData); } return result; } Link createJunction(const QString &linkPath, const QString &targetPath) { if (!QDir().mkpath(linkPath)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot create the mount directory" << linkPath; return Link(linkPath); } FileHandleWrapper dirHandle(linkPath); if (dirHandle.handle() == INVALID_HANDLE_VALUE) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open" << linkPath << ":" << QInstaller::windowsErrorString(GetLastError()); return Link(linkPath); } const QString szDestDir = QString::fromLatin1("\\??\\%1").arg(targetPath).replace(QLatin1Char('/'), QLatin1Char('\\')); // Get string length in bytes, not in characters count const size_t destDirBytes = szDestDir.size() * sizeof(ushort); // Allocates a block of memory for an array of num elements(1) and initializes all its bits to zero. REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); reparseStructData->Reserved = 0; reparseStructData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; reparseStructData->MountPointReparseBuffer.PrintNameLength = 0; reparseStructData->MountPointReparseBuffer.SubstituteNameOffset = 0; reparseStructData->MountPointReparseBuffer.SubstituteNameLength = destDirBytes; reparseStructData->MountPointReparseBuffer.PrintNameOffset = destDirBytes + sizeof(WCHAR); uint spaceAfterGeneralData = sizeof(USHORT) * 5 + sizeof(WCHAR); //should be 12 reparseStructData->ReparseDataLength = destDirBytes + spaceAfterGeneralData; #ifndef Q_CC_MINGW StringCchCopy(reparseStructData->MountPointReparseBuffer.PathBuffer, 1024, (wchar_t*)szDestDir.utf16()); #else wcsncpy(reparseStructData->MountPointReparseBuffer.PathBuffer, (wchar_t*)szDestDir.utf16(), 1024); #endif DWORD bytesReturned; if (!::DeviceIoControl(dirHandle.handle(), FSCTL_SET_REPARSE_POINT, reparseStructData, reparseStructData->ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE, nullptr, 0, &bytesReturned, nullptr)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot set the reparse point for" << linkPath << "to" << targetPath << ":" << QInstaller::windowsErrorString(GetLastError()); } return Link(linkPath); } bool removeJunction(const QString &path) { // Allocates a block of memory for an array of num elements(1) and initializes all its bits to zero. REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); reparseStructData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; { // extra scope because we need to close the dirHandle before we can remove that directory FileHandleWrapper dirHandle(path); DWORD bytesReturned; if (!::DeviceIoControl(dirHandle.handle(), FSCTL_DELETE_REPARSE_POINT, reparseStructData, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, nullptr, 0, &bytesReturned, nullptr)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot remove the reparse point" << path << ":" << QInstaller::windowsErrorString(GetLastError()); return false; } } return QDir().rmdir(path); } #else Link createLnSymlink(const QString &linkPath, const QString &targetPath) { int linkedError = symlink(QFileInfo(targetPath).absoluteFilePath().toUtf8(), QFileInfo(linkPath).absoluteFilePath().toUtf8()); if (linkedError != 0) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot create a symlink from" << linkPath << "to" << targetPath << ":" << linkedError; } return Link(linkPath); } bool removeLnSymlink(const QString &path) { return QFile::remove(path); } #endif Link::Link(const QString &path) : m_path(path) { } Link Link::create(const QString &link, const QString &targetPath) { QStringList pathParts = QFileInfo(link).absoluteFilePath().split(QLatin1Char('/')); pathParts.removeLast(); QString linkPath = pathParts.join(QLatin1String("/")); bool linkPathExists = QFileInfo(linkPath).exists(); if (!linkPathExists) linkPathExists = QDir().mkpath(linkPath); if (!linkPathExists) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot create the needed directories" << link; return Link(link); } #ifdef Q_OS_WIN if (QFileInfo(targetPath).isDir()) return createJunction(link, targetPath); qCWarning(QInstaller::lcInstallerInstallLog) << "At the moment the" << Q_FUNC_INFO << "can not create anything else as " << "junctions for directories under windows"; return Link(link); #else return createLnSymlink(link, targetPath); #endif } QString Link::targetPath() const { #ifdef Q_OS_WIN return readWindowsSymLink(m_path); #else return QFileInfo(m_path).readLink(); #endif } bool Link::exists() { #ifdef Q_OS_WIN return QFileInfo(m_path).exists(); #else return QFileInfo(m_path).isSymLink(); #endif } bool Link::targetExists() { return QFileInfo(targetPath()).exists(); } bool Link::isValid() { return targetExists() && QFileInfo(m_path).exists(); } bool Link::remove() { if (!exists()) return false; #ifdef Q_OS_WIN return removeJunction(m_path); #else return removeLnSymlink(m_path); #endif } qt-installer-framework-4.0.1/src/libs/installer/link.h0100777000000000000000000000311413761647206017722 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef LINK_H #define LINK_H #include class Link { public: explicit Link(const QString &path); static Link create(const QString &link, const QString &targetPath); QString targetPath() const; bool targetExists(); bool exists(); bool isValid(); bool remove(); private: QString m_path; }; #endif // LINK_H qt-installer-framework-4.0.1/src/libs/installer/messageboxhandler.cpp0100777000000000000000000004622513761647206023025 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "messageboxhandler.h" #include "globals.h" #include #include #include #include #include /*! \inmodule QtInstallerFramework \class QInstaller::MessageBoxHandler \brief The MessageBoxHandler class provides a modal dialog for informing the user or asking the user a question and receiving an answer. \badcode var result = QMessageBox.question("quit.question", "Installer", "Do you want to quit the installer?", QMessageBox.Yes | QMessageBox.No); if (result == QMessageBox.Yes) { // ... } \endcode \section2 Buttons in Message Boxes \c QMessageBox defines a list of common buttons: \list \li \l{QMessageBox::Ok}{OK} \li \l{QMessageBox::Open}{Open} \li \l{QMessageBox::Save}{Save} \li \l{QMessageBox::Cancel}{Cancel} \li \l{QMessageBox::Close}{Close} \li \l{QMessageBox::Discard}{Discard} \li \l{QMessageBox::Apply}{Apply} \li \l{QMessageBox::Reset}{Reset} \li \l{QMessageBox::RestoreDefaults}{RestoreDefaults} \li \l{QMessageBox::Help}{Help} \li \l{QMessageBox::SaveAll}{SaveAll} \li \l{QMessageBox::Yes}{Yes} \li \l{QMessageBox::YesToAll}{YesToAll} \li \l{QMessageBox::No}{No} \li \l{QMessageBox::NoToAll}{NoToAll} \li \l{QMessageBox::Abort}{Abort} \li \l{QMessageBox::Retry}{Retry} \li \l{QMessageBox::Ignore}{Ignore} \li \l{QMessageBox::NoButton}{NoButton} \endlist */ using namespace QInstaller; // -- MessageBoxHandler /*! \enum MessageBoxHandler::DefaultAction This enum value holds the default action for the message box handler: \value AskUser Ask the end user for confirmation. \value Accept Accept the message box. \value Reject Reject the message box. \value Default Uses default answer set for message box. */ /*! \enum MessageBoxHandler::MessageType This enum value holds the severity level of the message displayed in the message box: \value criticalType Reports critical errors. \value informationType Reports information about normal operations. \value questionType Asks a question during normal operations. \value warningType Reports non-critical errors. */ MessageBoxHandler *MessageBoxHandler::m_instance = nullptr; MessageBoxHandler::MessageBoxHandler(QObject *parent) : QObject(parent) , m_defaultAction(MessageBoxHandler::AskUser) { } /*! Returns a message box handler instance. */ MessageBoxHandler *MessageBoxHandler::instance() { if (m_instance == nullptr) m_instance = new MessageBoxHandler(qApp); return m_instance; } /*! Returns the widget or window that is most suitable to become the parent of the message box. Returns \c 0 if an application cannot be found. */ QWidget *MessageBoxHandler::currentBestSuitParent() { if (qobject_cast (qApp) == nullptr) return nullptr; if (qApp->activeModalWidget()) return qApp->activeModalWidget(); return qApp->activeWindow(); } /*! Returns an ordered list of buttons to display in the message box. */ QList MessageBoxHandler::orderedButtons() { static QList buttons; if (!buttons.isEmpty()) return buttons; buttons << QMessageBox::YesToAll << QMessageBox::Yes << QMessageBox::Ok << QMessageBox::Apply << QMessageBox::SaveAll << QMessageBox::Save <showMessageBox(criticalType, parent, identifier, title, text, buttons, button); } /*! Opens an information message box with the parent \a parent, identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ QMessageBox::StandardButton MessageBoxHandler::information(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton button) { return instance()->showMessageBox(informationType, parent, identifier, title, text, buttons, button); } /*! Opens a question message box with the parent \a parent, identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ QMessageBox::StandardButton MessageBoxHandler::question(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton button) { return instance()->showMessageBox(questionType, parent, identifier, title, text, buttons, button); } /*! Opens a warning message box with the parent \a parent, identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ QMessageBox::StandardButton MessageBoxHandler::warning(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton button) { return instance()->showMessageBox(warningType, parent, identifier, title, text, buttons, button); } // -- invokable /*! Opens a critical message box with the identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ int MessageBoxHandler::critical(const QString &identifier, const QString &title, const QString &text, int buttons, int button) { return showMessageBox(criticalType, currentBestSuitParent(), identifier, title, text, QMessageBox::StandardButtons(buttons), QMessageBox::StandardButton(button)); } /*! Opens an information message box with the identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ int MessageBoxHandler::information(const QString &identifier, const QString &title, const QString &text, int buttons, int button) { return showMessageBox(informationType, currentBestSuitParent(), identifier, title, text, QMessageBox::StandardButtons(buttons), QMessageBox::StandardButton(button)); } /*! Opens a question message box with the identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ int MessageBoxHandler::question(const QString &identifier, const QString &title, const QString &text, int buttons, int button) { return showMessageBox(questionType, currentBestSuitParent(), identifier, title, text, QMessageBox::StandardButtons(buttons), QMessageBox::StandardButton(button)); } /*! Opens a warning message box with the identifier \a identifier, title \a title, and text \a text. The standard buttons specified by \a buttons are added to the message box. \a button specifies the button that is used when \key Enter is pressed. \a button must refer to a button that is specified in \a buttons. If \a button is QMessageBox::NoButton, a suitable default is chosen automatically. Returns the identity of the standard button that was clicked. However, if \key Esc was pressed, returns the escape button. */ int MessageBoxHandler::warning(const QString &identifier, const QString &title, const QString &text, int buttons, int button) { return showMessageBox(warningType, currentBestSuitParent(), identifier, title, text, QMessageBox::StandardButtons(buttons), QMessageBox::StandardButton(button)); } // -- private QMessageBox::StandardButton MessageBoxHandler::autoReply(QMessageBox::StandardButtons buttons) const { if (buttons == QMessageBox::NoButton) return QMessageBox::NoButton; foreach (const QMessageBox::StandardButton ¤tButton, m_buttonOrder) { if ((buttons & currentButton) != 0) return currentButton; } Q_ASSERT(!"the list must have all possible buttons"); return QMessageBox::NoButton; } static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != nullptr); uint mask = QMessageBox::FirstButton; while (mask <= QMessageBox::LastButton) { uint sb = buttons & mask; mask <<= 1; if (!sb) continue; QPushButton *button = msgBox.addButton((QMessageBox::StandardButton)sb); // Choose the first accept role as the default if (msgBox.defaultButton()) continue; if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton))) { msgBox.setDefaultButton(button); } } #if defined(Q_OS_MACOS) msgBox.setWindowModality(Qt::WindowModal); #endif if (msgBox.exec() == -1) return QMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } QMessageBox::StandardButton MessageBoxHandler::showMessageBox(MessageType messageType, QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, const QMessageBox::StandardButton defaultButton) { QString availableAnswers = availableAnswerOptions(buttons); qCDebug(QInstaller::lcInstallerInstallLog).noquote() << identifier << ":" << title << ":" << text << availableAnswers; if (m_automaticAnswers.contains(identifier)) { QMessageBox::StandardButton selectedButton = m_automaticAnswers.value(identifier); const QString buttonName = enumToString(QMessageBox::staticMetaObject, "StandardButton", selectedButton); if (buttons & selectedButton) { qCDebug(QInstaller::lcInstallerInstallLog).nospace() << "Automatic answer for "<< identifier << ": " << buttonName; } else { qCDebug(QInstaller::lcInstallerInstallLog()).nospace() << "Invalid answer " << buttonName << "for " << identifier << ". Using default value " << enumToString(QMessageBox::staticMetaObject, "StandardButton", defaultButton) << " instead."; selectedButton = defaultButton; } return selectedButton; } if (qobject_cast (qApp) == nullptr) { QMessageBox::StandardButton button = defaultButton; bool showAnswerInLog = true; if (m_defaultAction == AskUser) { if (!availableAnswers.isEmpty()) { while (!askAnswerFromUser(button, buttons)) { qCDebug(QInstaller::lcInstallerInstallLog) << "Invalid answer, please retry"; } } showAnswerInLog = false; } else if (m_defaultAction != Default) { button = autoReply(buttons); } if (showAnswerInLog) { qCDebug(QInstaller::lcInstallerInstallLog) << "Answer:" << enumToString(QMessageBox::staticMetaObject, "StandardButton", button); } return button; } if (m_defaultAction == AskUser) { switch (messageType) { case criticalType: return showNewMessageBox(parent, QMessageBox::Critical, title, text, buttons, defaultButton); case informationType: return showNewMessageBox(parent, QMessageBox::Information, title, text, buttons, defaultButton); case questionType: return showNewMessageBox(parent, QMessageBox::Question, title, text, buttons, defaultButton); case warningType: return showNewMessageBox(parent, QMessageBox::Warning, title, text, buttons, defaultButton); } } else { return autoReply(buttons); } Q_ASSERT_X(false, Q_FUNC_INFO, "Something went really wrong."); return defaultButton; } bool MessageBoxHandler::askAnswerFromUser(QMessageBox::StandardButton &selectedButton, QMessageBox::StandardButtons &availableButtons) const { QTextStream stream(stdin); QString answer; stream.readLineInto(&answer); const QMetaObject metaObject = QMessageBox::staticMetaObject; int enumIndex = metaObject.indexOfEnumerator("StandardButton"); if (enumIndex != -1) { QMetaEnum en = metaObject.enumerator(enumIndex); answer.prepend(QLatin1String("QMessageBox::")); bool ok = false; int button = en.keyToValue(answer.toLocal8Bit().data(), &ok); if (ok) { selectedButton = static_cast(button); if (availableButtons & selectedButton) return true; } } return false; } QString MessageBoxHandler::availableAnswerOptions(const QFlags &flags) const { QString answers = QString(); QMetaObject metaObject = QMessageBox::staticMetaObject; int enumIndex = metaObject.indexOfEnumerator("StandardButton"); if (enumIndex != -1) { QMetaEnum en = metaObject.enumerator(enumIndex); // If valueToKey returned a value, we don't have a question // as there was only one value in the flags. if (QLatin1String(en.valueToKey(quint64(flags))).isEmpty()) answers = QLatin1String(en.valueToKeys(quint64(flags))); } return answers; } qt-installer-framework-4.0.1/src/libs/installer/messageboxhandler.h0100777000000000000000000001171413761647206022465 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_MESSAGEBOXHANDLER_H #define QINSTALLER_MESSAGEBOXHANDLER_H #include #include #include #include namespace QInstaller { class INSTALLER_EXPORT MessageBoxHandler : public QObject { Q_OBJECT public: enum DefaultAction { AskUser, Accept, Reject, Default }; enum MessageType{ criticalType, informationType, questionType, warningType }; static MessageBoxHandler *instance(); static QWidget *currentBestSuitParent(); void setDefaultAction(DefaultAction defaultAction); void setAutomaticAnswer(const QString &identifier, QMessageBox::StandardButton answer); static QMessageBox::StandardButton critical(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton button = QMessageBox::NoButton); static QMessageBox::StandardButton information(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton); static QMessageBox::StandardButton question(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, QMessageBox::StandardButton button = QMessageBox::NoButton); static QMessageBox::StandardButton warning(QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton button = QMessageBox::NoButton); Q_INVOKABLE int critical(const QString &identifier, const QString &title, const QString &text, int buttons = QMessageBox::Ok, int button = QMessageBox::NoButton); Q_INVOKABLE int information(const QString &identifier, const QString &title, const QString &text, int buttons = QMessageBox::Ok, int button = QMessageBox::NoButton); Q_INVOKABLE int question(const QString &identifier, const QString &title, const QString &text, int buttons = QMessageBox::Yes | QMessageBox::No, int button = QMessageBox::NoButton); Q_INVOKABLE int warning(const QString &identifier, const QString &title, const QString &text, int buttons = QMessageBox::Ok, int button = QMessageBox::NoButton); static QList orderedButtons(); private Q_SLOTS: //this removes the slot from the script area virtual void deleteLater() { QObject::deleteLater(); } private: explicit MessageBoxHandler(QObject *parent); QMessageBox::StandardButton autoReply(QMessageBox::StandardButtons buttons) const; QMessageBox::StandardButton showMessageBox(MessageType messageType, QWidget *parent, const QString &identifier, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, const QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); bool askAnswerFromUser(QMessageBox::StandardButton &selectedButton, QMessageBox::StandardButtons &availableButtons) const; QString availableAnswerOptions(const QFlags &flags) const; private: static MessageBoxHandler *m_instance; DefaultAction m_defaultAction; QList m_buttonOrder; QHash m_automaticAnswers; }; } Q_DECLARE_METATYPE(QMessageBox::StandardButton) Q_DECLARE_METATYPE(QMessageBox::StandardButtons) #endif // QINSTALLER_MESSAGEBOXHANDLER_H qt-installer-framework-4.0.1/src/libs/installer/metadatajob.cpp0100777000000000000000000011070113761647206021574 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "metadatajob.h" #include "metadatajob_p.h" #include "packagemanagercore.h" #include "packagemanagerproxyfactory.h" #include "productkeycheck.h" #include "proxycredentialsdialog.h" #include "serverauthenticationdialog.h" #include "settings.h" #include "testrepository.h" #include "globals.h" #include #include const QStringList metaElements = {QLatin1String("Script"), QLatin1String("Licenses"), QLatin1String("UserInterfaces"), QLatin1String("Translations")}; namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::Metadata \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::ArchiveMetadata \internal */ /*! \enum QInstaller::DownloadType \value All \value CompressedPackage \value UpdatesXML */ /*! \inmodule QtInstallerFramework \class QInstaller::MetadataJob \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::UnzipArchiveTask \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::UnzipArchiveException \internal */ static QUrl resolveUrl(const FileTaskResult &result, const QString &url) { QUrl u(url); if (u.isRelative()) return QUrl(result.taskItem().source()).resolved(u); return u; } MetadataJob::MetadataJob(QObject *parent) : Job(parent) , m_core(nullptr) , m_downloadType(DownloadType::All) , m_downloadableChunkSize(1000) , m_taskNumber(0) { QByteArray downloadableChunkSize = qgetenv("IFW_METADATA_SIZE"); if (!downloadableChunkSize.isEmpty()) { int chunkSize = QString::fromLocal8Bit(downloadableChunkSize).toInt(); if (chunkSize > 0) m_downloadableChunkSize = chunkSize; } setCapabilities(Cancelable); connect(&m_xmlTask, &QFutureWatcherBase::finished, this, &MetadataJob::xmlTaskFinished); connect(&m_metadataTask, &QFutureWatcherBase::finished, this, &MetadataJob::metadataTaskFinished); connect(&m_metadataTask, &QFutureWatcherBase::progressValueChanged, this, &MetadataJob::progressChanged); } MetadataJob::~MetadataJob() { resetCompressedFetch(); reset(); } /* * Parse the metadata of currently selected repositories. We cannot * return all metadata as that contains metadata also from categorized archived * repositories which might not be currently selected. */ QList MetadataJob::metadata() const { QList metadata = m_metaFromDefaultRepositories.values(); foreach (RepositoryCategory repositoryCategory, m_core->settings().repositoryCategories()) { if (m_core->isUpdater() || (repositoryCategory.isEnabled() && m_fetchedArchive.contains(repositoryCategory.displayname()))) { QList archiveMetaList = m_fetchedArchive.values(repositoryCategory.displayname()); foreach (ArchiveMetadata archiveMeta, archiveMetaList) { metadata.append(archiveMeta.metaData); } } } return metadata; } Repository MetadataJob::repositoryForDirectory(const QString &directory) const { if (m_metaFromDefaultRepositories.contains(directory)) return m_metaFromDefaultRepositories.value(directory).repository; else return m_metaFromArchive.value(directory).repository; } // -- private slots void MetadataJob::doStart() { setError(Job::NoError); setErrorString(QString()); if (!m_core) { emitFinishedWithError(Job::Canceled, tr("Missing package manager core engine.")); return; // We can't do anything here without core, so avoid tons of !m_core checks. } const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(); if (m_downloadType == DownloadType::All || m_downloadType == DownloadType::UpdatesXML) { emit infoMessage(this, tr("Preparing meta information download...")); const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly(); if (onlineInstaller || m_core->isMaintainer()) { QList items; QSet repositories = getRepositories(); foreach (const Repository &repo, repositories) { if (repo.isEnabled() && productKeyCheck->isValidRepository(repo)) { QAuthenticator authenticator; authenticator.setUser(repo.username()); authenticator.setPassword(repo.password()); if (!repo.isCompressed()) { QString url = repo.url().toString() + QLatin1String("/Updates.xml?"); if (!m_core->value(scUrlQueryString).isEmpty()) url += m_core->value(scUrlQueryString) + QLatin1Char('&'); // also append a random string to avoid proxy caches FileTaskItem item(url.append(QString::number(qrand() * qrand()))); item.insert(TaskRole::UserRole, QVariant::fromValue(repo)); item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator)); items.append(item); } else { qCWarning(QInstaller::lcInstallerInstallLog) << "Trying to parse compressed repo as " "normal repository. Check repository syntax."; } } } if (items.count() > 0) { startXMLTask(items); } else { emitFinished(); } } else { emitFinished(); } } else { resetCompressedFetch(); bool repositoriesFound = false; foreach (const Repository &repo, m_core->settings().temporaryRepositories()) { if (repo.isCompressed() && repo.isEnabled() && productKeyCheck->isValidRepository(repo)) { repositoriesFound = true; startUnzipRepositoryTask(repo); //Set the repository disabled so we don't handle it many times Repository replacement = repo; replacement.setEnabled(false); Settings &s = m_core->settings(); QSet temporaries = s.temporaryRepositories(); if (temporaries.contains(repo)) { temporaries.remove(repo); temporaries.insert(replacement); s.setTemporaryRepositories(temporaries, true); } } } if (!repositoriesFound) { emitFinished(); } else { setProgressTotalAmount(0); emit infoMessage(this, tr("Unpacking compressed repositories. This may take a while...")); } } } void MetadataJob::startXMLTask(const QList &items) { DownloadFileTask *const xmlTask = new DownloadFileTask(items); xmlTask->setProxyFactory(m_core->proxyFactory()); connect(&m_xmlTask, &QFutureWatcher::progressValueChanged, this, &MetadataJob::progressChanged); m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask)); } void MetadataJob::doCancel() { reset(); emitFinishedWithError(Job::Canceled, tr("Meta data download canceled.")); } void MetadataJob::startUnzipRepositoryTask(const Repository &repo) { QTemporaryDir tempRepoDir(QDir::tempPath() + QLatin1String("/compressedRepo-XXXXXX")); if (!tempRepoDir.isValid()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot create unique temporary directory."; return; } tempRepoDir.setAutoRemove(false); m_tempDirDeleter.add(tempRepoDir.path()); QString url = repo.url().toLocalFile(); UnzipArchiveTask *task = new UnzipArchiveTask(url, tempRepoDir.path()); QFutureWatcher *watcher = new QFutureWatcher(); m_unzipRepositoryTasks.insert(watcher, qobject_cast (task)); connect(watcher, &QFutureWatcherBase::finished, this, &MetadataJob::unzipRepositoryTaskFinished); connect(watcher, &QFutureWatcherBase::progressValueChanged, this, &MetadataJob::progressChanged); watcher->setFuture(QtConcurrent::run(&UnzipArchiveTask::doTask, task)); } void MetadataJob::unzipRepositoryTaskFinished() { QFutureWatcher *watcher = static_cast *>(sender()); int error = Job::NoError; QString errorString; try { watcher->waitForFinished(); // trigger possible exceptions QHashIterator *, QObject*> i(m_unzipRepositoryTasks); while (i.hasNext()) { i.next(); if (i.key() == watcher) { UnzipArchiveTask *task = qobject_cast (i.value()); QString url = task->target(); QUrl targetUrl = targetUrl.fromLocalFile(url); Repository repo(targetUrl, false, true); url = repo.url().toString() + QLatin1String("/Updates.xml"); TestRepository testJob(m_core); testJob.setRepository(repo); testJob.start(); testJob.waitForFinished(); error = testJob.error(); errorString = testJob.errorString(); if (error == Job::NoError) { FileTaskItem item(url); item.insert(TaskRole::UserRole, QVariant::fromValue(repo)); m_unzipRepositoryitems.append(item); } else { //Repository is not valid, remove it Repository repository; repository.setUrl(QUrl(task->archive())); Settings &s = m_core->settings(); QSet temporaries = s.temporaryRepositories(); foreach (Repository repository, temporaries) { if (repository.url().toLocalFile() == task->archive()) { temporaries.remove(repository); } } s.setTemporaryRepositories(temporaries, false); } } } delete m_unzipRepositoryTasks.value(watcher); m_unzipRepositoryTasks.remove(watcher); delete watcher; //One can specify many zipped repository items at once. As the repositories are //unzipped one by one, we collect here all items before parsing xml files from those. if (m_unzipRepositoryitems.count() > 0 && m_unzipRepositoryTasks.isEmpty()) { startXMLTask(m_unzipRepositoryitems); } else { if (error != Job::NoError) { emitFinishedWithError(QInstaller::DownloadError, errorString); } } } catch (const UnzipArchiveException &e) { reset(); emitFinishedWithError(QInstaller::ExtractionError, e.message()); } catch (const QUnhandledException &e) { reset(); emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what())); } catch (...) { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during extracting.")); } } void MetadataJob::xmlTaskFinished() { Status status = XmlDownloadFailure; try { m_xmlTask.waitForFinished(); status = parseUpdatesXml(m_xmlTask.future().results()); } catch (const AuthenticationRequiredException &e) { if (e.type() == AuthenticationRequiredException::Type::Proxy) { const QNetworkProxy proxy = e.proxy(); ProxyCredentialsDialog proxyCredentials(proxy); qCWarning(QInstaller::lcInstallerInstallLog) << e.message(); if (proxyCredentials.exec() == QDialog::Accepted) { qCDebug(QInstaller::lcInstallerInstallLog) << "Retrying with new credentials ..."; PackageManagerProxyFactory *factory = m_core->proxyFactory(); factory->setProxyCredentials(proxy, proxyCredentials.userName(), proxyCredentials.password()); m_core->setProxyFactory(factory); status = XmlDownloadRetry; } else { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Missing proxy credentials.")); } } else if (e.type() == AuthenticationRequiredException::Type::Server) { qCWarning(QInstaller::lcInstallerInstallLog) << e.message(); ServerAuthenticationDialog dlg(e.message(), e.taskItem()); if (dlg.exec() == QDialog::Accepted) { Repository original = e.taskItem().value(TaskRole::UserRole) .value(); Repository replacement = original; replacement.setUsername(dlg.user()); replacement.setPassword(dlg.password()); Settings &s = m_core->settings(); QSet temporaries = s.temporaryRepositories(); if (temporaries.contains(original)) { temporaries.remove(original); temporaries.insert(replacement); s.addTemporaryRepositories(temporaries, true); } else { QHash > update; update.insert(QLatin1String("replace"), qMakePair(original, replacement)); if (s.updateRepositoryCategories(update) == Settings::UpdatesApplied) qCDebug(QInstaller::lcDeveloperBuild) << "Repository categories updated."; if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied || s.updateUserRepositories(update) == Settings::UpdatesApplied) { if (m_core->isMaintainer()) { bool gainedAdminRights = false; if (!m_core->directoryWritable(m_core->value(scTargetDir))) { m_core->gainAdminRights(); gainedAdminRights = true; } m_core->writeMaintenanceConfigFiles(); if (gainedAdminRights) m_core->dropAdminRights(); } } } status = XmlDownloadRetry; } else { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Authentication failed.")); } } } catch (const TaskException &e) { reset(); emitFinishedWithError(QInstaller::DownloadError, e.message()); } catch (const QUnhandledException &e) { reset(); emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what())); } catch (...) { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during download.")); } if (error() != Job::NoError) return; if (status == XmlDownloadSuccess) { if (m_downloadType != DownloadType::UpdatesXML) { if (!fetchMetaDataPackages()) emitFinished(); } else { emitFinished(); } } else if (status == XmlDownloadRetry) { QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); } else { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Failure to fetch repositories.")); } } void MetadataJob::unzipTaskFinished() { QFutureWatcher *watcher = static_cast *>(sender()); try { watcher->waitForFinished(); // trigger possible exceptions } catch (const UnzipArchiveException &e) { emitFinishedWithError(QInstaller::ExtractionError, e.message()); } catch (const QUnhandledException &e) { emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what())); } catch (...) { emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during extracting.")); } if (error() != Job::NoError) return; delete m_unzipTasks.value(watcher); m_unzipTasks.remove(watcher); delete watcher; if (m_unzipTasks.isEmpty()) { setProcessedAmount(100); emitFinished(); } } void MetadataJob::progressChanged(int progress) { setProcessedAmount(progress); } void MetadataJob::setProgressTotalAmount(int maximum) { setTotalAmount(maximum); } void MetadataJob::metadataTaskFinished() { try { m_metadataTask.waitForFinished(); m_metadataResult.append(m_metadataTask.future().results()); if (!fetchMetaDataPackages()) { if (m_metadataResult.count() > 0) { emit infoMessage(this, tr("Extracting meta information...")); foreach (const FileTaskResult &result, m_metadataResult) { const FileTaskItem item = result.value(TaskRole::TaskItem).value(); if (result.value(TaskRole::ChecksumMismatch).toBool()) { QString mismatchMessage = tr("Checksum mismatch detected for \"%1\".") .arg(item.value(TaskRole::SourceFile).toString()); if (m_core->settings().allowUnstableComponents()) { m_shaMissmatchPackages.append(item.value(TaskRole::Name).toString()); qCWarning(QInstaller::lcInstallerInstallLog) << mismatchMessage; } else { throw QInstaller::TaskException(mismatchMessage); } } UnzipArchiveTask *task = new UnzipArchiveTask(result.target(), item.value(TaskRole::UserRole).toString()); QFutureWatcher *watcher = new QFutureWatcher(); m_unzipTasks.insert(watcher, qobject_cast (task)); connect(watcher, &QFutureWatcherBase::finished, this, &MetadataJob::unzipTaskFinished); watcher->setFuture(QtConcurrent::run(&UnzipArchiveTask::doTask, task)); } } else { emitFinished(); } } } catch (const TaskException &e) { reset(); emitFinishedWithError(QInstaller::DownloadError, e.message()); } catch (const QUnhandledException &e) { reset(); emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what())); } catch (...) { reset(); emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during download.")); } } // -- private bool MetadataJob::fetchMetaDataPackages() { //Download files in chunks. QtConcurrent will choke if too many task is given to it int chunkSize = qMin(m_packages.length(), m_downloadableChunkSize); QList tempPackages = m_packages.mid(0, chunkSize); m_packages = m_packages.mid(chunkSize, m_packages.length()); if (tempPackages.length() > 0) { m_taskNumber++; setProcessedAmount(0); DownloadFileTask *const metadataTask = new DownloadFileTask(tempPackages); metadataTask->setProxyFactory(m_core->proxyFactory()); m_metadataTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, metadataTask)); setProgressTotalAmount(100); QString metaInformation; if (m_totalTaskCount > 1) metaInformation = tr("Retrieving meta information from remote repository... %1/%2 ").arg(m_taskNumber).arg(m_totalTaskCount); else metaInformation = tr("Retrieving meta information from remote repository... "); emit infoMessage(this, metaInformation); return true; } return false; } void MetadataJob::reset() { m_packages.clear(); m_metaFromDefaultRepositories.clear(); m_metaFromArchive.clear(); m_fetchedArchive.clear(); setError(Job::NoError); setErrorString(QString()); setCapabilities(Cancelable); try { m_xmlTask.cancel(); m_metadataTask.cancel(); } catch (...) {} m_tempDirDeleter.releaseAndDeleteAll(); m_metadataResult.clear(); m_taskNumber = 0; } void MetadataJob::resetCompressedFetch() { setError(Job::NoError); setErrorString(QString()); m_unzipRepositoryitems.clear(); try { foreach (QFutureWatcher *const watcher, m_unzipTasks.keys()) { watcher->cancel(); watcher->deleteLater(); } foreach (QObject *const object, m_unzipTasks) object->deleteLater(); m_unzipTasks.clear(); foreach (QFutureWatcher *const watcher, m_unzipRepositoryTasks.keys()) { watcher->cancel(); watcher->deleteLater(); } foreach (QObject *const object, m_unzipRepositoryTasks) object->deleteLater(); m_unzipRepositoryTasks.clear(); } catch (...) {} } MetadataJob::Status MetadataJob::parseUpdatesXml(const QList &results) { foreach (const FileTaskResult &result, results) { if (error() != Job::NoError) return XmlDownloadFailure; //If repository is not found, target might be empty. Do not continue parsing the //repository and do not prevent further repositories usage. if (result.target().isEmpty()) { continue; } Metadata metadata; QTemporaryDir tmp(QDir::tempPath() + QLatin1String("/remoterepo-XXXXXX")); if (!tmp.isValid()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot create unique temporary directory."; return XmlDownloadFailure; } tmp.setAutoRemove(false); metadata.directory = tmp.path(); m_tempDirDeleter.add(metadata.directory); QFile file(result.target()); if (!file.rename(metadata.directory + QLatin1String("/Updates.xml"))) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot rename target to Updates.xml:" << file.errorString(); return XmlDownloadFailure; } if (!file.open(QIODevice::ReadOnly)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open Updates.xml for reading:" << file.errorString(); return XmlDownloadFailure; } QString error; QDomDocument doc; if (!doc.setContent(&file, &error)) { qCWarning(QInstaller::lcInstallerInstallLog).nospace() << "Cannot fetch a valid version of Updates.xml from repository " << metadata.repository.displayname() << ": " << error; //If there are other repositories, try to use those continue; } file.close(); const FileTaskItem item = result.value(TaskRole::TaskItem).value(); metadata.repository = item.value(TaskRole::UserRole).value(); const bool online = !(metadata.repository.url().scheme()).isEmpty(); bool testCheckSum = true; const QDomElement root = doc.documentElement(); const QDomNode checksum = root.firstChildElement(QLatin1String("Checksum")); if (!checksum.isNull()) testCheckSum = (checksum.toElement().text().toLower() == scTrue); // If we have top level sha1 and MetadataName elements, we have compressed // all metadata inside one repository to a single 7z file. Fetch that // instead of component specific meta 7z files. const QDomNode sha1 = root.firstChildElement(scSHA1); QDomElement metadataNameElement = root.firstChildElement(QLatin1String("MetadataName")); QDomNodeList children = root.childNodes(); if (!sha1.isNull() && !metadataNameElement.isNull()) { const QString repoUrl = metadata.repository.url().toString(); const QString metadataName = metadataNameElement.toElement().text(); addFileTaskItem(QString::fromLatin1("%1/%2").arg(repoUrl, metadataName), metadata.directory + QString::fromLatin1("/%1").arg(metadataName), metadata, sha1.toElement().text(), QString()); } else { bool metaFound = false; for (int i = 0; i < children.count(); ++i) { const QDomElement el = children.at(i).toElement(); if (!el.isNull() && el.tagName() == QLatin1String("PackageUpdate")) { const QDomNodeList c2 = el.childNodes(); QString packageName, packageVersion, packageHash; metaFound = parsePackageUpdate(c2, packageName, packageVersion, packageHash, online, testCheckSum); //If meta element (script, licenses, etc.) is not found, no need to fetch metadata if (metaFound) { const QString repoUrl = metadata.repository.url().toString(); addFileTaskItem(QString::fromLatin1("%1/%2/%3meta.7z").arg(repoUrl, packageName, packageVersion), metadata.directory + QString::fromLatin1("/%1-%2-meta.7z").arg(packageName, packageVersion), metadata, packageHash, packageName); } else { QString fileName = metadata.directory + QLatin1Char('/') + packageName; QDir directory(fileName); if (!directory.exists()) { directory.mkdir(fileName); } } } } } if (metadata.repository.categoryname().isEmpty()) { m_metaFromDefaultRepositories.insert(metadata.directory, metadata); } else { //Hash metadata to help checking if meta for repository is already fetched ArchiveMetadata archiveMetadata; archiveMetadata.metaData = metadata; m_fetchedArchive.insertMulti(metadata.repository.categoryname(), archiveMetadata); //Check if other categories have the same url (contains same metadata) //so we can speed up other category fetches foreach (RepositoryCategory category, m_core->settings().repositoryCategories()) { if (category.displayname() != metadata.repository.categoryname()) { foreach (Repository repository, category.repositories()) { if (repository.url() == metadata.repository.url()) { m_fetchedArchive.insertMulti(category.displayname(), archiveMetadata); } } } } // Hash for faster lookups m_metaFromArchive.insert(metadata.directory, metadata); } // search for additional repositories that we might need to check const QDomNode repositoryUpdate = root.firstChildElement(QLatin1String("RepositoryUpdate")); if (!repositoryUpdate.isNull()) { QHash > repositoryUpdates = searchAdditionalRepositories(repositoryUpdate, result, metadata); if (!repositoryUpdates.isEmpty()) { MetadataJob::Status status = setAdditionalRepositories(repositoryUpdates, result, metadata); if (status == XmlDownloadRetry) return status; } } } double taskCount = m_packages.length()/static_cast(m_downloadableChunkSize); m_totalTaskCount = qCeil(taskCount); m_taskNumber = 0; return XmlDownloadSuccess; } QSet MetadataJob::getRepositories() { QSet repositories; //In the first run, m_metadata is empty. Get always the default repositories if (m_metaFromDefaultRepositories.isEmpty()) { repositories = m_core->settings().repositories(); } // Fetch repositories under archive which are selected in UI. // If repository is already fetched, do not fetch it again. // In updater mode, fetch always all archive repositories to get updates foreach (RepositoryCategory repositoryCategory, m_core->settings().repositoryCategories()) { if (m_core->isUpdater() || (repositoryCategory.isEnabled())) { foreach (Repository repository, repositoryCategory.repositories()) { QHashIterator i(m_fetchedArchive); bool fetch = true; while (i.hasNext()) { i.next(); ArchiveMetadata metaData = i.value(); if (repository.url() == metaData.metaData.repository.url()) fetch = false; } if (fetch) repositories.insert(repository); } } } return repositories; } void MetadataJob::addFileTaskItem(const QString &source, const QString &target, const Metadata &metadata, const QString &sha1, const QString &packageName) { FileTaskItem item(source, target); QAuthenticator authenticator; authenticator.setUser(metadata.repository.username()); authenticator.setPassword(metadata.repository.password()); item.insert(TaskRole::UserRole, metadata.directory); item.insert(TaskRole::Checksum, sha1.toLatin1()); item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator)); item.insert(TaskRole::Name, packageName); m_packages.append(item); } bool MetadataJob::parsePackageUpdate(const QDomNodeList &c2, QString &packageName, QString &packageVersion, QString &packageHash, bool online, bool testCheckSum) { bool metaFound = false; for (int j = 0; j < c2.count(); ++j) { const QDomElement element = c2.at(j).toElement(); if (element.tagName() == scName) packageName = element.text(); else if (element.tagName() == scVersion) packageVersion = (online ? element.text() : QString()); else if ((element.tagName() == QLatin1String("SHA1")) && testCheckSum) packageHash = element.text(); else { foreach (QString meta, metaElements) { if (element.tagName() == meta) { metaFound = true; break; } } } } return metaFound; } QHash > MetadataJob::searchAdditionalRepositories (const QDomNode &repositoryUpdate, const FileTaskResult &result, const Metadata &metadata) { QHash > repositoryUpdates; const QDomNodeList children = repositoryUpdate.toElement().childNodes(); for (int i = 0; i < children.count(); ++i) { const QDomElement el = children.at(i).toElement(); if (!el.isNull() && el.tagName() == QLatin1String("Repository")) { const QString action = el.attribute(QLatin1String("action")); if (action == QLatin1String("add")) { // add a new repository to the defaults list Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true); repository.setUsername(el.attribute(QLatin1String("username"))); repository.setPassword(el.attribute(QLatin1String("password"))); repository.setDisplayName(el.attribute(QLatin1String("displayname"))); if (ProductKeyCheck::instance()->isValidRepository(repository)) { repositoryUpdates.insertMulti(action, qMakePair(repository, Repository())); qDebug() << "Repository to add:" << repository.displayname(); } } else if (action == QLatin1String("remove")) { // remove possible default repositories using the given server url Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true); repository.setDisplayName(el.attribute(QLatin1String("displayname"))); repositoryUpdates.insertMulti(action, qMakePair(repository, Repository())); qDebug() << "Repository to remove:" << repository.displayname(); } else if (action == QLatin1String("replace")) { // replace possible default repositories using the given server url Repository oldRepository(resolveUrl(result, el.attribute(QLatin1String("oldUrl"))), true); Repository newRepository(resolveUrl(result, el.attribute(QLatin1String("newUrl"))), true); newRepository.setUsername(el.attribute(QLatin1String("username"))); newRepository.setPassword(el.attribute(QLatin1String("password"))); newRepository.setDisplayName(el.attribute(QLatin1String("displayname"))); if (ProductKeyCheck::instance()->isValidRepository(newRepository)) { // store the new repository and the one old it replaces repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository)); qDebug() << "Replace repository" << oldRepository.displayname() << "with" << newRepository.displayname(); } } else { qDebug() << "Invalid additional repositories action set in Updates.xml fetched " "from" << metadata.repository.displayname() << "line:" << el.lineNumber(); } } } return repositoryUpdates; } MetadataJob::Status MetadataJob::setAdditionalRepositories(QHash > repositoryUpdates, const FileTaskResult &result, const Metadata& metadata) { MetadataJob::Status status = XmlDownloadSuccess; Settings &s = m_core->settings(); const QSet temporaries = s.temporaryRepositories(); // in case the temp repository introduced something new, we only want that temporary if (temporaries.contains(metadata.repository)) { QSet tmpRepositories; typedef QPair RepositoryPair; QList values = repositoryUpdates.values(QLatin1String("add")); foreach (const RepositoryPair &value, values) tmpRepositories.insert(value.first); values = repositoryUpdates.values(QLatin1String("replace")); foreach (const RepositoryPair &value, values) tmpRepositories.insert(value.first); tmpRepositories = tmpRepositories.subtract(temporaries); if (tmpRepositories.count() > 0) { s.addTemporaryRepositories(tmpRepositories, true); QFile::remove(result.target()); m_metaFromDefaultRepositories.clear(); status = XmlDownloadRetry; } } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { if (m_core->isMaintainer()) { bool gainedAdminRights = false; if (!m_core->directoryWritable(m_core->value(scTargetDir))) { m_core->gainAdminRights(); gainedAdminRights = true; } m_core->writeMaintenanceConfigFiles(); if (gainedAdminRights) m_core->dropAdminRights(); } m_metaFromDefaultRepositories.clear(); QFile::remove(result.target()); status = XmlDownloadRetry; } return status; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/metadatajob.h0100777000000000000000000001066713761647206021253 0ustar00/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef METADATAJOB_H #define METADATAJOB_H #include "downloadfiletask.h" #include "fileutils.h" #include "job.h" #include "repository.h" #include class QDomNodeList; class QDomNode; namespace QInstaller { class PackageManagerCore; struct Metadata { QString directory; Repository repository; }; struct ArchiveMetadata { QString archive; Metadata metaData; }; enum DownloadType { All, CompressedPackage, UpdatesXML }; class INSTALLER_EXPORT MetadataJob : public Job { Q_OBJECT Q_DISABLE_COPY(MetadataJob) enum Status { XmlDownloadRetry, XmlDownloadFailure, XmlDownloadSuccess }; public: explicit MetadataJob(QObject *parent = 0); ~MetadataJob(); QList metadata() const; Repository repositoryForDirectory(const QString &directory) const; void setPackageManagerCore(PackageManagerCore *core) { m_core = core; } void addDownloadType(DownloadType downloadType) { m_downloadType = downloadType;} QStringList shaMismatchPackages() const { return m_shaMissmatchPackages; } private slots: void doStart(); void doCancel(); void xmlTaskFinished(); void unzipTaskFinished(); void metadataTaskFinished(); void progressChanged(int progress); void setProgressTotalAmount(int maximum); void unzipRepositoryTaskFinished(); void startXMLTask(const QList &items); private: bool fetchMetaDataPackages(); void startUnzipRepositoryTask(const Repository &repo); void reset(); void resetCompressedFetch(); Status parseUpdatesXml(const QList &results); QSet getRepositories(); void addFileTaskItem(const QString &source, const QString &target, const Metadata &metadata, const QString &sha1, const QString &packageName); bool parsePackageUpdate(const QDomNodeList &c2, QString &packageName, QString &packageVersion, QString &packageHash, bool online, bool testCheckSum); QHash > searchAdditionalRepositories(const QDomNode &repositoryUpdate, const FileTaskResult &result, const Metadata &metadata); MetadataJob::Status setAdditionalRepositories(QHash > repositoryUpdates, const FileTaskResult &result, const Metadata& metadata); private: PackageManagerCore *m_core; QList m_packages; TempDirDeleter m_tempDirDeleter; QFutureWatcher m_xmlTask; QFutureWatcher m_metadataTask; QHash *, QObject*> m_unzipTasks; QHash *, QObject*> m_unzipRepositoryTasks; DownloadType m_downloadType; QList m_unzipRepositoryitems; QList m_metadataResult; int m_downloadableChunkSize; int m_taskNumber; int m_totalTaskCount; QStringList m_shaMissmatchPackages; QHash m_fetchedArchive; QHash m_metaFromDefaultRepositories; QHash m_metaFromArchive; //for faster lookups. }; } // namespace QInstaller #endif // METADATAJOB_H qt-installer-framework-4.0.1/src/libs/installer/metadatajob_p.h0100777000000000000000000000664113761647206021567 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef METADATAJOB_P_H #define METADATAJOB_P_H #include "lib7z_extract.h" #include "lib7z_facade.h" #include "metadatajob.h" #include #include namespace QInstaller{ class UnzipArchiveException : public QException { public: UnzipArchiveException() {} ~UnzipArchiveException() throw() {} explicit UnzipArchiveException(const QString &message) : m_message(message) {} void raise() const { throw *this; } QString message() const { return m_message; } UnzipArchiveException *clone() const { return new UnzipArchiveException(*this); } private: QString m_message; }; class UnzipArchiveTask : public AbstractTask { Q_OBJECT Q_DISABLE_COPY(UnzipArchiveTask) public: UnzipArchiveTask(const QString &arcive, const QString &target) : m_archive(arcive), m_targetDir(target) {} QString target() { return m_targetDir; } QString archive() { return m_archive; } void doTask(QFutureInterface &fi) { fi.reportStarted(); fi.setExpectedResultCount(1); if (fi.isCanceled()) { fi.reportFinished(); return; // ignore already canceled } QFile archive(m_archive); if (archive.open(QIODevice::ReadOnly)) { try { Lib7z::extractArchive(&archive, m_targetDir); } catch (const Lib7z::SevenZipException& e) { fi.reportException(UnzipArchiveException(MetadataJob::tr("Error while extracting " "archive \"%1\": %2").arg(QDir::toNativeSeparators(m_archive), e.message()))); } catch (...) { fi.reportException(UnzipArchiveException(MetadataJob::tr("Unknown exception " "caught while extracting archive \"%1\".").arg(QDir::toNativeSeparators(m_archive)))); } } else { fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open file \"%1\" for " "reading: %2").arg(QDir::toNativeSeparators(m_archive), archive.errorString()))); } fi.reportFinished(); } private: QString m_archive; QString m_targetDir; }; } // namespace QInstaller #endif // METADATAJOB_P_H qt-installer-framework-4.0.1/src/libs/installer/minimumprogressoperation.cpp0100777000000000000000000000367413761647206024514 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "minimumprogressoperation.h" using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::MinimumProgressOperation \internal */ MinimumProgressOperation::MinimumProgressOperation(PackageManagerCore *core) : UpdateOperation(core) { // This shouldn't be callable by script, but we need a name for the binary format setName(QLatin1String("MinimumProgress")); } void MinimumProgressOperation::backup() { } bool MinimumProgressOperation::performOperation() { progressChanged(1); return true; } bool MinimumProgressOperation::undoOperation() { progressChanged(1); return true; } bool MinimumProgressOperation::testOperation() { return true; } qt-installer-framework-4.0.1/src/libs/installer/minimumprogressoperation.h0100777000000000000000000000340013761647206024144 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef MINIMUMPROGRESSOPERATION_H #define MINIMUMPROGRESSOPERATION_H #include "qinstallerglobal.h" #include namespace QInstaller { class MinimumProgressOperation : public QObject, public Operation { Q_OBJECT public: explicit MinimumProgressOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); signals: void progressChanged(double progress); }; } // namespace QInstaller #endif // MINIMUMPROGRESSOPERATION_H qt-installer-framework-4.0.1/src/libs/installer/observer.cpp0100777000000000000000000001267113761647206021157 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "observer.h" #include namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::FileTaskObserver \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::Observer \internal */ FileTaskObserver::FileTaskObserver(QCryptographicHash::Algorithm algorithm) : m_hash(algorithm) { init(); } FileTaskObserver::~FileTaskObserver() { if (m_timerId >= 0) killTimer(m_timerId); } int FileTaskObserver::progressValue() const { if (m_bytesToTransfer <= 0 || m_bytesTransfered > m_bytesToTransfer) return 0; return 100 * m_bytesTransfered / m_bytesToTransfer; } QString FileTaskObserver::progressText() const { QString progressText; if (m_bytesToTransfer > 0) { QString bytesReceived = QInstaller::humanReadableSize(m_bytesTransfered); const QString bytesToReceive = QInstaller::humanReadableSize(m_bytesToTransfer); // remove the unit from the bytesReceived value if bytesToReceive has the same const QString tmp = bytesToReceive.mid(bytesToReceive.indexOf(QLatin1Char(' '))); if (bytesReceived.endsWith(tmp)) bytesReceived.chop(tmp.length()); progressText = tr("%1 of %2").arg(bytesReceived).arg(bytesToReceive); } else { if (m_bytesTransfered > 0) progressText = tr("%1 received.").arg(QInstaller::humanReadableSize(m_bytesTransfered)); } if (!progressText.isEmpty()) progressText += QLatin1Char(' '); progressText += tr("(%1/sec)").arg(QInstaller::humanReadableSize(m_bytesPerSecond)); if (m_bytesToTransfer > 0 && m_bytesPerSecond > 0) { const qint64 time = (m_bytesToTransfer - m_bytesTransfered) / m_bytesPerSecond; int s = time % 60; const int d = time / 86400; const int h = (time / 3600) - (d * 24); const int m = (time / 60) - (d * 1440) - (h * 60); QString days; if (d > 0) days = tr("%n day(s), ", "", d); QString hours; if (h > 0) hours = tr("%n hour(s), ", "", h); QString minutes; if (m > 0) minutes = tr("%n minute(s)", "", m); QString seconds; if (s >= 0 && minutes.isEmpty()) { s = (s <= 0 ? 1 : s); seconds = tr("%n second(s)", "", s); } progressText += tr(" - %1%2%3%4 remaining.").arg(days).arg(hours).arg(minutes).arg(seconds); } else { progressText += tr(" - unknown time remaining."); } return progressText; } QByteArray FileTaskObserver::checkSum() const { return m_hash.result(); } void FileTaskObserver::addCheckSumData(const char *data, int length) { m_hash.addData(data, length); } void FileTaskObserver::addSample(qint64 sample) { m_currentSpeedBin += sample; } void FileTaskObserver::setBytesTransfered(qint64 bytesReceived) { m_bytesTransfered = bytesReceived; } void FileTaskObserver::addBytesTransfered(qint64 bytesReceived) { m_bytesTransfered += bytesReceived; } void FileTaskObserver::setBytesToTransfer(qint64 bytesToReceive) { m_bytesToTransfer = bytesToReceive; } // -- private void FileTaskObserver::init() { m_hash.reset(); m_sampleIndex = 0; m_bytesTransfered = 0; m_bytesToTransfer = 0; m_bytesPerSecond = 0; m_currentSpeedBin = 0; m_timerId = -1; m_timerInterval = 100; memset(m_samples, 0, sizeof(m_samples)); m_timerId = startTimer(m_timerInterval); } void FileTaskObserver::timerEvent(QTimerEvent *event) { Q_UNUSED(event) unsigned int windowSize = sizeof(m_samples) / sizeof(qint64); // add speed of last time bin to the window m_samples[m_sampleIndex % windowSize] = m_currentSpeedBin; m_currentSpeedBin = 0; // reset bin for next time interval // advance the sample index m_sampleIndex++; m_bytesPerSecond = 0; // dynamic window size until the window is completely filled if (m_sampleIndex < windowSize) windowSize = m_sampleIndex; for (unsigned int i = 0; i < windowSize; ++i) m_bytesPerSecond += m_samples[i]; m_bytesPerSecond /= windowSize; // computer average m_bytesPerSecond *= 1000.0 / m_timerInterval; // rescale to bytes/second } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/observer.h0100777000000000000000000000473313761647206020624 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef OBSERVER_H #define OBSERVER_H #include #include namespace QInstaller { class Observer : public QObject { Q_OBJECT Q_DISABLE_COPY(Observer) public: Observer() {} virtual ~Observer() {} virtual int progressValue() const = 0; virtual QString progressText() const = 0; }; class FileTaskObserver : public Observer { Q_OBJECT Q_DISABLE_COPY(FileTaskObserver) public: FileTaskObserver(QCryptographicHash::Algorithm algorithm); ~FileTaskObserver(); int progressValue() const; QString progressText() const; QByteArray checkSum() const; void addCheckSumData(const char *data, int length); void addSample(qint64 sample); void timerEvent(QTimerEvent *event); void setBytesTransfered(qint64 bytesTransfered); void addBytesTransfered(qint64 bytesTransfered); void setBytesToTransfer(qint64 bytesToTransfer); private: void init(); private: int m_timerId; int m_timerInterval; qint64 m_bytesTransfered; qint64 m_bytesToTransfer; qint64 m_samples[50]; quint32 m_sampleIndex; qint64 m_bytesPerSecond; qint64 m_currentSpeedBin; QCryptographicHash m_hash; }; } // namespace QInstaller #endif // OBSERVER_H qt-installer-framework-4.0.1/src/libs/installer/packagemanagercore.cpp0100777000000000000000000041512113761647206023124 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "packagemanagercore.h" #include "packagemanagercore_p.h" #include "adminauthorization.h" #include "binarycontent.h" #include "component.h" #include "componentmodel.h" #include "downloadarchivesjob.h" #include "errors.h" #include "globals.h" #include "messageboxhandler.h" #include "packagemanagerproxyfactory.h" #include "progresscoordinator.h" #include "qprocesswrapper.h" #include "qsettingswrapper.h" #include "remoteclient.h" #include "remotefileengine.h" #include "settings.h" #include "utils.h" #include "installercalculator.h" #include "uninstallercalculator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysinfo.h" #include "updateoperationfactory.h" #ifdef Q_OS_WIN # include "qt_windows.h" #endif #include /*! \namespace QInstaller \inmodule QtInstallerFramework \keyword qinstaller-module \brief Contains classes to implement the core functionality of the Qt Installer Framework and the installer UI. */ using namespace QInstaller; /*! \class QInstaller::PackageManagerCore \inmodule QtInstallerFramework \brief The PackageManagerCore class provides the core functionality of the Qt Installer Framework. */ /*! \enum PackageManagerCore::WizardPage This enum type holds the pre-defined package manager pages: \value Introduction \l{Introduction Page} \value TargetDirectory \l{Target Directory Page} \value ComponentSelection \l{Component Selection Page} \value LicenseCheck \l{License Agreement Page} \value StartMenuSelection \l{Start Menu Directory Page} \value ReadyForInstallation \l{Ready for Installation Page} \value PerformInstallation \l{Perform Installation Page} \value InstallationFinished \l{Finished Page} \omitvalue End */ /*! \enum PackageManagerCore::Status This enum type holds the package manager status: \value Success Installation was successful. \value Failure Installation failed. \value Running Installation is in progress. \value Canceled Installation was canceled. \value Unfinished Installation was not completed. \value ForceUpdate Installation has to be updated. \value EssentialUpdated Installation essential components were updated. */ /*! \property PackageManagerCore::status \brief Installation status. */ /*! \fn QInstaller::PackageManagerCore::aboutCalculateComponentsToInstall() const \sa {installer::aboutCalculateComponentsToInstall}{installer.aboutCalculateComponentsToInstall} */ /*! \fn QInstaller::PackageManagerCore::finishedCalculateComponentsToInstall() const \sa {installer::finishedCalculateComponentsToInstall}{installer.finishedCalculateComponentsToInstall} */ /*! \fn QInstaller::PackageManagerCore::aboutCalculateComponentsToUninstall() const \sa {installer::aboutCalculateComponentsToUninstall}{installer.aboutCalculateComponentsToUninstall} */ /*! \fn QInstaller::PackageManagerCore::finishedCalculateComponentsToUninstall() const \sa {installer::finishedCalculateComponentsToUninstall}{installer.finishedCalculateComponentsToUninstall} */ /*! \fn QInstaller::PackageManagerCore::componentAdded(QInstaller::Component *comp) Emitted when the new root component \a comp is added. \sa {installer::componentAdded}{installer.componentAdded} \sa rootComponentsAdded(), updaterComponentsAdded() */ /*! \fn QInstaller::PackageManagerCore::rootComponentsAdded(QList components) Emitted when the list of root components specified by \a components is added. \sa {installer::rootComponentsAdded}{installer.rootComponentsAdded} \sa componentAdded(), updaterComponentsAdded() */ /*! \fn QInstaller::PackageManagerCore::updaterComponentsAdded(QList components) Emitted when a new list of updater components specified by \a components is added. \sa {installer::updaterComponentsAdded}{installer.updaterComponentsAdded} \sa componentAdded(), rootComponentsAdded() */ /*! \fn QInstaller::PackageManagerCore::valueChanged(const QString &key, const QString &value) Emitted when the value \a value of the key \a key changes. \sa {installer::valueChanged}{installer.valueChanged}, setValue() */ /*! \fn QInstaller::PackageManagerCore::currentPageChanged(int page) Emitted when the current page \a page changes. \sa {installer::currentPageChanged}{installer.currentPageChanged} */ /*! \fn QInstaller::PackageManagerCore::finishButtonClicked() \sa {installer::finishButtonClicked}{installer.finishButtonClicked} */ /*! \fn QInstaller::PackageManagerCore::metaJobProgress(int progress) Triggered with progress updates of the communication with a remote repository. Values of \a progress range from 0 to 100. \sa {installer::metaJobProgress}{installer.metaJobProgress} */ /*! \fn QInstaller::PackageManagerCore::metaJobTotalProgress(int progress) Triggered when the total \a progress value of the communication with a remote repository changes. \sa {installer::metaJobTotalProgress}{installer.metaJobTotalProgress} */ /*! \fn QInstaller::PackageManagerCore::metaJobInfoMessage(const QString &message) Triggered with informative updates, \a message, of the communication with a remote repository. \sa {installer::metaJobInfoMessage}{installer.metaJobInfoMessage} */ /*! \fn QInstaller::PackageManagerCore::startAllComponentsReset() \sa {installer::startAllComponentsReset}{installer.startAllComponentsReset} \sa finishAllComponentsReset() */ /*! \fn QInstaller::PackageManagerCore::finishAllComponentsReset(const QList &rootComponents) Triggered when the list of new root components, \a rootComponents, has been updated. \sa {installer::finishAllComponentsReset}{installer.finishAllComponentsReset} \sa startAllComponentsReset() */ /*! \fn QInstaller::PackageManagerCore::startUpdaterComponentsReset() \sa {installer::startUpdaterComponentsReset}{installer.startUpdaterComponentsReset} */ /*! \fn QInstaller::PackageManagerCore::finishUpdaterComponentsReset(const QList &componentsWithUpdates) Triggered when the list of available remote updates, \a componentsWithUpdates, has been updated. \sa {installer::finishUpdaterComponentsReset}{installer.finishUpdaterComponentsReset} */ /*! \fn QInstaller::PackageManagerCore::installationStarted() \sa {installer::installationStarted}{installer.installationStarted}, installationFinished(), installationInterrupted() */ /*! \fn QInstaller::PackageManagerCore::installationInterrupted() \sa {installer::installationInterrupted}{installer.installationInterrupted}, interrupt(), installationStarted(), installationFinished() */ /*! \fn QInstaller::PackageManagerCore::installationFinished() \sa {installer::installationFinished}{installer.installationFinished}, installationStarted(), installationInterrupted() */ /*! \fn QInstaller::PackageManagerCore::updateFinished() \sa {installer::installationFinished}{installer.installationFinished} */ /*! \fn QInstaller::PackageManagerCore::uninstallationStarted() \sa {installer::uninstallationStarted}{installer.uninstallationStarted} \sa uninstallationFinished() */ /*! \fn QInstaller::PackageManagerCore::uninstallationFinished() \sa {installer::uninstallationFinished}{installer.uninstallationFinished} \sa uninstallationStarted() */ /*! \fn QInstaller::PackageManagerCore::titleMessageChanged(const QString &title) Emitted when the text of the installer status (on the PerformInstallation page) changes to \a title. \sa {installer::titleMessageChanged}{installer.titleMessageChanged} */ /*! \fn QInstaller::PackageManagerCore::wizardPageInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page) Emitted when a custom \a widget is about to be inserted into \a page by addWizardPage(). \sa {installer::wizardPageInsertionRequested}{installer.wizardPageInsertionRequested} */ /*! \fn QInstaller::PackageManagerCore::wizardPageRemovalRequested(QWidget *widget) Emitted when a \a widget is removed by removeWizardPage(). \sa {installer::wizardPageRemovalRequested}{installer.wizardPageRemovalRequested} */ /*! \fn QInstaller::PackageManagerCore::wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page, int position) Emitted when a \a widget is inserted into \a page by addWizardPageItem(). If several widgets are added to the same \a page, widget with lower \a position number will be inserted on top. \sa {installer::wizardWidgetInsertionRequested}{installer.wizardWidgetInsertionRequested} */ /*! \fn QInstaller::PackageManagerCore::wizardWidgetRemovalRequested(QWidget *widget) Emitted when a \a widget is removed by removeWizardPageItem(). \sa {installer::wizardWidgetRemovalRequested}{installer.wizardWidgetRemovalRequested} */ /*! \fn QInstaller::PackageManagerCore::wizardPageVisibilityChangeRequested(bool visible, int page) Emitted when the visibility of the page with the ID \a page changes to \a visible. \sa setDefaultPageVisible() \sa {installer::wizardPageVisibilityChangeRequested}{installer.wizardPageVisibilityChangeRequested} */ /*! \fn QInstaller::PackageManagerCore::setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name, const QString &callbackName) Requests that a validator be set for the custom page specified by \a name and \a callbackName for the component \a component. Triggered when setValidatorForCustomPage() is called. \sa {installer::setValidatorForCustomPageRequested}{installer.setValidatorForCustomPageRequested} */ /*! \fn QInstaller::PackageManagerCore::setAutomatedPageSwitchEnabled(bool request) Triggered when the automatic switching from the perform installation to the installation finished page is enabled (\a request is \c true) or disabled (\a request is \c false). The automatic switching is disabled automatically when for example the user expands or unexpands the \uicontrol Details section of the PerformInstallation page. \sa {installer::setAutomatedPageSwitchEnabled}{installer.setAutomatedPageSwitchEnabled} */ /*! \fn QInstaller::PackageManagerCore::coreNetworkSettingsChanged() \sa {installer::coreNetworkSettingsChanged}{installer.coreNetworkSettingsChanged} */ /*! \fn QInstaller::PackageManagerCore::guiObjectChanged(QObject *gui) Emitted when the GUI object is set to \a gui. */ /*! \fn QInstaller::PackageManagerCore::unstableComponentFound(const QString &type, const QString &errorMessage, const QString &component) Emitted when an unstable \a component is found containing an unstable \a type and \a errorMessage. */ /*! \fn QInstaller::PackageManagerCore::installerBinaryMarkerChanged(qint64 magicMarker) Emitted when installer binary marker \a magicMarker has changed. */ Q_GLOBAL_STATIC(QMutex, globalModelMutex); static QFont *sVirtualComponentsFont = nullptr; Q_GLOBAL_STATIC(QMutex, globalVirtualComponentsFontMutex); static bool sNoForceInstallation = false; static bool sNoDefaultInstallation = false; static bool sVirtualComponentsVisible = false; static bool sCreateLocalRepositoryFromBinary = false; static bool componentMatches(const Component *component, const QString &name, const QString &version = QString()) { if (name.isEmpty() || component->name() != name) return false; if (version.isEmpty()) return true; // can be remote or local version return PackageManagerCore::versionMatches(component->value(scVersion), version); } /*! Creates the maintenance tool in the installation directory. */ void PackageManagerCore::writeMaintenanceTool() { if (d->m_disableWriteMaintenanceTool) { qCDebug(QInstaller::lcInstallerInstallLog()) << "Maintenance tool writing disabled."; return; } if (d->m_needToWriteMaintenanceTool) { try { d->writeMaintenanceTool(d->m_performedOperationsOld + d->m_performedOperationsCurrentSession); bool gainedAdminRights = false; if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } d->m_localPackageHub->writeToDisk(); if (gainedAdminRights) dropAdminRights(); d->m_needToWriteMaintenanceTool = false; } catch (const Error &error) { qCritical() << "Error writing Maintenance Tool: " << error.message(); MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("WriteError"), tr("Error writing Maintenance Tool"), error.message(), QMessageBox::Ok, QMessageBox::Ok); } } } /*! Creates the maintenance tool configuration files. */ void PackageManagerCore::writeMaintenanceConfigFiles() { d->writeMaintenanceConfigFiles(); } /*! Disables writing of maintenance tool for the current session if \a disable is \c true. */ void PackageManagerCore::disableWriteMaintenanceTool(bool disable) { d->m_disableWriteMaintenanceTool = disable; } /*! Resets the class to its initial state. */ void PackageManagerCore::reset() { d->m_completeUninstall = false; d->m_needsHardRestart = false; d->m_status = PackageManagerCore::Unfinished; d->m_installerBaseBinaryUnreplaced.clear(); d->m_coreCheckedHash.clear(); d->m_componentsToInstallCalculated = false; } /*! Sets the maintenance tool UI to \a gui. */ void PackageManagerCore::setGuiObject(QObject *gui) { if (gui == d->m_guiObject) return; d->m_guiObject = gui; emit guiObjectChanged(gui); } /*! Returns the GUI object. */ QObject *PackageManagerCore::guiObject() const { return d->m_guiObject; } /*! Sets the uninstallation to be \a complete. If \a complete is false, only components deselected by the user will be uninstalled. This option applies only on uninstallation. \sa {installer::setCompleteUninstallation}{installer.setCompleteUninstallation} */ void PackageManagerCore::setCompleteUninstallation(bool complete) { d->m_completeUninstall = complete; } /*! \sa {installer::cancelMetaInfoJob}{installer.cancelMetaInfoJob} */ void PackageManagerCore::cancelMetaInfoJob() { d->m_metadataJob.cancel(); } /*! \sa {installer::componentsToInstallNeedsRecalculation}{installer.componentsToInstallNeedsRecalculation} */ void PackageManagerCore::componentsToInstallNeedsRecalculation() { d->clearInstallerCalculator(); d->clearUninstallerCalculator(); QList selectedComponentsToInstall = componentsMarkedForInstallation(); d->m_componentsToInstallCalculated = d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall); QList componentsToInstall = d->installerCalculator()->orderedComponentsToInstall(); QList selectedComponentsToUninstall; foreach (Component *component, components(ComponentType::All)) { if (component->uninstallationRequested() && !selectedComponentsToInstall.contains(component)) selectedComponentsToUninstall.append(component); } d->uninstallerCalculator()->appendComponentsToUninstall(selectedComponentsToUninstall); QSet componentsToUninstall = d->uninstallerCalculator()->componentsToUninstall(); foreach (Component *component, components(ComponentType::All)) component->setInstallAction(component->isInstalled() ? ComponentModelHelper::KeepInstalled : ComponentModelHelper::KeepUninstalled); foreach (Component *component, componentsToUninstall) component->setInstallAction(ComponentModelHelper::Uninstall); foreach (Component *component, componentsToInstall) component->setInstallAction(ComponentModelHelper::Install); // update all nodes uncompressed size foreach (Component *const component, components(ComponentType::Root)) component->updateUncompressedSize(); // this is a recursive call } /*! Forces a recalculation of components to install. \sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated} */ void PackageManagerCore::clearComponentsToInstallCalculated() { d->m_componentsToInstallCalculated = false; } /*! \sa {installer::autoAcceptMessageBoxes}{installer.autoAcceptMessageBoxes} \sa autoRejectMessageBoxes(), setMessageBoxAutomaticAnswer() */ void PackageManagerCore::autoAcceptMessageBoxes() { MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Accept); } /*! \sa {installer::autoRejectMessageBoxes}{installer.autoRejectMessageBoxes} \sa autoAcceptMessageBoxes(), setMessageBoxAutomaticAnswer() */ void PackageManagerCore::autoRejectMessageBoxes() { MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Reject); } /*! Automatically closes the message box with the ID \a identifier as if the user had pressed \a button. This can be used for unattended (automatic) installations. \sa {installer::setMessageBoxAutomaticAnswer}{installer.setMessageBoxAutomaticAnswer} \sa QMessageBox, autoAcceptMessageBoxes(), autoRejectMessageBoxes() */ void PackageManagerCore::setMessageBoxAutomaticAnswer(const QString &identifier, int button) { MessageBoxHandler::instance()->setAutomaticAnswer(identifier, static_cast(button)); } /*! Automatically uses the default button value set for the message box. This can be used for unattended (automatic) installations. */ void PackageManagerCore::acceptMessageBoxDefaultButton() { MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Default); } /*! Automatically accepts all license agreements required to install the selected components. \sa {installer::setAutoAcceptLicenses}{installer.setAutoAcceptLicenses} */ void PackageManagerCore::setAutoAcceptLicenses() { d->m_autoAcceptLicenses = true; } /*! Automatically sets the existing directory or filename \a value to QFileDialog with the ID \a identifier. QFileDialog can be called from script. This can be used for unattended (automatic) installations. \sa {installer::setFileDialogAutomaticAnswer}{installer.setFileDialogAutomaticAnswer} \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} */ void PackageManagerCore::setFileDialogAutomaticAnswer(const QString &identifier, const QString &value) { m_fileDialogAutomaticAnswers.insert(identifier, value); } /*! Removes the automatic answer from QFileDialog with the ID \a identifier. QFileDialog can be called from script. \sa {installer::removeFileDialogAutomaticAnswer}{installer.removeFileDialogAutomaticAnswer} \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} */ void PackageManagerCore::removeFileDialogAutomaticAnswer(const QString &identifier) { m_fileDialogAutomaticAnswers.remove(identifier); } /*! Returns \c true if QFileDialog with the ID \a identifier has an automatic answer set. \sa {installer::containsFileDialogAutomaticAnswer}{installer.containsFileDialogAutomaticAnswer} \sa {installer::removeFileDialogAutomaticAnswer}{installer.removeFileDialogAutomaticAnswer} \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} */ bool PackageManagerCore::containsFileDialogAutomaticAnswer(const QString &identifier) const { return m_fileDialogAutomaticAnswers.contains(identifier); } /*! * Returns the hash of file dialog automatic answers * \sa setFileDialogAutomaticAnswer() */ QHash PackageManagerCore::fileDialogAutomaticAnswers() const { return m_fileDialogAutomaticAnswers; } /*! Set to automatically confirm install, update or remove without asking user. */ void PackageManagerCore::setAutoConfirmCommand() { d->m_autoConfirmCommand = true; } /*! Returns the size of the component \a component as \a value. */ quint64 PackageManagerCore::size(QInstaller::Component *component, const QString &value) const { if (component->installAction() == ComponentModelHelper::Install) return component->value(value).toLongLong(); return quint64(0); } /*! \sa {installer::requiredDiskSpace}{installer.requiredDiskSpace} \sa requiredTemporaryDiskSpace() */ quint64 PackageManagerCore::requiredDiskSpace() const { quint64 result = 0; foreach (QInstaller::Component *component, orderedComponentsToInstall()) result += size(component, scUncompressedSize); return result; } /*! \sa {installer::requiredTemporaryDiskSpace}{installer.requiredTemporaryDiskSpace} \sa requiredDiskSpace() */ quint64 PackageManagerCore::requiredTemporaryDiskSpace() const { if (isOfflineOnly()) return 0; quint64 result = 0; foreach (QInstaller::Component *component, orderedComponentsToInstall()) result += size(component, scCompressedSize); return result; } /*! Returns the number of archives that will be downloaded. \a partProgressSize is reserved for the download progress. */ int PackageManagerCore::downloadNeededArchives(double partProgressSize) { Q_ASSERT(partProgressSize >= 0 && partProgressSize <= 1); QList > archivesToDownload; QList neededComponents = orderedComponentsToInstall(); foreach (Component *component, neededComponents) { // collect all archives to be downloaded const QStringList toDownload = component->downloadableArchives(); foreach (const QString &versionFreeString, toDownload) { archivesToDownload.push_back(qMakePair(QString::fromLatin1("installer://%1/%2") .arg(component->name(), versionFreeString), QString::fromLatin1("%1/%2/%3") .arg(component->repositoryUrl().toString(), component->name(), versionFreeString))); } } if (archivesToDownload.isEmpty()) return 0; ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nDownloading packages...")); DownloadArchivesJob archivesJob(this); archivesJob.setAutoDelete(false); archivesJob.setArchivesToDownload(archivesToDownload); connect(this, &PackageManagerCore::installationInterrupted, &archivesJob, &Job::cancel); connect(&archivesJob, &DownloadArchivesJob::outputTextChanged, ProgressCoordinator::instance(), &ProgressCoordinator::emitLabelAndDetailTextChanged); connect(&archivesJob, &DownloadArchivesJob::downloadStatusChanged, ProgressCoordinator::instance(), &ProgressCoordinator::downloadStatusChanged); ProgressCoordinator::instance()->registerPartProgress(&archivesJob, SIGNAL(progressChanged(double)), partProgressSize); archivesJob.start(); archivesJob.waitForFinished(); if (archivesJob.error() == Job::Canceled) interrupt(); else if (archivesJob.error() != Job::NoError) throw Error(archivesJob.errorString()); if (d->statusCanceledOrFailed()) throw Error(tr("Installation canceled by user.")); ProgressCoordinator::instance()->emitDownloadStatus(tr("All downloads finished.")); return archivesJob.numberOfDownloads(); } /*! Returns \c true if an essential component update is found. */ bool PackageManagerCore::foundEssentialUpdate() const { return d->m_foundEssentialUpdate; } /*! Sets the value of \a foundEssentialUpdate, defaults to \c true. */ void PackageManagerCore::setFoundEssentialUpdate(bool foundEssentialUpdate) { d->m_foundEssentialUpdate = foundEssentialUpdate; } /*! Returns \c true if a hard restart of the application is requested. */ bool PackageManagerCore::needsHardRestart() const { return d->m_needsHardRestart; } /*! Enables a component to request a hard restart of the application if \a needsHardRestart is set to \c true. */ void PackageManagerCore::setNeedsHardRestart(bool needsHardRestart) { d->m_needsHardRestart = needsHardRestart; } /*! Cancels the installation and performs the UNDO step of all already executed operations. */ void PackageManagerCore::rollBackInstallation() { emit titleMessageChanged(tr("Cancelling the Installer")); // this unregisters all operation progressChanged connected ProgressCoordinator::instance()->setUndoMode(); const int progressOperationCount = d->countProgressOperations(d->m_performedOperationsCurrentSession); const double progressOperationSize = double(1) / progressOperationCount; // reregister all the undo operations with the new size to the ProgressCoordinator foreach (Operation *const operation, d->m_performedOperationsCurrentSession) { QObject *const operationObject = dynamic_cast (operation); if (operationObject != nullptr) { const QMetaObject* const mo = operationObject->metaObject(); if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) { ProgressCoordinator::instance()->registerPartProgress(operationObject, SIGNAL(progressChanged(double)), progressOperationSize); } } } while (!d->m_performedOperationsCurrentSession.isEmpty()) { try { Operation *const operation = d->m_performedOperationsCurrentSession.takeLast(); const bool becameAdmin = !RemoteClient::instance().isActive() && operation->value(QLatin1String("admin")).toBool() && gainAdminRights(); if (operation->value(QLatin1String("uninstall-only")).toBool() && QVariant(value(scRemoveTargetDir)).toBool() && (operation->name() == QLatin1String("Mkdir"))) { // We know the mkdir operation which is creating the target path. If we do a // full uninstall, prevent a forced remove of the full install path including the // target, instead try to remove the target only and only if it is empty, // otherwise fail silently. Note: this can only happen if RemoveTargetDir is set, // otherwise the operation does not exist at all. operation->setValue(QLatin1String("forceremoval"), false); } PackageManagerCorePrivate::performOperationThreaded(operation, PackageManagerCorePrivate::Undo); const QString componentName = operation->value(QLatin1String("component")).toString(); if (!componentName.isEmpty()) { Component *component = componentByName(checkableName(componentName)); if (!component) component = d->componentsToReplace().value(componentName).second; if (component) { component->setUninstalled(); d->m_localPackageHub->removePackage(component->name()); } } d->m_localPackageHub->writeToDisk(); if (isInstaller()) { if (d->m_localPackageHub->packageInfoCount() == 0) { QFile file(d->m_localPackageHub->fileName()); file.remove(); } } if (becameAdmin) dropAdminRights(); } catch (const Error &e) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("ElevationError"), tr("Authentication Error"), tr("Some components " "could not be removed completely because administrative rights could not be acquired: %1.") .arg(e.message())); } catch (...) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("unknown"), tr("Unknown error."), tr("Some components could not be removed completely because an unknown " "error happened.")); } } } /*! Returns whether the file extension \a extension is already registered in the Windows registry. Returns \c false on all other platforms. \sa {installer::isFileExtensionRegistered}{installer.isFileExtensionRegistered} */ bool PackageManagerCore::isFileExtensionRegistered(const QString &extension) const { QSettingsWrapper settings(QLatin1String("HKEY_CLASSES_ROOT"), QSettingsWrapper::NativeFormat); return settings.value(QString::fromLatin1(".%1/Default").arg(extension)).isValid(); } /*! Returns \c true if the \a filePath exists; otherwise returns \c false. \note If the file is a symlink that points to a non existing file, \c false is returned. \sa {installer::fileExists}{installer.fileExists} */ bool PackageManagerCore::fileExists(const QString &filePath) const { return QFileInfo(filePath).exists(); } /*! Returns the contents of the file \a filePath using the encoding specified by \a codecName. The file is read in the text mode, that is, end-of-line terminators are translated to the local encoding. \note If the file does not exist or an error occurs while reading the file, an empty string is returned. \sa {installer::readFile}{installer.readFile} */ QString PackageManagerCore::readFile(const QString &filePath, const QString &codecName) const { QFile f(filePath); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return QString(); QTextCodec *codec = QTextCodec::codecForName(qPrintable(codecName)); if (!codec) return QString(); QTextStream stream(&f); stream.setCodec(codec); return stream.readAll(); } /*! * Prints \a title to console and reads console input. Function will halt the * installer and wait for user input. Returns a line which user has typed into * console. The maximum allowed line length is set to \a maxlen. If the stream * contains lines longer than this, then the line will be split after maxlen * characters. If \a maxlen is 0, the line can be of any length. * * \note Can be only called when installing from command line instance without GUI. * * \sa {installer::readConsoleLine}{installer.readConsoleLine} */ QString PackageManagerCore::readConsoleLine(const QString &title, qint64 maxlen) const { if (!isCommandLineInstance()) return QString(); if (!title.isEmpty()) qDebug() << title; QTextStream stream(stdin); QString input; stream.readLineInto(&input, maxlen); return input; } /*! Checks whether the target directory \a targetDirectory exists and has contents: \list \li Returns \c true if the directory exists and is empty. \li Returns \c false if the directory already exists and contains an installation. \li Returns \c false if the target is a file or a symbolic link. \li Returns \c true or \c false if the directory exists but is not empty, depending on the choice that the end users make in the displayed message box. \endlist */ bool PackageManagerCore::checkTargetDir(const QString &targetDirectory) { const QDir dir(targetDirectory); // the directory exists and is empty... if (dir.exists() && dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) return true; const QFileInfo fi(targetDirectory); if (fi.isDir()) { QString fileName = settings().maintenanceToolName(); #if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) fileName += QLatin1String(".app/Contents/MacOS/") + fileName; #elif defined(Q_OS_WIN) fileName += QLatin1String(".exe"); #endif QFileInfo fi2(targetDirectory + QDir::separator() + fileName); if (fi2.exists()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("TargetDirectoryInUse"), tr("Error"), tr("The directory you selected already " "exists and contains an installation. Choose a different target for installation.")); return false; } QMessageBox::StandardButton bt = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), QLatin1String("OverwriteTargetDirectory"), tr("Warning"), tr("You have selected an existing, non-empty directory for installation.\nNote that it will be " "completely wiped on uninstallation of this application.\nIt is not advisable to install into " "this directory as installation might fail.\nDo you want to continue?"), QMessageBox::Yes | QMessageBox::No); return bt == QMessageBox::Yes; } else if (fi.isFile() || fi.isSymLink()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("WrongTargetDirectory"), tr("Error"), tr("You have selected an existing file " "or symlink, please choose a different target for installation.")); return false; } return true; } /*! Returns a warning if the path to the target directory \a targetDirectory is not set or if it is invalid. */ QString PackageManagerCore::targetDirWarning(const QString &targetDirectory) const { if (targetDirectory.isEmpty()) return tr("The installation path cannot be empty, please specify a valid directory."); QDir target(targetDirectory); if (target.isRelative()) return tr("The installation path cannot be relative, please specify an absolute path."); QString nativeTargetDir = QDir::toNativeSeparators(target.absolutePath()); if (!settings().allowNonAsciiCharacters()) { for (int i = 0; i < nativeTargetDir.length(); ++i) { if (nativeTargetDir.at(i).unicode() & 0xff80) { return tr("The path or installation directory contains non ASCII characters. This " "is currently not supported! Please choose a different path or installation " "directory."); } } } target = target.canonicalPath(); if (!target.isEmpty() && (target == QDir::root() || target == QDir::home())) { return tr("As the install directory is completely deleted, installing in %1 is forbidden.") .arg(QDir::toNativeSeparators(target.path())); } #ifdef Q_OS_WIN // folder length (set by user) + maintenance tool name length (no extension) + extra padding if ((nativeTargetDir.length() + settings().maintenanceToolName().length() + 20) >= MAX_PATH) { return tr("The path you have entered is too long, please make sure to " "specify a valid path."); } static QRegularExpression reg(QLatin1String( "^(?[a-zA-Z]:\\\\)|" "^(\\\\\\\\(?\\w+)\\\\)|" "^(\\\\\\\\(?\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\\\)")); const QRegularExpressionMatch regMatch = reg.match(nativeTargetDir); const QString ipMatch = regMatch.captured(QLatin1String("ip")); const QString pathMatch = regMatch.captured(QLatin1String("path")); const QString driveMatch = regMatch.captured(QLatin1String("drive")); if (ipMatch.isEmpty() && pathMatch.isEmpty() && driveMatch.isEmpty()) { return tr("The path you have entered is not valid, please make sure to " "specify a valid target."); } if (!driveMatch.isEmpty()) { bool validDrive = false; const QFileInfo drive(driveMatch); foreach (const QFileInfo &driveInfo, QDir::drives()) { if (drive == driveInfo) { validDrive = true; break; } } if (!validDrive) { // right now we can only verify local drives return tr("The path you have entered is not valid, please make sure to " "specify a valid drive."); } nativeTargetDir = nativeTargetDir.mid(2); } if (nativeTargetDir.endsWith(QLatin1Char('.'))) return tr("The installation path must not end with '.', please specify a valid directory."); QString ambiguousChars = QLatin1String("[\"~<>|?*!@#$%^&:,; ]" "|(\\\\CON)(\\\\|$)|(\\\\PRN)(\\\\|$)|(\\\\AUX)(\\\\|$)|(\\\\NUL)(\\\\|$)|(\\\\COM\\d)(\\\\|$)|(\\\\LPT\\d)(\\\\|$)"); #else // Q_OS_WIN QString ambiguousChars = QStringLiteral("[~<>|?*!@#$%^&:,; \\\\]"); #endif // Q_OS_WIN if (settings().allowSpaceInPath()) ambiguousChars.remove(QLatin1Char(' ')); static QRegularExpression ambCharRegEx(ambiguousChars, QRegularExpression::CaseInsensitiveOption); // check if there are not allowed characters in the target path QRegularExpressionMatch match = ambCharRegEx.match(nativeTargetDir); if (match.hasMatch()) { return tr("The installation path must not contain \"%1\", " "please specify a valid directory.").arg(match.captured(0)); } return QString(); } // -- QInstaller /*! Used by operation runner to get a fake installer. */ PackageManagerCore::PackageManagerCore() : d(new PackageManagerCorePrivate(this)) { //TODO: Can be removed if installerbase can do what operation runner does. Repository::registerMetaType(); // register, cause we stream the type as QVariant qRegisterMetaType("QInstaller::PackageManagerCore::Status"); qRegisterMetaType("QInstaller::PackageManagerCore::WizardPage"); } /*! Creates an installer or uninstaller and performs sanity checks on the operations specified by \a operations. A hash table of variables to be stored as package manager core values can be specified by \a params. Sets the current instance type to be either a GUI or CLI one based on the value of \a commandLineInstance. The magic marker \a magicmaker is a \c quint64 that identifies the type of the binary: \c installer or \c uninstaller. Creates and initializes a remote client. Requests administrator's rights for QFile, QSettings, and QProcess operations. Calls \c init() with \a socketName, \a key, and \a mode to set the server side authorization key. */ PackageManagerCore::PackageManagerCore(qint64 magicmaker, const QList &operations, const QString &socketName, const QString &key, Protocol::Mode mode, const QHash ¶ms, const bool commandLineInstance) : d(new PackageManagerCorePrivate(this, magicmaker, operations)) { setCommandLineInstance(commandLineInstance); Repository::registerMetaType(); // register, cause we stream the type as QVariant qRegisterMetaType("QInstaller::PackageManagerCore::Status"); qRegisterMetaType("QInstaller::PackageManagerCore::WizardPage"); d->initialize(params); // Creates and initializes a remote client, makes us get admin rights for QFile, QSettings // and QProcess operations. Init needs to called to set the server side authorization key. if (!d->isUpdater()) { RemoteClient::instance().init(socketName, key, mode, Protocol::StartAs::SuperUser); RemoteClient::instance().setAuthorizationFallbackDisabled(settings().disableAuthorizationFallback()); } // // Sanity check to detect a broken installations with missing operations. // Every installed package should have at least one MinimalProgress operation. // QSet installedPackages = d->m_core->localInstalledPackages().keys().toSet(); QSet operationPackages; foreach (QInstaller::Operation *operation, d->m_performedOperationsOld) { if (operation->hasValue(QLatin1String("component"))) operationPackages.insert(operation->value(QLatin1String("component")).toString()); } QSet packagesWithoutOperation = installedPackages - operationPackages; QSet orphanedOperations = operationPackages - installedPackages; if (!packagesWithoutOperation.isEmpty() || !orphanedOperations.isEmpty()) { qCritical() << "Operations missing for installed packages" << packagesWithoutOperation.toList(); qCritical() << "Orphaned operations" << orphanedOperations.toList(); qCritical() << "Your installation seems to be corrupted. Please consider re-installing from scratch, " "remove the packages from components.xml which operations are missing, " "or reinstall the packages."; } else { qCDebug(QInstaller::lcInstallerInstallLog) << "Operations sanity check succeeded."; } connect(this, &PackageManagerCore::metaJobProgress, ProgressCoordinator::instance(), &ProgressCoordinator::printProgressPercentage); connect(this, &PackageManagerCore::metaJobInfoMessage, ProgressCoordinator::instance(), &ProgressCoordinator::printProgressMessage); } class VerboseWriterAdminOutput : public VerboseWriterOutput { public: VerboseWriterAdminOutput(PackageManagerCore *core) : m_core(core) {} virtual bool write(const QString &fileName, QIODevice::OpenMode openMode, const QByteArray &data) { bool gainedAdminRights = false; if (!RemoteClient::instance().isActive()) { m_core->gainAdminRights(); gainedAdminRights = true; } RemoteFileEngine file; file.setFileName(fileName); if (file.open(openMode)) { file.write(data.constData(), data.size()); file.close(); if (gainedAdminRights) m_core->dropAdminRights(); return true; } if (gainedAdminRights) m_core->dropAdminRights(); return false; } private: PackageManagerCore *m_core; }; /*! Destroys the instance. */ PackageManagerCore::~PackageManagerCore() { if (!isUninstaller() && !(isInstaller() && status() == PackageManagerCore::Canceled)) { QDir targetDir(value(scTargetDir)); QString logFileName = targetDir.absoluteFilePath(value(QLatin1String("LogFileName"), QLatin1String("InstallationLog.txt"))); QInstaller::VerboseWriter::instance()->setFileName(logFileName); } delete d; try { PlainVerboseWriterOutput plainOutput; if (!VerboseWriter::instance()->flush(&plainOutput)) { VerboseWriterAdminOutput adminOutput(this); VerboseWriter::instance()->flush(&adminOutput); } } catch (...) { // Intentionally left blank; don't permit exceptions from VerboseWriter // to escape destructor. } RemoteClient::instance().setActive(false); RemoteClient::instance().destroy(); QMutexLocker _(globalVirtualComponentsFontMutex()); delete sVirtualComponentsFont; sVirtualComponentsFont = nullptr; } /* static */ /*! Returns the virtual components' font. */ QFont PackageManagerCore::virtualComponentsFont() { QMutexLocker _(globalVirtualComponentsFontMutex()); if (!sVirtualComponentsFont) sVirtualComponentsFont = new QFont; return *sVirtualComponentsFont; } /* static */ /*! Sets the virtual components' font to \a font. */ void PackageManagerCore::setVirtualComponentsFont(const QFont &font) { QMutexLocker _(globalVirtualComponentsFontMutex()); if (sVirtualComponentsFont) delete sVirtualComponentsFont; sVirtualComponentsFont = new QFont(font); } /* static */ /*! Returns \c true if virtual components are visible. */ bool PackageManagerCore::virtualComponentsVisible() { return sVirtualComponentsVisible; } /* static */ /*! Shows virtual components if \a visible is \c true. */ void PackageManagerCore::setVirtualComponentsVisible(bool visible) { sVirtualComponentsVisible = visible; } /* static */ /*! Returns \c true if forced installation is not set for all components for which the element is set in the package information file. */ bool PackageManagerCore::noForceInstallation() { return sNoForceInstallation; } /* static */ /*! Overwrites the value specified for the component in the \c element in the package information file with \a value. This enables end users to select or deselect the component in the installer. */ void PackageManagerCore::setNoForceInstallation(bool value) { sNoForceInstallation = value; } /* static */ /*! Returns \c true if components are not selected by default although \c element is set in the package information file. */ bool PackageManagerCore::noDefaultInstallation() { return sNoDefaultInstallation; } /* static */ /*! Overwrites the value specified for the component in the \c element in the package information file with \a value. Setting \a value to \c true unselects the components. */ void PackageManagerCore::setNoDefaultInstallation(bool value) { sNoDefaultInstallation = value; } /* static */ /*! Returns \c true if a local repository should be created from binary content. */ bool PackageManagerCore::createLocalRepositoryFromBinary() { return sCreateLocalRepositoryFromBinary; } /* static */ /*! Determines that a local repository should be created from binary content if \a create is \c true. */ void PackageManagerCore::setCreateLocalRepositoryFromBinary(bool create) { sCreateLocalRepositoryFromBinary = create; } /*! Returns \c true if the package manager is running and installed packages are found. Otherwise, returns \c false. */ bool PackageManagerCore::fetchLocalPackagesTree() { d->setStatus(Running); if (!isPackageManager()) { d->setStatus(Failure, tr("Application not running in Package Manager mode.")); return false; } LocalPackagesHash installedPackages = d->localInstalledPackages(); if (installedPackages.isEmpty()) { if (status() != Failure) d->setStatus(Failure, tr("No installed packages found.")); return false; } emit startAllComponentsReset(); d->clearAllComponentLists(); QHash components; const QStringList &keys = installedPackages.keys(); foreach (const QString &key, keys) { QScopedPointer component(new QInstaller::Component(this)); component->loadDataFromPackage(installedPackages.value(key)); const QString &name = component->name(); if (components.contains(name)) { qCritical("Cannot register component! Component with identifier %s already registered.", qPrintable(name)); continue; } components.insert(name, component.take()); } if (!d->buildComponentTree(components, false)) return false; updateDisplayVersions(scDisplayVersion); emit finishAllComponentsReset(d->m_rootComponents); d->setStatus(Success); return true; } /*! Returns a list of local installed packages. The list can be empty. */ LocalPackagesHash PackageManagerCore::localInstalledPackages() { return d->localInstalledPackages(); } /*! Emits the coreNetworkSettingsChanged() signal when network settings change. */ void PackageManagerCore::networkSettingsChanged() { cancelMetaInfoJob(); d->m_updates = false; d->m_repoFetched = false; d->m_updateSourcesAdded = false; if (isMaintainer() ) { bool gainedAdminRights = false; if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } d->writeMaintenanceConfigFiles(); if (gainedAdminRights) dropAdminRights(); } KDUpdater::FileDownloaderFactory::instance().setProxyFactory(proxyFactory()); emit coreNetworkSettingsChanged(); } /*! Returns a copy of the proxy factory that the package manager uses to determine the proxies to be used for requests. */ PackageManagerProxyFactory *PackageManagerCore::proxyFactory() const { if (d->m_proxyFactory) return d->m_proxyFactory->clone(); return new PackageManagerProxyFactory(this); } /*! Sets the proxy factory for the package manager to be \a factory. A proxy factory is used to determine a more specific list of proxies to be used for a given request, instead of trying to use the same proxy value for all requests. This might only be of use for HTTP or FTP requests. */ void PackageManagerCore::setProxyFactory(PackageManagerProxyFactory *factory) { delete d->m_proxyFactory; d->m_proxyFactory = factory; KDUpdater::FileDownloaderFactory::instance().setProxyFactory(proxyFactory()); } /*! Returns a list of packages available in all the repositories that were looked at. */ PackagesList PackageManagerCore::remotePackages() { return d->remotePackages(); } /*! Checks for compressed packages to install. Returns \c true if newer versions exist and they can be installed. */ bool PackageManagerCore::fetchCompressedPackagesTree() { const LocalPackagesHash installedPackages = d->localInstalledPackages(); if (!isInstaller() && status() == Failure) return false; if (!d->fetchMetaInformationFromCompressedRepositories()) return false; if (!d->addUpdateResourcesFromRepositories(true, true)) { return false; } PackagesList packages; const PackagesList &compPackages = d->compressedPackages(); if (compPackages.isEmpty()) return false; packages.append(compPackages); const PackagesList &rPackages = d->remotePackages(); packages.append(rPackages); return fetchPackagesTree(packages, installedPackages); } /*! Checks for packages to install. Returns \c true if newer versions exist and they can be installed. */ bool PackageManagerCore::fetchRemotePackagesTree() { d->setStatus(Running); if (isUninstaller()) { d->setStatus(Failure, tr("Application running in Uninstaller mode.")); return false; } if (!ProductKeyCheck::instance()->hasValidKey()) { d->setStatus(Failure, ProductKeyCheck::instance()->lastErrorString()); return false; } const LocalPackagesHash installedPackages = d->localInstalledPackages(); if (!isInstaller() && status() == Failure) return false; if (!d->fetchMetaInformationFromRepositories()) return false; if (!d->fetchMetaInformationFromCompressedRepositories()) return false; if (!d->addUpdateResourcesFromRepositories(true)) return false; const PackagesList &packages = d->remotePackages(); if (packages.isEmpty()) return false; return fetchPackagesTree(packages, installedPackages); } bool PackageManagerCore::fetchPackagesTree(const PackagesList &packages, const LocalPackagesHash installedPackages) { bool success = false; if (!isUpdater()) { success = fetchAllPackages(packages, installedPackages); if (d->statusCanceledOrFailed()) return false; if (success && isPackageManager()) { foreach (Package *const update, packages) { if (update->data(scEssential, scFalse).toString().toLower() == scTrue) { const QString name = update->data(scName).toString(); if (!installedPackages.contains(name)) { success = false; continue; // unusual, the maintenance tool should always be available } const LocalPackage localPackage = installedPackages.value(name); const QString updateVersion = update->data(scVersion).toString(); if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) continue; // remote version equals or is less than the installed maintenance tool const QDate updateDate = update->data(scReleaseDate).toDate(); if (localPackage.lastUpdateDate >= updateDate) continue; // remote release date equals or is less than the installed maintenance tool success = false; break; // we found a newer version of the maintenance tool } } if (!success && !d->statusCanceledOrFailed()) { updateDisplayVersions(scRemoteDisplayVersion); d->setStatus(ForceUpdate, tr("There is an important update available, please run the " "updater first.")); return false; } } } else { success = fetchUpdaterPackages(packages, installedPackages); } updateDisplayVersions(scRemoteDisplayVersion); if (success && !d->statusCanceledOrFailed()) d->setStatus(Success); return success; } /*! \fn QInstaller::PackageManagerCore::addWizardPage(QInstaller::Component * component, const QString & name, int page) Adds the widget with object name \a name registered by \a component as a new page into the installer's GUI wizard. The widget is added before \a page. See \l{Controller Scripting} for the possible values of \a page. Returns \c true if the operation succeeded. \sa {installer::addWizardPage}{installer.addWizardPage} */ bool PackageManagerCore::addWizardPage(Component *component, const QString &name, int page) { if (!isCommandLineInstance()) { if (QWidget* const widget = component->userInterface(name)) { emit wizardPageInsertionRequested(widget, static_cast(page)); return true; } } else { qCDebug(QInstaller::lcDeveloperBuild) << "Headless installation: skip wizard page addition: " << name; } return false; } /*! \fn QInstaller::PackageManagerCore::removeWizardPage(QInstaller::Component * component, const QString & name) Removes the widget with the object name \a name previously added to the installer's wizard by \a component. Returns \c true if the operation succeeded. \sa {installer::removeWizardPage}{installer.removeWizardPage} \sa addWizardPage(), setDefaultPageVisible(), wizardPageRemovalRequested() */ bool PackageManagerCore::removeWizardPage(Component *component, const QString &name) { if (!isCommandLineInstance()) { if (QWidget* const widget = component->userInterface(name)) { emit wizardPageRemovalRequested(widget); return true; } } else { qCDebug(QInstaller::lcDeveloperBuild) << "Headless installation: skip wizard page removal: " << name; } return false; } /*! Sets the visibility of the default page with the ID \a page to \a visible. That is, removes it from or adds it to the wizard. This works only for pages that were in the installer when it was started. Returns \c true. \sa {installer::setDefaultPageVisible}{installer.setDefaultPageVisible} \sa addWizardPage(), removeWizardPage() */ bool PackageManagerCore::setDefaultPageVisible(int page, bool visible) { emit wizardPageVisibilityChangeRequested(visible, page); return true; } /*! \fn QInstaller::PackageManagerCore::setValidatorForCustomPage(QInstaller::Component * component, const QString & name, const QString & callbackName) Sets a validator for the custom page specified by \a name and \a callbackName for the component \a component. When using this, \a name has to match a dynamic page starting with \c Dynamic. For example, if the page is called DynamicReadyToInstallWidget, then \a name should be set to \c ReadyToInstallWidget. The \a callbackName should be set to a function that returns a boolean. When the \c Next button is pressed on the custom page, then it will call the \a callbackName function. If this returns \c true, then it will move to the next page. \sa {installer::setValidatorForCustomPage}{installer.setValidatorForCustomPage} \sa setValidatorForCustomPageRequested() */ void PackageManagerCore::setValidatorForCustomPage(Component *component, const QString &name, const QString &callbackName) { emit setValidatorForCustomPageRequested(component, name, callbackName); } /*! Selects the component with \a id. \sa {installer::selectComponent}{installer.selectComponent} \sa deselectComponent() */ void PackageManagerCore::selectComponent(const QString &id) { d->setComponentSelection(id, Qt::Checked); } /*! Deselects the component with \a id. \sa {installer::deselectComponent}{installer.deselectComponent} \sa selectComponent() */ void PackageManagerCore::deselectComponent(const QString &id) { d->setComponentSelection(id, Qt::Unchecked); } /*! \fn QInstaller::PackageManagerCore::addWizardPageItem(QInstaller::Component * component, const QString & name, int page, int position) Adds the widget with the object name \a name registered by \a component as a GUI element into the installer's GUI wizard. The widget is added on \a page ordered by \a position number. If several widgets are added to the same page, the widget with lower \a position number will be inserted on top. See \l{Controller Scripting} for the possible values of \a page. If the widget can be found in an UI file for the component, returns \c true and emits the wizardWidgetInsertionRequested() signal. \sa {installer::addWizardPageItem}{installer.addWizardPageItem} \sa removeWizardPageItem(), wizardWidgetInsertionRequested() */ bool PackageManagerCore::addWizardPageItem(Component *component, const QString &name, int page, int position) { if (!isCommandLineInstance()) { if (QWidget* const widget = component->userInterface(name)) { emit wizardWidgetInsertionRequested(widget, static_cast(page), position); return true; } } else { qCDebug(QInstaller::lcDeveloperBuild) << "Headless installation: skip wizard page item addition: " << name; } return false; } /*! \fn QInstaller::PackageManagerCore::removeWizardPageItem(QInstaller::Component * component, const QString & name) Removes the widget with the object name \a name previously added to the installer's wizard by \a component. If the widget can be found in an UI file for the component, returns \c true and emits the wizardWidgetRemovalRequested() signal. \sa {installer::removeWizardPageItem}{installer.removeWizardPageItem} \sa addWizardPageItem() */ bool PackageManagerCore::removeWizardPageItem(Component *component, const QString &name) { if (!isCommandLineInstance()) { if (QWidget* const widget = component->userInterface(name)) { emit wizardWidgetRemovalRequested(widget); return true; } } return false; } /*! Registers additional \a repositories. \sa {installer::addUserRepositories}{installer.addUserRepositories} \sa setTemporaryRepositories() */ void PackageManagerCore::addUserRepositories(const QStringList &repositories) { QSet repositorySet; foreach (const QString &repository, repositories) repositorySet.insert(Repository::fromUserInput(repository)); settings().addUserRepositories(repositorySet); } /*! Sets additional \a repositories for this instance of the installer or updater if \a replace is \c false. \a compressed repositories can be added as well. Will be removed after invoking it again. \sa {installer::setTemporaryRepositories}{installer.setTemporaryRepositories} \sa addUserRepositories() */ void PackageManagerCore::setTemporaryRepositories(const QStringList &repositories, bool replace, bool compressed) { QSet repositorySet; foreach (const QString &repository, repositories) repositorySet.insert(Repository::fromUserInput(repository, compressed)); settings().setTemporaryRepositories(repositorySet, replace); } /*! Checks whether the downloader should try to download SHA-1 checksums for archives and returns the checksums. */ bool PackageManagerCore::testChecksum() const { return d->m_testChecksum; } /*! The \a test argument determines whether the downloader should try to download SHA-1 checksums for archives. */ void PackageManagerCore::setTestChecksum(bool test) { d->m_testChecksum = test; } /*! Returns the script engine that prepares and runs the component scripts. \sa {Component Scripting} */ ScriptEngine *PackageManagerCore::componentScriptEngine() const { return d->componentScriptEngine(); } /*! Returns the script engine that prepares and runs the control script. \sa {Controller Scripting} */ ScriptEngine *PackageManagerCore::controlScriptEngine() const { return d->controlScriptEngine(); } /*! Appends \a component as the root component to the internal storage for installer or package manager components. To append a component as a child to an already existing component, use Component::appendComponent(). Emits the componentAdded() signal. */ void PackageManagerCore::appendRootComponent(Component *component) { d->m_rootComponents.append(component); emit componentAdded(component); } /*! \enum PackageManagerCore::ComponentType \brief This enum holds the type of the component list to be returned: \value Root Returns a list of root components. \value Descendants Returns a list of all descendant components. In updater mode the list is empty, because component updates cannot have children. \value Dependencies Returns a list of all available dependencies when run as updater. When running as installer, package manager, or uninstaller, this will always result in an empty list. \value Replacements Returns a list of all available replacement components relevant to the run mode. \value AllNoReplacements Returns a list of available components, including root, descendant, and dependency components relevant to the run mode. \value All Returns a list of all available components, including root, descendant, dependency, and replacement components relevant to the run mode. */ /*! \typedef PackageManagerCore::ComponentTypes Synonym for QList. */ /*! Returns a list of components depending on the component types passed in \a mask. */ QList PackageManagerCore::components(ComponentTypes mask) const { QList components; const bool updater = isUpdater(); if (mask.testFlag(ComponentType::Root)) components += updater ? d->m_updaterComponents : d->m_rootComponents; if (mask.testFlag(ComponentType::Replacements)) components += updater ? d->m_updaterDependencyReplacements : d->m_rootDependencyReplacements; if (!updater) { if (mask.testFlag(ComponentType::Descendants)) { foreach (QInstaller::Component *component, d->m_rootComponents) components += component->descendantComponents(); } } else { if (mask.testFlag(ComponentType::Dependencies)) components.append(d->m_updaterComponentsDeps); // No descendants here, updates are always a flat list and cannot have children! } return components; } /*! Appends \a component to the internal storage for updater components. Emits the componentAdded() signal. */ void PackageManagerCore::appendUpdaterComponent(Component *component) { component->setUpdateAvailable(true); d->m_updaterComponents.append(component); emit componentAdded(component); } /*! Returns a component matching \a name. \a name can also contain a version requirement. For example, \c org.qt-project.sdk.qt returns any component with that name, whereas \c{org.qt-project.sdk.qt->=4.5} requires the returned component to have at least version 4.5. If no component matches the requirement, \c 0 is returned. */ Component *PackageManagerCore::componentByName(const QString &name) const { return componentByName(name, components(ComponentType::AllNoReplacements)); } /*! Searches \a components for a component matching \a name and returns it. \a name can also contain a version requirement. For example, \c org.qt-project.sdk.qt returns any component with that name, whereas \c{org.qt-project.sdk.qt->=4.5} requires the returned component to have at least version 4.5. If no component matches the requirement, \c 0 is returned. */ Component *PackageManagerCore::componentByName(const QString &name, const QList &components) { if (name.isEmpty()) return nullptr; QString fixedVersion; QString fixedName; parseNameAndVersion(name, &fixedName, &fixedVersion); foreach (Component *component, components) { if (componentMatches(component, fixedName, fixedVersion)) return component; } return nullptr; } /*! Returns \c true if directory specified by \a path is writable by the current user. */ bool PackageManagerCore::directoryWritable(const QString &path) const { return d->directoryWritable(path); } /*! Returns a list of components that are marked for installation. The list can be empty. */ QList PackageManagerCore::componentsMarkedForInstallation() const { QList markedForInstallation; const QList relevant = components(ComponentType::Root | ComponentType::Descendants); if (isUpdater()) { foreach (Component *component, relevant) { if (component->updateRequested()) markedForInstallation.append(component); } } else { // relevant means all components which are not replaced foreach (Component *component, relevant) { // ask for all components which will be installed to get all dependencies // even dependencies which are changed without an increased version if (component->isSelectedForInstallation() || (component->isInstalled() && !component->uninstallationRequested())) { markedForInstallation.append(component); } } } return markedForInstallation; } /*! Determines which components to install based on the current run mode and returns an ordered list of components to install. Also auto installed dependencies are resolved. The aboutCalculateComponentsToInstall() signal is emitted before the calculation starts, the finishedCalculateComponentsToInstall() signal once all calculations are done. \sa {installer::calculateComponentsToInstall}{installer.calculateComponentsToInstall} */ bool PackageManagerCore::calculateComponentsToInstall() const { emit aboutCalculateComponentsToInstall(); if (!d->m_componentsToInstallCalculated) { d->clearInstallerCalculator(); QList selectedComponentsToInstall = componentsMarkedForInstallation(); d->storeCheckState(); d->m_componentsToInstallCalculated = d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall); } emit finishedCalculateComponentsToInstall(); return d->m_componentsToInstallCalculated; } /*! Returns an ordered list of components to install. The list can be empty. */ QList PackageManagerCore::orderedComponentsToInstall() const { return d->installerCalculator()->orderedComponentsToInstall(); } /*! Calculates components to install and uninstall. In case of an error, returns \c false and and sets the \a displayString for error detail. */ bool PackageManagerCore::calculateComponents(QString *displayString) { QString htmlOutput; QString lastInstallReason; if (!calculateComponentsToUninstall() || !calculateComponentsToInstall()) { htmlOutput.append(QString::fromLatin1("

%1

    ") .arg(tr("Cannot resolve all dependencies."))); //if we have a missing dependency or a recursion we can display it if (!componentsToInstallError().isEmpty()) { htmlOutput.append(QString::fromLatin1("
  • %1
  • ").arg( componentsToInstallError())); } htmlOutput.append(QLatin1String("
")); if (displayString) *displayString = htmlOutput; return false; } // In case of updater mode we don't uninstall components. if (!isUpdater()) { QList componentsToRemove = componentsToUninstall(); if (!componentsToRemove.isEmpty()) { htmlOutput.append(QString::fromLatin1("

%1

    ").arg(tr("Components about to " "be removed."))); foreach (Component *component, componentsToRemove) htmlOutput.append(QString::fromLatin1("
  • %1
  • ").arg(component->name())); htmlOutput.append(QLatin1String("
")); } } foreach (Component *component, orderedComponentsToInstall()) { const QString reason = installReason(component); if (lastInstallReason != reason) { if (!lastInstallReason.isEmpty()) // means we had to close the previous list htmlOutput.append(QLatin1String("")); htmlOutput.append(QString::fromLatin1("

%1

    ").arg(reason)); lastInstallReason = reason; } htmlOutput.append(QString::fromLatin1("
  • %1
  • ").arg(component->name())); } if (displayString) *displayString = htmlOutput; return true; } /*! Calculates a list of components to uninstall based on the current run mode. The aboutCalculateComponentsToUninstall() signal is emitted before the calculation starts, the finishedCalculateComponentsToUninstall() signal once all calculations are done. Always returns \c true. \sa {installer::calculateComponentsToUninstall}{installer.calculateComponentsToUninstall} */ bool PackageManagerCore::calculateComponentsToUninstall() const { emit aboutCalculateComponentsToUninstall(); if (!isUpdater()) { // hack to avoid removing needed dependencies QSet componentsToInstall = d->installerCalculator()->orderedComponentsToInstall().toSet(); QList componentsToUninstall; foreach (Component *component, components(ComponentType::All)) { if (component->uninstallationRequested() && !componentsToInstall.contains(component)) componentsToUninstall.append(component); } d->clearUninstallerCalculator(); d->storeCheckState(); d->uninstallerCalculator()->appendComponentsToUninstall(componentsToUninstall); } emit finishedCalculateComponentsToUninstall(); return true; } /*! Returns a human-readable description of the error that occurred when evaluating the components to install. The error message is empty if no error occurred. \sa calculateComponentsToInstall */ QList PackageManagerCore::componentsToUninstall() const { return d->uninstallerCalculator()->componentsToUninstall().toList(); } /*! Returns errors found in the components that are marked for installation. */ QString PackageManagerCore::componentsToInstallError() const { return d->installerCalculator()->componentsToInstallError(); } /*! Returns the reason why \a component needs to be installed: \list \li The component was scheduled for installation. \li The component was added as a dependency for another component. \li The component was added as an automatic dependency. \endlist */ QString PackageManagerCore::installReason(Component *component) const { return d->installerCalculator()->installReason(component); } /*! Returns a list of components that depend on \a _component. The list can be empty. \note Automatic dependencies are not resolved. */ QList PackageManagerCore::dependees(const Component *_component) const { if (!_component) return QList(); const QList availableComponents = components(ComponentType::All); if (availableComponents.isEmpty()) return QList(); QList dependees; QString name; QString version; foreach (Component *component, availableComponents) { const QStringList &dependencies = component->dependencies(); foreach (const QString &dependency, dependencies) { parseNameAndVersion(dependency, &name, &version); if (componentMatches(_component, name, version)) dependees.append(component); } } return dependees; } /*! Returns the default component model. */ ComponentModel *PackageManagerCore::defaultComponentModel() const { QMutexLocker _(globalModelMutex()); if (!d->m_defaultModel) { d->m_defaultModel = componentModel(const_cast (this), QLatin1String("AllComponentsModel")); } connect(this, &PackageManagerCore::finishAllComponentsReset, d->m_defaultModel, &ComponentModel::setRootComponents); return d->m_defaultModel; } /*! Returns the updater component model. */ ComponentModel *PackageManagerCore::updaterComponentModel() const { QMutexLocker _(globalModelMutex()); if (!d->m_updaterModel) { d->m_updaterModel = componentModel(const_cast (this), QLatin1String("UpdaterComponentsModel")); } connect(this, &PackageManagerCore::finishUpdaterComponentsReset, d->m_updaterModel, &ComponentModel::setRootComponents); return d->m_updaterModel; } /*! Lists available packages filtered with \a regexp without GUI. Virtual components are not listed unless set visible. \sa setVirtualComponentsVisible() */ void PackageManagerCore::listAvailablePackages(const QString ®exp) { qCDebug(QInstaller::lcInstallerInstallLog) << "Searching packages with regular expression:" << regexp; d->fetchMetaInformationFromRepositories(DownloadType::UpdatesXML); d->addUpdateResourcesFromRepositories(true); QRegularExpression re(regexp); const PackagesList &packages = d->remotePackages(); bool foundMatch = false; foreach (const Package *update, packages) { const QString name = update->data(scName).toString(); if (re.match(name).hasMatch() && (virtualComponentsVisible() ? true : !update->data(scVirtual, false).toBool())) { d->printPackageInformation(name, update); foundMatch = true; } } if (!foundMatch) qCDebug(QInstaller::lcInstallerInstallLog) << "No matching packages found."; } bool PackageManagerCore::componentUninstallableFromCommandLine(const QString &componentName) { // We will do a recursive check for every child this component has. Component *component = componentByName(componentName); const QList childComponents = component->childItems(); foreach (const Component *childComponent, childComponents) { if (!componentUninstallableFromCommandLine(childComponent->name())) return false; } ComponentModel *model = defaultComponentModel(); const QModelIndex &idx = model->indexFromComponentName(componentName); if (model->data(idx, Qt::CheckStateRole) == QVariant::Invalid) { // Component cannot be unselected, check why if (component->forcedInstallation()) { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot uninstall ForcedInstallation component " << component->name(); } else if (component->autoDependencies().count() > 0) { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot uninstall component " << componentName << " because it is added as auto dependency to " << component->autoDependencies().join(QLatin1Char(',')); } else if (component->isVirtual() && !virtualComponentsVisible()) { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot uninstall virtual component " << component->name(); } else { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot uninstall component " << component->name(); } return false; } return true; } /*! Lists installed packages without GUI. */ void PackageManagerCore::listInstalledPackages() { LocalPackagesHash installedPackages = this->localInstalledPackages(); const QStringList &keys = installedPackages.keys(); foreach (const QString &key, keys) { KDUpdater::LocalPackage package = installedPackages.value(key); d->printLocalPackageInformation(package); } } /*! Updates the selected components \a componentsToUpdate without GUI. If essential components are found, then only those will be updated. Returns PackageManagerCore installation status. */ PackageManagerCore::Status PackageManagerCore::updateComponentsSilently(const QStringList &componentsToUpdate) { if (d->runningProcessesFound()) throw Error(tr("Running processes found.")); setUpdater(); ComponentModel *model = updaterComponentModel(); fetchRemotePackagesTree(); // List contains components containing update, if essential found contains only essential component const QList componentList = componentsMarkedForInstallation(); if (componentList.count() == 0) { qCDebug(QInstaller::lcInstallerInstallLog) << "No updates available."; } else { // Check if essential components are available (essential components are disabled). // If essential components are found, update first essential updates, // restart installer and install rest of the updates. bool essentialUpdatesFound = false; foreach (Component *component, componentList) { if (component->value(scEssential, scFalse).toLower() == scTrue) essentialUpdatesFound = true; } if (!essentialUpdatesFound) { const bool userSelectedComponents = !componentsToUpdate.isEmpty(); QList componentsToBeUpdated; //Mark components to be updated foreach (Component *comp, componentList) { const QModelIndex &idx = model->indexFromComponentName(comp->name()); if (!userSelectedComponents) { // No components given, update all model->setData(idx, Qt::Checked, Qt::CheckStateRole); } else { //Collect the componets to list which we want to update foreach (const QString &name, componentsToUpdate) { if (comp->name() == name) componentsToBeUpdated.append(comp); else model->setData(idx, Qt::Unchecked, Qt::CheckStateRole); } } } // No updates for selected components, do not run updater if (userSelectedComponents && componentsToBeUpdated.isEmpty()) { qCDebug(QInstaller::lcInstallerInstallLog) << "No updates available for selected components."; return PackageManagerCore::Success; } foreach (Component *componentToUpdate, componentsToBeUpdated) { const QModelIndex &idx = model->indexFromComponentName(componentToUpdate->name()); model->setData(idx, Qt::Checked, Qt::CheckStateRole); } } if (!d->calculateComponentsAndRun()) return status(); if (essentialUpdatesFound) { qCDebug(QInstaller::lcInstallerInstallLog) << "Essential components updated successfully." " Please restart maintenancetool to update other components."; } else { qCDebug(QInstaller::lcInstallerInstallLog) << "Components updated successfully."; } } return status(); } /*! Saves temporarily current operations for installer usage. This is needed for unit tests when several commands (for example install and uninstall) are performed with the same installer instance. */ void PackageManagerCore::commitSessionOperations() { d->commitSessionOperations(); } /*! Uninstalls the selected components \a components without GUI. Returns PackageManagerCore installation status. */ PackageManagerCore::Status PackageManagerCore::uninstallComponentsSilently(const QStringList& components) { if (d->runningProcessesFound()) throw Error(tr("Running processes found.")); if (components.isEmpty()) { qCDebug(QInstaller::lcInstallerInstallLog) << "No components selected for uninstallation."; return PackageManagerCore::Success; } ComponentModel *model = defaultComponentModel(); fetchLocalPackagesTree(); bool uninstallComponentFound = false; foreach (const QString &componentName, components){ const QModelIndex &idx = model->indexFromComponentName(componentName); Component *component = componentByName(componentName); if (component) { if (componentUninstallableFromCommandLine(componentName)) { model->setData(idx, Qt::Unchecked, Qt::CheckStateRole); uninstallComponentFound = true; } } else { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot uninstall component " << componentName <<". Component not found in install tree."; } } if (uninstallComponentFound) { if (d->calculateComponentsAndRun()) qCDebug(QInstaller::lcInstallerInstallLog) << "Components uninstalled successfully"; } return status(); } /*! Uninstalls all installed components without GUI and removes the program directory. Returns PackageManagerCore installation status. */ PackageManagerCore::Status PackageManagerCore::removeInstallationSilently() { setCompleteUninstallation(true); if (d->runningProcessesFound()) throw Error(tr("Running processes found.")); qCDebug(QInstaller::lcInstallerInstallLog) << "Complete uninstallation was chosen."; if (!(d->m_autoConfirmCommand || d->askUserConfirmCommand())) { qCDebug(QInstaller::lcInstallerInstallLog) << "Uninstallation aborted."; return status(); } if (run()) return PackageManagerCore::Success; else return PackageManagerCore::Failure; } /*! Installs the selected components \a components without displaying a user interface. Virtual components cannot be installed unless made visible with --show-virtual-components. AutoDependOn nor non-checkable components cannot be installed directly. Returns PackageManagerCore installation status. */ PackageManagerCore::Status PackageManagerCore::installSelectedComponentsSilently(const QStringList& components) { if (!isInstaller()) { // Check if there are processes running in the install if maintenancetool is used. if (d->runningProcessesFound()) throw Error(tr("Running processes found.")); setPackageManager(); //Check that packages are not already installed const LocalPackagesHash installedPackages = this->localInstalledPackages(); QStringList helperStrList; helperStrList << components << installedPackages.keys(); helperStrList.removeDuplicates(); if (helperStrList.count() == installedPackages.count()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Components already installed."; return PackageManagerCore::Success; } } ComponentModel *model = defaultComponentModel(); if (!fetchRemotePackagesTree()) return status(); bool installComponentsFound = false; foreach (const QString &name, components){ const QModelIndex &idx = model->indexFromComponentName(name); Component *component = componentByName(name); if (idx.isValid()) { if ((model->data(idx, Qt::CheckStateRole) == QVariant::Invalid) && !component->forcedInstallation()) { // User cannot select the component, check why if (component && component->autoDependencies().count() > 0) qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot install component "<< name << ". Component is installed only as automatic dependency to "<< component->autoDependencies().join(QLatin1Char(',')) << "."; if (component && !component->isCheckable()) qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot install component "<< name <<". Component is not checkable meaning you have to select one of the subcomponents."; } else if (component->isInstalled()) { qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Component " << name <<" already installed"; } else { model->setData(idx, Qt::Checked, Qt::CheckStateRole); installComponentsFound = true; } } else { // idx is invalid and component valid when we have invisible virtual component if (component && component->isVirtual()) qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot install " << name <<". Component is virtual."; else qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot install " << name <<". Component not found."; } } if (installComponentsFound) { if (d->calculateComponentsAndRun()) qCDebug(QInstaller::lcInstallerInstallLog) << "Components installed successfully"; } return status(); } /*! Installs components that are checked by default, i.e. those that are set with or and their respective dependencies without GUI. Returns PackageManagerCore installation status. */ PackageManagerCore::Status PackageManagerCore::installDefaultComponentsSilently() { d->m_defaultInstall = true; ComponentModel *model = defaultComponentModel(); fetchRemotePackagesTree(); if (!(model->checkedState() & ComponentModel::AllUnchecked)) { // There are components that are checked by default, we should install them if (d->calculateComponentsAndRun()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Components installed successfully."; } } else { qCDebug(QInstaller::lcInstallerInstallLog) << "No components available for default installation."; } return status(); } /*! Returns the settings for the package manager. */ Settings &PackageManagerCore::settings() const { return d->m_data.settings(); } /*! Tries to gain admin rights. On success, it returns \c true. \sa {installer::gainAdminRights}{installer.gainAdminRights} \sa dropAdminRights() */ bool PackageManagerCore::gainAdminRights() { if (AdminAuthorization::hasAdminRights()) return true; if (isCommandLineInstance()) { throw Error(tr("Cannot elevate access rights while running from command line. " "Please restart the application as administrator.")); } RemoteClient::instance().setActive(true); if (!RemoteClient::instance().isActive()) throw Error(tr("Error while elevating access rights.")); return true; } /*! \sa {installer::dropAdminRights}{installer.dropAdminRights} \sa gainAdminRights() */ void PackageManagerCore::dropAdminRights() { RemoteClient::instance().setActive(false); } /*! Sets checkAvailableSpace based on value of \a check. */ void PackageManagerCore::setCheckAvailableSpace(bool check) { d->m_checkAvailableSpace = check; } /*! Checks available disk space if the feature is not explicitly disabled. Informative text about space status can be retrieved by passing \a message parameter. Returns \c true if there is sufficient free space on installation and temporary volumes. */ bool PackageManagerCore::checkAvailableSpace(QString &message) const { const quint64 extraSpace = 256 * 1024 * 1024LL; quint64 required(requiredDiskSpace()); quint64 tempRequired(requiredTemporaryDiskSpace()); if (required < extraSpace) { required += 0.1 * required; tempRequired += 0.1 * tempRequired; } else { required += extraSpace; tempRequired += extraSpace; } quint64 repositorySize = 0; const bool createLocalRepository = createLocalRepositoryFromBinary(); if (createLocalRepository && isInstaller()) { repositorySize = QFile(QCoreApplication::applicationFilePath()).size(); // if we create a local repository, take that space into account as well required += repositorySize; } qDebug() << "Installation space required:" << humanReadableSize(required) << "Temporary space " "required:" << humanReadableSize(tempRequired) << "Local repository size:" << humanReadableSize(repositorySize); if (d->m_checkAvailableSpace) { const VolumeInfo tempVolume = VolumeInfo::fromPath(QDir::tempPath()); const VolumeInfo targetVolume = VolumeInfo::fromPath(value(scTargetDir)); const quint64 tempVolumeAvailableSize = tempVolume.availableSize(); const quint64 installVolumeAvailableSize = targetVolume.availableSize(); // at the moment there is no better way to check this if (targetVolume.size() == 0 && installVolumeAvailableSize == 0) { qDebug().nospace() << "Cannot determine available space on device. " "Volume descriptor: " << targetVolume.volumeDescriptor() << ", Mount path: " << targetVolume.mountPath() << ". Continue silently."; return true; } const bool tempOnSameVolume = (targetVolume == tempVolume); if (tempOnSameVolume) { qDebug() << "Tmp and install directories are on the same volume. Volume mount point:" << targetVolume.mountPath() << "Free space available:" << humanReadableSize(installVolumeAvailableSize); } else { qDebug() << "Tmp is on a different volume than the installation directory. Tmp volume mount point:" << tempVolume.mountPath() << "Free space available:" << humanReadableSize(tempVolumeAvailableSize) << "Install volume mount point:" << targetVolume.mountPath() << "Free space available:" << humanReadableSize(installVolumeAvailableSize); } if (tempOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) { message = tr("Not enough disk space to store temporary files and the " "installation. %1 are available, while %2 are at least required.").arg( humanReadableSize(installVolumeAvailableSize), humanReadableSize(required + tempRequired)); return false; } if (installVolumeAvailableSize < required) { message = tr("Not enough disk space to store all selected components! %1 are " "available while %2 are at least required.").arg(humanReadableSize(installVolumeAvailableSize), humanReadableSize(required)); return false; } if (tempVolumeAvailableSize < tempRequired) { message = tr("Not enough disk space to store temporary files! %1 are available " "while %2 are at least required.").arg(humanReadableSize(tempVolumeAvailableSize), humanReadableSize(tempRequired)); return false; } if (installVolumeAvailableSize - required < 0.01 * targetVolume.size()) { // warn for less than 1% of the volume's space being free message = tr("The volume you selected for installation seems to have sufficient space for " "installation, but there will be less than 1% of the volume's space available afterwards."); } else if (installVolumeAvailableSize - required < 100 * 1024 * 1024LL) { // warn for less than 100MB being free message = tr("The volume you selected for installation seems to have sufficient " "space for installation, but there will be less than 100 MB available afterwards."); } } message = QString::fromLatin1("%1 %2").arg(message, tr("Installation will use %1 of disk space.") .arg(humanReadableSize(requiredDiskSpace()))).simplified(); return true; } /*! Returns \c true if a process with \a name is running. On Windows, the comparison is case-insensitive. \sa {installer::isProcessRunning}{installer.isProcessRunning} */ bool PackageManagerCore::isProcessRunning(const QString &name) const { return PackageManagerCorePrivate::isProcessRunning(name, runningProcesses()); } /*! Returns \c true if a process with \a absoluteFilePath could be killed or is not running. \note This is implemented in a semi blocking way (to keep the main thread to paint the UI). \sa {installer::killProcess}{installer.killProcess} */ bool PackageManagerCore::killProcess(const QString &absoluteFilePath) const { QString normalizedPath = replaceVariables(absoluteFilePath); normalizedPath = QDir::cleanPath(normalizedPath.replace(QLatin1Char('\\'), QLatin1Char('/'))); QList allProcesses = runningProcesses(); foreach (const ProcessInfo &process, allProcesses) { QString processPath = process.name; processPath = QDir::cleanPath(processPath.replace(QLatin1Char('\\'), QLatin1Char('/'))); if (processPath == normalizedPath) { qCDebug(QInstaller::lcInstallerInstallLog).nospace() << "try to kill process " << process.name << " (" << process.id << ")"; //to keep the ui responsible use QtConcurrent::run QFutureWatcher futureWatcher; const QFuture future = QtConcurrent::run(KDUpdater::killProcess, process, 30000); QEventLoop loop; connect(&futureWatcher, &QFutureWatcher::finished, &loop, &QEventLoop::quit, Qt::QueuedConnection); futureWatcher.setFuture(future); if (!future.isFinished()) loop.exec(); qCDebug(QInstaller::lcInstallerInstallLog) << process.name << "killed!"; return future.result(); } } return true; } /*! Sets additional \a processes that can run when updating with the maintenance tool. \sa {installer::setAllowedRunningProcesses}{installer.setAllowedRunningProcesses} */ void PackageManagerCore::setAllowedRunningProcesses(const QStringList &processes) { d->m_allowedRunningProcesses = processes; } /*! Returns processes that are allowed to run when updating with the maintenance tool. \sa {installer::allowedRunningProcesses}{installer.allowedRunningProcesses} */ QStringList PackageManagerCore::allowedRunningProcesses() const { return d->m_allowedRunningProcesses; } /*! Makes sure the installer runs from a local drive. Otherwise the user will get an appropriate error message. \note This only works on Windows. \sa {installer::setDependsOnLocalInstallerBinary}{installer.setDependsOnLocalInstallerBinary} \sa localInstallerBinaryUsed() */ void PackageManagerCore::setDependsOnLocalInstallerBinary() { d->m_dependsOnLocalInstallerBinary = true; } /*! Returns \c false if the installer is run on Windows, and the installer has been started from a remote file system drive. Otherwise returns \c true. \sa {installer::localInstallerBinaryUsed}{installer.localInstallerBinaryUsed} \sa setDependsOnLocalInstallerBinary() */ bool PackageManagerCore::localInstallerBinaryUsed() { #ifdef Q_OS_WIN return KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath()); #endif return true; } /*! Starts the program \a program with the arguments \a arguments in a new process and waits for it to finish. \a stdIn is sent as standard input to the application. \a stdInCodec is the name of the codec to use for converting the input string into bytes to write to the standard input of the application. \a stdOutCodec is the name of the codec to use for converting data written by the application to standard output into a string. Returns an empty array if the program could not be executed, otherwise the output of command as the first item, and the return code as the second. \note On Unix, the output is just the output to stdout, not to stderr. \sa {installer::execute}{installer.execute} \sa executeDetached() */ QList PackageManagerCore::execute(const QString &program, const QStringList &arguments, const QString &stdIn, const QString &stdInCodec, const QString &stdOutCodec) const { QProcessWrapper process; QString adjustedProgram = replaceVariables(program); QStringList adjustedArguments; foreach (const QString &argument, arguments) adjustedArguments.append(replaceVariables(argument)); QString adjustedStdIn = replaceVariables(stdIn); process.start(adjustedProgram, adjustedArguments, adjustedStdIn.isNull() ? QIODevice::ReadOnly : QIODevice::ReadWrite); if (!process.waitForStarted()) return QList< QVariant >(); if (!adjustedStdIn.isNull()) { QTextCodec *codec = QTextCodec::codecForName(qPrintable(stdInCodec)); if (!codec) return QList(); QTextEncoder encoder(codec); process.write(encoder.fromUnicode(adjustedStdIn)); process.closeWriteChannel(); } process.waitForFinished(-1); QTextCodec *codec = QTextCodec::codecForName(qPrintable(stdOutCodec)); if (!codec) return QList(); return QList() << QTextDecoder(codec).toUnicode(process.readAllStandardOutput()) << process.exitCode(); } /*! Starts the program \a program with the arguments \a arguments in a new process, and detaches from it. Returns \c true on success; otherwise returns \c false. If the installer exits, the detached process will continue to live. \note Arguments that contain spaces are not passed to the process as separate arguments. \b{Unix:} The started process will run in its own session and act like a daemon. \b{Windows:} Arguments that contain spaces are wrapped in quotes. The started process will run as a regular standalone process. The process will be started in the directory \a workingDirectory. \sa {installer::executeDetached}{installer.executeDetached} */ bool PackageManagerCore::executeDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory) const { QString adjustedProgram = replaceVariables(program); QStringList adjustedArguments; QString adjustedWorkingDir = replaceVariables(workingDirectory); foreach (const QString &argument, arguments) adjustedArguments.append(replaceVariables(argument)); qCDebug(QInstaller::lcInstallerInstallLog) << "run application as detached process:" << adjustedProgram << adjustedArguments << adjustedWorkingDir; if (workingDirectory.isEmpty()) return QProcess::startDetached(adjustedProgram, adjustedArguments); else return QProcess::startDetached(adjustedProgram, adjustedArguments, adjustedWorkingDir); } /*! Returns the content of the environment variable \a name. An empty string is returned if the environment variable is not set. \sa {installer::environmentVariable}{installer.environmentVariable} */ QString PackageManagerCore::environmentVariable(const QString &name) const { if (name.isEmpty()) return QString(); #ifdef Q_OS_WIN static TCHAR buffer[32767]; DWORD size = GetEnvironmentVariable(LPCWSTR(name.utf16()), buffer, 32767); QString value = QString::fromUtf16((const unsigned short *) buffer, size); if (value.isEmpty()) { static QLatin1String userEnvironmentRegistryPath("HKEY_CURRENT_USER\\Environment"); value = QSettings(userEnvironmentRegistryPath, QSettings::NativeFormat).value(name).toString(); if (value.isEmpty()) { static QLatin1String systemEnvironmentRegistryPath("HKEY_LOCAL_MACHINE\\SYSTEM\\" "CurrentControlSet\\Control\\Session Manager\\Environment"); value = QSettings(systemEnvironmentRegistryPath, QSettings::NativeFormat).value(name).toString(); } } return value; #else return QString::fromUtf8(qgetenv(name.toLatin1())); #endif } /*! Returns \c true if the operation specified by \a name exists. */ bool PackageManagerCore::operationExists(const QString &name) { return KDUpdater::UpdateOperationFactory::instance().containsProduct(name); } /*! Performs the operation \a name with \a arguments. Returns \c false if the operation cannot be created or executed. \note The operation is performed threaded. It is not advised to call this function after installation finished signals. \sa {installer::performOperation}{installer.performOperation} */ bool PackageManagerCore::performOperation(const QString &name, const QStringList &arguments) { QScopedPointer op(KDUpdater::UpdateOperationFactory::instance().create(name, this)); if (!op.data()) return false; op->setArguments(replaceVariables(arguments)); op->backup(); if (!PackageManagerCorePrivate::performOperationThreaded(op.data())) { PackageManagerCorePrivate::performOperationThreaded(op.data(), PackageManagerCorePrivate::Undo); return false; } return true; } /*! Returns \c true when \a version matches the \a requirement. \a requirement can be a fixed version number or it can be prefixed by the comparators '>', '>=', '<', '<=' and '='. \sa {installer::versionMatches}{installer.versionMatches} */ bool PackageManagerCore::versionMatches(const QString &version, const QString &requirement) { QRegExp compEx(QLatin1String("([<=>]+)(.*)")); const QString comparator = compEx.exactMatch(requirement) ? compEx.cap(1) : QLatin1String("="); const QString ver = compEx.exactMatch(requirement) ? compEx.cap(2) : requirement; const bool allowEqual = comparator.contains(QLatin1Char('=')); const bool allowLess = comparator.contains(QLatin1Char('<')); const bool allowMore = comparator.contains(QLatin1Char('>')); if (allowEqual && version == ver) return true; if (allowLess && KDUpdater::compareVersion(ver, version) > 0) return true; if (allowMore && KDUpdater::compareVersion(ver, version) < 0) return true; return false; } /*! Finds a library named \a name in \a paths. If \a paths is empty, it gets filled with platform dependent default paths. The resulting path is returned. This method can be used by scripts to check external dependencies. \sa {installer::findLibrary}{installer.findLibrary} \sa findPath() */ QString PackageManagerCore::findLibrary(const QString &name, const QStringList &paths) { QStringList findPaths = paths; #if defined(Q_OS_WIN) return findPath(QString::fromLatin1("%1.lib").arg(name), findPaths); #else #if defined(Q_OS_MACOS) if (findPaths.isEmpty()) { findPaths.push_back(QLatin1String("/lib")); findPaths.push_back(QLatin1String("/usr/lib")); findPaths.push_back(QLatin1String("/usr/local/lib")); findPaths.push_back(QLatin1String("/opt/local/lib")); } const QString dynamic = findPath(QString::fromLatin1("lib%1.dylib").arg(name), findPaths); #else if (findPaths.isEmpty()) { findPaths.push_back(QLatin1String("/lib")); findPaths.push_back(QLatin1String("/usr/lib")); findPaths.push_back(QLatin1String("/usr/local/lib")); findPaths.push_back(QLatin1String("/lib64")); findPaths.push_back(QLatin1String("/usr/lib64")); findPaths.push_back(QLatin1String("/usr/local/lib64")); } const QString dynamic = findPath(QString::fromLatin1("lib%1.so*").arg(name), findPaths); #endif if (!dynamic.isEmpty()) return dynamic; return findPath(QString::fromLatin1("lib%1.a").arg(name), findPaths); #endif } /*! Tries to find the file name \a name in one of the paths specified by \a paths. The resulting path is returned. This method can be used by scripts to check external dependencies. \sa {installer::findPath}{installer.findPath} \sa findLibrary() */ QString PackageManagerCore::findPath(const QString &name, const QStringList &paths) { foreach (const QString &path, paths) { const QDir dir(path); const QStringList entries = dir.entryList(QStringList() << name, QDir::Files | QDir::Hidden); if (entries.isEmpty()) continue; return dir.absoluteFilePath(entries.first()); } return QString(); } /*! Sets the \c installerbase binary located at \a path to use when writing the maintenance tool. Set the path if an update to the binary is available. If the path is not set, the executable segment of the running installer or uninstaller will be used. \sa {installer::setInstallerBaseBinary}{installer.setInstallerBaseBinary} */ void PackageManagerCore::setInstallerBaseBinary(const QString &path) { d->m_installerBaseBinaryUnreplaced = path; } /*! Returns the installer value for \a key. If \a key is not known to the system, \a defaultValue is returned. Additionally, on Windows, \a key can be a registry key. \sa {installer::value}{installer.value} \sa setValue(), containsValue(), valueChanged() */ QString PackageManagerCore::value(const QString &key, const QString &defaultValue) const { return d->m_data.value(key, defaultValue).toString(); } /*! Returns the installer value for \a key. If \a key is not known to the system, \a defaultValue is returned. Additionally, on Windows, \a key can be a registry key. \sa {installer::values}{installer.values} \sa value() */ QStringList PackageManagerCore::values(const QString &key, const QStringList &defaultValue) const { return d->m_data.value(key, defaultValue).toStringList(); } /*! Sets the installer value for \a key to \a value. \sa {installer::setValue}{installer.setValue} \sa value(), containsValue(), valueChanged() */ void PackageManagerCore::setValue(const QString &key, const QString &value) { const QString normalizedValue = replaceVariables(value); if (d->m_data.setValue(key, normalizedValue)) emit valueChanged(key, normalizedValue); } /*! Returns \c true if the installer contains a value for \a key. \sa {installer::containsValue}{installer.containsValue} \sa value(), setValue(), valueChanged() */ bool PackageManagerCore::containsValue(const QString &key) const { return d->m_data.contains(key); } /*! Returns \c true if the package manager displays detailed information. */ bool PackageManagerCore::isVerbose() const { return QInstaller::isVerbose(); } /*! Returns verbose level. */ uint PackageManagerCore::verboseLevel() const { return QInstaller::verboseLevel(); } /*! Determines that the package manager displays detailed information if \a on is \c true. Calling setVerbose() more than once increases verbosity. */ void PackageManagerCore::setVerbose(bool on) { QInstaller::setVerbose(on); } PackageManagerCore::Status PackageManagerCore::status() const { return PackageManagerCore::Status(d->m_status); } /*! Returns a human-readable description of the last error that occurred. */ QString PackageManagerCore::error() const { return d->m_error; } /*! Returns \c true if at least one complete installation or update was successful, even if the user cancelled the latest installation process. */ bool PackageManagerCore::finishedWithSuccess() const { return d->m_status == PackageManagerCore::Success || d->m_needToWriteMaintenanceTool; } /*! \sa {installer::interrupt}{installer.interrupt} \sa installationInterrupted() */ void PackageManagerCore::interrupt() { setCanceled(); emit installationInterrupted(); } /*! \sa {installer::setCanceled}{installer.setCanceled} */ void PackageManagerCore::setCanceled() { if (!d->m_repoFetched) cancelMetaInfoJob(); d->setStatus(PackageManagerCore::Canceled); } /*! Replaces all variables within \a str by their respective values and returns the result. */ QString PackageManagerCore::replaceVariables(const QString &str) const { return d->replaceVariables(str); } /*! \overload Replaces all variables in any instance of \a str by their respective values and returns the results. */ QStringList PackageManagerCore::replaceVariables(const QStringList &str) const { QStringList result; foreach (const QString &s, str) result.append(d->replaceVariables(s)); return result; } /*! \overload Replaces all variables within \a ba by their respective values and returns the result. */ QByteArray PackageManagerCore::replaceVariables(const QByteArray &ba) const { return d->replaceVariables(ba); } /*! Returns the path to the installer binary. */ QString PackageManagerCore::installerBinaryPath() const { return d->installerBinaryPath(); } /*! \sa {installer::setInstaller}{installer.setInstaller} \sa isInstaller(), setUpdater(), setPackageManager() */ void PackageManagerCore::setInstaller() { d->m_magicBinaryMarker = BinaryContent::MagicInstallerMarker; emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } /*! Returns \c true if running as installer. \sa {installer::isInstaller}{installer.isInstaller} \sa isUninstaller(), isUpdater(), isPackageManager() */ bool PackageManagerCore::isInstaller() const { return d->isInstaller(); } /*! Returns \c true if this is an offline-only installer. \sa {installer::isOfflineOnly}{installer.isOfflineOnly} */ bool PackageManagerCore::isOfflineOnly() const { return d->isOfflineOnly(); } /*! \sa {installer::setUninstaller}{installer.setUninstaller} \sa isUninstaller(), setUpdater(), setPackageManager() */ void PackageManagerCore::setUninstaller() { d->m_magicBinaryMarker = BinaryContent::MagicUninstallerMarker; emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } /*! Returns \c true if running as uninstaller. \sa {installer::isUninstaller}{installer.isUninstaller} \sa setUninstaller(), isInstaller(), isUpdater(), isPackageManager() */ bool PackageManagerCore::isUninstaller() const { return d->isUninstaller(); } /*! \sa {installer::setUpdater}{installer.setUpdater} \sa isUpdater(), setUninstaller(), setPackageManager() */ void PackageManagerCore::setUpdater() { d->m_magicBinaryMarker = BinaryContent::MagicUpdaterMarker; emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } /*! Returns \c true if running as updater. \sa {installer::isUpdater}{installer.isUpdater} \sa setUpdater(), isInstaller(), isUninstaller(), isPackageManager() */ bool PackageManagerCore::isUpdater() const { return d->isUpdater(); } /*! \sa {installer::setPackageManager}{installer.setPackageManager} */ void PackageManagerCore::setPackageManager() { d->m_magicBinaryMarker = BinaryContent::MagicPackageManagerMarker; emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } /*! Returns \c true if running as the package manager. \sa {installer::isPackageManager}{installer.isPackageManager} \sa setPackageManager(), isInstaller(), isUninstaller(), isUpdater() */ bool PackageManagerCore::isPackageManager() const { return d->isPackageManager(); } /*! Sets the installer magic binary marker based on \a magicMarker and userSetBinaryMarker to \c true. */ void PackageManagerCore::setUserSetBinaryMarker(qint64 magicMarker) { d->m_magicBinaryMarker = magicMarker; d->m_userSetBinaryMarker = true; emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } /*! Returns \c true if the magic binary marker has been set by user, for example from a command line argument. \sa {installer::isUserSetBinaryMarker}{installer.isUserSetBinaryMarker} */ bool PackageManagerCore::isUserSetBinaryMarker() const { return d->m_userSetBinaryMarker; } /*! Set to use command line instance based on \a commandLineInstance. */ void PackageManagerCore::setCommandLineInstance(bool commandLineInstance) { d->m_commandLineInstance = commandLineInstance; } /*! Returns \c true if running as command line instance. \sa {installer::isCommandLineInstance}{installer.isCommandLineInstance} */ bool PackageManagerCore::isCommandLineInstance() const { return d->m_commandLineInstance; } /*! Returns \c true if installation is performed with default components. \sa {installer::isCommandLineDefaultInstall}{installer.isCommandLineDefaultInstall} */ bool PackageManagerCore::isCommandLineDefaultInstall() const { return d->m_defaultInstall; } /*! Returns \c true if it is a package manager or an updater. */ bool PackageManagerCore::isMaintainer() const { return isPackageManager() || isUpdater(); } /*! Runs the installer. Returns \c true on success, \c false otherwise. \sa {installer::runInstaller}{installer.runInstaller} */ bool PackageManagerCore::runInstaller() { return d->runInstaller(); } /*! Runs the uninstaller. Returns \c true on success, \c false otherwise. \sa {installer::runUninstaller}{installer.runUninstaller} */ bool PackageManagerCore::runUninstaller() { return d->runUninstaller(); } /*! Runs the updater. Returns \c true on success, \c false otherwise. \sa {installer::runPackageUpdater}{installer.runPackageUpdater} */ bool PackageManagerCore::runPackageUpdater() { return d->runPackageUpdater(); } /*! \sa {installer::languageChanged}{installer.languageChanged} */ void PackageManagerCore::languageChanged() { foreach (Component *component, components(ComponentType::All)) component->languageChanged(); } /*! Runs the installer, uninstaller, updater, or package manager, depending on the type of this binary. Returns \c true on success, otherwise \c false. */ bool PackageManagerCore::run() { if (isInstaller()) return d->runInstaller(); else if (isUninstaller()) return d->runUninstaller(); else if (isMaintainer()) return d->runPackageUpdater(); return false; } /*! Returns the path name of the maintenance tool binary. */ QString PackageManagerCore::maintenanceToolName() const { return d->maintenanceToolName(); } bool PackageManagerCore::updateComponentData(struct Data &data, Component *component) { try { // check if we already added the component to the available components list const QString name = data.package->data(scName).toString(); if (data.components->contains(name)) { qCritical("Cannot register component! Component with identifier %s already registered.", qPrintable(name)); return false; } if (settings().allowUnstableComponents()) { // Check if there are sha checksum mismatch. Component will still show in install tree // but is unselectable. foreach (const QString packageName, d->m_metadataJob.shaMismatchPackages()) { if (packageName == component->name()) { QString errorString = QLatin1String("SHA mismatch detected for component ") + packageName; component->setUnstable(Component::UnstableError::ShaMismatch, errorString); } } } component->setUninstalled(); const QString localPath = component->localTempPath(); if (verboseLevel() > 1) { static QString lastLocalPath; if (lastLocalPath != localPath) qCDebug(QInstaller::lcDeveloperBuild()) << "Url is:" << localPath; lastLocalPath = localPath; } const Repository repo = d->m_metadataJob.repositoryForDirectory(localPath); if (repo.isValid()) { component->setRepositoryUrl(repo.url()); component->setValue(QLatin1String("username"), repo.username()); component->setValue(QLatin1String("password"), repo.password()); } // add downloadable archive from xml const QStringList downloadableArchives = data.package->data(scDownloadableArchives).toString() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (component->isFromOnlineRepository()) { foreach (const QString downloadableArchive, downloadableArchives) component->addDownloadableArchive(downloadableArchive); } const QStringList componentsToReplace = data.package->data(scReplaces).toString() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (!componentsToReplace.isEmpty()) { // Store the component (this is a component that replaces others) and all components that // this one will replace. data.replacementToExchangeables.insert(component, componentsToReplace); } if (isInstaller()) { // Running as installer means no component is installed, we do not need to check if the // replacement needs to be marked as installed, just return. return true; } if (data.installedPackages->contains(name)) { // The replacement is already installed, we can mark it as installed and skip the search for // a possible component to replace that might be installed (to mark the replacement as installed). component->setInstalled(); component->setValue(scInstalledVersion, data.installedPackages->value(name).version); return true; } // The replacement is not yet installed, check all components to replace for there install state. foreach (const QString &componentName, componentsToReplace) { if (data.installedPackages->contains(componentName)) { // We found a replacement that is installed. if (isPackageManager()) { // Mark the replacement component as installed as well. Only do this in package manager // mode, otherwise it would not show up in the updaters component list. component->setInstalled(); component->setValue(scInstalledVersion, data.installedPackages->value(componentName).version); break; // Break as soon as we know we found an installed component this one replaces. } } } } catch (...) { return false; } return true; } void PackageManagerCore::storeReplacedComponents(QHash &components, const struct Data &data) { QHash::const_iterator it = data.replacementToExchangeables.constBegin(); // remember all components that got a replacement, required for uninstall for (; it != data.replacementToExchangeables.constEnd(); ++it) { foreach (const QString &componentName, it.value()) { Component *componentToReplace = components.take(componentName); if (!componentToReplace) { // If a component replaces another component which is not existing in the // installer binary or the installed component list, just ignore it. This // can happen when in installer mode and probably package manager mode too. if (isUpdater()) qCWarning(QInstaller::lcDeveloperBuild) << componentName << "- Does not exist in the repositories anymore."; continue; } if (!componentToReplace && !d->componentsToReplace().contains(componentName)) { componentToReplace = new Component(this); componentToReplace->setValue(scName, componentName); } else { // This case can happen when in installer mode as well, a component // is in the installer binary and its replacement component as well. d->replacementDependencyComponents().append(componentToReplace); } d->componentsToReplace().insert(componentName, qMakePair(it.key(), componentToReplace)); } } } bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const LocalPackagesHash &locals) { emit startAllComponentsReset(); d->clearAllComponentLists(); QHash components; Data data; data.components = &components; data.installedPackages = &locals; foreach (Package *const package, remotes) { if (d->statusCanceledOrFailed()) return false; if (!ProductKeyCheck::instance()->isValidPackage(package->data(scName).toString())) continue; QScopedPointer component(new QInstaller::Component(this)); data.package = package; component->loadDataFromPackage(*package); if (updateComponentData(data, component.data())) { const QString name = component->name(); components.insert(name, component.take()); } } foreach (const QString &key, locals.keys()) { QScopedPointer component(new QInstaller::Component(this)); component->loadDataFromPackage(locals.value(key)); const QString &name = component->name(); if (!components.contains(name)) components.insert(name, component.take()); } // store all components that got a replacement storeReplacedComponents(components, data); if (!d->buildComponentTree(components, true)) return false; emit finishAllComponentsReset(d->m_rootComponents); return true; } bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const LocalPackagesHash &locals) { emit startUpdaterComponentsReset(); d->clearUpdaterComponentLists(); QHash components; Data data; data.components = &components; data.installedPackages = &locals; setFoundEssentialUpdate(false); LocalPackagesHash installedPackages = locals; QStringList replaceMes; foreach (Package *const update, remotes) { if (d->statusCanceledOrFailed()) return false; if (!ProductKeyCheck::instance()->isValidPackage(update->data(scName).toString())) continue; QScopedPointer component(new QInstaller::Component(this)); data.package = update; component->loadDataFromPackage(*update); if (updateComponentData(data, component.data())) { // Keep a reference so we can resolve dependencies during update. d->m_updaterComponentsDeps.append(component.take()); // const QString isNew = update->data(scNewComponent).toString(); // if (isNew.toLower() != scTrue) // continue; const QString &name = d->m_updaterComponentsDeps.last()->name(); const QString replaces = data.package->data(scReplaces).toString(); installedPackages.take(name); // remove from local installed packages bool isValidUpdate = locals.contains(name); if (!isValidUpdate && !replaces.isEmpty()) { const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(), QString::SkipEmptyParts); foreach (const QString &possibleName, possibleNames) { if (locals.contains(possibleName)) { isValidUpdate = true; replaceMes << possibleName; } } } // break if the update is not valid and if it's not the maintenance tool (we might get an update // for the maintenance tool even if it's not currently installed - possible offline installation) if (!isValidUpdate && (update->data(scEssential, scFalse).toString().toLower() == scFalse)) continue; // Update for not installed package found, skip it. const LocalPackage &localPackage = locals.value(name); const QString updateVersion = update->data(scVersion).toString(); if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) continue; // It is quite possible that we may have already installed the update. Lets check the last // update date of the package and the release date of the update. This way we can compare and // figure out if the update has been installed or not. const QDate updateDate = update->data(scReleaseDate).toDate(); if (localPackage.lastUpdateDate > updateDate) continue; if (update->data(scEssential, scFalse).toString().toLower() == scTrue) setFoundEssentialUpdate(true); // this is not a dependency, it is a real update components.insert(name, d->m_updaterComponentsDeps.takeLast()); } } QHash localReplaceMes; foreach (const QString &key, installedPackages.keys()) { QInstaller::Component *component = new QInstaller::Component(this); component->loadDataFromPackage(installedPackages.value(key)); d->m_updaterComponentsDeps.append(component); // Keep a list of local components that should be replaced if (replaceMes.contains(component->name())) localReplaceMes.insert(component->name(), component); } // store all components that got a replacement, but do not modify the components list storeReplacedComponents(localReplaceMes.unite(components), data); try { if (!components.isEmpty()) { // append all components w/o parent to the direct list foreach (QInstaller::Component *component, components) { appendUpdaterComponent(component); } // after everything is set up, load the scripts foreach (QInstaller::Component *component, components) { if (d->statusCanceledOrFailed()) return false; component->loadComponentScript(); if (!component->isUnstable()) component->setCheckState(Qt::Checked); } // after everything is set up, check installed components foreach (QInstaller::Component *component, d->m_updaterComponentsDeps) { if (d->statusCanceledOrFailed()) return false; // even for possible dependency we need to load the script for example to get archives component->loadComponentScript(); if (component->isInstalled()) { // since we do not put them into the model, which would force a update of e.g. tri state // components, we have to check all installed components ourselves if (!component->isUnstable()) component->setCheckState(Qt::Checked); } } if (foundEssentialUpdate()) { foreach (QInstaller::Component *component, components) { if (d->statusCanceledOrFailed()) return false; component->setCheckable(false); component->setSelectable(false); if (component->value(scEssential, scFalse).toLower() == scFalse) { // non essential updates are disabled, not checkable and unchecked component->setEnabled(false); component->setCheckState(Qt::Unchecked); } else { // essential updates are enabled, still not checkable but checked component->setEnabled(true); } } } std::sort(d->m_updaterComponents.begin(), d->m_updaterComponents.end(), Component::SortingPriorityGreaterThan()); } else { // we have no updates, no need to store possible dependencies d->clearUpdaterComponentLists(); } } catch (const Error &error) { d->clearUpdaterComponentLists(); emit finishUpdaterComponentsReset(QList()); d->setStatus(Failure, error.message()); // TODO: make sure we remove all message boxes inside the library at some point. MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"), tr("Error"), error.message()); return false; } emit finishUpdaterComponentsReset(d->m_updaterComponents); return true; } void PackageManagerCore::restoreCheckState() { d->restoreCheckState(); } void PackageManagerCore::updateDisplayVersions(const QString &displayKey) { QHash componentsHash; foreach (QInstaller::Component *component, components(ComponentType::All)) componentsHash[component->name()] = component; // set display version for all components in list const QStringList &keys = componentsHash.keys(); foreach (const QString &key, keys) { QHash visited; if (componentsHash.value(key)->isInstalled()) { componentsHash.value(key)->setValue(scDisplayVersion, findDisplayVersion(key, componentsHash, scInstalledVersion, visited)); } visited.clear(); const QString displayVersionRemote = findDisplayVersion(key, componentsHash, scVersion, visited); if (displayVersionRemote.isEmpty()) componentsHash.value(key)->setValue(displayKey, tr("invalid")); else componentsHash.value(key)->setValue(displayKey, displayVersionRemote); } } QString PackageManagerCore::findDisplayVersion(const QString &componentName, const QHash &components, const QString &versionKey, QHash &visited) { if (!components.contains(componentName)) return QString(); const QString replaceWith = components.value(componentName)->value(scInheritVersion); visited[componentName] = true; if (replaceWith.isEmpty()) return components.value(componentName)->value(versionKey); if (visited.contains(replaceWith)) // cycle return QString(); return findDisplayVersion(replaceWith, components, versionKey, visited); } ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, const QString &objectName) const { ComponentModel *model = new ComponentModel(ComponentModelHelper::LastColumn, core); model->setObjectName(objectName); model->setHeaderData(ComponentModelHelper::NameColumn, Qt::Horizontal, ComponentModel::tr("Component Name")); model->setHeaderData(ComponentModelHelper::ActionColumn, Qt::Horizontal, ComponentModel::tr("Action")); model->setHeaderData(ComponentModelHelper::InstalledVersionColumn, Qt::Horizontal, ComponentModel::tr("Installed Version")); model->setHeaderData(ComponentModelHelper::NewVersionColumn, Qt::Horizontal, ComponentModel::tr("New Version")); model->setHeaderData(ComponentModelHelper::ReleaseDateColumn, Qt::Horizontal, ComponentModel::tr("Release Date")); model->setHeaderData(ComponentModelHelper::UncompressedSizeColumn, Qt::Horizontal, ComponentModel::tr("Size")); connect(model, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, SLOT(componentsToInstallNeedsRecalculation())); return model; } /*! Returns the file list used for delayed deletion. */ QStringList PackageManagerCore::filesForDelayedDeletion() const { return d->m_filesForDelayedDeletion; } /*! Adds \a files for delayed deletion. */ void PackageManagerCore::addFilesForDelayedDeletion(const QStringList &files) { d->m_filesForDelayedDeletion.append(files); } /*! Adds a colon symbol to the component \c name as a separator between component \a name and version. */ QString PackageManagerCore::checkableName(const QString &name) { // to ensure backward compatibility, fix component name with dash (-) symbol if (!name.contains(QLatin1Char(':'))) if (name.contains(QLatin1Char('-'))) return name + QLatin1Char(':'); return name; } /*! Parses \a name and \a version from \a requirement component. \c requirement contains both \a name and \a version separated either with ':' or with '-'. */ void PackageManagerCore::parseNameAndVersion(const QString &requirement, QString *name, QString *version) { if (requirement.isEmpty()) { if (name) name->clear(); if (version) version->clear(); return; } int pos = requirement.indexOf(QLatin1Char(':')); // to ensure backward compatibility, check dash (-) symbol too if (pos == -1) pos = requirement.indexOf(QLatin1Char('-')); if (pos != -1) { if (name) *name = requirement.left(pos); if (version) *version = requirement.mid(pos + 1); } else { if (name) *name = requirement; if (version) version->clear(); } } /*! Excludes version numbers from names from \a requirements components. \a requirements list contains names that have both name and version. Returns a list containing names without version numbers. */ QStringList PackageManagerCore::parseNames(const QStringList &requirements) { QString name; QString version; QStringList names; foreach (const QString &requirement, requirements) { parseNameAndVersion(requirement, &name, &version); names.append(name); } return names; } qt-installer-framework-4.0.1/src/libs/installer/packagemanagercore.h0100777000000000000000000004014213761647206022566 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGERCORE_H #define PACKAGEMANAGERCORE_H #include "binaryformat.h" #include "protocol.h" #include "repository.h" #include "qinstallerglobal.h" #include #include #include #include namespace QInstaller { class Component; class ComponentModel; class ScriptEngine; class PackageManagerCorePrivate; class PackageManagerProxyFactory; class Settings; // -- PackageManagerCore class INSTALLER_EXPORT PackageManagerCore : public QObject { Q_OBJECT Q_DISABLE_COPY(PackageManagerCore) Q_ENUMS(Status WizardPage) Q_PROPERTY(int status READ status NOTIFY statusChanged) public: PackageManagerCore(); PackageManagerCore(qint64 magicmaker, const QList &ops, const QString &socketName = QString(), const QString &key = QLatin1String(Protocol::DefaultAuthorizationKey), Protocol::Mode mode = Protocol::Mode::Production, const QHash ¶ms = QHash(), const bool commandLineInstance = false); ~PackageManagerCore(); // status enum Status { Success = EXIT_SUCCESS, Failure = EXIT_FAILURE, Running = 2, Canceled = 3, Unfinished = 4, ForceUpdate = 5, EssentialUpdated = 6 }; Status status() const; QString error() const; enum WizardPage { Introduction = 0x1000, TargetDirectory = 0x2000, ComponentSelection = 0x3000, LicenseCheck = 0x4000, StartMenuSelection = 0x5000, ReadyForInstallation = 0x6000, PerformInstallation = 0x7000, InstallationFinished = 0x8000, End = 0xffff }; enum struct ComponentType { Root = 0x1, Descendants = 0x2, Dependencies = 0x4, Replacements = 0x8, AllNoReplacements = (Root | Descendants | Dependencies), All = (Root | Descendants | Dependencies | Replacements) }; Q_DECLARE_FLAGS(ComponentTypes, ComponentType) static QFont virtualComponentsFont(); static void setVirtualComponentsFont(const QFont &font); static bool virtualComponentsVisible(); static void setVirtualComponentsVisible(bool visible); static bool noForceInstallation(); static void setNoForceInstallation(bool value); static bool noDefaultInstallation(); static void setNoDefaultInstallation(bool value); static bool createLocalRepositoryFromBinary(); static void setCreateLocalRepositoryFromBinary(bool create); static Component *componentByName(const QString &name, const QList &components); bool directoryWritable(const QString &path) const; bool fetchLocalPackagesTree(); LocalPackagesHash localInstalledPackages(); void networkSettingsChanged(); PackageManagerProxyFactory *proxyFactory() const; void setProxyFactory(PackageManagerProxyFactory *factory); PackagesList remotePackages(); bool fetchRemotePackagesTree(); bool fetchCompressedPackagesTree(); bool run(); void reset(); void setGuiObject(QObject *gui); QObject *guiObject() const; Q_INVOKABLE void setDependsOnLocalInstallerBinary(); Q_INVOKABLE bool localInstallerBinaryUsed(); Q_INVOKABLE QList execute(const QString &program, const QStringList &arguments = QStringList(), const QString &stdIn = QString(), const QString &stdInCodec = QLatin1String("latin1"), const QString &stdOutCodec = QLatin1String("latin1")) const; Q_INVOKABLE bool executeDetached(const QString &program, const QStringList &arguments = QStringList(), const QString &workingDirectory = QString()) const; Q_INVOKABLE QString environmentVariable(const QString &name) const; Q_INVOKABLE bool operationExists(const QString &name); Q_INVOKABLE bool performOperation(const QString &name, const QStringList &arguments); Q_INVOKABLE static bool versionMatches(const QString &version, const QString &requirement); Q_INVOKABLE static QString findLibrary(const QString &name, const QStringList &paths = QStringList()); Q_INVOKABLE static QString findPath(const QString &name, const QStringList &paths = QStringList()); Q_INVOKABLE void setInstallerBaseBinary(const QString &path); // parameter handling Q_INVOKABLE bool containsValue(const QString &key) const; Q_INVOKABLE void setValue(const QString &key, const QString &value); Q_INVOKABLE QString value(const QString &key, const QString &defaultValue = QString()) const; Q_INVOKABLE QStringList values(const QString &key, const QStringList &defaultValue = QStringList()) const; QString replaceVariables(const QString &str) const; QByteArray replaceVariables(const QByteArray &str) const; QStringList replaceVariables(const QStringList &str) const; void writeMaintenanceTool(); void writeMaintenanceConfigFiles(); void disableWriteMaintenanceTool(bool disable = true); QString maintenanceToolName() const; QString installerBinaryPath() const; bool testChecksum() const; void setTestChecksum(bool test); Q_INVOKABLE void addUserRepositories(const QStringList &repositories); Q_INVOKABLE void setTemporaryRepositories(const QStringList &repositories, bool replace = false, bool compressed = false); Q_INVOKABLE void autoAcceptMessageBoxes(); Q_INVOKABLE void autoRejectMessageBoxes(); Q_INVOKABLE void setMessageBoxAutomaticAnswer(const QString &identifier, int button); Q_INVOKABLE void acceptMessageBoxDefaultButton(); Q_INVOKABLE void setAutoAcceptLicenses(); Q_INVOKABLE void setFileDialogAutomaticAnswer(const QString &identifier, const QString &value); Q_INVOKABLE void removeFileDialogAutomaticAnswer(const QString &identifier); Q_INVOKABLE bool containsFileDialogAutomaticAnswer(const QString &identifier) const; QHash fileDialogAutomaticAnswers() const; void setAutoConfirmCommand(); quint64 size(QInstaller::Component *component, const QString &value) const; Q_INVOKABLE bool isFileExtensionRegistered(const QString &extension) const; Q_INVOKABLE bool fileExists(const QString &filePath) const; Q_INVOKABLE QString readFile(const QString &filePath, const QString &codecName) const; Q_INVOKABLE QString readConsoleLine(const QString &title = QString(), qint64 maxlen = 0) const; bool checkTargetDir(const QString &targetDirectory); QString targetDirWarning(const QString &targetDirectory) const; public: ScriptEngine *componentScriptEngine() const; ScriptEngine *controlScriptEngine() const; // component handling void appendRootComponent(Component *components); void appendUpdaterComponent(Component *components); QList components(ComponentTypes mask) const; Component *componentByName(const QString &identifier) const; Q_INVOKABLE bool calculateComponentsToInstall() const; QList orderedComponentsToInstall() const; bool calculateComponents(QString *displayString); Q_INVOKABLE bool calculateComponentsToUninstall() const; QList componentsToUninstall() const; QString componentsToInstallError() const; QString installReason(Component *component) const; QList dependees(const Component *component) const; ComponentModel *defaultComponentModel() const; ComponentModel *updaterComponentModel() const; void listInstalledPackages(); void listAvailablePackages(const QString ®exp); PackageManagerCore::Status updateComponentsSilently(const QStringList &componentsToUpdate); PackageManagerCore::Status installSelectedComponentsSilently(const QStringList& components); PackageManagerCore::Status installDefaultComponentsSilently(); PackageManagerCore::Status uninstallComponentsSilently(const QStringList& components); PackageManagerCore::Status removeInstallationSilently(); // convenience Q_INVOKABLE void setInstaller(); Q_INVOKABLE bool isInstaller() const; Q_INVOKABLE bool isOfflineOnly() const; Q_INVOKABLE void setUninstaller(); Q_INVOKABLE bool isUninstaller() const; Q_INVOKABLE void setUpdater(); Q_INVOKABLE bool isUpdater() const; Q_INVOKABLE void setPackageManager(); Q_INVOKABLE bool isPackageManager() const; void setUserSetBinaryMarker(qint64 magicMarker); Q_INVOKABLE bool isUserSetBinaryMarker() const; void setCommandLineInstance(bool commandLineInstance); Q_INVOKABLE bool isCommandLineInstance() const; Q_INVOKABLE bool isCommandLineDefaultInstall() const; bool isMaintainer() const; bool isVerbose() const; void setVerbose(bool on); uint verboseLevel() const; Q_INVOKABLE bool gainAdminRights(); Q_INVOKABLE void dropAdminRights(); void setCheckAvailableSpace(bool check); bool checkAvailableSpace(QString &message) const; Q_INVOKABLE quint64 requiredDiskSpace() const; Q_INVOKABLE quint64 requiredTemporaryDiskSpace() const; Q_INVOKABLE bool isProcessRunning(const QString &name) const; Q_INVOKABLE bool killProcess(const QString &absoluteFilePath) const; Q_INVOKABLE void setAllowedRunningProcesses(const QStringList &processes); Q_INVOKABLE QStringList allowedRunningProcesses() const; Settings &settings() const; Q_INVOKABLE bool addWizardPage(QInstaller::Component *component, const QString &name, int page); Q_INVOKABLE bool removeWizardPage(QInstaller::Component *component, const QString &name); Q_INVOKABLE bool addWizardPageItem(QInstaller::Component *component, const QString &name, int page, int position = 100); Q_INVOKABLE bool removeWizardPageItem(QInstaller::Component *component, const QString &name); Q_INVOKABLE bool setDefaultPageVisible(int page, bool visible); Q_INVOKABLE void setValidatorForCustomPage(QInstaller::Component *component, const QString &name, const QString &callbackName); Q_INVOKABLE void selectComponent(const QString &id); Q_INVOKABLE void deselectComponent(const QString &id); void rollBackInstallation(); int downloadNeededArchives(double partProgressSize); bool foundEssentialUpdate() const; void setFoundEssentialUpdate(bool foundEssentialUpdate = true); bool needsHardRestart() const; void setNeedsHardRestart(bool needsHardRestart = true); bool finishedWithSuccess() const; QStringList filesForDelayedDeletion() const; void addFilesForDelayedDeletion(const QStringList &files); static QString checkableName(const QString &name); static void parseNameAndVersion(const QString &requirement, QString *name, QString *version); static QStringList parseNames(const QStringList &requirements); void commitSessionOperations(); public Q_SLOTS: bool runInstaller(); bool runUninstaller(); bool runPackageUpdater(); void interrupt(); void setCanceled(); void languageChanged(); void setCompleteUninstallation(bool complete); void cancelMetaInfoJob(); void componentsToInstallNeedsRecalculation(); void clearComponentsToInstallCalculated(); Q_SIGNALS: void aboutCalculateComponentsToInstall() const; void finishedCalculateComponentsToInstall() const; void aboutCalculateComponentsToUninstall() const; void finishedCalculateComponentsToUninstall() const; void componentAdded(QInstaller::Component *comp); void rootComponentsAdded(QList components); void updaterComponentsAdded(QList components); void valueChanged(const QString &key, const QString &value); void statusChanged(QInstaller::PackageManagerCore::Status); void currentPageChanged(int page); void finishButtonClicked(); void metaJobProgress(int progress); void metaJobTotalProgress(int progress); void metaJobInfoMessage(const QString &message); void startAllComponentsReset(); void finishAllComponentsReset(const QList &rootComponents); void startUpdaterComponentsReset(); void finishUpdaterComponentsReset(const QList &componentsWithUpdates); void installationStarted(); void installationInterrupted(); void installationFinished(); void updateFinished(); void uninstallationStarted(); void uninstallationFinished(); void titleMessageChanged(const QString &title); void wizardPageInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page); void wizardPageRemovalRequested(QWidget *widget); void wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page, int position); void wizardWidgetRemovalRequested(QWidget *widget); void wizardPageVisibilityChangeRequested(bool visible, int page); void setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name, const QString &callbackName); void setAutomatedPageSwitchEnabled(bool request); void coreNetworkSettingsChanged(); void guiObjectChanged(QObject *gui); void unstableComponentFound(const QString &type, const QString &errorMessage, const QString &component); void installerBinaryMarkerChanged(qint64 magicMarker); private: struct Data { Package *package; QHash *components; const LocalPackagesHash *installedPackages; QHash replacementToExchangeables; }; bool updateComponentData(struct Data &data, QInstaller::Component *component); void storeReplacedComponents(QHash &components, const struct Data &data); bool fetchAllPackages(const PackagesList &remotePackages, const LocalPackagesHash &localPackages); bool fetchUpdaterPackages(const PackagesList &remotePackages, const LocalPackagesHash &localPackages); void updateDisplayVersions(const QString &displayKey); QString findDisplayVersion(const QString &componentName, const QHash &components, const QString& versionKey, QHash &visited); ComponentModel *componentModel(PackageManagerCore *core, const QString &objectName) const; QList componentsMarkedForInstallation() const; bool fetchPackagesTree(const PackagesList &packages, const LocalPackagesHash installedPackages); bool componentUninstallableFromCommandLine(const QString &componentName); private: PackageManagerCorePrivate *const d; friend class PackageManagerCorePrivate; QHash m_fileDialogAutomaticAnswers; private: // remove once we deprecate isSelected, setSelected etc... friend class ComponentSelectionPage; void restoreCheckState(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(PackageManagerCore::ComponentTypes) } Q_DECLARE_METATYPE(QInstaller::PackageManagerCore*) #endif // PACKAGEMANAGERCORE_H qt-installer-framework-4.0.1/src/libs/installer/packagemanagercoredata.cpp0100777000000000000000000002466213761647206023764 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "packagemanagercoredata.h" #include "errors.h" #include "fileutils.h" #include "qsettingswrapper.h" #include "utils.h" #include #include #include #ifdef Q_OS_WIN # include # include #endif namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::PackageManagerCoreData \internal */ PackageManagerCoreData::PackageManagerCoreData(const QHash &variables) { setDynamicPredefinedVariables(); // Set some common variables that may used e.g. as placeholder in some of the settings variables or // in a script or... m_variables.insert(scTargetConfigurationFile, QLatin1String("components.xml")); m_variables.insert(QLatin1String("InstallerDirPath"), QCoreApplication::applicationDirPath()); m_variables.insert(QLatin1String("InstallerFilePath"), QCoreApplication::applicationFilePath()); #ifdef Q_OS_WIN m_variables.insert(QLatin1String("os"), QLatin1String("win")); #elif defined(Q_OS_MACOS) m_variables.insert(QLatin1String("os"), QLatin1String("mac")); #elif defined(Q_OS_LINUX) m_variables.insert(QLatin1String("os"), QLatin1String("x11")); #else // TODO: add more platforms as needed... #endif m_settings = Settings::fromFileAndPrefix(QLatin1String(":/metadata/installer-config/config.xml"), QLatin1String(":/metadata/installer-config/"), Settings::RelaxedParseMode); // fill the variables defined in the settings m_variables.insert(QLatin1String("ProductName"), m_settings.applicationName()); m_variables.insert(QLatin1String("ProductVersion"), m_settings.version()); m_variables.insert(scTitle, replaceVariables(m_settings.title())); m_variables.insert(scPublisher, m_settings.publisher()); m_variables.insert(QLatin1String("Url"), m_settings.url()); m_variables.insert(scStartMenuDir, m_settings.startMenuDir()); m_variables.insert(scTargetConfigurationFile, m_settings.configurationFileName()); m_variables.insert(QLatin1String("LogoPixmap"), m_settings.logo()); m_variables.insert(QLatin1String("WatermarkPixmap"), m_settings.watermark()); m_variables.insert(QLatin1String("BannerPixmap"), m_settings.banner()); m_variables.insert(QLatin1String("PageListPixmap"), m_settings.pageListPixmap()); const QString description = m_settings.runProgramDescription(); if (!description.isEmpty()) m_variables.insert(scRunProgramDescription, description); m_variables.insert(scTargetDir, replaceVariables(m_settings.targetDir())); m_variables.insert(scRemoveTargetDir, replaceVariables(m_settings.removeTargetDir())); // Iterate over user defined parameters. If those are found, add to table or // replace existing values. QHash::const_iterator it; for (it = variables.begin(); it != variables.end(); ++it) m_variables.insert(it.key(), it.value()); } void PackageManagerCoreData::clear() { m_variables.clear(); m_settings = Settings(); } /*! Set some common variables that may be used e.g. as placeholder in some of the settings variables or in a script or... */ void PackageManagerCoreData::setDynamicPredefinedVariables() { m_variables.insert(QLatin1String("rootDir"), QDir::rootPath()); m_variables.insert(QLatin1String("homeDir"), QDir::homePath()); m_variables.insert(QLatin1String("RootDir"), QDir::rootPath()); m_variables.insert(QLatin1String("HomeDir"), QDir::homePath()); QString dir = QLatin1String("/opt"); #ifdef Q_OS_WIN TCHAR buffer[MAX_PATH + 1] = { 0 }; SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr, 0, buffer); dir = QString::fromWCharArray(buffer); #elif defined (Q_OS_MACOS) dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); #endif m_variables.insert(QLatin1String("ApplicationsDir"), dir); QString dirUser = dir; #ifdef Q_OS_MACOS dirUser = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); #endif m_variables.insert(QLatin1String("ApplicationsDirUser"), dirUser); QString dirX86 = dir; QString dirX64 = dir; #ifdef Q_OS_WIN QSettingsWrapper current(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion") , QSettingsWrapper::NativeFormat); BOOL onWow64Or64bit = TRUE; #ifndef Q_OS_WIN64 IsWow64Process(GetCurrentProcess(), &onWow64Or64bit); #endif QString programfilesX86; QString programfilesX64; if (onWow64Or64bit == TRUE) { programfilesX86 = current.value(QLatin1String("ProgramFilesDir (x86)"), QString()).toString(); programfilesX64 = current.value(QLatin1String("ProgramW6432Dir"), QString()).toString(); } else { programfilesX86 = current.value(QLatin1String("ProgramFilesDir"), QString()).toString(); programfilesX64 = programfilesX86; } dirX86 = replaceWindowsEnvironmentVariables(programfilesX86); dirX64 = replaceWindowsEnvironmentVariables(programfilesX64); #endif m_variables.insert(QLatin1String("ApplicationsDirX86"), dirX86); m_variables.insert(QLatin1String("ApplicationsDirX64"), dirX64); #ifdef Q_OS_WIN QSettingsWrapper user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\" "CurrentVersion\\Explorer\\User Shell Folders"), QSettingsWrapper::NativeFormat); QSettingsWrapper system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\" "CurrentVersion\\Explorer\\Shell Folders"), QSettingsWrapper::NativeFormat); const QString programs = user.value(QLatin1String("Programs"), QString()).toString(); const QString allPrograms = system.value(QLatin1String("Common Programs"), QString()) .toString(); QString desktop; if (m_variables.value(QLatin1String("AllUsers")) == scTrue) { desktop = system.value(QLatin1String("Desktop")).toString(); } else { desktop = user.value(QLatin1String("Desktop")).toString(); } m_variables.insert(QLatin1String("DesktopDir"), replaceWindowsEnvironmentVariables(desktop)); m_variables.insert(scUserStartMenuProgramsPath, replaceWindowsEnvironmentVariables(programs)); m_variables.insert(scAllUsersStartMenuProgramsPath, replaceWindowsEnvironmentVariables(allPrograms)); #endif #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) m_variables.insert(QLatin1String("IFW_VERSION_STR"), QLatin1String(QUOTE(IFW_VERSION_STR))); #undef QUOTE #undef QUOTE_ } Settings &PackageManagerCoreData::settings() const { return m_settings; } QStringList PackageManagerCoreData::keys() const { return m_variables.keys(); } bool PackageManagerCoreData::contains(const QString &key) const { return m_variables.contains(key) || m_settings.containsValue(key); } bool PackageManagerCoreData::setValue(const QString &key, const QString &normalizedValue) { if (m_variables.contains(key) && m_variables.value(key) == normalizedValue) return false; m_variables.insert(key, normalizedValue); return true; } QVariant PackageManagerCoreData::value(const QString &key, const QVariant &_default) const { if (key == scTargetDir) { QString dir = m_variables.value(key); if (dir.isEmpty()) dir = replaceVariables(m_settings.value(key, _default).toString()); #ifdef Q_OS_WIN return QInstaller::normalizePathName(dir); #else if (dir.startsWith(QLatin1String("~/"))) return QDir::home().absoluteFilePath(dir.mid(2)); return dir; #endif } #ifdef Q_OS_WIN if (!m_variables.contains(key)) { static const QRegExp regex(QLatin1String("\\\\|/")); const QString filename = key.section(regex, 0, -2); const QString regKey = key.section(regex, -1); const QSettingsWrapper registry(filename, QSettingsWrapper::NativeFormat); if (!filename.isEmpty() && !regKey.isEmpty() && registry.contains(regKey)) return registry.value(regKey).toString(); } #endif if (m_variables.contains(key)) return m_variables.value(key); return m_settings.value(key, _default); } QString PackageManagerCoreData::replaceVariables(const QString &str) const { static const QChar at = QLatin1Char('@'); QString res; int pos = 0; while (true) { const int pos1 = str.indexOf(at, pos); if (pos1 == -1) break; const int pos2 = str.indexOf(at, pos1 + 1); if (pos2 == -1) break; res += str.mid(pos, pos1 - pos); const QString name = str.mid(pos1 + 1, pos2 - pos1 - 1); res += value(name).toString(); pos = pos2 + 1; } res += str.mid(pos); return res; } QByteArray PackageManagerCoreData::replaceVariables(const QByteArray &ba) const { static const QChar at = QLatin1Char('@'); QByteArray res; int pos = 0; while (true) { const int pos1 = ba.indexOf(at, pos); if (pos1 == -1) break; const int pos2 = ba.indexOf(at, pos1 + 1); if (pos2 == -1) break; res += ba.mid(pos, pos1 - pos); const QString name = QString::fromLocal8Bit(ba.mid(pos1 + 1, pos2 - pos1 - 1)); res += value(name).toString().toLocal8Bit(); pos = pos2 + 1; } res += ba.mid(pos); return res; } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/packagemanagercoredata.h0100777000000000000000000000411713761647206023422 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PACKAGEMANAGERCOREDATA_H #define PACKAGEMANAGERCOREDATA_H #include "settings.h" namespace QInstaller { class PackageManagerCoreData { public: PackageManagerCoreData() {} explicit PackageManagerCoreData(const QHash &variables); void clear(); void setDynamicPredefinedVariables(); Settings &settings() const; QStringList keys() const; bool contains(const QString &key) const; bool setValue(const QString &key, const QString &normalizedValue); QVariant value(const QString &key, const QVariant &_default = QVariant()) const; QString replaceVariables(const QString &str) const; QByteArray replaceVariables(const QByteArray &ba) const; private: mutable Settings m_settings; QHash m_variables; }; } // namespace QInstaller #endif // PACKAGEMANAGERCOREDATA_H qt-installer-framework-4.0.1/src/libs/installer/packagemanagercore_p.cpp0100777000000000000000000034710413761647206023450 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "packagemanagercore_p.h" #include "adminauthorization.h" #include "binarycontent.h" #include "binaryformatenginehandler.h" #include "binarylayout.h" #include "component.h" #include "scriptengine.h" #include "componentmodel.h" #include "errors.h" #include "fileio.h" #include "remotefileengine.h" #include "graph.h" #include "messageboxhandler.h" #include "packagemanagercore.h" #include "progresscoordinator.h" #include "qprocesswrapper.h" #include "protocol.h" #include "qsettingswrapper.h" #include "installercalculator.h" #include "uninstallercalculator.h" #include "componentchecker.h" #include "globals.h" #include "selfrestarter.h" #include "filedownloaderfactory.h" #include "updateoperationfactory.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::PackageManagerCorePrivate \internal */ class OperationTracer { public: OperationTracer(Operation *operation) : m_operation(nullptr) { // don't create output for that hacky pseudo operation if (operation->name() != QLatin1String("MinimumProgress")) m_operation = operation; } void trace(const QString &state) { if (!m_operation) return; qCDebug(QInstaller::lcInstallerInstallLog).noquote() << QString::fromLatin1("%1 %2 operation: %3") .arg(state, m_operation->value(QLatin1String("component")).toString(), m_operation->name()); qCDebug(QInstaller::lcInstallerInstallLog).noquote() << QString::fromLatin1("\t- arguments: %1") .arg(m_operation->arguments().join(QLatin1String(", "))); } ~OperationTracer() { if (!m_operation) return; qCDebug(QInstaller::lcInstallerInstallLog) << "Done"; } private: Operation *m_operation; }; static bool runOperation(Operation *operation, PackageManagerCorePrivate::OperationType type) { OperationTracer tracer(operation); switch (type) { case PackageManagerCorePrivate::Backup: tracer.trace(QLatin1String("backup")); operation->backup(); return true; case PackageManagerCorePrivate::Perform: tracer.trace(QLatin1String("perform")); return operation->performOperation(); case PackageManagerCorePrivate::Undo: tracer.trace(QLatin1String("undo")); return operation->undoOperation(); default: Q_ASSERT(!"unexpected operation type"); } return false; } static QStringList checkRunningProcessesFromList(const QStringList &processList) { const QList allProcesses = runningProcesses(); QStringList stillRunningProcesses; foreach (const QString &process, processList) { if (!process.isEmpty() && PackageManagerCorePrivate::isProcessRunning(process, allProcesses)) stillRunningProcesses.append(process); } return stillRunningProcesses; } static void deferredRename(const QString &oldName, const QString &newName, bool restart = false) { #ifdef Q_OS_WIN QStringList arguments; // Check if .vbs extension can be used for running renaming script. If not, create own extension QString extension = QLatin1String(".vbs"); QSettingsWrapper settingRoot(QLatin1String("HKEY_CLASSES_ROOT\\.vbs"), QSettingsWrapper::NativeFormat); if (settingRoot.value(QLatin1String(".")).toString() != QLatin1String("VBSFile")) { extension = QLatin1String(".qtInstaller"); QSettingsWrapper settingsUser(QLatin1String("HKEY_CURRENT_USER\\Software\\Classes"), QSettingsWrapper::NativeFormat); QString value = settingsUser.value(extension).toString(); if (value != QLatin1String("VBSFile")) settingsUser.setValue(extension, QLatin1String("VBSFile")); } QTemporaryFile f(QDir::temp().absoluteFilePath(QLatin1String("deferredrenameXXXXXX%1")).arg(extension)); QInstaller::openForWrite(&f); f.setAutoRemove(false); arguments << QDir::toNativeSeparators(f.fileName()) << QDir::toNativeSeparators(oldName) << QDir::toNativeSeparators(QFileInfo(oldName).dir().absoluteFilePath(QFileInfo(newName) .fileName())); QTextStream batch(&f); batch.setCodec("UTF-16"); batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; batch << "Set tmp = WScript.CreateObject(\"WScript.Shell\")\n"; batch << QString::fromLatin1("file = \"%1\"\n").arg(arguments[2]); batch << "on error resume next\n"; batch << "while fso.FileExists(file)\n"; batch << " fso.DeleteFile(file)\n"; batch << " WScript.Sleep(1000)\n"; batch << "wend\n"; batch << QString::fromLatin1("fso.MoveFile \"%1\", file\n").arg(arguments[1]); if (restart) { //Restart with same command line arguments as first executable QStringList commandLineArguments = QCoreApplication::arguments(); batch << QString::fromLatin1("tmp.exec \"%1 --%2") .arg(arguments[2]).arg(CommandLineOptions::scStartUpdaterLong); //Skip the first argument as that is executable itself for (int i = 1; i < commandLineArguments.count(); i++) { batch << QString::fromLatin1(" %1").arg(commandLineArguments.at(i)); } batch << QString::fromLatin1("\"\n"); } batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; QProcessWrapper::startDetached(QLatin1String("cscript"), QStringList() << QLatin1String("//Nologo") << arguments[0]); #else QFile::remove(newName); QFile::rename(oldName, newName); SelfRestarter::setRestartOnQuit(restart); #endif } // -- PackageManagerCorePrivate PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) : m_updateFinder(nullptr) , m_compressedFinder(nullptr) , m_localPackageHub(std::make_shared()) , m_status(PackageManagerCore::Unfinished) , m_needsHardRestart(false) , m_testChecksum(false) , m_launchedAsRoot(AdminAuthorization::hasAdminRights()) , m_completeUninstall(false) , m_needToWriteMaintenanceTool(false) , m_dependsOnLocalInstallerBinary(false) , m_core(core) , m_updates(false) , m_repoFetched(false) , m_updateSourcesAdded(false) , m_magicBinaryMarker(0) // initialize with pseudo marker , m_componentsToInstallCalculated(false) , m_componentScriptEngine(nullptr) , m_controlScriptEngine(nullptr) , m_installerCalculator(nullptr) , m_uninstallerCalculator(nullptr) , m_proxyFactory(nullptr) , m_defaultModel(nullptr) , m_updaterModel(nullptr) , m_guiObject(nullptr) , m_remoteFileEngineHandler(nullptr) , m_foundEssentialUpdate(false) , m_commandLineInstance(false) , m_defaultInstall(false) , m_userSetBinaryMarker(false) , m_checkAvailableSpace(true) , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) { } PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker, const QList &performedOperations) : m_updateFinder(nullptr) , m_compressedFinder(nullptr) , m_localPackageHub(std::make_shared()) , m_status(PackageManagerCore::Unfinished) , m_needsHardRestart(false) , m_testChecksum(false) , m_launchedAsRoot(AdminAuthorization::hasAdminRights()) , m_completeUninstall(false) , m_needToWriteMaintenanceTool(false) , m_dependsOnLocalInstallerBinary(false) , m_core(core) , m_updates(false) , m_repoFetched(false) , m_updateSourcesAdded(false) , m_magicBinaryMarker(magicInstallerMaker) , m_componentsToInstallCalculated(false) , m_componentScriptEngine(nullptr) , m_controlScriptEngine(nullptr) , m_installerCalculator(nullptr) , m_uninstallerCalculator(nullptr) , m_proxyFactory(nullptr) , m_defaultModel(nullptr) , m_updaterModel(nullptr) , m_guiObject(nullptr) , m_remoteFileEngineHandler(new RemoteFileEngineHandler) , m_foundEssentialUpdate(false) , m_commandLineInstance(false) , m_defaultInstall(false) , m_userSetBinaryMarker(false) , m_checkAvailableSpace(true) , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) { foreach (const OperationBlob &operation, performedOperations) { QScopedPointer op(KDUpdater::UpdateOperationFactory::instance() .create(operation.name, core)); if (op.isNull()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to load unknown operation" << operation.name; continue; } if (!op->fromXml(operation.xml)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to load XML for operation" << operation.name; continue; } m_performedOperationsOld.append(op.take()); } connect(this, &PackageManagerCorePrivate::installationStarted, m_core, &PackageManagerCore::installationStarted); connect(this, &PackageManagerCorePrivate::installationFinished, m_core, &PackageManagerCore::installationFinished); connect(this, &PackageManagerCorePrivate::uninstallationStarted, m_core, &PackageManagerCore::uninstallationStarted); connect(this, &PackageManagerCorePrivate::uninstallationFinished, m_core, &PackageManagerCore::uninstallationFinished); } PackageManagerCorePrivate::~PackageManagerCorePrivate() { clearAllComponentLists(); clearUpdaterComponentLists(); clearInstallerCalculator(); clearUninstallerCalculator(); qDeleteAll(m_ownedOperations); qDeleteAll(m_performedOperationsOld); qDeleteAll(m_performedOperationsCurrentSession); delete m_updateFinder; delete m_proxyFactory; delete m_defaultModel; delete m_updaterModel; // at the moment the tabcontroller deletes the m_gui, this needs to be changed in the future // delete m_gui; } /* Return true, if a process with \a name is running. On Windows, comparison is case-insensitive. */ /* static */ bool PackageManagerCorePrivate::isProcessRunning(const QString &name, const QList &processes) { QList::const_iterator it; for (it = processes.constBegin(); it != processes.constEnd(); ++it) { if (it->name.isEmpty()) continue; #ifndef Q_OS_WIN if (it->name == name) return true; const QFileInfo fi(it->name); if (fi.fileName() == name || fi.baseName() == name) return true; #else if (it->name.toLower() == name.toLower()) return true; if (it->name.toLower() == QDir::toNativeSeparators(name.toLower())) return true; const QFileInfo fi(it->name); if (fi.fileName().toLower() == name.toLower() || fi.baseName().toLower() == name.toLower()) return true; #endif } return false; } /* static */ bool PackageManagerCorePrivate::performOperationThreaded(Operation *operation, OperationType type) { QFutureWatcher futureWatcher; const QFuture future = QtConcurrent::run(runOperation, operation, type); QEventLoop loop; QObject::connect(&futureWatcher, &decltype(futureWatcher)::finished, &loop, &QEventLoop::quit, Qt::QueuedConnection); futureWatcher.setFuture(future); if (!future.isFinished()) loop.exec(); return future.result(); } QString PackageManagerCorePrivate::targetDir() const { return m_core->value(scTargetDir); } bool PackageManagerCorePrivate::directoryWritable(const QString &path) const { QTemporaryFile tempFile(path + QLatin1String("/tempFile.XXXXXX")); return (tempFile.open() && tempFile.isWritable()); } QString PackageManagerCorePrivate::configurationFileName() const { return m_core->value(scTargetConfigurationFile, QLatin1String("components.xml")); } QString PackageManagerCorePrivate::componentsXmlPath() const { return QDir::toNativeSeparators(QDir(QDir::cleanPath(targetDir())) .absoluteFilePath(configurationFileName())); } bool PackageManagerCorePrivate::buildComponentTree(QHash &components, bool loadScript) { try { if (statusCanceledOrFailed()) return false; // append all components to their respective parents QHash::const_iterator it; for (it = components.constBegin(); it != components.constEnd(); ++it) { QString id = it.key(); QInstaller::Component *component = it.value(); while (!id.isEmpty() && component->parentComponent() == nullptr) { id = id.section(QLatin1Char('.'), 0, -2); if (components.contains(id)) components[id]->appendComponent(component); } } // append all components w/o parent to the direct list foreach (QInstaller::Component *component, components) { if (component->parentComponent() == nullptr) m_core->appendRootComponent(component); } // after everything is set up, load the scripts if needed if (loadScript) { foreach (QInstaller::Component *component, components) component->loadComponentScript(); } // now we can preselect components in the tree foreach (QInstaller::Component *component, components) { // set the checked state for all components without child (means without tristate) // set checked state also for installed virtual tristate componets as otherwise // those will be uninstalled if (component->isCheckable() && !component->isTristate()) { if (component->isDefault() && isInstaller()) component->setCheckState(Qt::Checked); else if (component->isInstalled()) component->setCheckState(Qt::Checked); } else if (component->isVirtual() && component->isInstalled() && component->isTristate()) { component->setCheckState(Qt::Checked); } } std::sort(m_rootComponents.begin(), m_rootComponents.end(), Component::SortingPriorityGreaterThan()); storeCheckState(); foreach (QInstaller::Component *component, components) component->setCheckState(Qt::Checked); clearInstallerCalculator(); if (installerCalculator()->appendComponentsToInstall(components.values()) == false) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"), tr("Unresolved dependencies"), installerCalculator()->componentsToInstallError()); return false; } restoreCheckState(); if (m_core->verboseLevel() > 1) { foreach (QInstaller::Component *component, components) { const QStringList warnings = ComponentChecker::checkComponent(component); foreach (const QString &warning, warnings) qCWarning(lcDeveloperBuild).noquote() << warning; } } } catch (const Error &error) { clearAllComponentLists(); emit m_core->finishAllComponentsReset(QList()); setStatus(PackageManagerCore::Failure, error.message()); // TODO: make sure we remove all message boxes inside the library at some point. MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"), tr("Error"), error.message()); return false; } return true; } void PackageManagerCorePrivate::cleanUpComponentEnvironment() { // clean up registered (downloaded) data if (m_core->isMaintainer()) BinaryFormatEngineHandler::instance()->clear(); // there could be still some references to already deleted components, // so we need to remove the current component script engine delete m_componentScriptEngine; m_componentScriptEngine = nullptr; } ScriptEngine *PackageManagerCorePrivate::componentScriptEngine() const { if (!m_componentScriptEngine) m_componentScriptEngine = new ScriptEngine(m_core); return m_componentScriptEngine; } ScriptEngine *PackageManagerCorePrivate::controlScriptEngine() const { if (!m_controlScriptEngine) m_controlScriptEngine = new ScriptEngine(m_core); return m_controlScriptEngine; } void PackageManagerCorePrivate::clearAllComponentLists() { QList toDelete; toDelete << m_rootComponents; m_rootComponents.clear(); m_rootDependencyReplacements.clear(); const QList > list = m_componentsToReplaceAllMode.values(); for (int i = 0; i < list.count(); ++i) toDelete << list.at(i).second; m_componentsToReplaceAllMode.clear(); m_componentsToInstallCalculated = false; qDeleteAll(toDelete); cleanUpComponentEnvironment(); } void PackageManagerCorePrivate::clearUpdaterComponentLists() { QSet usedComponents = QSet::fromList(m_updaterComponents + m_updaterComponentsDeps); const QList > list = m_componentsToReplaceUpdaterMode.values(); for (int i = 0; i < list.count(); ++i) { if (usedComponents.contains(list.at(i).second)) qCWarning(QInstaller::lcDeveloperBuild) << "a replacement was already in the list - is that correct?"; else usedComponents.insert(list.at(i).second); } m_updaterComponents.clear(); m_updaterComponentsDeps.clear(); m_updaterDependencyReplacements.clear(); m_componentsToReplaceUpdaterMode.clear(); m_componentsToInstallCalculated = false; qDeleteAll(usedComponents); cleanUpComponentEnvironment(); } QList &PackageManagerCorePrivate::replacementDependencyComponents() { return (!isUpdater()) ? m_rootDependencyReplacements : m_updaterDependencyReplacements; } QHash > &PackageManagerCorePrivate::componentsToReplace() { return (!isUpdater()) ? m_componentsToReplaceAllMode : m_componentsToReplaceUpdaterMode; } void PackageManagerCorePrivate::clearInstallerCalculator() { delete m_installerCalculator; m_installerCalculator = nullptr; } InstallerCalculator *PackageManagerCorePrivate::installerCalculator() const { if (!m_installerCalculator) { PackageManagerCorePrivate *const pmcp = const_cast (this); pmcp->m_installerCalculator = new InstallerCalculator( m_core->components(PackageManagerCore::ComponentType::AllNoReplacements)); } return m_installerCalculator; } void PackageManagerCorePrivate::clearUninstallerCalculator() { delete m_uninstallerCalculator; m_uninstallerCalculator = nullptr; } UninstallerCalculator *PackageManagerCorePrivate::uninstallerCalculator() const { if (!m_uninstallerCalculator) { PackageManagerCorePrivate *const pmcp = const_cast (this); QList installedComponents; foreach (const QString &name, pmcp->localInstalledPackages().keys()) { if (Component *component = m_core->componentByName(PackageManagerCore::checkableName(name))) { if (!component->uninstallationRequested()) installedComponents.append(component); } } pmcp->m_uninstallerCalculator = new UninstallerCalculator(installedComponents); } return m_uninstallerCalculator; } void PackageManagerCorePrivate::initialize(const QHash ¶ms) { m_coreCheckedHash.clear(); m_data = PackageManagerCoreData(params); m_componentsToInstallCalculated = false; #ifdef Q_OS_LINUX if (m_launchedAsRoot) m_data.setValue(scTargetDir, replaceVariables(m_data.settings().adminTargetDir())); #endif if (!m_core->isInstaller()) { #ifdef Q_OS_MACOS readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); #else readMaintenanceConfigFiles(QCoreApplication::applicationDirPath()); #endif } processFilesForDelayedDeletion(); // Set shortcut path for command line interface, in GUI version // we have a separate page where the whole path is set. #ifdef Q_OS_WIN if (m_core->isCommandLineInstance() && m_core->isInstaller()) { QString startMenuPath; if (params.value(QLatin1String("AllUsers")) == scTrue) startMenuPath = m_data.value(scAllUsersStartMenuProgramsPath).toString(); else startMenuPath = m_data.value(scUserStartMenuProgramsPath).toString(); QString startMenuDir = m_core->value(scStartMenuDir, m_core->value(QLatin1String("ProductName"))); m_data.setValue(scStartMenuDir, startMenuPath + QDir::separator() + startMenuDir); } #endif disconnect(this, &PackageManagerCorePrivate::installationStarted, ProgressCoordinator::instance(), &ProgressCoordinator::reset); connect(this, &PackageManagerCorePrivate::installationStarted, ProgressCoordinator::instance(), &ProgressCoordinator::reset); disconnect(this, &PackageManagerCorePrivate::uninstallationStarted, ProgressCoordinator::instance(), &ProgressCoordinator::reset); connect(this, &PackageManagerCorePrivate::uninstallationStarted, ProgressCoordinator::instance(), &ProgressCoordinator::reset); if (!isInstaller()) m_localPackageHub->setFileName(componentsXmlPath()); if (isInstaller() || m_localPackageHub->applicationName().isEmpty()) { // TODO: this seems to be wrong, we should ask for ProductName defaulting to applicationName... m_localPackageHub->setApplicationName(m_data.settings().applicationName()); } if (isInstaller() || m_localPackageHub->applicationVersion().isEmpty()) m_localPackageHub->setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); if (isInstaller()) m_packageSources.insert(PackageSource(QUrl(QLatin1String("resource://metadata/")), 0)); m_metadataJob.disconnect(); m_metadataJob.setAutoDelete(false); m_metadataJob.setPackageManagerCore(m_core); connect(&m_metadataJob, &Job::infoMessage, this, &PackageManagerCorePrivate::infoMessage); connect(&m_metadataJob, &Job::progress, this, &PackageManagerCorePrivate::infoProgress); connect(&m_metadataJob, &Job::totalProgress, this, &PackageManagerCorePrivate::totalProgress); KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); } bool PackageManagerCorePrivate::isOfflineOnly() const { if (!isInstaller()) return false; QSettings confInternal(QLatin1String(":/config/config-internal.ini"), QSettings::IniFormat); return confInternal.value(QLatin1String("offlineOnly"), false).toBool(); } QString PackageManagerCorePrivate::installerBinaryPath() const { return qApp->applicationFilePath(); } bool PackageManagerCorePrivate::isInstaller() const { return m_magicBinaryMarker == BinaryContent::MagicInstallerMarker; } bool PackageManagerCorePrivate::isUninstaller() const { return m_magicBinaryMarker == BinaryContent::MagicUninstallerMarker; } bool PackageManagerCorePrivate::isUpdater() const { return m_magicBinaryMarker == BinaryContent::MagicUpdaterMarker; } bool PackageManagerCorePrivate::isPackageManager() const { return m_magicBinaryMarker == BinaryContent::MagicPackageManagerMarker; } bool PackageManagerCorePrivate::statusCanceledOrFailed() const { return m_status == PackageManagerCore::Canceled || m_status == PackageManagerCore::Failure; } void PackageManagerCorePrivate::setStatus(int status, const QString &error) { m_error = error; if (!error.isEmpty()) qCWarning(QInstaller::lcInstallerInstallLog) << m_error; if (m_status != status) { m_status = status; emit m_core->statusChanged(PackageManagerCore::Status(m_status)); } } QString PackageManagerCorePrivate::replaceVariables(const QString &str) const { return m_data.replaceVariables(str); } QByteArray PackageManagerCorePrivate::replaceVariables(const QByteArray &ba) const { return m_data.replaceVariables(ba); } /*! \internal Creates an update operation owned by the installer, not by any component. */ Operation *PackageManagerCorePrivate::createOwnedOperation(const QString &type) { m_ownedOperations.append(KDUpdater::UpdateOperationFactory::instance().create(type, m_core)); return m_ownedOperations.last(); } /*! \internal Removes \a operation from the operations owned by the installer, returns the very same operation if the operation was found, otherwise 0. */ Operation *PackageManagerCorePrivate::takeOwnedOperation(Operation *operation) { if (!m_ownedOperations.contains(operation)) return nullptr; m_ownedOperations.removeAll(operation); return operation; } QString PackageManagerCorePrivate::maintenanceToolName() const { QString filename = m_data.settings().maintenanceToolName(); #if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) filename += QLatin1String(".app/Contents/MacOS/") + filename; #elif defined(Q_OS_WIN) filename += QLatin1String(".exe"); #endif return QString::fromLatin1("%1/%2").arg(targetDir()).arg(filename); } static QNetworkProxy readProxy(QXmlStreamReader &reader) { QNetworkProxy proxy(QNetworkProxy::HttpProxy); while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("Host")) proxy.setHostName(reader.readElementText()); else if (reader.name() == QLatin1String("Port")) proxy.setPort(reader.readElementText().toInt()); else if (reader.name() == QLatin1String("Username")) proxy.setUser(reader.readElementText()); else if (reader.name() == QLatin1String("Password")) proxy.setPassword(reader.readElementText()); else reader.skipCurrentElement(); } return proxy; } static QSet readRepositories(QXmlStreamReader &reader, bool isDefault) { QSet set; while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("Repository")) { Repository repo(QString(), isDefault); while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("Host")) repo.setUrl(reader.readElementText()); else if (reader.name() == QLatin1String("Username")) repo.setUsername(reader.readElementText()); else if (reader.name() == QLatin1String("Password")) repo.setPassword(reader.readElementText()); else if (reader.name() == QLatin1String("DisplayName")) repo.setDisplayName(reader.readElementText()); else if (reader.name() == QLatin1String("Enabled")) repo.setEnabled(bool(reader.readElementText().toInt())); else reader.skipCurrentElement(); } set.insert(repo); } else { reader.skipCurrentElement(); } } return set; } void PackageManagerCorePrivate::writeMaintenanceConfigFiles() { // write current state (variables) to the maintenance tool ini file const QString iniPath = targetDir() + QLatin1Char('/') + m_data.settings().maintenanceToolIniFile(); QVariantHash variables; // Do not change to QVariantMap! Breaks existing .ini files, // cause the variant types do not match while restoring the variables from the file. QSettingsWrapper cfg(iniPath, QSettingsWrapper::IniFormat); foreach (const QString &key, m_data.keys()) { if (key == scRunProgramDescription || key == scRunProgram || key == scRunProgramArguments) continue; QVariant value = m_data.value(key); if (value.canConvert(QVariant::String)) value = replacePath(value.toString(), targetDir(), QLatin1String(scRelocatable)); variables.insert(key, value); } cfg.setValue(QLatin1String("Variables"), variables); QVariantList repos; // Do not change either! if (m_data.settings().saveDefaultRepositories()) { foreach (const Repository &repo, m_data.settings().defaultRepositories()) repos.append(QVariant().fromValue(repo)); } cfg.setValue(QLatin1String("DefaultRepositories"), repos); cfg.setValue(QLatin1String("FilesForDelayedDeletion"), m_filesForDelayedDeletion); cfg.sync(); if (cfg.status() != QSettingsWrapper::NoError) { const QString reason = cfg.status() == QSettingsWrapper::AccessError ? tr("Access error") : tr("Format error"); throw Error(tr("Cannot write installer configuration to %1: %2").arg(iniPath, reason)); } setDefaultFilePermissions(iniPath, DefaultFilePermissions::NonExecutable); QFile file(targetDir() + QLatin1Char('/') + QLatin1String("network.xml")); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QXmlStreamWriter writer(&file); writer.setCodec("UTF-8"); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement(QLatin1String("Network")); writer.writeTextElement(QLatin1String("ProxyType"), QString::number(m_data.settings().proxyType())); writer.writeStartElement(QLatin1String("Ftp")); const QNetworkProxy &ftpProxy = m_data.settings().ftpProxy(); writer.writeTextElement(QLatin1String("Host"), ftpProxy.hostName()); writer.writeTextElement(QLatin1String("Port"), QString::number(ftpProxy.port())); writer.writeTextElement(QLatin1String("Username"), ftpProxy.user()); writer.writeTextElement(QLatin1String("Password"), ftpProxy.password()); writer.writeEndElement(); writer.writeStartElement(QLatin1String("Http")); const QNetworkProxy &httpProxy = m_data.settings().httpProxy(); writer.writeTextElement(QLatin1String("Host"), httpProxy.hostName()); writer.writeTextElement(QLatin1String("Port"), QString::number(httpProxy.port())); writer.writeTextElement(QLatin1String("Username"), httpProxy.user()); writer.writeTextElement(QLatin1String("Password"), httpProxy.password()); writer.writeEndElement(); writer.writeStartElement(QLatin1String("Repositories")); foreach (const Repository &repo, m_data.settings().userRepositories()) { writer.writeStartElement(QLatin1String("Repository")); writer.writeTextElement(QLatin1String("Host"), repo.url().toString()); writer.writeTextElement(QLatin1String("Username"), repo.username()); writer.writeTextElement(QLatin1String("Password"), repo.password()); writer.writeTextElement(QLatin1String("Enabled"), QString::number(repo.isEnabled())); writer.writeEndElement(); } writer.writeEndElement(); writer.writeEndElement(); } setDefaultFilePermissions(&file, DefaultFilePermissions::NonExecutable); } void PackageManagerCorePrivate::readMaintenanceConfigFiles(const QString &targetDir) { QSettingsWrapper cfg(targetDir + QLatin1Char('/') + m_data.settings().maintenanceToolIniFile(), QSettingsWrapper::IniFormat); const QVariantHash v = cfg.value(QLatin1String("Variables")).toHash(); // Do not change to // QVariantMap! Breaks reading from existing .ini files, cause the variant types do not match. for (QVariantHash::const_iterator it = v.constBegin(); it != v.constEnd(); ++it) { m_data.setValue(it.key(), replacePath(it.value().toString(), QLatin1String(scRelocatable), targetDir)); } QSet repos; const QVariantList variants = cfg.value(QLatin1String("DefaultRepositories")) .toList(); // Do not change either! foreach (const QVariant &variant, variants) repos.insert(variant.value()); if (!repos.isEmpty()) m_data.settings().setDefaultRepositories(repos); m_filesForDelayedDeletion = cfg.value(QLatin1String("FilesForDelayedDeletion")).toStringList(); QFile file(targetDir + QLatin1String("/network.xml")); if (!file.open(QIODevice::ReadOnly)) return; QXmlStreamReader reader(&file); while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: { if (reader.name() == QLatin1String("Network")) { while (reader.readNextStartElement()) { const QStringRef name = reader.name(); if (name == QLatin1String("Ftp")) { m_data.settings().setFtpProxy(readProxy(reader)); } else if (name == QLatin1String("Http")) { m_data.settings().setHttpProxy(readProxy(reader)); } else if (reader.name() == QLatin1String("Repositories")) { m_data.settings().addUserRepositories(readRepositories(reader, false)); } else if (name == QLatin1String("ProxyType")) { m_data.settings().setProxyType(Settings::ProxyType(reader.readElementText().toInt())); } else { reader.skipCurrentElement(); } } } } break; case QXmlStreamReader::Invalid: { qCWarning(QInstaller::lcInstallerInstallLog) << reader.errorString(); } break; default: break; } } } void PackageManagerCorePrivate::callBeginInstallation(const QList &componentList) { foreach (Component *component, componentList) component->beginInstallation(); } void PackageManagerCorePrivate::stopProcessesForUpdates(const QList &components) { QStringList processList; foreach (const Component *component, components) processList << m_core->replaceVariables(component->stopProcessForUpdateRequests()); std::sort(processList.begin(), processList.end()); processList.erase(std::unique(processList.begin(), processList.end()), processList.end()); if (processList.isEmpty()) return; uint retryCount = 5; while (true) { const QStringList processes = checkRunningProcessesFromList(processList); if (processes.isEmpty()) return; const QMessageBox::StandardButton button = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), QLatin1String("stopProcessesForUpdates"), tr("Stop Processes"), tr("These processes " "should be stopped to continue:\n\n%1").arg(QDir::toNativeSeparators(processes .join(QLatin1String("\n")))), QMessageBox::Retry | QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Cancel); if (button == QMessageBox::Ignore) return; if (button == QMessageBox::Cancel) { m_core->setCanceled(); throw Error(tr("Installation canceled by user")); } if (!m_core->isCommandLineInstance()) continue; // Do not allow infinite retries with cli instance if (--retryCount == 0) throw Error(tr("Retry count exceeded")); } } int PackageManagerCorePrivate::countProgressOperations(const OperationList &operations) { int operationCount = 0; foreach (Operation *operation, operations) { if (QObject *operationObject = dynamic_cast (operation)) { const QMetaObject *const mo = operationObject->metaObject(); if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) operationCount++; } } return operationCount; } int PackageManagerCorePrivate::countProgressOperations(const QList &components) { int operationCount = 0; foreach (Component *component, components) operationCount += countProgressOperations(component->operations()); return operationCount; } void PackageManagerCorePrivate::connectOperationToInstaller(Operation *const operation, double operationPartSize) { Q_ASSERT(operationPartSize); QObject *const operationObject = dynamic_cast< QObject*> (operation); if (operationObject != nullptr) { const QMetaObject *const mo = operationObject->metaObject(); if (mo->indexOfSignal(QMetaObject::normalizedSignature("outputTextChanged(QString)")) > -1) { connect(operationObject, SIGNAL(outputTextChanged(QString)), ProgressCoordinator::instance(), SLOT(emitDetailTextChanged(QString))); } if (mo->indexOfSlot(QMetaObject::normalizedSignature("cancelOperation()")) > -1) connect(m_core, SIGNAL(installationInterrupted()), operationObject, SLOT(cancelOperation())); if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) { ProgressCoordinator::instance()->registerPartProgress(operationObject, SIGNAL(progressChanged(double)), operationPartSize); } } } Operation *PackageManagerCorePrivate::createPathOperation(const QFileInfo &fileInfo, const QString &componentName) { const bool isDir = fileInfo.isDir(); // create an operation with the dir/ file as target, it will get deleted on undo Operation *operation = createOwnedOperation(QLatin1String(isDir ? "Mkdir" : "Copy")); if (isDir) operation->setValue(QLatin1String("createddir"), fileInfo.absoluteFilePath()); operation->setValue(QLatin1String("component"), componentName); operation->setArguments(isDir ? QStringList() << fileInfo.absoluteFilePath() : QStringList() << QString() << fileInfo.absoluteFilePath()); return operation; } /*! This creates fake operations which remove stuff which was registered for uninstallation afterwards */ void PackageManagerCorePrivate::registerPathsForUninstallation( const QList > &pathsForUninstallation, const QString &componentName) { if (pathsForUninstallation.isEmpty()) return; QList >::const_iterator it; for (it = pathsForUninstallation.begin(); it != pathsForUninstallation.end(); ++it) { const bool wipe = it->second; const QString path = replaceVariables(it->first); const QFileInfo fi(path); // create a copy operation with the file as target -> it will get deleted on undo Operation *op = createPathOperation(fi, componentName); if (fi.isDir()) op->setValue(QLatin1String("forceremoval"), wipe ? scTrue : scFalse); addPerformed(takeOwnedOperation(op)); // get recursive afterwards if (fi.isDir() && !wipe) { QDirIterator dirIt(path, QDir::Hidden | QDir::AllEntries | QDir::System | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (dirIt.hasNext()) { dirIt.next(); op = createPathOperation(dirIt.fileInfo(), componentName); addPerformed(takeOwnedOperation(op)); } } } } void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, qint64 size, bool writeBinaryLayout) { QString maintenanceToolRenamedName = maintenanceToolName() + QLatin1String(".new"); qCDebug(QInstaller::lcInstallerInstallLog) << "Writing maintenance tool:" << maintenanceToolRenamedName; ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Writing maintenance tool.")); QFile out(generateTemporaryFileName()); QInstaller::openForWrite(&out); // throws an exception in case of error if (!input->seek(0)) throw Error(tr("Failed to seek in file %1: %2").arg(input->fileName(), input->errorString())); QInstaller::appendData(&out, input, size); if (writeBinaryLayout) { QDir resourcePath(QFileInfo(maintenanceToolRenamedName).dir()); #ifdef Q_OS_MACOS if (!resourcePath.path().endsWith(QLatin1String("Contents/MacOS"))) throw Error(tr("Maintenance tool is not a bundle")); resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); #endif // It's a bit odd to have only the magic in the data file, but this simplifies // other code a lot (since installers don't have any appended data either) QFile dataOut(generateTemporaryFileName()); QInstaller::openForWrite(&dataOut); QInstaller::appendInt64(&dataOut, 0); // operations start QInstaller::appendInt64(&dataOut, 0); // operations end QInstaller::appendInt64(&dataOut, 0); // resource count QInstaller::appendInt64(&dataOut, 4 * sizeof(qint64)); // data block size QInstaller::appendInt64(&dataOut, BinaryContent::MagicUninstallerMarker); QInstaller::appendInt64(&dataOut, BinaryContent::MagicCookie); { QFile dummy(resourcePath.filePath(QLatin1String("installer.dat"))); if (dummy.exists() && !dummy.remove()) { throw Error(tr("Cannot remove data file \"%1\": %2").arg(dummy.fileName(), dummy.errorString())); } } if (!dataOut.rename(resourcePath.filePath(QLatin1String("installer.dat")))) { throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(dataOut.fileName(), dataOut.errorString())); } setDefaultFilePermissions(&dataOut, DefaultFilePermissions::NonExecutable); } { QFile dummy(maintenanceToolRenamedName); if (dummy.exists() && !dummy.remove()) { throw Error(tr("Cannot remove data file \"%1\": %2").arg(dummy.fileName(), dummy.errorString())); } } if (!out.copy(maintenanceToolRenamedName)) { throw Error(tr("Cannot write maintenance tool to \"%1\": %2").arg(maintenanceToolRenamedName, out.errorString())); } QFile mt(maintenanceToolRenamedName); if (setDefaultFilePermissions(&mt, DefaultFilePermissions::Executable)) qCDebug(QInstaller::lcInstallerInstallLog) << "Wrote permissions for maintenance tool."; else qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to write permissions for maintenance tool."; if (out.exists() && !out.remove()) { qCWarning(QInstaller::lcInstallerInstallLog) << tr("Cannot remove temporary data file \"%1\": %2") .arg(out.fileName(), out.errorString()); } } void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input, const OperationList &performedOperations, const BinaryLayout &layout) { const qint64 dataBlockStart = output->pos(); QVector >resourceSegments; QVector >existingResourceSegments = layout.metaResourceSegments; const QString newDefaultResource = m_core->value(QString::fromLatin1("DefaultResourceReplacement")); if (!newDefaultResource.isEmpty()) { QFile file(newDefaultResource); if (file.open(QIODevice::ReadOnly)) { resourceSegments.append(Range::fromStartAndLength(output->pos(), file.size())); QInstaller::appendData(output, &file, file.size()); existingResourceSegments.remove(0); file.remove(); // clear all possible leftovers m_core->setValue(QString::fromLatin1("DefaultResourceReplacement"), QString()); } else { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot replace default resource with" << QDir::toNativeSeparators(newDefaultResource); } } foreach (const Range &segment, existingResourceSegments) { input->seek(segment.start()); resourceSegments.append(Range::fromStartAndLength(output->pos(), segment.length())); QInstaller::appendData(output, input, segment.length()); } const qint64 operationsStart = output->pos(); QInstaller::appendInt64(output, performedOperations.count()); foreach (Operation *operation, performedOperations) { QInstaller::appendString(output, operation->name()); QInstaller::appendString(output, operation->toXml().toString()); // for the ui not to get blocked qApp->processEvents(); } QInstaller::appendInt64(output, performedOperations.count()); const qint64 operationsEnd = output->pos(); // we don't save any component-indexes. const qint64 numComponents = 0; QInstaller::appendInt64(output, numComponents); // for the indexes // we don't save any components. const qint64 compIndexStart = output->pos(); QInstaller::appendInt64(output, numComponents); // and 2 times number of components, QInstaller::appendInt64(output, numComponents); // one before and one after the components const qint64 compIndexEnd = output->pos(); QInstaller::appendInt64Range(output, Range::fromStartAndEnd(compIndexStart, compIndexEnd) .moved(-dataBlockStart)); foreach (const Range segment, resourceSegments) QInstaller::appendInt64Range(output, segment.moved(-dataBlockStart)); QInstaller::appendInt64Range(output, Range::fromStartAndEnd(operationsStart, operationsEnd) .moved(-dataBlockStart)); QInstaller::appendInt64(output, layout.metaResourceSegments.count()); // data block size, from end of .exe to end of file QInstaller::appendInt64(output, output->pos() + 3 * sizeof(qint64) -dataBlockStart); QInstaller::appendInt64(output, BinaryContent::MagicUninstallerMarker); } void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) { if (m_disableWriteMaintenanceTool) { qCDebug(QInstaller::lcInstallerInstallLog()) << "Maintenance tool writing disabled."; return; } bool gainedAdminRights = false; if (!directoryWritable(targetDir())) { m_core->gainAdminRights(); gainedAdminRights = true; } const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path(); if (!QDir().exists(targetAppDirPath)) { // create the directory containing the maintenance tool (like a bundle structure on macOS...) Operation *op = createOwnedOperation(QLatin1String("Mkdir")); op->setArguments(QStringList() << targetAppDirPath); performOperationThreaded(op, Backup); performOperationThreaded(op); performedOperations.append(takeOwnedOperation(op)); } #ifdef Q_OS_MACOS // if it is a bundle, we need some stuff in it... const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); if (isInstaller() && QInstaller::isInBundle(sourceAppDirPath)) { Operation *op = createOwnedOperation(QLatin1String("Copy")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../PkgInfo")) << (targetAppDirPath + QLatin1String("/../PkgInfo"))); performOperationThreaded(op, Backup); performOperationThreaded(op); // copy Info.plist to target directory op = createOwnedOperation(QLatin1String("Copy")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../Info.plist")) << (targetAppDirPath + QLatin1String("/../Info.plist"))); performOperationThreaded(op, Backup); performOperationThreaded(op); // patch the Info.plist after copying it QFile sourcePlist(sourceAppDirPath + QLatin1String("/../Info.plist")); QInstaller::openForRead(&sourcePlist); QFile targetPlist(targetAppDirPath + QLatin1String("/../Info.plist")); QInstaller::openForWrite(&targetPlist); QTextStream in(&sourcePlist); QTextStream out(&targetPlist); const QString before = QLatin1String("") + QFileInfo(QCoreApplication::applicationFilePath()) .fileName() + QLatin1String(""); const QString after = QLatin1String("") + QFileInfo(maintenanceToolName()).baseName() + QLatin1String(""); while (!in.atEnd()) out << in.readLine().replace(before, after) << endl; // copy qt_menu.nib if it exists op = createOwnedOperation(QLatin1String("Mkdir")); op->setArguments(QStringList() << (targetAppDirPath + QLatin1String("/../Resources/qt_menu.nib"))); if (!op->performOperation()) { qCWarning(QInstaller::lcInstallerInstallLog) << "ERROR in Mkdir operation:" << op->errorString(); } op = createOwnedOperation(QLatin1String("CopyDirectory")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../Resources/qt_menu.nib")) << (targetAppDirPath + QLatin1String("/../Resources/qt_menu.nib"))); performOperationThreaded(op); op = createOwnedOperation(QLatin1String("Mkdir")); op->setArguments(QStringList() << (QFileInfo(targetAppDirPath).path() + QLatin1String("/Resources"))); performOperationThreaded(op, Backup); performOperationThreaded(op); // copy application icons if it exists. const QString icon = QFileInfo(QCoreApplication::applicationFilePath()).fileName() + QLatin1String(".icns"); op = createOwnedOperation(QLatin1String("Copy")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../Resources/") + icon) << (targetAppDirPath + QLatin1String("/../Resources/") + icon)); performOperationThreaded(op, Backup); performOperationThreaded(op); // finally, copy everything within Frameworks and plugins op = createOwnedOperation(QLatin1String("CopyDirectory")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../Frameworks")) << (targetAppDirPath + QLatin1String("/../Frameworks"))); performOperationThreaded(op); op = createOwnedOperation(QLatin1String("CopyDirectory")); op->setArguments(QStringList() << (sourceAppDirPath + QLatin1String("/../plugins")) << (targetAppDirPath + QLatin1String("/../plugins"))); performOperationThreaded(op); } #endif try { // 1 - check if we have a installer base replacement // |--- if so, write out the new tool and remove the replacement // |--- remember to restart and that we need to replace the original binary // // 2 - if we do not have a replacement, try to open the binary data file as input // |--- try to read the binary layout // |--- on error (see 2.1) // |--- remember we might to append uncompressed resource data (see 3) // |--- set the installer or maintenance binary as input to take over binary data // |--- in case we did not have a replacement, write out an new maintenance tool binary // |--- remember that we need to replace the original binary // // 3 - open a new binary data file // |--- try to write out the binary data based on the loaded input file (see 2) // |--- on error (see 3.1) // |--- if we wrote a new maintenance tool, take this as output - if not, write out a new // one and set it as output file, remember we did this // |--- append the binary data based on the loaded input file (see 2), make sure we force // uncompressing the resource section if we read from a binary data file (see 4.1). // // 4 - force a deferred rename on the .dat file (see 4.1) // 5 - force a deferred rename on the maintenance file (see 5.1) // 2.1 - Error cases are: no data file (in fact we are the installer or an old installation), // could not find the data file magic cookie (unknown .dat file), failed to read binary // layout (mostly likely the resource section or we couldn't seek inside the file) // // 3.1 - most likely the commit operation will fail // 4.1 - if 3 failed, this makes sure the .dat file will get removed and on the next run all // binary data is read from the maintenance tool, otherwise it get replaced be the new one // 5.1 - this will only happen -if- we wrote out a new binary bool newBinaryWritten = false; bool replacementExists = false; const QString installerBaseBinary = replaceVariables(m_installerBaseBinaryUnreplaced); if (!installerBaseBinary.isEmpty() && QFileInfo(installerBaseBinary).exists()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Got a replacement installer base binary:" << installerBaseBinary; QFile replacementBinary(installerBaseBinary); try { QInstaller::openForRead(&replacementBinary); writeMaintenanceToolBinary(&replacementBinary, replacementBinary.size(), true); qCDebug(QInstaller::lcInstallerInstallLog) << "Wrote the binary with the new replacement."; newBinaryWritten = true; replacementExists = true; } catch (const Error &error) { qCWarning(QInstaller::lcInstallerInstallLog) << error.message(); } if (!replacementBinary.remove()) { // Is there anything more sensible we can do with this error? I think not. It's not serious // enough for throwing / aborting the process. qCDebug(QInstaller::lcInstallerInstallLog) << "Cannot remove installer base binary" << installerBaseBinary << "after updating the maintenance tool:" << replacementBinary.errorString(); } else { qCDebug(QInstaller::lcInstallerInstallLog) << "Removed installer base binary" << installerBaseBinary << "after updating the maintenance tool."; } m_installerBaseBinaryUnreplaced.clear(); } else if (!installerBaseBinary.isEmpty() && !QFileInfo(installerBaseBinary).exists()) { qCWarning(QInstaller::lcInstallerInstallLog) << "The current maintenance tool could not be updated." << installerBaseBinary << "does not exist. Please fix the \"setInstallerBaseBinary" "()\" call in your script."; } QFile input; BinaryLayout layout; const QString dataFile = targetDir() + QLatin1Char('/') + m_data.settings().maintenanceToolName() + QLatin1String(".dat"); try { if (isInstaller()) { if (QFile::exists(dataFile)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Found binary data file" << dataFile << "but deliberately not used. Running as installer requires to read the " "resources from the application binary."; } throw Error(); } input.setFileName(dataFile); QInstaller::openForRead(&input); layout = BinaryContent::binaryLayout(&input, BinaryContent::MagicCookieDat); } catch (const Error &/*error*/) { // We are only here when using installer QString binaryName = installerBinaryPath(); // On Mac data is always in a separate file so that the binary can be signed. // On other platforms data is in separate file only after install so that the // maintenancetool sign does not break. #ifdef Q_OS_MACOS QDir dataPath(QFileInfo(binaryName).dir()); dataPath.cdUp(); dataPath.cd(QLatin1String("Resources")); input.setFileName(dataPath.filePath(QLatin1String("installer.dat"))); #else input.setFileName(binaryName); #endif QInstaller::openForRead(&input); layout = BinaryContent::binaryLayout(&input, BinaryContent::MagicCookie); if (!newBinaryWritten) { newBinaryWritten = true; QFile tmp(binaryName); QInstaller::openForRead(&tmp); #ifdef Q_OS_MACOS writeMaintenanceToolBinary(&tmp, tmp.size(), true); #else writeMaintenanceToolBinary(&tmp, layout.endOfBinaryContent - layout.binaryContentSize, true); #endif } } performedOperations = sortOperationsBasedOnComponentDependencies(performedOperations); m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); try { QFile file(generateTemporaryFileName()); QInstaller::openForWrite(&file); writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout); QInstaller::appendInt64(&file, BinaryContent::MagicCookieDat); QFile dummy(dataFile + QLatin1String(".new")); if (dummy.exists() && !dummy.remove()) { throw Error(tr("Cannot remove data file \"%1\": %2").arg(dummy.fileName(), dummy.errorString())); } if (!file.rename(dataFile + QLatin1String(".new"))) { throw Error(tr("Cannot write maintenance tool binary data to %1: %2") .arg(file.fileName(), file.errorString())); } setDefaultFilePermissions(&file, DefaultFilePermissions::NonExecutable); } catch (const Error &/*error*/) { if (!newBinaryWritten) { newBinaryWritten = true; QFile tmp(isInstaller() ? installerBinaryPath() : maintenanceToolName()); QInstaller::openForRead(&tmp); BinaryLayout tmpLayout = BinaryContent::binaryLayout(&tmp, BinaryContent::MagicCookie); writeMaintenanceToolBinary(&tmp, tmpLayout.endOfBinaryContent - tmpLayout.binaryContentSize, false); } QFile file(maintenanceToolName() + QLatin1String(".new")); QInstaller::openForAppend(&file); file.seek(file.size()); writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout); QInstaller::appendInt64(&file, BinaryContent::MagicCookie); } input.close(); if (m_core->isInstaller()) registerMaintenanceTool(); writeMaintenanceConfigFiles(); deferredRename(dataFile + QLatin1String(".new"), dataFile, false); if (newBinaryWritten) { const bool restart = replacementExists && isUpdater() && (!statusCanceledOrFailed()) && m_needsHardRestart; deferredRename(maintenanceToolName() + QLatin1String(".new"), maintenanceToolName(), restart); qCDebug(QInstaller::lcInstallerInstallLog) << "Maintenance tool restart:" << (restart ? "true." : "false."); } } catch (const Error &err) { setStatus(PackageManagerCore::Failure); if (gainedAdminRights) m_core->dropAdminRights(); m_needToWriteMaintenanceTool = false; throw err; } if (gainedAdminRights) m_core->dropAdminRights(); commitSessionOperations(); m_needToWriteMaintenanceTool = false; } QString PackageManagerCorePrivate::registerPath() { #ifdef Q_OS_WIN QString guid = m_data.value(scProductUUID).toString(); if (guid.isEmpty()) { guid = QUuid::createUuid().toString(); m_data.setValue(scProductUUID, guid); writeMaintenanceConfigFiles(); // save uuid persistently } QString path = QLatin1String("HKEY_CURRENT_USER"); if (m_data.value(scAllUsers, scFalse).toString() == scTrue) path = QLatin1String("HKEY_LOCAL_MACHINE"); return path + QLatin1String("\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + guid; #endif return QString(); } bool PackageManagerCorePrivate::runInstaller() { bool adminRightsGained = false; try { setStatus(PackageManagerCore::Running); emit installationStarted(); // resets also the ProgressCoordninator // to have some progress for writeMaintenanceTool ProgressCoordinator::instance()->addReservePercentagePoints(1); const QString target = QDir::cleanPath(targetDir().replace(QLatin1Char('\\'), QLatin1Char('/'))); if (target.isEmpty()) throw Error(tr("Variable 'TargetDir' not set.")); if (!QDir(target).exists()) { const QString &pathToTarget = target.mid(0, target.lastIndexOf(QLatin1Char('/'))); if (!QDir(pathToTarget).exists()) { Operation *pathToTargetOp = createOwnedOperation(QLatin1String("Mkdir")); pathToTargetOp->setArguments(QStringList() << pathToTarget); if (!performOperationThreaded(pathToTargetOp)) { adminRightsGained = m_core->gainAdminRights(); if (!performOperationThreaded(pathToTargetOp)) throw Error(pathToTargetOp->errorString()); } } } else if (QDir(target).exists()) { if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); } // add the operation to create the target directory Operation *mkdirOp = createOwnedOperation(QLatin1String("Mkdir")); mkdirOp->setArguments(QStringList() << target); mkdirOp->setValue(QLatin1String("forceremoval"), true); mkdirOp->setValue(QLatin1String("uninstall-only"), true); performOperationThreaded(mkdirOp, Backup); if (!performOperationThreaded(mkdirOp)) { // if we cannot create the target dir, we try to activate the admin rights adminRightsGained = m_core->gainAdminRights(); if (!performOperationThreaded(mkdirOp)) throw Error(mkdirOp->errorString()); } setDefaultFilePermissions(target, DefaultFilePermissions::Executable); const QString remove = m_core->value(scRemoveTargetDir); if (QVariant(remove).toBool()) addPerformed(takeOwnedOperation(mkdirOp)); // to show that there was some work ProgressCoordinator::instance()->addManualPercentagePoints(1); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); const QList componentsToInstall = m_core->orderedComponentsToInstall(); qCDebug(QInstaller::lcInstallerInstallLog) << "Install size:" << componentsToInstall.size() << "components"; callBeginInstallation(componentsToInstall); stopProcessesForUpdates(componentsToInstall); if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { throw Error(tr("It is not possible to install from network location")); } if (!adminRightsGained) { foreach (Component *component, componentsToInstall) { if (component->value(scRequiresAdminRights, scFalse) == scFalse) continue; m_core->gainAdminRights(); m_core->dropAdminRights(); break; } } const double downloadPartProgressSize = double(1) / double(3); double componentsInstallPartProgressSize = double(2) / double(3); const int downloadedArchivesCount = m_core->downloadNeededArchives(downloadPartProgressSize); // if there was no download we have the whole progress for installing components if (!downloadedArchivesCount) componentsInstallPartProgressSize = double(1); // Force an update on the components xml as the install dir might have changed. m_localPackageHub->setFileName(componentsXmlPath()); // Clear the packages as we might install into an already existing installation folder. m_localPackageHub->clearPackageInfos(); // also update the application name, might be set from a script as well m_localPackageHub->setApplicationName(m_data.value(QLatin1String("ProductName"), m_data.settings().applicationName()).toString()); m_localPackageHub->setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); const int progressOperationCount = countProgressOperations(componentsToInstall) // add one more operation as we support progress + (PackageManagerCore::createLocalRepositoryFromBinary() ? 1 : 0); double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; foreach (Component *component, componentsToInstall) installComponent(component, progressOperationSize, adminRightsGained); if (m_core->isOfflineOnly() && PackageManagerCore::createLocalRepositoryFromBinary()) { emit m_core->titleMessageChanged(tr("Creating local repository")); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(QString()); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Creating local repository")); Operation *createRepo = createOwnedOperation(QLatin1String("CreateLocalRepository")); if (createRepo) { QString binaryFile = QCoreApplication::applicationFilePath(); #ifdef Q_OS_MACOS // The installer binary on macOS does not contain the binary content, it's put into // the resources folder as separate file. Adjust the actual binary path. No error // checking here since we will fail later while reading the binary content. QDir resourcePath(QFileInfo(binaryFile).dir()); resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); binaryFile = resourcePath.filePath(QLatin1String("installer.dat")); #endif createRepo->setValue(QLatin1String("uninstall-only"), true); createRepo->setArguments(QStringList() << binaryFile << target + QLatin1String("/repository")); connectOperationToInstaller(createRepo, progressOperationSize); bool success = performOperationThreaded(createRepo); if (!success) { adminRightsGained = m_core->gainAdminRights(); success = performOperationThreaded(createRepo); } if (success) { QSet repos; foreach (Repository repo, m_data.settings().defaultRepositories()) { repo.setEnabled(false); repos.insert(repo); } repos.insert(Repository(QUrl::fromUserInput(createRepo ->value(QLatin1String("local-repo")).toString()), true)); m_data.settings().setDefaultRepositories(repos); addPerformed(takeOwnedOperation(createRepo)); } else { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationError"), tr("Error"), createRepo->errorString()); createRepo->undoOperation(); } } } emit m_core->titleMessageChanged(tr("Creating Maintenance Tool")); m_needToWriteMaintenanceTool = true; m_core->writeMaintenanceTool(); // fake a possible wrong value to show a full progress bar const int progress = ProgressCoordinator::instance()->progressInPercentage(); // usually this should be only the reserved one from the beginning if (progress < 100) ProgressCoordinator::instance()->addManualPercentagePoints(100 - progress); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation finished!")); if (adminRightsGained) m_core->dropAdminRights(); setStatus(PackageManagerCore::Success); emit installationFinished(); } catch (const Error &err) { if (m_core->status() != PackageManagerCore::Canceled) { setStatus(PackageManagerCore::Failure); MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationError"), tr("Error"), err.message()); qCDebug(QInstaller::lcInstallerInstallLog) << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count(); } m_core->rollBackInstallation(); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation aborted!")); if (adminRightsGained) m_core->dropAdminRights(); emit installationFinished(); return false; } return true; } bool PackageManagerCorePrivate::runPackageUpdater() { bool adminRightsGained = false; if (m_completeUninstall) { return runUninstaller(); } try { setStatus(PackageManagerCore::Running); emit installationStarted(); //resets also the ProgressCoordninator //to have some progress for the cleanup/write component.xml step ProgressCoordinator::instance()->addReservePercentagePoints(1); // check if we need admin rights and ask before the action happens if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); const QList componentsToInstall = m_core->orderedComponentsToInstall(); qCDebug(QInstaller::lcInstallerInstallLog) << "Install size:" << componentsToInstall.size() << "components"; callBeginInstallation(componentsToInstall); stopProcessesForUpdates(componentsToInstall); if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { throw Error(tr("It is not possible to run that operation from a network location")); } bool updateAdminRights = false; if (!adminRightsGained) { foreach (Component *component, componentsToInstall) { if (component->value(scRequiresAdminRights, scFalse) == scFalse) continue; updateAdminRights = true; break; } } OperationList undoOperations; OperationList nonRevertedOperations; QHash componentsByName; // order the operations in the right component dependency order // next loop will save the needed operations in reverse order for uninstallation OperationList performedOperationsOld = m_performedOperationsOld; if (m_core->value(QLatin1String("installedOperationAreSorted")) != QLatin1String("true")) performedOperationsOld = sortOperationsBasedOnComponentDependencies(m_performedOperationsOld); // build a list of undo operations based on the checked state of the component foreach (Operation *operation, performedOperationsOld) { const QString &name = operation->value(QLatin1String("component")).toString(); Component *component = componentsByName.value(name, nullptr); if (!component) component = m_core->componentByName(PackageManagerCore::checkableName(name)); if (component) componentsByName.insert(name, component); if (isUpdater()) { // We found the component, the component is not scheduled for update, the dependency solver // did not add the component as install dependency and there is no replacement, keep it. if ((component && !component->updateRequested() && !componentsToInstall.contains(component) && !m_componentsToReplaceUpdaterMode.contains(name))) { nonRevertedOperations.append(operation); continue; } // There is a replacement, but the replacement is not scheduled for update, keep it as well. if (m_componentsToReplaceUpdaterMode.contains(name) && !m_componentsToReplaceUpdaterMode.value(name).first->updateRequested()) { nonRevertedOperations.append(operation); continue; } } else if (isPackageManager()) { // We found the component, the component is still checked and the dependency solver did not // add the component as install dependency, keep it. if (component && component->installAction() == ComponentModelHelper::KeepInstalled && !componentsToInstall.contains(component)) { nonRevertedOperations.append(operation); continue; } // There is a replacement, but the replacement is not scheduled for update, keep it as well. if (m_componentsToReplaceAllMode.contains(name) && !m_componentsToReplaceAllMode.value(name).first->isSelectedForInstallation()) { nonRevertedOperations.append(operation); continue; } } else { Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid package manager mode!"); } // Filter out the create target dir undo operation, it's only needed for full uninstall. // Note: We filter for unnamed operations as well, since old installations had the remove target // dir operation without the "uninstall-only", which will result in a complete uninstallation // during an update for the maintenance tool. if (operation->value(QLatin1String("uninstall-only")).toBool() || operation->value(QLatin1String("component")).toString().isEmpty()) { nonRevertedOperations.append(operation); continue; } // uninstallation should be in reverse order so prepend it here undoOperations.prepend(operation); updateAdminRights |= operation->value(QLatin1String("admin")).toBool(); } // we did not request admin rights till we found out that a component/ undo needs admin rights if (updateAdminRights && !adminRightsGained) { m_core->gainAdminRights(); m_core->dropAdminRights(); } double undoOperationProgressSize = 0; const double downloadPartProgressSize = double(2) / double(5); double componentsInstallPartProgressSize = double(3) / double(5); if (undoOperations.count() > 0) { undoOperationProgressSize = double(1) / double(5); componentsInstallPartProgressSize = downloadPartProgressSize; undoOperationProgressSize /= countProgressOperations(undoOperations); } ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); // following, we download the needed archives m_core->downloadNeededArchives(downloadPartProgressSize); if (undoOperations.count() > 0) { ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Removing deselected components...")); runUndoOperations(undoOperations, undoOperationProgressSize, adminRightsGained, true); } m_performedOperationsOld = nonRevertedOperations; // these are all operations left: those not reverted const double progressOperationCount = countProgressOperations(componentsToInstall); const double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; foreach (Component *component, componentsToInstall) installComponent(component, progressOperationSize, adminRightsGained); emit m_core->titleMessageChanged(tr("Creating Maintenance Tool")); commitSessionOperations(); //end session, move ops to "old" m_needToWriteMaintenanceTool = true; // fake a possible wrong value to show a full progress bar const int progress = ProgressCoordinator::instance()->progressInPercentage(); // usually this should be only the reserved one from the beginning if (progress < 100) ProgressCoordinator::instance()->addManualPercentagePoints(100 - progress); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nUpdate finished!")); if (adminRightsGained) m_core->dropAdminRights(); if (m_foundEssentialUpdate) setStatus(PackageManagerCore::EssentialUpdated); else setStatus(PackageManagerCore::Success); emit installationFinished(); } catch (const Error &err) { if (m_core->status() != PackageManagerCore::Canceled) { setStatus(PackageManagerCore::Failure); MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationError"), tr("Error"), err.message()); qCDebug(QInstaller::lcInstallerInstallLog) << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count(); } m_core->rollBackInstallation(); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nUpdate aborted!")); if (adminRightsGained) m_core->dropAdminRights(); emit installationFinished(); return false; } return true; } bool PackageManagerCorePrivate::runUninstaller() { emit uninstallationStarted(); bool adminRightsGained = false; try { setStatus(PackageManagerCore::Running); // check if we need to run elevated and ask before the action happens if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); OperationList undoOperations = m_performedOperationsOld; std::reverse(undoOperations.begin(), undoOperations.end()); bool updateAdminRights = false; if (!adminRightsGained) { foreach (Operation *op, m_performedOperationsOld) { updateAdminRights |= op->value(QLatin1String("admin")).toBool(); if (updateAdminRights) break; // an operation needs elevation to be able to perform their undo } } // We did not yet request elevated permissions but they are required. if (updateAdminRights && !adminRightsGained) { m_core->gainAdminRights(); m_core->dropAdminRights(); } const int uninstallOperationCount = countProgressOperations(undoOperations); const double undoOperationProgressSize = double(1) / double(uninstallOperationCount); runUndoOperations(undoOperations, undoOperationProgressSize, adminRightsGained, false); // No operation delete here, as all old undo operations are deleted in the destructor. deleteMaintenanceTool(); // this will also delete the TargetDir on Windows // If not on Windows, we need to remove TargetDir manually. #ifndef Q_OS_WIN if (QVariant(m_core->value(scRemoveTargetDir)).toBool() && !targetDir().isEmpty()) { if (updateAdminRights && !adminRightsGained) adminRightsGained = m_core->gainAdminRights(); removeDirectoryThreaded(targetDir(), true); qCDebug(QInstaller::lcInstallerInstallLog) << "Complete uninstallation was chosen."; } #endif unregisterMaintenanceTool(); m_needToWriteMaintenanceTool = false; setStatus(PackageManagerCore::Success); } catch (const Error &err) { if (m_core->status() != PackageManagerCore::Canceled) { setStatus(PackageManagerCore::Failure); MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationError"), tr("Error"), err.message()); } } const bool success = (m_core->status() == PackageManagerCore::Success); if (adminRightsGained) m_core->dropAdminRights(); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(QString::fromLatin1("\n%1").arg( success ? tr("Uninstallation completed successfully.") : tr("Uninstallation aborted."))); emit uninstallationFinished(); return success; } void PackageManagerCorePrivate::installComponent(Component *component, double progressOperationSize, bool adminRightsGained) { const OperationList operations = component->operations(); if (!component->operationsCreatedSuccessfully()) m_core->setCanceled(); const int opCount = operations.count(); // show only components which do something, MinimumProgress is only for progress calculation safeness bool showDetailsLog = false; if (opCount > 1 || (opCount == 1 && operations.at(0)->name() != QLatin1String("MinimumProgress"))) { ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nInstalling component %1") .arg(component->displayName())); showDetailsLog = true; } foreach (Operation *operation, operations) { if (statusCanceledOrFailed()) throw Error(tr("Installation canceled by user")); // maybe this operations wants us to be admin... bool becameAdmin = false; if (!adminRightsGained && operation->value(QLatin1String("admin")).toBool()) { becameAdmin = m_core->gainAdminRights(); qCDebug(QInstaller::lcInstallerInstallLog) << operation->name() << "as admin:" << becameAdmin; } connectOperationToInstaller(operation, progressOperationSize); connectOperationCallMethodRequest(operation); // allow the operation to backup stuff before performing the operation performOperationThreaded(operation, PackageManagerCorePrivate::Backup); bool ignoreError = false; bool ok = performOperationThreaded(operation); while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) { qCDebug(QInstaller::lcInstallerInstallLog) << QString::fromLatin1("Operation \"%1\" with arguments " "\"%2\" failed: %3").arg(operation->name(), operation->arguments() .join(QLatin1String("; ")), operation->errorString()); const QMessageBox::StandardButton button = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationErrorWithCancel"), tr("Installer Error"), tr("Error during installation process (%1):\n%2").arg(component->name(), operation->errorString()), QMessageBox::Retry | QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Cancel); if (button == QMessageBox::Retry) ok = performOperationThreaded(operation); else if (button == QMessageBox::Ignore) ignoreError = true; else if (button == QMessageBox::Cancel) m_core->interrupt(); } if (ok || operation->error() > Operation::InvalidArguments) { // Remember that the operation was performed, that allows us to undo it if a following operation // fails or if this operation failed but still needs an undo call to cleanup. addPerformed(operation); } if (becameAdmin) m_core->dropAdminRights(); if (!ok && !ignoreError) throw Error(operation->errorString()); if ((component->value(scEssential, scFalse) == scTrue) && !m_core->isCommandLineInstance()) m_needsHardRestart = true; } registerPathsForUninstallation(component->pathsForUninstallation(), component->name()); if (!component->stopProcessForUpdateRequests().isEmpty()) { Operation *stopProcessForUpdatesOp = KDUpdater::UpdateOperationFactory::instance() .create(QLatin1String("FakeStopProcessForUpdate"), m_core); const QStringList arguments(component->stopProcessForUpdateRequests().join(QLatin1String(","))); stopProcessForUpdatesOp->setArguments(arguments); addPerformed(stopProcessForUpdatesOp); stopProcessForUpdatesOp->setValue(QLatin1String("component"), component->name()); } // now mark the component as installed m_localPackageHub->addPackage(component->name(), component->value(scVersion), component->value(scDisplayName), component->value(scDescription), component->dependencies(), component->autoDependencies(), component->forcedInstallation(), component->isVirtual(), component->value(scUncompressedSize).toULongLong(), component->value(scInheritVersion), component->isCheckable(), component->isExpandedByDefault()); m_localPackageHub->writeToDisk(); component->setInstalled(); component->markAsPerformedInstallation(); if (showDetailsLog) ProgressCoordinator::instance()->emitDetailTextChanged(tr("Done")); } bool PackageManagerCorePrivate::runningProcessesFound() { //Check if there are processes running in the install QStringList excludeFiles = m_allowedRunningProcesses; excludeFiles.append(maintenanceToolName()); const QString performModeWarning = m_completeUninstall ? QLatin1String("Unable to remove components.") : QLatin1String("Unable to update components."); QStringList runningProcesses = runningInstallerProcesses(excludeFiles); if (!runningProcesses.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << performModeWarning << " Please stop these processes: " << runningProcesses << " and try again."; return true; } return false; } void PackageManagerCorePrivate::setComponentSelection(const QString &id, Qt::CheckState state) { ComponentModel *model = m_core->isUpdater() ? m_core->updaterComponentModel() : m_core->defaultComponentModel(); const QModelIndex &idx = model->indexFromComponentName(id); if (idx.isValid()) model->setData(idx, state, Qt::CheckStateRole); } // -- private void PackageManagerCorePrivate::deleteMaintenanceTool() { #ifdef Q_OS_WIN // Since Windows does not support that the maintenance tool deletes itself we have to go with a rather dirty // hack. What we do is to create a batchfile that will try to remove the maintenance tool once per second. Then // we start that batchfile detached, finished our job and close ourselves. Once that's done the batchfile // will succeed in deleting our uninstall.exe and, if the installation directory was created but us and if // it's empty after the uninstall, deletes the installation-directory. const QString batchfile = QDir::toNativeSeparators(QFileInfo(QDir::tempPath(), QLatin1String("uninstall.vbs")).absoluteFilePath()); QFile f(batchfile); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) throw Error(tr("Cannot prepare uninstall")); QTextStream batch(&f); batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; batch << "file = WScript.Arguments.Item(0)\n"; batch << "folderpath = WScript.Arguments.Item(1)\n"; batch << "Set folder = fso.GetFolder(folderpath)\n"; batch << "on error resume next\n"; batch << "while fso.FileExists(file)\n"; batch << " fso.DeleteFile(file)\n"; batch << " WScript.Sleep(1000)\n"; batch << "wend\n"; // batch << "if folder.SubFolders.Count = 0 and folder.Files.Count = 0 then\n"; batch << " Set folder = Nothing\n"; batch << " fso.DeleteFolder folderpath, true\n"; // batch << "end if\n"; batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; f.close(); QStringList arguments; arguments << QLatin1String("//Nologo") << batchfile; // execute the batchfile arguments << QDir::toNativeSeparators(QFileInfo(installerBinaryPath()).absoluteFilePath()); if (!m_performedOperationsOld.isEmpty()) { const Operation *const op = m_performedOperationsOld.first(); if (op->name() == QLatin1String("Mkdir")) // the target directory name arguments << QDir::toNativeSeparators(QFileInfo(op->arguments().first()).absoluteFilePath()); } if (!QProcessWrapper::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath())) throw Error(tr("Cannot start uninstall")); #else // every other platform has no problem if we just delete ourselves now QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath()); maintenanceTool.remove(); # ifdef Q_OS_MACOS if (QInstaller::isInBundle(installerBinaryPath())) { const QLatin1String cdUp("/../../.."); removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); QFile::remove(QFileInfo(installerBinaryPath() + cdUp).absolutePath() + QLatin1String("/") + configurationFileName()); } else # endif #endif { // finally remove the components.xml, since it still exists now QFile::remove(QFileInfo(installerBinaryPath()).absolutePath() + QLatin1String("/") + configurationFileName()); } } void PackageManagerCorePrivate::registerMaintenanceTool() { #ifdef Q_OS_WIN QSettingsWrapper settings(registerPath(), QSettingsWrapper::NativeFormat); settings.setValue(scDisplayName, m_data.value(QLatin1String("ProductName"))); settings.setValue(QLatin1String("DisplayVersion"), m_data.value(QLatin1String("ProductVersion"))); const QString maintenanceTool = QDir::toNativeSeparators(maintenanceToolName()); settings.setValue(QLatin1String("DisplayIcon"), maintenanceTool); settings.setValue(scPublisher, m_data.value(scPublisher)); settings.setValue(QLatin1String("UrlInfoAbout"), m_data.value(QLatin1String("Url"))); settings.setValue(QLatin1String("Comments"), m_data.value(scTitle)); settings.setValue(QLatin1String("InstallDate"), QDateTime::currentDateTime().toString()); settings.setValue(QLatin1String("InstallLocation"), QDir::toNativeSeparators(targetDir())); settings.setValue(QLatin1String("UninstallString"), maintenanceTool); settings.setValue(QLatin1String("ModifyPath"), QString(maintenanceTool + QLatin1String(" --manage-packages"))); // required disk space of the installed components quint64 estimatedSizeKB = m_core->requiredDiskSpace() / 1024; // add required space for the maintenance tool estimatedSizeKB += QFileInfo(maintenanceTool).size() / 1024; if (m_core->createLocalRepositoryFromBinary()) { // add required space for a local repository quint64 result(0); foreach (QInstaller::Component *component, m_core->components(PackageManagerCore::ComponentType::All)) { result += m_core->size(component, scCompressedSize); } estimatedSizeKB += result / 1024; } // Windows can only handle 32bit REG_DWORD (max. recordable installation size is 4TiB) const quint64 limit = std::numeric_limits::max(); // maximum 32 bit value if (estimatedSizeKB <= limit) settings.setValue(QLatin1String("EstimatedSize"), static_cast(estimatedSizeKB)); const bool supportsModify = m_core->value(scSupportsModify, scTrue) == scTrue; if (supportsModify) settings.setValue(QLatin1String("NoModify"), 0); else settings.setValue(QLatin1String("NoModify"), 1); settings.setValue(QLatin1String("NoRepair"), 1); #endif } void PackageManagerCorePrivate::unregisterMaintenanceTool() { #ifdef Q_OS_WIN QSettingsWrapper settings(registerPath(), QSettingsWrapper::NativeFormat); settings.remove(QString()); #endif } void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOperations, double progressSize, bool adminRightsGained, bool deleteOperation) { try { foreach (Operation *undoOperation, undoOperations) { if (statusCanceledOrFailed()) throw Error(tr("Installation canceled by user")); bool becameAdmin = false; if (!adminRightsGained && undoOperation->value(QLatin1String("admin")).toBool()) becameAdmin = m_core->gainAdminRights(); connectOperationToInstaller(undoOperation, progressSize); qCDebug(QInstaller::lcInstallerInstallLog) << "undo operation=" << undoOperation->name(); bool ignoreError = false; bool ok = performOperationThreaded(undoOperation, PackageManagerCorePrivate::Undo); const QString componentName = undoOperation->value(QLatin1String("component")).toString(); if (!componentName.isEmpty()) { while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) { const QMessageBox::StandardButton button = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationErrorWithIgnore"), tr("Installer Error"), tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()), QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Ignore); if (button == QMessageBox::Retry) ok = performOperationThreaded(undoOperation, Undo); else if (button == QMessageBox::Ignore) ignoreError = true; } Component *component = m_core->componentByName(PackageManagerCore::checkableName(componentName)); if (!component) component = componentsToReplace().value(componentName).second; if (component) { component->setUninstalled(); m_localPackageHub->removePackage(component->name()); } } if (becameAdmin) m_core->dropAdminRights(); if (deleteOperation) delete undoOperation; } } catch (const Error &error) { m_localPackageHub->writeToDisk(); throw Error(error.message()); } catch (...) { m_localPackageHub->writeToDisk(); throw Error(tr("Unknown error")); } m_localPackageHub->writeToDisk(); } PackagesList PackageManagerCorePrivate::remotePackages() { if (m_updates && m_updateFinder) return m_updateFinder->updates(); m_updates = false; delete m_updateFinder; m_updateFinder = new KDUpdater::UpdateFinder; m_updateFinder->setAutoDelete(false); m_updateFinder->setPackageSources(m_packageSources); m_updateFinder->setLocalPackageHub(m_localPackageHub); m_updateFinder->run(); if (m_updateFinder->updates().isEmpty()) { setStatus(PackageManagerCore::Failure, tr("Cannot retrieve remote tree %1.") .arg(m_updateFinder->errorString())); return PackagesList(); } m_updates = true; return m_updateFinder->updates(); } PackagesList PackageManagerCorePrivate::compressedPackages() { if (m_compressedUpdates && m_compressedFinder) return m_compressedFinder->updates(); m_compressedUpdates = false; delete m_compressedFinder; m_compressedFinder = new KDUpdater::UpdateFinder; m_compressedFinder->setAutoDelete(false); m_compressedFinder->addCompressedPackage(true); m_compressedFinder->setPackageSources(m_compressedPackageSources); m_compressedFinder->setLocalPackageHub(m_localPackageHub); m_compressedFinder->run(); if (m_compressedFinder->updates().isEmpty()) { setStatus(PackageManagerCore::Failure, tr("Cannot retrieve remote tree %1.") .arg(m_compressedFinder->errorString())); return PackagesList(); } m_compressedUpdates = true; return m_compressedFinder->updates(); } /*! Returns a hash containing the installed package name and it's associated package information. If the application is running in installer mode or the local components file could not be parsed, the hash is empty. */ LocalPackagesHash PackageManagerCorePrivate::localInstalledPackages() { if (isInstaller()) return LocalPackagesHash(); LocalPackagesHash installedPackages; if (m_localPackageHub->error() != LocalPackageHub::NoError) { if (m_localPackageHub->fileName().isEmpty()) m_localPackageHub->setFileName(componentsXmlPath()); else m_localPackageHub->refresh(); if (m_localPackageHub->applicationName().isEmpty()) m_localPackageHub->setApplicationName(m_data.settings().applicationName()); if (m_localPackageHub->applicationVersion().isEmpty()) m_localPackageHub->setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); } if (m_localPackageHub->error() != LocalPackageHub::NoError) { setStatus(PackageManagerCore::Failure, tr("Failure to read packages from %1.") .arg(componentsXmlPath())); } foreach (const LocalPackage &package, m_localPackageHub->packageInfos()) { if (statusCanceledOrFailed()) break; installedPackages.insert(package.name, package); } return installedPackages; } bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories(DownloadType type) { m_updates = false; m_repoFetched = false; m_updateSourcesAdded = false; try { m_metadataJob.addDownloadType(type); m_metadataJob.start(); m_metadataJob.waitForFinished(); } catch (Error &error) { setStatus(PackageManagerCore::Failure, tr("Cannot retrieve meta information: %1") .arg(error.message())); return m_repoFetched; } if (m_metadataJob.error() != Job::NoError) { switch (m_metadataJob.error()) { case QInstaller::UserIgnoreError: break; // we can simply ignore this error, the user knows about it default: setStatus(PackageManagerCore::Failure, m_metadataJob.errorString()); return m_repoFetched; } } m_repoFetched = true; return m_repoFetched; } bool PackageManagerCorePrivate::fetchMetaInformationFromCompressedRepositories() { bool compressedRepoFetched = false; m_compressedUpdates = false; m_updateSourcesAdded = false; try { //Tell MetadataJob that only compressed packages needed to be fetched and not all. //We cannot do this in general fetch meta method as the compressed packages might be //installed after components tree is generated m_metadataJob.addDownloadType(DownloadType::CompressedPackage); m_metadataJob.start(); m_metadataJob.waitForFinished(); } catch (Error &error) { setStatus(PackageManagerCore::Failure, tr("Cannot retrieve meta information: %1") .arg(error.message())); return compressedRepoFetched; } if (m_metadataJob.error() != Job::NoError) { switch (m_metadataJob.error()) { case QInstaller::UserIgnoreError: break; // we can simply ignore this error, the user knows about it default: //Do not change core status here, we can recover if there is invalid //compressed repository setStatus(m_core->status(), m_metadataJob.errorString()); return compressedRepoFetched; } } compressedRepoFetched = true; return compressedRepoFetched; } bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository) { if (!compressedRepository && m_updateSourcesAdded) return m_updateSourcesAdded; const QList metadata = m_metadataJob.metadata(); if (metadata.isEmpty()) { m_updateSourcesAdded = true; return m_updateSourcesAdded; } if (compressedRepository) { m_compressedPackageSources.clear(); } else { m_packageSources.clear(); m_updates = false; m_updateSourcesAdded = false; if (isInstaller()) m_packageSources.insert(PackageSource(QUrl(QLatin1String("resource://metadata/")), 0)); } foreach (const Metadata &data, metadata) { if (compressedRepository && !data.repository.isCompressed()) { continue; } if (statusCanceledOrFailed()) return false; if (data.directory.isEmpty()) continue; if (parseChecksum) { const QString updatesXmlPath = data.directory + QLatin1String("/Updates.xml"); QFile updatesFile(updatesXmlPath); try { QInstaller::openForRead(&updatesFile); } catch(const Error &e) { qCWarning(QInstaller::lcInstallerInstallLog) << "Error opening Updates.xml:" << e.message(); setStatus(PackageManagerCore::Failure, tr("Cannot add temporary update source information.")); return false; } int line = 0; int column = 0; QString error; QDomDocument doc; if (!doc.setContent(&updatesFile, &error, &line, &column)) { qCWarning(QInstaller::lcInstallerInstallLog).nospace() << "Parse error in file " << updatesFile.fileName() << ": " << error << " at line " << line << " col " << column; setStatus(PackageManagerCore::Failure, tr("Cannot add temporary update source information.")); return false; } const QDomNode checksum = doc.documentElement().firstChildElement(QLatin1String("Checksum")); if (!checksum.isNull()) m_core->setTestChecksum(checksum.toElement().text().toLower() == scTrue); } if (compressedRepository) m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1)); else m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1)); ProductKeyCheck::instance()->addPackagesFromXml(data.directory + QLatin1String("/Updates.xml")); } if ((compressedRepository && m_compressedPackageSources.count() == 0 ) || (!compressedRepository && m_packageSources.count() == 0)) { setStatus(PackageManagerCore::Failure, tr("Cannot find any update source information.")); return false; } m_updateSourcesAdded = true; return m_updateSourcesAdded; } void PackageManagerCorePrivate::restoreCheckState() { if (m_coreCheckedHash.isEmpty()) return; foreach (Component *component, m_coreCheckedHash.keys()) { component->setCheckState(m_coreCheckedHash.value(component)); // Never allow component to be checked when it is unstable // and not installed if (component->isUnstable() && !component->isInstalled()) component->setCheckState(Qt::Unchecked); } m_coreCheckedHash.clear(); m_componentsToInstallCalculated = false; } void PackageManagerCorePrivate::storeCheckState() { m_coreCheckedHash.clear(); const QList components = m_core->components(PackageManagerCore::ComponentType::AllNoReplacements); foreach (Component *component, components) m_coreCheckedHash.insert(component, component->checkState()); } void PackageManagerCorePrivate::connectOperationCallMethodRequest(Operation *const operation) { QObject *const operationObject = dynamic_cast (operation); if (operationObject != nullptr) { const QMetaObject *const mo = operationObject->metaObject(); if (mo->indexOfSignal(QMetaObject::normalizedSignature("requestBlockingExecution(QString)")) > -1) { connect(operationObject, SIGNAL(requestBlockingExecution(QString)), this, SLOT(handleMethodInvocationRequest(QString)), Qt::BlockingQueuedConnection); } } } OperationList PackageManagerCorePrivate::sortOperationsBasedOnComponentDependencies(const OperationList &operationList) { OperationList sortedOperations; QHash componentOperationHash; // sort component unrelated operations to the beginning foreach (Operation *operation, operationList) { const QString componentName = operation->value(QLatin1String("component")).toString(); if (componentName.isEmpty()) sortedOperations.append(operation); else componentOperationHash[componentName].append(operation); } Graph componentGraph; // create the complete component graph foreach (const Component* node, m_core->components(PackageManagerCore::ComponentType::All)) { componentGraph.addNode(node->name()); componentGraph.addEdges(node->name(), m_core->parseNames(node->dependencies())); } const QStringList resolvedComponents = componentGraph.sort(); if (componentGraph.hasCycle()) { throw Error(tr("Dependency cycle between components \"%1\" and \"%2\" detected.") .arg(componentGraph.cycle().first, componentGraph.cycle().second)); } foreach (const QString &componentName, resolvedComponents) sortedOperations.append(componentOperationHash.value(componentName)); return sortedOperations; } void PackageManagerCorePrivate::handleMethodInvocationRequest(const QString &invokableMethodName) { QObject *obj = QObject::sender(); if (obj != nullptr) QMetaObject::invokeMethod(obj, qPrintable(invokableMethodName)); } void PackageManagerCorePrivate::processFilesForDelayedDeletion() { if (m_filesForDelayedDeletion.isEmpty()) return; const QStringList filesForDelayedDeletion = std::move(m_filesForDelayedDeletion); foreach (const QString &i, filesForDelayedDeletion) { QFile file(i); //TODO: this should happen asnyc and report errors, I guess if (file.exists() && !file.remove()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot delete file " << qPrintable(i) << ": " << qPrintable(file.errorString()); m_filesForDelayedDeletion << i; // try again next time } } } void PackageManagerCorePrivate::findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result) { QDirIterator it(path, QDir::NoDotAndDotDot | QDir::Executable | QDir::Files | QDir::System, QDirIterator::Subdirectories ); while (it.hasNext()) result->append(QDir::toNativeSeparators(it.next().toLower())); foreach (const QString &process, excludeFiles) result->removeAll(QDir::toNativeSeparators(process.toLower())); } QStringList PackageManagerCorePrivate::runningInstallerProcesses(const QStringList &excludeFiles) { QStringList resultFiles; findExecutablesRecursive(QCoreApplication::applicationDirPath(), excludeFiles, &resultFiles); return checkRunningProcessesFromList(resultFiles); } bool PackageManagerCorePrivate::calculateComponentsAndRun() { QString htmlOutput; bool componentsOk = m_core->calculateComponents(&htmlOutput); if (statusCanceledOrFailed()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Installation canceled."; } else if (componentsOk && acceptLicenseAgreements()) { qCDebug(QInstaller::lcInstallerInstallLog).noquote() << htmlToString(htmlOutput); if (!(m_autoConfirmCommand || askUserConfirmCommand())) { qCDebug(QInstaller::lcInstallerInstallLog) << "Installation aborted."; } else if (m_core->run()) { // Write maintenance tool if required m_core->writeMaintenanceTool(); return true; } } return false; } bool PackageManagerCorePrivate::acceptLicenseAgreements() const { // Always skip for uninstaller if (isUninstaller()) return true; typedef QHash > LicensesHash; foreach (Component *component, m_core->orderedComponentsToInstall()) { // Package manager or updater, no need to accept again as long as // the component is installed. if (m_core->isMaintainer() && component->isInstalled()) continue; LicensesHash hash = component->licenses(); for (LicensesHash::iterator it = hash.begin(); it != hash.end(); ++it) { if (m_autoAcceptLicenses || askUserAcceptLicense(it.key(), it.value().second)) { qCDebug(QInstaller::lcInstallerInstallLog) << "License" << it.key() << "accepted by user."; } else { qCDebug(QInstaller::lcInstallerInstallLog) << "License" << it.key() << "not accepted by user. Aborting."; return false; } } } return true; } bool PackageManagerCorePrivate::askUserAcceptLicense(const QString &name, const QString &content) const { qCDebug(QInstaller::lcInstallerInstallLog) << "You must accept " "the terms contained in the following license agreement " "before continuing with the installation:" << name; forever { const QString input = m_core->readConsoleLine(QLatin1String("Accept|Reject|Show")); if (QString::compare(input, QLatin1String("Accept"), Qt::CaseInsensitive) == 0 || QString::compare(input, QLatin1String("A"), Qt::CaseInsensitive) == 0) { return true; } else if (QString::compare(input, QLatin1String("Reject"), Qt::CaseInsensitive) == 0 || QString::compare(input, QLatin1String("R"), Qt::CaseInsensitive) == 0) { return false; } else if (QString::compare(input, QLatin1String("Show"), Qt::CaseInsensitive) == 0 || QString::compare(input, QLatin1String("S"), Qt::CaseInsensitive) == 0) { qCDebug(QInstaller::lcInstallerInstallLog).noquote() << content; } else { qCDebug(QInstaller::lcInstallerInstallLog) << "Unknown answer:" << input; } } } void PackageManagerCorePrivate::printPackageInformation(const QString &name, const Package *update) { qCDebug(QInstaller::lcPackageName).noquote() << "Id:" << name; qCDebug(QInstaller::lcPackageDisplayname).noquote() << "\tDisplay name:" << update->data(scDisplayName).toString(); qCDebug(QInstaller::lcPackageVersion).noquote() << "\tVersion:" << update->data(scVersion).toString(); qCDebug(QInstaller::lcPackageDescription).noquote() << "\tDescription:" << update->data(scDescription).toString(); qCDebug(QInstaller::lcPackageReleasedate).noquote() << "\tRelease date:" << update->data(scReleaseDate).toString(); qCDebug(QInstaller::lcPackageDependencies).noquote() << "\tDependencies:" << update->data(scDependencies).toString(); qCDebug(QInstaller::lcPackageAutodependon).noquote() << "\tAutodependon:" << update->data(scAutoDependOn).toString(); qCDebug(QInstaller::lcPackageVirtual).noquote() << "\tVirtual:" << update->data(scVirtual, false).toString(); qCDebug(QInstaller::lcPackageSortingpriority).noquote() << "\tSorting priority:" << update->data(scSortingPriority).toString(); qCDebug(QInstaller::lcPackageScript).noquote() << "\tScript:" << update->data(scScript).toString(); qCDebug(QInstaller::lcPackageDefault).noquote() << "\tDefault:"<< update->data(scDefault, false).toString(); qCDebug(QInstaller::lcPackageEssential).noquote() << "\tEssential:" << update->data(scEssential, false).toString(); qCDebug(QInstaller::lcPackageForcedinstallation).noquote() << "\tForced installation:" << update->data(QLatin1String("ForcedInstallation"), false).toString(); qCDebug(QInstaller::lcPackageReplaces).noquote() << "\tReplaces:" << update->data(scReplaces).toString(); qCDebug(QInstaller::lcPackageDownloadableArchives).noquote() << "\tDownloadable archives:" << update->data(scDownloadableArchives).toString(); qCDebug(QInstaller::lcPackageRequiresAdminRights).noquote() << "\tRequires admin rights:" << update->data(scRequiresAdminRights).toString(); qCDebug(QInstaller::lcPackageCheckable).noquote() << "\tCheckable:" << update->data(scCheckable).toString(); qCDebug(QInstaller::lcPackageLicenses).noquote() << "\tLicenses:" << update->data(QLatin1String("Licenses")).toString(); qCDebug(QInstaller::lcPackageCompressedSize).noquote() << "\tCompressed size:" << update->data(QLatin1String("CompressedSize")).toString(); qCDebug(QInstaller::lcPackageUncompressedSize).noquote() << "\tUncompressed size:" << update->data(QLatin1String("UncompressedSize")).toString(); //Check if package already installed LocalPackagesHash installedPackages = this->localInstalledPackages(); if (installedPackages.contains(name)) qCDebug(QInstaller::lcPackageInstalledVersion).noquote() << "\tInstalled version:" << installedPackages.value(name).version; } void PackageManagerCorePrivate::printLocalPackageInformation(const KDUpdater::LocalPackage package) const { qCDebug(QInstaller::lcPackageName).noquote() << "Id:" << package.name; qCDebug(QInstaller::lcPackageDisplayname).noquote() << "\tDisplay name:" << package.title; qCDebug(QInstaller::lcPackageVersion).noquote() << "\tVersion:" << package.version; qCDebug(QInstaller::lcPackageDescription).noquote() << "\tDescription:" << package.description; qCDebug(QInstaller::lcPackageDependencies).noquote() << "\tDependencies:" << package.dependencies; qCDebug(QInstaller::lcPackageAutodependon).noquote() << "\tAutodependon:" << package.autoDependencies; qCDebug(QInstaller::lcPackageVirtual).noquote() << "\tVirtual:" << package.virtualComp; qCDebug(QInstaller::lcPackageForcedinstallation).noquote() << "\tForced installation:" << package.forcedInstallation; qCDebug(QInstaller::lcPackageCheckable).noquote() << "\tCheckable:" << package.checkable; qCDebug(QInstaller::lcPackageUncompressedSize).noquote() << "\tUncompressed size:" << package.uncompressedSize; qCDebug(QInstaller::lcPackageInstallDate).noquote() << "\tInstalled:" << package.installDate; qCDebug(QInstaller::lcPackageUpdateDate).noquote() << "\tLast updated:" << package.lastUpdateDate; } bool PackageManagerCorePrivate::askUserConfirmCommand() const { qCDebug(QInstaller::lcInstallerInstallLog) << "Do you want to continue?"; forever { const QString input = m_core->readConsoleLine(QLatin1String("Yes|No")); if (QString::compare(input, QLatin1String("Yes"), Qt::CaseInsensitive) == 0 || QString::compare(input, QLatin1String("Y"), Qt::CaseInsensitive) == 0) { return true; } else if (QString::compare(input, QLatin1String("No"), Qt::CaseInsensitive) == 0 || QString::compare(input, QLatin1String("N"), Qt::CaseInsensitive) == 0) { return false; } else { qCDebug(QInstaller::lcInstallerInstallLog) << "Unknown answer:" << input; } } } } // namespace QInstaller qt-installer-framework-4.0.1/src/libs/installer/packagemanagercore_p.h0100777000000000000000000002375313761647206023116 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGERCORE_P_H #define PACKAGEMANAGERCORE_P_H #include "metadatajob.h" #include "packagemanagercore.h" #include "packagemanagercoredata.h" #include "packagemanagerproxyfactory.h" #include "packagesource.h" #include "qinstallerglobal.h" #include "sysinfo.h" #include "updatefinder.h" #include class Job; QT_FORWARD_DECLARE_CLASS(QFile) QT_FORWARD_DECLARE_CLASS(QFileDevice) QT_FORWARD_DECLARE_CLASS(QFileInfo) using namespace KDUpdater; namespace QInstaller { struct BinaryLayout; class Component; class ScriptEngine; class ComponentModel; class TempDirDeleter; class InstallerCalculator; class UninstallerCalculator; class RemoteFileEngineHandler; class PackageManagerCorePrivate : public QObject { Q_OBJECT friend class PackageManagerCore; Q_DISABLE_COPY(PackageManagerCorePrivate) public: enum OperationType { Backup, Perform, Undo }; explicit PackageManagerCorePrivate(PackageManagerCore *core); explicit PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker, const QList &performedOperations); ~PackageManagerCorePrivate(); static bool isProcessRunning(const QString &name, const QList &processes); static bool performOperationThreaded(Operation *op, PackageManagerCorePrivate::OperationType type = PackageManagerCorePrivate::Perform); void initialize(const QHash ¶ms); bool isOfflineOnly() const; bool statusCanceledOrFailed() const; void setStatus(int status, const QString &error = QString()); QString targetDir() const; QString registerPath(); bool directoryWritable(const QString &path) const; QString maintenanceToolName() const; QString installerBinaryPath() const; void writeMaintenanceConfigFiles(); void readMaintenanceConfigFiles(const QString &targetDir); void writeMaintenanceTool(OperationList performedOperations); QString componentsXmlPath() const; QString configurationFileName() const; bool buildComponentTree(QHash &components, bool loadScript); void cleanUpComponentEnvironment(); ScriptEngine *componentScriptEngine() const; ScriptEngine *controlScriptEngine() const; void clearAllComponentLists(); void clearUpdaterComponentLists(); QList &replacementDependencyComponents(); QHash > &componentsToReplace(); void clearInstallerCalculator(); InstallerCalculator *installerCalculator() const; void clearUninstallerCalculator(); UninstallerCalculator *uninstallerCalculator() const; bool runInstaller(); bool isInstaller() const; bool runUninstaller(); bool isUninstaller() const; bool isUpdater() const; bool runPackageUpdater(); bool isPackageManager() const; QString replaceVariables(const QString &str) const; QByteArray replaceVariables(const QByteArray &str) const; void callBeginInstallation(const QList &componentList); void stopProcessesForUpdates(const QList &components); int countProgressOperations(const QList &components); int countProgressOperations(const OperationList &operations); void connectOperationToInstaller(Operation *const operation, double progressOperationPartSize); void connectOperationCallMethodRequest(Operation *const operation); OperationList sortOperationsBasedOnComponentDependencies(const OperationList &operationList); Operation *createOwnedOperation(const QString &type); Operation *takeOwnedOperation(Operation *operation); Operation *createPathOperation(const QFileInfo &fileInfo, const QString &componentName); void registerPathsForUninstallation(const QList > &pathsForUninstallation, const QString &componentName); void addPerformed(Operation *op) { m_performedOperationsCurrentSession.append(op); } void commitSessionOperations() { m_performedOperationsOld += m_performedOperationsCurrentSession; m_performedOperationsCurrentSession.clear(); } void installComponent(Component *component, double progressOperationSize, bool adminRightsGained = false); bool runningProcessesFound(); void setComponentSelection(const QString &id, Qt::CheckState state); signals: void installationStarted(); void installationFinished(); void uninstallationStarted(); void uninstallationFinished(); public: UpdateFinder *m_updateFinder; UpdateFinder *m_compressedFinder; QSet m_packageSources; QSet m_compressedPackageSources; std::shared_ptr m_localPackageHub; QStringList m_filesForDelayedDeletion; int m_status; QString m_error; bool m_needsHardRestart; bool m_testChecksum; bool m_launchedAsRoot; bool m_commandLineInstance; bool m_defaultInstall; bool m_userSetBinaryMarker; bool m_checkAvailableSpace; bool m_completeUninstall; bool m_needToWriteMaintenanceTool; PackageManagerCoreData m_data; QString m_installerBaseBinaryUnreplaced; QList m_rootComponents; QList m_rootDependencyReplacements; QList m_updaterComponents; QList m_updaterComponentsDeps; QList m_updaterDependencyReplacements; OperationList m_ownedOperations; OperationList m_performedOperationsOld; OperationList m_performedOperationsCurrentSession; bool m_dependsOnLocalInstallerBinary; QStringList m_allowedRunningProcesses; bool m_autoAcceptLicenses; bool m_disableWriteMaintenanceTool; bool m_autoConfirmCommand; private slots: void infoMessage(Job *, const QString &message) { emit m_core->metaJobInfoMessage(message); } void infoProgress(Job *, quint64 progress, quint64) { emit m_core->metaJobProgress(progress); } void totalProgress(quint64 total) { emit m_core->metaJobTotalProgress(total); } void handleMethodInvocationRequest(const QString &invokableMethodName); private: void deleteMaintenanceTool(); void registerMaintenanceTool(); void unregisterMaintenanceTool(); void writeMaintenanceToolBinary(QFile *const input, qint64 size, bool writeBinaryLayout); void writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input, const OperationList &performed, const BinaryLayout &layout); void runUndoOperations(const OperationList &undoOperations, double undoOperationProgressSize, bool adminRightsGained, bool deleteOperation); PackagesList remotePackages(); PackagesList compressedPackages(); LocalPackagesHash localInstalledPackages(); bool fetchMetaInformationFromRepositories(DownloadType type = DownloadType::All); bool fetchMetaInformationFromCompressedRepositories(); bool addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository = false); void processFilesForDelayedDeletion(); void findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result); QStringList runningInstallerProcesses(const QStringList &exludeFiles); bool calculateComponentsAndRun(); bool acceptLicenseAgreements() const; bool askUserAcceptLicense(const QString &name, const QString &content) const; bool askUserConfirmCommand() const; void printPackageInformation(const QString &name, const Package *update); void printLocalPackageInformation(const KDUpdater::LocalPackage package) const; private: PackageManagerCore *m_core; MetadataJob m_metadataJob; bool m_updates; bool m_compressedUpdates; bool m_repoFetched; bool m_updateSourcesAdded; qint64 m_magicBinaryMarker; bool m_componentsToInstallCalculated; bool m_foundEssentialUpdate; mutable ScriptEngine *m_componentScriptEngine; mutable ScriptEngine *m_controlScriptEngine; // < name (component to replace), < replacement component, component to replace > > QHash > m_componentsToReplaceAllMode; QHash > m_componentsToReplaceUpdaterMode; InstallerCalculator *m_installerCalculator; UninstallerCalculator *m_uninstallerCalculator; PackageManagerProxyFactory *m_proxyFactory; ComponentModel *m_defaultModel; ComponentModel *m_updaterModel; QObject *m_guiObject; QScopedPointer m_remoteFileEngineHandler; private: // remove once we deprecate isSelected, setSelected etc... void restoreCheckState(); void storeCheckState(); QHash m_coreCheckedHash; }; } // namespace QInstaller #endif // PACKAGEMANAGERCORE_P_H qt-installer-framework-4.0.1/src/libs/installer/packagemanagergui.cpp0100777000000000000000000030414413761647206022762 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "packagemanagergui.h" #include "component.h" #include "componentmodel.h" #include "errors.h" #include "fileutils.h" #include "messageboxhandler.h" #include "packagemanagercore.h" #include "progresscoordinator.h" #include "performinstallationform.h" #include "settings.h" #include "utils.h" #include "scriptengine.h" #include "productkeycheck.h" #include "repositorycategory.h" #include "componentselectionpage_p.h" #include "sysinfo.h" #include "globals.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN # include # include # include #endif using namespace KDUpdater; using namespace QInstaller; class DynamicInstallerPage : public PackageManagerPage { Q_OBJECT Q_DISABLE_COPY(DynamicInstallerPage) Q_PROPERTY(bool final READ isFinal WRITE setFinal) Q_PROPERTY(bool commit READ isCommit WRITE setCommit) Q_PROPERTY(bool complete READ isComplete WRITE setComplete) public: explicit DynamicInstallerPage(QWidget *widget, PackageManagerCore *core = nullptr) : PackageManagerPage(core) , m_widget(widget) { setObjectName(QLatin1String("Dynamic") + widget->objectName()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); setColoredSubTitle(QLatin1String(" ")); setColoredTitle(widget->windowTitle()); m_widget->setProperty("complete", true); m_widget->setProperty("final", false); m_widget->setProperty("commit", false); widget->installEventFilter(this); setLayout(new QVBoxLayout); layout()->addWidget(widget); layout()->setContentsMargins(0, 0, 0, 0); addPageAndProperties(packageManagerCore()->controlScriptEngine()); addPageAndProperties(packageManagerCore()->componentScriptEngine()); } QWidget *widget() const { return m_widget; } bool isComplete() const { return m_widget->property("complete").toBool(); } void setFinal(bool final) { if (isFinal() == final) return; m_widget->setProperty("final", final); } bool isFinal() const { return m_widget->property("final").toBool(); } void setCommit(bool commit) { if (isCommit() == commit) return; m_widget->setProperty("commit", commit); } bool isCommit() const { return m_widget->property("commit").toBool(); } void setComplete(bool complete) { if (isComplete() == complete) return; m_widget->setProperty("complete", complete); } protected: bool eventFilter(QObject *obj, QEvent *event) { if (obj == m_widget) { switch(event->type()) { case QEvent::WindowTitleChange: setColoredTitle(m_widget->windowTitle()); break; case QEvent::DynamicPropertyChange: emit completeChanged(); if (m_widget->property("final").toBool() != isFinalPage()) setFinalPage(m_widget->property("final").toBool()); if (m_widget->property("commit").toBool() != isCommitPage()) setCommitPage(m_widget->property("commit").toBool()); break; default: break; } } return PackageManagerPage::eventFilter(obj, event); } void addPageAndProperties(ScriptEngine *engine) { engine->addToGlobalObject(this); engine->addToGlobalObject(widget()); static const QStringList properties = QStringList() << QStringLiteral("final") << QStringLiteral("commit") << QStringLiteral("complete"); foreach (const QString &property, properties) { engine->evaluate(QString::fromLatin1( "Object.defineProperty(%1, \"%2\", {" "get : function() { return Dynamic%1.%2; }," "set: function(val) { Dynamic%1.%2 = val; }" "});" ).arg(m_widget->objectName(), property)); } } private: QWidget *const m_widget; }; Q_DECLARE_METATYPE(DynamicInstallerPage*) // -- PackageManagerGui::Private class PackageManagerGui::Private { public: Private() : m_currentId(-1) , m_modified(false) , m_autoSwitchPage(true) , m_showSettingsButton(false) , m_silent(false) { m_wizardButtonTypes.insert(QWizard::BackButton, QLatin1String("QWizard::BackButton")); m_wizardButtonTypes.insert(QWizard::NextButton, QLatin1String("QWizard::NextButton")); m_wizardButtonTypes.insert(QWizard::CommitButton, QLatin1String("QWizard::CommitButton")); m_wizardButtonTypes.insert(QWizard::FinishButton, QLatin1String("QWizard::FinishButton")); m_wizardButtonTypes.insert(QWizard::CancelButton, QLatin1String("QWizard::CancelButton")); m_wizardButtonTypes.insert(QWizard::HelpButton, QLatin1String("QWizard::HelpButton")); m_wizardButtonTypes.insert(QWizard::CustomButton1, QLatin1String("QWizard::CustomButton1")); m_wizardButtonTypes.insert(QWizard::CustomButton2, QLatin1String("QWizard::CustomButton2")); m_wizardButtonTypes.insert(QWizard::CustomButton3, QLatin1String("QWizard::CustomButton3")); m_wizardButtonTypes.insert(QWizard::Stretch, QLatin1String("QWizard::Stretch")); } QString buttonType(int wizardButton) { return m_wizardButtonTypes.value(static_cast(wizardButton), QLatin1String("unknown button")); } int m_currentId; bool m_modified; bool m_autoSwitchPage; bool m_showSettingsButton; bool m_silent; QHash m_defaultPages; QHash m_defaultButtonText; QJSValue m_controlScriptContext; QHash m_wizardButtonTypes; }; // -- PackageManagerGui /*! \class QInstaller::PackageManagerGui \inmodule QtInstallerFramework \brief The PackageManagerGui class provides the core functionality for non-interactive installations. */ /*! \fn void QInstaller::PackageManagerGui::interrupted() \sa {gui::interrupted}{gui.interrupted} */ /*! \fn void QInstaller::PackageManagerGui::languageChanged() \sa {gui::languageChanged}{gui.languageChanged} */ /*! \fn void QInstaller::PackageManagerGui::finishButtonClicked() \sa {gui::finishButtonClicked}{gui.finishButtonClicked} */ /*! \fn void QInstaller::PackageManagerGui::gotRestarted() \sa {gui::gotRestarted}{gui.gotRestarted} */ /*! \fn void QInstaller::PackageManagerGui::settingsButtonClicked() \sa {gui::settingsButtonClicked}{gui.settingsButtonClicked} */ /*! \fn void QInstaller::PackageManagerGui::packageManagerCore() const Returns the package manager core. */ /*! Constructs a package manager UI with package manager specified by \a core and \a parent as parent. */ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) : QWizard(parent) , d(new Private) , m_core(core) { if (m_core->isInstaller()) setWindowTitle(tr("%1 Setup").arg(m_core->value(scTitle))); else setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle))); setWindowFlags(windowFlags() &~ Qt::WindowContextHelpButtonHint); #ifndef Q_OS_MACOS setWindowIcon(QIcon(m_core->settings().installerWindowIcon())); #endif if (!m_core->settings().wizardShowPageList()) setPixmap(QWizard::BackgroundPixmap, m_core->settings().background()); #ifdef Q_OS_LINUX setWizardStyle(QWizard::ModernStyle); setSizeGripEnabled(true); #endif if (!m_core->settings().wizardStyle().isEmpty()) setWizardStyle(getStyle(m_core->settings().wizardStyle())); // set custom stylesheet const QString styleSheetFile = m_core->settings().styleSheet(); if (!styleSheetFile.isEmpty()) { QFile sheet(styleSheetFile); if (sheet.exists()) { if (sheet.open(QIODevice::ReadOnly)) { setStyleSheet(QString::fromLatin1(sheet.readAll())); } else { qCWarning(QInstaller::lcDeveloperBuild) << "The specified style sheet file " "can not be opened."; } } else { qCWarning(QInstaller::lcDeveloperBuild) << "A style sheet file is specified, " "but it does not exist."; } } setOption(QWizard::NoBackButtonOnStartPage); setOption(QWizard::NoBackButtonOnLastPage); if (m_core->settings().wizardShowPageList()) { QWidget *sideWidget = new QWidget(this); sideWidget->setObjectName(QLatin1String("SideWidget")); m_pageListWidget = new QListWidget(sideWidget); m_pageListWidget->setObjectName(QLatin1String("PageListWidget")); m_pageListWidget->viewport()->setAutoFillBackground(false); m_pageListWidget->setFrameShape(QFrame::NoFrame); m_pageListWidget->setMinimumWidth(200); // The widget should be view-only but we do not want it to be grayed out, // so instead of calling setEnabled(false), do not accept focus. m_pageListWidget->setFocusPolicy(Qt::NoFocus); m_pageListWidget->setSelectionMode(QAbstractItemView::NoSelection); m_pageListWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); QVBoxLayout *sideWidgetLayout = new QVBoxLayout(sideWidget); const QString pageListPixmap = m_core->settings().pageListPixmap(); if (!pageListPixmap.isEmpty()) { QLabel *pageListPixmapLabel = new QLabel(sideWidget); pageListPixmapLabel->setObjectName(QLatin1String("PageListPixmapLabel")); pageListPixmapLabel->setPixmap(pageListPixmap); pageListPixmapLabel->setMinimumWidth(QPixmap(pageListPixmap).width()); sideWidgetLayout->addWidget(pageListPixmapLabel); } sideWidgetLayout->addWidget(m_pageListWidget); sideWidget->setLayout(sideWidgetLayout); setSideWidget(sideWidget); } connect(this, &QDialog::rejected, m_core, &PackageManagerCore::setCanceled); connect(this, &PackageManagerGui::interrupted, m_core, &PackageManagerCore::interrupt); // both queued to show the finished page once everything is done connect(m_core, &PackageManagerCore::installationFinished, this, &PackageManagerGui::showFinishedPage, Qt::QueuedConnection); connect(m_core, &PackageManagerCore::uninstallationFinished, this, &PackageManagerGui::showFinishedPage, Qt::QueuedConnection); connect(this, &QWizard::currentIdChanged, this, &PackageManagerGui::currentPageChanged); connect(this, &QWizard::currentIdChanged, m_core, &PackageManagerCore::currentPageChanged); connect(button(QWizard::FinishButton), &QAbstractButton::clicked, this, &PackageManagerGui::finishButtonClicked); connect(button(QWizard::FinishButton), &QAbstractButton::clicked, m_core, &PackageManagerCore::finishButtonClicked); // make sure the QUiLoader's retranslateUi is executed first, then the script connect(this, &PackageManagerGui::languageChanged, m_core, &PackageManagerCore::languageChanged, Qt::QueuedConnection); connect(this, &PackageManagerGui::languageChanged, this, &PackageManagerGui::onLanguageChanged, Qt::QueuedConnection); connect(m_core, &PackageManagerCore::wizardPageInsertionRequested, this, &PackageManagerGui::wizardPageInsertionRequested); connect(m_core, &PackageManagerCore::wizardPageRemovalRequested, this, &PackageManagerGui::wizardPageRemovalRequested); connect(m_core, &PackageManagerCore::wizardWidgetInsertionRequested, this, &PackageManagerGui::wizardWidgetInsertionRequested); connect(m_core, &PackageManagerCore::wizardWidgetRemovalRequested, this, &PackageManagerGui::wizardWidgetRemovalRequested); connect(m_core, &PackageManagerCore::wizardPageVisibilityChangeRequested, this, &PackageManagerGui::wizardPageVisibilityChangeRequested, Qt::QueuedConnection); connect(m_core, &PackageManagerCore::setValidatorForCustomPageRequested, this, &PackageManagerGui::setValidatorForCustomPageRequested); connect(m_core, &PackageManagerCore::setAutomatedPageSwitchEnabled, this, &PackageManagerGui::setAutomatedPageSwitchEnabled); connect(this, &QWizard::customButtonClicked, this, &PackageManagerGui::customButtonClicked); for (int i = QWizard::BackButton; i < QWizard::CustomButton1; ++i) d->m_defaultButtonText.insert(i, buttonText(QWizard::WizardButton(i))); m_core->setGuiObject(this); // We need to create this ugly hack so that the installer doesn't exceed the maximum size of the // screen. The screen size where the widget lies is not available until the widget is visible. QTimer::singleShot(30, this, SLOT(setMaxSize())); } /*! Limits installer maximum size to screen size. */ void PackageManagerGui::setMaxSize() { setMaximumSize(qApp->desktop()->availableGeometry(this).size()); } /*! Updates the installer page list. */ void PackageManagerGui::updatePageListWidget() { if (!m_core->settings().wizardShowPageList() || !m_pageListWidget) return; static const QRegularExpression regExp1 {QLatin1String("(.)([A-Z][a-z]+)")}; static const QRegularExpression regExp2 {QLatin1String("([a-z0-9])([A-Z])")}; m_pageListWidget->clear(); foreach (int id, pageIds()) { PackageManagerPage *page = qobject_cast(pageById(id)); if (!page->showOnPageList()) continue; // Use page list title if set, otherwise try to use the normal title. If that // is not set either, use the object name with spaces added between words. QString itemText; if (!page->pageListTitle().isEmpty()) { itemText = page->pageListTitle(); } else if (!page->title().isEmpty()) { // Title may contain formatting, return only contained plain text QTextDocument doc; doc.setHtml(page->title()); itemText = doc.toPlainText().trimmed(); } else { // Remove "Page" suffix from object name if exists and add spaces between words itemText = page->objectName(); itemText.remove(QLatin1String("Page"), Qt::CaseInsensitive); itemText.replace(regExp1, QLatin1String("\\1 \\2")); itemText.replace(regExp2, QLatin1String("\\1 \\2")); } QListWidgetItem *item = new QListWidgetItem(itemText, m_pageListWidget); item->setSizeHint(QSize(item->sizeHint().width(), 30)); // Give visual indication about current & non-visited pages if (id == d->m_currentId) { QFont currentItemFont = item->font(); currentItemFont.setBold(true); item->setFont(currentItemFont); // Current item should be always visible on the list m_pageListWidget->scrollToItem(item); } else if (id > d->m_currentId) { item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } } } /*! Destructs a package manager UI. */ PackageManagerGui::~PackageManagerGui() { m_core->setGuiObject(nullptr); delete d; } /*! Returns the style of the package manager UI depending on \a name: \list \li \c Classic - Classic UI style for Windows 7 and earlier. \li \c Modern - Modern UI style for Windows 8. \li \c Mac - UI style for macOS. \li \c Aero - Aero Peek for Windows 7. \endlist */ QWizard::WizardStyle PackageManagerGui::getStyle(const QString &name) { if (name == QLatin1String("Classic")) return QWizard::ClassicStyle; if (name == QLatin1String("Modern")) return QWizard::ModernStyle; if (name == QLatin1String("Mac")) return QWizard::MacStyle; if (name == QLatin1String("Aero")) return QWizard::AeroStyle; return QWizard::ModernStyle; } /*! Hides the GUI when \a silent is \c true. */ void PackageManagerGui::setSilent(bool silent) { d->m_silent = silent; setVisible(!silent); } /*! Returns the current silent state. */ bool PackageManagerGui::isSilent() const { return d->m_silent; } /*! Updates the model of \a object (which must be a QComboBox or QAbstractItemView) such that it contains the given \a items. */ void PackageManagerGui::setTextItems(QObject *object, const QStringList &items) { if (QComboBox *comboBox = qobject_cast(object)) { comboBox->setModel(new QStringListModel(items)); return; } if (QAbstractItemView *view = qobject_cast(object)) { view->setModel(new QStringListModel(items)); return; } qCWarning(QInstaller::lcDeveloperBuild) << "Cannot set text items on object of type" << object->metaObject()->className() << "."; } /*! Enables automatic page switching when \a request is \c true. */ void PackageManagerGui::setAutomatedPageSwitchEnabled(bool request) { d->m_autoSwitchPage = request; } /*! Returns the default text for the button specified by \a wizardButton. \sa {gui::defaultButtonText}{gui.defaultButtonText} */ QString PackageManagerGui::defaultButtonText(int wizardButton) const { return d->m_defaultButtonText.value(wizardButton); } /* Check if we need to "transform" the finish button into a cancel button, caused by the misuse of cancel as the finish button on the FinishedPage. This is only a problem if we run as updater or package manager, as then there will be two button shown on the last page with the cancel button renamed to "Finish". */ static bool swapFinishButton(PackageManagerCore *core, int currentId, int button) { if (button != QWizard::FinishButton) return false; if (currentId != PackageManagerCore::InstallationFinished) return false; if (core->isInstaller() || core->isUninstaller()) return false; return true; } /*! Clicks the button specified by \a wb after the delay specified by \a delay. \sa {gui::clickButton}{gui.clickButton} */ void PackageManagerGui::clickButton(int wb, int delay) { // We need to to swap here, cause scripts expect to call this function with FinishButton on the // finish page. if (swapFinishButton(m_core, currentId(), wb)) wb = QWizard::CancelButton; if (QAbstractButton *b = button(static_cast(wb))) QTimer::singleShot(delay, b, &QAbstractButton::click); else qCWarning(QInstaller::lcDeveloperBuild) << "Button with type: " << d->buttonType(wb) << "not found!"; } /*! Clicks the button specified by \a objectName after the delay specified by \a delay. \sa {gui::clickButton}{gui.clickButton} */ void PackageManagerGui::clickButton(const QString &objectName, int delay) const { QPushButton *button = findChild(objectName); if (button) QTimer::singleShot(delay, button, &QAbstractButton::click); else qCWarning(QInstaller::lcDeveloperBuild) << "Button with objectname: " << objectName << "not found!"; } /*! Returns \c true if the button specified by \a wb is enabled. Returns \c false if a button of the specified type is not found. \sa {gui::isButtonEnabled}{gui.isButtonEnabled} */ bool PackageManagerGui::isButtonEnabled(int wb) { // We need to to swap here, cause scripts expect to call this function with FinishButton on the // finish page. if (swapFinishButton(m_core, currentId(), wb)) wb = QWizard::CancelButton; if (QAbstractButton *b = button(static_cast(wb))) return b->isEnabled(); qCWarning(QInstaller::lcDeveloperBuild) << "Button with type: " << d->buttonType(wb) << "not found!"; return false; } /*! Sets a validator for the custom page specified by \a name and \a callbackName requested by \a component. */ void PackageManagerGui::setValidatorForCustomPageRequested(Component *component, const QString &name, const QString &callbackName) { component->setValidatorCallbackName(callbackName); const QString componentName = QLatin1String("Dynamic") + name; const QList ids = pageIds(); foreach (const int i, ids) { PackageManagerPage *const p = qobject_cast (page(i)); if (p && p->objectName() == componentName) { p->setValidatePageComponent(component); return; } } } /*! Loads the script specified by \a scriptPath to perform the installation non-interactively. Throws QInstaller::Error if the script is not readable or it cannot be parsed. */ void PackageManagerGui::loadControlScript(const QString &scriptPath) { d->m_controlScriptContext = m_core->controlScriptEngine()->loadInContext( QLatin1String("Controller"), scriptPath); qCDebug(QInstaller::lcInstallerInstallLog) << "Loaded control script" << scriptPath; } /*! Calls the control script method specified by \a methodName. */ void PackageManagerGui::callControlScriptMethod(const QString &methodName) { if (d->m_controlScriptContext.isUndefined()) return; try { const QJSValue returnValue = m_core->controlScriptEngine()->callScriptMethod( d->m_controlScriptContext, methodName); if (returnValue.isUndefined()) { qCDebug(QInstaller::lcDeveloperBuild) << "Control script callback" << methodName << "does not exist."; return; } } catch (const QInstaller::Error &e) { qCritical() << qPrintable(e.message()); } } /*! Executes the control script on the page specified by \a pageId. */ void PackageManagerGui::executeControlScript(int pageId) { if (PackageManagerPage *const p = qobject_cast (page(pageId))) callControlScriptMethod(p->objectName() + QLatin1String("Callback")); } /*! Replaces the default button text with translated text when the application language changes. */ void PackageManagerGui::onLanguageChanged() { d->m_defaultButtonText.clear(); for (int i = QWizard::BackButton; i < QWizard::CustomButton1; ++i) d->m_defaultButtonText.insert(i, buttonText(QWizard::WizardButton(i))); } /*! \reimp */ bool PackageManagerGui::event(QEvent *event) { switch(event->type()) { case QEvent::LanguageChange: emit languageChanged(); break; default: break; } return QWizard::event(event); } /*! \reimp */ void PackageManagerGui::showEvent(QShowEvent *event) { if (!event->spontaneous()) { foreach (int id, pageIds()) { const QString subTitle = page(id)->subTitle(); if (subTitle.isEmpty()) { const QWizard::WizardStyle style = wizardStyle(); if ((style == QWizard::ClassicStyle) || (style == QWizard::ModernStyle)) { // otherwise the colors might screw up page(id)->setSubTitle(QLatin1String(" ")); } } } setMinimumSize(size()); if (minimumWidth() < m_core->settings().wizardDefaultWidth()) resize(m_core->settings().wizardDefaultWidth(), height()); if (minimumHeight() < m_core->settings().wizardDefaultHeight()) resize(width(), m_core->settings().wizardDefaultHeight()); } QWizard::showEvent(event); QMetaObject::invokeMethod(this, "dependsOnLocalInstallerBinary", Qt::QueuedConnection); } /*! Requests the insertion of the page specified by \a widget at the position specified by \a page. If that position is already occupied by another page, the value is decremented until an empty slot is found. */ void PackageManagerGui::wizardPageInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page) { // just in case it was already in there... wizardPageRemovalRequested(widget); int pageId = static_cast(page) - 1; while (QWizard::page(pageId) != nullptr) --pageId; // add it setPage(pageId, new DynamicInstallerPage(widget, m_core)); updatePageListWidget(); } /*! Requests the removal of the page specified by \a widget. */ void PackageManagerGui::wizardPageRemovalRequested(QWidget *widget) { foreach (int pageId, pageIds()) { DynamicInstallerPage *const dynamicPage = qobject_cast(page(pageId)); if (dynamicPage == nullptr) continue; if (dynamicPage->widget() != widget) continue; removePage(pageId); d->m_defaultPages.remove(pageId); packageManagerCore()->controlScriptEngine()->removeFromGlobalObject(dynamicPage); packageManagerCore()->componentScriptEngine()->removeFromGlobalObject(dynamicPage); } updatePageListWidget(); } /*! Requests the insertion of \a widget on \a page. Widget with lower \a position number will be inserted on top. */ void PackageManagerGui::wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page, int position) { Q_ASSERT(widget); if (PackageManagerPage *p = qobject_cast(QWizard::page(page))) { p->m_customWidgets.insert(position, widget); if (p->m_customWidgets.count() > 1 ) { //Reorder the custom widgets based on their position QMultiMap::Iterator it = p->m_customWidgets.begin(); while (it != p->m_customWidgets.end()) { p->layout()->removeWidget(it.value()); ++it; } it = p->m_customWidgets.begin(); while (it != p->m_customWidgets.end()) { p->layout()->addWidget(it.value()); ++it; } } else { p->layout()->addWidget(widget); } packageManagerCore()->controlScriptEngine()->addToGlobalObject(p); packageManagerCore()->componentScriptEngine()->addToGlobalObject(p); } } /*! Requests the removal of \a widget from installer pages. */ void PackageManagerGui::wizardWidgetRemovalRequested(QWidget *widget) { Q_ASSERT(widget); const QList pages = pageIds(); foreach (int id, pages) { PackageManagerPage *managerPage = qobject_cast(page(id)); managerPage->removeCustomWidget(widget); } widget->setParent(nullptr); packageManagerCore()->controlScriptEngine()->removeFromGlobalObject(widget); packageManagerCore()->componentScriptEngine()->removeFromGlobalObject(widget); } /*! Requests changing the visibility of the page specified by \a p to \a visible. */ void PackageManagerGui::wizardPageVisibilityChangeRequested(bool visible, int p) { if (visible && page(p) == nullptr) { setPage(p, d->m_defaultPages[p]); } else if (!visible && page(p) != nullptr) { d->m_defaultPages[p] = page(p); removePage(p); } updatePageListWidget(); } /*! Returns the page specified by \a id. \sa {gui::pageById}{gui.pageById} */ QWidget *PackageManagerGui::pageById(int id) const { return page(id); } /*! Returns the page specified by the object name \a name from a UI file. \sa {gui::pageByObjectName}{gui.pageByObjectName} */ QWidget *PackageManagerGui::pageByObjectName(const QString &name) const { const QList ids = pageIds(); foreach (const int i, ids) { PackageManagerPage *const p = qobject_cast (page(i)); if (p && p->objectName() == name) return p; } qCDebug(QInstaller::lcDeveloperBuild) << "No page found for object name" << name; return nullptr; } /*! \sa {gui::currentPageWidget}{gui.currentPageWidget} */ QWidget *PackageManagerGui::currentPageWidget() const { return currentPage(); } /*! For dynamic pages, returns the widget specified by \a name read from the UI file. \sa {gui::pageWidgetByObjectName}{gui.pageWidgetByObjectName} */ QWidget *PackageManagerGui::pageWidgetByObjectName(const QString &name) const { QWidget *const widget = pageByObjectName(name); if (PackageManagerPage *const p = qobject_cast (widget)) { // For dynamic pages, return the contained widget (as read from the UI file), not the // wrapper page if (DynamicInstallerPage *dp = qobject_cast(p)) return dp->widget(); return p; } qCDebug(QInstaller::lcDeveloperBuild) << "No page found for object name" << name; return nullptr; } /*! \sa {gui::cancelButtonClicked}{gui.cancelButtonClicked} */ void PackageManagerGui::cancelButtonClicked() { const int id = currentId(); if (id == PackageManagerCore::Introduction || id == PackageManagerCore::InstallationFinished) { m_core->setNeedsHardRestart(false); QDialog::reject(); return; } QString question; bool interrupt = false; PackageManagerPage *const page = qobject_cast (currentPage()); if (page && page->isInterruptible() && m_core->status() != PackageManagerCore::Canceled && m_core->status() != PackageManagerCore::Failure) { interrupt = true; question = tr("Do you want to cancel the installation process?"); if (m_core->isUninstaller()) question = tr("Do you want to cancel the uninstallation process?"); } else { question = tr("Do you want to quit the installer application?"); if (m_core->isUninstaller()) question = tr("Do you want to quit the uninstaller application?"); if (m_core->isMaintainer()) question = tr("Do you want to quit the maintenance application?"); } const QMessageBox::StandardButton button = MessageBoxHandler::question(MessageBoxHandler::currentBestSuitParent(), QLatin1String("cancelInstallation"), tr("%1 Question").arg(m_core->value(scTitle)), question, QMessageBox::Yes | QMessageBox::No); if (button == QMessageBox::Yes) { if (interrupt) emit interrupted(); else QDialog::reject(); } } /*! \sa {gui::rejectWithoutPrompt}{gui.rejectWithoutPrompt} */ void PackageManagerGui::rejectWithoutPrompt() { QDialog::reject(); } /*! \reimp */ void PackageManagerGui::reject() { cancelButtonClicked(); } /*! \internal */ void PackageManagerGui::setModified(bool value) { d->m_modified = value; } /*! \sa {gui::showFinishedPage}{gui.showFinishedPage} */ void PackageManagerGui::showFinishedPage() { if (d->m_autoSwitchPage) next(); else qobject_cast(button(QWizard::CancelButton))->setEnabled(false); } /*! Shows the \uicontrol Settings button if \a show is \c true. \sa {gui::showSettingsButton}{gui.showSettingsButton} */ void PackageManagerGui::showSettingsButton(bool show) { if (d->m_showSettingsButton == show) return; d->m_showSettingsButton = show; setOption(QWizard::HaveCustomButton1, show); setButtonText(QWizard::CustomButton1, tr("Settings")); updateButtonLayout(); } /*! Forces an update of our own button layout. Needs to be called whenever a button option has been set. */ void PackageManagerGui::updateButtonLayout() { QVector buttons(12, QWizard::NoButton); if (options() & QWizard::HaveHelpButton) buttons[(options() & QWizard::HelpButtonOnRight) ? 11 : 0] = QWizard::HelpButton; buttons[1] = QWizard::Stretch; if (options() & QWizard::HaveCustomButton1) { buttons[1] = QWizard::CustomButton1; buttons[2] = QWizard::Stretch; } if (options() & QWizard::HaveCustomButton2) buttons[3] = QWizard::CustomButton2; if (options() & QWizard::HaveCustomButton3) buttons[4] = QWizard::CustomButton3; if (!(options() & QWizard::NoCancelButton)) buttons[(options() & QWizard::CancelButtonOnLeft) ? 5 : 10] = QWizard::CancelButton; buttons[6] = QWizard::BackButton; buttons[7] = QWizard::NextButton; buttons[8] = QWizard::CommitButton; buttons[9] = QWizard::FinishButton; setOption(QWizard::NoBackButtonOnLastPage, true); setOption(QWizard::NoBackButtonOnStartPage, true); setButtonLayout(buttons.toList()); } /*! Enables the \uicontrol Settings button by setting \a enabled to \c true. \sa {gui::setSettingsButtonEnabled}{gui.setSettingsButtonEnabled} */ void PackageManagerGui::setSettingsButtonEnabled(bool enabled) { if (QAbstractButton *btn = button(QWizard::CustomButton1)) btn->setEnabled(enabled); } /*! Emits the settingsButtonClicked() signal when the custom button specified by \a which is clicked if \a which is the \uicontrol Settings button. */ void PackageManagerGui::customButtonClicked(int which) { if (QWizard::WizardButton(which) == QWizard::CustomButton1 && d->m_showSettingsButton) emit settingsButtonClicked(); } /*! Prevents installation from a network location by determining that a local installer binary must be used. */ void PackageManagerGui::dependsOnLocalInstallerBinary() { if (m_core->settings().dependsOnLocalInstallerBinary() && !m_core->localInstallerBinaryUsed()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Installer_Needs_To_Be_Local_Error"), tr("Error"), tr("It is not possible to install from network location.\n" "Please copy the installer to a local drive"), QMessageBox::Ok); rejectWithoutPrompt(); } } /*! Called when the current page changes to \a newId. Calls the leaving() method for the old page and the entering() method for the new one. Also, executes the control script associated with the new page by calling executeControlScript(). Updates the page list set as QWizard::sideWidget(). Emits the left() and entered() signals. */ void PackageManagerGui::currentPageChanged(int newId) { PackageManagerPage *oldPage = qobject_cast(page(d->m_currentId)); if (oldPage) { oldPage->leaving(); emit oldPage->left(); } d->m_currentId = newId; PackageManagerPage *newPage = qobject_cast(page(d->m_currentId)); if (newPage) { newPage->entering(); emit newPage->entered(); updatePageListWidget(); } executeControlScript(newId); } // -- PackageManagerPage /*! \class QInstaller::PackageManagerPage \inmodule QtInstallerFramework \brief The PackageManagerPage class displays information about the product to install. */ /*! \fn QInstaller::PackageManagerPage::~PackageManagerPage() Destructs a package manager page. */ /*! \fn QInstaller::PackageManagerPage::gui() const Returns the wizard this page belongs to. */ /*! \fn QInstaller::PackageManagerPage::isInterruptible() const Returns \c true if the installation can be interrupted. */ /*! \fn QInstaller::PackageManagerPage::settingsButtonRequested() const Returns \c true if the page requests the wizard to show the \uicontrol Settings button. */ /*! \fn QInstaller::PackageManagerPage::setSettingsButtonRequested(bool request) Determines that the page should request the \uicontrol Settings button if \a request is \c true. */ /*! \fn QInstaller::PackageManagerPage::entered() This signal is called when a page is entered. */ /*! \fn QInstaller::PackageManagerPage::left() This signal is called when a page is left. */ /*! \fn QInstaller::PackageManagerPage::entering() Called when end users enter the page and the PackageManagerGui:currentPageChanged() signal is triggered. Supports the QWizardPage::​initializePage() function to ensure that the page's fields are properly initialized based on fields from previous pages. Otherwise, \c initializePage() would only be called once if the installer has been set to QWizard::IndependentPages. */ /*! \fn QInstaller::PackageManagerPage::showOnPageListChanged() Called when page visibility on page list has changed and refresh is needed. */ /*! \fn QInstaller::PackageManagerPage::leaving() Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ /*! Constructs a package manager page with \a core as parent. */ PackageManagerPage::PackageManagerPage(PackageManagerCore *core) : m_complete(true) , m_titleColor(QString()) , m_needsSettingsButton(false) , m_core(core) , validatorComponent(nullptr) , m_showOnPageList(true) { if (!m_core->settings().titleColor().isEmpty()) m_titleColor = m_core->settings().titleColor(); if (!m_core->settings().wizardShowPageList()) setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); setPixmap(QWizard::BannerPixmap, bannerPixmap()); setPixmap(QWizard::LogoPixmap, logoPixmap()); // Can't use PackageManagerPage::gui() here as the page is not set yet if (PackageManagerGui *gui = qobject_cast(core->guiObject())) { connect(this, &PackageManagerPage::showOnPageListChanged, gui, &PackageManagerGui::updatePageListWidget); } } /*! Returns the package manager core. */ PackageManagerCore *PackageManagerPage::packageManagerCore() const { return m_core; } /*! Returns the watermark pixmap specified in the \c element of the package information file. */ QPixmap PackageManagerPage::watermarkPixmap() const { return QPixmap(m_core->value(QLatin1String("WatermarkPixmap"))); } /*! Returns the banner pixmap specified in the \c element of the package information file. Only used by the modern UI style. */ QPixmap PackageManagerPage::bannerPixmap() const { QPixmap banner(m_core->value(QLatin1String("BannerPixmap"))); if (!banner.isNull()) { int width; if (m_core->settings().containsValue(QLatin1String("WizardDefaultWidth")) ) width = m_core->settings().wizardDefaultWidth(); else width = size().width(); banner = banner.scaledToWidth(width, Qt::SmoothTransformation); } return banner; } /*! Returns the logo pixmap specified in the \c element of the package information file. */ QPixmap PackageManagerPage::logoPixmap() const { return QPixmap(m_core->value(QLatin1String("LogoPixmap"))); } /*! Returns the product name of the application being installed. */ QString PackageManagerPage::productName() const { return m_core->value(QLatin1String("ProductName")); } /*! Sets the font color of \a title. The title is specified in the \c element of the package information file. It is the name of the installer as displayed on the title bar. */ void PackageManagerPage::setColoredTitle(const QString &title) { setTitle(QString::fromLatin1("<font color=\"%1\">%2</font>").arg(m_titleColor, title)); } /*! Sets the font color of \a subTitle. */ void PackageManagerPage::setColoredSubTitle(const QString &subTitle) { setSubTitle(QString::fromLatin1("<font color=\"%1\">%2</font>").arg(m_titleColor, subTitle)); } /*! Sets the title shown on installer page indicator for this page to \a title. Pages that do not set this will use a fallback title instead. */ void PackageManagerPage::setPageListTitle(const QString &title) { m_pageListTitle = title; } /*! Returns the title shown on installer page indicator for this page. If empty, a fallback title is being used instead. */ QString PackageManagerPage::pageListTitle() const { return m_pageListTitle; } /*! Sets the page visibility on installer page indicator based on \a show. All pages are shown by default. */ void PackageManagerPage::setShowOnPageList(bool show) { if (m_showOnPageList != show) emit showOnPageListChanged(); m_showOnPageList = show; } /*! Returns \c true if the page should be shown on installer page indicator. */ bool PackageManagerPage::showOnPageList() const { return m_showOnPageList; } /*! Returns \c true if the page is complete; otherwise, returns \c false. */ bool PackageManagerPage::isComplete() const { return m_complete; } /*! Sets the package manager page to complete if \a complete is \c true. Emits the completeChanged() signal. */ void PackageManagerPage::setComplete(bool complete) { m_complete = complete; if (QWizard *w = wizard()) { if (QAbstractButton *cancel = w->button(QWizard::CancelButton)) { if (cancel->hasFocus()) { if (QAbstractButton *next = w->button(QWizard::NextButton)) next->setFocus(); } } } emit completeChanged(); } /*! Sets the \a component that validates the page. */ void PackageManagerPage::setValidatePageComponent(Component *component) { validatorComponent = component; } /*! Returns \c true if the end user has entered complete and valid information. */ bool PackageManagerPage::validatePage() { if (validatorComponent) return validatorComponent->validatePage(); return true; } /*! \internal */ void PackageManagerPage::removeCustomWidget(const QWidget *widget) { for (auto it = m_customWidgets.begin(); it != m_customWidgets.end();) { if (it.value() == widget) it = m_customWidgets.erase(it); else ++it; } } /*! Inserts \a widget at the position specified by \a offset in relation to another widget specified by \a siblingName. The default position is directly behind the sibling. */ void PackageManagerPage::insertWidget(QWidget *widget, const QString &siblingName, int offset) { QWidget *sibling = findChild<QWidget *>(siblingName); QWidget *parent = sibling ? sibling->parentWidget() : nullptr; QLayout *layout = parent ? parent->layout() : nullptr; QBoxLayout *blayout = qobject_cast<QBoxLayout *>(layout); if (blayout) { const int index = blayout->indexOf(sibling) + offset; blayout->insertWidget(index, widget); } } /*! Returns the widget specified by \a objectName. */ QWidget *PackageManagerPage::findWidget(const QString &objectName) const { return findChild<QWidget*> (objectName); } /*! Determines which page should be shown next depending on whether the application is being installed, updated, or uninstalled. The license check page is shown only if a component that provides a license is selected for installation. It is hidden during uninstallation and update. */ int PackageManagerPage::nextId() const { const int next = QWizardPage::nextId(); // the page to show next if (next == PackageManagerCore::LicenseCheck) { // calculate the page after the license page const int nextNextId = gui()->pageIds().value(gui()->pageIds().indexOf(next) + 1, -1); const PackageManagerCore *const core = packageManagerCore(); if (core->isUninstaller()) return nextNextId; // forcibly hide the license page if we run as uninstaller core->calculateComponentsToInstall(); foreach (Component* component, core->orderedComponentsToInstall()) { if (core->isMaintainer() && component->isInstalled()) continue; // package manager or updater, hide as long as the component is installed // The component is about to be installed and provides a license, so the page needs to // be shown. if (!component->licenses().isEmpty()) return next; } return nextNextId; // no component with a license or all components with license installed } return next; // default, show the next page } // -- IntroductionPage /*! \class QInstaller::IntroductionPage \inmodule QtInstallerFramework \brief The IntroductionPage class displays information about the product to install. */ /*! \fn QInstaller::IntroductionPage::packageManagerCoreTypeChanged() This signal is emitted when the package manager core type changes. */ /*! Constructs an introduction page with \a core as parent. */ IntroductionPage::IntroductionPage(PackageManagerCore *core) : PackageManagerPage(core) , m_updatesFetched(false) , m_allPackagesFetched(false) , m_label(nullptr) , m_msgLabel(nullptr) , m_errorLabel(nullptr) , m_progressBar(nullptr) , m_packageManager(nullptr) , m_updateComponents(nullptr) , m_removeAllComponents(nullptr) { setObjectName(QLatin1String("IntroductionPage")); setColoredTitle(tr("Setup - %1").arg(productName())); QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); m_msgLabel = new QLabel(this); m_msgLabel->setWordWrap(true); m_msgLabel->setObjectName(QLatin1String("MessageLabel")); m_msgLabel->setText(tr("Welcome to the %1 Setup Wizard.").arg(productName())); QWidget *widget = new QWidget(this); QVBoxLayout *boxLayout = new QVBoxLayout(widget); m_packageManager = new QRadioButton(tr("&Add or remove components"), this); m_packageManager->setObjectName(QLatin1String("PackageManagerRadioButton")); boxLayout->addWidget(m_packageManager); connect(m_packageManager, &QAbstractButton::toggled, this, &IntroductionPage::setPackageManager); m_updateComponents = new QRadioButton(tr("&Update components"), this); m_updateComponents->setObjectName(QLatin1String("UpdaterRadioButton")); boxLayout->addWidget(m_updateComponents); connect(m_updateComponents, &QAbstractButton::toggled, this, &IntroductionPage::setUpdater); m_removeAllComponents = new QRadioButton(tr("&Remove all components"), this); m_removeAllComponents->setObjectName(QLatin1String("UninstallerRadioButton")); boxLayout->addWidget(m_removeAllComponents); connect(m_removeAllComponents, &QAbstractButton::toggled, this, &IntroductionPage::setUninstaller); connect(m_removeAllComponents, &QAbstractButton::toggled, core, &PackageManagerCore::setCompleteUninstallation); boxLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding)); m_label = new QLabel(this); m_label->setWordWrap(true); m_label->setObjectName(QLatin1String("InformationLabel")); m_label->setText(tr("Retrieving information from remote installation sources...")); boxLayout->addWidget(m_label); m_progressBar = new QProgressBar(this); m_progressBar->setRange(0, 0); boxLayout->addWidget(m_progressBar); m_progressBar->setObjectName(QLatin1String("InformationProgressBar")); boxLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding)); m_errorLabel = new QLabel(this); m_errorLabel->setWordWrap(true); boxLayout->addWidget(m_errorLabel); m_errorLabel->setObjectName(QLatin1String("ErrorLabel")); layout->addWidget(m_msgLabel); layout->addWidget(widget); layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); connect(core, &PackageManagerCore::metaJobProgress, this, &IntroductionPage::onProgressChanged); connect(core, &PackageManagerCore::metaJobTotalProgress, this, &IntroductionPage::setTotalProgress); connect(core, &PackageManagerCore::metaJobInfoMessage, this, &IntroductionPage::setMessage); connect(core, &PackageManagerCore::coreNetworkSettingsChanged, this, &IntroductionPage::onCoreNetworkSettingsChanged); m_updateComponents->setEnabled(ProductKeyCheck::instance()->hasValidKey()); #ifdef Q_OS_WIN if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { m_taskButton = new QWinTaskbarButton(this); connect(core, &PackageManagerCore::metaJobProgress, m_taskButton->progress(), &QWinTaskbarProgress::setValue); } else { m_taskButton = nullptr; } #endif } /*! Determines which page should be shown next depending on whether the application is being installed, updated, or uninstalled. */ int IntroductionPage::nextId() const { if (packageManagerCore()->isUninstaller()) return PackageManagerCore::ReadyForInstallation; if (packageManagerCore()->isMaintainer()) return PackageManagerCore::ComponentSelection; return PackageManagerPage::nextId(); } /*! For an uninstaller, always returns \c true. For the package manager and updater, at least one valid repository is required. For the online installer, package manager, and updater, valid meta data has to be fetched successfully to return \c true. */ bool IntroductionPage::validatePage() { PackageManagerCore *core = packageManagerCore(); if (core->isUninstaller()) return true; setComplete(false); bool isOfflineOnlyInstaller = core->isInstaller() && core->isOfflineOnly(); // If not offline only installer, at least one valid repository needs to be available if (!isOfflineOnlyInstaller && !validRepositoriesAvailable()) { setErrorMessage(QLatin1String("<font color=\"red\">") + tr("At least one valid and enabled " "repository required for this action to succeed.") + QLatin1String("</font>")); return isComplete(); } gui()->setSettingsButtonEnabled(false); if (core->isMaintainer()) { showAll(); setMaintenanceToolsEnabled(false); } else { showMetaInfoUpdate(); } #ifdef Q_OS_WIN if (m_taskButton) { if (!m_taskButton->window()) { if (QWidget *widget = QApplication::activeWindow()) m_taskButton->setWindow(widget->windowHandle()); } m_taskButton->progress()->reset(); m_taskButton->progress()->resume(); m_taskButton->progress()->setVisible(true); } #endif // fetch updater packages if (core->isUpdater()) { if (!m_updatesFetched) { m_updatesFetched = core->fetchRemotePackagesTree(); if (!m_updatesFetched) setErrorMessage(core->error()); } if (m_updatesFetched) { if (core->components(QInstaller::PackageManagerCore::ComponentType::Root).count() <= 0) setErrorMessage(QString::fromLatin1("<b>%1</b>").arg(tr("No updates available."))); else setComplete(true); } } // fetch common packages if (core->isInstaller() || core->isPackageManager()) { bool localPackagesTreeFetched = false; if (!m_allPackagesFetched) { // first try to fetch the server side packages tree m_allPackagesFetched = core->fetchRemotePackagesTree(); if (!m_allPackagesFetched) { QString error = core->error(); if (core->isPackageManager() && core->status() != PackageManagerCore::ForceUpdate) { // if that fails and we're in maintenance mode, try to fetch local installed tree localPackagesTreeFetched = core->fetchLocalPackagesTree(); if (localPackagesTreeFetched) { // if that succeeded, adjust error message error = QLatin1String("<font color=\"red\">") + error + tr(" Only local package " "management available.") + QLatin1String("</font>"); } } setErrorMessage(error); } } if (m_allPackagesFetched || localPackagesTreeFetched) setComplete(true); } if (core->isMaintainer()) { showMaintenanceTools(); setMaintenanceToolsEnabled(true); } else { hideAll(); } gui()->setSettingsButtonEnabled(true); #ifdef Q_OS_WIN if (m_taskButton) m_taskButton->progress()->setVisible(!isComplete()); #endif return isComplete(); } /*! Shows all widgets on the page. */ void IntroductionPage::showAll() { showWidgets(true); } /*! Hides all widgets on the page. */ void IntroductionPage::hideAll() { showWidgets(false); } /*! Hides the widgets on the page except a text label and progress bar. */ void IntroductionPage::showMetaInfoUpdate() { showWidgets(false); m_label->setVisible(true); m_progressBar->setVisible(true); } /*! Shows the options to install, add, and unistall components on the page. */ void IntroductionPage::showMaintenanceTools() { showWidgets(true); m_label->setVisible(false); m_progressBar->setVisible(false); } /*! Sets \a enable to \c true to enable the options to install, add, and uninstall components on the page. */ void IntroductionPage::setMaintenanceToolsEnabled(bool enable) { m_packageManager->setEnabled(enable); m_updateComponents->setEnabled(enable && ProductKeyCheck::instance()->hasValidKey()); m_removeAllComponents->setEnabled(enable); } // -- public slots /*! Displays the message \a msg on the page. */ void IntroductionPage::setMessage(const QString &msg) { m_label->setText(msg); } /*! Updates the value of \a progress on the progress bar. */ void IntroductionPage::onProgressChanged(int progress) { m_progressBar->setValue(progress); } /*! Sets total \a totalProgress value to progress bar. */ void IntroductionPage::setTotalProgress(int totalProgress) { if (m_progressBar) m_progressBar->setRange(0, totalProgress); } /*! Displays the error message \a error on the page. */ void IntroductionPage::setErrorMessage(const QString &error) { QPalette palette; const PackageManagerCore::Status s = packageManagerCore()->status(); if (s == PackageManagerCore::Failure) { palette.setColor(QPalette::WindowText, Qt::red); } else { palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText)); } m_errorLabel->setText(error); m_errorLabel->setPalette(palette); #ifdef Q_OS_WIN if (m_taskButton) { m_taskButton->progress()->stop(); m_taskButton->progress()->setValue(100); } #endif } /*! Returns \c true if at least one valid and enabled repository is available. */ bool IntroductionPage::validRepositoriesAvailable() const { const PackageManagerCore *const core = packageManagerCore(); bool valid = false; foreach (const Repository &repo, core->settings().repositories()) { if (repo.isEnabled() && repo.isValid()) { valid = true; break; } } return valid; } // -- private slots void IntroductionPage::setUpdater(bool value) { if (value) { entering(); gui()->showSettingsButton(true); packageManagerCore()->setUpdater(); emit packageManagerCoreTypeChanged(); } } void IntroductionPage::setUninstaller(bool value) { if (value) { entering(); gui()->showSettingsButton(false); packageManagerCore()->setUninstaller(); emit packageManagerCoreTypeChanged(); } } void IntroductionPage::setPackageManager(bool value) { if (value) { entering(); gui()->showSettingsButton(true); packageManagerCore()->setPackageManager(); emit packageManagerCoreTypeChanged(); } } /*! Initializes the page. */ void IntroductionPage::initializePage() { PackageManagerCore *core = packageManagerCore(); if (core->isPackageManager()) { m_packageManager->setChecked(true); } else if (core->isUpdater()) { m_updateComponents->setChecked(true); } else if (core->isUninstaller()) { // If we are running maintenance tool and the default uninstaller // marker is not overridden, set the default checked radio button // based on if we have valid repositories available. if (!core->isUserSetBinaryMarker() && validRepositoriesAvailable()) { m_packageManager->setChecked(true); } else { // No repositories available, default to complete uninstallation. m_removeAllComponents->setChecked(true); core->setCompleteUninstallation(true); } } } /*! Resets the internal page state, so that on clicking \uicontrol Next the metadata needs to be fetched again. */ void IntroductionPage::onCoreNetworkSettingsChanged() { m_updatesFetched = false; m_allPackagesFetched = false; } // -- private /*! Initializes the page's fields. */ void IntroductionPage::entering() { setComplete(true); showWidgets(false); setMessage(QString()); setErrorMessage(QString()); setButtonText(QWizard::CancelButton, tr("&Quit")); m_progressBar->setValue(0); m_progressBar->setRange(0, 0); PackageManagerCore *core = packageManagerCore(); if (core->isUninstaller() || core->isMaintainer()) { showMaintenanceTools(); setMaintenanceToolsEnabled(true); } setSettingsButtonRequested((!core->isOfflineOnly()) && (!core->isUninstaller())); } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void IntroductionPage::leaving() { m_progressBar->setValue(0); m_progressBar->setRange(0, 0); setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton)); } /*! Displays widgets on the page. */ void IntroductionPage::showWidgets(bool show) { m_label->setVisible(show); m_progressBar->setVisible(show); m_packageManager->setVisible(show); m_updateComponents->setVisible(show); m_removeAllComponents->setVisible(show); } /*! Displays the text \a text on the page. */ void IntroductionPage::setText(const QString &text) { m_msgLabel->setText(text); } // -- LicenseAgreementPage::ClickForwarder class LicenseAgreementPage::ClickForwarder : public QObject { Q_OBJECT public: explicit ClickForwarder(QAbstractButton *button) : QObject(button) , m_abstractButton(button) {} protected: bool eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::MouseButtonRelease) { m_abstractButton->click(); return true; } // standard event processing return QObject::eventFilter(object, event); } private: QAbstractButton *m_abstractButton; }; // -- LicenseAgreementPage /*! \class QInstaller::LicenseAgreementPage \inmodule QtInstallerFramework \brief The LicenseAgreementPage presents a license agreement to the end users for acceptance. The license check page is displayed if you specify a license file in the package information file and copy the file to the meta directory. End users must accept the terms of the license agreement for the installation to continue. */ /*! Constructs a license check page with \a core as parent. */ LicenseAgreementPage::LicenseAgreementPage(PackageManagerCore *core) : PackageManagerPage(core) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("LicenseAgreementPage")); setColoredTitle(tr("License Agreement")); m_licenseListWidget = new QListWidget(this); m_licenseListWidget->setObjectName(QLatin1String("LicenseListWidget")); m_licenseListWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); connect(m_licenseListWidget, &QListWidget::currentItemChanged, this, &LicenseAgreementPage::currentItemChanged); m_textBrowser = new QTextBrowser(this); m_textBrowser->setReadOnly(true); m_textBrowser->setOpenLinks(false); m_textBrowser->setOpenExternalLinks(true); m_textBrowser->setObjectName(QLatin1String("LicenseTextBrowser")); m_textBrowser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); connect(m_textBrowser, &QTextBrowser::anchorClicked, this, &LicenseAgreementPage::openLicenseUrl); QVBoxLayout *licenseBoxLayout = new QVBoxLayout(); licenseBoxLayout->addWidget(m_licenseListWidget); licenseBoxLayout->addWidget(m_textBrowser); QVBoxLayout *layout = new QVBoxLayout(this); layout->addLayout(licenseBoxLayout); m_acceptRadioButton = new QRadioButton(this); m_acceptRadioButton->setShortcut(QKeySequence(tr("Alt+A", "agree license"))); m_acceptRadioButton->setObjectName(QLatin1String("AcceptLicenseRadioButton")); ClickForwarder *acceptClickForwarder = new ClickForwarder(m_acceptRadioButton); m_acceptLabel = new QLabel; m_acceptLabel->setWordWrap(true); m_acceptLabel->installEventFilter(acceptClickForwarder); m_acceptLabel->setObjectName(QLatin1String("AcceptLicenseLabel")); m_acceptLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); m_rejectRadioButton = new QRadioButton(this); ClickForwarder *rejectClickForwarder = new ClickForwarder(m_rejectRadioButton); m_rejectRadioButton->setObjectName(QString::fromUtf8("RejectLicenseRadioButton")); m_rejectRadioButton->setShortcut(QKeySequence(tr("Alt+D", "do not agree license"))); m_rejectLabel = new QLabel; m_rejectLabel->setWordWrap(true); m_rejectLabel->installEventFilter(rejectClickForwarder); m_rejectLabel->setObjectName(QLatin1String("RejectLicenseLabel")); m_rejectLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); QGridLayout *gridLayout = new QGridLayout; gridLayout->setColumnStretch(1, 1); gridLayout->addWidget(m_acceptRadioButton, 0, 0); gridLayout->addWidget(m_acceptLabel, 0, 1); gridLayout->addWidget(m_rejectRadioButton, 1, 0); gridLayout->addWidget(m_rejectLabel, 1, 1); layout->addLayout(gridLayout); connect(m_acceptRadioButton, &QAbstractButton::toggled, this, &QWizardPage::completeChanged); connect(m_rejectRadioButton, &QAbstractButton::toggled, this, &QWizardPage::completeChanged); m_rejectRadioButton->setChecked(true); } /*! Initializes the page's fields based on values from fields on previous pages. */ void LicenseAgreementPage::entering() { m_licenseListWidget->clear(); m_textBrowser->setHtml(QString()); m_licenseListWidget->setVisible(false); packageManagerCore()->calculateComponentsToInstall(); foreach (QInstaller::Component *component, packageManagerCore()->orderedComponentsToInstall()) addLicenseItem(component->licenses()); const int licenseCount = m_licenseListWidget->count(); if (licenseCount > 0) { m_licenseListWidget->setVisible(licenseCount > 1); m_licenseListWidget->setCurrentItem(m_licenseListWidget->item(0)); } updateUi(); } /*! Returns \c true if the accept license radio button is checked; otherwise, returns \c false. */ bool LicenseAgreementPage::isComplete() const { return m_acceptRadioButton->isChecked(); } void LicenseAgreementPage::openLicenseUrl(const QUrl &url) { QDesktopServices::openUrl(url); } void LicenseAgreementPage::currentItemChanged(QListWidgetItem *current) { if (current) m_textBrowser->setText(current->data(Qt::UserRole).toString()); } void LicenseAgreementPage::addLicenseItem(const QHash<QString, QPair<QString, QString> > &hash) { for (QHash<QString, QPair<QString, QString> >::const_iterator it = hash.begin(); it != hash.end(); ++it) { QListWidgetItem *item = new QListWidgetItem(it.key(), m_licenseListWidget); item->setData(Qt::UserRole, it.value().second); } } void LicenseAgreementPage::updateUi() { QString subTitleText; QString acceptButtonText; QString rejectButtonText; if (m_licenseListWidget->count() == 1) { subTitleText = tr("Please read the following license agreement. You must accept the terms " "contained in this agreement before continuing with the installation."); acceptButtonText = tr("I accept the license."); rejectButtonText = tr("I do not accept the license."); } else { subTitleText = tr("Please read the following license agreements. You must accept the terms " "contained in these agreements before continuing with the installation."); acceptButtonText = tr("I accept the licenses."); rejectButtonText = tr("I do not accept the licenses."); } m_licenseListWidget->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); setColoredSubTitle(subTitleText); m_acceptLabel->setText(acceptButtonText); m_rejectLabel->setText(rejectButtonText); } // -- ComponentSelectionPage /*! \class QInstaller::ComponentSelectionPage \inmodule QtInstallerFramework \brief The ComponentSelectionPage class changes the checked state of components. */ /*! Constructs a component selection page with \a core as parent. */ ComponentSelectionPage::ComponentSelectionPage(PackageManagerCore *core) : PackageManagerPage(core) , d(new ComponentSelectionPagePrivate(this, core)) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("ComponentSelectionPage")); setColoredTitle(tr("Select Components")); } /*! Destructs a component selection page. */ ComponentSelectionPage::~ComponentSelectionPage() { delete d; } /*! Initializes the page's fields based on values from fields on previous pages. The text to display depends on whether the page is being used in an installer, updater, or uninstaller. */ void ComponentSelectionPage::entering() { static const char *strings[] = { QT_TR_NOOP("Please select the components you want to update."), QT_TR_NOOP("Please select the components you want to install."), QT_TR_NOOP("Please select the components you want to uninstall."), QT_TR_NOOP("Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated."), QT_TR_NOOP("Mandatory components need to be updated first before you can select other components to update.") }; int index = 0; PackageManagerCore *core = packageManagerCore(); if (core->isInstaller()) index = 1; if (core->isUninstaller()) index = 2; if (core->isPackageManager()) index = 3; if (core->foundEssentialUpdate() && core->isUpdater()) index = 4; setColoredSubTitle(tr(strings[index])); d->updateTreeView(); // check component model state so we can enable needed component selection buttons if (core->isUpdater()) d->onModelStateChanged(d->m_currentModel->checkedState()); setModified(isComplete()); if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly() && !core->isUpdater()) { d->showCategoryLayout(true); core->settings().setAllowUnstableComponents(true); } else { d->showCategoryLayout(false); } d->showCompressedRepositoryButton(); } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void ComponentSelectionPage::leaving() { d->hideCompressedRepositoryButton(); } /*! Called when the show event \a event occurs. Switching pages back and forth might restore or remove the checked state of certain components the end users have checked or not checked, because the dependencies are resolved and checked when clicking \uicontrol Next. So as not to confuse the end users with newly checked components they did not check, the state they left the page in is restored. */ void ComponentSelectionPage::showEvent(QShowEvent *event) { // remove once we deprecate isSelected, setSelected etc... if (!event->spontaneous()) packageManagerCore()->restoreCheckState(); QWizardPage::showEvent(event); } /*! Selects all components in the component tree. */ void ComponentSelectionPage::selectAll() { d->selectAll(); } /*! Deselects all components in the component tree. */ void ComponentSelectionPage::deselectAll() { d->deselectAll(); } /*! Selects the components that have the \c <Default> element set to \c true in the package information file. */ void ComponentSelectionPage::selectDefault() { if (packageManagerCore()->isInstaller()) d->selectDefault(); } /*! Selects the component with \a id in the component tree. */ void ComponentSelectionPage::selectComponent(const QString &id) { d->m_core->selectComponent(id); } /*! Deselects the component with \a id in the component tree. */ void ComponentSelectionPage::deselectComponent(const QString &id) { d->m_core->deselectComponent(id); } /*! Adds the possibility to install a compressed repository on component selection page. A new button which opens a file browser is added for compressed repository selection. */ void ComponentSelectionPage::allowCompressedRepositoryInstall() { d->allowCompressedRepositoryInstall(); } /*! Adds an additional virtual component with the \a name to be installed. Returns \c true if the virtual component is found and not installed. */ bool ComponentSelectionPage::addVirtualComponentToUninstall(const QString &name) { PackageManagerCore *core = packageManagerCore(); const QList<Component *> allComponents = core->components(PackageManagerCore::ComponentType::All); Component *component = PackageManagerCore::componentByName( name, allComponents); if (component && component->isInstalled() && component->isVirtual()) { component->setCheckState(Qt::Unchecked); core->componentsToInstallNeedsRecalculation(); qCDebug(QInstaller::lcDeveloperBuild) << "Virtual component " << name << " was selected for uninstall by script."; return true; } return false; } void ComponentSelectionPage::setModified(bool modified) { setComplete(modified); } /*! Returns \c true if at least one component is checked on the page. */ bool ComponentSelectionPage::isComplete() const { if (packageManagerCore()->isInstaller() || packageManagerCore()->isUpdater()) return d->m_currentModel->checked().count(); return d->m_currentModel->checkedState().testFlag(ComponentModel::DefaultChecked) == false; } // -- TargetDirectoryPage /*! \class QInstaller::TargetDirectoryPage \inmodule QtInstallerFramework \brief The TargetDirectoryPage class specifies the target directory for the installation. End users can leave the page to continue the installation only if certain criteria are fulfilled. Some of them are checked in the validatePage() function, some in the targetDirWarning() function: \list \li No empty path given as target. \li No relative path given as target. \li Only ASCII characters are allowed in the path if the <AllowNonAsciiCharacters> element in the configuration file is set to \c false. \li The following ambiguous characters are not allowed in the path: [\"~<>|?*!@#$%^&:,;] \li No root or home directory given as target. \li On Windows, path names must be less than 260 characters long. \li No spaces in the path if the <AllowSpaceInPath> element in the configuration file is set to \c false. \endlist */ /*! Constructs a target directory selection page with \a core as parent. */ TargetDirectoryPage::TargetDirectoryPage(PackageManagerCore *core) : PackageManagerPage(core) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("TargetDirectoryPage")); setColoredTitle(tr("Installation Folder")); QVBoxLayout *layout = new QVBoxLayout(this); QLabel *msgLabel = new QLabel(this); msgLabel->setWordWrap(true); msgLabel->setObjectName(QLatin1String("MessageLabel")); msgLabel->setText(tr("Please specify the directory where %1 will be installed.").arg(productName())); layout->addWidget(msgLabel); QHBoxLayout *hlayout = new QHBoxLayout; m_textChangeTimer.setSingleShot(true); m_textChangeTimer.setInterval(200); connect(&m_textChangeTimer, &QTimer::timeout, this, &QWizardPage::completeChanged); m_lineEdit = new QLineEdit(this); m_lineEdit->setObjectName(QLatin1String("TargetDirectoryLineEdit")); connect(m_lineEdit, &QLineEdit::textChanged, &m_textChangeTimer, static_cast<void (QTimer::*)()>(&QTimer::start)); hlayout->addWidget(m_lineEdit); QPushButton *browseButton = new QPushButton(this); browseButton->setObjectName(QLatin1String("BrowseDirectoryButton")); connect(browseButton, &QAbstractButton::clicked, this, &TargetDirectoryPage::dirRequested); browseButton->setShortcut(QKeySequence(tr("Alt+R", "browse file system to choose a file"))); browseButton->setText(tr("B&rowse...")); hlayout->addWidget(browseButton); layout->addLayout(hlayout); QPalette palette; palette.setColor(QPalette::WindowText, Qt::red); m_warningLabel = new QLabel(this); m_warningLabel->setPalette(palette); m_warningLabel->setWordWrap(true); m_warningLabel->setObjectName(QLatin1String("WarningLabel")); layout->addWidget(m_warningLabel); setLayout(layout); } /*! Returns the target directory for the installation. */ QString TargetDirectoryPage::targetDir() const { return m_lineEdit->text().trimmed(); } /*! Sets the directory specified by \a dirName as the target directory for the installation. */ void TargetDirectoryPage::setTargetDir(const QString &dirName) { m_lineEdit->setText(dirName); } /*! Initializes the page. */ void TargetDirectoryPage::initializePage() { QString targetDir = packageManagerCore()->value(scTargetDir); if (targetDir.isEmpty()) { targetDir = QDir::homePath() + QDir::separator(); if (!packageManagerCore()->settings().allowSpaceInPath()) { // prevent spaces in the default target directory if (targetDir.contains(QLatin1Char(' '))) targetDir = QDir::rootPath(); targetDir += productName().remove(QLatin1Char(' ')); } else { targetDir += productName(); } } m_lineEdit->setText(QDir::toNativeSeparators(QDir(targetDir).absolutePath())); PackageManagerPage::initializePage(); } /*! Returns \c true if the target directory exists and has correct content. */ bool TargetDirectoryPage::validatePage() { m_textChangeTimer.stop(); if (!isComplete()) return false; if (!isVisible()) return true; const QString remove = packageManagerCore()->value(QLatin1String("RemoveTargetDir")); if (!QVariant(remove).toBool()) return true; return this->packageManagerCore()->checkTargetDir(targetDir()); } /*! Initializes the page's fields based on values from fields on previous pages. */ void TargetDirectoryPage::entering() { if (QPushButton *const b = qobject_cast<QPushButton *>(gui()->button(QWizard::NextButton))) b->setDefault(true); } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void TargetDirectoryPage::leaving() { packageManagerCore()->setValue(scTargetDir, targetDir()); } void TargetDirectoryPage::dirRequested() { const QString newDirName = QFileDialog::getExistingDirectory(this, tr("Select Installation Folder"), targetDir()); if (newDirName.isEmpty() || newDirName == targetDir()) return; m_lineEdit->setText(QDir::toNativeSeparators(newDirName)); } /*! Requests a warning message to be shown to end users upon invalid input. If the input is valid, the \uicontrol Next button is enabled. Returns \c true if a valid path to the target directory is set; otherwise returns \c false. */ bool TargetDirectoryPage::isComplete() const { m_warningLabel->setText(packageManagerCore()->targetDirWarning(targetDir())); return m_warningLabel->text().isEmpty(); } // -- StartMenuDirectoryPage /*! \class QInstaller::StartMenuDirectoryPage \inmodule QtInstallerFramework \brief The StartMenuDirectoryPage class specifies the program group for the product in the Windows Start menu. */ /*! Constructs a Start menu directory selection page with \a core as parent. */ StartMenuDirectoryPage::StartMenuDirectoryPage(PackageManagerCore *core) : PackageManagerPage(core) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("StartMenuDirectoryPage")); setColoredTitle(tr("Start Menu shortcuts")); setColoredSubTitle(tr("Select the Start Menu in which you would like to create the program's " "shortcuts. You can also enter a name to create a new directory.")); m_lineEdit = new QLineEdit(this); m_lineEdit->setText(core->value(scStartMenuDir, productName())); m_lineEdit->setObjectName(QLatin1String("StartMenuPathLineEdit")); startMenuPath = core->value(QLatin1String("UserStartMenuProgramsPath")); QStringList dirs = QDir(startMenuPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot); if (core->value(scAllUsers, scFalse) == scTrue) { startMenuPath = core->value(scAllUsersStartMenuProgramsPath); dirs += QDir(startMenuPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot); } dirs.removeDuplicates(); m_listWidget = new QListWidget(this); foreach (const QString &dir, dirs) new QListWidgetItem(dir, m_listWidget); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(m_lineEdit); layout->addWidget(m_listWidget); setLayout(layout); connect(m_listWidget, &QListWidget::currentItemChanged, this, &StartMenuDirectoryPage::currentItemChanged); } /*! Returns the program group for the product in the Windows Start menu. */ QString StartMenuDirectoryPage::startMenuDir() const { return m_lineEdit->text().trimmed(); } /*! Sets \a startMenuDir as the program group for the product in the Windows Start menu. */ void StartMenuDirectoryPage::setStartMenuDir(const QString &startMenuDir) { m_lineEdit->setText(startMenuDir.trimmed()); } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void StartMenuDirectoryPage::leaving() { packageManagerCore()->setValue(scStartMenuDir, startMenuPath + QDir::separator() + startMenuDir()); } void StartMenuDirectoryPage::currentItemChanged(QListWidgetItem *current) { if (current) setStartMenuDir(current->data(Qt::DisplayRole).toString()); } // -- ReadyForInstallationPage /*! \class QInstaller::ReadyForInstallationPage \inmodule QtInstallerFramework \brief The ReadyForInstallationPage class informs end users that the installation can begin. */ /*! Constructs a ready for installation page with \a core as parent. */ ReadyForInstallationPage::ReadyForInstallationPage(PackageManagerCore *core) : PackageManagerPage(core) , m_msgLabel(new QLabel) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("ReadyForInstallationPage")); updatePageListTitle(); QVBoxLayout *baseLayout = new QVBoxLayout(); baseLayout->setObjectName(QLatin1String("BaseLayout")); QVBoxLayout *topLayout = new QVBoxLayout(); topLayout->setObjectName(QLatin1String("TopLayout")); m_msgLabel->setWordWrap(true); m_msgLabel->setObjectName(QLatin1String("MessageLabel")); m_msgLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); topLayout->addWidget(m_msgLabel); baseLayout->addLayout(topLayout); QVBoxLayout *bottomLayout = new QVBoxLayout(); bottomLayout->setObjectName(QLatin1String("BottomLayout")); bottomLayout->addStretch(); m_taskDetailsBrowser = new QTextBrowser(this); m_taskDetailsBrowser->setReadOnly(true); m_taskDetailsBrowser->setObjectName(QLatin1String("TaskDetailsBrowser")); m_taskDetailsBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_taskDetailsBrowser->setVisible(false); bottomLayout->addWidget(m_taskDetailsBrowser); bottomLayout->setStretch(1, 10); baseLayout->addLayout(bottomLayout); setCommitPage(true); setLayout(baseLayout); connect(core, &PackageManagerCore::installerBinaryMarkerChanged, this, &ReadyForInstallationPage::updatePageListTitle); } /*! Initializes the page's fields based on values from fields on previous pages. The text to display depends on whether the page is being used in an installer, updater, or uninstaller. */ void ReadyForInstallationPage::entering() { setComplete(false); if (packageManagerCore()->isUninstaller()) { m_taskDetailsBrowser->setVisible(false); setButtonText(QWizard::CommitButton, tr("U&ninstall")); setColoredTitle(tr("Ready to Uninstall")); m_msgLabel->setText(tr("Setup is now ready to begin removing %1 from your computer.<br>" "<font color=\"red\">The program directory %2 will be deleted completely</font>, " "including all content in that directory!") .arg(productName(), QDir::toNativeSeparators(QDir(packageManagerCore()->value(scTargetDir)) .absolutePath()))); setComplete(true); return; } else if (packageManagerCore()->isMaintainer()) { setButtonText(QWizard::CommitButton, tr("U&pdate")); setColoredTitle(tr("Ready to Update Packages")); m_msgLabel->setText(tr("Setup is now ready to begin updating your installation.")); } else { Q_ASSERT(packageManagerCore()->isInstaller()); setButtonText(QWizard::CommitButton, tr("&Install")); setColoredTitle(tr("Ready to Install")); m_msgLabel->setText(tr("Setup is now ready to begin installing %1 on your computer.") .arg(productName())); } QString htmlOutput; bool componentsOk = packageManagerCore()->calculateComponents(&htmlOutput); m_taskDetailsBrowser->setHtml(htmlOutput); m_taskDetailsBrowser->setVisible(!componentsOk || isVerbose()); setComplete(componentsOk); QString spaceInfo; if (packageManagerCore()->checkAvailableSpace(spaceInfo)) { m_msgLabel->setText(QString::fromLatin1("%1 %2").arg(m_msgLabel->text(), spaceInfo)); } else { m_msgLabel->setText(spaceInfo); setComplete(false); } } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void ReadyForInstallationPage::leaving() { setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton)); } /*! Updates page list title based on installer binary type. */ void ReadyForInstallationPage::updatePageListTitle() { PackageManagerCore *core = packageManagerCore(); if (core->isInstaller()) setPageListTitle(tr("Ready to Install")); else if (core->isMaintainer()) setPageListTitle(tr("Ready to Update")); else if (core->isUninstaller()) setPageListTitle(tr("Ready to Uninstall")); } // -- PerformInstallationPage /*! \class QInstaller::PerformInstallationPage \inmodule QtInstallerFramework \brief The PerformInstallationPage class shows progress information about the installation state. This class is a container for the PerformInstallationForm class, which constructs the actual UI for the page. */ /*! \fn QInstaller::PerformInstallationPage::isInterruptible() const Returns \c true if the installation can be interrupted. */ /*! \fn QInstaller::PerformInstallationPage::setAutomatedPageSwitchEnabled(bool request) Enables automatic switching of pages when \a request is \c true. */ /*! Constructs a perform installation page with \a core as parent. The page contains a PerformInstallationForm that defines the UI for the page. */ PerformInstallationPage::PerformInstallationPage(PackageManagerCore *core) : PackageManagerPage(core) , m_performInstallationForm(new PerformInstallationForm(this)) { setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("PerformInstallationPage")); updatePageListTitle(); m_performInstallationForm->setupUi(this); m_imageChangeTimer.setInterval(10000); connect(ProgressCoordinator::instance(), &ProgressCoordinator::detailTextChanged, m_performInstallationForm, &PerformInstallationForm::appendProgressDetails); connect(ProgressCoordinator::instance(), &ProgressCoordinator::detailTextResetNeeded, m_performInstallationForm, &PerformInstallationForm::clearDetailsBrowser); connect(m_performInstallationForm, &PerformInstallationForm::showDetailsChanged, this, &PerformInstallationPage::toggleDetailsWereChanged); connect(core, &PackageManagerCore::installationStarted, this, &PerformInstallationPage::installationStarted); connect(core, &PackageManagerCore::installationFinished, this, &PerformInstallationPage::installationFinished); connect(core, &PackageManagerCore::uninstallationStarted, this, &PerformInstallationPage::uninstallationStarted); connect(core, &PackageManagerCore::uninstallationFinished, this, &PerformInstallationPage::uninstallationFinished); connect(core, &PackageManagerCore::titleMessageChanged, this, &PerformInstallationPage::setTitleMessage); connect(this, &PerformInstallationPage::setAutomatedPageSwitchEnabled, core, &PackageManagerCore::setAutomatedPageSwitchEnabled); connect(core, &PackageManagerCore::installerBinaryMarkerChanged, this, &PerformInstallationPage::updatePageListTitle); connect(&m_imageChangeTimer, &QTimer::timeout, this, &PerformInstallationPage::changeCurrentImage); m_performInstallationForm->setDetailsWidgetVisible(true); setCommitPage(true); } /*! Destructs a perform installation page. */ PerformInstallationPage::~PerformInstallationPage() { delete m_performInstallationForm; } /*! Returns \c true if automatically switching to the page is requested. */ bool PerformInstallationPage::isAutoSwitching() const { return !m_performInstallationForm->isShowingDetails(); } // -- protected /*! Initializes the page's fields based on values from fields on previous pages. The text to display depends on whether the page is being used in an installer, updater, or uninstaller. */ void PerformInstallationPage::entering() { setComplete(false); m_performInstallationForm->enableDetails(); emit setAutomatedPageSwitchEnabled(true); changeCurrentImage(); // No need to start the timer if we only have one, or no images if (packageManagerCore()->settings().productImages().count() > 1) m_imageChangeTimer.start(); if (isVerbose()) { m_performInstallationForm->toggleDetails(); } if (packageManagerCore()->isUninstaller()) { setButtonText(QWizard::CommitButton, tr("U&ninstall")); setColoredTitle(tr("Uninstalling %1").arg(productName())); QTimer::singleShot(30, packageManagerCore(), SLOT(runUninstaller())); } else if (packageManagerCore()->isMaintainer()) { setButtonText(QWizard::CommitButton, tr("&Update")); setColoredTitle(tr("Updating components of %1").arg(productName())); QTimer::singleShot(30, packageManagerCore(), SLOT(runPackageUpdater())); } else { setButtonText(QWizard::CommitButton, tr("&Install")); setColoredTitle(tr("Installing %1").arg(productName())); QTimer::singleShot(30, packageManagerCore(), SLOT(runInstaller())); } } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void PerformInstallationPage::leaving() { setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton)); m_imageChangeTimer.stop(); } /*! Updates page list title based on installer binary type. */ void PerformInstallationPage::updatePageListTitle() { PackageManagerCore *core = packageManagerCore(); if (core->isInstaller()) setPageListTitle(tr("Installing")); else if (core->isMaintainer()) setPageListTitle(tr("Updating")); else if (core->isUninstaller()) setPageListTitle(tr("Uninstalling")); } // -- public slots /*! Sets \a title as the title of the perform installation page. */ void PerformInstallationPage::setTitleMessage(const QString &title) { setColoredTitle(title); } /*! Changes the currently shown product image to the next available image from installer configuration. */ void PerformInstallationPage::changeCurrentImage() { const QStringList productImages = packageManagerCore()->settings().productImages(); if (productImages.isEmpty()) return; const QString nextImage = (m_currentImage.isEmpty() || m_currentImage == productImages.last()) ? productImages.first() : productImages.at(productImages.indexOf(m_currentImage) + 1); // Do not update the pixmap if there was only one image available if (nextImage != m_currentImage) { m_performInstallationForm->setImageFromFileName(nextImage); m_currentImage = nextImage; } } // -- private slots void PerformInstallationPage::installationStarted() { m_performInstallationForm->startUpdateProgress(); } void PerformInstallationPage::installationFinished() { m_performInstallationForm->stopUpdateProgress(); if (!isAutoSwitching()) { m_performInstallationForm->scrollDetailsToTheEnd(); m_performInstallationForm->setDetailsButtonEnabled(false); setComplete(true); setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::NextButton)); } } void PerformInstallationPage::uninstallationStarted() { m_performInstallationForm->startUpdateProgress(); if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) cancel->setEnabled(false); } void PerformInstallationPage::uninstallationFinished() { installationFinished(); if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) cancel->setEnabled(false); } void PerformInstallationPage::toggleDetailsWereChanged() { emit setAutomatedPageSwitchEnabled(isAutoSwitching()); } // -- FinishedPage /*! \class QInstaller::FinishedPage \inmodule QtInstallerFramework \brief The FinishedPage class completes the installation wizard. You can add the option to open the installed application to the page. */ /*! Constructs an installation finished page with \a core as parent. */ FinishedPage::FinishedPage(PackageManagerCore *core) : PackageManagerPage(core) , m_commitButton(nullptr) { setObjectName(QLatin1String("FinishedPage")); setColoredTitle(tr("Completing the %1 Wizard").arg(productName())); setPageListTitle(tr("Finished")); m_msgLabel = new QLabel(this); m_msgLabel->setWordWrap(true); m_msgLabel->setObjectName(QLatin1String("MessageLabel")); m_runItCheckBox = new QCheckBox(this); m_runItCheckBox->setObjectName(QLatin1String("RunItCheckBox")); m_runItCheckBox->setChecked(true); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(m_msgLabel); layout->addWidget(m_runItCheckBox); setLayout(layout); setCommitPage(true); } /*! Initializes the page's fields based on values from fields on previous pages. */ void FinishedPage::entering() { m_msgLabel->setText(tr("Click %1 to exit the %2 Wizard.") .arg(gui()->defaultButtonText(QWizard::FinishButton).remove(QLatin1Char('&'))) .arg(productName())); if (m_commitButton) { disconnect(m_commitButton, &QAbstractButton::clicked, this, &FinishedPage::handleFinishClicked); m_commitButton = nullptr; } if (packageManagerCore()->isMaintainer()) { #ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, false); #endif if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { m_commitButton = cancel; cancel->setEnabled(true); cancel->setVisible(true); // we don't use the usual FinishButton so we need to connect the misused CancelButton connect(cancel, &QAbstractButton::clicked, gui(), &PackageManagerGui::finishButtonClicked); connect(cancel, &QAbstractButton::clicked, packageManagerCore(), &PackageManagerCore::finishButtonClicked); // for the moment we don't want the rejected signal connected disconnect(gui(), &QDialog::rejected, packageManagerCore(), &PackageManagerCore::setCanceled); connect(gui()->button(QWizard::CommitButton), &QAbstractButton::clicked, this, &FinishedPage::cleanupChangedConnects); } setButtonText(QWizard::CommitButton, tr("Restart")); setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::FinishButton)); } else { if (packageManagerCore()->isInstaller()) { m_commitButton = wizard()->button(QWizard::FinishButton); if (QPushButton *const b = qobject_cast<QPushButton *>(m_commitButton)) b->setDefault(true); } gui()->setOption(QWizard::NoCancelButton, true); if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) cancel->setVisible(false); } gui()->updateButtonLayout(); if (m_commitButton) { disconnect(m_commitButton, &QAbstractButton::clicked, this, &FinishedPage::handleFinishClicked); connect(m_commitButton, &QAbstractButton::clicked, this, &FinishedPage::handleFinishClicked); } if (packageManagerCore()->status() == PackageManagerCore::Success) { const QString finishedText = packageManagerCore()->value(QLatin1String("FinishedText")); if (!finishedText.isEmpty()) m_msgLabel->setText(finishedText); if (!packageManagerCore()->isUninstaller() && !packageManagerCore()->value(scRunProgram) .isEmpty()) { m_runItCheckBox->show(); m_runItCheckBox->setText(packageManagerCore()->value(scRunProgramDescription, tr("Run %1 now.")).arg(productName())); return; // job done } } else { // TODO: how to handle this using the config.xml setColoredTitle(tr("The %1 Wizard failed.").arg(productName())); } m_runItCheckBox->hide(); m_runItCheckBox->setChecked(false); } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void FinishedPage::leaving() { #ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, true); #endif if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) cancel->setVisible(false); gui()->updateButtonLayout(); setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton)); setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton)); } /*! Performs the necessary operations when end users select the \uicontrol Finish button. */ void FinishedPage::handleFinishClicked() { const QString program = packageManagerCore()->replaceVariables(packageManagerCore()->value(scRunProgram)); const QStringList args = packageManagerCore()->replaceVariables(packageManagerCore() ->values(scRunProgramArguments)); if (!m_runItCheckBox->isChecked() || program.isEmpty()) return; qCDebug(QInstaller::lcInstallerInstallLog) << "starting" << program << args; QProcess::startDetached(program, args); } /*! Removes changed connects from the page. */ void FinishedPage::cleanupChangedConnects() { if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { // remove the workaround connect from entering page disconnect(cancel, &QAbstractButton::clicked, gui(), &PackageManagerGui::finishButtonClicked); disconnect(cancel, &QAbstractButton::clicked, packageManagerCore(), &PackageManagerCore::finishButtonClicked); connect(gui(), &QDialog::rejected, packageManagerCore(), &PackageManagerCore::setCanceled); disconnect(gui()->button(QWizard::CommitButton), &QAbstractButton::clicked, this, &FinishedPage::cleanupChangedConnects); } } // -- RestartPage /*! \class QInstaller::RestartPage \inmodule QtInstallerFramework \brief The RestartPage class enables restarting the installer. The restart installation page enables end users to restart the wizard. This is useful, for example, if the maintenance tool itself needs to be updated before updating the application components. When updating is done, end users can select \uicontrol Restart to start the maintenance tool. */ /*! \fn QInstaller::RestartPage::restart() This signal is emitted when the installer is restarted. */ /*! Constructs a restart installation page with \a core as parent. */ RestartPage::RestartPage(PackageManagerCore *core) : PackageManagerPage(core) { setObjectName(QLatin1String("RestartPage")); setColoredTitle(tr("Completing the %1 Setup Wizard").arg(productName())); // Never show this page on the page list setShowOnPageList(false); setFinalPage(false); } /*! Returns the introduction page. */ int RestartPage::nextId() const { return PackageManagerCore::Introduction; } /*! Initializes the page's fields based on values from fields on previous pages. */ void RestartPage::entering() { if (!packageManagerCore()->needsHardRestart()) { if (QAbstractButton *finish = wizard()->button(QWizard::FinishButton)) finish->setVisible(false); QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection); } else { gui()->accept(); } } /*! Called when end users leave the page and the PackageManagerGui:currentPageChanged() signal is triggered. */ void RestartPage::leaving() { } #include "packagemanagergui.moc" #include "moc_packagemanagergui.cpp" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagemanagergui.h���������������������������������0100777�0000000�0000000�00000031115�13761647206�022422� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGERGUI_H #define PACKAGEMANAGERGUI_H #include "packagemanagercore.h" #include <QtCore/QEvent> #include <QtCore/QMetaType> #include <QtCore/QTimer> #include <QWizard> #include <QWizardPage> // FIXME: move to private classes QT_BEGIN_NAMESPACE class QAbstractButton; class QCheckBox; class QLabel; class QLineEdit; class QListWidget; class QListWidgetItem; class QProgressBar; class QRadioButton; class QTextBrowser; class QWinTaskbarButton; QT_END_NAMESPACE namespace QInstaller { class PackageManagerCore; class PackageManagerPage; class PerformInstallationForm; class ComponentSelectionPagePrivate; // -- PackageManagerGui class INSTALLER_EXPORT PackageManagerGui : public QWizard { Q_OBJECT public: explicit PackageManagerGui(PackageManagerCore *core, QWidget *parent = 0); virtual ~PackageManagerGui() = 0; void loadControlScript(const QString& scriptPath); void callControlScriptMethod(const QString& methodName); QWidget *pageById(int id) const; QWidget *pageByObjectName(const QString &name) const; QWidget *currentPageWidget() const; QWidget *pageWidgetByObjectName(const QString &name) const; QString defaultButtonText(int wizardButton) const; void clickButton(int wizardButton, int delayInMs = 0); void clickButton(const QString &objectName, int delayInMs = 0) const; bool isButtonEnabled(int wizardButton); void showSettingsButton(bool show); void setSettingsButtonEnabled(bool enable); void updateButtonLayout(); static QWizard::WizardStyle getStyle(const QString &name); void setSilent(bool silent); bool isSilent() const; void setTextItems(QObject *object, const QStringList &items); Q_SIGNALS: void interrupted(); void languageChanged(); void finishButtonClicked(); void gotRestarted(); void settingsButtonClicked(); public Q_SLOTS: void cancelButtonClicked(); void reject(); void rejectWithoutPrompt(); void showFinishedPage(); void setModified(bool value); void setMaxSize(); void updatePageListWidget(); protected Q_SLOTS: void wizardPageInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page); void wizardPageRemovalRequested(QWidget *widget); void wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page, int position); void wizardWidgetRemovalRequested(QWidget *widget); void wizardPageVisibilityChangeRequested(bool visible, int page); void setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name, const QString &callbackName); void setAutomatedPageSwitchEnabled(bool request); private Q_SLOTS: void onLanguageChanged(); void customButtonClicked(int which); void dependsOnLocalInstallerBinary(); void currentPageChanged(int newId); protected: bool event(QEvent *event); void showEvent(QShowEvent *event); PackageManagerCore *packageManagerCore() const { return m_core; } void executeControlScript(int pageId); private: class Private; Private *const d; PackageManagerCore *m_core; QListWidget *m_pageListWidget; }; // -- PackageManagerPage class INSTALLER_EXPORT PackageManagerPage : public QWizardPage { Q_OBJECT public: explicit PackageManagerPage(PackageManagerCore *core); virtual ~PackageManagerPage() {} virtual QPixmap logoPixmap() const; virtual QString productName() const; virtual QPixmap watermarkPixmap() const; virtual QPixmap bannerPixmap() const; void setColoredTitle(const QString &title); void setColoredSubTitle(const QString &subTitle); void setPageListTitle(const QString &title); QString pageListTitle() const; void setShowOnPageList(bool show); bool showOnPageList() const; virtual bool isComplete() const; void setComplete(bool complete); virtual bool isInterruptible() const { return false; } PackageManagerGui* gui() const { return qobject_cast<PackageManagerGui*>(wizard()); } void setValidatePageComponent(QInstaller::Component *component); bool validatePage(); bool settingsButtonRequested() const { return m_needsSettingsButton; } void setSettingsButtonRequested(bool request) { m_needsSettingsButton = request; } void removeCustomWidget(const QWidget *widget); signals: void entered(); void left(); void showOnPageListChanged(); protected: PackageManagerCore *packageManagerCore() const; // Inserts widget into the same layout like a sibling identified // by its name. Default position is just behind the sibling. virtual void insertWidget(QWidget *widget, const QString &siblingName, int offset = 1); virtual QWidget *findWidget(const QString &objectName) const; virtual int nextId() const; // reimp // Used to support some kind of initializePage() in the case the wizard has been set // to QWizard::IndependentPages. If that option has been set, initializePage() would be only // called once. So we provide entering() and leaving() based on currentPageChanged() signal. virtual void entering() {} // called on entering virtual void leaving() {} // called on leaving private: bool m_complete; QString m_titleColor; QString m_pageListTitle; bool m_showOnPageList; bool m_needsSettingsButton; PackageManagerCore *m_core; QInstaller::Component *validatorComponent; QMultiMap<int, QWidget*> m_customWidgets; friend class PackageManagerGui; }; // -- IntroductionPage class INSTALLER_EXPORT IntroductionPage : public PackageManagerPage { Q_OBJECT public: explicit IntroductionPage(PackageManagerCore *core); void setText(const QString &text); int nextId() const; bool validatePage(); void showAll(); void hideAll(); void showMetaInfoUpdate(); void showMaintenanceTools(); void setMaintenanceToolsEnabled(bool enable); public Q_SLOTS: void onCoreNetworkSettingsChanged(); void setMessage(const QString &msg); void onProgressChanged(int progress); void setTotalProgress(int totalProgress); void setErrorMessage(const QString &error); Q_SIGNALS: void packageManagerCoreTypeChanged(); private Q_SLOTS: void setUpdater(bool value); void setUninstaller(bool value); void setPackageManager(bool value); private: void initializePage(); void entering(); void leaving(); void showWidgets(bool show); bool validRepositoriesAvailable() const; private: bool m_updatesFetched; bool m_allPackagesFetched; QLabel *m_label; QLabel *m_msgLabel; QLabel *m_errorLabel; QProgressBar *m_progressBar; QRadioButton *m_packageManager; QRadioButton *m_updateComponents; QRadioButton *m_removeAllComponents; #ifdef Q_OS_WIN QWinTaskbarButton *m_taskButton; #endif }; // -- LicenseAgreementPage class INSTALLER_EXPORT LicenseAgreementPage : public PackageManagerPage { Q_OBJECT class ClickForwarder; public: explicit LicenseAgreementPage(PackageManagerCore *core); void entering(); bool isComplete() const; private Q_SLOTS: void openLicenseUrl(const QUrl &url); void currentItemChanged(QListWidgetItem *current); private: void addLicenseItem(const QHash<QString, QPair<QString, QString> > &hash); void updateUi(); private: QTextBrowser *m_textBrowser; QListWidget *m_licenseListWidget; QRadioButton *m_acceptRadioButton; QRadioButton *m_rejectRadioButton; QLabel *m_acceptLabel; QLabel *m_rejectLabel; }; // -- ComponentSelectionPage class INSTALLER_EXPORT ComponentSelectionPage : public PackageManagerPage { Q_OBJECT public: explicit ComponentSelectionPage(PackageManagerCore *core); ~ComponentSelectionPage(); bool isComplete() const; Q_INVOKABLE void selectAll(); Q_INVOKABLE void deselectAll(); Q_INVOKABLE void selectDefault(); Q_INVOKABLE void selectComponent(const QString &id); Q_INVOKABLE void deselectComponent(const QString &id); Q_INVOKABLE void allowCompressedRepositoryInstall(); Q_INVOKABLE bool addVirtualComponentToUninstall(const QString &name); protected: void entering(); void leaving(); void showEvent(QShowEvent *event); private Q_SLOTS: void setModified(bool modified); private: friend class ComponentSelectionPagePrivate; ComponentSelectionPagePrivate *const d; }; // -- TargetDirectoryPage class INSTALLER_EXPORT TargetDirectoryPage : public PackageManagerPage { Q_OBJECT public: explicit TargetDirectoryPage(PackageManagerCore *core); QString targetDir() const; void setTargetDir(const QString &dirName); void initializePage(); bool validatePage(); bool isComplete() const; protected: void entering(); void leaving(); private Q_SLOTS: void dirRequested(); private: QString targetDirWarning() const; private: QLineEdit *m_lineEdit; QLabel *m_warningLabel; QTimer m_textChangeTimer; }; // -- StartMenuDirectoryPage class INSTALLER_EXPORT StartMenuDirectoryPage : public PackageManagerPage { Q_OBJECT public: explicit StartMenuDirectoryPage(PackageManagerCore *core); QString startMenuDir() const; void setStartMenuDir(const QString &startMenuDir); protected: void leaving(); private Q_SLOTS: void currentItemChanged(QListWidgetItem* current); private: QString startMenuPath; QLineEdit *m_lineEdit; QListWidget *m_listWidget; }; // -- ReadyForInstallationPage class INSTALLER_EXPORT ReadyForInstallationPage : public PackageManagerPage { Q_OBJECT public: explicit ReadyForInstallationPage(PackageManagerCore *core); protected: void entering(); void leaving(); private Q_SLOTS: void updatePageListTitle(); private: QLabel *m_msgLabel; QTextBrowser* m_taskDetailsBrowser; }; // -- PerformInstallationPage class INSTALLER_EXPORT PerformInstallationPage : public PackageManagerPage { Q_OBJECT public: explicit PerformInstallationPage(PackageManagerCore *core); ~PerformInstallationPage(); bool isAutoSwitching() const; protected: void entering(); void leaving(); bool isInterruptible() const { return true; } public Q_SLOTS: void setTitleMessage(const QString& title); void changeCurrentImage(); Q_SIGNALS: void setAutomatedPageSwitchEnabled(bool request); private Q_SLOTS: void installationStarted(); void installationFinished(); void uninstallationStarted(); void uninstallationFinished(); void toggleDetailsWereChanged(); void updatePageListTitle(); private: PerformInstallationForm *m_performInstallationForm; QTimer m_imageChangeTimer; QString m_currentImage; }; // -- FinishedPage class INSTALLER_EXPORT FinishedPage : public PackageManagerPage { Q_OBJECT public: explicit FinishedPage(PackageManagerCore *core); public Q_SLOTS: void handleFinishClicked(); void cleanupChangedConnects(); protected: void entering(); void leaving(); private: QLabel *m_msgLabel; QCheckBox *m_runItCheckBox; QAbstractButton *m_commitButton; }; // -- RestartPage class INSTALLER_EXPORT RestartPage : public PackageManagerPage { Q_OBJECT public: explicit RestartPage(PackageManagerCore *core); virtual int nextId() const; protected: void entering(); void leaving(); Q_SIGNALS: void restart(); }; } //namespace QInstaller #endif // PACKAGEMANAGERGUI_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagemanagerpagefactory.cpp�����������������������0100777�0000000�0000000�00000003042�13761647206�024473� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include <packagemanagerpagefactory.h> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::PackageManagerPageFactory \internal */ PackageManagerPageFactory &PackageManagerPageFactory::instance() { static PackageManagerPageFactory factory; return factory; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagemanagerpagefactory.h�������������������������0100777�0000000�0000000�00000003723�13761647206�024146� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGERPAGEFACTORY_H #define PACKAGEMANAGERPAGEFACTORY_H #include "genericfactory.h" #include "qinstallerglobal.h" namespace QInstaller { class PackageManagerCore; class PackageManagerPage; class INSTALLER_EXPORT PackageManagerPageFactory : public GenericFactory<PackageManagerPage, int, PackageManagerCore*> { Q_DISABLE_COPY(PackageManagerPageFactory) public: static PackageManagerPageFactory &instance(); template<typename T> void registerPackageManagerPage(int id) { registerProduct<T>(id); } private: PackageManagerPageFactory() = default; }; } // namespace QInstaller #endif // PACKAGEMANAGERPAGEFACTORY_H ���������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagemanagerproxyfactory.cpp����������������������0100777�0000000�0000000�00000011261�13761647206�024742� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "packagemanagerproxyfactory.h" #include "packagemanagercore.h" #include "settings.h" #include <QNetworkProxy> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::PackageManagerProxyFactory \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::ProxyCredential \internal */ PackageManagerProxyFactory::PackageManagerProxyFactory(const PackageManagerCore *const core) : m_core(core) { } PackageManagerProxyFactory *PackageManagerProxyFactory::clone() const { PackageManagerProxyFactory *factory = new PackageManagerProxyFactory(m_core); factory->m_proxyCredentials = m_proxyCredentials; return factory; } struct FindProxyCredential { FindProxyCredential(const QString &host, int port) : host(host), port(port) {} bool operator()(const ProxyCredential &c) { return c.host == host && c.port == port; } private: QString host; int port; }; QList<QNetworkProxy> PackageManagerProxyFactory::queryProxy(const QNetworkProxyQuery &query) { const Settings &settings = m_core->settings(); QList<QNetworkProxy> list; if (settings.proxyType() == Settings::SystemProxy) { QList<QNetworkProxy> systemProxies = systemProxyForQuery(query); auto proxyIter = systemProxies.begin(); for (; proxyIter != systemProxies.end(); ++proxyIter) { QNetworkProxy &proxy = *proxyIter; auto p = std::find_if(m_proxyCredentials.constBegin(), m_proxyCredentials.constEnd(), FindProxyCredential(proxy.hostName(), proxy.port())); if (p != m_proxyCredentials.constEnd()) { proxy.setUser(p->user); proxy.setPassword(p->password); } } return systemProxies; } if ((settings.proxyType() == Settings::NoProxy)) return list << QNetworkProxy(QNetworkProxy::NoProxy); if (query.queryType() == QNetworkProxyQuery::UrlRequest) { QNetworkProxy proxy; if (query.url().scheme() == QLatin1String("ftp")) { proxy = settings.ftpProxy(); } else if (query.url().scheme() == QLatin1String("http") || query.url().scheme() == QLatin1String("https")) { proxy = settings.httpProxy(); } auto p = std::find_if(m_proxyCredentials.constBegin(), m_proxyCredentials.constEnd(), FindProxyCredential(proxy.hostName(), proxy.port())); if (p != m_proxyCredentials.constEnd()) { proxy.setUser(p->user); proxy.setPassword(p->password); } return list << proxy; } return list << QNetworkProxy(QNetworkProxy::DefaultProxy); } void PackageManagerProxyFactory::setProxyCredentials(const QNetworkProxy &proxy, const QString &user, const QString &password) { auto p = std::find_if(m_proxyCredentials.begin(), m_proxyCredentials.end(), FindProxyCredential(proxy.hostName(), proxy.port())); if (p == m_proxyCredentials.end()) { ProxyCredential proxyCredential; proxyCredential.host = proxy.hostName(); proxyCredential.port = proxy.port(); proxyCredential.user = user; proxyCredential.password = password; m_proxyCredentials.append(proxyCredential); } else { p->user = user; p->password = password; } } } // QInstaller �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagemanagerproxyfactory.h������������������������0100777�0000000�0000000�00000004070�13761647206�024407� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGERPROXYFACTORY_H #define PACKAGEMANAGERPROXYFACTORY_H #include "filedownloaderfactory.h" namespace QInstaller { class PackageManagerCore; struct ProxyCredential { QString host; QString user; QString password; int port; }; class PackageManagerProxyFactory : public KDUpdater::FileDownloaderProxyFactory { public: explicit PackageManagerProxyFactory(const PackageManagerCore *const core); PackageManagerProxyFactory *clone() const; QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()); void setProxyCredentials(const QNetworkProxy &proxy, const QString &user, const QString &password); private: QList<ProxyCredential> m_proxyCredentials; const PackageManagerCore *const m_core; }; } // QInstaller #endif // PACKAGEMANAGERPROXYFACTORY_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/packagesource.cpp�����������������������������������0100777�0000000�0000000�00000006752�13761647206�022147� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "packagesource.h" namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::PackageSource \brief The PackageSource class specifies a single package source. An package source represents a link to an repository that contains packages applicable by the installer or package maintenance application. This structure describes a single package source in terms of url and priority. While different repositories can host the same packages, packages coming from a higher priority source take precedence over lower priority packages during applicable package computation. */ /*! \fn QInstaller::PackageSource::PackageSource() Constructs an empty package source info object. The object's priority is set to -1. The url is initialized using a \l{default-constructed value}. */ /*! \fn QInstaller::PackageSource::PackageSource(const QUrl &u, int p) Constructs a package source info object. The object's url is set to \a u, while the priority is set to \a p. */ /*! \variable PackageSource::url \brief The URL of the package source. */ /*! \variable PackageSource::priority \brief The priority of the package source. */ /*! Returns the hash value for the \a key, using \a seed to seed the calculation. */ uint qHash(const PackageSource &key, uint seed) { return qHash(key.url, seed) ^ key.priority; } /*! Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false. */ bool operator==(const PackageSource &lhs, const PackageSource &rhs) { return lhs.url == rhs.url && lhs.priority == rhs.priority; } } // namespace QInstaller ����������������������qt-installer-framework-4.0.1/src/libs/installer/packagesource.h�������������������������������������0100777�0000000�0000000�00000004617�13761647206�021612� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGESOURCE_H #define PACKAGESOURCE_H #include "installer_global.h" #include <QUrl> namespace QInstaller { struct INSTALLER_EXPORT PackageSource { PackageSource() : priority(-1) {} PackageSource(const QUrl &u, int p) : url(u) , priority(p) {} QUrl url; int priority; }; INSTALLER_EXPORT uint qHash(const PackageSource &key, uint seed); INSTALLER_EXPORT bool operator==(const PackageSource &lhs, const PackageSource &rhs); } // namespace QInstaller #endif // PACKAGESOURCE_H �����������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/performinstallationform.cpp�������������������������0100777�0000000�0000000�00000024141�13761647206�024303� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "performinstallationform.h" #include "lazyplaintextedit.h" #include "progresscoordinator.h" #include "globals.h" #include <QApplication> #include <QLabel> #include <QProgressBar> #include <QPushButton> #include <QScrollBar> #include <QVBoxLayout> #include <QImageReader> #include <QScrollArea> #include <QtCore/QTimer> #ifdef Q_OS_WIN # include <QWinTaskbarButton> # include <QWinTaskbarProgress> #endif using namespace QInstaller; // -- PerformInstallationForm /*! \class QInstaller::PerformInstallationForm \inmodule QtInstallerFramework \brief The PerformInstallationForm class shows progress information about the installation state. A progress bar indicates the progress of the installation, update, or uninstallation. The page contains a button for showing or hiding detailed information about the progress in an \e {details browser}. The text on the button changes depending on whether the details browser is currently shown or hidden. */ /*! \fn QInstaller::PerformInstallationForm::showDetailsChanged() This signal is emitted when the end users select the details button to show or hide progress details. */ /*! Constructs the perform installation UI with \a parent as parent. */ PerformInstallationForm::PerformInstallationForm(QObject *parent) : QObject(parent) , m_progressBar(nullptr) , m_progressLabel(nullptr) , m_productImagesScrollArea(nullptr) , m_productImagesLabel(nullptr) , m_detailsButton(nullptr) , m_detailsBrowser(nullptr) , m_updateTimer(nullptr) { #ifdef Q_OS_WIN if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { m_taskButton = new QWinTaskbarButton(this); m_taskButton->progress()->setVisible(true); } else { m_taskButton = nullptr; } #endif } /*! Sets up the perform installation UI specified by \a widget. */ void PerformInstallationForm::setupUi(QWidget *widget) { QVBoxLayout *baseLayout = new QVBoxLayout(widget); baseLayout->setObjectName(QLatin1String("BaseLayout")); QVBoxLayout *topLayout = new QVBoxLayout(); topLayout->setObjectName(QLatin1String("TopLayout")); m_progressBar = new QProgressBar(widget); m_progressBar->setRange(1, 100); m_progressBar->setObjectName(QLatin1String("ProgressBar")); topLayout->addWidget(m_progressBar); m_progressLabel = new QLabel(widget); m_progressLabel->setObjectName(QLatin1String("ProgressLabel")); m_progressLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); topLayout->addWidget(m_progressLabel); m_downloadStatus = new QLabel(widget); m_downloadStatus->setObjectName(QLatin1String("DownloadStatus")); m_downloadStatus->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); topLayout->addWidget(m_downloadStatus); connect(ProgressCoordinator::instance(), &ProgressCoordinator::downloadStatusChanged, this, &PerformInstallationForm::onDownloadStatusChanged); m_detailsButton = new QPushButton(tr("&Show Details"), widget); m_detailsButton->setObjectName(QLatin1String("DetailsButton")); m_detailsButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); connect(m_detailsButton, &QAbstractButton::clicked, this, &PerformInstallationForm::toggleDetails); topLayout->addWidget(m_detailsButton); QVBoxLayout *bottomLayout = new QVBoxLayout(); bottomLayout->setObjectName(QLatin1String("BottomLayout")); bottomLayout->addStretch(); m_productImagesScrollArea = new QScrollArea(widget); m_productImagesScrollArea->setObjectName(QLatin1String("ProductImagesScrollArea")); m_productImagesScrollArea->setWidgetResizable(true); m_productImagesScrollArea->setFrameShape(QFrame::NoFrame); m_productImagesScrollArea->setStyleSheet(QLatin1String("background-color:transparent;")); m_productImagesLabel = new AspectRatioLabel(widget); m_productImagesLabel->setObjectName(QLatin1String("ProductImagesLabel")); m_productImagesScrollArea->setWidget(m_productImagesLabel); bottomLayout->addWidget(m_productImagesScrollArea); m_detailsBrowser = new LazyPlainTextEdit(widget); m_detailsBrowser->setReadOnly(true); m_detailsBrowser->setWordWrapMode(QTextOption::NoWrap); m_detailsBrowser->setObjectName(QLatin1String("DetailsBrowser")); m_detailsBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); bottomLayout->addWidget(m_detailsBrowser); bottomLayout->setStretch(1, 10); bottomLayout->setStretch(2, 10); baseLayout->addLayout(topLayout); baseLayout->addLayout(bottomLayout); m_updateTimer = new QTimer(widget); connect(m_updateTimer, &QTimer::timeout, this, &PerformInstallationForm::updateProgress); //updateProgress includes label m_updateTimer->setInterval(30); m_progressBar->setRange(0, 100); } /*! Shows the details button if \a visible is \c true. */ void PerformInstallationForm::setDetailsWidgetVisible(bool visible) { m_detailsButton->setVisible(visible); } /*! Displays \a details about progress of the installation in the details browser. */ void PerformInstallationForm::appendProgressDetails(const QString &details) { m_detailsBrowser->append(details); } /*! Updates the progress of the installation on the progress bar. */ void PerformInstallationForm::updateProgress() { QInstaller::ProgressCoordinator *progressCoordninator = QInstaller::ProgressCoordinator::instance(); const int progressPercentage = progressCoordninator->progressInPercentage(); m_progressBar->setValue(progressPercentage); #ifdef Q_OS_WIN if (m_taskButton) { if (!m_taskButton->window() && QApplication::activeWindow()) m_taskButton->setWindow(QApplication::activeWindow()->windowHandle()); m_taskButton->progress()->setValue(progressPercentage); } #endif static QString lastLabelText; if (lastLabelText == progressCoordninator->labelText()) return; lastLabelText = progressCoordninator->labelText(); m_progressLabel->setText(m_progressLabel->fontMetrics().elidedText(progressCoordninator->labelText(), Qt::ElideRight, m_progressLabel->width())); } /*! Sets the text of the details button to \uicontrol {Hide Details} or \uicontrol {Show Details} depending on whether the details are currently shown or hidden. Emits the showDetailsChanged() signal. */ void PerformInstallationForm::toggleDetails() { const bool willShow = !isShowingDetails(); m_detailsButton->setText(willShow ? tr("&Hide Details") : tr("&Show Details")); m_detailsBrowser->setVisible(willShow); m_productImagesScrollArea->setVisible(!willShow); emit showDetailsChanged(); } /*! Clears the contents of the details browser. */ void PerformInstallationForm::clearDetailsBrowser() { m_detailsBrowser->clear(); } /*! Enables the details button with the text \uicontrol {Show Details} and hides the details browser. */ void PerformInstallationForm::enableDetails() { m_detailsButton->setEnabled(true); m_detailsButton->setText(tr("&Show Details")); m_detailsBrowser->setVisible(false); m_productImagesScrollArea->setVisible(true); } /*! Starts the update progress timer. */ void PerformInstallationForm::startUpdateProgress() { m_updateTimer->start(); updateProgress(); } /*! Stops the update progress timer. */ void PerformInstallationForm::stopUpdateProgress() { m_updateTimer->stop(); updateProgress(); } /*! Enables the details button if \a enable is \c true. */ void PerformInstallationForm::setDetailsButtonEnabled(bool enable) { m_detailsButton->setEnabled(enable); } /*! Scrolls to the bottom of the details browser. */ void PerformInstallationForm::scrollDetailsToTheEnd() { m_detailsBrowser->updateCursor(LazyPlainTextEdit::TextCursorPosition::ForceEnd); } /*! Returns \c true if the details browser is visible. */ bool PerformInstallationForm::isShowingDetails() const { return m_detailsBrowser->isVisible(); } /*! Changes the label text according to the changes in the download status specified by \a status. */ void PerformInstallationForm::onDownloadStatusChanged(const QString &status) { m_downloadStatus->setText(m_downloadStatus->fontMetrics().elidedText(status, Qt::ElideRight, m_downloadStatus->width())); } /*! Sets currently shown form image specified by \a fileName. */ void PerformInstallationForm::setImageFromFileName(const QString &fileName) { if (!QFile::exists(fileName)) { qCWarning(QInstaller::lcDeveloperBuild) << "Image file does not exist:" << fileName; return; } QImageReader reader(fileName); QPixmap pixmap = QPixmap::fromImageReader(&reader); if (!pixmap.isNull()) { m_productImagesLabel->setPixmap(pixmap); } else { qCWarning(QInstaller::lcDeveloperBuild) << QString::fromLatin1("Failed to load image '%1' : %2.").arg(fileName, reader.errorString()); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/performinstallationform.h���������������������������0100777�0000000�0000000�00000005264�13761647206�023755� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PERFORMINSTALLATIONFORM_H #define PERFORMINSTALLATIONFORM_H #include "aspectratiolabel.h" #include <QObject> QT_BEGIN_NAMESPACE class QLabel; class QProgressBar; class QPushButton; class QTimer; class QWidget; class QWinTaskbarButton; class QScrollArea; QT_END_NAMESPACE class LazyPlainTextEdit; namespace QInstaller { class PerformInstallationForm : public QObject { Q_OBJECT public: explicit PerformInstallationForm(QObject *parent); void setupUi(QWidget *widget); void setDetailsWidgetVisible(bool visible); void enableDetails(); void startUpdateProgress(); void stopUpdateProgress(); void setDetailsButtonEnabled(bool enable); void scrollDetailsToTheEnd(); bool isShowingDetails() const; signals: void showDetailsChanged(); public slots: void appendProgressDetails(const QString &details); void updateProgress(); void toggleDetails(); void clearDetailsBrowser(); void onDownloadStatusChanged(const QString &status); void setImageFromFileName(const QString &fileName); private: QProgressBar *m_progressBar; QLabel *m_progressLabel; QLabel *m_downloadStatus; QScrollArea *m_productImagesScrollArea; AspectRatioLabel *m_productImagesLabel; QPushButton *m_detailsButton; LazyPlainTextEdit *m_detailsBrowser; QTimer *m_updateTimer; #ifdef Q_OS_WIN QWinTaskbarButton *m_taskButton; #endif }; } // namespace QInstaller #endif // PERFORMINSTALLATIONFORM_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/permissionsettings.cpp������������������������������0100777�0000000�0000000�00000003175�13761647206�023300� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "permissionsettings.h" #include <QFile> using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::PermissionSettings \internal */ PermissionSettings::~PermissionSettings() { if (!fileName().isEmpty()) { sync(); QFile file(fileName()); file.setPermissions(file.permissions() | QFile::ReadGroup | QFile::ReadOther); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/permissionsettings.h��������������������������������0100777�0000000�0000000�00000004265�13761647206�022746� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PERMISSIONSETTINGS_H #define PERMISSIONSETTINGS_H #include <QSettings> namespace QInstaller { class PermissionSettings : public QSettings { public: explicit PermissionSettings(const QString &organization, const QString &application = QString(), QObject *parent = 0) : QSettings(organization, application, parent) {} PermissionSettings(Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = 0) : QSettings(scope, organization, application, parent) {} PermissionSettings(Format format, Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = 0) : QSettings(format, scope, organization, application, parent) {} PermissionSettings(const QString &fileName, Format format, QObject *parent = 0) : QSettings(fileName, format, parent) {} ~PermissionSettings(); }; } #endif // PERMISSIONSETTINGS_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/productkeycheck.cpp���������������������������������0100777�0000000�0000000�00000005071�13761647206�022513� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "productkeycheck.h" #include "packagemanagercore.h" class ProductKeyCheckPrivate { }; ProductKeyCheck::ProductKeyCheck() : d(new ProductKeyCheckPrivate()) { } ProductKeyCheck::~ProductKeyCheck() { delete d; } ProductKeyCheck *ProductKeyCheck::instance() { static ProductKeyCheck instance; return &instance; } void ProductKeyCheck::init(QInstaller::PackageManagerCore *core) { Q_UNUSED(core) } bool ProductKeyCheck::hasValidKey() { return true; } bool ProductKeyCheck::applyKey(const QStringList &/*arguments*/) { return true; } QString ProductKeyCheck::lastErrorString() { return QString(); } QString ProductKeyCheck::maintainanceToolDetailErrorNotice() { return QString(); } // to filter none valid licenses bool ProductKeyCheck::isValidLicenseTextFile(const QString &/*fileName*/) { return true; } bool ProductKeyCheck::isValidRepository(const QInstaller::Repository &repository) const { Q_UNUSED(repository) return true; } void ProductKeyCheck::addPackagesFromXml(const QString &xmlPath) { Q_UNUSED(xmlPath) } bool ProductKeyCheck::isValidPackage(const QString &packageName) const { Q_UNUSED(packageName) return true; } QList<int> ProductKeyCheck::registeredPages() const { return QList<int>(); } bool ProductKeyCheck::hasValidLicense() const { return true; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/productkeycheck.h�����������������������������������0100777�0000000�0000000�00000004466�13761647206�022167� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PRODUCTKEYCHECK_H #define PRODUCTKEYCHECK_H #include "installer_global.h" #include <QString> namespace QInstaller { class PackageManagerCore; class Repository; } // QInstaller class INSTALLER_EXPORT ProductKeyCheck { Q_DISABLE_COPY(ProductKeyCheck) public: ~ProductKeyCheck(); static ProductKeyCheck *instance(); void init(QInstaller::PackageManagerCore *core); // was validLicense bool hasValidKey(); QString lastErrorString(); QString maintainanceToolDetailErrorNotice(); bool applyKey(const QStringList &arguments); // to filter none valid licenses bool isValidLicenseTextFile(const QString &fileName); // to filter repositories not matching the license bool isValidRepository(const QInstaller::Repository &repository) const; void addPackagesFromXml(const QString &xmlPath); bool isValidPackage(const QString &packageName) const; QList<int> registeredPages() const; bool hasValidLicense() const; private: ProductKeyCheck(); class ProductKeyCheckPrivate *const d; }; #endif // PRODUCTKEYCHECK_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/progresscoordinator.cpp�����������������������������0100777�0000000�0000000�00000027243�13761647206�023441� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "progresscoordinator.h" #include <iostream> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include "globals.h" #include "utils.h" using namespace QInstaller; QT_BEGIN_NAMESPACE uint qHash(QPointer<QObject> key) { return qHash(key.data()); } QT_END_NAMESPACE ProgressCoordinator::ProgressCoordinator(QObject *parent) : QObject(parent) , m_currentCompletePercentage(0) , m_currentBasePercentage(0) , m_manualAddedPercentage(0) , m_reservedPercentage(0) , m_undoMode(false) , m_reachedPercentageBeforeUndo(0) { // it has to be in the main thread to be able refresh the ui with processEvents Q_ASSERT(thread() == qApp->thread()); m_progressSpinner = new ProgressSpinner(); } ProgressCoordinator::~ProgressCoordinator() { delete m_progressSpinner; m_progressSpinner = nullptr; } ProgressCoordinator *ProgressCoordinator::instance() { static ProgressCoordinator *instance =nullptr; if (instance == nullptr) instance = new ProgressCoordinator(qApp); return instance; } void ProgressCoordinator::reset() { disconnectAllSenders(); m_installationLabelText.clear(); m_currentCompletePercentage = 0; m_currentBasePercentage = 0; m_manualAddedPercentage = 0; m_reservedPercentage = 0; m_undoMode = false; m_reachedPercentageBeforeUndo = 0; emit detailTextResetNeeded(); } void ProgressCoordinator::registerPartProgress(QObject *sender, const char *signal, double partProgressSize) { Q_ASSERT(sender); Q_ASSERT(QString::fromLatin1(signal).contains(QLatin1String("(double)"))); Q_ASSERT(partProgressSize <= 1); m_senderPartProgressSizeHash.insert(sender, partProgressSize); bool isConnected = connect(sender, signal, this, SLOT(partProgressChanged(double))); Q_UNUSED(isConnected); Q_ASSERT(isConnected); } /*! This slot gets the progress changed signals from different tasks. The \a fraction values 0 and 1 are handled as special values. 0 - is just ignored, so you can use a timer which gives the progress, e.g. like a downloader does. 1 - means the task is finished, even if there comes another 1 from that task, so it will be ignored. */ void ProgressCoordinator::partProgressChanged(double fraction) { if (fraction < 0 || fraction > 1) { qCWarning(QInstaller::lcInstallerInstallLog) << "The fraction is outside from possible value:" << fraction; return; } // no fraction no change if (fraction == 0) return; // ignore senders sending 100% multiple times if (fraction == 1 && m_senderPendingCalculatedPercentageHash.contains(sender()) && m_senderPendingCalculatedPercentageHash.value(sender()) == 0) { return; } double partProgressSize = m_senderPartProgressSizeHash.value(sender(), 0); if (partProgressSize == 0) { qCWarning(QInstaller::lcInstallerInstallLog) << "It seems that this sender was not registered " "in the right way:" << sender(); return; } if (m_undoMode) { double maxSize = m_reachedPercentageBeforeUndo * partProgressSize; double pendingCalculatedPartPercentage = maxSize * fraction; // allPendingCalculatedPartPercentages has negative values double newCurrentCompletePercentage = m_currentBasePercentage - pendingCalculatedPartPercentage + allPendingCalculatedPartPercentages(sender()); //we can't check this here, because some round issues can make it little bit under 0 or over 100 //Q_ASSERT(newCurrentCompletePercentage >= 0); //Q_ASSERT(newCurrentCompletePercentage <= 100); if (newCurrentCompletePercentage < 0) { qCDebug(QInstaller::lcDeveloperBuild) << newCurrentCompletePercentage << "is smaller than 0 " "- this should not happen more than once"; newCurrentCompletePercentage = 0; } if (newCurrentCompletePercentage > 100) { qCDebug(QInstaller::lcDeveloperBuild) << newCurrentCompletePercentage << "is bigger than 100 " "- this should not happen more than once"; newCurrentCompletePercentage = 100; } // In undo mode, the progress has to go backward, new has to be smaller than current if (qRound(m_currentCompletePercentage) < qRound(newCurrentCompletePercentage)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Something is wrong with the calculation " "of the progress."; } m_currentCompletePercentage = newCurrentCompletePercentage; if (fraction == 1) { m_currentBasePercentage = m_currentBasePercentage - pendingCalculatedPartPercentage; m_senderPendingCalculatedPercentageHash.insert(sender(), 0); } else { m_senderPendingCalculatedPercentageHash.insert(sender(), pendingCalculatedPartPercentage); } } else { //if (m_undoMode) int availablePercentagePoints = 100 - m_manualAddedPercentage - m_reservedPercentage; double pendingCalculatedPartPercentage = availablePercentagePoints * partProgressSize * fraction; //double checkValue = allPendingCalculatedPartPercentages(sender()); double newCurrentCompletePercentage = m_manualAddedPercentage + m_currentBasePercentage + pendingCalculatedPartPercentage + allPendingCalculatedPartPercentages(sender()); //we can't check this here, because some round issues can make it little bit under 0 or over 100 //Q_ASSERT(newCurrentCompletePercentage >= 0); //Q_ASSERT(newCurrentCompletePercentage <= 100); if (newCurrentCompletePercentage < 0) { qCDebug(QInstaller::lcDeveloperBuild) << newCurrentCompletePercentage << "is smaller than 0 " "- this should not happen more than once"; newCurrentCompletePercentage = 0; } if (newCurrentCompletePercentage > 100) { qCDebug(QInstaller::lcDeveloperBuild) << newCurrentCompletePercentage << "is bigger than 100 " "- this should not happen more than once"; newCurrentCompletePercentage = 100; } // In normal mode, the progress has to go forward, new has to be larger than current if (qRound(m_currentCompletePercentage) > qRound(newCurrentCompletePercentage)) qCWarning(QInstaller::lcInstallerInstallLog) << "Something is wrong with the calculation of the progress."; m_currentCompletePercentage = newCurrentCompletePercentage; if (fraction == 1) { m_currentBasePercentage = m_currentBasePercentage + pendingCalculatedPartPercentage; m_senderPendingCalculatedPercentageHash.insert(sender(), 0); } else { m_senderPendingCalculatedPercentageHash.insert(sender(), pendingCalculatedPartPercentage); } } //if (m_undoMode) printProgressPercentage(progressInPercentage()); } /*! Contains the installation progress percentage. */ int ProgressCoordinator::progressInPercentage() const { int currentValue = qRound(m_currentCompletePercentage); Q_ASSERT( currentValue <= 100); Q_ASSERT( currentValue >= 0); return currentValue; } void ProgressCoordinator::disconnectAllSenders() { foreach (QPointer<QObject> sender, m_senderPartProgressSizeHash.keys()) { if (!sender.isNull()) { bool isDisconnected = sender->disconnect(this); Q_UNUSED(isDisconnected); Q_ASSERT(isDisconnected); } } m_senderPartProgressSizeHash.clear(); m_senderPendingCalculatedPercentageHash.clear(); } void ProgressCoordinator::setUndoMode() { Q_ASSERT(!m_undoMode); m_undoMode = true; disconnectAllSenders(); m_reachedPercentageBeforeUndo = progressInPercentage(); m_currentBasePercentage = m_reachedPercentageBeforeUndo; } void ProgressCoordinator::addManualPercentagePoints(int value) { m_manualAddedPercentage = m_manualAddedPercentage + value; if (m_undoMode) { //we don't do other things in the undomode, maybe later if the last percentage point comes to early return; } m_currentCompletePercentage = m_currentCompletePercentage + value; if (m_currentCompletePercentage > 100.0) m_currentCompletePercentage = 100.0; qApp->processEvents(); //makes the result available in the ui } void ProgressCoordinator::addReservePercentagePoints(int value) { m_reservedPercentage = m_reservedPercentage + value; } void ProgressCoordinator::setLabelText(const QString &text) { if (m_installationLabelText == text) return; m_installationLabelText = text; // Refresh both message & progress percentage on console // when the label text is changed printProgressMessage(text); printProgressPercentage(progressInPercentage()); } /*! Contains the installation progress label text. */ QString ProgressCoordinator::labelText() const { return m_installationLabelText; } void ProgressCoordinator::emitDetailTextChanged(const QString &text) { emit detailTextChanged(text); } void ProgressCoordinator::emitLabelAndDetailTextChanged(const QString &text) { emit detailTextChanged(text); setLabelText(QString(text).remove(QLatin1String("\n"))); qApp->processEvents(); //makes the result available in the ui } double ProgressCoordinator::allPendingCalculatedPartPercentages(QObject *excludeKeyObject) { double result = 0; QHash<QPointer<QObject>, double>::iterator it = m_senderPendingCalculatedPercentageHash.begin(); while (it != m_senderPendingCalculatedPercentageHash.end()) { if (it.key() != excludeKeyObject) result += it.value(); it++; } return result; } void ProgressCoordinator::emitDownloadStatus(const QString &status) { emit downloadStatusChanged(status); } void ProgressCoordinator::printProgressPercentage(int progress) { if (!isVerbose()) return; Q_ASSERT(m_progressSpinner->currentIndex < m_progressSpinner->spinnerChars.size()); QString formatted = QString::fromLatin1("[%1 %2%]").arg( m_progressSpinner->spinnerChars.at(m_progressSpinner->currentIndex), QString::number(progress)); qCDebug(QInstaller::lcProgressIndicator).noquote() << formatted; m_progressSpinner->currentIndex == (m_progressSpinner->spinnerChars.size() - 1) ? m_progressSpinner->currentIndex = 0 : m_progressSpinner->currentIndex++; } void ProgressCoordinator::printProgressMessage(const QString &message) { qCDebug(QInstaller::lcInstallerInstallLog).nospace().noquote() << message; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/progresscoordinator.h�������������������������������0100777�0000000�0000000�00000006405�13761647206�023103� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PROGRESSCOORDINATOR_H #define PROGRESSCOORDINATOR_H #include "installer_global.h" #include <QtCore/QHash> #include <QtCore/QObject> #include <QtCore/QPointer> namespace QInstaller { class INSTALLER_EXPORT ProgressCoordinator : public QObject { Q_OBJECT struct ProgressSpinner { ProgressSpinner() : spinnerChars(QLatin1String("/-\\|")) , currentIndex(0) {} const QString spinnerChars; quint8 currentIndex; }; public: static ProgressCoordinator *instance(); ~ProgressCoordinator(); void registerPartProgress(QObject *sender, const char *signal, double partProgressSize); public slots: void reset(); void setUndoMode(); QString labelText() const; void setLabelText(const QString &text); int progressInPercentage() const; void partProgressChanged(double fraction); void addManualPercentagePoints(int value); void addReservePercentagePoints(int value); void emitDetailTextChanged(const QString &text); void emitLabelAndDetailTextChanged(const QString &text); void emitDownloadStatus(const QString &status); void printProgressPercentage(int progress); void printProgressMessage(const QString &message); signals: void detailTextChanged(const QString &text); void detailTextResetNeeded(); void downloadStatusChanged(const QString &status); protected: explicit ProgressCoordinator(QObject *parent); private: double allPendingCalculatedPartPercentages(QObject *excludeKeyObject = 0); void disconnectAllSenders(); private: QHash<QPointer<QObject>, double> m_senderPendingCalculatedPercentageHash; QHash<QPointer<QObject>, double> m_senderPartProgressSizeHash; ProgressSpinner *m_progressSpinner; QString m_installationLabelText; double m_currentCompletePercentage; double m_currentBasePercentage; int m_manualAddedPercentage; int m_reservedPercentage; bool m_undoMode; double m_reachedPercentageBeforeUndo; }; } //namespace QInstaller #endif //PROGRESSCOORDINATOR_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/protocol.cpp����������������������������������������0100777�0000000�0000000�00000007135�13761647206�021170� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "protocol.h" #include <QIODevice> namespace QInstaller { typedef qint32 PackageSize; /*! \inmodule QtInstallerFramework \namespace Protocol \brief Contains values related to the internal client-server connection protocol. */ /*! \enum Protocol::Mode \value Debug \value Production */ /*! \enum Protocol::StartAs \value User \value SuperUser */ /*! Write a packet containing \a command and \a data to \a device. \note Both client and server need to have the same endianness. */ void sendPacket(QIODevice *device, const QByteArray &command, const QByteArray &data) { // use aliasing for writing payload size into bytes char payloadBytes[sizeof(PackageSize)]; PackageSize *payloadSize = reinterpret_cast<PackageSize*>(&payloadBytes); *payloadSize = command.size() + sizeof(char) + data.size(); QByteArray packet; packet.reserve(sizeof(PackageSize) + *payloadSize); packet.append(payloadBytes, sizeof(PackageSize)); packet.append(command); packet.append('\0'); packet.append(data); forever { const int bytesWritten = device->write(packet); Q_ASSERT(bytesWritten >= 0); if (bytesWritten == packet.size()) break; packet.remove(0, bytesWritten); } } /*! Reads a packet from \a device, and stores its content into \a command and \a data. Returns \c false if the packet in the device buffer is yet incomplete, \c true otherwise. \note Both client and server need to have the same endianness. */ bool receivePacket(QIODevice *device, QByteArray *command, QByteArray *data) { if (device->bytesAvailable() < static_cast<qint64>(sizeof(PackageSize))) return false; // read payload size char payloadBytes[sizeof(PackageSize)]; PackageSize *payloadSize = reinterpret_cast<PackageSize*>(&payloadBytes); device->read(payloadBytes, sizeof(PackageSize)); // not enough data yet? back off ... if (device->bytesAvailable() < *payloadSize) { for (int i = sizeof(PackageSize) - 1; i >= 0; --i) device->ungetChar(payloadBytes[i]); return false; } const QByteArray payload = device->read(*payloadSize); int separator = payload.indexOf('\0'); *command = payload.left(separator); *data = payload.right(payload.size() - separator - 1); return true; } } // namespace QInstaller �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/protocol.h������������������������������������������0100777�0000000�0000000�00000020751�13761647206�020634� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PROTOCOL_H #define PROTOCOL_H #include "installer_global.h" QT_FORWARD_DECLARE_CLASS(QIODevice) namespace QInstaller { namespace Protocol { enum struct Mode { Debug, Production }; const char ModeDebug[] = "DEBUG"; const char ModeProduction[] = "PRODUCTION"; enum struct StartAs { User, SuperUser }; const char DefaultSocket[] = "ifw_srv"; const char DefaultAuthorizationKey[] = "DefaultAuthorizationKey"; const char Create[] = "Create"; const char Destroy[] = "Destroy"; const char Shutdown[] = "Shutdown"; const char Authorize[] = "Authorize"; const char Reply[] = "Reply"; // QProcessWrapper const char QProcess[] = "QProcess"; const char QProcessCloseWriteChannel[] = "QProcess::closeWriteChannel"; const char QProcessExitCode[] = "QProcess::exitCode"; const char QProcessExitStatus[] = "QProcess::exitStatus"; const char QProcessKill[] = "QProcess::kill"; const char QProcessReadAll[] = "QProcess::readAll"; const char QProcessReadAllStandardOutput[] = "QProcess::readAllStandardOutput"; const char QProcessReadAllStandardError[] = "QProcess::readAllStandardError"; const char QProcessStartDetached[] = "QProcess::startDetached"; const char QProcessSetWorkingDirectory[] = "QProcess::setWorkingDirectory"; const char QProcessSetEnvironment[] = "QProcess::setEnvironment"; const char QProcessEnvironment[] = "QProcess::environment"; const char QProcessStart3Arg[] = "QProcess::start3"; const char QProcessStart2Arg[] = "QProcess::start2"; const char QProcessState[] = "QProcess::state"; const char QProcessTerminate[] = "QProcess::terminate"; const char QProcessWaitForFinished[] = "QProcess::waitForFinished"; const char QProcessWaitForStarted[] = "QProcess::waitForStarted"; const char QProcessWorkingDirectory[] = "QProcess::workingDirectory"; const char QProcessErrorString[] = "QProcess::errorString"; const char QProcessReadChannel[] = "QProcess::readChannel"; const char QProcessSetReadChannel[] = "QProcess::setReadChannel"; const char QProcessWrite[] = "QProcess::write"; const char QProcessProcessChannelMode[] = "QProcess::processChannelMode"; const char QProcessSetProcessChannelMode[] = "QProcess::setProcessChannelMode"; const char QProcessSetNativeArguments[] = "QProcess::setNativeArguments"; const char GetQProcessSignals[] = "GetQProcessSignals"; const char QProcessSignalBytesWritten[] = "QProcess::bytesWritten"; const char QProcessSignalAboutToClose[] = "QProcess::aboutToClose"; const char QProcessSignalReadChannelFinished[] = "QProcess::readChannelFinished"; const char QProcessSignalError[] = "QProcess::error"; const char QProcessSignalReadyReadStandardOutput[] = "QProcess::readyReadStandardOutput"; const char QProcessSignalReadyReadStandardError[] = "QProcess::readyReadStandardError"; const char QProcessSignalStarted[] = "QProcess::started"; const char QProcessSignalReadyRead[] = "QProcess::readyRead"; const char QProcessSignalStateChanged[] = "QProcess::stateChanged"; const char QProcessSignalFinished[] = "QProcess::finished"; // QSettingsWrapper const char QSettings[] = "QSettings"; const char QSettingsAllKeys[] = "QSettings::allKeys"; const char QSettingsBeginGroup[] = "QSettings::beginGroup"; const char QSettingsBeginWriteArray[] = "QSettings::beginWriteArray"; const char QSettingsBeginReadArray[] = "QSettings::beginReadArray"; const char QSettingsChildGroups[] = "QSettings::childGroups"; const char QSettingsChildKeys[] = "QSettings::childKeys"; const char QSettingsClear[] = "QSettings::clear"; const char QSettingsContains[] = "QSettings::contains"; const char QSettingsEndArray[] = "QSettings::endArray"; const char QSettingsEndGroup[] = "QSettings::endGroup"; const char QSettingsFallbacksEnabled[] = "QSettings::fallbacksEnabled"; const char QSettingsFileName[] = "QSettings::fileName"; const char QSettingsGroup[] = "QSettings::group"; const char QSettingsIsWritable[] = "QSettings::isWritable"; const char QSettingsRemove[] = "QSettings::remove"; const char QSettingsSetArrayIndex[] = "QSettings::setArrayIndex"; const char QSettingsSetFallbacksEnabled[] = "QSettings::setFallbacksEnabled"; const char QSettingsStatus[] = "QSettings::status"; const char QSettingsSync[] = "QSettings::sync"; const char QSettingsSetValue[] = "QSettings::setValue"; const char QSettingsValue[] = "QSettings::value"; const char QSettingsOrganizationName[] = "QSettings::organizationName"; const char QSettingsApplicationName[] = "QSettings::applicationName"; // RemoteFileEngine const char QAbstractFileEngine[] = "QAbstractFileEngine"; const char QAbstractFileEngineAtEnd[] = "QAbstractFileEngine::atEnd"; const char QAbstractFileEngineCaseSensitive[] = "QAbstractFileEngine::caseSensitive"; const char QAbstractFileEngineClose[] = "QAbstractFileEngine::close"; const char QAbstractFileEngineCopy[] = "QAbstractFileEngine::copy"; const char QAbstractFileEngineEntryList[] = "QAbstractFileEngine::entryList"; const char QAbstractFileEngineError[] = "QAbstractFileEngine::error"; const char QAbstractFileEngineErrorString[] = "QAbstractFileEngine::errorString"; const char QAbstractFileEngineFileFlags[] = "QAbstractFileEngine::fileFlags"; const char QAbstractFileEngineFileName[] = "QAbstractFileEngine::fileName"; const char QAbstractFileEngineFlush[] = "QAbstractFileEngine::flush"; const char QAbstractFileEngineHandle[] = "QAbstractFileEngine::handle"; const char QAbstractFileEngineIsRelativePath[] = "QAbstractFileEngine::isRelativePath"; const char QAbstractFileEngineIsSequential[] = "QAbstractFileEngine::isSequential"; const char QAbstractFileEngineLink[] = "QAbstractFileEngine::link"; const char QAbstractFileEngineMkdir[] = "QAbstractFileEngine::mkdir"; const char QAbstractFileEngineOpen[] = "QAbstractFileEngine::open"; const char QAbstractFileEngineOwner[] = "QAbstractFileEngine::owner"; const char QAbstractFileEngineOwnerId[] = "QAbstractFileEngine::ownerId"; const char QAbstractFileEnginePos[] = "QAbstractFileEngine::pos"; const char QAbstractFileEngineRead[] = "QAbstractFileEngine::read"; const char QAbstractFileEngineReadLine[] = "QAbstractFileEngine::readLine"; const char QAbstractFileEngineRemove[] = "QAbstractFileEngine::remove"; const char QAbstractFileEngineRename[] = "QAbstractFileEngine::rename"; const char QAbstractFileEngineRmdir[] = "QAbstractFileEngine::rmdir"; const char QAbstractFileEngineSeek[] = "QAbstractFileEngine::seek"; const char QAbstractFileEngineSetFileName[] = "QAbstractFileEngine::setFileName"; const char QAbstractFileEngineSetPermissions[] = "QAbstractFileEngine::setPermissions"; const char QAbstractFileEngineSetSize[] = "QAbstractFileEngine::setSize"; const char QAbstractFileEngineSize[] = "QAbstractFileEngine::size"; const char QAbstractFileEngineSupportsExtension[] = "QAbstractFileEngine::supportsExtension"; const char QAbstractFileEngineExtension[] = "QAbstractFileEngine::extension"; const char QAbstractFileEngineWrite[] = "QAbstractFileEngine::write"; const char QAbstractFileEngineSyncToDisk[] = "QAbstractFileEngine::syncToDisk"; const char QAbstractFileEngineRenameOverwrite[] = "QAbstractFileEngine::renameOverwrite"; const char QAbstractFileEngineFileTime[] = "QAbstractFileEngine::fileTime"; } // namespace Protocol void INSTALLER_EXPORT sendPacket(QIODevice *device, const QByteArray &command, const QByteArray &data); bool INSTALLER_EXPORT receivePacket(QIODevice *device, QByteArray *command, QByteArray *data); } // namespace QInstaller #endif // PROTOCOL_H �����������������������qt-installer-framework-4.0.1/src/libs/installer/proxycredentialsdialog.cpp��������������������������0100777�0000000�0000000�00000005152�13761647206�024103� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "proxycredentialsdialog.h" #include "ui_proxycredentialsdialog.h" #include <QNetworkProxy> namespace QInstaller { /*! \inmodule QtInstallerFramework \namespace Ui \brief Groups user interface forms generated with Qt Designer. */ /*! \inmodule QtInstallerFramework \class QInstaller::ProxyCredentialsDialog \internal */ ProxyCredentialsDialog::ProxyCredentialsDialog(const QNetworkProxy &proxy, QWidget *parent) : QDialog(parent), ui(new Ui::ProxyCredentialsDialog) { setWindowTitle(tr("Proxy Credentials")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->setupUi(this); setUserName(proxy.user()); setPassword(proxy.password()); const QString proxyString = QString::fromLatin1("%1:%2").arg(proxy.hostName()).arg(proxy.port()); ui->infotext->setText(ui->infotext->text().arg(proxyString)); } ProxyCredentialsDialog::~ProxyCredentialsDialog() { delete ui; } QString ProxyCredentialsDialog::userName() const { return ui->usernameLineEdit->text(); } void ProxyCredentialsDialog::setUserName(const QString &username) { ui->usernameLineEdit->setText(username); } QString ProxyCredentialsDialog::password() const { return ui->passwordLineEdit->text(); } void ProxyCredentialsDialog::setPassword(const QString &passwd) { ui->passwordLineEdit->setText(passwd); } } // namespace QInstaller ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/proxycredentialsdialog.h����������������������������0100777�0000000�0000000�00000003557�13761647206�023557� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PROXYCREDENTIALSDIALOG_H #define PROXYCREDENTIALSDIALOG_H #include <QDialog> QT_FORWARD_DECLARE_CLASS(QNetworkProxy) namespace QInstaller { namespace Ui { class ProxyCredentialsDialog; } class ProxyCredentialsDialog : public QDialog { Q_OBJECT public: explicit ProxyCredentialsDialog(const QNetworkProxy &proxy, QWidget *parent = 0); ~ProxyCredentialsDialog(); QString userName() const; void setUserName(const QString &username); QString password() const; void setPassword(const QString &passwd); private: Ui::ProxyCredentialsDialog *ui; }; } // QInstaller #endif // PROXYCREDENTIALSDIALOG_H �������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/proxycredentialsdialog.ui���������������������������0100777�0000000�0000000�00000005214�13761647206�023735� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QInstaller::ProxyCredentialsDialog</class> <widget class="QDialog" name="QInstaller::ProxyCredentialsDialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>262</width> <height>114</height> </rect> </property> <property name="windowTitle"> <string>Dialog</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="infotext"> <property name="text"> <string>The proxy %1 requires a username and password.</string> </property> </widget> </item> <item> <layout class="QFormLayout" name="formLayout"> <item row="0" column="0"> <widget class="QLabel" name="usernameLabel"> <property name="text"> <string>Username:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLineEdit" name="usernameLineEdit"> <property name="placeholderText"> <string>Username</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="passwordLabel"> <property name="text"> <string>Password:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLineEdit" name="passwordLineEdit"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> <property name="placeholderText"> <string>Password</string> </property> </widget> </item> </layout> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> </layout> </widget> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>accepted()</signal> <receiver>QInstaller::ProxyCredentialsDialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>248</x> <y>254</y> </hint> <hint type="destinationlabel"> <x>157</x> <y>274</y> </hint> </hints> </connection> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>QInstaller::ProxyCredentialsDialog</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>316</x> <y>260</y> </hint> <hint type="destinationlabel"> <x>286</x> <y>274</y> </hint> </hints> </connection> </connections> </ui> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qinstallerglobal.cpp��������������������������������0100777�0000000�0000000�00000003726�13761647206�022670� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "qinstallerglobal.h" /*! \enum QInstaller::JobError \value InvalidUrl \value Timeout \value DownloadError \value InvalidUpdatesXml \value InvalidMetaInfo \value ExtractionError \value UserIgnoreError \value RepositoryUpdatesReceived */ /*! \typedef QInstaller::Operation Synonym for KDUpdater::UpdateOperation. */ /*! \typedef QInstaller::OperationList Synonym for QList<QInstaller::Operation*>. */ /*! \typedef QInstaller::Package Synonym for KDUpdater::Update. */ /*! \typedef QInstaller::PackagesList Synonym for QList<QInstaller::Package*>. */ /*! \typedef QInstaller::LocalPackagesHash Synonym for QHash<QString, KDUpdater::LocalPackage>. */ ������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qinstallerglobal.h����������������������������������0100777�0000000�0000000�00000003667�13761647206�022341� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_GLOBAL_H #define QINSTALLER_GLOBAL_H #include <installer_global.h> #include "update.h" #include "updateoperation.h" #include "localpackagehub.h" namespace QInstaller { enum INSTALLER_EXPORT JobError { InvalidUrl = 0x24B04, Timeout, DownloadError, InvalidUpdatesXml, InvalidMetaInfo, ExtractionError, UserIgnoreError, RepositoryUpdatesReceived }; typedef KDUpdater::UpdateOperation Operation; typedef QList<QInstaller::Operation*> OperationList; typedef KDUpdater::Update Package; typedef QList<QInstaller::Package*> PackagesList; typedef QHash<QString, KDUpdater::LocalPackage> LocalPackagesHash; } // namespace QInstaller #endif // QINSTALLER_GLOBAL_H �������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qprocesswrapper.cpp���������������������������������0100777�0000000�0000000�00000033767�13761647206�022601� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "qprocesswrapper.h" #include "protocol.h" #include "utils.h" #include <QDir> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::QProcessWrapper \internal */ QProcessWrapper::QProcessWrapper(QObject *parent) : RemoteObject(QLatin1String(Protocol::QProcess), parent) { qRegisterMetaType<QProcess::ExitStatus>(); qRegisterMetaType<QProcess::ProcessError>(); qRegisterMetaType<QProcess::ProcessState>(); m_timer.start(250); connect(&m_timer, &QTimer::timeout, this, &QProcessWrapper::processSignals); connect(&process, &QIODevice::bytesWritten, this, &QProcessWrapper::bytesWritten); connect(&process, &QIODevice::aboutToClose, this, &QProcessWrapper::aboutToClose); connect(&process, &QIODevice::readChannelFinished, this, &QProcessWrapper::readChannelFinished); connect(&process, SIGNAL(error(QProcess::ProcessError)), SIGNAL(error(QProcess::ProcessError))); connect(&process, &QProcess::readyReadStandardOutput, this, &QProcessWrapper::readyReadStandardOutput); connect(&process, &QProcess::readyReadStandardError, this, &QProcessWrapper::readyReadStandardError); connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), SIGNAL(finished(int,QProcess::ExitStatus))); connect(&process, &QIODevice::readyRead, this, &QProcessWrapper::readyRead); connect(&process, &QProcess::started, this, &QProcessWrapper::started); connect(&process, &QProcess::stateChanged, this, &QProcessWrapper::stateChanged); } QProcessWrapper::~QProcessWrapper() { m_timer.stop(); } void QProcessWrapper::processSignals() { if (!isConnectedToServer()) return; if (!m_lock.tryLockForRead()) return; QList<QVariant> receivedSignals = callRemoteMethod<QList<QVariant> >(QString::fromLatin1(Protocol::GetQProcessSignals)); while (!receivedSignals.isEmpty()) { const QString name = receivedSignals.takeFirst().toString(); if (name == QLatin1String(Protocol::QProcessSignalBytesWritten)) { emit bytesWritten(receivedSignals.takeFirst().value<qint64>()); } else if (name == QLatin1String(Protocol::QProcessSignalAboutToClose)) { emit aboutToClose(); } else if (name == QLatin1String(Protocol::QProcessSignalReadChannelFinished)) { emit readChannelFinished(); } else if (name == QLatin1String(Protocol::QProcessSignalError)) { emit error(static_cast<QProcess::ProcessError> (receivedSignals.takeFirst().toInt())); } else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardOutput)) { emit readyReadStandardOutput(); } else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardError)) { emit readyReadStandardError(); } else if (name == QLatin1String(Protocol::QProcessSignalStarted)) { emit started(); } else if (name == QLatin1String(Protocol::QProcessSignalReadyRead)) { emit readyRead(); } else if (name == QLatin1String(Protocol::QProcessSignalStateChanged)) { emit stateChanged(static_cast<QProcess::ProcessState> (receivedSignals.takeFirst() .toInt())); } else if (name == QLatin1String(Protocol::QProcessSignalFinished)) { emit finished(receivedSignals.takeFirst().toInt(), static_cast<QProcess::ExitStatus> (receivedSignals.takeFirst().toInt())); } } m_lock.unlock(); } bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) { QProcessWrapper w; if (w.connectToServer()) { const QPair<bool, qint64> result = w.callRemoteMethod<QPair<bool, qint64> >(QLatin1String(Protocol::QProcessStartDetached), program, arguments, workingDirectory); if (pid != nullptr) *pid = result.second; w.processSignals(); return result.first; } return QInstaller::startDetached(program, arguments, workingDirectory, pid); } bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments) { return startDetached(program, arguments, QDir::currentPath()); } bool QProcessWrapper::startDetached(const QString &program) { return startDetached(program, QStringList()); } void QProcessWrapper::setProcessChannelMode(QProcessWrapper::ProcessChannelMode mode) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetProcessChannelMode), static_cast<QProcess::ProcessChannelMode>(mode), dummy); m_lock.unlock(); } else { process.setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(mode)); } } /*! Cancels the process. This methods tries to terminate the process gracefully by calling QProcess::terminate. After 10 seconds, the process gets killed. */ void QProcessWrapper::cancel() { if (state() == QProcessWrapper::Running) terminate(); if (!waitForFinished(10000)) kill(); } void QProcessWrapper::setReadChannel(QProcessWrapper::ProcessChannel chan) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetReadChannel), static_cast<QProcess::ProcessChannel>(chan), dummy); m_lock.unlock(); } else { process.setReadChannel(static_cast<QProcess::ProcessChannel>(chan)); } } bool QProcessWrapper::waitForFinished(int msecs) { if (connectToServer()) { m_lock.lockForWrite(); const bool value = callRemoteMethod<bool>(QLatin1String(Protocol::QProcessWaitForFinished), qint32(msecs)); m_lock.unlock(); return value; } return process.waitForFinished(msecs); } bool QProcessWrapper::waitForStarted(int msecs) { if (connectToServer()) { m_lock.lockForWrite(); const bool value = callRemoteMethod<bool>(QLatin1String(Protocol::QProcessWaitForStarted), qint32(msecs)); m_lock.unlock(); return value; } return process.waitForStarted(msecs); } qint64 QProcessWrapper::write(const QByteArray &data) { if (connectToServer()) { m_lock.lockForWrite(); const qint64 value = callRemoteMethod<qint64>(QLatin1String(Protocol::QProcessWrite), data); m_lock.unlock(); return value; } return process.write(data); } void QProcessWrapper::closeWriteChannel() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessCloseWriteChannel)); m_lock.unlock(); } else { process.closeWriteChannel(); } } int QProcessWrapper::exitCode() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const int value = callRemoteMethod<qint32>(QLatin1String(Protocol::QProcessExitCode)); m_lock.unlock(); return value; } return process.exitCode(); } QProcessWrapper::ExitStatus QProcessWrapper::exitStatus() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const int status = callRemoteMethod<qint32>(QLatin1String(Protocol::QProcessExitStatus)); m_lock.unlock(); return static_cast<QProcessWrapper::ExitStatus>(status); } return static_cast<QProcessWrapper::ExitStatus>(process.exitStatus()); } void QProcessWrapper::kill() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessKill)); m_lock.unlock(); } else { process.kill(); } } QByteArray QProcessWrapper::readAll() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod<QByteArray>(QLatin1String(Protocol::QProcessReadAll)); m_lock.unlock(); return ba; } return process.readAll(); } QByteArray QProcessWrapper::readAllStandardOutput() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod<QByteArray>(QLatin1String(Protocol::QProcessReadAllStandardOutput)); m_lock.unlock(); return ba; } return process.readAllStandardOutput(); } QByteArray QProcessWrapper::readAllStandardError() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod<QByteArray>(QLatin1String(Protocol::QProcessReadAllStandardError)); m_lock.unlock(); return ba; } return process.readAllStandardError(); } void QProcessWrapper::start(const QString ¶m1, const QStringList ¶m2, QIODevice::OpenMode param3) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessStart3Arg), param1, param2, param3); m_lock.unlock(); } else { process.start(param1, param2, param3); } } void QProcessWrapper::start(const QString ¶m1, QIODevice::OpenMode param2) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessStart2Arg), param1, param2); m_lock.unlock(); } else { process.start(param1, param2); } } QProcessWrapper::ProcessState QProcessWrapper::state() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const int state = callRemoteMethod<qint32>(QLatin1String(Protocol::QProcessState)); m_lock.unlock(); return static_cast<QProcessWrapper::ProcessState>(state); } return static_cast<QProcessWrapper::ProcessState>(process.state()); } void QProcessWrapper::terminate() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessTerminate)); m_lock.unlock(); } else { process.terminate(); } } QProcessWrapper::ProcessChannel QProcessWrapper::readChannel() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const int channel = callRemoteMethod<qint32>(QLatin1String(Protocol::QProcessReadChannel)); m_lock.unlock(); return static_cast<QProcessWrapper::ProcessChannel>(channel); } return static_cast<QProcessWrapper::ProcessChannel>(process.readChannel()); } QProcessWrapper::ProcessChannelMode QProcessWrapper::processChannelMode() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const int mode = callRemoteMethod<qint32>(QLatin1String(Protocol::QProcessProcessChannelMode)); m_lock.unlock(); return static_cast<QProcessWrapper::ProcessChannelMode>(mode); } return static_cast<QProcessWrapper::ProcessChannelMode>(process.processChannelMode()); } QString QProcessWrapper::workingDirectory() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const QString dir = callRemoteMethod<QString>(QLatin1String(Protocol::QProcessWorkingDirectory)); m_lock.unlock(); return dir; } return static_cast<QString>(process.workingDirectory()); } QString QProcessWrapper::errorString() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const QString error = callRemoteMethod<QString>(QLatin1String(Protocol::QProcessErrorString)); m_lock.unlock(); return error; } return static_cast<QString>(process.errorString()); } QStringList QProcessWrapper::environment() const { if ((const_cast<QProcessWrapper *>(this))->connectToServer()) { m_lock.lockForWrite(); const QStringList env = callRemoteMethod<QStringList>(QLatin1String(Protocol::QProcessEnvironment)); m_lock.unlock(); return env; } return process.environment(); } void QProcessWrapper::setEnvironment(const QStringList ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetEnvironment), param1, dummy); m_lock.unlock(); } else { process.setEnvironment(param1); } } #ifdef Q_OS_WIN void QProcessWrapper::setNativeArguments(const QString ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetNativeArguments), param1, dummy); m_lock.unlock(); } else { process.setNativeArguments(param1); } } #endif void QProcessWrapper::setWorkingDirectory(const QString ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetWorkingDirectory), param1, dummy); m_lock.unlock(); } else { process.setWorkingDirectory(param1); } } } // namespace QInstaller ���������qt-installer-framework-4.0.1/src/libs/installer/qprocesswrapper.h�����������������������������������0100777�0000000�0000000�00000010172�13761647206�022227� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QPROCESSWRAPPER_H #define QPROCESSWRAPPER_H #include "remoteobject.h" #include <QIODevice> #include <QProcess> #include <QReadWriteLock> #include <QTimer> namespace QInstaller { class INSTALLER_EXPORT QProcessWrapper : public RemoteObject { Q_OBJECT Q_DISABLE_COPY(QProcessWrapper) public: enum ProcessState { NotRunning, Starting, Running }; enum ExitStatus { NormalExit, CrashExit }; enum ProcessChannel { StandardOutput = 0, StandardError = 1 }; enum ProcessChannelMode { SeparateChannels = 0, MergedChannels = 1, ForwardedChannels = 2 }; explicit QProcessWrapper(QObject *parent = 0); ~QProcessWrapper(); int exitCode() const; ProcessState state() const; ExitStatus exitStatus() const; QString workingDirectory() const; void setWorkingDirectory(const QString &dir); QStringList environment() const; void setEnvironment(const QStringList &environment); QProcessWrapper::ProcessChannel readChannel() const; void setReadChannel(QProcessWrapper::ProcessChannel channel); QProcessWrapper::ProcessChannelMode processChannelMode() const; void setProcessChannelMode(QProcessWrapper::ProcessChannelMode channel); bool waitForStarted(int msecs = 30000); bool waitForFinished(int msecs = 30000); void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = QIODevice::ReadWrite); void start(const QString &program, QIODevice::OpenMode mode = QIODevice::ReadWrite); void closeWriteChannel(); void kill(); void terminate(); QByteArray readAll(); QByteArray readAllStandardOutput(); QByteArray readAllStandardError(); static bool startDetached(const QString &program); static bool startDetached(const QString &program, const QStringList &arguments); static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid = 0); QString errorString() const; qint64 write(const QByteArray &byteArray); #ifdef Q_OS_WIN void setNativeArguments(const QString &arguments); #endif Q_SIGNALS: void bytesWritten(qint64); void aboutToClose(); void readChannelFinished(); void error(QProcess::ProcessError); void readyReadStandardOutput(); void readyReadStandardError(); void finished(int exitCode, QProcess::ExitStatus exitStatus); void readyRead(); void started(); void stateChanged(QProcess::ProcessState newState); public Q_SLOTS: void cancel(); private slots: void processSignals(); private: QTimer m_timer; QProcess process; mutable QReadWriteLock m_lock; }; } // namespace QInstaller Q_DECLARE_METATYPE(QProcess::ExitStatus) Q_DECLARE_METATYPE(QProcess::ProcessError) Q_DECLARE_METATYPE(QProcess::ProcessState) #endif // QPROCESSWRAPPER_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qsettingswrapper.cpp��������������������������������0100777�0000000�0000000�00000023603�13761647206�022747� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "qsettingswrapper.h" #include "permissionsettings.h" #include <QStringList> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::QSettingsWrapper \internal */ // -- QSettingsWrapper::Private class QSettingsWrapper::Private { public: Private(const QString &organization, const QString &application) : m_application(application) , m_organization(organization) , m_scope(QSettings::UserScope) , m_format(QSettings::NativeFormat) , settings(organization, application) { } Private(QSettings::Scope scope, const QString &organization, const QString &application) : m_application(application) , m_organization(organization) , m_scope(scope) , m_format(QSettings::NativeFormat) , settings(scope, organization, application) { } Private(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) : m_application(application) , m_organization(organization) , m_scope(scope) , m_format(format) , settings(format, scope, organization, application) { } Private(const QString &fileName, QSettings::Format format) : m_filename(fileName) , settings(fileName, format) { m_format = format; m_scope = settings.scope(); m_application = settings.applicationName(); m_organization = settings.organizationName(); } QString m_filename; QString m_application; QString m_organization; QSettings::Scope m_scope; QSettings::Format m_format; PermissionSettings settings; }; // -- QSettingsWrapper QSettingsWrapper::QSettingsWrapper(const QString &organization, const QString &application, QObject *parent) : RemoteObject(QLatin1String(Protocol::QSettings), parent) , d(new Private(organization, application)) { } QSettingsWrapper::QSettingsWrapper(QSettingsWrapper::Scope scope, const QString &organization, const QString &application, QObject *parent) : RemoteObject(QLatin1String(Protocol::QSettings), parent) , d(new Private(static_cast<QSettings::Scope>(scope), organization, application)) { } QSettingsWrapper::QSettingsWrapper(QSettingsWrapper::Format format, QSettingsWrapper::Scope scope, const QString &organization, const QString &application, QObject *parent) : RemoteObject(QLatin1String(Protocol::QSettings), parent) , d(new Private(static_cast<QSettings::Format>(format), static_cast<QSettings::Scope> (scope), organization, application)) { } QSettingsWrapper::QSettingsWrapper(const QString &fileName, QSettingsWrapper::Format format, QObject *parent) : RemoteObject(QLatin1String(Protocol::QSettings), parent) , d(new Private(fileName, static_cast<QSettings::Format>(format))) { } QSettingsWrapper::~QSettingsWrapper() { delete d; } QStringList QSettingsWrapper::allKeys() const { if (createSocket()) return callRemoteMethod<QStringList>(QLatin1String(Protocol::QSettingsAllKeys)); return d->settings.allKeys(); } QString QSettingsWrapper::applicationName() const { if (createSocket()) return callRemoteMethod<QString>(QLatin1String(Protocol::QSettingsApplicationName)); return d->settings.applicationName(); } void QSettingsWrapper::beginGroup(const QString ¶m1) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsBeginGroup), param1, dummy); else d->settings.beginGroup(param1); } int QSettingsWrapper::beginReadArray(const QString ¶m1) { if (createSocket()) return callRemoteMethod<qint32>(QLatin1String(Protocol::QSettingsBeginReadArray), param1); return d->settings.beginReadArray(param1); } void QSettingsWrapper::beginWriteArray(const QString ¶m1, int param2) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsBeginWriteArray), param1, qint32(param2)); else d->settings.beginWriteArray(param1, param2); } QStringList QSettingsWrapper::childGroups() const { if (createSocket()) return callRemoteMethod<QStringList>(QLatin1String(Protocol::QSettingsChildGroups)); return d->settings.childGroups(); } QStringList QSettingsWrapper::childKeys() const { if (createSocket()) return callRemoteMethod<QStringList>(QLatin1String(Protocol::QSettingsChildKeys)); return d->settings.childKeys(); } void QSettingsWrapper::clear() { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsClear)); else d->settings.clear(); } bool QSettingsWrapper::contains(const QString ¶m1) const { if (createSocket()) return callRemoteMethod<bool>(QLatin1String(Protocol::QSettingsContains), param1); return d->settings.contains(param1); } void QSettingsWrapper::endArray() { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsEndArray)); else d->settings.endArray(); } void QSettingsWrapper::endGroup() { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsEndGroup)); else d->settings.endGroup(); } bool QSettingsWrapper::fallbacksEnabled() const { if (createSocket()) return callRemoteMethod<bool>(QLatin1String(Protocol::QSettingsFallbacksEnabled)); return d->settings.fallbacksEnabled(); } QString QSettingsWrapper::fileName() const { if (createSocket()) return callRemoteMethod<QString>(QLatin1String(Protocol::QSettingsFileName)); return d->settings.fileName(); } QSettingsWrapper::Format QSettingsWrapper::format() const { // No need to talk to the server, we've setup the local settings object the same way. return static_cast<QSettingsWrapper::Format>(d->settings.format()); } QString QSettingsWrapper::group() const { if (createSocket()) return callRemoteMethod<QString>(QLatin1String(Protocol::QSettingsGroup)); return d->settings.group(); } bool QSettingsWrapper::isWritable() const { if (createSocket()) return callRemoteMethod<bool>(QLatin1String(Protocol::QSettingsIsWritable)); return d->settings.isWritable(); } QString QSettingsWrapper::organizationName() const { if (createSocket()) return callRemoteMethod<QString>(QLatin1String(Protocol::QSettingsOrganizationName)); return d->settings.organizationName(); } void QSettingsWrapper::remove(const QString ¶m1) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsRemove), param1, dummy); else d->settings.remove(param1); } QSettingsWrapper::Scope QSettingsWrapper::scope() const { // No need to talk to the server, we've setup the local settings object the same way. return static_cast<QSettingsWrapper::Scope>(d->settings.scope()); } void QSettingsWrapper::setArrayIndex(int param1) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsSetArrayIndex), qint32(param1), dummy); else d->settings.setArrayIndex(param1); } void QSettingsWrapper::setFallbacksEnabled(bool param1) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsSetFallbacksEnabled), param1, dummy); else d->settings.setFallbacksEnabled(param1); } void QSettingsWrapper::setValue(const QString ¶m1, const QVariant ¶m2) { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsSetValue), param1, param2); else d->settings.setValue(param1, param2); } QSettingsWrapper::Status QSettingsWrapper::status() const { if (createSocket()) { return static_cast<QSettingsWrapper::Status> (callRemoteMethod<qint32>(QLatin1String(Protocol::QSettingsStatus))); } return static_cast<QSettingsWrapper::Status>(d->settings.status()); } void QSettingsWrapper::sync() { if (createSocket()) callRemoteMethod(QLatin1String(Protocol::QSettingsSync)); else d->settings.sync(); } QVariant QSettingsWrapper::value(const QString ¶m1, const QVariant ¶m2) const { if (createSocket()) return callRemoteMethod<QVariant>(QLatin1String(Protocol::QSettingsValue), param1, param2); return d->settings.value(param1, param2); } // -- private bool QSettingsWrapper::createSocket() const { if ((d->m_format != QSettings::NativeFormat) && (d->m_format != QSettings::IniFormat)) { Q_ASSERT_X(false, Q_FUNC_INFO, "Settings wrapper only supports QSettingsWrapper::NativeFormat" " and QSettingsWrapper::IniFormat."); } return (const_cast<QSettingsWrapper *>(this))->connectToServer(QVariantList() << d->m_application << d->m_organization << d->m_scope << d->m_format << d->m_filename); } } // namespace QInstaller �����������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qsettingswrapper.h����������������������������������0100777�0000000�0000000�00000010653�13761647206�022415� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QSETTINGSWRAPPER_H #define QSETTINGSWRAPPER_H #include "protocol.h" #include "remoteobject.h" #include <QVariant> namespace QInstaller { class INSTALLER_EXPORT QSettingsWrapper : public RemoteObject { Q_OBJECT Q_DISABLE_COPY(QSettingsWrapper) public: enum Status { NoError = 0, AccessError, FormatError }; enum Format { NativeFormat, IniFormat, InvalidFormat = 16 }; enum Scope { UserScope, SystemScope }; explicit QSettingsWrapper(const QString &organization, const QString &application = QString(), QObject *parent = 0); QSettingsWrapper(Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = 0); QSettingsWrapper(Format format, Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = 0); QSettingsWrapper(const QString &fileName, Format format, QObject *parent = 0); ~QSettingsWrapper(); void clear(); void sync(); Status status() const; void beginGroup(const QString &prefix); void endGroup(); QString group() const; int beginReadArray(const QString &prefix); void beginWriteArray(const QString &prefix, int size = -1); void endArray(); void setArrayIndex(int i); QStringList allKeys() const; QStringList childKeys() const; QStringList childGroups() const; bool isWritable() const; void setValue(const QString &key, const QVariant &value); QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; void remove(const QString &key); bool contains(const QString &key) const; void setFallbacksEnabled(bool b); bool fallbacksEnabled() const; QString fileName() const; Format format() const; Scope scope() const; QString organizationName() const; QString applicationName() const; private: bool createSocket() const; private: // we cannot support the following functionality explicit QSettingsWrapper(QObject *parent = 0) : RemoteObject(QLatin1String(Protocol::QSettings), parent) {} void setIniCodec(QTextCodec * /*codec*/); void setIniCodec(const char * /*codecName*/); QTextCodec *iniCodec() const { return 0; } static void setDefaultFormat(Format /*format*/); static Format defaultFormat() { return NativeFormat; } static void setSystemIniPath(const QString & /*dir*/); static void setUserIniPath(const QString & /*dir*/); static void setPath(Format /*format*/, Scope /*scope*/, const QString & /*path*/); typedef QMap<QString, QVariant> SettingsMap; typedef bool(*ReadFunc)(QIODevice &device, SettingsMap &map); typedef bool(*WriteFunc)(QIODevice &device, const SettingsMap &map); static Format registerFormat(const QString &extension, ReadFunc readFunc, WriteFunc writeFunc, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) { Q_UNUSED(extension) Q_UNUSED(readFunc) Q_UNUSED(writeFunc) Q_UNUSED(caseSensitivity) return NativeFormat; } private: class Private; Private *d; }; } // namespace QInstaller #endif // QSETTINGSWRAPPER_H �������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qtpatch.cpp�����������������������������������������0100777�0000000�0000000�00000016651�13761647206�020776� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "qtpatch.h" #include "utils.h" #include "globals.h" #include <QString> #include <QStringList> #include <QFileInfo> #include <QProcess> #include <QTextStream> #include <QVector> #include <QTime> #include <QtCore/QDebug> #include <QCoreApplication> #include <QByteArrayMatcher> QHash<QString, QByteArray> QtPatch::readQmakeOutput(const QByteArray &data) { QHash<QString, QByteArray> qmakeValueHash; QTextStream stream(data, QIODevice::ReadOnly); while (!stream.atEnd()) { const QString line = stream.readLine(); const int index = line.indexOf(QLatin1Char(':')); if (index != -1) { QString value = line.mid(index+1); if (value != QLatin1String("**Unknown**") ) qmakeValueHash.insert(line.left(index), value.toUtf8()); } } return qmakeValueHash; } QHash<QString, QByteArray> QtPatch::qmakeValues(const QString &qmakePath, QByteArray *qmakeOutput) { QHash<QString, QByteArray> qmakeValueHash; // in some cases qmake is not runable, because another process is blocking it(filewatcher ...) int waitCount = 0; while (qmakeValueHash.isEmpty() && waitCount < 3) { QFileInfo qmake(qmakePath); if (!qmake.exists()) { qmakeOutput->append(QString::fromLatin1("%1 is not existing").arg(qmakePath)); return qmakeValueHash; } if (!qmake.isExecutable()) { qmakeOutput->append(QString::fromLatin1("%1 is not executable").arg(qmakePath)); return qmakeValueHash; } QStringList args; args << QLatin1String("-query"); QProcess process; process.start(qmake.absoluteFilePath(), args, QIODevice::ReadOnly); if (process.waitForFinished(10000)) { QByteArray output = process.readAllStandardOutput(); qmakeOutput->append(output); if (process.exitStatus() == QProcess::CrashExit) { qCWarning(QInstaller::lcInstallerInstallLog) << qmake.absoluteFilePath() << args << "crashed with exit code" << process.exitCode() << "standard output:" << output << "error output:" << process.readAllStandardError(); return qmakeValueHash; } qmakeValueHash = readQmakeOutput(output); } if (qmakeValueHash.isEmpty()) { ++waitCount; static const int waitTimeInMilliSeconds = 500; QInstaller::uiDetachedWait(waitTimeInMilliSeconds); } if (process.state() > QProcess::NotRunning ) { qCWarning(QInstaller::lcInstallerInstallLog) << "qmake process is still running, need to kill it."; process.kill(); } } if (qmakeValueHash.isEmpty()) qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot get any query output from qmake."; return qmakeValueHash; } bool QtPatch::patchBinaryFile(const QString &fileName, const QByteArray &oldQtPath, const QByteArray &newQtPath) { QFile file(fileName); if (!file.exists()) { qCWarning(QInstaller::lcInstallerInstallLog) << "qpatch: warning: file" << fileName << "not found"; return false; } openFileForPatching(&file); if (!file.isOpen()) { qCWarning(QInstaller::lcInstallerInstallLog) << "qpatch: warning: file" << qPrintable(fileName) << "cannot open."; qCWarning(QInstaller::lcInstallerInstallLog).noquote() << file.errorString(); return false; } bool isPatched = patchBinaryFile(&file, oldQtPath, newQtPath); file.close(); return isPatched; } // device must be open bool QtPatch::patchBinaryFile(QIODevice *device, const QByteArray &oldQtPath, const QByteArray &newQtPath) { if (!(device->openMode() == QIODevice::ReadWrite)) { qCWarning(QInstaller::lcInstallerInstallLog) << "qpatch: warning: This function needs an " "open device for writing."; return false; } const QByteArray source = device->readAll(); device->seek(0); int offset = 0; QByteArray overwritePath(newQtPath); if (overwritePath.size() < oldQtPath.size()) { QByteArray fillByteArray(oldQtPath.size() - overwritePath.size(), '\0'); overwritePath.append(fillByteArray); } QByteArrayMatcher byteArrayMatcher(oldQtPath); forever { offset = byteArrayMatcher.indexIn(source, offset); if (offset == -1) break; device->seek(offset); device->write(overwritePath); offset += overwritePath.size(); } device->seek(0); //for next reading we should be at the beginning return true; } bool QtPatch::patchTextFile(const QString &fileName, const QHash<QByteArray, QByteArray> &searchReplacePairs) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open file" << fileName << "for patching:" << file.errorString(); return false; } QByteArray source = file.readAll(); file.close(); QHashIterator<QByteArray, QByteArray> it(searchReplacePairs); while (it.hasNext()) { it.next(); source.replace(it.key(), it.value()); } if (!file.open(QFile::WriteOnly | QFile::Truncate)) { qCWarning(QInstaller::lcInstallerInstallLog) << "File" << fileName << "not writable."; return false; } file.write(source); return true; } bool QtPatch::openFileForPatching(QFile *file) { if (file->openMode() == QIODevice::NotOpen) { // in some cases the file cannot be opened, because another process is blocking it (filewatcher ...) int waitCount = 0; while (!file->open(QFile::ReadWrite) && waitCount < 60) { ++waitCount; static const int waitTimeInMilliSeconds = 500; QInstaller::uiDetachedWait(waitTimeInMilliSeconds); } return file->openMode() == QFile::ReadWrite; } qCWarning(QInstaller::lcInstallerInstallLog) << "File" << file->fileName() << "is open, " "so it cannot be opened again."; return false; } ���������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/qtpatch.h�������������������������������������������0100777�0000000�0000000�00000004311�13761647206�020431� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QTPATCH_H #define QTPATCH_H #include "installer_global.h" #include <QString> #include <QByteArray> #include <QHash> #include <QFile> namespace QtPatch { QHash<QString, QByteArray> INSTALLER_EXPORT readQmakeOutput(const QByteArray &data); QHash<QString, QByteArray> INSTALLER_EXPORT qmakeValues(const QString &qmakePath, QByteArray *qmakeOutput); bool INSTALLER_EXPORT patchBinaryFile(const QString &fileName, const QByteArray &oldQtPath, const QByteArray &newQtPath ); bool INSTALLER_EXPORT patchBinaryFile(QIODevice *device, const QByteArray &oldQtPath, const QByteArray &newQtPath ); bool INSTALLER_EXPORT patchTextFile(const QString &fileName, const QHash<QByteArray, QByteArray> &searchReplacePairs); bool INSTALLER_EXPORT openFileForPatching(QFile *file); } #endif // QTPATCH_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/range.h���������������������������������������������0100777�0000000�0000000�00000005071�13761647206�020065� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef RANGE_H #define RANGE_H #include <algorithm> template <typename T> class Range { public: static Range<T> fromStartAndEnd( const T& start, const T& end ) { Range<T> r; r.m_start = start; r.m_end = end; return r; } static Range<T> fromStartAndLength( const T& start, const T& length ) { Range<T> r; r.m_start = start; r.m_end = start + length; return r; } Range() : m_start( 0 ), m_end( 0 ) {} T start() const { return m_start; } T end() const { return m_end; } void move( const T& by ) { m_start += by; m_end += by; } Range<T> moved( const T& by ) const { Range<T> b = *this; b.move( by ); return b; } T length() const { return m_end - m_start; } Range<T> normalized() const { Range<T> r2( *this ); if ( r2.m_start > r2.m_end ) std::swap( r2.m_start, r2.m_end ); return r2; } bool operator==( const Range<T>& other ) const { return m_start == other.m_start && m_end && other.m_end; } bool operator<( const Range<T>& other ) const { if ( m_start != other.m_start ) return m_start < other.m_start; return m_end < other.m_end; } private: T m_start; T m_end; }; #endif /* RANGE_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/registerfiletypeoperation.cpp�����������������������0100777�0000000�0000000�00000020175�13761647206�024635� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "registerfiletypeoperation.h" #include "constants.h" #include "packagemanagercore.h" #include "qsettingswrapper.h" using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::RegisterFileTypeOperation \internal */ #ifdef Q_OS_WIN #include <shlobj.h> struct StartsWithProgId { bool operator()(const QString &s) { return s.startsWith(QLatin1String("ProgId=")); } }; static QString takeProgIdArgument(QStringList &args) { // if the arguments contain an option in the form "ProgId=...", find it and consume it QStringList::iterator it = std::find_if (args.begin(), args.end(), StartsWithProgId()); if (it == args.end()) return QString(); const QString progId = it->mid(QString::fromLatin1("ProgId=").size()); args.erase(it); return progId; } static QVariantHash readHive(QSettingsWrapper *const settings, const QString &hive) { QVariantHash keyValues; settings->beginGroup(hive); foreach (const QString &key, settings->allKeys()) keyValues.insert(key, settings->value(key)); settings->endGroup(); return keyValues; } #endif // -- RegisterFileTypeOperation RegisterFileTypeOperation::RegisterFileTypeOperation(PackageManagerCore *core) : UpdateOperation(core) , m_optionalArgumentsRead(false) { setName(QLatin1String("RegisterFileType")); } void RegisterFileTypeOperation::backup() { } bool RegisterFileTypeOperation::performOperation() { #ifdef Q_OS_WIN ensureOptionalArgumentsRead(); if (!checkArgumentCount(2, 5, QString::fromLatin1("<extension> <command> [description [contentType [icon]]]"))) return false; QStringList args = arguments(); bool allUsers = false; PackageManagerCore *const core = packageManager(); if (core && core->value(scAllUsers) == scTrue) allUsers = true; QSettingsWrapper settings(QLatin1String(allUsers ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER") , QSettingsWrapper::NativeFormat); const QString classesProgId = QString::fromLatin1("Software/Classes/") + m_progId; const QString classesFileType = QString::fromLatin1("Software/Classes/.%2").arg(args.at(0)); const QString classesApplications = QString::fromLatin1("Software/Classes/Applications/") + m_progId; // backup old value setValue(QLatin1String("oldType"), readHive(&settings, classesFileType)); // register new values settings.setValue(QString::fromLatin1("%1/Default").arg(classesFileType), m_progId); settings.setValue(QString::fromLatin1("%1/OpenWithProgIds/%2").arg(classesFileType, m_progId), QString()); settings.setValue(QString::fromLatin1("%1/shell/Open/Command/Default").arg(classesProgId), args.at(1)); settings.setValue(QString::fromLatin1("%1/shell/Open/Command/Default").arg(classesApplications), args.at(1)); // content type (optional) const QString contentType = args.value(3); if (!contentType.isEmpty()) settings.setValue(QString::fromLatin1("%1/Content Type").arg(classesFileType), contentType); // description (optional) const QString description = args.value(2); if (!description.isEmpty()) settings.setValue(QString::fromLatin1("%1/Default").arg(classesProgId), description); // icon (optional) const QString icon = args.value(4); if (!icon.isEmpty()) settings.setValue(QString::fromLatin1("%1/DefaultIcon/Default").arg(classesProgId), icon); // backup new value setValue(QLatin1String("newType"), readHive(&settings, classesFileType)); // force the shell to invalidate its cache SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); return true; #else setError(UserDefinedError); setErrorString(tr("Registering file types is only supported on Windows.")); return false; #endif } bool RegisterFileTypeOperation::undoOperation() { #ifdef Q_OS_WIN ensureOptionalArgumentsRead(); QStringList args = arguments(); if (!checkArgumentCount(2, 5, tr("Register File Type: Invalid arguments"))) return false; bool allUsers = false; PackageManagerCore *const core = packageManager(); if (core && core->value(scAllUsers) == scTrue) allUsers = true; QSettingsWrapper settings(QLatin1String(allUsers ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER") , QSettingsWrapper::NativeFormat); const QString classesProgId = QString::fromLatin1("Software/Classes/") + m_progId; const QString classesFileType = QString::fromLatin1("Software/Classes/.%2").arg(args.at(0)); const QString classesApplications = QString::fromLatin1("Software/Classes/Applications/") + m_progId; // Quoting MSDN here: When uninstalling an application, the ProgIDs and most other registry information // associated with that application should be deleted as part of the uninstallation.However, applications // that have taken ownership of a file type (by setting the Default value of the file type's // HKEY...\.extension subkey to the ProgID of the application) should not attempt to remove that value // when uninstalling. Leaving the data in place for the Default value avoids the difficulty of // determining whether another application has taken ownership of the file type and overwritten the // Default value after the original application was installed. Windows respects the Default value only // if the ProgID found there is a registered ProgID. If the ProgID is unregistered, it is ignored. // if the hive didn't change since we touched it if (value(QLatin1String("newType")).toHash() == readHive(&settings, classesFileType)) { // reset to the values we found settings.remove(classesFileType); settings.beginGroup(classesFileType); const QVariantHash keyValues = value(QLatin1String("oldType")).toHash(); foreach (const QString &key, keyValues.keys()) settings.setValue(key, keyValues.value(key)); settings.endGroup(); } else { // some changes happened, remove the only save value we know about settings.remove(QString::fromLatin1("%1/OpenWithProgIds/%2").arg(classesFileType, m_progId)); } // remove ProgId and Applications entry settings.remove(classesProgId); settings.remove(classesApplications); // force the shell to invalidate its cache SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); return true; #else setErrorString(tr("Registering file types is only supported on Windows.")); return false; #endif } bool RegisterFileTypeOperation::testOperation() { return true; } void RegisterFileTypeOperation::ensureOptionalArgumentsRead() { #ifdef Q_OS_WIN if (m_optionalArgumentsRead) return; m_optionalArgumentsRead = true; QStringList args = arguments(); m_progId = takeProgIdArgument(args); if (m_progId.isEmpty() && args.count() > 0) m_progId = QString::fromLatin1("%1_auto_file").arg(args.at(0)); setArguments(args); #endif } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/registerfiletypeoperation.h�������������������������0100777�0000000�0000000�00000003372�13761647206�024302� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REGISTERFILETYPEOPERATION_H #define REGISTERFILETYPEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT RegisterFileTypeOperation : public QObject, public Operation { Q_OBJECT public: explicit RegisterFileTypeOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); private: void ensureOptionalArgumentsRead(); bool m_optionalArgumentsRead; QString m_progId; }; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteclient.cpp������������������������������������0100777�0000000�0000000�00000007346�13761647206�022025� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "remoteclient.h" #include "remoteclient_p.h" #include <QDir> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::RemoteClient \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::RemoteClientPrivate \internal */ RemoteClient *RemoteClient::s_instance = nullptr; RemoteClient::RemoteClient() : d_ptr(new RemoteClientPrivate(this)) { } RemoteClient::~RemoteClient() { } RemoteClient &RemoteClient::instance() { if (!s_instance) s_instance = new RemoteClient; return *s_instance; } QString RemoteClient::socketName() const { Q_D(const RemoteClient); return d->m_socketName; } QString RemoteClient::authorizationKey() const { Q_D(const RemoteClient); return d->m_key; } QString RemoteClient::socketPathName(const QString &socketName) const { QString socketPathName; if (socketName.startsWith(QLatin1Char('/'))) { socketPathName = socketName; } else { socketPathName = QDir::tempPath(); socketPathName += QLatin1Char('/') + socketName; } return socketPathName; } /*! Initializes the client with \a socketName, with the \a key the client sends to authenticate with the server, \a mode and \a startAs. */ void RemoteClient::init(const QString &socketName, const QString &key, Protocol::Mode mode, Protocol::StartAs startAs) { Q_D(RemoteClient); // Since Qt 5.12.0, we should determince the full socket path on Unix // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). // Otherwise the new canonical implementation of QDir::tempPath() // presents unintended usage of RemoteFileEngine. #if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) d->init(socketPathName(socketName), key, mode, startAs); #else d->init(socketName, key, mode, startAs); #endif } void RemoteClient::setAuthorizationFallbackDisabled(bool disabled) { Q_D(RemoteClient); d->setAuthorizationFallbackDisabled(disabled); } void RemoteClient::shutdown() { Q_D(RemoteClient); d->shutdown(); d_ptr.reset(new RemoteClientPrivate(this)); } void RemoteClient::destroy() { delete s_instance; s_instance = nullptr; } bool RemoteClient::isActive() const { Q_D(const RemoteClient); return d->m_active; } void RemoteClient::setActive(bool active) { Q_D(RemoteClient); d->m_active = active; if (d->m_active) { d->maybeStartServer(); d->m_active = d->m_serverStarted; } } } // namespace QInstaller ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteclient.h��������������������������������������0100777�0000000�0000000�00000004244�13761647206�021464� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTECLIENT_H #define REMOTECLIENT_H #include "installer_global.h" #include "protocol.h" #include <QScopedPointer> namespace QInstaller { class RemoteClientPrivate; class INSTALLER_EXPORT RemoteClient { Q_DISABLE_COPY(RemoteClient) Q_DECLARE_PRIVATE(RemoteClient) public: static RemoteClient &instance(); void init(const QString &socketName, const QString &key, Protocol::Mode mode, Protocol::StartAs startAs); void setAuthorizationFallbackDisabled(bool disabled); void shutdown(); void destroy(); QString socketName() const; QString authorizationKey() const; QString socketPathName(const QString &socketName) const; bool isActive() const; void setActive(bool active); private: RemoteClient(); ~RemoteClient(); private: static RemoteClient *s_instance; QScopedPointer<RemoteClientPrivate> d_ptr; }; } // namespace QInstaller #endif // REMOTECLIENT_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteclient_p.h������������������������������������0100777�0000000�0000000�00000017417�13761647206�022011� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTECLIENT_P_H #define REMOTECLIENT_P_H #include "adminauthorization.h" #include "keepaliveobject.h" #include "messageboxhandler.h" #include "protocol.h" #include "remoteclient.h" #include "remoteobject.h" #include "utils.h" #include "constants.h" #include <QCoreApplication> #include <QElapsedTimer> #include <QMutex> #include <QThread> namespace QInstaller { class RemoteClientPrivate : public RemoteObject { Q_DECLARE_PUBLIC(RemoteClient) Q_DISABLE_COPY(RemoteClientPrivate) public: RemoteClientPrivate(RemoteClient *parent) : RemoteObject(QLatin1String("RemoteClientPrivate")) , q_ptr(parent) , m_mutex(QMutex::Recursive) , m_startServerAs(Protocol::StartAs::User) , m_serverStarted(false) , m_active(false) , m_key(QLatin1String(Protocol::DefaultAuthorizationKey)) , m_mode(Protocol::Mode::Debug) , m_authorizationFallbackDisabled(false) { m_thread.setObjectName(QLatin1String("KeepAlive")); } ~RemoteClientPrivate() { shutdown(); } void shutdown() { m_thread.quit(); m_thread.wait(); maybeStopServer(); } void init(const QString &socketName, const QString &key, Protocol::Mode mode, Protocol::StartAs startAs) { m_socketName = socketName; m_key = key; m_mode = mode; if (mode == Protocol::Mode::Production) { m_startServerAs = startAs; m_serverCommand = QCoreApplication::applicationFilePath(); m_serverArguments = QStringList() << QLatin1String("--") + CommandLineOptions::scStartServerLong << QString::fromLatin1("%1,%2,%3") .arg(QLatin1String(Protocol::ModeProduction)) .arg(socketName) .arg(key); KeepAliveObject *object = new KeepAliveObject; object->moveToThread(&m_thread); QObject::connect(&m_thread, &QThread::started, object, &KeepAliveObject::start); QObject::connect(&m_thread, &QThread::finished, object, &QObject::deleteLater); m_thread.start(); } else if (mode == Protocol::Mode::Debug) { // To be able to debug the client-server connection start and stop the server manually, // e.g. installer --start-server DEBUG. } } void setAuthorizationFallbackDisabled(bool disabled) { m_authorizationFallbackDisabled = disabled; } void maybeStartServer() { if (m_mode == Protocol::Mode::Debug) m_serverStarted = true; // we expect the server to be started by the developer if (m_serverStarted) return; const QMutexLocker ml(&m_mutex); if (m_serverStarted) return; m_serverStarted = false; bool started = false; if (m_startServerAs == Protocol::StartAs::SuperUser) { started = AdminAuthorization::execute(0, m_serverCommand, m_serverArguments); if (!started) { if (m_authorizationFallbackDisabled) { QMessageBox::Button res = QMessageBox::Retry; while (res == QMessageBox::Retry && !started) { res = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("AuthorizationError"), QCoreApplication::translate("RemoteClient", "Cannot get authorization."), QCoreApplication::translate("RemoteClient", "Cannot get authorization that is needed for continuing the installation.\n\n" "Please start the setup program as a user with the appropriate rights.\n" "Or accept the elevation of access rights if being asked."), QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Abort); if (res == QMessageBox::Retry) started = AdminAuthorization::execute(0, m_serverCommand, m_serverArguments); } } else { // something went wrong with authorizing, either user pressed cancel or entered // wrong password const QString fallback = m_serverCommand + QLatin1String(" ") + m_serverArguments .join(QLatin1String(" ")); const QMessageBox::Button res = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("AuthorizationError"), QCoreApplication::translate("RemoteClient", "Cannot get authorization."), QCoreApplication::translate("RemoteClient", "Cannot get authorization that " "is needed for continuing the installation.\n Either abort the " "installation or use the fallback solution by running\n\n%1\n\nas a user " "with the appropriate rights and then clicking OK.").arg(fallback), QMessageBox::Abort | QMessageBox::Ok, QMessageBox::Ok); if (res == QMessageBox::Ok) started = true; } } } else { started = QInstaller::startDetached(m_serverCommand, m_serverArguments, QCoreApplication::applicationDirPath()); } if (started) { QElapsedTimer t; t.start(); // 30 seconds waiting ought to be enough for the app to start while ((!m_serverStarted) && (t.elapsed() < 30000)) m_serverStarted = authorize(); } } void maybeStopServer() { if (m_mode == Protocol::Mode::Debug) m_serverStarted = false; // we never started the server in debug mode if (!m_serverStarted) return; const QMutexLocker ml(&m_mutex); if (!m_serverStarted) return; if (!authorize()) return; m_serverStarted = !callRemoteMethod<bool>(QString::fromLatin1(Protocol::Shutdown)); } private: RemoteClient *q_ptr; QMutex m_mutex; QString m_socketName; Protocol::StartAs m_startServerAs; bool m_serverStarted; bool m_active; QString m_serverCommand; QStringList m_serverArguments; QString m_key; QThread m_thread; Protocol::Mode m_mode; bool m_authorizationFallbackDisabled; }; } // namespace QInstaller #endif // REMOTECLIENT_P_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remotefileengine.cpp��������������������������������0100777�0000000�0000000�00000034576�13761647206�022661� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "remotefileengine.h" #include "protocol.h" #include "remoteclient.h" #include <QRegExp> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::RemoteFileEngineHandler \internal */ // -- RemoteFileEngineHandler QAbstractFileEngine* RemoteFileEngineHandler::create(const QString &fileName) const { if (!RemoteClient::instance().isActive()) return 0; static QRegExp re(QLatin1String("^[a-z0-9]*://.*$")); if (re.exactMatch(fileName)) // stuff like installer:// return 0; if (fileName.isEmpty() || fileName.startsWith(QLatin1String(":"))) return 0; // empty filename or Qt resource QScopedPointer<RemoteFileEngine> client(new RemoteFileEngine()); client->setFileName(fileName); if (client->isConnectedToServer()) return client.take(); return 0; } // -- RemoteFileEngineIterator class RemoteFileEngineIterator : public QAbstractFileEngineIterator { public: RemoteFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &files) : QAbstractFileEngineIterator(filters, nameFilters) , index(-1) , entries(files) { } QString next(); bool hasNext() const; QString currentFileName() const; private: qint32 index; QStringList entries; }; /* Advances the iterator to the next entry, and returns the current file path of this new entry. If hasNext() returns \c false, the function does nothing and returns an empty QString. */ bool RemoteFileEngineIterator::hasNext() const { return index < entries.size() - 1; } /* Returns \c true if there is at least one more entry in the directory, otherwise returns \c false. */ QString RemoteFileEngineIterator::next() { if (!hasNext()) return QString(); ++index; return currentFilePath(); } /* Returns the name of the current directory entry, excluding the path. */ QString RemoteFileEngineIterator::currentFileName() const { return entries.at(index); } /*! \class QInstaller::RemoteFileEngine \inmodule QtInstallerFramework \internal */ RemoteFileEngine::RemoteFileEngine() : RemoteObject(QLatin1String(Protocol::QAbstractFileEngine)) { } RemoteFileEngine::~RemoteFileEngine() { } /*! */ bool RemoteFileEngine::atEnd() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineAtEnd)); return m_fileEngine.atEnd(); } /*! \reimp */ QAbstractFileEngine::Iterator* RemoteFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) { if (connectToServer()) { QStringList entries = entryList(filters, filterNames); entries.removeAll(QString()); return new RemoteFileEngineIterator(filters, filterNames, entries); } return m_fileEngine.beginEntryList(filters, filterNames); } QAbstractFileEngine::Iterator* RemoteFileEngine::endEntryList() { if (connectToServer()) return 0; // right now all other implementations return 0 too return m_fileEngine.endEntryList(); } /*! \reimp */ bool RemoteFileEngine::caseSensitive() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineCaseSensitive)); return m_fileEngine.caseSensitive(); } /*! \reimp */ bool RemoteFileEngine::close() { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineClose)); return m_fileEngine.close(); } /*! \reimp */ bool RemoteFileEngine::copy(const QString &newName) { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineCopy), newName); return m_fileEngine.copy(newName); } /*! \reimp */ QStringList RemoteFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<QStringList> (QString::fromLatin1(Protocol::QAbstractFileEngineEntryList), static_cast<qint32>(filters), filterNames); } return m_fileEngine.entryList(filters, filterNames); } /*! */ QFile::FileError RemoteFileEngine::error() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return static_cast<QFile::FileError> (callRemoteMethod<qint32>(QString::fromLatin1(Protocol::QAbstractFileEngineError))); } return m_fileEngine.error(); } /*! */ QString RemoteFileEngine::errorString() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineErrorString)); return m_fileEngine.errorString(); } /*! \reimp */ bool RemoteFileEngine::extension(Extension extension, const ExtensionOption *eo, ExtensionReturn *er) { if (connectToServer()) return false; return m_fileEngine.extension(extension, eo, er); } /*! \reimp */ QAbstractFileEngine::FileFlags RemoteFileEngine::fileFlags(FileFlags type) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return static_cast<QAbstractFileEngine::FileFlags> (callRemoteMethod<qint32>(QString::fromLatin1(Protocol::QAbstractFileEngineFileFlags), static_cast<qint32>(type))); } return m_fileEngine.fileFlags(type); } /*! \reimp */ QString RemoteFileEngine::fileName(FileName file) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineFileName), static_cast<qint32>(file)); } return m_fileEngine.fileName(file); } /*! \reimp */ bool RemoteFileEngine::flush() { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineFlush)); return m_fileEngine.flush(); } /*! \reimp */ int RemoteFileEngine::handle() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<qint32>(QString::fromLatin1(Protocol::QAbstractFileEngineHandle)); return m_fileEngine.handle(); } /*! \reimp */ bool RemoteFileEngine::isRelativePath() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineIsRelativePath)); return m_fileEngine.isRelativePath(); } /*! \reimp */ bool RemoteFileEngine::isSequential() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineIsSequential)); return m_fileEngine.isSequential(); } /*! \reimp */ bool RemoteFileEngine::link(const QString &newName) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineLink), newName); } return m_fileEngine.link(newName); } /*! \reimp */ bool RemoteFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineMkdir), dirName, createParentDirectories); } return m_fileEngine.mkdir(dirName, createParentDirectories); } /*! \reimp */ bool RemoteFileEngine::open(QIODevice::OpenMode mode) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen), static_cast<qint32>(mode | QIODevice::Unbuffered)); } return m_fileEngine.open(mode | QIODevice::Unbuffered); } /*! \reimp */ QString RemoteFileEngine::owner(FileOwner owner) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<QString>(QString::fromLatin1(Protocol::QAbstractFileEngineOwner), static_cast<qint32>(owner)); } return m_fileEngine.owner(owner); } /*! \reimp */ uint RemoteFileEngine::ownerId(FileOwner owner) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<quint32>(QString::fromLatin1(Protocol::QAbstractFileEngineOwnerId), static_cast<qint32>(owner)); } return m_fileEngine.ownerId(owner); } /*! \reimp */ qint64 RemoteFileEngine::pos() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEnginePos)); return m_fileEngine.pos(); } /*! \reimp */ bool RemoteFileEngine::remove() { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRemove)); return m_fileEngine.remove(); } /*! \reimp */ bool RemoteFileEngine::rename(const QString &newName) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRename), newName); } return m_fileEngine.rename(newName); } /*! \reimp */ bool RemoteFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineRmdir), dirName, recurseParentDirectories); } return m_fileEngine.rmdir(dirName, recurseParentDirectories); } /*! \reimp */ bool RemoteFileEngine::seek(qint64 offset) { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSeek), offset); return m_fileEngine.seek(offset); } /*! \reimp */ void RemoteFileEngine::setFileName(const QString &fileName) { if (connectToServer()) { callRemoteMethod(QString::fromLatin1(Protocol::QAbstractFileEngineSetFileName), fileName, dummy); } m_fileEngine.setFileName(fileName); } /*! \reimp */ bool RemoteFileEngine::setPermissions(uint perms) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSetPermissions), perms); } return m_fileEngine.setPermissions(perms); } /*! \reimp */ bool RemoteFileEngine::setSize(qint64 size) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSetSize), size); } return m_fileEngine.setSize(size); } /*! \reimp */ qint64 RemoteFileEngine::size() const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEngineSize)); return m_fileEngine.size(); } /*! \reimp */ bool RemoteFileEngine::supportsExtension(Extension extension) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) return false; return m_fileEngine.supportsExtension(extension); } /*! \reimp */ qint64 RemoteFileEngine::read(char *data, qint64 maxlen) { if (connectToServer()) { QPair<qint64, QByteArray> result = callRemoteMethod<QPair<qint64, QByteArray> > (QString::fromLatin1(Protocol::QAbstractFileEngineRead), maxlen); if (result.first <= 0) return result.first; QDataStream dataStream(result.second); dataStream.readRawData(data, result.first); return result.first; } return m_fileEngine.read(data, maxlen); } /*! \reimp */ qint64 RemoteFileEngine::readLine(char *data, qint64 maxlen) { if (connectToServer()) { QPair<qint64, QByteArray> result = callRemoteMethod<QPair<qint64, QByteArray> > (QString::fromLatin1(Protocol::QAbstractFileEngineReadLine), maxlen); if (result.first <= 0) return result.first; QDataStream dataStream(result.second); dataStream.readRawData(data, result.first); return result.first; } return m_fileEngine.readLine(data, maxlen); } /*! \reimp */ qint64 RemoteFileEngine::write(const char *data, qint64 len) { if (connectToServer()) { QByteArray ba(data, len); return callRemoteMethod<qint64>(QString::fromLatin1(Protocol::QAbstractFileEngineWrite), ba); } return m_fileEngine.write(data, len); } bool RemoteFileEngine::syncToDisk() { if (connectToServer()) return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineSyncToDisk)); return m_fileEngine.syncToDisk(); } bool RemoteFileEngine::renameOverwrite(const QString &newName) { if (connectToServer()) { return callRemoteMethod<bool> (QString::fromLatin1(Protocol::QAbstractFileEngineRenameOverwrite), newName); } return m_fileEngine.renameOverwrite(newName); } QDateTime RemoteFileEngine::fileTime(FileTime time) const { if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) { return callRemoteMethod<QDateTime> (QString::fromLatin1(Protocol::QAbstractFileEngineFileTime), static_cast<qint32> (time)); } return m_fileEngine.fileTime(time); } } // namespace QInstaller ����������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remotefileengine.h����������������������������������0100777�0000000�0000000�00000010274�13761647206�022313� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTEFILEENGINE_H #define REMOTEFILEENGINE_H #include "remoteobject.h" #include <QtCore/private/qabstractfileengine_p.h> #include <QtCore/private/qfsfileengine_p.h> namespace QInstaller { class INSTALLER_EXPORT RemoteFileEngineHandler : public QAbstractFileEngineHandler { Q_DISABLE_COPY(RemoteFileEngineHandler) public: RemoteFileEngineHandler() : QAbstractFileEngineHandler() {} QAbstractFileEngine* create(const QString &fileName) const Q_DECL_OVERRIDE; }; class RemoteFileEngine : public RemoteObject, public QAbstractFileEngine { Q_DISABLE_COPY(RemoteFileEngine) public: RemoteFileEngine(); ~RemoteFileEngine(); bool open(QIODevice::OpenMode mode) Q_DECL_OVERRIDE; bool close() Q_DECL_OVERRIDE; bool flush() Q_DECL_OVERRIDE; bool syncToDisk() Q_DECL_OVERRIDE; qint64 size() const Q_DECL_OVERRIDE; qint64 pos() const Q_DECL_OVERRIDE; bool seek(qint64 offset) Q_DECL_OVERRIDE; bool isSequential() const Q_DECL_OVERRIDE; bool remove() Q_DECL_OVERRIDE; bool copy(const QString &newName) Q_DECL_OVERRIDE; bool rename(const QString &newName) Q_DECL_OVERRIDE; bool renameOverwrite(const QString &newName) Q_DECL_OVERRIDE; bool link(const QString &newName) Q_DECL_OVERRIDE; bool mkdir(const QString &dirName, bool createParentDirectories) const Q_DECL_OVERRIDE; bool rmdir(const QString &dirName, bool recurseParentDirectories) const Q_DECL_OVERRIDE; bool setSize(qint64 size) Q_DECL_OVERRIDE; bool caseSensitive() const Q_DECL_OVERRIDE; bool isRelativePath() const Q_DECL_OVERRIDE; QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE; FileFlags fileFlags(FileFlags type = FileInfoAll) const Q_DECL_OVERRIDE; bool setPermissions(uint perms) Q_DECL_OVERRIDE; QString fileName(FileName file = DefaultName) const Q_DECL_OVERRIDE; uint ownerId(FileOwner owner) const Q_DECL_OVERRIDE; QString owner(FileOwner owner) const Q_DECL_OVERRIDE; QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE; void setFileName(const QString &fileName) Q_DECL_OVERRIDE; int handle() const Q_DECL_OVERRIDE; bool atEnd() const; uchar *map(qint64, qint64, QFile::MemoryMapFlags) { return 0; } bool unmap(uchar *) { return true; } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; Iterator *endEntryList() Q_DECL_OVERRIDE; qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 readLine(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; QFile::FileError error() const; QString errorString() const; bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE; bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE; private: QFSFileEngine m_fileEngine; }; } // namespace QInstaller #endif // REMOTEFILEENGINE_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteobject.cpp������������������������������������0100777�0000000�0000000�00000007313�13761647206�022007� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "remoteobject.h" #include "protocol.h" #include "remoteclient.h" #include <QCoreApplication> #include <QElapsedTimer> #include <QThread> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::RemoteObject \internal */ RemoteObject::RemoteObject(const QString &wrappedType, QObject *parent) : QObject(parent) , dummy(nullptr) , m_type(wrappedType) , m_socket(nullptr) { Q_ASSERT_X(!m_type.isEmpty(), Q_FUNC_INFO, "The wrapped Qt type needs to be passed as " "argument and cannot be empty."); } RemoteObject::~RemoteObject() { if (m_socket) { if (QThread::currentThread() == m_socket->thread()) { if (m_type != QLatin1String("RemoteClientPrivate")) writeData(QLatin1String(Protocol::Destroy), m_type, dummy, dummy); } else { Q_ASSERT_X(false, Q_FUNC_INFO, "Socket running in a different Thread than this object."); } delete m_socket; } } bool RemoteObject::authorize() { if (m_socket && (m_socket->state() == QLocalSocket::ConnectedState)) return true; if (m_socket) delete m_socket; m_socket = new QLocalSocket; m_socket->connectToServer(RemoteClient::instance().socketName()); if (m_socket->waitForConnected()) { bool authorized = callRemoteMethod<bool>(QString::fromLatin1(Protocol::Authorize), RemoteClient::instance().authorizationKey()); if (authorized) return true; } delete m_socket; m_socket = nullptr; return false; } bool RemoteObject::connectToServer(const QVariantList &arguments) { if (!RemoteClient::instance().isActive()) return false; if (m_socket && (m_socket->state() == QLocalSocket::ConnectedState)) return true; if (!authorize()) return false; QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); out << m_type; foreach (const QVariant &arg, arguments) out << arg; sendPacket(m_socket, Protocol::Create, data); m_socket->flush(); return true; } bool RemoteObject::isConnectedToServer() const { if ((!m_socket) || (!RemoteClient::instance().isActive())) return false; if (m_socket && (m_socket->state() == QLocalSocket::ConnectedState)) return true; return false; } void RemoteObject::callRemoteMethod(const QString &name) { writeData(name, dummy, dummy, dummy); } } // namespace QInstaller ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteobject.h��������������������������������������0100777�0000000�0000000�00000011772�13761647206�021460� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTEOBJECT_H #define REMOTEOBJECT_H #include "errors.h" #include "installer_global.h" #include "protocol.h" #include <QCoreApplication> #include <QDataStream> #include <QObject> #include <QLocalSocket> namespace QInstaller { class INSTALLER_EXPORT RemoteObject : public QObject { Q_OBJECT Q_DISABLE_COPY(RemoteObject) public: RemoteObject(const QString &wrappedType, QObject *parent = 0); virtual ~RemoteObject() = 0; bool isConnectedToServer() const; void callRemoteMethod(const QString &name); template<typename T1, typename T2> void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2) { writeData(name, arg, arg2, dummy); } template<typename T1, typename T2, typename T3> void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 & arg3) { writeData(name, arg, arg2, arg3); } template<typename T> T callRemoteMethod(const QString &name) const { return callRemoteMethod<T>(name, dummy, dummy, dummy); } template<typename T, typename T1> T callRemoteMethod(const QString &name, const T1 &arg) const { return callRemoteMethod<T>(name, arg, dummy, dummy); } template<typename T, typename T1, typename T2> T callRemoteMethod(const QString &name, const T1 & arg, const T2 &arg2) const { return callRemoteMethod<T>(name, arg, arg2, dummy); } template<typename T, typename T1, typename T2, typename T3> T callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const { writeData(name, arg, arg2, arg3); while (m_socket->bytesToWrite()) m_socket->waitForBytesWritten(); QByteArray command; QByteArray data; while (!receivePacket(m_socket, &command, &data)) { if (!m_socket->waitForReadyRead(-1)) { throw Error(tr("Cannot read all data after sending command: %1. " "Bytes expected: %2, Bytes received: %3. Error: %4").arg(name).arg(0) .arg(m_socket->bytesAvailable()).arg(m_socket->errorString())); } } Q_ASSERT(command == Protocol::Reply); QDataStream stream(&data, QIODevice::ReadOnly); T result; stream >> result; Q_ASSERT(stream.status() == QDataStream::Ok); Q_ASSERT(stream.atEnd()); return result; } protected: bool authorize(); bool connectToServer(const QVariantList &arguments = QVariantList()); // Use this structure to allow derived classes to manipulate the template // function signature of the callRemoteMethod templates, since most of the // generated functions will differ in return type rather given arguments. struct Dummy {}; Dummy *dummy; private: template<typename T> bool isValueType(T) const { return true; } template<typename T> bool isValueType(T *dummy) const { // Force compiler error while passing anything different then Dummy* to the function. // It really doesn't make sense to send any pointer over to the server, so bail early. Q_UNUSED(static_cast<Dummy*> (dummy)) return false; } template<typename T1, typename T2, typename T3> void writeData(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const { QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); if (isValueType(arg)) out << arg; if (isValueType(arg2)) out << arg2; if (isValueType(arg3)) out << arg3; sendPacket(m_socket, name.toLatin1(), data); m_socket->flush(); } private: QString m_type; QLocalSocket *m_socket; }; } // namespace QInstaller #endif // REMOTEOBJECT_H ������qt-installer-framework-4.0.1/src/libs/installer/remoteserver.cpp������������������������������������0100777�0000000�0000000�00000011264�13761647206�022047� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "remoteserver.h" #include "remoteserver_p.h" #include "repository.h" namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::LocalServer \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::RemoteServerPrivate \internal */ /*! Constructs an remote server object with \a parent. */ RemoteServer::RemoteServer(QObject *parent) : QObject(parent) , d_ptr(new RemoteServerPrivate(this)) { Repository::registerMetaType(); // register, cause we stream the type as QVariant } /*! Destroys the remote server object. */ RemoteServer::~RemoteServer() { Q_D(RemoteServer); d->m_thread.quit(); d->m_thread.wait(); } /*! Starts the server. \note If running in debug mode, the timer that kills the server after 30 seconds without usage is not started, so the server runs in an endless loop. */ void RemoteServer::start() { Q_D(RemoteServer); if (d->m_localServer) return; #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // avoid writing to stderr: // the parent process has redirected stderr to a pipe to work with sudo, // but is not reading anymore -> writing to stderr will block after a while. if (d->m_mode == Protocol::Mode::Production) fclose(stderr); #endif d->m_localServer = new LocalServer(d->m_socketName, d->m_key); d->m_localServer->moveToThread(&d->m_thread); connect(&d->m_thread, &QThread::finished, d->m_localServer, &QObject::deleteLater); connect(d->m_localServer, &LocalServer::newIncomingConnection, this, &RemoteServer::restartWatchdog); connect(d->m_localServer, &LocalServer::shutdownRequested, this, &QObject::deleteLater); d->m_thread.start(); if (d->m_mode == Protocol::Mode::Production) { connect(d->m_watchdog.data(), &QTimer::timeout, this, &QObject::deleteLater); d->m_watchdog->start(); } } /*! Initializes the server with \a socketName, with \a key, the key the client needs to send to authenticate with the server, and \a mode. */ void RemoteServer::init(const QString &socketName, const QString &key, Protocol::Mode mode) { Q_D(RemoteServer); // Since Qt 5.12.0, we should determince the full socket path on Unix // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). // Otherwise the new canonical implementation of QDir::tempPath() // presents unintended usage of RemoteFileEngine. #if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) d->m_socketName = socketPathName(socketName); #else d->m_socketName = socketName; #endif d->m_key = key; d->m_mode = mode; } /*! Returns the socket name the server is listening on. */ QString RemoteServer::socketName() const { Q_D(const RemoteServer); return d->m_socketName; } /*! Returns the authorization key. */ QString RemoteServer::authorizationKey() const { Q_D(const RemoteServer); return d->m_key; } QString RemoteServer::socketPathName(const QString &socketName) const { QString socketPathName; if (socketName.startsWith(QLatin1Char('/'))) { socketPathName = socketName; } else { socketPathName = QDir::tempPath(); socketPathName += QLatin1Char('/') + socketName; } return socketPathName; } /*! Restarts the watchdog that tries to kill the server. */ void RemoteServer::restartWatchdog() { Q_D(RemoteServer); if (d->m_watchdog) d->m_watchdog->start(); } } // namespace QInstaller ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteserver.h��������������������������������������0100777�0000000�0000000�00000004005�13761647206�021507� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTESERVER_H #define REMOTESERVER_H #include "installer_global.h" #include "protocol.h" #include <QObject> namespace QInstaller { class RemoteServerPrivate; class INSTALLER_EXPORT RemoteServer : public QObject { Q_OBJECT Q_DISABLE_COPY(RemoteServer) Q_DECLARE_PRIVATE(RemoteServer) public: explicit RemoteServer(QObject *parent = 0); ~RemoteServer(); void start(); void init(const QString &socketName, const QString &authorizationKey, Protocol::Mode mode); QString socketName() const; QString authorizationKey() const; QString socketPathName(const QString &socketName) const; private slots: void restartWatchdog(); private: QScopedPointer<RemoteServerPrivate> d_ptr; }; } // namespace QInstaller #endif // REMOTESERVER_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteserverconnection.cpp��������������������������0100777�0000000�0000000�00000054427�13761647206�024137� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "remoteserverconnection.h" #include "errors.h" #include "protocol.h" #include "remoteserverconnection_p.h" #include "utils.h" #include "permissionsettings.h" #include "globals.h" #include <QCoreApplication> #include <QDataStream> #include <QLocalSocket> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::RemoteServerConnection \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::QProcessSignalReceiver \internal */ RemoteServerConnection::RemoteServerConnection(qintptr socketDescriptor, const QString &key, QObject *parent) : QThread(parent) , m_socketDescriptor(socketDescriptor) , m_process(nullptr) , m_engine(nullptr) , m_authorizationKey(key) , m_signalReceiver(nullptr) { setObjectName(QString::fromLatin1("RemoteServerConnection(%1)").arg(socketDescriptor)); } // Helper RAII to ensure stream data was correctly (and completely) read struct StreamChecker { StreamChecker(QDataStream *stream) : stream(stream) {} ~StreamChecker() { Q_ASSERT(stream->status() == QDataStream::Ok); Q_ASSERT(stream->atEnd()); } private: QDataStream *stream; }; void RemoteServerConnection::run() { QLocalSocket socket; socket.setSocketDescriptor(m_socketDescriptor); QScopedPointer<PermissionSettings> settings; bool authorized = false; while (socket.state() == QLocalSocket::ConnectedState) { QByteArray cmd; QByteArray data; if (!receivePacket(&socket, &cmd, &data)) { socket.waitForReadyRead(250); continue; } const QString command = QString::fromLatin1(cmd); QBuffer buf; buf.setBuffer(&data); buf.open(QIODevice::ReadOnly); QDataStream stream; stream.setDevice(&buf); StreamChecker streamChecker(&stream); if (authorized && command == QLatin1String(Protocol::Shutdown)) { authorized = false; sendData(&socket, true); socket.flush(); socket.close(); emit shutdownRequested(); return; } else if (command == QLatin1String(Protocol::Authorize)) { QString key; stream >> key; sendData(&socket, (authorized = (key == m_authorizationKey))); socket.flush(); if (!authorized) { socket.close(); return; } } else if (authorized) { if (command.isEmpty()) continue; if (command == QLatin1String(Protocol::Create)) { QString type; stream >> type; if (type == QLatin1String(Protocol::QSettings)) { QVariant application; QVariant organization; QVariant scope, format; QVariant fileName; stream >> application; stream >> organization; stream >> scope; stream >> format; stream >> fileName; if (fileName.toString().isEmpty()) { settings.reset(new PermissionSettings(QSettings::Format(format.toInt()), QSettings::Scope(scope.toInt()), organization.toString(), application .toString())); } else { settings.reset(new PermissionSettings(fileName.toString(), QSettings::Format(format.toInt()))); } } else if (type == QLatin1String(Protocol::QProcess)) { if (m_process) m_process->deleteLater(); m_process = new QProcess; m_signalReceiver = new QProcessSignalReceiver(m_process); } else if (type == QLatin1String(Protocol::QAbstractFileEngine)) { if (m_engine) delete m_engine; m_engine = new QFSFileEngine; } continue; } if (command == QLatin1String(Protocol::Destroy)) { QString type; stream >> type; if (type == QLatin1String(Protocol::QSettings)) { settings.reset(); } else if (type == QLatin1String(Protocol::QProcess)) { m_signalReceiver->m_receivedSignals.clear(); m_process->deleteLater(); m_process = nullptr; } else if (type == QLatin1String(Protocol::QAbstractFileEngine)) { delete m_engine; m_engine = nullptr; } return; } if (command == QLatin1String(Protocol::GetQProcessSignals)) { if (m_signalReceiver) { QMutexLocker _(&m_signalReceiver->m_lock); sendData(&socket, m_signalReceiver->m_receivedSignals); socket.flush(); m_signalReceiver->m_receivedSignals.clear(); } continue; } if (command.startsWith(QLatin1String(Protocol::QProcess))) { handleQProcess(&socket, command, stream); } else if (command.startsWith(QLatin1String(Protocol::QSettings))) { handleQSettings(&socket, command, stream, settings.data()); } else if (command.startsWith(QLatin1String(Protocol::QAbstractFileEngine))) { handleQFSFileEngine(&socket, command, stream); } else { qCDebug(QInstaller::lcServer) << "Unknown command:" << command; } socket.flush(); } else { // authorization failed, connection not wanted socket.close(); qCDebug(QInstaller::lcServer) << "Unknown command:" << command; return; } } } template <typename T> void RemoteServerConnection::sendData(QIODevice *device, const T &data) { QByteArray result; QDataStream returnStream(&result, QIODevice::WriteOnly); returnStream << data; sendPacket(device, Protocol::Reply, result); } void RemoteServerConnection::handleQProcess(QIODevice *socket, const QString &command, QDataStream &data) { if (command == QLatin1String(Protocol::QProcessCloseWriteChannel)) { m_process->closeWriteChannel(); } else if (command == QLatin1String(Protocol::QProcessExitCode)) { sendData(socket, m_process->exitCode()); } else if (command == QLatin1String(Protocol::QProcessExitStatus)) { sendData(socket, static_cast<qint32> (m_process->exitStatus())); } else if (command == QLatin1String(Protocol::QProcessKill)) { m_process->kill(); } else if (command == QLatin1String(Protocol::QProcessReadAll)) { sendData(socket, m_process->readAll()); } else if (command == QLatin1String(Protocol::QProcessReadAllStandardOutput)) { sendData(socket, m_process->readAllStandardOutput()); } else if (command == QLatin1String(Protocol::QProcessReadAllStandardError)) { sendData(socket, m_process->readAllStandardError()); } else if (command == QLatin1String(Protocol::QProcessStartDetached)) { QString program; QStringList arguments; QString workingDirectory; data >> program; data >> arguments; data >> workingDirectory; qint64 pid = -1; bool success = QInstaller::startDetached(program, arguments, workingDirectory, &pid); sendData(socket, qMakePair< bool, qint64>(success, pid)); } else if (command == QLatin1String(Protocol::QProcessSetWorkingDirectory)) { QString dir; data >> dir; m_process->setWorkingDirectory(dir); } else if (command == QLatin1String(Protocol::QProcessSetEnvironment)) { QStringList env; data >> env; m_process->setEnvironment(env); } else if (command == QLatin1String(Protocol::QProcessEnvironment)) { sendData(socket, m_process->environment()); } else if (command == QLatin1String(Protocol::QProcessStart3Arg)) { QString program; QStringList arguments; qint32 mode; data >> program; data >> arguments; data >> mode; m_process->start(program, arguments, static_cast<QIODevice::OpenMode> (mode)); } else if (command == QLatin1String(Protocol::QProcessStart2Arg)) { QString program; qint32 mode; data >> program; data >> mode; m_process->start(program, static_cast<QIODevice::OpenMode> (mode)); } else if (command == QLatin1String(Protocol::QProcessState)) { sendData(socket, static_cast<qint32> (m_process->state())); } else if (command == QLatin1String(Protocol::QProcessTerminate)) { m_process->terminate(); } else if (command == QLatin1String(Protocol::QProcessWaitForFinished)) { qint32 msecs; data >> msecs; sendData(socket, m_process->waitForFinished(msecs)); } else if (command == QLatin1String(Protocol::QProcessWaitForStarted)) { qint32 msecs; data >> msecs; sendData(socket, m_process->waitForStarted(msecs)); } else if (command == QLatin1String(Protocol::QProcessWorkingDirectory)) { sendData(socket, m_process->workingDirectory()); } else if (command == QLatin1String(Protocol::QProcessErrorString)) { sendData(socket, m_process->errorString()); } else if (command == QLatin1String(Protocol::QProcessReadChannel)) { sendData(socket, static_cast<qint32> (m_process->readChannel())); } else if (command == QLatin1String(Protocol::QProcessSetReadChannel)) { qint32 processChannel; data >> processChannel; m_process->setReadChannel(static_cast<QProcess::ProcessChannel>(processChannel)); } else if (command == QLatin1String(Protocol::QProcessWrite)) { QByteArray byteArray; data >> byteArray; sendData(socket, m_process->write(byteArray)); } else if (command == QLatin1String(Protocol::QProcessProcessChannelMode)) { sendData(socket, static_cast<qint32> (m_process->processChannelMode())); } else if (command == QLatin1String(Protocol::QProcessSetProcessChannelMode)) { qint32 processChannel; data >> processChannel; m_process->setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(processChannel)); } #ifdef Q_OS_WIN else if (command == QLatin1String(Protocol::QProcessSetNativeArguments)) { QString arguments; data >> arguments; m_process->setNativeArguments(arguments); } #endif else if (!command.isEmpty()) { qCDebug(QInstaller::lcServer) << "Unknown QProcess command:" << command; } } void RemoteServerConnection::handleQSettings(QIODevice *socket, const QString &command, QDataStream &data, PermissionSettings *settings) { if (!settings) return; if (command == QLatin1String(Protocol::QSettingsAllKeys)) { sendData(socket, settings->allKeys()); } else if (command == QLatin1String(Protocol::QSettingsBeginGroup)) { QString prefix; data >> prefix; settings->beginGroup(prefix); } else if (command == QLatin1String(Protocol::QSettingsBeginWriteArray)) { QString prefix; data >> prefix; qint32 size; data >> size; settings->beginWriteArray(prefix, size); } else if (command == QLatin1String(Protocol::QSettingsBeginReadArray)) { QString prefix; data >> prefix; sendData(socket, settings->beginReadArray(prefix)); } else if (command == QLatin1String(Protocol::QSettingsChildGroups)) { sendData(socket, settings->childGroups()); } else if (command == QLatin1String(Protocol::QSettingsChildKeys)) { sendData(socket, settings->childKeys()); } else if (command == QLatin1String(Protocol::QSettingsClear)) { settings->clear(); } else if (command == QLatin1String(Protocol::QSettingsContains)) { QString key; data >> key; sendData(socket, settings->contains(key)); } else if (command == QLatin1String(Protocol::QSettingsEndArray)) { settings->endArray(); } else if (command == QLatin1String(Protocol::QSettingsEndGroup)) { settings->endGroup(); } else if (command == QLatin1String(Protocol::QSettingsFallbacksEnabled)) { sendData(socket, settings->fallbacksEnabled()); } else if (command == QLatin1String(Protocol::QSettingsFileName)) { sendData(socket, settings->fileName()); } else if (command == QLatin1String(Protocol::QSettingsGroup)) { sendData(socket, settings->group()); } else if (command == QLatin1String(Protocol::QSettingsIsWritable)) { sendData(socket, settings->isWritable()); } else if (command == QLatin1String(Protocol::QSettingsRemove)) { QString key; data >> key; settings->remove(key); } else if (command == QLatin1String(Protocol::QSettingsSetArrayIndex)) { qint32 i; data >> i; settings->setArrayIndex(i); } else if (command == QLatin1String(Protocol::QSettingsSetFallbacksEnabled)) { bool b; data >> b; settings->setFallbacksEnabled(b); } else if (command == QLatin1String(Protocol::QSettingsStatus)) { sendData(socket, settings->status()); } else if (command == QLatin1String(Protocol::QSettingsSync)) { settings->sync(); } else if (command == QLatin1String(Protocol::QSettingsSetValue)) { QString key; QVariant value; data >> key; data >> value; settings->setValue(key, value); } else if (command == QLatin1String(Protocol::QSettingsValue)) { QString key; QVariant defaultValue; data >> key; data >> defaultValue; sendData(socket, settings->value(key, defaultValue)); } else if (command == QLatin1String(Protocol::QSettingsOrganizationName)) { sendData(socket, settings->organizationName()); } else if (command == QLatin1String(Protocol::QSettingsApplicationName)) { sendData(socket, settings->applicationName()); } else if (!command.isEmpty()) { qCDebug(QInstaller::lcServer) << "Unknown QSettings command:" << command; } } void RemoteServerConnection::handleQFSFileEngine(QIODevice *socket, const QString &command, QDataStream &data) { if (command == QLatin1String(Protocol::QAbstractFileEngineAtEnd)) { sendData(socket, m_engine->atEnd()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineCaseSensitive)) { sendData(socket, m_engine->caseSensitive()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineClose)) { sendData(socket, m_engine->close()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) { QString newName; data >>newName; #ifdef Q_OS_LINUX // QFileSystemEngine::copyFile() is currently unimplemented on Linux, // copy using QFile instead of directly with QFSFileEngine. QFile file(m_engine->fileName(QAbstractFileEngine::AbsoluteName)); sendData(socket, file.copy(newName)); #else sendData(socket, m_engine->copy(newName)); #endif } else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) { qint32 filters; QStringList filterNames; data >>filters; data >>filterNames; sendData(socket, m_engine->entryList(static_cast<QDir::Filters> (filters), filterNames)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineError)) { sendData(socket, static_cast<qint32> (m_engine->error())); } else if (command == QLatin1String(Protocol::QAbstractFileEngineErrorString)) { sendData(socket, m_engine->errorString()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineFileFlags)) { qint32 flags; data >>flags; flags = m_engine->fileFlags(static_cast<QAbstractFileEngine::FileFlags>(flags)); sendData(socket, static_cast<qint32>(flags)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineFileName)) { qint32 file; data >>file; sendData(socket, m_engine->fileName(static_cast<QAbstractFileEngine::FileName> (file))); } else if (command == QLatin1String(Protocol::QAbstractFileEngineFlush)) { sendData(socket, m_engine->flush()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineHandle)) { sendData(socket, m_engine->handle()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineIsRelativePath)) { sendData(socket, m_engine->isRelativePath()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineIsSequential)) { sendData(socket, m_engine->isSequential()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineLink)) { QString newName; data >>newName; sendData(socket, m_engine->link(newName)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineMkdir)) { QString dirName; bool createParentDirectories; data >>dirName; data >>createParentDirectories; sendData(socket, m_engine->mkdir(dirName, createParentDirectories)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineOpen)) { qint32 openMode; data >>openMode; sendData(socket, m_engine->open(static_cast<QIODevice::OpenMode> (openMode))); } else if (command == QLatin1String(Protocol::QAbstractFileEngineOwner)) { qint32 owner; data >>owner; sendData(socket, m_engine->owner(static_cast<QAbstractFileEngine::FileOwner> (owner))); } else if (command == QLatin1String(Protocol::QAbstractFileEngineOwnerId)) { qint32 owner; data >>owner; sendData(socket, m_engine->ownerId(static_cast<QAbstractFileEngine::FileOwner> (owner))); } else if (command == QLatin1String(Protocol::QAbstractFileEnginePos)) { sendData(socket, m_engine->pos()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineRead)) { qint64 maxlen; data >> maxlen; QByteArray byteArray(maxlen, '\0'); const qint64 r = m_engine->read(byteArray.data(), maxlen); sendData(socket, qMakePair<qint64, QByteArray>(r, byteArray)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineReadLine)) { qint64 maxlen; data >> maxlen; QByteArray byteArray(maxlen, '\0'); const qint64 r = m_engine->readLine(byteArray.data(), maxlen); sendData(socket, qMakePair<qint64, QByteArray>(r, byteArray)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineRemove)) { sendData(socket, m_engine->remove()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineRename)) { QString newName; data >>newName; sendData(socket, m_engine->rename(newName)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineRmdir)) { QString dirName; bool recurseParentDirectories; data >>dirName; data >>recurseParentDirectories; sendData(socket, m_engine->rmdir(dirName, recurseParentDirectories)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSeek)) { quint64 offset; data >>offset; sendData(socket, m_engine->seek(offset)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSetFileName)) { QString fileName; data >>fileName; m_engine->setFileName(fileName); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSetPermissions)) { uint perms; data >>perms; sendData(socket, m_engine->setPermissions(perms)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSetSize)) { qint64 size; data >>size; sendData(socket, m_engine->setSize(size)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSize)) { sendData(socket, m_engine->size()); } else if ((command == QLatin1String(Protocol::QAbstractFileEngineSupportsExtension)) || (command == QLatin1String(Protocol::QAbstractFileEngineExtension))) { // Implemented client side. } else if (command == QLatin1String(Protocol::QAbstractFileEngineWrite)) { QByteArray content; data >> content; sendData(socket, m_engine->write(content.data(), content.size())); } else if (command == QLatin1String(Protocol::QAbstractFileEngineSyncToDisk)) { sendData(socket, m_engine->syncToDisk()); } else if (command == QLatin1String(Protocol::QAbstractFileEngineRenameOverwrite)) { QString newFilename; data >> newFilename; sendData(socket, m_engine->renameOverwrite(newFilename)); } else if (command == QLatin1String(Protocol::QAbstractFileEngineFileTime)) { qint32 filetime; data >> filetime; sendData(socket, m_engine->fileTime(static_cast<QAbstractFileEngine::FileTime> (filetime))); } else if (!command.isEmpty()) { qCDebug(QInstaller::lcServer) << "Unknown QAbstractFileEngine command:" << command; } } } // namespace QInstaller �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteserverconnection.h����������������������������0100777�0000000�0000000�00000004746�13761647206�023603� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTESERVERCONNECTION_H #define REMOTESERVERCONNECTION_H #include <QPointer> #include <QThread> #include <QtCore/private/qfsfileengine_p.h> QT_BEGIN_NAMESPACE class QProcess; class QIODevice; QT_END_NAMESPACE namespace QInstaller { class PermissionSettings; class QProcessSignalReceiver; class RemoteServerConnection : public QThread { Q_OBJECT Q_DISABLE_COPY(RemoteServerConnection) public: RemoteServerConnection(qintptr socketDescriptor, const QString &authorizationKey, QObject *parent); void run() Q_DECL_OVERRIDE; signals: void shutdownRequested(); private: template <typename T> void sendData(QIODevice *device, const T &arg); void handleQProcess(QIODevice *device, const QString &command, QDataStream &data); void handleQSettings(QIODevice *device, const QString &command, QDataStream &data, PermissionSettings *settings); void handleQFSFileEngine(QIODevice *device, const QString &command, QDataStream &data); private: qintptr m_socketDescriptor; QProcess *m_process; QFSFileEngine *m_engine; QString m_authorizationKey; QProcessSignalReceiver *m_signalReceiver; }; } // namespace QInstaller #endif // REMOTESERVERCONNECTION_H ��������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteserverconnection_p.h��������������������������0100777�0000000�0000000�00000011405�13761647206�024110� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTESERVERCONNECTION_P_H #define REMOTESERVERCONNECTION_P_H #include "protocol.h" #include <QMutex> #include <QProcess> #include <QVariant> namespace QInstaller { class QProcessSignalReceiver : public QObject { Q_OBJECT friend class RemoteServerConnection; private: explicit QProcessSignalReceiver(QProcess *process) : QObject(process) { connect(process, &QIODevice::bytesWritten, this, &QProcessSignalReceiver::onBytesWritten); connect(process, &QIODevice::aboutToClose, this, &QProcessSignalReceiver::onAboutToClose); connect(process, &QIODevice::readChannelFinished, this, &QProcessSignalReceiver::onReadChannelFinished); connect(process, SIGNAL(error(QProcess::ProcessError)), SLOT(onError(QProcess::ProcessError))); connect(process, &QProcess::readyReadStandardOutput, this, &QProcessSignalReceiver::onReadyReadStandardOutput); connect(process, &QProcess::readyReadStandardError, this, &QProcessSignalReceiver::onReadyReadStandardError); connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onFinished(int,QProcess::ExitStatus))); connect(process, &QIODevice::readyRead, this, &QProcessSignalReceiver::onReadyRead); connect(process, &QProcess::started, this, &QProcessSignalReceiver::onStarted); connect(process, &QProcess::stateChanged, this, &QProcessSignalReceiver::onStateChanged); } private Q_SLOTS: void onBytesWritten(qint64 count) { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalBytesWritten)); m_receivedSignals.append(count); } void onAboutToClose() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalAboutToClose)); } void onReadChannelFinished() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadChannelFinished)); } void onError(QProcess::ProcessError error) { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalError)); m_receivedSignals.append(static_cast<int> (error)); } void onReadyReadStandardOutput() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyReadStandardOutput)); } void onReadyReadStandardError() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyReadStandardError)); } void onFinished(int exitCode, QProcess::ExitStatus exitStatus) { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalFinished)); m_receivedSignals.append(exitCode); m_receivedSignals.append(static_cast<int> (exitStatus)); } void onReadyRead() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalReadyRead)); } void onStarted() { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalStarted)); } void onStateChanged(QProcess::ProcessState newState) { QMutexLocker _(&m_lock); m_receivedSignals.append(QLatin1String(Protocol::QProcessSignalStateChanged)); m_receivedSignals.append(static_cast<int>(newState)); } private: QMutex m_lock; QVariantList m_receivedSignals; }; } // namespace QInstaller #endif // REMOTESERVERCONNECTION_P_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/remoteserver_p.h������������������������������������0100777�0000000�0000000�00000006633�13761647206�022037� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REMOTESERVER_P_H #define REMOTESERVER_P_H #include "protocol.h" #include "remoteserver.h" #include "remoteserverconnection.h" #include <QHostAddress> #include <QPointer> #include <QLocalServer> #include <QTimer> namespace QInstaller { class LocalServer : public QLocalServer { Q_OBJECT Q_DISABLE_COPY(LocalServer) public: LocalServer(const QString &socketName, const QString &key) : QLocalServer(0) , m_key(key) , m_shutdown(false) { setSocketOptions(QLocalServer::WorldAccessOption); listen(socketName); } ~LocalServer() { shutdown(); } signals: void shutdownRequested(); void newIncomingConnection(); private slots: void shutdown() { m_shutdown = true; const QList<QThread *> threads = findChildren<QThread *>(); foreach (QThread *thread, threads) { thread->quit(); thread->wait(); } emit shutdownRequested(); } private: void incomingConnection(quintptr socketDescriptor) Q_DECL_OVERRIDE { if (m_shutdown) return; RemoteServerConnection *thread = new RemoteServerConnection(socketDescriptor, m_key, this); connect(thread, &QThread::finished, thread, &QObject::deleteLater); connect(thread, &RemoteServerConnection::shutdownRequested, this, &LocalServer::shutdown); thread->start(); emit newIncomingConnection(); } private: QString m_key; bool m_shutdown; }; class RemoteServerPrivate { Q_DECLARE_PUBLIC(RemoteServer) Q_DISABLE_COPY(RemoteServerPrivate) public: explicit RemoteServerPrivate(RemoteServer *server) : q_ptr(server) , m_localServer(0) , m_key(QLatin1String(Protocol::DefaultAuthorizationKey)) , m_mode(Protocol::Mode::Debug) , m_watchdog(new QTimer) { m_watchdog->setInterval(30000); m_watchdog->setSingleShot(true); } private: RemoteServer *q_ptr; LocalServer *m_localServer; QString m_key; QString m_socketName; QThread m_thread; Protocol::Mode m_mode; QScopedPointer<QTimer> m_watchdog; }; } // namespace QInstaller #endif // REMOTESERVER_P_H �����������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/replaceoperation.cpp��������������������������������0100777�0000000�0000000�00000010002�13761647206�022646� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "replaceoperation.h" #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QTextStream> #include <QtCore/QRegularExpression> using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::ReplaceOperation \internal */ ReplaceOperation::ReplaceOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Replace")); } void ReplaceOperation::backup() { } bool ReplaceOperation::performOperation() { static const QLatin1String stringMode("string"); static const QLatin1String regexMode("regex"); // Arguments: // 1. filename // 2. Source-String // 3. Replace-String // 4. mode=string|regex // Calling with three arguments defaults to string search, // this provides backward compatibility with the old syntax. if (!checkArgumentCount(3, 4)) return false; const QStringList args = arguments(); const QString fileName = args.at(0); const QString before = args.at(1); const QString after = args.at(2); QString mode = args.value(3); if (mode.isEmpty()) mode = stringMode; if (before.isEmpty()) { setError(InvalidArguments); setErrorString(tr("Current search argument calling \"%1\" with " "empty search argument is not supported.").arg(name())); return false; } if (!(mode == stringMode || mode == regexMode)) { setError(InvalidArguments); setErrorString(tr("Current mode argument calling \"%1\" with " "arguments \"%2\" is not supported. Please use string or regex.") .arg(name(), arguments().join(QLatin1String("; ")))); return false; } QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for reading: %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); return false; } QTextStream stream(&file); QString replacedFileContent = stream.readAll(); file.close(); if (!file.open(QIODevice::WriteOnly)) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); return false; } stream.setDevice(&file); if (mode == regexMode) { QRegularExpression regex(before); stream << replacedFileContent.replace(regex, after); } else if (mode == stringMode) { stream << replacedFileContent.replace(before, after); } file.close(); return true; } bool ReplaceOperation::undoOperation() { // Need to remove settings again return true; } bool ReplaceOperation::testOperation() { return true; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/replaceoperation.h����������������������������������0100777�0000000�0000000�00000003264�13761647206�022327� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REPLACEOPERATION_H #define REPLACEOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT ReplaceOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::ReplaceOperation) public: explicit ReplaceOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } // namespace QInstaller #endif // REPLACEOPERATION_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/repository.cpp��������������������������������������0100777�0000000�0000000�00000020356�13761647206�021546� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "repository.h" #include "filedownloaderfactory.h" #include <QDataStream> #include <QFileInfo> #include <QStringList> namespace QInstaller { /* Constructs an invalid Repository object. */ Repository::Repository() : m_default(false) , m_enabled(false) , m_compressed(false) { registerMetaType(); } /*! Constructs a new repository by using all fields of the given repository \a other. */ Repository::Repository(const Repository &other) : m_url(other.m_url) , m_default(other.m_default) , m_enabled(other.m_enabled) , m_username(other.m_username) , m_password(other.m_password) , m_displayname(other.m_displayname) , m_compressed(other.m_compressed) , m_categoryname(other.m_categoryname) { registerMetaType(); } /*! Constructs a new repository by setting its address to \a url and \a isDefault and \a compressed states. */ Repository::Repository(const QUrl &url, bool isDefault, bool compressed) : m_url(url) , m_default(isDefault) , m_enabled(true) , m_compressed(compressed) { registerMetaType(); } /*! Constructs a new repository by setting its address to \a repositoryUrl as string and its \a compressed state. Note: user and password can be inside the \a repositoryUrl string: http://user:password@repository.url */ Repository Repository::fromUserInput(const QString &repositoryUrl, bool compressed) { QUrl url = QUrl::fromUserInput(repositoryUrl); const QStringList supportedSchemes = KDUpdater::FileDownloaderFactory::supportedSchemes(); if (!supportedSchemes.contains(url.scheme()) && QFileInfo(url.toString()).exists()) url = QLatin1String("file:///") + url.toString(); QString userName = url.userName(); QString password = url.password(); url.setUserName(QString()); url.setPassword(QString()); Repository repository(url, false, compressed); repository.setUsername(userName); repository.setPassword(password); return repository; } /*! Returns true if the repository URL is valid; otherwise returns false. Note: The URL is simply run through a conformance test. It is not checked that the repository actually exists. */ bool Repository::isValid() const { return m_url.isValid(); } /*! Returns true if the repository was set using the package manager configuration file; otherwise returns false. */ bool Repository::isDefault() const { return m_default; } /*! Returns the URL of the repository. By default an invalid QUrl is returned. */ QUrl Repository::url() const { return m_url; } /*! Sets the repository URL to the one specified at \a url. */ void Repository::setUrl(const QUrl &url) { m_url = url; } /*! Returns whether the repository is enabled and used during information retrieval. */ bool Repository::isEnabled() const { return m_enabled; } /*! Sets this repository to \a enabled state. If \a enabled is \c true, the repository is used for information retrieval. */ void Repository::setEnabled(bool enabled) { m_enabled = enabled; } /*! Returns the user name used for authentication. */ QString Repository::username() const { return m_username; } /*! Sets the user name for authentication to be \a username. */ void Repository::setUsername(const QString &username) { m_username = username; } /*! Returns the password used for authentication. */ QString Repository::password() const { return m_password; } /*! Sets the password for authentication to be \a password. */ void Repository::setPassword(const QString &password) { m_password = password; } /*! Returns the Name for the repository to be displayed instead of the URL. */ QString Repository::displayname() const { return m_displayname.isEmpty() ? m_url.toString() : m_displayname; } /*! Sets the DisplayName of the repository to \a displayname. */ void Repository::setDisplayName(const QString &displayname) { m_displayname = displayname; } /*! Returns the archive name if the repository belongs to an archive. */ QString Repository::categoryname() const { return m_categoryname; } /*! Sets the category name to \a categoryname if the repository belongs to a category. */ void Repository::setCategoryName(const QString &categoryname) { m_categoryname = categoryname; } /*! Returns true if repository is compressed */ bool Repository::isCompressed() const { return m_compressed; } /*! Sets this repository to \a compressed state to know weather the repository needs to be uncompressed before use. */ void Repository::setCompressed(bool compressed) { m_compressed = compressed; } /*! Compares the values of this repository to \a other and returns true if they are equal (same server, default state, enabled state as well as username and password). \sa operator!=() */ bool Repository::operator==(const Repository &other) const { return m_url == other.m_url && m_default == other.m_default && m_enabled == other.m_enabled && m_username == other.m_username && m_password == other.m_password && m_displayname == other.m_displayname; } /*! Returns true if the \a other repository is not equal to this repository; otherwise returns false. Two repositories are considered equal if they contain the same elements. \sa operator==() */ bool Repository::operator!=(const Repository &other) const { return !(*this == other); } /*! Assigns the values of repository \a other to this repository. */ const Repository &Repository::operator=(const Repository &other) { if (this == &other) return *this; m_url = other.m_url; m_default = other.m_default; m_enabled = other.m_enabled; m_username = other.m_username; m_password = other.m_password; m_displayname = other.m_displayname; m_compressed = other.m_compressed; m_categoryname = other.m_categoryname; return *this; } void Repository::registerMetaType() { qRegisterMetaType<Repository>("Repository"); qRegisterMetaTypeStreamOperators<Repository>("Repository"); } /*! \internal */ QDataStream &operator>>(QDataStream &istream, Repository &repository) { QByteArray url, username, password, displayname, compressed; istream >> url >> repository.m_default >> repository.m_enabled >> username >> password >> displayname >> repository.m_categoryname; repository.setUrl(QUrl::fromEncoded(QByteArray::fromBase64(url))); repository.setUsername(QString::fromUtf8(QByteArray::fromBase64(username))); repository.setPassword(QString::fromUtf8(QByteArray::fromBase64(password))); repository.setDisplayName(QString::fromUtf8(QByteArray::fromBase64(displayname))); return istream; } /*! \internal */ QDataStream &operator<<(QDataStream &ostream, const Repository &repository) { return ostream << repository.m_url.toEncoded().toBase64() << repository.m_default << repository.m_enabled << repository.m_username.toUtf8().toBase64() << repository.m_password.toUtf8().toBase64() << repository.m_displayname.toUtf8().toBase64() << repository.m_categoryname.toUtf8().toBase64(); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/repository.h����������������������������������������0100777�0000000�0000000�00000006336�13761647206�021215� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REPOSITORY_H #define REPOSITORY_H #include "installer_global.h" #include <QtCore/QMetaType> #include <QtCore/QUrl> namespace QInstaller { class INSTALLER_EXPORT Repository { public: explicit Repository(); Repository(const Repository &other); explicit Repository(const QUrl &url, bool isDefault, bool compressed = false); static void registerMetaType(); static Repository fromUserInput(const QString &repositoryUrl, bool compressed = false); bool isValid() const; bool isDefault() const; QUrl url() const; void setUrl(const QUrl &url); bool isEnabled() const; void setEnabled(bool enabled); QString username() const; void setUsername(const QString &username); QString password() const; void setPassword(const QString &password); QString displayname() const; void setDisplayName(const QString &displayname); QString categoryname() const; void setCategoryName(const QString &categoryname); bool isCompressed() const; void setCompressed(bool compressed); bool operator==(const Repository &other) const; bool operator!=(const Repository &other) const; uint qHash(const Repository &repository); const Repository &operator=(const Repository &other); friend INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, Repository &repository); friend INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const Repository &repository); private: QUrl m_url; bool m_default; bool m_enabled; QString m_username; QString m_password; QString m_displayname; QString m_categoryname; bool m_compressed; }; inline uint qHash(const Repository &repository) { return qHash(repository.url()); } INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, Repository &repository); INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const Repository &repository); } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::Repository) #endif // REPOSITORY_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/repositorycategory.cpp������������������������������0100777�0000000�0000000�00000011554�13761647206�023304� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "repositorycategory.h" #include "filedownloaderfactory.h" #include "constants.h" #include <QDataStream> #include <QFileInfo> #include <QStringList> namespace QInstaller { template <typename T> static QSet<T> variantListToSet(const QVariantList &list) { QSet<T> set; foreach (const QVariant &variant, list) set.insert(variant.value<T>()); return set; } /*! Constructs an uninitialized RepositoryCategory object. */ RepositoryCategory::RepositoryCategory() : m_enabled(false) { registerMetaType(); } /*! Constructs a new category by using all fields of the given category \a other. */ RepositoryCategory::RepositoryCategory(const RepositoryCategory &other) : m_displayname(other.m_displayname), m_data(other.m_data), m_enabled(other.m_enabled), m_tooltip(other.m_tooltip) { registerMetaType(); } void RepositoryCategory::registerMetaType() { qRegisterMetaType<RepositoryCategory>("RepositoryCategory"); qRegisterMetaTypeStreamOperators<RepositoryCategory>("RepositoryCategory"); } /*! Returns the Name for the category to be displayed. */ QString RepositoryCategory::displayname() const { return m_displayname; } /*! Sets the DisplayName of the category to \a displayname. */ void RepositoryCategory::setDisplayName(const QString &displayname) { m_displayname = displayname; } /*! Returns the Tooltip for the category to be displayed. */ QString RepositoryCategory::tooltip() const { return m_tooltip; } /*! Sets the Tooltip of the category to \a tooltip. */ void RepositoryCategory::setTooltip(const QString &tooltip) { m_tooltip = tooltip; } /*! Returns the list of repositories the category has. */ QSet<Repository> RepositoryCategory::repositories() const { return variantListToSet<Repository>(m_data.values(scRepositories)); } /*! Inserts a set of \a repositories to the category. Removes old \a repositories if \a replace is set to \c true. */ void RepositoryCategory::setRepositories(const QSet<Repository> repositories, const bool replace) { if (replace) m_data.remove(scRepositories); foreach (const Repository &repository, repositories) m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! Inserts \a repository to the category. */ void RepositoryCategory::addRepository(const Repository &repository) { m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! Returns whether this category is enabled and used during information retrieval. */ bool RepositoryCategory::isEnabled() const { return m_enabled; } /*! Sets this category to \a enabled state and and thus determines whether to use this repository for information retrieval. */ void RepositoryCategory::setEnabled(bool enabled) { m_enabled = enabled; } /*! Compares the values of this category to \a other and returns true if they are equal. */ bool RepositoryCategory::operator==(const RepositoryCategory &other) const { return m_displayname == other.m_displayname; } /*! Returns true if the \a other category is not equal to this repository; otherwise returns false. Two categories are considered equal if they contain the same displayname. \sa operator==() */ bool RepositoryCategory::operator!=(const RepositoryCategory &other) const { return !(*this == other); } /*! \internal */ QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository) { return istream; } /*! \internal */ QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository) { return ostream << repository.m_displayname.toUtf8().toBase64() << repository.m_data; } } ����������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/repositorycategory.h��������������������������������0100777�0000000�0000000�00000005651�13761647206�022752� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REPOSITORYCATEGORY_H #define REPOSITORYCATEGORY_H #include "installer_global.h" #include "repository.h" #include <QtCore/QMetaType> #include <QtCore/QUrl> #include <QSet> namespace QInstaller { class INSTALLER_EXPORT RepositoryCategory { public: explicit RepositoryCategory(); RepositoryCategory(const RepositoryCategory &other); static void registerMetaType(); QString displayname() const; void setDisplayName(const QString &displayname); QString tooltip() const; void setTooltip(const QString &tooltip); QSet<Repository> repositories() const; void setRepositories(const QSet<Repository> repositories, const bool replace = false); void addRepository(const Repository &repository); bool isEnabled() const; void setEnabled(bool enabled); bool operator==(const RepositoryCategory &other) const; bool operator!=(const RepositoryCategory &other) const; uint qHash(const RepositoryCategory &repository); friend INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository); friend INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository); private: QVariantHash m_data; QString m_displayname; QString m_tooltip; bool m_enabled; }; inline uint qHash(const RepositoryCategory &repository) { return qHash(repository.displayname()); } INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository); INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository); } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::RepositoryCategory) #endif // REPOSITORYCATEGORY_H ���������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/������������������������������������������0040777�0000000�0000000�00000000000�13761647206�020627� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/files-to-patch-macx-emb-arm-qt5�����������0100777�0000000�0000000�00000000101�13761647206�026334� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������bin/qmake bin/lrelease bin/qdoc %% *.la *.prl *.pc *.pri *.cmake ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/install.png�������������������������������0100777�0000000�0000000�00000000414�13761647206�023002� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������;֕J���bKGD�ĸ�ĸ�ĸ ―§“��� pHYs�� �� �šœ���tIMEÞ  "&Ģ(ãá���iTXtComment�����Created with GIMPd.e���pIDAT(Ïc` �0Béĸč%Yó\ē:ÝŠõ0ö•ŌۍØÔ0á3žĢā>y|6Ē‹Ąŧ€…0ö Œ mFVČQðŋ›&ŽĄ‡îT“ß*ĸąyĶo€c+Uâų?ĀbÅВķÉ�D:)uÉ=õõ����IENDŪB`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/installer.icns����������������������������0100777�0000000�0000000�00000350320�13761647206�023505� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������icns�ÐÐis32��·ƒ�1rlr1ˆ�8‘Ž‘8ˆ�@ĻĪĻ@…� FjrtĄĢĒl`V-� “ŅÜŠŽĨ’žŧŠ\� ĨŧŽz†‰f� #ąÉ\UpjoY`p €� 0ŊĘÆJ?Y?GŽo€� :Ŧšš™48Īs€� GŊđĀŧĨ^›ĨĶ”{€� SķģģēÎÚšœ™‚'€� `ÄĮĩĄ˜’•ž›Š-€� fĩķĖÆŧļļĐ Š5€� XœĄ›ĨŦ§ ‘Ž€3€� ,b;Wc]CBDitf€�!€ %#�ƒ�1rlr1ˆ�8‘Ž‘8ˆ�@ĻĪĻ@…� FjrtĄĢĒl`V-� “ŅÜŠŽĨ’žŧŠ\� ĨŧŽ‚z…‰f� #ąÉ\UpjoY_p €� 0ŊĘÆJ@X?GŽo€� :Ŧšš™58Īs€� GŊđĀŧĨ^›ĨĶ”{€� SķģģēÎÚšœ™‚'€� `ÄĮĩĄ˜’•ž›Š-€� fĩķĖÆŧļļĐ Š5€� XœĄ›ĨŦ§ €3€� ,b;Wc]CBDivf€�!€ %#�ƒ�1rlq1ˆ�8‘Ž‘8ˆ�@ĻĪĻ@…� IlttĄĢĒmbX-� —ÕÞŠŽĨ’ĄÁŪ_� Đŋ‘€Ž}‡k� )·Î^TpkpX`–s €� 0īÏĖL>Z?Gģ•s€� =ēŋŋž68•Ļ”x€� GĩŋÅĀŦa Ŧޚ€ €� V―đđļŅßĀĄŸ•†'€� dĘĖŧĐ ˜–šĪĄ‘0€� iŧŧÐËĀ――ŊĶŽ‡8€� ]Ē§ĒŠŊŠĨ•”˜‡5€� 2kCbogKJOokr!€� %"" ' �s8mk�������]·ŧ·]���������væëæv������� |ðõð| ����T‚ŧũúũŧ‚}?���ģųúüĸĸĸüúö‹��� Æĸĸĸĸĸĸĸĸý ���,Ôĸĸĸĸĸĸĸĸþē���;āĸĸĸĸĸĸĸĸĸÃ��KęĸĸĸĸĸĸĸĸĸŌ)��]ņĸĸĸĸĸĸĸĸĸÞ7��qöĸĸĸĸĸĸĸĸĸčH��…úĸĸĸĸĸĸĸĸĸðZ� ™ýĸĸĸĸĸĸĸĸĸõn�ýĸĸĸĸĸĸĸĸĸös� …õúúúúúúúúúë]�G’˜˜˜˜˜˜˜˜˜Š0il32��ω�)bf€hfb%”�0{}€}{0”�+ˆ†‰Š‰†ˆ+”�0ĨŽēēģŽĨ.”�-žĒĢĒž+”�-™ŸĢĨ̟š-�Z^y{{wešĢĪĶĢ̚_iki[M4‡�*ŪĩØßÞᝋĶĒĢĒĨŽŒÁđšĻža‡�8ÆČŽŌÃՉˆŸž Œ|š­Ļwķk‡�GÎąĻäČ݈}–””’–}…ÎđÁgŪv †�VŌÃÞĒ™Šmv‹‡‰ˆ‰z`•ƒmŠ~†�cÓÏÛ:_|Xqzy{y{q^€dOk̇†�tÖĮÕš>aud€k lietc<Đxš"†�ÖĮČÜĀ6LaZ^]^Z_M8œĮp“—.…�‰ÖČĮŧÍē5BUMPMSC4ŠĐuŒ™4…�Ž…ŋĀšžŸ.5I?I5-ŽˆŦ„O€@…� ĀĪÆÁķžŽ‚-%B$.y„‘ž§Ž›I…�%ŽķĨÍ―ŋŧŦ‡,2ƒŽĄĪĄĢ}œU…�1ī•đÄŧššđ‘‰O”†xģ  ›Ļh\…�=ž‹ĩÁļđ·ĐâÞĐŊđÖĪ ž—Ķk‰f „�KÂĶĒÂļīģēĶĖäÞÕŦœ žš™˜u’l„�VÂļÎąģķŊąŪž››•š ›ššŽ—”’t„�dÃŊČðĻĨąŪŽŽĐĨ̟ž–ƒĢŊ‰Žy„�oÁīĐŋņÄ ™žĄžž›“Ž“ŧŧ„‹‰}%ƒ� zÄĩīĻĐŲįÕŧĐĄœžĻļģŧĨ…Š‹+ƒ�}n‘ĩ§Ī”žđÏÖÛÚÕŌī}|„†Jj4ƒ�€ŠŋËÃÃÄ―°ŦĻŽŠĐĒĪŽŪĻĨĢĒ‘ˆ3„�;vyCSZ_emxvS[W[YW]€yxw~h„�#Yf(6KPSW[\8A6886>\qySfN „� Yf?4?KUZ^^GI€EDK_jl\mC„�€�‚€ Ą�‰�)bffhhfb%”�0{}€}{0”�+ˆ†‰Š‰†ˆ+”�.ĨŽēģģŽĨ.”�+žĒĢĒž+”�-™ŸĢĨ̟›-�Z^y{{we™ĢĢĶĢĄš_iki[M4‡�*ŪĩØßÞᝌĶĒĢĒĨŽÁđšĻža‡�8ÆČŽŌÃՉˆ žŸ‹|š­Ļwķk‡�GÎąĻäČ݈}–’”’–~…ÎđÂgŪv †�VŌÃÞ̚Šmv‹‡‰‡‰z`•ƒmŠ~†�cÓÏÛ:`|Xqz{z{{q^dOk̇†�tÖĮÕš>cudikmiidtd<Đxš"†�ÖĮČÜĀ6LaZ^]\ZaL7œĮp“—.…�‰ÖČĮŧÍē5BUMPMSC4ŠĐuŒ™4…�Ž…ŋĀšžŸ/5I?I5-ŽˆŦ„O€@…� ĀĪÆÁķžŽ‚-%B$.y„‘ž§Ž›I…�%ŽķĨÍ―ŋŧŦ‡,0„ŽĄĪĄĢ}œU…�1ī•đÄŧššđ‘‰O“†xģ  ›Ļh\…�=ž‹ĩÁļđ·ĐâÞĐŊđÖĪ ž—Ķk‰f „�KÂĶĒÂļīģēĶĖäÞÕŦœ žš™˜u’l„�VÂļÎąģķŊąŪž››•š ›ššŽ—”’t„�dÃŊČðĻĨąŪŽŽĐĨ̟ž–ƒĢŊ‰Žy„�oÁīĐŋņÄ ™žĄžž›“Ž“ŧŧ„‹‰}%ƒ� zÄĩīĻĐŲįÕŧĐĄœžĻļģŧĨ…Š‹+ƒ�}n‘ĩ§Ī”žđÏÖÛÚÕŌī}|„†Jj4ƒ�€ŠŋËÃÃÄ―°ŦĻŽŠĐĒĪŽŽĻĨĢĒ‘ˆ3„�;vyCSZ_emxvS[W[ZW]€yxw~h„�#Yf(6KPSW[\8A6866>\rzSfN „�Yf?4?KUZ^^GIEFEEK_ln\mC„�€�‚€ Ą�‰�)bf€hfb%”�0{}€}{0”�+ˆ†‰Š‰†ˆ+”�.ĨŽēģģŽĨ.”�-žĒĢĒž+”�-™ŸĢĨ̟š-�Z`}{g™ĢĪĨĪ̚`€m]O9‡�*ģžÞåãæ ‹ĶĒĢĒĨސĮĀĀŽĨe‡�=ĘϰŅÁՈ‰ ž ŠĀą­|žn‡�GÓķŪåČ߈}–’”’–}ˆÔūĮlģy †�YŲĮā͜Žnv‰‰Š‡‹wc˜‡’pŊ„†�eÚÕā8^~Xq|xz{zq\dNqό†�xÜÍÚŋ>bvdkkmkietc;Ŋ}Ÿ”"†�„ÜÍÍäÆ6JaZ_]^Z_L8ĒÎs™.…�ÛÍÍŋŌđ5AUNONUC6ĢąŊ{‘ 7…�’‰ÃÅĀĢĒ’.5I?I5-…“°ŠT†C…�ĨÆĐËĮžĢ’†.%B$/~ˆ–ĪŪ“‡ĄK…�+ēŧŠÓÃÄÁąŠ-2‡’ĶЧĒЂĢW…�5š›ŋĘÁĀŋū˜ĒRšŒ}đĨ§ Ūm“`…�@ÁŧÉŋū―ŊæáŪķūÚŠĶĶΜŽpi „�MČŽĻĮūš·ļŦÏįāÜēĒĶĒ Ÿžz˜q„�YČ―Ó·đ―īĩķĶĄĄ› ĶĪ Ą”š˜y„�gÉĩÎņŊŦ·īēą­ŦĐĨĢĄœ‹Đģ”„�sĮšŊÃņČĶĄĪ§ĨĨĄš•”™ÁÁŒ‘ƒ%ƒ� ~ÉŧšŪŊÞëŨŋ°§ĒĢŽ―šĀŦ‹•ˆ.ƒ�t—ŧ­ŽœĢūŌŨÜÝØÔš“ƒ‚ІŒQp7ƒ�†ŊÄÏÉĮČÁķą­ąąŪĐϰēŪĻǧ–8„�@ƒH\cjpw‚Zc^aa^f‡‘”~ˆo„�&es->UZ_bhg?J=??=DtURmpW „�drE:EV_fjhNRKLLKRqMHnxI„�€‚€ $Ą�l8mk�������������>‚……………‚>���������������������pÚßßßßßÚp���������������������~ðõõõõõð~���������������������{ðõõõôõð{���������������������wïõõõõõïw���������������� xðõõõõõïw ����������^€ƒšũúúúúúũđƒz6���������+Ėųųųųųüĸĸĸĸĸĸĸüųųųųóƒ���������;Þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü› ��������Kčĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸþ­��������\ïĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸū��������oõĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖ'��������‚ųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŲ4�������� •üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸäC�������ĻýĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸėT�������đþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸóg�������$Éĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũz�������0Öĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸû �������?áĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸý ������Pëĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸþē������cņĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ ������vöĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŅ,������ ŠúĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÝ;������žüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸčK�����°þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸï^����� Āĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõp�����#ŋþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸôr����� üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸįT�����ŒųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÜA����� wíũũũũũũøøøøøøøøøøøøøøũĘ4�����@ŸŸŸŸŸŸ              r�����*222222222222222222220! ���it32��gh����Ž�€<˜;<Û�Kc™|bKÛ�hž™™žhÛ�“Īŧķ‘ĩķŧĢ“Û�:>€G„F€EDEƒFGGF>:Û�!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ�!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û�}―œ€ž€žœūzÛ�|ŋĄƒĢ‹ĪƒĢĄŋyÛ�|ūĄ†Ģ…ΆĢĄūyÛ�{― €Ē‘̀Ǡ―xÛ�zŧ ‚ĒĢ‚Ē ―xÛ�zšŸĄ…Ē…Ģ†ĒŸžvÛ�x🡕ĒĄŸđuÛ�x·ž‚ĄĒ‚ĄžđtÛ�wĩ€ ƒĄ…ĒƒĄ€ ķsÛ�vĩ€Ÿ  Ą  €ŸĩrÛ�uģ›žƒŸ‰ ƒŸž›ģqÛ�t皜žŸžœšēpÛ�q°™›€œ�ž…Ÿ�ž€œ›™°oÛ�rۘ›œˆ€œ›˜ŪnÛ�qŽ—š‚›�œƒ›�œƒ›€š™ŽmÃ�ŌÎÍŨÔŨÐÏŌŌŅŅÐÐÏπÎ�̀ĖË^nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl[šđļļ·ķĩĩīģ ēąŪŠĐŪŠ°ŽĐÆŠ� ‘ÖŌ҇O|ÏŅÓӁŅÐÎÐρÎÍËumĻ•——˜‚™šƒ™€˜ ——–Đjpžŧšđļļ··€ķ ĩĩīģŊŦĻj8]Ķ­ĩšĐ�~ÛŲ–!‹ÝÔÕÔÓŌŌ€Ņ ÐÎÎÏÎÎÍukĶ“––‚—‰˜‚— ––“§ip―ŧšđđļ··€ķ ĩĩīēŊ°€(hīģ_Ļ� X‹ß۝3ƒIœÝ€ÖÔӀŌŅЀπÎujĢ“”€•–‡—–€• ”“Ģhpžŧšđđļ··€ķĩīģģ°ą>…Huģķj5§�WšâÖÜžÎÛÕÕÔÔÓÓŌŌŅ€Ð�ρÎuiĒ‘’’“€”‰•€”“’’‘Ēgoŧ€š��ķ€ĩ īīēą°īŠĪ§°­ķv7§� VĒáŨŨÝÜŲÕØŲÕԀÓŌŌŅŅЁÏÎth ‘‚’“‚’‘  eožŧššđđļ ķķ――ģąģąąŪ­ķ6§�V­āŨŨÖÕÔŨĘĐŅÓŌÓŌÔŌÓŌŅÐÏŌÐÐufž€Ž€€‡‘€€€Ž ždnšđļļ·ķķĩīģąĩĶ·ēŊŪŪ­Ŧē‹7§�XžÞÖցÕ}yŨŌÔÄÁŊšīķšļžąķēgeœŒŒ‚އ‚Ž€Œœbnđ€ļ·ķĩīģēģļJOŊ°ŪŪŽŠ°–:§�[ĮÚրÕØÏh‡ØŅÔÄšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbnđļļ·ķĩīģēēąŧ[&Ģē­ŽŽŦŪĄ@§�aŅŲրÕØÉd’ÚŅÔÂĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜anđļļ·ķ€ĩīģ€ēąŧf%›ī­€ŦŽĶC§�eÔŨÕŲĀ_˜ÚÐŌĀīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_mđļ·ķķĩĩī€ģēą°ŧm"īŽŽŦĐŦĐH§�nŲÖÕÕÔÔŲ·[žÚÐÐūģąđļšđīŧ·ķši`”‚„„€…†€…„„‚”^mļ·ķķĩĩīīģģēēą°šx„ĩŽŦŠĐŠŊQ§�{݀ÔÓÓÚ­X§ŲÐÐÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]mļ·ķķĩĩī€ģēēą°ļƒ yģŠŦŠĐĐē\Ķ�U‰ß€ÓŌŌÛĶY°ŨÐŌÃķŊĩķĩą°īīēŊf]Ž}€€‚‰‚‚€}[l··ķ€ĩīģēē€ą°ķ"sī‚Đąi6Ĩ�T—ß€Ó ŌŌڟZļÖÏŌŋŋ€―žū‚―j\Ž{}€~‡€€~}{ŽZk·ķĩīģē€ą°Ŋī—&hīĐϰt5Ĩ�R Þ€Ó ŌŅŲ‘WšÓÎÍπÎ�Í€Ë ĘÉÉČp[Œy{{|}ƒ~}|{{yŒYkĩķ€ĩīģģē€ą°ŊēŸ*\īŠĐ€ĻŊ|4Ĩ�TŦÜÓŌŌŅÐ֋ŠÞÕĖĖ€Í�Ė€ĘÉȀĮnZŠwyyzŒ{€z yyw‹Xiģ°ēĩĩģ€ēąą°ŊŊēĒ.QēŦĐϧ§Ūˆ5Ĩ�Vđ؃ŅÃëþũúų†ø‹Y‡uwxyx wu‰WŒóōÅąī€ē ą°°ŊŊŪŊĶ6FŪŠ€Ļ§Š’8Ĩ�YÃւŅÐÐâūŸĶœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’emprsvwxyz{„ƒ“?=ĻЧĶĨĨĻ›=Ĩ�_ËÕŅŅ€ÐÏÏːixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj„H8ĨЧĶĨĨ§ AĨ�dŅÔŅŅЁÏΜtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s‘S2ŸŠ€ĶĨĨĢFĨ�lŨÓŅÐЁÏÎΈ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆš]+—Ŧ€ĶĨĪĻPĨ�yÚŅЁπПZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\YŽe&­€ĶĨĪŠ]Ī�O†ÜŅ€Ð�ρÎÍp�JCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:<?BDFGIQPDI!�a°l#„Ŋ§ĶĶĨĪŽh7Ģ�O“ÛŅ€Ð�σ΍ĨŌūž―·°ŦĄ—‡‚|pc€e‘f€ecq|‚‡—ĄŦą·――ūŌŽsŠģv"z°§ĶĶĨĪŽr5Ģ�MÚÐÐυÎ͉zzy{srpmkjea‚bc‚baejkmprszyyœ€lŦĐą"t°€ĶĨĪŽz6Ģ�NŠŲÐσÎÍÍĖĖˌeWmzf[]^›_^][eynWisŦŦĐŊ‹$jŊĶ€ĨĪŠ†5Ģ�P·ÖτÎĖĖ€Ë Ę“aƒVjyfYĢ]YdykV‚fvŽŦŦĐŪ”'^°Ķ€ĨĢĻ‘8Ģ�UÁӃÎÍÍË€Ę ÉČȕ\„VdvdWĄZXcvgVƒ`ŦŦĐĻĻŽš-S­€ĨĢĒ͚=Ģ�ZĘŌπÎÍÍËËĘ€É ČĮĮƘU„V`sbSŸWSaraU„[~ŠĐĐĻĻ§Đ›1IŠĨĪĢĒĒΟAĢ� `ÎŅÏÎÎÍĖËĘÉÉȀĮ ÆÅÄšO„VZo_PS P^m\TƒUƒ§§Ķ€§ ͧ 8@ĨĨĢĢĒĒĪĒHĢ�iÓÏÎÎÍÍËʀČĮĮÆÅÃÂĀÃĘĻH„VUk]N›PN[kVTƒN„ĨĨĶĨĶĨĪĪĶĨ@8ŸĨĒĄĨQĢ�uÖÎÎÍÍĖĘÉÉČĮĮÅÄÂÁĀĮČŋđŸ BƒWQdZKK—L KKXeRTƒGŠĒƒĢĪĢĪĻH4šĶĒĒĄĄ §[9Ą�!Q…ØÎÎÍĖËĘÉÉČĮÆÄÂÁÁÆĀļ·ķĩĄ=WKaWFF•HGFVaMTBˆžŸ  Ÿ  ĒĄĒĄĻQ-”Ķ€Ą Ÿ§g8Ą�M”ŨËÉɂČĮÅÄÂĀÁšķķīąą°œ$5XG]TDC“ECBS]HV;Š››šœ›žž€Ÿ ĄĻ['ŠĨžžžĶs9Ą�#MœÔÆÅÍÏĖÄÆĮĮÅÄÂū―ļ·ĩģŊ­ŽŠĐ›(/}YCVP@?‘A ?@PXDV}4…€•–—™™›žŸ  Đa"}žœŸŸ››Ĩy6Ą�$NĨÏÃĀyMÆÄÆĮĮ·ššļķē°ŽĐ§ĨĢĄ–+)z[>RN=;=$<=MR@W{.$ƒ‘“•—™›žŸŸĐimœj<S›Ģ‚7Ą�%NēĖÉu †ÍÅɰš―đ·ī°ŽĻĨĢ ›š“1"w\;MI:8:%8:IM=Yy'"‚‰‰‹ŒŽ‘’•˜š›žĻsh{L Œ:Ą�&R―ĘÍS.v)qÏČÃĨđÁ―š·ē­Š§ĪŸœ™—•’Œ-t]8GF74‹6&46FI8Zv"+}ƒƒ…‡‰ŠŒ‘”—š›œœŸ§}$hp$qA8›Ÿ•<Ą�'YČĖËģmŽ•ĀÉĮž°ÅĀ―ŧ·ēŪŠ§Ģžš—”‘Ž‹†3p_5CD41‰3'14CD5[r%y}~€‚…‡ŠŒ’”˜™š›žĶ…(^Ģqy…žšDĄ�(_ĖĖĘÏÕÎŅÉʝžĮÃÁŋžļīąŽ§Ģžš–’ŽŠˆ…‚3k`3?@1.‡0$.1??2]n,txy{~ƒ†Š“•™™šžŸĪ%QĶĨĒĒĄ€œ�HĄ�)fÏËÉÉČČĮĖŠ…ÃÅÂÁŋžš·īŊŦ§Ē—“Ž‹…ƒ}<ga0;=.*…,)*.<;0_i/rtvx{}€„ˆŒ“•—š›œžŸŸĒĄq]Ąžœ›šŸPĄ�*sŌÉÉČĮĮĘĀzĐÉÂÁÁŋūžšķģŊŦ͟›–‹…}{x: ac/7:,(ƒ*(+:7.`e3pqsux{„ˆ‹’•˜™œžŸ€  ĒĄ’žž›ššĄ[:Ÿ�MÓȁĮĖ‘}ĮÄ€ÁŋūžđķēŊŦĨĄ›”ˆƒ~zwt>\e-27*%'%)73,a` 6loqsvy~ƒ‡Œ”–™›œ€ž ž €‰Ąžœ€šĄf6Ÿ�IÓ€Į ÆĘđgĪËÃÃÂÁ€Ā7ūŧš·ĩąŦĶĄš”Ž†{xtsCWf,.5(#%%#(40+c[Clkoquz…ŠŽ‘•™›œžŸ€ Ÿ NJf– œšš˜Ÿo7Ÿ�I™Ō€ĮÆÎfÁČÄÀÂ7Áŋŋū―ŧļķēŽ§Ģœ•†€{vpoCQh,,3( &3-*dV8s{ppuz€†Œ‘”—›œœžŸ€ ‚Ÿ žŸœWq̜šš˜žv7Ÿ� IĢŅĮĮÆĮÂeƒÍĂÂ6ÁĀŋūū―ŧđīēŪŠĪž–ŽˆlbnkE�Lh,)2$$1**fP�<eg]iw{‚‰”˜šŸ ŸŸĄ� €Ÿ žĪfG—Ÿš˜˜œ~7Ÿ� J°ÍÆÅÅËĻRœËÂ�Á€Ā/ŋŋū―žŧ·ķģ°­ĻĒ›”~YiumhGFh,(11(*fK�BcgnW6lŠŒ’—œž €Ē€ĄĒĒĄ  ŸŸžĢz0{Ą™˜˜›‡:Ÿ� OšĘÆÅÅ΋RŊĮÂ�Á€Ā3ŋūū―žŧšļķĩģ°Ž§ĄpUwzpkfH?i,'()gEAaejtk!B•˜›ŸĒĒĢĪĪĒĄĒ�Ą€ ŸžĄŽ/^Ą™˜˜™=Ÿ�WÂȀÅČrXŧÆÂÂÁÁ€Āūū€―žŧš€ļ'ķīē°Ļja„…wphdF9i+'h?D`ciq}z76”ĒĄĒĢĪĪĢĢ‚ĒĄĄ  Ÿž€ ž–5Cœš˜——”CŸ� \ĮĮÄÃÄÁa[ūÅÁ€Āŋūū―�ŧ€š)đļ··ķĩģŪ~„—”‡yogbJ3hg8C_cis†aUœĶĪĨĪĢĪ́Ē�Ą€ ŸŸž‚ ˜=8”š—–——GŸ� cĘÅÂÂÅžY\―ĀĀ�ŋ€ū―žŧŧšđļ ķĩĨŊŧĪ—Œ}pf`K05H\ckw„š™Œ‡§ĶĶĨ΀̀ǀĄŸŸ€žžœ™B7š––•™PŸ� oÍÃÂÂÅđZ]žÄĀĀŋ€ū―žŧšđđ!ķķīđÐáŌ̜’‚uh_NI^eo}‹–œŽŪĨĪĻĨĨĪ΂ǀĄ� ‚ž›šœ˜C;™–•”™Y;� F}ÎÃÂÂÅŧ][ķÄŋŋū―ŧ€šđđķķ€ĩēØũüßŦž—‰ylbGF`iv…‘™ĒđÂŧŊĶĨĪĪĢ̀ǀĄ  €žœ›€š œ“E@™•””™d8� F‹ÎÃÂÂÄÁhZĻÆŋŋ€ū―žŧ€š�đ€ļ·ķķĩīąķïĸĸîĀĪ—Š~rkiq|ˆ”ŸąĖŌĘ―§ĢĨĪ̃ĒĄ  Ÿ€žœ›šš™™‰FK“—”“’˜l9�E•Ė€Â ÁĮ}]—Æŋŋū―ž€ŧššđ€ļ·ķƒĩģēŪĩčĸųðåŅĩŒ‚‚‰™ŪđÆŅØŨħĢĨ΃ĒĄĄ €Ÿžœœ›š™˜˜{J]™•”’‘–q7�DžË€Â ÁȔf‡Ãŋūžž€ŧšđđļļ··ķĩīīģ€ēŪŽĖëóúýúōæÝÜåōöÝŌŅÏđĢĢĨĢ́ĒĄĄ Ÿž€œšš™€˜ ›pTqš•”’‘—{8�IŦȀÂÁÄŽt€·ŋžŧšđđ€ļ·ķĩĩ€ī€ģ€ēąŊŠŊÆčþþýûúúûýýāĮķ§ĒĪĨĪ‚Ē�Ą€ €Ÿžžœ››š™™˜˜—˜’l`…˜•“’‘•ƒ<�LķĮÂÁÁĀĀū‰‡ĶÁžŧŧšđļļ·ķķĩīƒģēą€°Ŋ­ĻĻĩÅÖáääáÕ­ĢĒĪĨĪ́Ē�Ą‚ ŸŸž€›š€™˜—–˜†pp“•’’‘‘’Š?�SŋÅÁ€ĀŋÄĨ’ ŧūžŧ€đļļ··ķķĩĩ„ģ ēą°°ŊŪ­­ŽĻĨĒŸž ĢĨĨĪĪ́ĒĄĄ€ �Ÿ€žœ›š€™˜——–•€v‚–“’‘‘ŽD�XÃÁĀŋĀŧ Ķĩ―žŧ€đļļ··ķķĩī„ģ ēą°°ŊŪ­ŽŦŦ€Đϧ§€ĶĨĪ̃ĒĄĄ€ Ÿžž€›š™�˜€— Ž‚€”’’‘H�bÆÁĀĀŋŋ€ūģ°đžššđđķķĩĩīē‚ą°ŊŪŪ­Ž€ŠĐĻ€§ĶĨ€Ī�̂ǀĄ  €žœ›š€™˜——––•Œ‡‹•“’’‘ŽŽ“Oœ�GnÉĀŋŋūū€―ŧšÃĘšļđ·ķķ€ĩ�ģ„ą°°Ŋ€Ū­Ž€ŠĐĻ€§ĶĨĪĪ̀ǁĄ Ÿžœ›€š™˜˜€—––”Œ””“’’‘ŽŽ”X<›�E{ËĀŋū€―žŧšūÍŲÔķķļ··ķķĩĩīģēą€°€Ŋ€Ū­Ŧ€ŠĐĻ€§ĶĨĪ̀ǁĄ Ÿ€žœ›š™˜—–”™˜”“•””“’Ž”a8›�CŠĘŋ€ūžŧ€šļĘãėŲēĩ·ķĩģēąą€°€Ŋ‚ŪŽŦ€ŠĻĻ€§ĶĨĪĢĒǁĄ  Ÿ€žœ›€š™™˜€—–•“œ ›–”’‘ŽŒ“j8›�B’Éūū―žŧšļķÚõøÜąģĩ�ī€ēą°°ŊŪŪŽŦŠĐ€Ļ§Ķ€Ĩ�Ģ€ĒĄĄ  €Ÿžœ›š™€˜ —––•“ĨĒ›“’ŽŒŒ’n9›�BœČūū―ŧ€š đđļķļįûýáąą€ĩ�ģ€ēą°°ŊŊۭށŦŠŠĐ€Ļ§Ķ€Ĩ�Ģ€Ē�Ą€ Ÿžœœ›š™™€˜ —–•““ Ļ§Ą’‘ ŒŒ‹Žv9›�FĻÅū―ŧŧšđļ ·ģ·ëĸĸėđŪģē°°€ŊŪ­Ž€ŦŠŠĐ€Ļ§ĶĶ€Ĩ�Ģ€ĒĄ ƒŸž€œš™€˜ ——–•“•ĨŽŠĒ’€‘€Œ‹Š~:›�IģÂ―€ŧšđ€ļ·ķķēĩæĸĸũĮŦŊąą°°€Ŋ­­ŽŦ€ŠĐϧ€ĶĨĪĪ̀Ǡ €Ÿ€žœ››™™˜˜—––”’›ŦŊ­Ģ’€�€ŽŒ‹ŠŠ‹„?›�QŧĀž€ŧšđļļ·ķ€ĩēąÜĸĸýÜģŠŊ°°ŊŪ­­ŽŦЃĐϧ€ĶĨĨĪĢ̀Ǡ €Ÿ€žœ›š™™˜—––”•Ĩą°ŊĄ€€ŽŒ‹ŠˆB›� Vŋ―ŧŧšđđļļ·ķķĩģ­ĘøýûïČ­Š­Ū­­ŽŠŠƒĐ�ρĶĪĢ̂Ǡ Ÿ€ž›š€™˜—–”•ŸŽēē­›‘‘€Ž€Œ‹€Š€‰�F›�_Â―ŧšđđļ·€ķ€ĩīīģģŽ·âøöōÜūŦĻŦŽŦŠ€Đ€Ļ�§€ĶĨĪ̃ĒĄ  ž€›š™™˜—–”•œ§Ŋ°Ŋ§–’’‘ŽŽ€Œ‹‹Š‰‰ˆˆŒNš�DkÆžšđđﷁķĩīīģē­ŦÅæîčäÕŋ­ĶĶĐŠŠĐĻ€§ĶĶĨĪĪĢ‚ĒĄĄ Ÿžœšš™˜•”–ĨŦޭМ‚’‘ŽŽŒŒ‹‹Š‰ˆˆ‡‡V;™� CxÆŧđđļ··ķķ€ĩīīģģēēąą°ŠŪÅÜâßßÛÍšŠĒĒĨĶ€§ĶĶĨĪĪĢĒǁĄ Ÿžž€œ›š˜—•–› ĨĻĐŠ§ž”’””“’‘ŽŽŒ€‹ Љˆˆ‡††‹_9™�A…Åđđļ�ķ€ĩīīēēą°Ŋ­ĐŪÁÔÞäęņíÜÃŪǟ ĄĢĪĢĒĒ€Ą Ÿžžœ›™–““–ĢŠŽŦЧĶΜ”‘“’Œ ‹‹‰‰ˆˆ†……Še:™� ?ŽÄļ·ķķĩĩķķ€ĩīģēēą°ŊŊŪŽĻŠļÏåõûĸĸýîÜĮļ­Ģž›š™™—–••–šĢ­―ÍÏËÚģ­Ķ ™’ƒ‘Œ ‹‹Š‡†……„„…‹k9™�B—ŋģąķđļīģīĩīģēą°Ŋ‚ŪŽŦЧĨŊÅãüƒĸýôéáÚŌĖÉÄÃĮĘÐÖÞæōýĸĸųįÕÅķŠž–’‘‘…�Ž€Œ€‹ Šˆ…€ƒ„ƒ€ƒˆr<™� =ĢđŪŊƒESœēąģģē€ą�°ŊŪ­­€Ŧ ŠĐĻĶĒĒ­ÂÚîü“ĸņÔđĪ—“€’‘‘ŽŒŒ‹€Š ‰†€|sE3U~…{0™� $°ĩ°‡ ;Ŧēą°°€ŊŪŪ­Ž€ŦŠŠĐ€Ļ §Ī  ŠđÆŨįïõüþƒĸþüõîåÔÂēž”‘‘““’€‘€ŽŒ‹‹Šˆ„~z? V€ƒ�#™�9·ģĩ[_D!īēēą°€ŊۭށŦŠŠĐĻ§Ķ€ĨĢ ššœĄĨŠŪąēēŊŽĶ š–‘‘”€•”’’€‘ŽƒŒ‹€Š€‰ ‡ƒv#C^+;‚‚†.™�D―īķ”6`si€ēą°€ŊŪ­Ž€ŦŠŠĐ€Ļ�§ĶĨĨ΁ĒĄĄŸžœš˜„— ˜˜™˜——––•””€’‘‘ŽŒŒ‹Šˆ †ƒ†Y@€C_ƒ‚‡9™� Gŧķīš°œ°đģ€ą�°€Ŋ�ہŦ�Š€ĐĻϧ€ĶĨĨĪĢ‚ĒĄ  Ÿžœ‚œ›š€™˜—€–•””€’‘€ŽŒŒ‹€Š�‰‚ˆ ††‰}‚…‚‡D™� lŅąŊŪ°ą­ŽŠĐ�Ļ€ĶĪĢ€Ē ĄĄ ŸŸžžœœ‚š�™€˜–•”“’’‘€ŒŠŠ‰‡‡€…„„‚ƒ€€„~ {{|zzxw~‹W™�9āÖę€åää€âäį€äââáāāß߀ÞÝ݁܀ہÚŲÚßßÛÝÞÜŲÜÝÚÛÜÛŨÛÛÖØŲØÕŲŲÔŨØÕԀҀÐÏÏÍĖ„ËÍʁÉʗsš�"v°đļđđŧ―ŋĀģĄąŽŪąēģīĩķ·ļļđšŧŧž―ūŋĀÁ€ÂÃÆŋĶĶđąĶŪŋϧŧ°§ąŋĻĻŋąĐĩÁŠŦÂąŦīĖ€ĘËËÍÏŅŌŌÓÓÔÔÕÖÐĘÏŲØØÚÐ{œ�"$BRUUSW]ce@ 8(.37;>@BCFGHILMOPRSVXZ€[€\aH��4�B��9�>��>�?��>�\WX\`defhijjln[LZsrqqR: ›�$,N]aa_cioqSA:=BEILMOPRTUVXZ\]^_adeg€fhglV D)P G#$L L )M M#icdhlnopqsttuweYh}{{y[>œ�#(L]`a`cioqV><<BEILMPQRTUWYZ\]_`bdeeghlX F+!R J%&N N",O O&icdiknpqrsstuvcYj|zzwY:œ�$J\€`bhmrY:?;BEIKMOQRTUWYZ[]^`bc€e�f€gkY H.#T K((P P$.P Q!)icdiknpqqrsstuaZk{yytW5œ�!H[a``bhmr[ 1?;BDIKMOQRSTWYZ[\^`ace fggkY K2&V N*+S S'1S T$-icdhknoqqrrsts`ZmzxyrT1�EY€`bgms](-9CEHKMOPRSTWYZ[\^`acd‚egjZ L4(X P-.T T)3T U&/icdfi[bXhpqrsr_[nywynR,�CX€`bglr`-((5BIMMOPRSUVYZ[\^`acdd‚ej\ M5)X P..T T*3U U'/i‚cfE€â―bdprsp][pxuxlQ&�@W€`bflsb1+*(-9FMQQRSTVXZ[\^_ac€deiZ M5)X P..T T*3U U'/icfX(ßĸĸ|Kqqrn\]pwtwiO!�<U€`aflrd6%0//-,.6BKRVWWXZ[\]`ab‚deeiZ L4(X P-.T T*3U U&/icf]“ĸŨ0Wpprm\^qutvfL� 9S_``afkrg>.ƒ20029CNUZ]^__`acd‚efjZ L4 )WP. /TT* 3UU& /jfgkR,O:Lmnqrl[^qusucJ� 9Ubcbchnvh>2†4 2137=FKQVZ]_aab7afW'%I:%3R&%L6&7O&&O4%:P%&P2&5bZTRQRUZYP[ddilnh[buwvwdHž� DTUUWZZXLA…B‚CBA@@ABDEF€G‚HGEEFHEFH€F HGGHGGHIFFH€GHDBBCB€A CCDFIKLLQ[€fgO(ž�$€%€&�(€*ƒ+‚,†-„.//1202€3€4 55657769889::9€;:<==>?@@€A@@??A?ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ���Ž�€<˜;<Û�Kc™|bKÛ�hž™™žhÛ�“Īŧķ‘ĩķŧĢ“Û�:>€G„F€EDEƒFGGF>:Û�!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ�!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û�}―œ€ž€žœūzÛ�|ŋĄƒĢ‹ĪƒĢĄŋyÛ�|ūĄ†Ģ…ΆĢĄūyÛ�{― €Ē‘̀Ǡ―xÛ�zŧ ‚ĒĢ‚Ē ―xÛ�zšŸĄ…Ē…Ģ†ĒŸžvÛ�x🡕ĒĄŸđuÛ�x·ž‚ĄĒ‚ĄžđtÛ�wĩ€ ƒĄ…ĒƒĄ€ ķsÛ�vĩ€Ÿ  Ą  €ŸĩrÛ�uģ›žƒŸ‰ ƒŸž›ģqÛ�t皜žŸžœšēpÛ�q°™›€œ�ž…Ÿ�ž€œ›™°oÛ�rۘ›œˆ€œ›˜ŪnÛ�qŽ—š‚›�œƒ›�œƒ›€š™ŽmÃ�ŌÎÍŨÔŨÐÏŌŌŅŅÐÐÏπÎ�̀ĖË^nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl[šđļļ·ķĩĩīģ ēąŪŠĐŪŠ°ŽĐÆŠ� ‘ÖŌ҇O|ÏŅÓӁŅÐÎÐρÎÍËumĻ•——˜‚™šƒ™€˜ ——–Đjpžŧšđļļ··€ķ ĩĩīģŊŦĻj8]Ķ­ĩšĐ�~ÛŲ–!‹ÝÔÕÔÓŌŌ€Ņ ÐÎÎÏÎÎÍukĶ“––‚—‰˜‚— ––“§ip―ŧšđđļ··€ķ ĩĩīēŊ°€)hīģ_Ļ� X‹ß۝3ƒIœÝ€ÖÔӀŌŅЀπÎujĢ“”€•–‡—–€• ”“Ģhpžŧšđđļ··€ķĩīģģ°ą>†Huģķj5§�WšâÖÜžÎÛÕÕÔÔÓÓŌŌŅ€Ð�ρÎuiĒ‘’’“€”‰•€”“’’‘Ēgoŧ€š��ķ€ĩ īīēą°īŠĪ§°­ķv7§� VĒáŨŨÝÜŲÕØŲÕԀÓŌŌŅŅЁÏÎth ‘‚’“‚’‘  eožŧššđđļ ķķ――ģąģąąŪ­ķ6§�V­āŨŨÖÕÔŨĘĐŅÓŌÓŌÔŌÓŌŅÐÏŌÐÐufž€Ž€€‡‘€€€Ž ždnšđļļ·ķķĩīģąĩĶ·ēŊŪŪ­Ŧē‹7§�XžÞÖցÕ}yŨŌÔÄÁŊšīķšļžąķēgeœŒŒ‚އ‚Ž€Œœbnđ€ļ·ķĩīģēģļJOŊ°ŪŪŽŠ°–:§�[ĮÚրÕØÏh‡ØŅÔÄšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbnđļļ·ķĩīģēēąŧ[&Ģē­ŽŽŦŪĄ@§�aŅŲրÕØÉd’ÚŅÔÂĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜anđļļ·ķ€ĩīģ€ēąŧf%›ī­€ŦŽĶC§�eÔŨÕŲĀ_˜ÚÐŌĀīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_mđļ·ķķĩĩī€ģēą°ŧm"īŽŽŦĐŦĐH§�nŲÖÕÕÔÔŲ·[žÚÐÐūģąđļšđīŧ·ķši`”‚„„€…†€…„„‚”^mļ·ķķĩĩīīģģēēą°šx„ĩŽŦŠĐŠŊQ§�{݀ÔÓÓÚ­X§ŲÐÐÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]mļ·ķķĩĩī€ģēēą°ļƒ yģŠŦŠĐĐē\Ķ�U‰ß€ÓŌŌÛĶY°ŨÐŌÃķŊĩķĩą°īīēŊf]Ž}€€‚‰‚‚€}[l··ķ€ĩīģēē€ą°ķ"sī‚Đąi6Ĩ�T—ß€Ó ŌŌڟZļÖÏŌŋŋ€―žū‚―j\Ž{}€~‡€€~}{ŽZk·ķĩīģē€ą°Ŋī—&hīĐϰt5Ĩ�R Þ€Ó ŌŅŲ‘WšÓÎÍπÎ�Í€Ë ĘÉÉČp[Œy{{|}ƒ~}|{{yŒYkĩķ€ĩīģģē€ą°ŊēŸ*\īŠĐ€ĻŊ|4Ĩ�TŦÜÓŌŌŅÐ֋ŠÞÕĖĖ€Í�Ė€ĘÉȀĮnZŠwyyzŒ{€z yyw‹Xiģ°ēĩĩģ€ēąą°ŊŊēĒ.QēŦĐϧ§Ūˆ5Ĩ�Vđ؃ŅÃëþũúų†ø‹Y‡uwxyx wu‰WŒóōÅąī€ē ą°°ŊŊŪŊĶ6FŪŠ€Ļ§Š’8Ĩ�YÃւŅÐÐâūŸĶœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’emprsvwxyz{„ƒ“?=ĻЧĶĨĨĻ›=Ĩ�_ËÕŅŅ€ÐÏÏːixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj„H8ĨЧĶĨĨ§ AĨ�dŅÔŅŅЁÏΜtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s‘S2ŸŠ€ĶĨĨĢFĨ�lŨÓŅÐЁÏÎΈ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆš]+—Ŧ€ĶĨĪĻPĨ�yÚŅЁπПZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\YŽe&­€ĶĨĪŠ]Ī�O†ÜŅ€Ð�ρÎÍp�JCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:<?BDFGIQPDI!�a°l#„Ŋ§ĶĶĨĪŽh7Ģ�O“ÛŅ€Ð�σ΍ĨŌūž―·°ŦĄ—‡‚|pc€e‘f€ecq|‚‡—ĄŦą·――ūŌŽsŠģv"z°§ĶĶĨĪŽr5Ģ�MÚÐÐυÎ͉zzy{srpmkjea‚bc‚baejkmprszyyœ€lŦĐą"t°€ĶĨĪŽz6Ģ�NŠŲÐσÎÍÍĖĖˌeWmzf[]^›_^][eynWisŦŦĐŊ‹$jŊĶ€ĨĪŠ†5Ģ�P·ÖτÎĖĖ€Ë Ę“aƒVjyfYĢ]YdykV‚fvŽŦŦĐŪ”'^°Ķ€ĨĢĻ‘8Ģ�UÁӃÎÍÍË€Ę ÉČȕ\„VdvdWĄZXcvgVƒ`ŦŦĐĻĻŽš-S­€ĨĢĒ͚=Ģ�ZĘŌπÎÍÍËËĘ€É ČĮĮƘU„V`sbSŸWSaraU„[~ŠĐĐĻĻ§Đ›1IŠĨĪĢĒĒΟAĢ� `ÎŅÏÎÎÍĖËĘÉÉȀĮ ÆÅÄšO„VZo_PS P^m\TƒUƒ§§Ķ€§ ͧ 8@ĨĨĢĢĒĒĪĒHĢ�iÓÏÎÎÍÍËʀČĮĮÆÅÃÂĀÃĘĻH„VUk]N›PN[kVTƒN„ĨĨĶĨĶĨĪĪĶĨ@8ŸĨĒĄĨQĢ�uÖÎÎÍÍĖĘÉÉČĮĮÅÄÂÁĀĮČŋđŸ BƒWQdZKK—L KKXeRTƒGŠĒƒĢĪĢĪĻH4šĶĒĒĄĄ §[9Ą�!Q…ØÎÎÍĖËĘÉÉČĮÆÄÂÁÁÆĀļ·ķĩĄ=WKaWFF•HGFVaMTBˆžŸ  Ÿ  ĒĄĒĄĻQ-”Ķ€Ą Ÿ§g8Ą�M”ŨËÉɂČĮÅÄÂĀÁšķķīąą°œ$5XG]TDC“ECBS]HV;Š››šœ›žž€Ÿ ĄĻ['ŠĨžžžĶs9Ą�#MœÔÆÅÍÏĖÄÆĮĮÅÄÂū―ļ·ĩģŊ­ŽŠĐ›(/}YCVP@?‘A ?@PXDV}4…€•–—™™›žŸ  Đa"}žœŸŸ››Ĩy6Ą�$NĨÏÃĀyMÆÄÆĮĮ·ššļķē°ŽĐ§ĨĢĄ–+)z[>RN=;=$<=MR@W{.$ƒ‘“•—™›žŸŸĐimœj<S›Ģ‚7Ą�%NēĖÉu †ÍÅɰš―đ·ī°ŽĻĨĢ ›š“1"w\;MI:8:%8:IM=Yy'"‚‰‰‹ŒŽ‘’•˜š›žĻsh{L Œ:Ą�&R―ĘÍS.v)qÏČÃĨđÁ―š·ē­Š§ĪŸœ™—•’Œ-t]8GF74‹6&46FI8Zv"+}ƒƒ…‡‰ŠŒ‘”—š›œœŸ§}$hp$qA8›Ÿ•<Ą�'YČĖËģmŽ•ĀÉĮž°ÅĀ―ŧ·ēŪŠ§Ģžš—”‘Ž‹†3p_5CD41‰3'14CD5[r%y}~€‚…‡ŠŒ’”˜™š›žĶ…(^Ģqy…žšDĄ�(_ĖĖĘÏÕÎŅÉʝžĮÃÁŋžļīąŽ§Ģžš–’ŽŠˆ…‚3k`3?@1.‡0$.1??2]n,txy{~ƒ†Š“•™™šžŸĪ%QĶĨĒĒĄ€œ�HĄ�)fÏËÉÉČČĮĖŠ…ÃÅÂÁŋžš·īŊŦ§Ē—“Ž‹…ƒ}<ga0;=.*…,)*.<;0_i/rtvx{}€„ˆŒ“•—š›œžŸŸĒĄq]Ąžœ›šŸPĄ�*sŌÉÉČĮĮĘĀzĐÉÂÁÁŋūžšķģŊŦ͟›–‹…}{x: ac/7:,(ƒ*(+:7.`e3pqsux{„ˆ‹’•˜™œžŸ€  ĒĄ’žž›ššĄ[:Ÿ�MÓȁĮĖ‘}ĮÄ€ÁŋūžđķēŊŦĨĄ›”ˆƒ~zwt>\e-27*%'%)73,a` 6loqsvy~ƒ‡Œ”–™›œ€ž ž €‰Ąžœ€šĄf6Ÿ�IÓ€Į ÆĘđgĪËÃÃÂÁ€Ā7ūŧš·ĩąŦĶĄš”Ž†{xtsCWf,.5(#%%#(40+c[Clkoquz…ŠŽ‘•™›œžŸ€ Ÿ NJf– œšš˜Ÿo7Ÿ�I™Ō€ĮÆÎfÁČÄÀÂ7Áŋŋū―ŧļķēŽ§Ģœ•†€{vpoCQh,,3( &3-*dV8s{ppuz€†Œ‘”—›œœžŸ€ ‚Ÿ žŸœWq̜šš˜žv7Ÿ� IĢŅĮĮÆĮÂeƒÍĂÂ6ÁĀŋūū―ŧđīēŪŠĪž–ŽˆlbnkE�Lh,)2$$1**fP�<eg]iw{‚‰”˜šŸ ŸŸĄ� €Ÿ žĪfG—Ÿš˜˜œ~7Ÿ� J°ÍÆÅÅËĻRœËÂ�Á€Ā/ŋŋū―žŧ·ķģ°­ĻĒ›”~YiumhGFh,(11(*fK�BcgnW6lŠŒ’—œž €Ē€ĄĒĒĄ  ŸŸžĢz0{Ą™˜˜›‡:Ÿ� OšĘÆÅÅ΋RŊĮÂ�Á€Ā3ŋūū―žŧšļķĩģ°Ž§ĄpUwzpkfH?i,'()gEAaejtk!B•˜›ŸĒĒĢĪĪĒĄĒ�Ą€ ŸžĄŽ/^Ą™˜˜™=Ÿ�WÂȀÅČrXŧÆÂÂÁÁ€Āūū€―žŧš€ļ'ķīē°Ļja„…wphdF9i+'h?D`ciq}z76”ĒĄĒĢĪĪĢĢ‚ĒĄĄ  Ÿž€ ž–5Cœš˜——”CŸ� \ĮĮÄÃÄÁa[ūÅÁ€Āŋūū―�ŧ€š)đļ··ķĩģŪ~„—”‡yogbJ3hg8C_cis†aUœĶĪĨĪĢĪ́Ē�Ą€ ŸŸž‚ ˜=8”š—–——GŸ� cĘÅÂÂÅžY\―ĀĀ�ŋ€ū―žŧŧšđļ ķĩĨŊŧĪ—Œ}pf`K05H\ckw„š™Œ‡§ĶĶĨ΀̀ǀĄŸŸ€žžœ™B7š––•™PŸ� oÍÃÂÂÅđZ]žÄĀĀŋ€ū―žŧšđđ!ķķīđÐáŌ̜’‚uh_NI^eo}‹–œŽŪĨĪĻĨĨĪ΂ǀĄ� ‚ž›šœ˜C;™–•”™Y;� F}ÎÃÂÂÅŧ][ķÄŋŋū―ŧ€šđđķķ€ĩēØũüßŦž—‰ylbGF`iv…‘™ĒđÂŧŊĶĨĪĪĢ̀ǀĄ  €žœ›€š œ“E@™•””™d8� F‹ÎÃÂÂÄÁhZĻÆŋŋ€ū―žŧ€š�đ€ļ·ķķĩīąķïĸĸîĀĪ—Š~rkiq|ˆ”ŸąĖŌĘ―§ĢĨĪ̃ĒĄ  Ÿ€žœ›šš™™‰FK“—”“’˜l9�E•Ė€Â ÁĮ}]—Æŋŋū―ž€ŧššđ€ļ·ķƒĩģēŪĩčĸųðåŅĩŒ‚‚‰™ŪđÆŅØŨħĢĨ΃ĒĄĄ €Ÿžœœ›š™˜˜{J]™•”’‘–q7�DžË€Â ÁȔf‡Ãŋūžž€ŧšđđļļ··ķĩīīģ€ēŪŽĖëóúýúōæÝÜåōöÝŌŅÏđĢĢĨĢ́ĒĄĄ Ÿž€œšš™€˜ ›pTqš•”’‘—{8�IŦȀÂÁÄŽt€·ŋžŧšđđ€ļ·ķĩĩ€ī€ģ€ēąŊŠŊÆčþþýûúúûýýāĮķ§ĒĪĨĪ‚Ē�Ą€ €Ÿžžœ››š™™˜˜—˜’l`…˜•“’‘•ƒ<�LķĮÂÁÁĀĀū‰‡ĶÁžŧŧšđļļ·ķķĩīƒģēą€°Ŋ­ĻĻĩÅÖáääáÕ­ĢĒĪĨĪ́Ē�Ą‚ ŸŸž€›š€™˜—–˜†pp“•’’‘‘’Š?�SŋÅÁ€ĀŋÄĨ’ ŧūžŧ€đļļ··ķķĩĩ„ģ ēą°°ŊŪ­­ŽĻĨĒŸž ĢĨĨĪĪ́ĒĄĄ€ �Ÿ€žœ›š€™˜——–•€v‚–“’‘‘ŽD�XÃÁĀŋĀŧ Ķĩ―žŧ€đļļ··ķķĩī„ģ ēą°°ŊŪ­ŽŦŦ€Đϧ§€ĶĨĪ̃ĒĄĄ€ Ÿžž€›š™�˜€— Ž‚€”’’‘H�bÆÁĀĀŋŋ€ūģ°đžššđđķķĩĩīē‚ą°ŊŪŪ­Ž€ŠĐĻ€§ĶĨ€Ī�̂ǀĄ  €žœ›š€™˜——––•Œ‡‹•“’’‘ŽŽ“Oœ�GnÉĀŋŋūū€―ŧšÃĘšļđ·ķķ€ĩ�ģ„ą°°Ŋ€Ū­Ž€ŠĐĻ€§ĶĨĪĪ̀ǁĄ Ÿžœ›€š™˜˜€—––”Œ””“’’‘ŽŽ”X<›�E{ËĀŋū€―žŧšūÍŲÔķķļ··ķķĩĩīģēą€°€Ŋ€Ū­Ŧ€ŠĐĻ€§ĶĨĪ̀ǁĄ Ÿ€žœ›š™˜—–”™˜”“•””“’Ž”a8›�CŠĘŋ€ūžŧ€šļĘãėŲēĩ·ķĩģēąą€°€Ŋ‚ŪŽŦ€ŠĻĻ€§ĶĨĪĢĒǁĄ  Ÿ€žœ›€š™™˜€—–•“œ ›–”’‘ŽŒ“j8›�B’Éūū―žŧšļķÚõøÜąģĩ�ī€ēą°°ŊŪŪŽŦŠĐ€Ļ§Ķ€Ĩ�Ģ€ĒĄĄ  €Ÿžœ›š™€˜ —––•“ĨĒ›“’ŽŒŒ’n9›�BœČūū―ŧ€š đđļķļįûýáąą€ĩ�ģ€ēą°°ŊŊۭށŦŠŠĐ€Ļ§Ķ€Ĩ�Ģ€Ē�Ą€ Ÿžœœ›š™™€˜ —–•““ Ļ§Ą’‘ ŒŒ‹Žv9›�FĻÅū―ŧŧšđļ ·ģ·ëĸĸėđŪģē°°€ŊŪ­Ž€ŦŠŠĐ€Ļ§ĶĶ€Ĩ�Ģ€ĒĄ ƒŸž€œš™€˜ ——–•“•ĨŽŠĒ’€‘€Œ‹Š~:›�IģÂ―€ŧšđ€ļ·ķķēĩæĸĸũĮŦŊąą°°€Ŋ­­ŽŦ€ŠĐϧ€ĶĨĪĪ̀Ǡ €Ÿ€žœ››™™˜˜—––”’›ŦŊ­Ģ’€�€ŽŒ‹ŠŠ‹„?›�QŧĀž€ŧšđļļ·ķ€ĩēąÜĸĸýÜģŠŊ°°ŊŪ­­ŽŦЃĐϧ€ĶĨĨĪĢ̀Ǡ €Ÿ€žœ›š™™˜—––”•Ĩą°ŊĄ€€ŽŒ‹ŠˆB›� Vŋ―ŧŧšđđļļ·ķķĩģ­ĘøýûïČ­Š­Ū­­ŽŠŠƒĐ�ρĶĪĢ̂Ǡ Ÿ€ž›š€™˜—–”•ŸŽēē­›‘‘€Ž€Œ‹€Š€‰�F›�_Â―ŧšđđļ·€ķ€ĩīīģģŽ·âøöōÜūŦĻŦŽŦŠ€Đ€Ļ�§€ĶĨĪ̃ĒĄ  ž€›š™™˜—–”•œ§Ŋ°Ŋ§–’’‘ŽŽ€Œ‹‹Š‰‰ˆˆŒNš�DkÆžšđđﷁķĩīīģē­ŦÅæîčäÕŋ­ĶĶĐŠŠĐĻ€§ĶĶĨĪĪĢ‚ĒĄĄ Ÿžœšš™˜•”–ĨŦޭМ‚’‘ŽŽŒŒ‹‹Š‰ˆˆ‡‡V;™� CxÆŧđđļ··ķķ€ĩīīģģēēąą°ŠŪÅÜâßßÛÍšŠĒĒĨĶ€§ĶĶĨĪĪĢĒǁĄ Ÿžž€œ›š˜—•–› ĨĻĐŠ§ž”’””“’‘ŽŽŒ€‹ Љˆˆ‡††‹_9™�A…Åđđļ�ķ€ĩīīēēą°Ŋ­ĐŪÁÔÞäęņíÜÃŪǟ ĄĢĪĢĒĒ€Ą Ÿžžœ›™–““–ĢŠŽŦЧĶΜ”‘“’Œ ‹‹‰‰ˆˆ†……Še:™� ?ŽÄļ·ķķĩĩķķ€ĩīģēēą°ŊŊŪŽĻŠļÏåõûĸĸýîÜĮļ­Ģž›š™™—–••–šĢ­―ÍÏËÚģ­Ķ ™’ƒ‘Œ ‹‹Š‡†……„„…‹k9™�B—ŋģąķđļīģīĩīģēą°Ŋ‚ŪŽŦЧĨŊÅãüƒĸýôéáÚŌĖÉÄÃĮĘÐÖÞæōýĸĸųįÕÅķŠž–’‘‘…�Ž€Œ€‹ Šˆ…€ƒ„ƒ€ƒˆr<™� =ĢđŪŊƒESœēąģģē€ą�°ŊŪ­­€Ŧ ŠĐĻĶĒĒ­ÂÚîü“ĸņÔđĪ—“€’‘‘ŽŒŒ‹€Š ‰†€|sE3U~…{0™� $°ĩ°‡ ;Ŧēą°°€ŊŪŪ­Ž€ŦŠŠĐ€Ļ §Ī  ŠđÆŨįïõüþƒĸþüõîåÔÂēž”‘‘““’€‘€ŽŒ‹‹Šˆ„~z? V€ƒ�#™�9·ģĩ[_D!īēēą°€ŊۭށŦŠŠĐĻ§Ķ€ĨĢ ššœĄĨŠŪąēēŊŽĶ š–‘‘”€•”’’€‘ŽƒŒ‹€Š€‰ ‡ƒv#C^+;‚‚†.™�D―īķ”6`si€ēą°€ŊŪ­Ž€ŦŠŠĐ€Ļ�§ĶĨĨ΁ĒĄĄŸžœš˜„— ˜˜™˜——––•””€’‘‘ŽŒŒ‹Šˆ †ƒ†Y@€C_ƒ‚‡9™� Gŧķīš°œ°đģ€ą�°€Ŋ�ہŦ�Š€ĐĻϧ€ĶĨĨĪĢ‚ĒĄ  Ÿžœ‚œ›š€™˜—€–•””€’‘€ŽŒŒ‹€Š�‰‚ˆ ††‰}‚…‚‡D™� lŅąŊŪ°ą­ŽŠĐ�Ļ€ĶĪĢ€Ē ĄĄ ŸŸžžœœ‚š�™€˜–•”“’’‘€ŒŠŠ‰‡‡€…„„‚ƒ€€„~ {{|zzxw~‹W™�9āÖę€åää€âäį€äââáāāß߀ÞÝ݁܀ہÚŲÚßßÛÝÞÜŲÜÝÚÛÜÛŨÛÛÖØŲØÕŲŲÔŨØÕԀҀÐÏÏÍĖ„ËÍʁÉʗsš�"v°đļđđŧ―ŋĀģĄąŽŪąēģīĩķ·ļļđšŧŧž―ūŋĀÁ€ÂÃÆŋĶĶđąĶŪŋϧŧ°§ąŋĻĻŋąĐĩÁŠŦÂąŦīĖ€ĘËËÍÏŅŌŌÓÓÔÔÕÖÐĘÏŲØØÚÐ{œ�"$BRUUSW]de@ 8(.37;>@BCFGHILMOPRSVXZ€[€\aH��4�B��9�>��>�?��>�\WX\`defhijjln[LZsrqqR: ›�$,N]aa_cioqSA:=BEILMOPRTUVXZ\]^_adeg€fhglV D)P G#$L L )M M#icdhlnopqsttuweYh}{{y[>œ�#(L]`a`cinqV><<BEILMPQRTUWYZ\]_`bdeeghlX F+!R J%&N N",O O&icdiknpqrsstuvcYj|zzwY:œ�$J\€`chmrY:?;BEIKMOQRTUWYZ[]^`bc€e�f€gkY H.#T K((P P$.P Q!)icdiknpqqrsstuaZk{yytW5œ�!H[a``bhmr[ 1?;BDIKMOQRSTWYZ[\^`ace fggkY K2&V N*+S S'1S T$-icdhknoqqrrsts`ZmzxyrT1�EY€`bgms](-9CEHKMOPRSTWYZ[\^`acd‚egjZ L4(X P-.T T)3T U&/icdfi[bXhpqrsr_[nywynR,�CX€`bglr`-)(5CIMMOPRSUVYZ[\^`acdd‚ej\ M5)X P..T T*3U U'/i‚cfE€â―bdprsp][pxuxlQ&�@W€`bflsb1,*(-9FMQQRSTVXZ[\^_ac€deiZ M5)X P..T T*3U U'/icfX(ßĸĸ|Kqqrn\]pwtwiO!�<U€`bflrd6%0//--.6BKRVWWXZ[\]`ab‚deeiZ L4(X P-.T T*3U U&/icf]“ĸŨ0Wpprm\^qutvfL� 9S_``afkrg>.ƒ20029CNUZ]^__`acd‚efjZ L4 )WP. /TT* 3UU& /jfgkR,O:Lmnqrl[^qusucJ� 9Ubcbdhnvh>2†4 3137=FKQVZ]_aab7afW'%I:&3R'%L6&7O&&O4%:P%&P2&5bZTRQRUZYP[ddilnh[buwvwdHž� DTUUWYZXLA…B‚CBA@@ABDEF€G‚HGEEFHEFH€F HGGHGGHIFFH€GHDBBCB€A CCDFIKLLQ[€fgO(ž�$€%'&&(€*ƒ+‚,†-„.//1202€3€4 55657769889::9€;:<==>?@@€A@@??A?ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ���Ž�€<˜;<Û�Kc™|bKÛ�hž™™žhÛ�“Īŧķ‘ĩķŧĢ“Û�:>€G„F€EDEƒFGGF>:Û�!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ�!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û�}―œ€ž€žœūzÛ�|ŋĄƒĢ‹ĪƒĢĄŋyÛ�|ūĄ†Ģ…ΆĢĄūyÛ�{― €Ē‘̀Ǡ―xÛ�zŧ ‚ĒĢ‚Ē ―xÛ�zšŸĄ…Ē…Ģ†ĒŸžvÛ�x🡕ĒĄŸđuÛ�x·ž‚ĄĒ‚ĄžđtÛ�wĩ€ ƒĄ…ĒƒĄ€ ķsÛ�vĩ€Ÿ  Ą  €ŸĩrÛ�uģ›žƒŸ‰ ƒŸž›ģqÛ�t皜žŸžœšēpÛ�q°™›€œ�ž…Ÿ�ž€œ›™°oÛ�rۘ›œˆ€œ›˜ŪnÛ�qŽ—š‚›�œƒ›�œƒ›€š™ŽmÃ�ÔÓŌÚØÚÕӁՁԀÓ�Ō€ŅÐ`nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl^Āŋū―ŧŧšš€đ ļ··ĩģŊ­ēŊīą­ËŠ�”ÚŨՌSÓÖØØŨÕŨŨԀՁŌŅÏwmĻ•——˜‚™šƒ™€˜——–ĐjsÁÁĀŋūū―žŧ€š đđ·ģ°­p=bŦģŧŧĐ�ƒāޚ'â€Ų�؀ŨÖÖՀÔÓŌŅwkĶ“––‚—‰˜‚— ––“§irÂÁĀŋŋū―ž€ŧ šđļ·ģĩ…/mšđdĻ� \ãßĒ;RĒâ€Ú�؁ØŨրÕÔÓŌwjĢ“”€•–‡—–€• ”“ĢhrÂÁĀŋŋū―ž€ŧšđļ·ĩķ•FRz·žo:§� [žįÛāÆÁÓāÚ€ŲØŨÖ€Õ ÓŌŌŅwiĒ‘’’“€”‰•€” “’’‘ĒgrÁĀŋŋū―€žŧšđļđ·ķĩđŊŦ­ķģž|<§� Z§æÛÜāāÞÚÜÝŲØ€ŨÖÕՀÓŌvh ‘‚’“‚’‘ erÁÁĀŋūū――ž€ŧ ššÁÁķĩļ·ķģēŧ„;§�ZēäÛÚÚŲŲÜÏ­ÕŲØŨÖØÖŨŨÔÔÓÕÓÓwfž€Ž€€‡‘€€€Ž ždqĀŋū――žŧŧš€đļķđŠž·ī€ģąļ‘<§�]ĀâÛڀŲڂ~ÜØÚĮĀŊšīķšļžą·ągeœŒŒ‚އ‚Ž€Œœbqŋ€ū―ŧ€šđđļ··ŧOSķĩģģē°ķœ?§�^ĖßڀŲÜÓnÞŨÚÅšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbqŋūū―ž€š đļļ··ķŋ_+Đļē€ąīĶD§�eÕÞڀŲÝÎj—ßŨÚÃĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜aqŋūū―ŧ€šđķĀj*Ąđē€ąēŽH§�iŲہŲÝÅeāÖØÁīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_pŋū―ŧŧšđđ€ļ·ķĩĀq&–š€ąŊ°ŊM§�rÞÛŲŲØØÞ―aĪßŨÖŋģąđļšđīŧ·ķši`”‚„„€…†€… „„‚”^pū―ŧŧšđļ··ķĩŋ|#‰ŧąą°ŊŊīW§�â€ŲØØāģ^­ßŨÖÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]pū―ŧŧšđļ··ķĩ―ˆ#š°ą°ŊŊ·bĶ�Xã‚ØāŽ_ķÝÖÖÂĩŊīĩĩ°°īīēŊf]Ž}€€‚‰‚‚€}[o――ŧšđđļļ··€ķĩž’%xš‚Ŋ·o;Ĩ�W›ä‚ØßĨ`ūÜÕŨÁÁ€ŋ ūŋŋ――ūŋk\Ž{}€~‡€€~ }{ŽZo―žššđđļļ·€ķĩĩš)lšŊŪķx:Ĩ�VĪâØŨߗ]ĀŲÔӀÔÓŌŅŅÐπÎs[Œy{{|}ƒ~}|{{yŒYnŧŧššđđļļ·€ķĩĩļĪ.aš°Ŋ€Ūķ‚9Ĩ�Wąá€ØŨÖݑâۀŌŅÐЀÏ�΁ÍrZŠwyyzŒ{€z yyw‹Xlđĩļšđ�ķĩ ·Ļ3Uļ°ŊŪ­­ī:Ĩ�YūރŨÉïĸųû€ú‡ų‹Y‡uwxyx wu‰WŒôôÉķ�ķĩ ģĩŽ:KģŊŪۭް—>Ĩ�^ČۂŨÖŨæÁ Ķœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’€gprtvxy{||}†…—CAŪŊ­ŽŦŠŪĄBĨ�cŅÚŨŨ€ÖÕÔŌ“ixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj†N=Ŧ°ŽŦŠŠŽĶGĨ�hÖÚŨŨցÕԞtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s“X7Ĩ°ŽŦŦŠŦĐLĨ�rÜŲŨŨÖÕÕÔÔÓĨˆ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆc0ą€ŦŠĐŪUĨ�~ßŨ€ÖÕÕÓŌŌĄZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\Y‘k,•ģŽŦŦŠĐ°bĪ�TŒâŨ€ÖÕԀŌŅr�JCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:<?BDFGIQPDI!�dķr)Šĩ­ŽŦŠĐēm<Ģ�T™áŨÖÖÕÔӂŌĨŌūž―·°ŦĄ—‡‚|pc€e‘f€ecq|‚‡—ĄŦą·――ūŌŽv°ļ|(€ĩŽŦŦŠĐēw:Ģ�SĒāÖÖÕÔÓӃŌ‹zzy{srpmkjea‚bc‚baejkmprszyyœ€oąŊķ†(zķ€ŦŠŠą;Ģ�TŊßՀÔÓÓŌŌ€Ņ ÐЏeWmzf[]^›_^][eynWiwąąŊĩ*pĩŦ€ŠĐŊ‹:Ģ�VžÜԂÓŌŌŅŅ€Ð Ï–aƒVjyfYĢ]YdykV‚fyēēąŊĩ™-cĩŦ€ŠĐ­–=Ģ�ZĮŲԀÓŌŌ€ŅÐÏÏÎÍ͙\„VdvdWĄZXcvgVƒ`…ąąŊŪŪąŸ0XīŽŠŠĐĻŦŸBĢ�`ÏØÕÓŌ€ŅÐÐπÎ�̀ĖœU„V`sbSŸWSaraU„[‚°ŊŊŪŪ­ŊĄ6M°ŦЀĻŠĢGĢ� eÔŨÕÓŌŅŅÐÏÎÎÍĖ ËĘƟO„VZo_PSP^m\TƒUˆ€­ Ū­­ŽŪĶ>DŦŦĐЀϧLĢ�pŲÕÓŌŌŅÐπÎĖĖËËÉČÆÉÎŦH„VUk]N›PN[kVTƒNˆŠŦŽŦŽŦŠŦŽŠF>ĨŽĐϧĶĶŠWĢ�|܀ŌŅÐÏÎÎÍĖĖËĘČĮĮĖÍÅŋĪ BƒWQdZKK—L KKXeRTƒGĻĻ‚ĐŠĻĐ­N: Ŧ§€ĶĨŽ`>Ą�VŠÜŌŌŅŅÐÏÎÎÍĖËʀĮĘÄū―žŧĶ=WKaWFF•HGFVaMTBŽĨĪĶĨĨͧ§Ķ§§ŊW3™Ŧ€ĶĨĪŦl>Ą�S˜ÜςÎÍÍĖËĘČÆÆÅŋžŧđ·ķīŸ%5XG]TDC“ECBS]HV; ŸŸ ĄĒĪĨĶŪ`,ŠĢĪĒĒĢŦx>Ą�RĄØËÉŅÓÐɀĖËÉĮÁÂūžđļĩēąŊ­Ÿ)/}YCVP@?‘A#?@PXDV}4Ššš››œžŸĄĒĢĪĨĨŊf&ĢĄĪĪĄĄŠ<Ą� RŦÔĮÄ~Q…ĘʀĖÆŧŋĀ―ŧ·ĩąŪŽĐ§Ĩ™+)z[>RN=;=<=MR@W{.$ˆ•”•–—™™œž Ē€Ī Ŋm#rĄn@W• Ļˆ<Ą�%U·ŅĖ{ŠŌËÎĮīŋÂŋžđĩą­Š§ĪĄŸž–2"w\;MI:8:%8:IM=Yy'#†ŽŽ’“•—šœžĄĒĢĢŪw$m"RĒĶ’=Ą�&XÂÐÐY6~2wÔÍÉĐžĮÁŋž·ī°ŽĻĢĄž›˜•.t]8GF74‹6&46FI8Zv",‡ˆŠ‹‘•–˜œž ĒĒĨށ)lt,zL? ĪšBĄ�']ĖŅзt—œÅÏÍĄĩĖÆÃĀ―ļĩ°Ŧ§ĒŸ›—”‘ŽŠ4p_5CD41‰3'14CD5[r&|‚…‡‰‹‘•˜™œŸ ĒĪĪŠŠ-dĐvˆ€ŠĢĢ IĄ�(cŅŅÏÔŲÓÖÏŅĒĢÏČÆÅÁ―šķ°ŽĻĢž™•‘Ž‹‰…4k`3?@1.‡0(.1??2]n.x|~€‚„ˆ‹Ž“–˜šœŸĄĢĪĪĻ“,WŽŠĶϧĄĒĒMĄ�jÔÐπÎ"ÍÓ°‰ČËČĮÄÂĀžļģŊŦĨ š–‘ŽŠ‡„‚=ga0;=.*…,)*.<;0_i0vxz|‚†‰‘”˜šœŸĄĒĒĢĪĶĨvbĶĢĒĒĄ  ĨWĄ�xŨ€ÎÍĖÐÆ~ŪπČÆÄÂūŧļēŪĐΟ™”Š†‚|< ac/7:,(ƒ*+(+:7.`e5tuwy|€„ˆŒ”—šžŸĒĢĢĪĨĶͧĨ•ĒĢĒĒĄ  Ļ`>Ÿ�O†Ø€ÎÍĖŌ•ÎËɀĮÅÃÂūŧķēŊŠĪŸ™’‡‚~{x@\e-27*%',%)73,a` 8psuwz~„ˆ‹“˜›Ÿ ĄĒĢĪĶĶĨĨĢĨ…ĨĒĄĄ Ÿ§k=Ÿ�JM•ØÎÎÍĖÐūkĐŅÉÉČĮÆÅÅÃĀŋžļī°Ŧ͟™’‹…€|xvDWf,.5(#%%#(40+c[Dposuz„ŠŽ’–š ĒĢĢĪ€ĨĪ ϐišĨĄĄ žĶu=Ÿ�GMžØÎÍĖËӒmČÍĘÉČČĮÆÄÄÃÂĀžš·ē­ĻĄš’‹…yrrEQh,,3( &3-*dV:v}tty†‹‘–™ ĄĒ΁ĨĪĨĨĪĢĒĪĄ[vĻĄĄŸžĨ|;Ÿ� MĐÖÍĖËÍČiˆŌɀČ5ĮÆÆÅÄÃÃÁŋ―ŧļīŊĐ̜”Œ…odrnG�Lh,)2$$1**fP�>ij_k|€†Ž”™œ ĢĪ€Ĩ�§€Ķ€Ĩ�Ī€Ē ŠkLĪ ŸŸĢƒ<Ÿ� OĩÓĖËËŅ­WĒŅ€ČĮƁÅ.ÄÂÁĀĀ―ŧš·ģ­§ ™‚[mxpkIFh,(11(*fK�Cfjr[9p‘—ĄĢĨ…§�Ķ€Ĩ�Ī€Ē Đ€5€§ŸŸžĄ?Ÿ�SŋЀËӐVĩÎČČĮĮ€ÆÅĀÂ)ÁÁŋū―ŧšķēŽ§uY|~sniJ?i,'()gEDehnxo&GšĄĨρĐĻĻĐϧĶĨĢ€Ē §“3b§ŸŸž •CŸ� [ČÎËĘÉÏw]ÁĖĮÆÅĂÂ*ÁÁĀŋūūžš·ķ­oeˆˆ{skgH9i+'h?Fcglu‚~<:šĻ§ĐĐρĐĻϧ§€ĶĨĢĒ Ī›;IĒ ž›HŸ� `ÍĖÉÉËĮf`ÂʀÆÅÃÂ�Á€Āŋū€―"ŧšīƒ‰œ˜Š}rjeM3hg8Eagnwƒ’‹fZĒŽŦŠĐĻ€Đϧ§€ĶĨĪĢ‚ĒĢžB>™ €œNŸ�gÐËÉÉËĀ_bÂČÆÅāÁĀĀŋū!―žŧŠīĀĻ›€ticM05J`fo|‰•Ÿž’Ū­ŽŠŠ€ĐĻĻ€§ĶĪĪĢƒĒ ĢŸG<• ›šŸUŸ�tÓÉÉČÉū_bÁÉÅÄÃÀÁĀĀŋū―žŧŧđŋÖįŨ§Ą—‡wkcQ Kaht‚›ĒēģĐŠ­€Š�Đ€Ļ€§ĶĶĪĪĢ‚Ē ĄĄĢH@” œš™ _@� J‚ÔÉČĮÉÁb`ŧČĀÀ€ÁĀŋŋ€ū―žŧŧ€š·Þųþâ°Ē›~pfHHdnz‰–ŸĻĀČĀĩŽ€ŠĐĻ‚§ĶĨ€Ī�Ģ€ĒĄĄ  Ē˜KF•žšš™Ÿi>� I‘ÔÉČĮČĮm_ŪĘĀÀ€ÁĀŋ€ū�žŧššđķŧōĸĸðÅŠœ‚vnnu€šĪ·ŌØÐÃ­ŠŠĐĐĻ §§ĶĨĨĪĢĢĒĒ€Ą ŸŸĢKQ™š™˜r?�JšÓȀĮĖ‚cËÃÂÂÁĀĀŋŋūūž€ŧššđđļļīđėĸüõęÔ𠐇‡ŽžīŋÍØÝÝʭЊЁĻ§§ĶĨ�́ĒĄĄ €Ÿ ΁Pbž›š˜—x>� JĪŅČĮĮÆĖšlĮÂÂÁĀ€ŋū―žŧŧššđđ€ļ··ģąÐïöýýúóæÞÝæōųäŲØÕĀŠĐŠĻ§§ĶĶ€ĨĪ́ĒĄ €Ÿ žžĄvZwĄš™˜˜œ?� KąÎČĮĮÆÉąz…ŧŀÂÁÁŋū―ŧŧšƒđļ·ķķīŊīĖėþþýûúúûýþįΞŪĻŠŠ€ĐϧĶĶ‚Ĩ�΁ĒĄ €Ÿžž˜qfŠŸš™˜˜š‰A�PžĖĮÆÅÅÆÃ‹ŦÆÂÁÁ€Āŋŋūū――žšđ€ļ�·€ķĩĩģŪŊšÉŲãææãŲĮģŠĻ€Š€Đϧ€Ķ€ĨĪ́ǀ  ŸŸžŸŒuv™š€˜—˜D�XÄÉÆÆÅÅÄČŠ—ĨĀÃÁ€Āŋūū€―žšđđƒļ·ķķĩĩīģģēŪŦĐĐĻĻĶͧ€ŠĐϧ§ĶĨĪĢ́ǀ ŸŸž€ œ†{‡™˜˜—–—”I�^ČĮÆÆÅÄÃÅŋĶŽšÃÁÁĀŋŋūū€―ŧšđ„ļ··ķĩĩīģēąą°°Ŋ­Ž­ŽŦ€Š€Đ€Ļ�§ĶĨĪ́Ē�Ą€ Ÿžžž”ˆ…–›™˜—––——N� fËĮÅÄÃÃÂÂÄļĩŋÂ€Āū――ŧššđ…·�ķ€ĩģē€ąŊŊ€ŪŽŦ€Š�Đ€Ļ§ĶĶĨĪĪĢĢĒĒ€Ą ŸŸž›’Œ‘›™™˜€–•™Tœ�LsÎÅÄÂÂÁĀČÏĀūŋ€ū―žŧššđ‚·€ķ‚ĩģē€ąŊŊ€ŪŽŦŠŠĐσ§ĶĨ€Ī�̀ǀĄ Ÿž››š–’™šš™˜––•”š^A›�I€ÐĀÀÂÁÁÄÓÝŲŧžūūžŧŧššđļ··€ķ…ĩģē€ą ŊŊŪŪ­ŽŦŠŠĐρ§ĶĶĨĪĢ̀ǀĄ  Ÿ€žœ›šŸž™™€š™˜—–•”›g=›�HŽÎÃÁ ĀūÏčņÞđžžŧ€šđļļ·ķ…ĩ�īēą°€ŊŪ­€ŦŠĐĻϧ§ĶĶ€ĨĪ́ĒĄĄ ŸŸžžœš™ĄĪĄœ€š ™˜——•””™o>›�H—ÍÃÁÁ ĀĀ――āũúā·ļŧššđ€ļ·ķ‚ĩīģēąą°€Ŋ­Ž€ŦŠĐĻϧĶ́ĨĪĢ€ĒĄĄ Ÿ žœœ›šĢЧ ™˜—–•””’—t>›�HĒĖÃÂÂÁÁŋ žūęýĸåļ·šđđ€ļ·ķ€ĩīģģ€ēąą°€ŊŪŪŽ€ŦŠĐĻϧ͂ĨĪ́ĒĄ €Ÿ žžœ›š˜§Ū­Ķ™€˜——€•“’‘”|?›�JŊʀÂÁŋ ū―đžïĸĸï―ē€ļ·ķķ€ĩīģē�ą°ŊŪ­­ŽŦŠ€ĐϧĶĶ€ĨĪĪ́ĒĄ €Ÿžœœ™›Žģ°Ļ™–˜—––€•“’‘‘“ƒ@›�QļĮÂÂÁÁĀŋŋū―žŧŧļšëĸĸųĖąĩĩ€ķĩīīģģēą‚°ŊŊŪ­­ŽŦЁĐĻĶĶĨ€Ī€ĢĒĒĄ€ Ÿžž€š˜ ąĩīŠ˜•€–€•”“’‘‘‘ŠC›� WĀÅÂÂÁÁĀŋŋū―ž€ŧ·ķā€ĸāļ°īĩĩī€ģąąƒ°ŊŪ­­Ž€ŠĐ§ĶĶĨ€Ģ‚Ē�Ą€  Ÿž›ššŠ·ķīĻ–•€–€• ”“’‘‘ŽH›�]ÄÄÂÁ€Āŋū――ŧ€š đ·ģÏúĸýōÍ簁ģ�瀰ŊŪŪ­­ŦЃĐϧĶĶ΀́Ē�Ą€ žž››Īēļ·īĒ–——––••””€’‘ŽŽL›�cČÃÁĀĀŋū€―žšƒđ ąžæüųöâÄēŊą°°ŊŪ­ŽŦ€ŠĐЀϧ§ĶĪ΀̀ĒĄĄ Ÿžž›œĢŪĩ··­œ—˜˜—––•”“€’‘Ž’Sš� IpËÃĀĀŋū――žŧŧšđļļ·ģąÉëôîčÛÆģŽ­€°�Ŋ€Ū­Ŧ€ŠĐĐĻρ§ĶĨĪ̃ĒĄ Ÿžœ›ĪŽēīīąĢ˜™™˜——––•”€’€Ž“\A™�F~ËĀĀŋ€ū―ŧ€šđđļķīŊģĖâįææáÔĀŊ§ĻŦ­Ū­­Ŧ€ŠĐĐρ§ĶĨĪ΁ǀĄŸœ›Ą§ŽŊ°°ŪĨš˜šš™˜——–€” “‘ŽŽŒŒ‘e@™�FŒËÁŋū―ŧššđļ�ķ€ĩģ°īÆÚåéðöðāĮīŠĶĶĻĻ€Š�ЀϧĶĶĨĨĪĒĒĄŸššĒаģģ°Ŋ­Ŧ̚—˜——–•€”�“€‘Ž€Œ‘l@™�F”Éūžŧžšŧžŧššđļ�ķ‚ĩēŊąūÕëøþĸĸþïßËžēŠĨĢǁ žžœ›šœ ĻēÃŅÕÓÉÁđīŪ§Ÿ™–˜˜——˜€—•”“€’ ‘‘Œ‹ŠŠ‹Œ‘p?™� GžÄļĩŧū―đķđšđ‚ĩīī€ēą­ŦīËčýƒĸýôëäÜÕÏĖĮĮĘÍŌŲāčóýĸĸüíÜËūąĨœ˜—˜„—–••”’€‘ Ž‹†…ˆˆ‰†‰ŽxB™� AĐūēī‡JYĄļķ€ļ·ķķĩīģē ą°ŊŪ­ĐĐģÆÜðü“ĸõÛŋŠž˜—€˜�—–‚•’’‘ Œ†wK8[ƒ„‹4™�(ķšĩ‹ A°·ļļ·ķ€ĩīīģēąą°ŊŪŽŠĶΧŊūËÚčðöüþƒĸ þüöïįŨŷʘ˜™™€˜——–ƒ•”’€‘€ ŽŠƒ~D[ˆ‰Š%™� >―·š`(gN(Ģđ··ķĩģģ€ēąą€°ŊŊŪ€­ŽŽŦĐĶĪĄŸĄĒĶŦŊģĩķķĩąŦĶ ˜––—šœš€™˜—€–€•€”�’€‘�€Ž ‰…z(Lf4@ˆ‡Œ2™� HÂđŧ™=i{oļķ€ĩīģģēēą€°ŊŊŪ€­ŽŦŠŠ€ĐϧĶĨĪĢĒ …€Ÿ�ž€œ›š€™˜—€– ••””““’‘Ž ŒŠ‹_HŠKd‰‡=™� LžđūĩĄĩ―·ķĩĩīģģēą°ŊŪŪ­ŽŦŦŠŠĐϧ§ĶĶĨĪ„Ē�Ą Ÿžœšš™˜—€–••““€’‘ƒŽ Œƒ‡‡‹‡ˆŽI™�pØļīīķļģąŊ ŪŪ­­ŽŠŠĐĐĻ€§ĶĶĨĪĢĢ€ĒĄ Ÿžœœ›€š™˜˜–••””’’‘‘€Œ‹ŠŠ‰ˆ‡€…ƒ„ ‚‚ƒ€~~…’[™�9ãÛëįįæåääããæęæį῁ä�ãâ�áā€ß�ށÝÜÜÛÛÜââÞßáāÝāāÜÝßÝÚÞÝŲÛÜÚŨÛÛŨÛÛ؃ÓŅŅÐςΠÍÍÎÎÍĖËĘË͝yš�}ķŋÁÃÅÆļĢķ°īĩ·ļšŧžž€ūĀÁÁ€ÃÅÆĮČ€É ĘĘËĖÃϧ―ģ§ŊÃĐĐĀģĻģÃĐŠÄģŠļÅŦ­ÆģŽķҁÐŅÓÕÖŨŨØØŲŲÚÛÖÏÕÞÞÝßփ›�$-O`ecbflrsM D28?DGILOQTTVXY[\^`cegjijkrU��>!�M��C�I��I� J��J�keflprsuwwxy{|jZj‚€€`E ›�"4Ykpompw|~_LDFMPTVZ[]^`adefijknoq€tu{b M. "[ Q( (W V#.W X 'wq€prwy|}~€ƒ…revЇˆ†iI œ�!/Xjoonqv{€c HFEMQSVZ[]_abdegijknprt€uzc O1 $] T* +X X% 1Y Z" )wqrwz{}~€‚ƒpfx‰‡ˆ…fCœ�"*Uhoonpv{e#CIDLQSVY[]_abdeghiknprs‚tuzd Q4 &_ V, -Z Z( 3Z \$ -wqrwz{|}~€‚‚nfzˆ…‡‚d>œ�#%Sgoonpu{€h'8IELPSVY[]_abdeghikmprss‚tze T6 )a X/ 0\ ]+ 5\ ^' 0wqrwy|}~~€€€mg{‡…†a:� Pf€npuz€k04BNPSVY[]_abceghikmpq€styf U9 ,c Z1 2^ ^- 8^ `) 3wqruwulpy~~€€lh|‡„†}_3�!Menmmptz€m4//=MUWY[\_`bceghijmoq‚sttyf V: ,c Z3 2_ _- 8_ `* 4vqruY9‡Tdv~~€~ii~†ƒ†y]-�"Jcnmmotz€o9#30/4BPY]^_`bcefhijmoqr‚styf V: ,c Z3 2_ _- 8_ `* 4vqti)&ģNBd~}|ij~…‚…v['�Fa€motz€r?+766436>LW_bccdfhijloqrr‚sxf V:,c Z22^ _,8_ `*3vqtk+*i~}~zhkƒƒtX �B_€mosy€tH5‚;:88:BMZcgjkklnpqs€uyfU: -bZ3 3]^. 9^_+ 4xtt€uyb62`{{~€ygl‚‚pU � Capqpqv}„vI<„> ==<:;@GPW\bgkmo9pqqtb.,TC-:].-W>-?Z,-Z;-BZ--Z9-<og`^]_agijoqrvy{uhpƒ„ƒ…rT� &OabbcdecVI„KLLKKLLKJIIJLMOP†Q NOPPOOQOOQ€P ROPRPPQRPPR€PQM‚KJJLLMPS€U[g€rs[0ž� *++,,++-//ƒ0‚1�2344334434€5€68878€9€:;;<;€=�>€@AA@BCCDDEDDEFFGFEEGF$ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ�ĸ���t8mk��@�����������������������������������������������tøęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęøn����������������������������������������������������������������������������������������������ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸy����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx����������������������������������������������������������������������*œšššššššššššššššššššššĖĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸƚššššššššššššššššššššœƒ0���������������������������������������������DėĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņP��������������������������������������������ģĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÁ�������������������������������������������ÏĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÚ������������������������������������������äĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸí������������������������������������������ōĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõ!������������������������������������������*úĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ4������������������������������������������@ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸN������������������������������������������[ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸi������������������������������������������wĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸƒ������������������������������������������Œĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ•������������������������������������������Ąĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ­������������������������������������������žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸČ�����������������������������������������ÓĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÞ ����������������������������������������įĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸï����������������������������������������óĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũ$����������������������������������������-ýĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ8����������������������������������������EĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸR����������������������������������������`ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸm����������������������������������������|ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‡����������������������������������������Žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ˜����������������������������������������Ĩĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸģ����������������������������������������ĀĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖ���������������������������������������Öĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸá ��������������������������������������ęĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸð��������������������������������������ôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸų'��������������������������������������1ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ<��������������������������������������JĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸW��������������������������������������eĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸs��������������������������������������‚ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŽ��������������������������������������—ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ ��������������������������������������Ŧĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ·��������������������������������������ÄĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÏ������������������������������������Úĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸå������������������������������������îĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸô������������������������������������%øĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü,������������������������������������5ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸA������������������������������������Oĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ\������������������������������������iĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx������������������������������������‡ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ’������������������������������������šĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĢ������������������������������������Ūĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸž������������������������������������ÉĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÓ���������������������������������� Þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸč����������������������������������ðĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõ!����������������������������������(ųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸý/����������������������������������9ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸE����������������������������������Sĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸa����������������������������������oĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ~����������������������������������‹ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ•����������������������������������ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ§����������������������������������ģĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÁ����������������������������������ĖĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŨ�������������������������������� âĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸë��������������������������������óĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũ#��������������������������������*úĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ2��������������������������������=ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸJ��������������������������������Xĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸf��������������������������������sĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‚��������������������������������ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ—�������������������������������� ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŦ��������������������������������ļĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÅ�������������������������������ÐĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÛ������������������������������åĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸï������������������������������ôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸø%������������������������������,üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ5������������������������������AĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸO������������������������������\ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸj������������������������������yĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‡������������������������������’ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸš������������������������������ĢĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŊ������������������������������žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÉ�����������������������������ÔĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÞ ����������������������������čĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņ����������������������������$ũĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü,����������������������������3ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ:����������������������������FĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸS����������������������������bĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸo����������������������������~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ����������������������������šĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĪ����������������������������Žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸķ����������������������������ÅĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÏ�������������������������ŧĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÆ�����������������������Pôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸų[����������������������� ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ ���������������������� wĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ„ ���������������������� hĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸs ���������������������� Xĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸd ��������������������� NüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸU ����������������������� GũĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúN ������������������������ =ėĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸôF ������������������������ 6āĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸį< ������������������������ 1ÓĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÜ6 ������������������������+ÃĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÍ/������������������������)ŋĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÉ,������������������������%·ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸū)������������������������#€ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‰%������������������������#B’ÛîïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïݘE$������������������������5NkˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‚mP6 ������������������������� ,@Q]dfgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggd^RA- �������������������������� !2@JPSSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSPJ@2" �������������������������� !+38:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:83," �������������������������� "######################################################################################" ���������������������������  ����������������������������������������������������������������������������������ic09�Â��� jP ‡ ���ftypjp2 ����jp2 ���Ojp2h���ihdr�����������colr��������"cdef����������������������jp2cĸOĸQ�2�������������������������������ĸR� ����ĸ\� PXX`XX`XX`XX`XX`ĸd��Kakadu-3.2ĸ� ���Ø�ĸ“Ïūö—zYÝdŅ€†h&’‚ŋōĨ‡æ CFE°9D“þŪ!Á·"“ĻĮøŨ-B^ð͌ōJY9…[τ„ƒdÏãÂĻoiĸŒŊŋŲøĄWÐËÁ=0B�=ËWšä9ŠL6Úœô([okĄęė™3-ņ‹Ōŧøþųņó™ĘõŽ3ŽĄxĻprųVúh(ôÔĶũ–>ņT=i†SÞ]íģw„NÍxîįé úęĒÆ/S‹WĀ“īBĶĻHŊޜJVĄķœCSlįŠ\ņH ðTę^Å%‰YÉį'cē,­ŠÓ+Œv1[Å,―Š`sī'~qŋÖū ÁóW@Ą ĩķŧG<cóÕ|[“ú­Zv]+XĻøFúA~!wĶý§E°šŧQB|‘ �þõuĨƒŠ„9ā˜jŽĄŽ§íÂ7Ļ} #Æã#F(ŨHĸ) ü[u .ø=e‰MŪ€ÏūÔOþŦ…č5å'ęóÚðǁR/)ļĩKŠ Vkįî+ÅjÍ̆e čŧōÍ'Øï΂Đož đĪß2ãĐĄš'ÄR{wĀž›ýŧ§ē‹[šOŅ#0./`üĢČGŌ}üË7:G*w$ÞåaŠüO‰*™Í°ÕäI=Ā:ϧx.æj”Z#”WŌ·ïßA‡jjĄ‘―TI5ï/ŠēŽ‘ømJjZþúR{ęb(ØĮ™’•ëz‡Âiėh1Ī˜ÝŽŽ5šÉí’ĢW]�aØþáæô “œį9Ė~ÏĘÆŸ•w•vžYZoÜę’]‹a›īs Ôîï2p_ĢQ þü3ĮÆ/6^‹3ã=Ūģ”ą ssk9j"ÁôæÏNdˆ q@o F9:j$]rp]‡ŲĒ„ûÎôwtÉ Ã$ÝÏč„BA ˆ žKnóv%7…h ĶąVx€rŌF‡°AĶÏå^*ô:‚NËÅ|öęáŌbŧÜšï —ƒzo B^ĻŊ,T;ІŧÝp-ß cFŒy*ŸvÆį“ZŋŨ‰!ūÉĪplKη-/éÉ`™ó_i‡Ā-ČéĮK*k­BYĢcĩ6‘Šę*ú™đ@ņį“$1Îr҈…ŦNžŋņx`Ū6Ÿ{ƒ)ą1âXL?íY1!·ņĘĄæĄmķ~z­qLųül Ģ.óÎ| RqüM`3ƒŒ“=3ûØøė äíIĪ“'[ĖŠb Or/í9BÛE€jŧ… ”=P[ÝËIŨēóO™ęGtSYcy1B‰ūēĀQ°ÚÞÅ:Ģ4DņØõ@€·#Ģuv_™čßý$d”‰ÖôŽV’qŋHe#ąGĩÆ>s 9^Æp§†ŧ É,•ēė4B6ĀčOŋWõ;ŽoAāãėÃQĮcãŽíĘÍQ"žÐX§‹Š6ØĨ– o+$€4>+Œ‰3!ĸ`6!ýÎZƒšũVōÝAY_ÅÂ,ŪōÓ°6Áē’ÞúĶ–GpēĮđ$øķķW_.cŌÎÛōL'ū^Üžëg–žÚÐ+͝‚ÃÃj›o>ĄĮĶ{0-ÁôÓáöĐAö§�П[ÜŨðZŨWŨ(oŽ.ÝĨČf‘öģ°ïZ˜öŽŽ>}œ ė&îHZ&æ%ÃŒļk a ð݂7•w8‡ ā‡b2QeMī4e Ų`wŠŠ‘IÓRCÂļë…ũKį=Ŧĸ>.Åm=zäLļþ›eŌýŧņóŅ-8gÆ(ņ›ÚčŪ/žßĻ9ˆęŅĖÔņņ4Õâ-xå%ž"ú=öaũ~RDóO'ЉÓ,~~ŧJ J[/í īsCŠW’ÐņÄiØąúö{ýmUq7ĨkÍßŪ r_zöïYûzÓąĢ%z+īątæïâW=T ˆb~ĸ5>Ü€ĮÞÁ‚äjPĒņL‰ŧÏíL—Ŋ$rž•žņ)íãęĢlĨ`;ƒí |ą 2G}žG°]Â\yW7l‰˜-ņsš‹0Āŧ1œ~>œuĘdîZïg–šF$ĻÏŽŽŠĪüú\ģðŦTä–ĒzĐ"á­ĩýÖĖ–æL”ðTē'œŨ(ßHpÔnČŠiæ(~MÝÄÐ|ąĐaQ2| _ Ȗ/Ērԝ$Jڋ 'ęCÁ€Ÿ3[ƒĮœQmæķ8-û4o~’įJ)önûŦTĒŋáQgí4�ĮœõÓDÅLĨq'įčL‡П dNņųįã <tX#] ō)>árģb_žÁ]Ļ?aóŠKëČØÉĮáŅt~ Įįū�zЧ]ßØ_Õîā]ãë°?Ð8[x­kBÍ―ū›%ŧ"KÎvPĸ_Ÿ—ãÃÍ3ââ]Ŋ"f}§ûctäþâÏVĪ\#ņL8Ÿ ĶõÞVÜņC0S‰…Vƒ_.q­L} ;ÍĸÕ=Ïí”s˜3ÛöĶâD€!Lã č€āß�ô@�†ąM’,…Ï}ģwĶ–įŸ!ĩJ#š–ŲÍWä1NĘÜÃlHMÕŨ"CįÞąēÄížæzų X/bLkŅŋ_ ~“imå›ý>pþ}]4.Ý ·rõjEûtauð%:ųŨUę [€­ķÁĻ_‰[ķ/ØFm*ŠMߘÚo>ŽÔ8DëĶH6ïģÁ x%ëTô*_:YŲl€*c؞ējˆ‹vŨãņäú"āĖ< œČÕÓåŠ―"™NeŊĸOœpŌKy9W^X ņÆĨ\Ō SXÔĶ%{ŠĘĐęĖ Ž6c õp—TÝԂd™ëbEݔēö+€šm,ˆû6šþ7jCŸĢzņ ]ÞÄåovačd2507*ŧŅ,‹RŽäi'$ÚPk^‡āČžC /^0Žĩ'‹uˆQ ­ũyņFëdÕ&Eû#ĩ}(čÄcēūĖ=Ō"KRį:ÞöŠÂš€šĢdJzU +îäoSl·Ž@kq[~°ĩÛų,đ‘ŽÍŪ”Ųúū•™`ö%Ä―/Į ‚3ðÔa'“™ķYīöÍčĸSäÁęÂFûý<—å#oÉĻŋ ð ĨŊāé€ÔĢW9jäZ]‚vxÞp:›••LpTššøĀĢ3Gĩ•ŲęØŠÂwĮĘ{ ‹dzŸ!…b œĪ4C:φ―“I Ō藛l,^›ãI'ō>tĀ@ulđĖė―Zë―·Þž5H˜$^ð­ËÆŋ°62·ž'ę<­šÂtYĸPāÉķ–;ƒŧģ>īBD‘ĸ}›ÕSdĪŊ!o}ĐÝíũˆÎÞYó†ZîßÛŌąļ=YũŋŽß—ĄÁģpëĶĄŦ` šĖÃą&XĄ æįūž>QˆĶFŽïþŽŪÕļqÐÖ 9âØė›zâî—u™cc{)‹ÞáóÎm*ᰓųBjXO·!ýŌĩ’ĖŠîHīŲÜ·Ï0Ž—ŊôĻĨœKi|[Zô-Ō_ļŲ++ï7œ$ ŋ3ĘðbˆÁ>%/e ˜˜Õîģđ>>m™’ĘŪīü•ƒœhKiszlĘU·Ķ9a3É5Ŧh °6`mņŊorāč%)zUŧ'!ūā=jx$2b0ÎÏā–ųK~ÓóĪí^švÎÚJ—a˜―T;l$*ŨÛÉ%”ÚîhÍ ã€ ŠNNd�°‡Ā3aŋ<â2‰V˜Ps„ÝuÚQ{ íūÅ6ÃŦÄo`/†ÖLæ?7ÅÍ8ęĪĄėû3#$ĢrÝÆhPž·'bë ƒĐĖpŊL@-…y<<zôŦ|a]ÖðUÔĘųö6›ŧ_‹aũņÓUÖ „5<6Ā^[ŲąĢTÖŌØĄcĪNÓīÕĄÄĒÆĐLKÃFr@ð\Nä ]ɐ; ΚIg*\ī°Ýˆž!,ßþũ—3Ũ‹ųšišÖvÃÖąsó)ššĮāVĻ.5Šrķ*ā•% 0teÄÖ;óEŅóŠ;#›āj—ÛĩGä8S8]ÐÅQƒR-ĘûIŠ1­ánwÛž&l(ŒdašüÉ'8ŽßPôŠF› Ü3Eūœ–ąĶąįîî?fþũF§”1åӏkFb,öw Õ(ÓÖ Ø1ð}ЌĸČÎÜâF=+‡]ŨeĻĪ<WÛžÅĀ“ĮąW”ÃĻ“r&*JŪ&―,HH, ŪØÅ!„ЀxĨ7”:ÖīieŦžNQ˜áF`üļËŨĮþÎ~ā|5Q�•ĩãij!ÚׁķöÄþ*Þęo$Œ;.­Ýų1áĩĪD‚Õōė o:ðø‡Øą|†B›MųÃK#ï3ÞŪíÏĖ8ÕóįfcĐ]—”ƒ0_ašUž^QâI‰FsŸ!ā )š2ŸX3ßŨwšwC/ŦŸ–ļŽÚģ―ŌĄüąWOOGZÃėĩáö\P}4ãv3ĨĀâ•uņ‰IžĮ "ģ™4K’›Ī2§O?+Q˜î™EAķė\ũ,ˆ~.ÆFޝ­Ŋãïę<Œāü^Ž1ŸŠĖ“ō^Ķā8ÂH°ōDú&æaŪ\6Jëjģ­"Á‰=Kþu•Į@͌pÉUNTøŦïØÂSÚŧ·|ũŊEmoŊĩg&~ķrY$x ąīÞę(ā@Åqa,Ð{M+MOüĶ>_X�ÖýģwčC*‰!ÛEkņțÁ-æÁø>‰)ĄÕ!Û2TÁSĸoyÄ ĖĐwãmû~€'īBĪ\‡Ũq^cš­{ąHjÝXä6OÜyųWŒk.Â.áOsAX{InÉ@cGÕM*väīœÍŧĀqĄqqIÍŠ`/œR:4Ķ-�ã]ę,ÓÁĖâáa`NÐyš+*D!Ú­‚øĻø) Áw-~t`Óaņē“v7ū`uT~ôPqäWÛeäÛöäIÃĩų+u`~Ž‚ņ&ŒæH0fA‘b^G·ķŌū―ÖvđÂxxLŒ€)ķë&ļđũŅ|gN1ĀpÝOģ-OhģąĮŨĢМ–ayč} /\ë!V?ã˜ČdĒ2F_$)ØŠÁaĪI—Āf‘•Q•ÕĘĖΊHĩ@øZ;ÓK}“É&dĐЏmŽ|B[þ·(ī óŽ―ë™gö‡ÉÓI€ĮßSĮáWAö>€Ju(8/*vq)‹3’\JJģ.ÎÚģkŋø§―V&<ģžÛë˜ysÐũÚî‹öœq†•|PO‰7ßC@Ï<ē"ĸĪj“røk™ðö§(bdČŧ@ W—éĐjüցjlũí‘a:—2p‡ÄkĻCÎ3Ũb;Ū“ÃCaÚÐjTĒāé”Ā'Xīĩ<äïéH*'ąJÅļ#šdįE<’]ŊĄšSÛx_9XöšĮ:·ŽŲÔü”‹ÓČWß0���úxčКÓrĸoÄ^þ…æīŽ \ų:‰%/tƒ*ų|?7}s’ŠŋEÖےI$’?^ĮŨ…*öøÅ=yŠZĄÛˆéþnúþÂ5ý8JąsGĩį` đ$’I#c–nķÝӘ,ew’ėč€qkÐĄ‡8ęƒŸ­C*4­ČÐeë x9-Q…†Ü’I$’ÚÁ”Đ—ąįæĩžļĨ֋eóW>G˜‡RT­āõ”š@{iKŠ^F Äģd�›F/Šʰ‘æh2�Ė{$ðvš$Ā<ąPkŽ‚€K‡/DŦē"Nė―šsJâė áĖ5ƒC2ŠØN~ĩƒF™ŨÔļÍ<ĶPŅ §‚Ķ€<)}§ĘĮáė-‡­Ž>ĸ&ļ•-QŊzÅēHÐäČ .ĩļÃíĶ'JP팘īŊJ<ė7ĢŌéȄ79+…Í{}Z<TG:>ČÛS‚sėW›$ŠþNĘð gpŲ”ÍōŒ#cļgÃč°ëqzžųĐdøló{…ŌīzŅýļEÞEhŐB •P°lNV™Ø0ƒdZqŠ Įļ#}ĻŦËŠ9‹éîДýƒB3ũe‡)šÚkmpÐÖøƒ3Û^8$ā UŅaoÓAæāļĮĀa3ΞåšâāýrėĪûÐ,k…>mß<úƒú`äŊ5Ōíģ ”jÏĄĢ{DGUŪå:Äû.{N—Tþ2 õđī8€Šˆ!, ōÚ*Ši·Ā FeĪÄKílÜ7Ī(”ŸÞÎ͜ūÜÜ}#·Á†ÚĄrįŲãó‹"Â―īéØ[‘8-–+ØGŲ‚r?ĘkđÉ.^Ŧœ( ķUgĒPáÓÕL8ë~a•+b+SíáóÞ0·Ķž,7g•d‚P§į―•œŲšœ%·Iþ4Ž-™Đ,°9ϔüô‚,ú’sÂV‚ûJÛ2―Dąķ9ũŌ͖“æ(įgÏ&Fu―Ų†'hŧņ)jvß§ŲƋģgĘŲKƒ‘(|cō%ņ|ݓú>ÛBF_@RĪÆ‚HÖ(éįPËÓOnW,­?"õ[ĒïĖ·’}Vęũķ Â.%“^t ›šX“53 ŧ”ŪÝ­^\Į“žõGķ1þŋÁül%u_›eęųMÎ)Þ8Īœđ˜°īĐXH‚ē{ĢŌËb Č}ĩPā!-F#ۘâüŽdč^N'Ąží�ëĪJĻtkĪ(óØ#ĮhqÅeæL@;ĐĮd=Â)°~Îôw§Pę.ĘÛIū―FõžZņäčŸChĢ:\ĮbÃ{ųûĶĸaĻ_Į’Åß!ĖÚIąĶüÁúæ’ÜŽõ·ū‡ î,G3‹Þ=HM~8oĄņ`Ôi:!GG,õÙäĩQģGU!ÜįĒæ›–m Zå†ú*Ē_*.õž Į:šz*ĢOJ$ū“6Įę=tČNjŲ>+”ĀÛïϐDPڐðÂĨ‚ð<†Z5�GÝØÝ%ɃÕļ$m1ŲĪ3riŠĒâi;8-@”:æũm‘–'—ĩð‹ãUa?úûÎïIĨöJP…!Ĩr|@lõït֏íҘ1đfÛŲi\@ úĄý:ģ9%æ4 –ęĀÝu$‡ í„š6Šuęéĩy-Vø$ĸ ðŠaĖv[")eI‡…íóųYtqĶ>ß+FiøĢ,ÃHƒ”…Š+Yų°aÃĮ?&LbTWŸôZ‚ð~ÓP§>îíž>•t؃-ĢmÏjUđ€#Ól}Į“þCï˜LÐ%i5–ĶĩL6ŪläkŊÅøö|s=Z(bQį…Elâø―œ ķÕáÕNølݖpþwĩNä/訓ë=ēEÎSXIš."ĩŲX“NŅßyŸĸsĻ•ûxĶč2ÔŲA‚qĸPžýĨXœ­õî3œQýõKh'HY“W§ pv’ ČūÞ\ĩ0[™‚ÜÝjŸ,‘õ0æsĩ ąC˜ÃÕ3>V…õ Ö霜œp&eš‡M!dH[Ū;p"Ï WöÃۅą4ōiþ"Vt$rwïŲy*AáQ§{pvöĶ%oGŌ›ŧg=%_ķ‚ĢapžåRĪdĸu>·Z…û]ŽĀ[ é*#lĩO4ąú=W ëí;sÕ|Rŋn�ü§Þõ}›˜œ#ļŪkēï“tôKýÝĻÚĨĖQûÜOōbԌ^Nh† cķ(‹CĒUgáÖ E”vMf―,VÄBÍ)ōäÁ…īĻLhŋ‰3YŽŠ ŸM(.Ֆ`avéĩ/Á܏ރĒÃģH„žęÐĸpÓúЌnŠjÍ™…ąŸÏĘÃōØãSGX~ņâõJÆ3Oüĸ5ܝhâļ‘Ģ•āŪæŸÞ1ĩš°cJa yxÕZ'ŠC/ÅÛŨóĖA™lļĩA“õgöĀ‘Vōēī7ņ%―ÐHÐiû_SĖĒ_ŸXųÂ:ŠŽ‘t°Äĸ#Ā\܀ÐŨŨ&z•īTŒËÞŲbŠíŌ{YŅŊéĢAZGāy ī2þmĸWN—kQŊäŲûæ-Ęøiˊ…pīõnŠĒĀ (þ›Âš“|ƘrՒfDoŸ[ÁŲ·ßTcÕÛÍ7>'aú ,õk“°PŧŲ0áŒH;\þg,ŋ5zæn|,WÄÎĐûŋÞfÂJåĶ@Aãõžß@4 Ėž|Ž\MuŠAŪwĢŧäWfĨVWl/ug§JÞåÃMyóņ^ƒ”Æ 7,ŧr‚þÁYÆ·5ĻgŸūƒ 7t'™‡įĮA\S.|š#Ŋų TJøķ˜î[ÓTūž 1-?óÜ˜ß Ÿ›g'ŋeĒýĨÏFđŽŽõˆÖ0‚CŋPŒHˆ™ÖQfuð -äĩ ų/Ž™ ūmÏĄČņ#�1äí―í`ŨÜ\ÅÛTeÜ]Ve ŊÁlā‡ïgõšāēņNs@r)Öv|#Ėcķ.Ã1á‹J”*FT˜ôĻD[Ģðų}õãûÓ9ēŽÂYÏÆT<xü˜ū_~…Š·‚"‚š@ŌŽÂf:ā…œÂáë]ü)BŅNoý?.wģ‰*> ĄxÁˆĮ'Ęm‰,/XöĪ%ӕ”øÔ%]ûÐð6)=ŋúÞäÅgz ï{īÔĘâÚėéâßYc™V•ɏíÞ„T@ƒ3aĨwwī|2Ï] ĘĀėãŽēúýîīoEÄōG'0>â Į þs}NHUúŸV‚Î_zŲ�QðŌī^Ïą spp bŒ‘(7óaÃ87 @æÃt~|Æv`ČÕEsxį̜ÜNQ{Øž„č™ĸ€ČëŅ\(íķÓ8ØîŒ ŅĮĮi֚Ö;ŧāNīBz­ÔXHĪęZœŊ ŋa Ý‡ŽzLVíįÅQ)†ģ�PôŨÝXaä(hc% 2…ÁëęÖÚ‡ 4‰—3Wđ.Z(>ÞC,úE)C}Î@ýk!ĪrvŦßhqnnX‚”<03#ąČ—BYšü1š–íúŒÞŽų;Ō2’Ýf―8ęŪŦsïLúØs 7+ž° iûŨĘCM’UŲrĄpÓVŦŠÃ9M΅ōøgóœuXĨiĨÉŌDšŊÝĀĄ2{]Žâ\žDŪÂ{ĢŦÄM1EQbdĻąīŽãJFŪ4gĮĀEŦï4’Ä”K\ą,zÕ-ņ[$v ‚·}S‹*•šeÛU:@TŽÄđ‹{čįšĮ## KôŦAÎ`”i\raå–ŋV†Č:óyZkũ˜1ßPÆ_ũS–BŒ―>FW—æ 7ËJcQ%ė75įTŪîJÚØđYĨã‚& ŽYqŨ6„ÃVFßýÜz(ófσ!ųКŦd­ēŲûðÓDhÎdŸÚÐgSŲãŋ”œ"pŊ"åmaŽŊ!ËT$‡"‚rķíBk…ÂóÄø](ē{Šö}Ąt*"”ąīlp>ę3"ŊļĻT…L`ŋu-$R6øŧė\Ó-nxP^OČq5ïv‚Þāīy $B°$ų hø‘(˜DÔnûIT€‚&ę#‰…ęÓœM^žÞz+f‰aßļAwt3ŠÆ$Üõļĸ,cP—īR§Öõð:Ÿ(iĮ’‡zCÉ#ŨlĘDÖ[SC‰ß /^fžjÛZĪÃwĘ{áMJdsÎOëJÅ6ūŸÓ.tÚūîæ"kCoģKIÞ`ĖzŪÐpڐ[Üķ„qðwëR–ī‘ĄŨįƒJĄïöã„ō�†šýmĖ;GgL/ģ-Č(J.xĘĀvĶūXlNĸ-ųl&beŸTLŦ.īĶŋĐųÚ1˜@ėâ—r+Œ~=ÝôŌ︘đðYÂŪũGĨM čũð4ß~ošĮ]ý›ŽE:mŦĩĸ;õ3 “DčŒģkāNšDÄ.Í,ž§=í6ėŊēþY ĀcpxĖû^=ŒčŪÖõĶāRĪĀĻ›ģ>Åk/Ą˜'hęy!KŦ°.ļ 'ôÔ vëũe“öÜŸ—r1,g)Þ)ðr‹lÏå'ļŒ'GSŊāĀĶDÂKބoG?힟ĢēQĐSJjĨÅ;Ob8XâöˆĶ―ôæ0ÉøŠĮˆ·á€žēO‘øiÛlĩsŧjĨÍøĀA}Ë(  €xÄā4A*HÕ ĻėqøōN2Äč™<ð“üä+ëķ}ėäųsó%ĖŒãÚęÜ=ŋíŦ˜^9~ą<E5Į Ý@éo82ĻĒ-Ę`Pļۆü\2IōĖŪüt‚ęš=á#ýšČáŧ*:―ģZ[öþú ĒĨt‡NÉZ�"ʙķOÎq1UĒá^‰ õŧfę_Ór&"%ē~ū•Ī)‹Ä ‰ŋÃðþģR6~?M ïŅc0mïzĖĖÓĄ‚|NhGؐ(?D#ĨYg‡hŪ·P ŠZLüzŌĀÁ‹qÝðŲŲ ä|‚ĢóÎö™Ū^ qŠ2 ĢĒé GōšŌĖÖG ĩB9ėŋаm@O†DĩŪBļ2Ī‚)síÏŊ?'lóž$ðÖ"čŊî<\‰+Ļ,ČĄeØ'†š­ąÕEĄķī”Ų ūír3ĩó˜9ÉG éGnZŊ€5™>ËĮs‡ãÎ/5„?ūŽ bï)áĨÔ˞āƒŧÆáąĸ,UēöÖ§ųĐö‘(nxčá4ž`wt~ĒôîËÁQL64Ū§ĩœēĘûy'NĐX'°gō=Š•ÓÞĢÝėÔi”vģĻr‹™o8ÄÅÎ=Ôŧâ]ÆÜMPīó›ŒHOvėđ@_đ>�JX]§ áŲVfĻ�–cŧðsDĀLðyÏ|úĨ„–TÍo5ðn8<Xö&:ŊÕS>—‚Ã_äĀUaŧËįgņœw:Þ―œƒ Ņ0؀،—],-ŋÞ>€§ŦmŌ,PiýR0ŪFÁЇå͕z―fŨkuô ææĖ•ę§Ąō‹VäŧŨ{úĘWޚ?-hšÉŽŪfžõŨ—ģ˜ęwÔρ2$oQ•#ϔú<KmSČĖ/E… ĖÐL§â°ĢpD9]N…ïYρU3Pø@.æeŧCé8ž`ŋáNáUO6‰ā•ûž_Ÿ?Ķ2iæŋ[0ésYHnĪõŠrĄúŸJüWŠ”ˆ~Ð: ™O Ęã[|SŌH;RF Sâå%͌aۋų,VĢĩũzáIŒ&ÝRŅÃ%Z‡†Ų•Ž&ĐhîšŅ†/Âzž“ØðŅ*†Ŧ]ečœAČeĸQpŽŠrĪ#ĸx[ÎLý•…Ë%ln ·ÉĄž?ÎĒö^=K­ŧOđ3ā|Aī—&cĄÉþ?2 &Ÿ"cPœ›f?ÅzīŦĸ�ý'Y’I@ÓĪŧ{ĀkĢ>ģ•œĻ’š€zĖVrcėPģP‚Ŋ…‹ßĖ:{ÚĜĘŲ1Ņ,‚âðzW] )ËsžKw†ųNĨŋ6ȌŨĢ*^NÓ`bėdݘ›DÄėÎĀÆ‹ŌŅhåüŠÔĒÆéÎÖg–? "š•ÎJ`­cý ­ COäXėôģ™ÃéŅąöUøÅ�ø:îãúîĒYšÃSžFūô†bI`(BōcmšY5zŧøÔdKĖlܒžWÏ‚õNZ›Rō(›8HØØÖýõvw`Ú―GŽĸ)6Ų)BEÂÃ�ĨĘō#ïŊ·iÖã7õz{ëûŽdl%ŋKĒýđx;z(Úzî1lô,ĸmž‘ęHš„M0ø=íĖpęä$…‹Bė1Ķ―ŸĐŸĨƒ­ÃČõėĪEũĢ6Yy Ā/)‘ŧûm…Čéx"ĸ#_įދĒ`GŪ,ĮÁ˜―H{u”;“€Iîņhí†x§đąÂŊ�Üæ:5•ĐŲ·~âīmÝįåð>ĀyĻK .íOiUĪīýPŊvŽÜnDm<D:Óޙe |íáĢØ€qo…+Ŋý ũĩÐn{æ:čÛŅŪø=ĢæBķ,Ēĩâ€ĮßĶŅũé,>ĘP‚ąĻéoũ™ÞBÎ݃BįPßnHAK1:eŽŲ6xE iŪķĐ֖[[@ l?ģĸƒ 3Ðũ 5Ւ­`˜æ:đRä'ÔQįŒP~ɕ›T‘ĮiŠŽs#ZAôU ãý †Mū9ÄM#ø‡TâΧwļEđ;oúÐ*<=Úõ˜Ē6QEžXnl_Í2cýï…ƒ“å Ÿ>$īƒéc]ž�ģđšð^Į)ŋ 1ĸov,>ZÍĐ|ĩĒĨėóh7æŋ:įšáևԅljü‘Ģ@&™/YČ.ž,þß"ŧĖųž ‡Ą‚ĩ|§'K>åï+.wfsI�ú?ŌVđi9ocš˜Ĩ`ėgėCš―ģúģOÉdā‡đčą_œ\ËdŌØ‘–~AÝæšÐ5‰―Q+IÃy œŒUįaå /œ‘LũÁzš $J"ŪÎ~đĄ˜Ēv{ i5 é}ío)r?ŌÃpfōčÅ6T0Ô[īÚ|pkJ˜üÍņtï-ģ5)—č4OâĐP|€—YAĘGNÝņ ž ô3đԇ ïÏM >rŦĐ&Ĩ2{þ óðéÎĀęm—ŠÐ1mģûNPcÏŌЏĸLļÕ�Vi^ =[v?Ēðóˆ°+_… ûˆ?ļpH˜Fe[›†Ī7ÕbķHŪēÓ|ŽšŌĘ~Z\Ĩ°Pyžâ(âĘG-”Ÿå‹hŒÞŸéĮ`zÄąWĐcZÂŦé›BI_Õ Âĸtē'nŊãe"ėķ;8ÐđÝŊDKôt/0 ĻŸÐÅڗ<2Ø/pßB&oÝđˆõBžĘæFeĖR…ąÃAø…ŸˆÚV4Ō6ūφœŧD^’ÁuŪâ ŌLëÝMėÛÜíĩ;ûéĘ 4ðm-§fįTx„‹XĶ%õšÎޔ=ó€ĐC|2âd4dąŲČânēŋ-ÔSgþxę1ÂÓ…Ü'Ë5ĨiĖ’Ęõ!‹ąZ‘eÄŽÂLÄãũö;}}~þâ Ö_sííųú ?D ?VĪþŦįõiëØpČ ĀŧĩýĪØŽIƒw[#g^?‰ï ņî Ŧđ Ī-‡eÅI%&t H“$RKR_!gĖĒ’9Þᨭb]X?„Vë^í<žÃ+6Ú^eŧMŨôkđũ–ÓĐBQđԖ‹Ä BZōļ ^péjIãËôbjŠŊ'tbúÉø(‰ã*Ũŧ·āR.äŧ#čBœŦ^Ųn›aí…ö†)‹ ― Ð3ĄDįŊÚAƒáÓÐEīHŌã3Ŧ}‹đÂcíøáöÝCƒį^ n;”VBBå‚BÁ ”ybFēīÆ.öāāįûķķ?øÎû�ĮÜļ_,˜uÍĀi,ĒĻ­GĩÔŨĀDą\Ÿ`p#�y;hÅ/aȚ˜$ž}r#ĄÐRösąúl”4ÍMbIzĄfÅ{ĩ‡ûŊîÍĨMîI8XÂgbO'Ũ’Í+hŪÍït*Ãâ+Yf?á<WÎV šĨ�ksÜ ŨÍhār•œÕ wSĸ6Įy‘ÜũM%ĐzÞ‡äüīWĐJŒßöU2^<jœŨJm­1Ðũ’Ĩ­ëï 5č‹âIĮIß]”ýÔïüEä_‚gĮîáI‰h|ëîÐbaėũúķ";ģĶÐ Ų;|É>.H’žÆhwŽðī›ū%”&#“ŸgvkĻ7Í äŲ‘—Ū\íÛÔIžhÎįqĶ™HõóŽH7j ûŽ–Åm“ĢŽ`MĨK*ÅAčÏf[)+RؘõmÍKhģo,2FėU˜AĀJ5ŋãŀÅLÎ―‡Ģ>ČĘ~U<ōšŧ9QĒeŪž7ûUA}gaBôąĪ+đmlíeӑq9óĒĩĩ ĖwŽgžEBŲĒÄ"ģ`ī82>%ąTū Â'š$ŒŽ™Ø:YˑËŨšÓĮ-ŽŲ-R2:―bŌųubLŌR,-MJFmĀA?'Æđ=;ģ€gŠååąĪq0Ú Ŧû ðŨ—‘œS‰ŸOņ=ZƒŠŊ1ā>/rC™1‡LÛڍ巭–­\y•G*Š"ŪÝZ3õĒzj=Éf9t`d }‰ø֋}ėp’Ž­ ĨŊK2zǁ Ž„ĸXõ‘tž0ЙĘwfÔ =ā‡DķŊ0ŊðĒCvčiēÕE–@ÂÝđiÎ`û…úĢķ Ģę5ŽÂ< GūĀqë‹āuxž)‹ ŠTEXâKfþĐvÄøyŋ0û―Ŧa‰V4ną…b\?nŽ^Û=hiœĮÜpï )pĀÐŊTа7(û<bÆ>N°qrU*rĸŠcÛÉĘy ?ēÜ.ßÍ —Ģ‚%úŪšX4RZIŨč!đû· Ü>fŚ“ósGZáĻ{bHHkEŽÓG36|8!ƒóÐ _XiĶË@ėó†đ6LˆāŲØ:a2ØðýJ fäôMl€Ѕ“đÝԂŧ?=+ŊoÔSx dŅënlRäŅĘQÓĖúø‰Ũæ”3ŨDĨÐ Įý;'TųãÎdr.b%ãsė†Pæ00;§ĸKHô§Œ pīDZeß/’a3~"ē›v8ŽãÃ_û‹V…Ïr xĘ+vŲĩžNî\į,öó\9ĪĻâĶADdߨï·zÃĢč?“ĸ(čKÅÅ&Ģne‹õ$ųšf5$ëāOŽ —‚.’”đ傄šēÞ\8ąýŒX Ä�xŨ#ũ§ PnBd1Ņņ=‡L’§uÏ ôÆĩõOäg5íRg;蒄x@]þHĸ>:?ŅŅýčMáāT 0ö<ģýËŪ‰*júž,"Ëó^bĻņĄō“/GjfÁčŽy\šŒĒŨCŽŲAŅYˆw/4CĮ5ÞĮŦ=ũ<’0KzÕįäđ[ĸKXæ%ūg°ˍÉ·ÄzųaŠĮ>cČLó+Ÿpk”Ģ=ÓQ+БÉáôö3fß/°3F/Îá0˟z6éĘ]ßVŧö–öX‰b ój^Ôi'”žĀPÏÁ“ëĩ§Å įÜ­øīŊá =ũzŊ@ˆïėNĮâōČā§l0ž’…œ�*2r{L–Ü ÖôÎŅ‹ ›w3ü=GŦčĘÏå Zå3zÍ͚ *!;…“ €ģ ßšó&Đü֓ÃēžzTņz·š iüäūYČķ‚]/݃viGÏB9Ũ9~CĪ\[sZJË1?R―\˜üÕý߉4lōãÜÂāœÚļ#æ‡@ũÕ|w†ķAËBŽØ‹�ĩðčC6aU‚ˆ(ŀDV8mz8eþã1kQFÄtŒ{8BwÚj• 'âāMĀœaÆŨ]ņB,ņčC‹VOßtŸŌdŠCčbđhâį? “„0,œIAPēÛ†4Å[ï뭆•T•Ā6žņÚįŌÃcýČŦÁŌ―nŠË‘ŲĢå0ÚúâØáģðÂģn@7™Ĩûóâũ3XčūÕdõ…ãÄ˃„mžÛœ…Ķ6~ėģĻĩÅķlÏOÆïĩ―‘KiÂĨ3wzUõÔĻm(ä’åúÛIļ‘đ+ųĩAĸ5–@]đâ§lóĢ?fëĢđā(Ôŋ]ĢÖØ(ķåSŋ<‚8hýJVī°īUJį}3�;'ÎkÄYeĒ@öķfĄ†LĖËØŠbUâ‚óISÍmßŦýÁvä“ĢŠ;ššĸ.Č(Ū­û€ úX�R{†OdtXãó]v>á݅ÝÔVØĩļĶīzžŠÜü  Bœ/ )5`^ȑ$?ĩĘO(”Đ.âj=eöݘðåBŦ:)'ôĄĩr•P}ÂŊŠ--ŧŸ2”Āö“îeĢš ÅZ2"ČäĪ~Ļ8Sm–rþðĶÁ"âSCQšˆ―…i:–”åg™…đƒgIRŌë0šTYōÁói Ž„ĪęÁbžrĄ]Út;;LÃ<ØÄÐyÉÏŅí*„ûlž›kļxÂ[ްy”#}„öOŋđ �Ú‚•F?EŸ"ŲĐZ‘4YLĨЇc SēZĸ?―Ŧa:˜d92Xč.M7w` Ä †ķ`…ČZ62Œ’îÓsŌŌ뚂–0gyy2Äøä đĻ6ïŨ€3ëïč&Ë·!E MWđSĖ sšNûrĘĨ§•nåÞïü†ō OAČKņŠÎtI:l'ôÎþ(JŧũŽŠ„9Ú:X·ÍÏŋč™ ˆ]f!Qd$Z—‰ŠmT―õģčķuĨOÓ@ÔŊˆi0Ōæs3ÞüU'|2^méÝÉÖú%čgHŲÃÐxŋv"óI™ĩš9%Ē.Jüxž’4GÅũQüÔg.káB>þH!–qÝCuūӊ�ÆÖYįIہ?âŽŋ’`ū&ÍøÜ…ÎX KC”ÄëW/ÖMk€ĘW?Ųu}�:Vœ}Z{P”ėõQėŧܚ}ĪdYJE^ÆðEu‰īšPõ d:ũ sjĒ­? æĮÂwō!—j—S‘éÉ;·qŧ‰ķÆĶRi{ūÏĪęyĄÅó&·šõōW a vMl2 ĢĸĄkJý›ŌJ(ÅÃ> ÕššÞ~Áš {ĮõĖ_>Ļ RļÄw›+U–ž1ęIĀiE•5 {ķį6Ÿ 1É`!§‡FÝÚU Ų.ĢYÉĮĖüŸ<'ŪŦ―ŋš:ŅU>7ü™š=>6€é­ž@U]Swų ÎGÖ7öŌ“[ĸ[ĄþāØSŽ&oÎÛõ‹-ŠĶfe ʆŪ|ĮVŪä”ŨPSAüōÇZ—þ™ŧÁū-X$ Ž �­CØa•Ԝ"{þ8 úËŨYĶökŪ­å ͆Éˉƒæýí4HĐÕgP.6―ßKó]‡·v%čknÁ‚Æó ģrËÛ{,Ōc m‰ēã?īŠų.“‚@üšón1á‡;Ÿq ó7ŅedÜæPúÕŲĪėIFųĩ-ĐS—LYnÆ9ˆIZĪhŽ7~üĩ =ý9ĒĨ˜å4q ģģ4*=ƒ*uC-š}^šģcĮ*ļiĨē}†ŲBŒ ŠĘĻļŒ1ĻyâŽÅļ„k܇þęËņY-îŊĪōgĸfnY/ YÜUó}ïˆÝx€%ũ ÜØą6čđø#Ygó›vS-73ēŨSÝpģŨ_ģĻݓ->Ä/–!Ī Wƒģ'ë"|K]ŨįŠ+€Q{ŲÓŧƒ—ýöáIÅm ·á5 ž?%ėbūjaäj_ŒhЭ)–~Á"õdõjØ-Ú{КæÂŠ.€”š $P6ðēÕ^ö„_:yŒëūĖS=wyĻŊĮĢšM§‹v󒚄 éWTØ;ßFéSaÁÕđ7MÂX%Č‚æŧĖFciœĖʘĒeŪ‘ipŲ&ÔáۈŠ.@ķõû—ė`™|KqČŋņ”ãW\V=ķÚI]â ÆIYŨüŒ]{<bĒ(Ä%”îĒH·KL݃7ӆĢíhĮ0‘šóĩԂö,īąs― ~vcŠaÏĪVHU’ėÜŦüļRg,ÃbĢ&Á|óļw’þ î›Ï�ī“™ö_픡njØöĶkQįTlķēIÃ<’b@ē.jö;‚čƒ˜?ÉÓzļ›c„'Ęá9+úJˆēÄõĸq ADøkŲeÝĸ)IįTFðŽĐiãŨ…ĸ>Ÿ2ÏlĄÜqŽŽŽ ĻÜyâĒ“áþfę”Wks’^ŒĘŌŋüŨðĮm‹ ųļßéK€\�_―s8IK)ÍĖį{&*ų'�Až@ÜAŠëQŧī9NƒtUÃôEF$Y ūā\‚Í€FŌĮAäÔúaũÜų(hŽ8c;“—O†ĩ3 aåđuË|ČCÄF}ŪŽ)ę=Sm�ÁâN!ã·—™ÖŸ4­ŽüO”Z á§&4CR1D3u‚c}åEcĻŋâ>Ŋ2õ~ķ�œ;Lę[0fÞįí!oÐY\gĪkšešVûĻ—ŅĒwn°čŠfūę’äžĩ’ķčE[čŦf0 "§ķ ązĮŌÛŋ4,™\ČkžÁÚ@3$ÂAĩÀ[—‘Ð)Þ/HķV\Vô@Ęã=CÉ&ÜRĄĖëD1ó8ˆ›ÍŸßíŦcŽH+Qh…° AŅû^+ØļŽŦÉó€<KĢ 9IîvWũ+SŽ~ÐÆójųš+ZA€ŨÄ<uÆbōݟ{üæ þÛķĀÕmŒē§ŪĄ˜‘ý{}‘ÏŪŧ.„ˆPûēv’_€…2$=1ō󹇡ÐIú­ÏPčĮūĢT‚j%eęšā�ˆŸ@ VÆ^ąR ōé"y ŨVZTā$ą5aÉ2fdą°"°ßį 7þXđ-ūS#ķrūFiģę$qm*ØĸĨp,Šé§ÅĀYŠ™þMz 'ÚØĒ>üSB }”ô!Õ ę(zl‡p%ŒOė:JĪXŌÐņu˜gŦiũˆāš Ýf-t6΍ÛXô‹!‘FīŒ‰|Ï+Ā}Šþíž+cxGî+!Ā+ũ―ƚûBv(ÜÓ6·_ÃĢ™X‡G' MĻÎmNũųá&ÍBđ0úw=ÏŲ!d‹ÏĶŋ3v’Đ<žũœuūƒdũÚHu˜‰?ĸoœÝú“�8Yý$Ĩib˜ŊŽXĒlā,đ2)ÆŊR°þÉ-åîS­TëŋŽ ã=sŧũėęY›Ū›T?į ˛mJŽ ČŦ6QJŒ#E3†]f eþÏÝđ]2ž'ë„ÓbÃá!k,iÂ}Fëe"Ŧ-ž?PÎîÂlö\§wÃ!PÝI3TėU ÓâŨč'PmäΆö`|:�˜]§ĘÉ= ųbPģāV•č؛ Ĩbý@įBņīvŪC™ë;’Ņy`ŨéĮüݐōۃÍ$Ķ–Ģ‘ĖÁÜSvôW‚(EÄ4ýJŋ2°ŪÍgœĐ| =šlÜcTînņÓúȌ~ÝĻÎûtĨ„žd™ -û2ąsōNŲÖ`‡ WPÏüîē� ę+ ‘ŠwÃG™ LšŠwîį6žãhŪÖ:$ĨDō"jĪ,Ę__kžr}~+ē%ÎuŸõČŌōąA`ŸÞ•h)`%$vÂ.ÝgýF*fāų"ī Oéâ1!FÜÄkÅ1ĶwGg4ûv'ïn3ÕîËČAüŒS§ƒ? L‹ @ÃF„ĸ[ö'ÔiQ‘ąQ:Ų—þđ Pč?ĸĸ{ÅĄ+xåųóō/,Y7s(Œ q‰ú E.;ÔÛ[3Ŧj æcāŒŊ ã6]ŦVŌ0“ļŽ/ŌĶŽ ŠnäĖĒĶ[Ąīc0?―6đƒ–bjąŋ™ĮôHÂē”đ™ģÉßͰ-ŊKžÐį,W āÅPkŨMÂ7ĶÐû™&=ĮāœW<EÎZû)/P5<hÕɀ€ī<m6ë< Į üĻ9}DŪžM~ÆÁđ‚Gë?ŨY|“{Œđãã–ģÍáDvᜠóˆÏŲÉ+é°Þ—ō,A%pOЃIÃx(ÜÞ<OY{}iNÓ*ĸXWüÛęŽK9ŲĐ ķī†5ž!>8:6TÐëJ=čŽ'åĩ”’ðŲįG*ņų â•ëÃÏŊ3ŽžßqQÚ*Žr?V€dƒM譅�ũ…QĢÉE=|eÍ`'ϑwŋÖ=ŌPō|D @4ąåUÍœæ3C1Ü}><š*įIų‹Ą‡ĩėĊčôFŪgũ75)(ōœ 5‚)ÛHa9 5Ã)ô=ė_e3ûuÎ9­:.롎f‹rq67ˆŦ<<mBð&ŠRļÔdnĖaÎēDU§ų|yģBi­čӊ9J9"ĸ]z§gí°Ïаĸ^ÕŨŋƔ―5v9Ē _ð"zzcŸ9$ÏąŠ ųs ģwø+čņō2ģóŪ>ž\O†ņ 1ûņēúžÉ+`ā_Ū°3fž #}\—БÔÝęĩpīyĻšu(=_/ũØqåúý mÚ§Âø^ >lŪ‚'<_cVŌČÁBJ‘-~ÃY†dÝ[ķs·,Ä֝WVč°yÛÍōvÁk“5ÓéÄ;úkĶ=oúôÅäęHÝ<ĸoö­8Ÿ"'‚Dc`,6ÏýĪTÏäZ1ūĪ :ÛUx‰fŪžQ˜ ÛýĪqwEūŪŪnļgQ9ðbl!’ <š„aFc(5<]k„ęoå)—žĐjˆÍn;.ɔî-―ûNƚLķO̘ž]íßb›ē؛^XŊP§+Nó-^õBÓDYÎĀgYŋŧÚýŪýÐ4PÕUÆžyė^_áyÚG6.·Nå„cŸÖū(ņd(?Ø&˂č)īR0fëđ=Šx*€Ļ‹ckéžÏįŒūãqžŽ…XMīM™›^?é“Ģ4σLßŊŠîÞ)åŦ1~€Ķsk_ë ĢbĮĸ\°ĩ(Wðˆß „îÁėM)EE[)yö„Ņk |")·ËZ•|ô? īųCÔ"/G'’€%―ބZNĮļ7â#zöîL$"  ;ð~ŌâCŠþ  úV'ˆWV9åĢ·ÓŧŨōÎÄυ2ųPĀnč~W49;%QĸU&DVˆįy&ŧ•w8’AnxjÅÛí­loËþŽ&71HĶ%€Ąųpâ;Zģ,SÜ–āt‡ŪœžäJôʇō†ŽÞ qœŦžĒ+ý{“–kÓО xÄðÞĖuƒ7H u6,‰ŠČY…ƒâŌۏ˜YéĪdŠ+ŨĄ2ŲsymA^”čåŅx'>gŦ_,SŸúæUģĘ\ĘāãˆõšØK‡ž‚>ō’@Ē \šqr*dēŊĀ|YlNaĩ+ŽŪß+‰Ĩúîį„āÓ0čš,Ŧ =§š‰ģ6<zWqƒ·īĘföEķ-ҊĨpÞæąbՃYãâŨh{ėĪtD#ý8ßy*„TÝ;8‚CĮĨïÐ@né—JŠMjJįjßĪÞäēWĩý&-ŋ–ė–(Ž< !úVÖZr쉷†ÞBŠzhÞgwVąĸ}ļdō&[^ČÄ1J3ƒŪÉøĒŽĨ<øü!øbS0nôû‚ąüڂ―ã”CDЖŠōþŽįé>k:}í…ý™")=”NƒP"yiZ=CîUU>Čič}ËtXÞ8•“Tŧæa0ŧā?F†éÎeĻÍÆÄÚÄ{Ūr:ģÞpXĒ8ļíweÐŠ1öœ‚ødŠŊ%ėoÛÚÆŧš•…gŠLŊ›žĪóÃLŠ0ũîYð`oËáå3EЉ}’·âØ$7Æå™dđÁ–IR3=­ĩ*čkuâ*žÕao.3?ņ8ŦW~Ž6íĐ0°|„ĐM͜đZj”ŧōïĖ S]Z) øŒbĶP2ˆ‹Š‹ÆvqģŠš3Ôą0uĮūÆJp- Ö§� ä°Ŋ“Kôíß@(|e‚ķdŸŲ‡īÛïðéÔZhžž"ŪuÛÜųĒÛĀ­(Dq�>?sæģþ7|mtO&FžąžŠeÆČĒïÆwüxFD!jóDPkÍ|ę`[yvS–īî§§þc‡ƒē%DOBuũÂfH{úâFWŦĨŋÂŨ k>)"˜†Ū HfŠƒÞ•nĐ4ЉmVóž^ÞÔúÞē4 ŽÚ}Rö˃Úņ8KIöO%0Ž_Îïî$Wü ĖéP˜}åtÜŋ^m*óš2Ĩv7prF·—b­é›Ô€�6ĒeQ5ĐN)0:—šĶZ!I5Ą2œ+“%UWDČÁeåĖSĀ~Z<j ŦĪæõØN/’Ißo|ÃýĩNä‹ žĸ.BÜÎ6õĻz‘ F*Ķ0ĸÛR°/ÛsËšĀčïCdGãû‡/l6õSQ˜+^œãičXĨŨAx{Ü,@Ņ:ląō"4ĩ˚ 7Đ-,6tÛę7!eÎÚ�†&„!)ÍÁĘđQ"ūÍ,R°`a‘D[š\ó°ŸøŪÃ"F Ë)Čx‚Y€ē!Ō†Æ6ÅŋÄŪ3-•RÐn><l>@/ęä)”H89ęïüŸę߯ĸty0īü’ŠPØSûɋ'ÝÁ\Šnbö\Þ€(šž J3ˆÕ�Z CŒ:ŋöG�+ÞäĐdL(Ģ8ē͇J|Ū"WÉ1úërœWŊĄ‡ŠÝC4І Óõî_‡ņĶ™ĻfŧĖöt=…Ä6―ÛÆ ģL"čaQHp­‹šËŠŽ(>`ļ’ƒš9*GÍúVĄŲĘp…Õ>\žYÝ Ãũl8Īō`j‹–/Å0f`kŠžTþšĘGÐŨ]täīm1Ũļå2DŠ"K/Q'Š…Ã]ĄuôݘÐaËg ĒԗLčï9úķ“y?Q1ÉäÛđÍĮ‡“‰k‹Ļ-Ōe\Ėã€óļveÞÎ;æ þPūÅڝ;˜ĩu…eî8nt�§I($ҁ§6v“ģ^üøÆķÄ<3åMā(p(w]/`ÝF tŨÃŅÜ]# T­Ú-\x�ēķûæ\Ôϕīq=ûNû€øŊQí!ŧĘį ôfųÉRgæeëeZRĀjĻĀw,ÎyëîI86} āGnĒEÅn^Vïw“vôŲ :p@ģ1–p…?Þēą2ÓS2õ˜8@ô\JÉ[M#įoðũrFĒÏ|˜Ø―‚íC(†™.)áß%ĻŠ0Ė@ņ9Š�Šīʁ%Ė ŅÂŅaßĪYī”ïŸBž@Ö~KÉ,øCĐĀR24íĘ 0ÓĖÐ;4āĸ·Šķ1$F†5$Ã[žd„{kõöXNXÄĒî|^öf7ĢŪ{ïŠïÜĘ·#}kВ߉BÚŅõæ>ŪvņOIĨ(åūŧųÕö nJÉ(F|z—r+.ŧt€”ŒÔOâp>øŪģCÅ:[F~ ŠÕuũ*ÎGãÕhuŦ°āŲDĨ%ÂãZ!TÁëây+!œ9‚ŊŠ ėø*X­Ąŋ.>ü01 á=ÁßփK ŒMG˜Tt†ÐöčŦŽýYqþŠ0ĸ+ž XĩëŠ(VĶKë›j’/Ę­Ą îę"bČp5Ūvį%œ~Y‡uę=ĖJ^bE9ĐÛ2 hô4Ɏ‹œōjÓ/›Ë‰!ŠĒsÝÍũīôä ĄĘä3rs~ĢYũ0É―ã§llmmPaŠlÝÂáy5ŧŸ0Ķ!D•ęŒôÖ Sfuoô<‘íM9ČÐDá*iRšīĻåČÉÆö\Þ,^mđ5õ)šãŪWØýļ =5’ŅŒ7Ûæ ĄŽ$ܛG”JWȋvNÁ™tÍ5·ņōĶČI\æÚ:_údx{âÞÅ@ý|~2]J Čë́D1 $wŠĢý+ÚÆï2D:Έo™ ßæ! a;}A õžĸ$ÔÎMA5ĪX˜5ŽĨ{sĘŽ%ĩĨmāN\>ĪČ<?ãĢhā§v ŧ)œĘŒ:€`îĨôäPšļÃÝ1ĪēP)ïđjÔļŽD•-”=ؙōE›5ĖØãáüũānJ>wOWLc}ŋĖĒq…đJšë”A? Āc…öĐLÁæ–ō―QĻ*pý@õÝĮ-“žÂŒg:ÝĀõÝ>ĐQ8ĪCÕKT rúļGlƒ “E@.óęÄĢÝČ&…jŧÜĸƒÞ'u­ÉCYݜÝBPAõÕ ’Me’d€K߯Æũä9AYÏ{æfw3ÂGJMōĄ™ā3ą‘ãĸ €°ÃyPƒ˜3?åIBCcōüK3ãŌËĖÐkŲG-Æ{ję7•T0äq}Þũå‰;cšŨ3ļČ·Ģ” ÖÉĘĒÕķÛBëå]-šnã_E{ÐĢúŊpW§z}Ž;ŋBÍ2IsûœŠü]%6€ÁūŽqgæĘéÁąūïœ`ŋËÜvÞyw’5 }…âåĸ4ÜÝo åĐÖ% 4"#AÆÂą\ŽČ‚øŒdĪŧuļ€Náä§ĩU‘ø·…ĮÔË―øčņŽõŲŊ2ģ9zÝŒ™ū6Ä#ršBØs؉ÃíčÎõIßŧa ĒDĘڐå43ģDÖG‚,-YĄå#74ĀôŽÏrHĩ+ý‹ĩä?ŦÓ.c&Lú\4ä á[ƒrrÚĨh–<Á†GdÃïó‡J]ęEĮ„S+―ģ$‘ZUJށįÔÁ9WæŠ+ģ<(☌ė2§°?pOÖĻ\ĸšÄŧ"aLÁčR…wu4;­Z‡ˆÅCJ 3dýóđ‘F―ĢUĀÛÖ8Į™ú‹n/ë&%ÖF@pˆ�­—Å―ę’!5Ēč/'vïŒxãų`›Đ[“ ԎCǰ=yh3=OĘĩg.•CĘ8Ēĸ$ĮųŨĄÁ―{åoAvv!°ã_ؕFÚTýw|fxWDCFŋ7†Ž6§æ^iz‹zkw =•­ēx†˜Š‹-ŧOčYŦŦŸVlŽ%ô7āÄģFîķÜ.ī4ŪÍĀȅoį]ųŠD? óûÄ~°ĨfĸsõôöNB9ûÕÔx' b ˆęý2'Ė+ĐÛ5UՔ‡S…vÎö―ēþO`ÂÞ\:öNđÁB;%üý>W[íÆĐĩI)WAöOY§3ĄŧoDäâtq€ãö9þĮoØõûą}4/؋}L3į­a|ęQgę,ūu íL°h;}\îSüՕŨÚAōŊÅ gčâeÃĢB ^›q$ʐwކÖĀŦąAã˜6qĪQGG$ŲĶ|‰CƅšÎãt[Ņí&û‘Á-ÅØųŠlï8ũũŸōMoÏīOÝâŧYîŊķũžî’ú*“ß‹ë&á‰Mu , Ís�ý“%ó&xFr­ßY?ÎÖO��`ÞreACåĒxi\ÝŪđh|=V7›‚øņCbž5ÝĒö2`ØlÁîWo="Ōę,ŲC :yQƒ jm^BūT1‰…# Āí=ŊZ"U"ÜÖ:Åæ SVdÃ)$ŧĸN3vVžöåiXߘŦge—ŊĒčÃ6‹ƒ&dïĶĖŲįہÛÝ D†ÄĶ˜ðĘė6bįē‘@2ƒŸåėˆČpJ·{••Ō?3�ģ,2ōÛnƒ™ý‡Eøąuz°`Ī=_bē4}~þ|1ôđÜJĒ=ã}wîsüĻofú:dNýöûēl••"kãŋŠōB ؂'~ÔËj9t )Gšŧ0?t@đ˜—á’DŦߨ%ÂK˜@4œ'·ÔūdĒ―X˜óæÂČĻðIXíéH/øj‰íˆíŊKĸElŦ[YðÏŨÍ•ãÞô+ĖpģÎ_qŦ7~kfūŧŧ“qĒĄŨg2Ã+x��oędTÉjobŠ?‚rŒð@C1įŠ`v}Úðę|C·N<qū{DRâ-84KÓG76&ö!<ý™õCļŒũë:T��ŽÁíóū|F*@Ĩí`Ą?þ;Ї܂döÂ$y.ĻídAčŊïų"á Õ`ÅV‰Đ„Ðwï#Ї0ú<ž+ÎĻx`°]‚Cb†8účðéþcÉŊFýЖ 2 ZYHbRƒĶųJ�Âhöč�Đøā'ã5p!nĸ>C}SE/í­x $X6xiāvūT.äĞĒmS7éI…ē`\>éL âAŊCđĪL^C‘f-‡ŒÂ—Āž†Ë ÅīpŽ 4Åü°Ë éIģQu{Éž \b§)íÖ?†N 9<ķœ°ûL…aÎō@ũŪkÚ WęqüŋU5î>áŧ0–Vj“G Ī.;ÁšōŒð�jŠ<ƒLi~BWģ#îóđC7É+ĻuŨl)""đ&k*§Ó4#k ÖÍ|ÕĖkô™ŦÉcÚ]*t™ôU Ļe|$M 5Ža@Féņ”Žr  lŅ‘t›{ó”âëšĘũááS=ņ~JwåŅ›ņĶütßɧ/M.­üšïūM9ÖđðčũÉĒ?F̟iņjßŅĶđ?%ņßģóUŋ3ōR/[?.ėüŪx*#áém>ęøÅ~ŠBųõWįØĸQē8^œŠŪŦö·Ũ–rÆŦŸ€ÓĀópÁāšČŽGŲv›Éø&ynD#ó.ŽbPĩf‹—ĮÞījĶuøha7ŠĄ‘Ķ>BÁčAØģ}FŨgÍ]į þė`―y―“KŠ%Īō�MyZŨ�°bá͒ŧÎTþg}ļ�―EÔþ_YžĸˆiõĘČëSYOäwãągckgi7ÕÕÏģđ�+Ž6úÕ7-!ŪeOquÜ1zĪ(æ ĩęŲar'–%ũ b;?TÂ'c{ëYdÁĸ]Q?þ‘+ $1Å5fš–3ŸüåŦ^ėĨ‚%r�NßÔ^"ÄŨw—Ũˆũä3_X|IgĀžš’?ƒÚĖ–ōU5ŌâŨOm·K|y›cDą”čaŸZ~bņŧ§~" â'Þcm7ÄŊÜbôˆ ?3ą�Č#›ß/vkâqßéõ\’>G؉Ž-+ņ‘™1OõélÂm}ĶDšŊcFÆYeBĖ*,ĮŽ>Ýϰƒ–ôį0 Ø7•FĢkđ’ę5Ī ę ˆÃãÉw%ėÜāŅu5Ąƒö9a+öđŪ_ߞž˜ŠĒíčė„˜ÖN�{ûdrÚČÁY Ë#KéïlåönŌôČōüšé\kĸH r€ožxĻðÄļÎþö*aŒzOį/Á°@–ftøþþŊōĮ?ā‘ĩÁļ-Í(lËh}LĄ•§áå ]ũŅ: ֋öü‰Qí7\ðâœMV}vĄč°íĩāfēÜÃÚŅ�BaĨ j­ĒrþpÏïõŦĘØĀ$~ZíƒF–ÖøĢû tG–ûĩD'ĩ…x`‚ŋ―Á؅rïK?ÐŊ›<ÖūÞ"oļíjw#Îŧ{įä‚é˚ĢB=NÉG›Aâw…ŽŪrŒ‚J nę>î1‚ęoæ.›RąōN#·}]…=“RŊõlWĘ+\d†Īĩļ,5ęu ý 3’ÏĻfįˆlæŪ%ó&ĻT†D-‡@“Ļ)óYs^†ÖĒÉO~([―Ķ_tĐ·~Õ! ‘šE1PŽ·Y‘áŽŅIöĀ?ķ<`Ž”�$\cDČČžÜTĶLĸ ôã’ę”đŽa]ÍKÜIcîv­Kdā[v•Uû\<ž)]2›ûGI<*S’iy„(‡âoē0Ü*Ŋ‡&gSĄØīëōOĸ>ņ„‚ēÂôm2.’dæMÖAïâØéņųNwĐ>R6ã7‚r+žEȉ!į°‡Ð•1ýûœkč―s_[v/ýeÃĸ–ZýlŒ‰@1ÏõÖôƒļŠÜČBIŸ3f1€·°" …–†žąą.ä8Ėïp‰ŋ›0}šŧØĐïa""%ĐÐÓ nŽ~i# VäJ—ČĮwũĘĸ):ļʑđF5ûãĀĨÕaöúx ])xŌÍeōËæĐsΊ~ü;Zö‡‰ķfēNmėgļFĩ]™ų`―į‚BRLĒėČó:eÛŽt ÔÅD―BïL°_]ŽŲbÔēð�Ęnŧō[ęޝ‰Ų8Ÿč>+ö}Āģ·ĸVÚ­Ī„âšŠäĪÚKįĒTģ%ŅáIŽÄÍÜÜÔËÔB=ÔÆo'ášųkö'+BiŌķšŊņ-ÆN‚�mó·Ž›Vé.ZN‹GáŋqHÆ@ÃCÛŲ$@ŲfĒYg―ėa·ZâĮc€Ą^ÂŅicæ>c4�� ūŠĀƒĀJژr^1k#ģ^čĮ9ŦĨ’ĸ~‹Ö;éĸ7(Γúf†*ƑxrœØQSũĨĖþØŠ§.Ī#Øs Qkï—"ŰΕÅ0Öø&;õ†LĄ-úϞąÕgS]}ķ&aį‚gá 7@ÂþĪĩĢTŨXīį՛—ųrüKáóŲ�x:q^QŸÐÚ4a—'dāŊĖVÍôÓNÖWš:Ž%Ž{.(fX;^pIũn[fDBĀÛjå n\F0TĩHĢ!w‰@1Ā}M?„�%vþˆF7üJ�–[’ĘíÉ*jŠNJûL˕áĪ#aXáÅZ*§ØÉŌ8ĐđōōĘbđŪÆ.Á|Aąôē4A­RŽ�ííø]yë$aŋĸ8Ÿsíļ@e^ĐH1 4„:l$$Đ+IföN· &Ķ`ũsÝM›<€1ŽíMXÂ<tnžwėsðiŦ'v‘d ›" „c(ý$rHßš'É6X@”{ēmó°*ų2œĘ|gũ<ð€CôP™� åÓMø*ē!ĩ;‚ė~°Ŧ›õÛ'ՖųîbÁč'VŨIčãé6>Ð@FþŦT$%@đÉĢI'ÏûuŊDįköĶčo1bÐ[ä&Ýb7ŋ_ģqÅāußū%ë<Yáprǰ}Ŋ…øz™!~aüaņC}‘RųÛ/·>rõRįüĨ-ƒĀ|§$ä\€NgŽÍJé˜6ã-‘ÓݒÕcđiŨ4ëūĒ. sÞ80Û+}1Óž .zI38THÁō;R؋•qÓĀ‹fED<îíüĢ|8x° ŠÚÝ*ļQ d@Ž\ë1ÎĪVą&%8:€0žß·â—„ÂÓÞːðŊ6šäIp#z ĒxŽ;ōŒ‰ō…Oļߋ óMÂCĄJD9…üi%†#zŨä+zÞUŪ%ķæ�ŧ= ŋáÝįsƒŪÛ5įĒ0fƒx ŽWvïá%ķ” Ā�%XÔPí9HąÂóm"EūôČ{LœÐ™5Ų={öâļ/W­õPAĮDėw•ö@‹(ÉZöõŪHyŋәĩžâxIČŲš”ė<p@4<hó0ïœ!rIPNl kĪ‚söĀËĐóvËbä[3Օ ļm8’:БĒBJd™Ú‰ũrĘĨ\·VĄ�MÄ 4ŋ藋?0Ö5{ČZLeY?@îYZōéôu[îōWĶiûĪBšƒë—ÝscØ[Āķ'ð $ _ĸ*ŊC;ŊËĖP†+i|ã ôß *1ŲƒĢšŸŦ<ZyDÍļé˜óÝxüĀ0Žĸ&Õohîøĩ‡üĐĶIî7:ĢþFōĪsé[ݧĄ|7îýQŋĀr“áAˆĀâBï"†!ŒōōŸ§#ĮŨ—œā #ßĨĢĪCŌ“Õ„;2‘Ā}C‹™,Røz>Įæ^ũVÜŨÝv~ï@ˆ€2œęœf&~Š]ęžÝ+D3{ņQfÉ\cŨę‘VÜ�ōW]E7ķĢzn">!ýųÆŪ–ŦÂÚKÛý‘á^šŅŒK2<'1܍xFáņ!PÃu›Xƒí^Đ)ŸQŠ‹uR[$šŌLģŋũIŪÂ0Aĩ8J™šVÍUjî>ðķDdvÃd "I�ƒ3ČH”ÔSß(ũ~ƓÕ5MʖÝw?ÅúuąoÂ,7ŌŠkģð;ëæīÂY/ŪAóŠ“ŋųrâĻóå…Ý $ÉäâŦĻ)ýqÖ[I2Ōfý;ÓØæ.wãV—1Ÿ*/ŌAuØÆ§WÉĻĀPÅķū”GÕx <)>―Ï.G ˜&zZ7w.�û—ÞP@a—ŦQ†hd ―ÁˆR�‘^[oĸc_wĒ^Ī‘>LŋÕĄvĘËã4“;ą™;đ ZßĖrï>lzŊۊ0Ŋa€lIĒĻËĖųũĻē_E`„{l—ĖŪģà Š^îóv2SFéJXJHg8ጠî‚`õŪđþČ$7īNģ܆pŠāÄ1 Vn†â:xb–]ĀtzoĮčžđ}šĸ§Iþ{–ķ–EÓnv\žÂ]šĀA ĻĄ4ĸl79` Ūgz™ąÍÓžĀŠü.õËBČ_F ßŨ 8ææ“tŧK Æ.ņ~ÖÁbWžY…Đ­n7’ûš6ģĪCƒfĄŌdĘ-wē ĪI ïĩäpó_Æ+d>ĸ~ÕÖÅ)·Šãl m"ÐŪ—T(âÓWŅ…TČ͎ˮxâÜiK6FÕĩŠö™Ū‡<~Ėþŧū ČļXSĮļ=ĘTv[˧…ĸ2/·ÓÝx`T!ÛЕũTS5IŒ oUŲ‰ũąZėoAߐ%æ2ķënĘčÂf@Į>嚍ęôؘl΃˜yÍۓĪ>%ÕŋÓíMÚvZėŸŧÎKņĄ#oښJß7îóøï@ĻevŋDýnī†*t€_\CŅ„+døÏóZ:Ōïi l’y™į6ßÜSzf0'bï‰užŪ“ëææüēuũųŒīdĄC ë††TzÓÝD*ŦÓĻô•W@-Ū·Ēđ<SšQpQ<„“O’$Ę}õšaf!ÁU5ląÔˆę"Õ9VÜĨSRÂWđ™;Ÿm("ĸ4°k]ïEĖĄŋF ™bp‚—ýāk8ĖHž†ŌKÝ-es<núûváûČqbR]ÝâôxŠĢwé―KG‡kwš‹ĨÅaÂT"°Ŧ.NÝė~ŋÉ4`[č 1ß9ˆå Uj•&@Iĩúī<þIÛ(ĩæ˜íïKCCė!Õœĩ•á)šÂÄúšÚā­z&#fGBÔx§–ē_øũēšėåhųÝžĩÁÛIŽĩ0_•ĩ}Žöܜ?s%6$a:Οs:šƒi$h7LOãåcÓý(ÄÔ5P›nēĶp_Û ðQĨ/Œð9AFxčuĒråŒ@4%W73úø|3t_d-―äÚÁÎÁŌÔóˆšŲƙZÝų}Ø]‹aHŋIŊĸLĸ~Pũ~dĸ–öč'æx  û…ĶĶÄsƒ‰óÕt–hcø•…$‹}ũōVņ™OrĪ@ĘâĖöā+SyņÃ1]yRd'Ų žg~Öu9đäÎą%ziŋ°îLė-=°`><TŦøP@*ŽaE&Ņ'ácÓ7gĪ)R,čsĢPiĀėX™_œ‰Ók:ZŽrĩēH}BųðîĘÉcô ĨøGõßÎÉ sĩ'at„1„„ū0p��ð Ð IÉ·‡Åŋø< ŸïĨecđŌĐÝ CĻüƒH~ÆtrcæFIšQFŌļ qLî–O‰bŒ�Č^ÍŨð•-/T„Tʄ„đGeóMÝŦðk°ÝæģŨOøP@*Ža5Ąnøl_:åb.)ÓĄÎ%dÓwd)ä€�HFĮ~ 7{ÓÕjð|@ Đš§pô’ų‘ n™Ác}U„ę Ą(ÏlËÜjbqĶ2 �€kt‡Å8<]ļČ*Ý$$ƙč*$o.öæIyô‘IH‚zjĄnWĸz:Ze€o[ĮbNQZęũŽn―Čé.Īã3‹Þ‚qï―ĸ æc—EFfoÉVšR ŒOÁ'ŠþxėĻ ŌŽ…ÅĶ Ԝę„ó—VwŅeAQoiŠ$ZæŨFįáčŦĻrv%†Ū݄1}―‹PėA D$€ÁQÏBcÓKÝðļŋĸdō~з:aägRģąý)â6A‰Ødđ5ŠŒŠ QLyÓMXŽtýIŦóÄÜÔÞkÅũ•ĢBKĄC§Ÿ64BĖ{^Em!(`O6Ę/pyŦô―ëIJ'6YĻĖ!*xxÞņj2E™á{ĐB•Qų`nŅŽÛōAĒŽ‹88mĖݏ{Ļ”ó?LrleöŽÄä_ķmÆEKĨïōW€žˆã›ĀœšxũE•ˆģÍo5Bð„ŪžÕë”ųī8Ļ;óôÉöj�ÚÚøgÁėšë€ŠzB1aCJSƒïæGDrģ­åę―Jï Jzi’�―ÎzO ŨAĮŒúŋāéƒÎ(]vŽ6”ųQƒę?ÍIĻ{ŸYš5Ŧ8Óėf•ø{ Ū#ģŊnRēEv[îšíšÕ=rķ˜Ä‡Ãøˆ‘ôF�ód?šô‰Áō[RŪnōOß5§8ņ5fĘą€ðþeˆoúJ~dŋšš~jŊú*‹ųŠßž”~joå3û ũéUøĖAhĐČÖÓōŪ‡Rę_‘Wų cïŒ'æ#:ų?*wó?°õhzxĐCEØÁšuŠÍÔ 3Zäōp ņ MÜėšSc,Î*ūŠ%ąOíûÉųCZxŒqąÏíäŽ―5íÁE\ķ�Hö …ļúšî;ŒiąëüfāÏÛų}ß!u™˜Ãc5’ÅåĐc–äÏš™ĀR •Op‡=ŸÛ°4AčÁ‰ĢMųŠ*é7ϞˆĢfÃˆîÆ âÞ&iņÃ:ą–ģíQb%õuU|AÂjS#Q•#‡žHNy+å›)žéyÉUûÎQÔĖōœÜNB„Dįņ-ŧ“LWR~͉c)<$Ģ0Đßy9að Áðóc$~Ņîļ–ÛU~| ÏŽkbûAqgÔ7IE™u ݏéæÚŽÂŌÂFYÝFHýŒiÎēåû|аÝōÁīw0Üũĩ“7W “||HĘÜ6|ëLÓōu y0Į#3Ĩ=ų8eÓEgÅŽĖψ§žŌ‡V]đŊ~ï7KÆøĻû;%Č:ãvMv •|qÕP ŪĮ?”Ÿ Æ„KI./†lÚRÆŦŋĶ?đē͊�5/ĪHķüÕmTLŊÕEū‘ŽZ&K. ŪРū)ļԉ ›ð.?'*ĸUþŧ`pžŽū (õH >`·3I•3DŠcŸy(žÓõ ‚ļĻoC8+‚ŲDŊSÔū9'å †Ųr°čG„~mY€Ä îWĒäzž7äŸ[âP\čšĪcԄÜ`ŠˆėûŠÜúvÞčņHPïý&'6đŌS…Õ—IJÍą #ZßDÖ·ïõn? ÚÛ·l0ëýØz+,ŧ,āBÔE§čõ'›ūcåŽĻĩ•­qžāķøâŒ#ĖYP€ Y#úRIï·i7žÃ%@���Xõ5cĨü5=-āˆÎ)=ið…˜�0â;ũäa"?JþŒ•���� ôžÓ•ÁPÜŋ5ĘĢŽuo@öĖ øÆūÃ@ųę@ðu(�Í~ēk#œÁ=ö;Ӆp#ûVdžï{ÔMæŽË4&ðũö;ø$@Mû§õDëī[Ī–/‡@õ*'ŪeäQ‡nö�Fïýē<e�Ûa‡Ųßą“FHį7áõÃĻ•ŊTPœ í$ûƒÕõÃĻ•ŊTPœ í$ûƒÕåƒC�BĩDĶÎÃðĩ‘ŨŸCĻë3HĖšB”KMô―6ÕD}5B'õi�9Ęų­ŧŪVŸ+MÛŠÕöƒ„Ų5õ'ŋõ1‹ôó1&Ũ“‡Ûk…rŽRÚ!ũŽŲ~ƖžĩÖŦÏ'*­je}:<*nóGÛũG>ÁHÍ |+ÄþúÝĩŸôųLöVĸ#qI”þþXˆ;ęoŒbކIũ@<Ž18å†ärĐņïDϟÚïgÝï^“0Põ"^!$-D˜Āë.YWv?ÞAßØlÚĮß瀀€€€€€€€Ã‰Ý,ŸoĻ·ˆb|x@}­ĒiĨL=ånlQt?‰0s’åÉ=ø·œ!oˆmÖvāĂq�·Čö™ÁÖ*›ē€â9ÆüĢoNÞVqō"“Ø€bz -oMAOōū%ÝļJ’>ßaYCø=zīû­ rDӏý}lÁրąôT:G· \o_OŋŌ§>ūåQ3·ŋNQÁSĐæšb…ļpM?ížiWڜ- €ßhÉ:€‘Ø”<{iĸ#+ēËmĀŌ[@ÂOSGJIguÂaRN._sVÓŧÕN:þÅÜAbŋ1$›1ö8FĶÐčÍũyûÞ?†Čũ’"‹[J‡Ž5YfCŽýRïxeŽ`GŠŲO‰Ķ―ÐtóÁŠ>ęÄÃüÝþ'ô͝Â7zjîÆ—M‚ģâ‡*ņ8Wų1MÔTŌ&o‰ģs.ũFRā݊L\FFQˆĻšcŽpœē]þô§E•ũ/ør·ręžē+KQ)#œôšĻ!yũ€õņBļ‚,)ʐaÁÜēķę†ĢŋŪg­ĘY…zīžĘƒÏüŽEŅĀ#6(e*2ŠÐėØã)|Ŧ}WÎEŊYŦiæÅŅĄÞē)LØd2‘,ģâü\Ļ—2ļoĒ8+Ä2đ dqiū|ĮExķwð+Å� ŠuýlįöÍN{[֐ˆØjũļæõ@­‡ ŒX2†Ų †‘ū&-§—ņÉnՅāyžúb$ekÕYO6ĄQ tÖ!o‰•šØ!6Ų@ÄÜd%AEöÞÆ›vgą†î(ēŦ_Sx Ž €é6nÏ ­z>™ũăzVĩĨšęŽch <óebBÍ äŸ3:ą.ÓY—Α”n]P;ģŦĖ ģÏæųģšk–ÃįZDí~Y„mĮmēP̅ސå@Y6ˆÛĨ<ŋ‚ŠøĸRdŽČ#Cr c… Tc*`žŧ — 5ÓßÍė_pƞŋOڋãbÞąP@Ӆ'wėüąâÏÏĒý=KG1#ųö–„—•°KG6]dũ+ *'\ۃŒŧCS8þäu-ęä•Ã:i‰ãÜŨYØZ .ņëN›ĘđÚwh>%GŠ™ÄŧmÜæNhsÏl!“>™ŅÔĩÚ\ĻÎēazRŸrœ“ïL;ïôï†q-™ÜŠýWðc5›p·1ú „đėŽ Ã›Tđ†Yj>TÅ17ļ{“ė:IŠę3R·2D'ū9?68ýĄÏžļÉđĻwR‹ļmf*™*•}ŊÕž"ČŊžzäLĸÝ(Ûí]Īú ĸ% ’\”s('Ïß8ŌZ–NÂÍ|KĀsð߁ Y§ũ Uû ›”ÞąÖ|’wJ68j‰Ędõ‹l+ŋŨNyđ ·ÕčzîŽŌrxQĐÓ― :Ę3„2ģyÚG-e$eÓĸhĐÝŨŸ°ö/�_Ëšī<iEÝVCC+Ÿ9ĩ8Z’:Ū€­­[žƒЍ%‡ØX4,ýđ"ÅķmÂ#ĐÁ”HþL hžđ8.SĻŽR3"fÓį^„Ëŧc™Éß F!#Ķ_>ÂĘg‡ôœ°Ŋ/uļā‹3ĸ‹cš% /za~Æw~U:K Á*|‹ÏeVžu˜=€ņ\ŪãŸÕÎcÅŎ0á­/�ÓB:_Ĩϊ}Ĩ Fjð0ÔŋĘH—hj;n—4tÝ7uņJ9D˜kï…EZ$ļw E€ ŧJcēhĩĮÉkXėdŪŨĐ-' ŧ#[Î9Е(E$ĸ:f Ík�jRhũū?QĪžÐ…ÄÚøY‹`› Yū … nÉÁ[~hóēāyFÕ*É_f™(öŦ{ĻþڞëšÞ…KĖ”8JķgrdþóŽ‘Ø’ãUíŽÅaŽdKÂāņQ‘ ͟ĪT‰ķl]šEÜi}‰iø4D|―'á-žĀ{ ýēļ@i[­Í™‘öæa—eĨ$äïSâ†ï՜ǰ‘Ëų§koė&Įüއ ōE”î)æļĘ"§īĒDYØ"ÄŪ=&9nn_ĄÛQ…ƒķė|AšB=>ŋt·ãģž9ž;ŌÄj;!$–Ó%ƒrm?9øä}û-Ē+úVËÄō1š.ŸŪéD�"å- q5æ!U-ęõÃâ počî3‹°sޜqĨ ĀwÖxœô“ÕėzdČÆęØhŦę4!îsąœ G =La–‡ĮJķ” <Ý6đ€ŸūÆÞŠgVÐ45& ˃Ž'cÉė”OĨ‹&§Ïä-\š.Å3Ų‹"įW1lũ:†Ę+VƒŅąüŌĩŠ?wĖiu( €Ņís='Š\Z‰ūƒ ý_"ļX#ýÆĪJŌN‚^xõĖũ—‘ÅāHš–ûÐނ`Xŧ?~KôÎlÕė/š~ŲŦÓg–NŸ• &ĢĻōÓCæ 6ĒÚÃe7īĻŽX"4Pæ`é/PæØ›ō2P%qšj„ũū+gϝŦĸQ,˜é­Ó^Ã―j†š\ŋĮ;\ ŚóėZoŪðļEå]p°>Ž7ä^W‡Š'Ä8°O‹“ū$ģŽ/2*Ž_N‹Cå!·{ßf―yR°ĮÎĩ”ÍÁæi'zė‰ąœĪø—Aĸg]„„Ūh1š―Pę0$­ÂūRŽį‡:�U–ˆ—• =hƒzÔØĶøĀ2Pž°~U~Uëþ،‡·€8EwĄ1ĐŽr Ÿ]pÕjdšĶp ŧ_VûiJųĮWÂËðoŊæ )=Z7+ĸGœĘât€øũ˜fÕ3– į~TkĻtD"j3Ė ČđfAVZĩýĢ-X2‘@ŧÓáŦĀģĪÍTcōœVO4@Ų€·ę Ļüo Ïm8tī\ðV˜‹Ė_ãZ ð˜2båeS§ÓZó“›LzŌsɊčx?#―+_ؖáōđ$„Л:,Ū―s”ō)žzĀŠÅP^Ũ:ũŋ#@K˜ÝÎ ņN9ąR•Ï” ?ÔziÉņ@ĘßÞģļWێĄœî] åÜģļ{ņ^ˆŋ‹ÜÆ Ũ“"Ë"(NŋŸZëʖ$WėŌA9 „26ÔĮÓ·•œ:T]ãĶöĮŨ[NÃn@“gŦĨ†úhQüąNĪ`_­Nō!qÞėûÉēP”ųŌã+RhÆwusČÃI!ān$|tÂņ™"~Ā\<ķØRžhYƒlðķėÃÁ%ëFŦ“õŠėȕÄþI6Ŧ:o €Ļô2;ũîh1siŦŽŒļkĒÛÍžĘĢĪļĸĀ33ƒũcž�YÔí[ÉõÕ$ ýŅX†…ũĪöã―,v‹žūŅŽ ļ7ōn‡āAîÄāîúZ/XsŧvE˜ÂĄ—‹š•BĀuØËėûŪ“į/zĨÁļÛdząMU—ïÏxZ(=™Ó?1’ÞzBø/Kd\ĖņGĀ&šŽÝŋÚO/ųôęQāĄU^ó5zĖ āL@Œ74m€Ÿ ý„N<-Y9ũöxŽī-OmŸ_ƒĒĘŊfļĄŽBŊÖâ°rB|ëåīð3zXû.ÄPLMާ(åT‹j·Å·iĪcäõ [Ë….š —ō8ÎŽ|"Ó­āz=Ļ™7ę-Eã_6ÔCM…äT]pvq1Ó!Ō―WįáæGŦRDĐ(Qōõ‡Ō9æŠčč4Āž�UĨ7čnáA52ŲG/ĩ=Á‰˜·—yҊwNëĩc,€šŌgPļÏĐ―ļ`‹›ÉáLŽü„VßL:ãv– {*j'þ?ӎcsĀÁdŋ(Gý} Mđ Ųþ˜ō—K§ņ_YiīÆōÉ›ųRšó#‰ ­Ŧm˜ŨX„ėŠčáD۝žt]mqcžPSoNÎė[ ÃݧrÜF·…}ŊðhTv3Núāã–38p \~ąb°æĘ{äÔlę­YđéÉĶ#rGō^ Ē(~ ‡„ôļ}OrÐ1čÐQÔ^Ą9ĸiP++0Î>đĖôæXšĘa8ēüfĻtïįl8{bAcīLJ=éXĻÖ4%ļp<éŽ`É―Ę;• 0ęĪ}u:åïŠAW-á"oĖĻ$ē‡dd™ãūh›6Äjd<īĨŽ(<€ēáN•Ÿ-8 [”—ęcÍ8ŠcÔĩīë۝ņÓÏ6•Ýģåk™CÏ ĩhŅJô5Éþ; X–điā9Īþsĸ ĮĀüM0ĮÁ(þޟį$BųŅų<Čð3<u|şČôj$|˜Šï•Ũŋ5HFÕo4˗―ʋ74ë­�*Gاˆē`<éځdÜU—€ßg] rð“AØWŌîBÔ―ē,zČĢĒĪ8ÚŠ’–ŸĄÍüī'ÝkÃęFOč ÏÝĐFâÁÚátr&së)vģ'EųÔ6ýh*\˜~m9Ôŧb8P(“+€fr‰;S~Ā nÝé Ņl§)š’ĒËīЭáešQš xöÏ\;›ĨéésÞ Āþ5ęOe ãLę­Ä’Ĩ#ÛʐꀔE°û–ö…éGØúŒĻ"ØĻĨ4ŠRûĖËX•Gø›Öpä”@P›Ž™Ī­đ؟öðMövŦ8(S”5Ô ũ›Ģ#ĘŽļíM―:ƒItÝ%ÕuîųÛHåB<|ēĶӞÔGâ?[éÛøüK·ŊŠėšõ$x€ōį,öÓķgÛ=ŌųŠúŊ”đ öĶ‡2Ŧ/‰sކ-nūqEže!)>sĄŸíaŧ‚.ŧOĻŪūo›Ņ5žB}ø\š ū:DGË?ũO<9ĄTŲ–KŌ*PwžÏgUë‡Į@ÐÖXFĒ.2ó 4ŲhÞ@ĖĪ%ūŧ‘ýēÄSiÞ yĐÜĸĀwģ{Ï댨!wŅï$qęZô,ĻYDĒO{ĢG€0š„Ė)9đQxåA€ĒUsHÖõ&ô•†QWɇ.%X ‹'Žö}\cŦšFcâËIĐēX°Ï4þ™›·ÅĀô•xiöÅ0VžĮsžŪÖ$ČPë•ļxūjcđk[œČ0T!Įī#žnzKfBï+Ū:ņ7) q ŨŲŦ€ú™ąŧ#ÞC*ð-šŠŠu7ŠWF|–ye_ĸ;Ąėé"Fü„ß’AÛĸKCî(§pj! žā؀npâäF·ŊöÝōdý‘â"Ôm ‘dnÍũH~wœŠa·íqHïDĸŸ& Ž)<n1fSWzÜ.(�­ ũ[€đtí^ė<Á”úēĸ įnUð>ï?ÛņŒZ ą2Ÿĸ=)*AĀޅzÍ+ ûĻqŒgŊN}ЌĶ}‡ÕĮ§Ā-~ėx·J“‘ߝ{ÝZ:ųZ�Óp1•e#ĸ%N҃\Ԏį.L 4Įyšs;„·ŌœŦʙįÉÃkķ!ÃĒë/e›ë4b(Ÿįni]OyJ‘‚įĻĸaņK‘ZĄÉM―]7]Œķ8ÐiņÏ3ržõ|'™õëīĩ§ŽÎūzīõ;֞đwIåĸjcÔoƒBrŨáŠüw•ũ4^Ō|'ĘVŸP{IúīõŧŨ~ĩyûĪôŨSwIw\―A>6ŊÖŋ:T|�ōĨ~JĢ=’)^ÕøÅŲ†·Ëš'Ķû^qžާ›ũ-&�ïo°\cąÃóēūģą1!þ˛CVJYĐø4‚ *ĸێpdjM>Ļ‚Ý^9#üÆV4ĄĨ}LjAÞßkZË–)”BÉWÅbtå22§æ, ŌôDĨߥą/įbvr ŌÞĄęåŠ$cÐc\š§j0P:•Ī‚`ī‘âKiūþH>Š?d[––°IŋBņ}ąˆÓĖ‘/•2Qï/GėbĨĶ!ƒv}Ķ6îöýß勨“3k†Ų:‚‰=ŪāZĀīëƒokÝíÔ·SŽS/rõŸõ#ÏļąðŠ/G°q•F―Ó]ŋ­Öy}r‡Zß=ó•l[ûÉý+Đ}_•I@­AtĒf*Ų% K�·SņũÉą€ pÎC ŸTK‹ó'áÖKī’Ę-Ýۜ0Î3 gšNwî+ĒMķ.~1Œ5þuellМJģÓm!pû€-֟ËŦ̓oUwŅ„ē0R‰ÐÂß͚‚Ši_یOoy*†…é?9`íģyþ $΃­ßjšcĪŋŲÃe#Ũq0ý­“Í-+XčfmóG‡A ÑōoļÎÖVO&X+ķĮ:"Hû‰ôÏŠŧuĪCI"ÎķU’ēJXĨĻĨŒ )ßĀ†ÍĄĮŋrŽ·Úžß#m%dÐŧŠ, 2ąŋCę6H&Ī'—é šũõå ƒÔĄNq2QųBP?ïb7d­đjŨ?ā$šMđöŽĖ z\čBˆ‘ßš°Ðí^†HËH$„ÞŲxīåäVŌÖb,wé!Õŧ%ó„/ęR=ØÄȏōô^Ņ;•·Œ–ËãŦH€äJĀĖÂÉC–ŊŅ”âßð]Ā„į—ŊĒ`|�†ŠzĶTšĒkË9CWËÎs0ĶĶ=žÛóý8,CK'‡ƒŽ­--]ÓAųámE‰"OÃÎ—đÆšŸ)úāVÅJUdÝ â‚ūDšv’$Nđsņv—Ýë[wÃz;:žÕÄQņĖÕcÕu^ģIð“Š>䞆‚H·hį=ļ}į3Žŧsö- ļŠĘíC\s—ƒžFÎ`âĢ―eŠ cÎýčË–CM�ŸM§^ũ+Ό žýŅī­ŲÛöĄå\*)ķx‚QŠ+cք Á–ïŠ54ð ņ•ȉzƎ3Mëu―ôU4{%+Éadm(xŒš ðŪîbĮ,F‘§Š‹<GÝڐBRåƒÏƒęãbØ û"Ą> VÚ1Í\ō�8áOãõBÝ ŽĐuÚ áĸ:°&<5Šž ų[Ũ’t0‚Vée}/øn%$6”Íã9“ęâmÝ„í4ðqaôÞšUkÆ#ō8"ņ8`F*>į­[›đ}ĻÛ?ųė\­XoÂÓý!IÖtļģlg+üÆū?8&9ŊŨMŽUýCÏj”Ý–BÜ2Ÿr4XîG“ó5Ø"ۜ–u[ŌPi3ũ ĩMŽ›Ø9ūņŧÓgE—°—=Ü~Z ÝüzÔ&š†)ĪIfØlcŠÖÍYGH]ĐķĀÌZQ]ĢE7ÏÆļf5ې2R+Jôßþ];f:ï~Ģ(ŠÄœgŸ0bc­éūčdúäAųv_ … å0ąĢŪ…Ë•-@„ģ›+―ëëE3�ĻîEÆ6bē‰žáĢjœ˜Ū}nđ˜ĪÁl#Â]Þú暉Īj­ÁųewÃC ō‚9AŽ?‚ûyë!ð7%ĸ~ÞáŲÝŧkũĸ8æĸoŠų~ Šr›b1dã•°�VÞų*ąhĨ õĀĪÔūŊmiŽ™æO…A‡îįŅAãŠĒÄeIŒ/N”ûÝÚ% ü<­l°-uĄņeČN‹ôė “·ĩąõ\ƒ€†âčJMŧå R›)'IM°rëhdhlsMĖA†rŦ'mĶᙃ{‹kðá3ĩ,Û<Â)Âj„ū KļގžŽĢĪÔę3Ċô5ĸ‚ē’Ø6•ǐ·ķŋ™ãsà ·S=ã<F(ö&ėÉŨú%Ī+Ą˜Šy?;rpØt–p&vW1ÄüˆĄ„ā“ßÁöŧF-ÚO:Į!ðÄŅ)ģŚ(~ũB6īԐoæ&ˆĘÂ�lU :€ƒ­ö”ļ8wóÞUī—Î1czTBŪģåņ Tï >ĐžÆŽ…“1[žë`_I>Ûyfä`"zÝĶž2ó‘T@U~ 2õķŽŽÆ†AhUŋ‚)Íá}ē[ûqmũPu!T 'ū qņwJGõÂF5�7+Nä'Ôëû yO#ŌĘÍ ˆóÍ, 1DÜĮJ2?Pōk˜Š:ė]*;‡ā|Üæ’#ãö‚M|€tï›ŧuĩJ”ų|Ųę“_ ŋQ…F ï`Ōzï5:%R“& Ï†0jÐbz‰ėuūũNú-ā·Ð„n{―ŦKÖbÐwϟõäp’+ĸX} ”ž\ƒīĒņĪ „ˆ°ß '|Eĸuņ”ũŧbąlŒWõÅiž Ø9wææžЍgœ™o3åŠŦ\szˆčĨ˜‰mbÛŊÂJtrXĖØ5ļsßĐf,Čn.ÅRFT―‹ī:#*|€aâĨđ?d‰{ĩ̈́žÅË{…y•5\5RHŸ –ïkŦ“ÃåAtšðĒĒ1y4*S&øČU0ų4Ō°óī•íz•ÎōŊÏēO �ÞÓįr€Ýķ8ĢA,ĸXœ/ˆÅŽã%˜ŠRÜšŨaĪûōąÅ…æÚF&A16­RĀ ö`f0 r_ ŪÁ+ցd Mē@-@ÛÏ&ĶLĸU['};đĻ™:-<ū&ãŒÉnÁ•…°Q·pÝíŋä9Â1'šäģÜkðšT‚ƒð—ŅŠ0$œLĐOķ<Đ­BĮ᠗uMūégƊ1ôûŧĻ”$”ĘÜ(x+t—rīÝÚā|ÔYĒhé|ãhũÖ7Žû§Ūã 2Į­æ›°ï‚lvęYũ) ‚>†xmG…Œņak6"PlÕÄRI2]ÔøXqŅ;ŪaE;/ĩ°ãҐĨ�1ߨãó5=Ũ†Ų5Fo—…0I‹›lÆO`q·ÕŽrŪÕĐâû5zYp/=ūfä›óŽŨĶsšœ æo/Äûį%čßí“ų‰š"ĩŽC”Œ“j@ŅN6ŒË</ĀËWS`šKR•ë=WÝ$L}Z+=Ū@Ē%ķįïĐ|‡‚ģØ@6UûîPœ53a§6 ūūŠ0}OSģFcīĄOÛfZ†“–?ÁwøVD3EgßfÞšŧf ŌōęõyÄ qóü_–‡äzþŒũDfxķ5Bð°ĀĒŪ"wōī üÔóLؐiÞ<ņ,]<˜N/ ㅧņæč,tÚÞo.īhÍŧ?Š ^0âĪT=.Ļ:ÎGˆðš•ŠđÚŅī ―ÝŅ7’Cüz@†Įļ'ī)‘L”Þë%—œF$āÖHÎTÜĒŊ­UÕý(ÍcV‡+ŊķÖ§ūú*R:N5:SÅä^ëųĒą?}}F[=žŲRDsÍWyŠd„}Ū Ÿ~ĒĩQØĄþߗz˜įÍĨņŒØw“õģ:Ž1>úŸĻāõŽ‰|„:ė M[úï4ø8ô9ÓGēõė?‹·đÁc&,1ŲrDâū= YÎþÄæŨÞéVß Vų ĀĐuh]~Kråv/Yâllšð_’e-Tšv―Db§*óžŨĸfqīĄ+Žø/+°ŠRU?AþAĢ4ÂlAAtvlˆJÝeŅ?R‰â#āÔVÄęÉÚ[G䌯! ĸ-WįuŨåkŧuAVwÍ ;hŠeu~A}‡øå(œæo]*Íj “ßí ĖðĪ*.ýŦéĸ/ŧ|ļÕ žûUŋēUýÆÏ•B(9ŨĐĨäu™N 2âŽį [6—óĶý·ž&#6zëōá/ü7ߒ•�QU īxOŅ”}AnĩOšjŽ=â0’fš‹đÕ§ŒPZwîąõÔ*vœŊ"GųV:Cŧ)é˜~v.99ž‚‘,RžVš\†_šËƒ_;  ĐÞ :ú#ðSj(IÎ_Ó$( –―čŒžØƒáˆíVwÅávšƒ-2Zī“DV“č―%p‘ŽāũėAŋÜŊ‘@€ß kĄ"#įėÐUO4ÅÁŧ:‘č*:Ï5€:,և1Ó/ôšA^ö ƒÚØN=7%ē·=ú ãވqÚScėÛýâ0õåAķĶó$ého,įŅzš0‚õ™]: äFrÏÞVô%|ĀÝY͘›YoŅ—…IĻ_ŸDÎWēȈdŪvd―EĄķĐb„ÛGĸo—Aų>ÎöÐņfz~o2úīŸ8SkÜ<ĘĩôVuQe=$a8%ĶĶdųō(Ņb?ų•gŽIČíˆ8Šy !&BeĪąĶH;OÝũ/$ÏĶV7°›<-ķ™é eõ›&Ôē}?Ų@ŌŲf“ ŸÏ.ĀųÝÉËôšęÉä9:]ŧļ39ŲčG̈k(Pũ<wmŠDđĩĘpĐæŪČjÐŦŸģ‚E†ļila­Ũ`("s0]û:KtōäīiŅkëšŲKũ<ãrģÆĨf”.ÓÏô…ums]ąa<NĻdVÅ4ýmbėÕ C-öÓHŅ2įŽb"3īÛO!#ÓėÅvËģųī­oęĶH!FŠĒöæ—ï’œ„ Vú1ÓnšĖît|d#īë”ÅųŪ[Úį°@á-N^ĸoMÎ&ŽĶ–€*ÞqųŽ”jóã8_z‹øÐÓw kũÎ!^ëņ3ʍŸTú @*ûĀŒžYL5ÐøíTėD·™ÍI /ÃziB-ú>ĩÐBw”›Ą ÁÞņu"45ëlūāŨŋ…ŅĖë~œBÆÄEė„ĸŽ^aŪ@―•ōNĄž—d‡"…ĨÜŊåZþE4<ũü![N=CžXAqļ%ŽĨD§·ģ+3{ ŧåŒqÅ\ĶÄô0A˜s#ä"_ų‘üŲ:ÉP�(e��QÐÖR“CŠĶPnd%ĸ|OļØMVö„„…þgÐę qĖâŦÄĘÍ^ėÄ8—ũÛqJ:šb~Ė>ŧÅ}â>Pß ņUËYEW‘›C.čûý(C4ŒæĶ'Á-_;”G&‰F>+,ÛĩþCķbðF_ᎄĖųę\”ag5ũž?%XP4vŨÆŠōFN(G.G ·͇ĻP阎’‡ēGXįïˆ&―Ėķ^>ô0Ļ-q‹ä2qŋĀÓŅķ"+‚ü… õÔ·c�ÂBA‹tz*IxĶČcd=æ—ęHpi ðd\kõâ*ýūGž5"[6;þJžãä‚*ZyHōĢß4(‡=œŌÕõÕ6]W'ŒÎoâW!A,J0ÎQŅl<>ęķ čŠÍo7Ŋn‰vĨ+ïõģ^•Îwƒĩ͓ˆNZņ;ĐóĀՌéģe”—ķķÝ �<Ã4 ß'ĄãbdÜļLļũ)˜rŅÜIý�&įIË֞ãÛBZRX·ÆĪLjīĨ“IäšĐ$Š+ Ôy™Øt=x%ŌåbÛŅ4CLOxëšĻGx?Öōųī— ŊÕ ūˆė ‚ÉAŋņ2—ú ÁæųQ&ā‹R™€^0:čbŌgî'~ÉąÎŨÝVJųĘ%šōßīžúA0}s€ųV9„”GÐY %Ōō$ŔōîÕóôݔŪãĄÃúŊ–ņÏ2(8RR>0 ėŽ[ó·o6€Ú@R‚./Š!žœJģÚ0Ý;ïtvŋ ÃûâþNģcé89įÅ ÍūĢ=Ā &ƒÅŨžļs F Û1ģ­Ž&ŪÅĀ·ŋĨˆķiPilF[ĪXáđ;‰20ÎSÕG-ÆÓD-KHõĶæĀíã=›õ|åˆö˜<·â1nŒ°jNđĐé=wIþÓf'Áú:/šH*sīÞ€1|ĖŊW+Ē~]ņœŲ;„čŠĨŋøj{ÚCN–ú/UūόCĀũÝHÛčLŧpzŠã€ųÎÜ>ąiė :Ũë+‹ĀD AātŠjõĖQŦūmÔvßĻ\ôŋnû–“‹)˜PũāüïϟR87ËjÉĻķSWą öëé<抛 iË šėütQ0ĶŽ§4ÂŧŽü .öޚáÚðÕzŨ†Ní#ōFĸ6ÁeRųÜģ Ģ{°ŋðéŒō‘ãxïŌ―CýšVŦn}Âg˜ÂũÏlî„1”jģļVđņSq3‡ābą…Ú9YwãYĶđ―·ī.usr0ˆ–kdÚMbōūÕŅÏĄïĢxA !Ý­ļ˜mXož^ÄdĪîoĀ™Twh‡ņģhCĀ.éTÔŋå{iŌvö%öąō•ņ€åÝÆ~Þ―gãíQ'Īkx…ņ t|k9x€éɑŅō<zTÂrWœ)í<ÞEoÁÕ'.ÅWPb•w{Uū˜ō HPzp…ülCŽÛôˆ|Ž 4ƒˆÄá�ĶÞQ{a*ííäĶQa&‚uā}°€üü‰x_ð#éóāCįGÁUøk8Þ/ãQãƒÍšļƒIũNŸOņŸ\>ŸŦŽõ‘Šöží5ú?ãĖiQÚCöĐų@ĪøÝ �a tū4„�ˆ>IŠˆy+ē<5OÂķëæųūo›æųŧpïaÁYņŌ?ĩö\š'‘ģÃųĄÅŪï.ķ1Ā5éÐ|q‡Ē‡! liØđ~ĻÛNówýNŒā‰Ķōōú)â•_Ûû€Ōp3ē–eĢÐĮčØïQkĀ5ÎĀIúe0N&h ƒdģčŽ*\ĻīTäËÉŦĶ\ÅįVõ“ î•ĸnðÉ6lŪôö'ŅÐˊQ˜§đGhqĀûŸ1ŅĢX›66å0ÞF˜é‘1FÉøFGâf€îî_<Ęó&Þžã‹ą*:Xðyû=ōÓ?å„b7Ķϝ ëÎŧ&‚Q2†ØD–ņZĒ;hŦÍĸƒ>IdJÜĀû*ÆŅĀ.ü07ĮáÐaoœũ”BZ}+N‡"Ūā}0†ý#Yr~+™ūU킚OģwŲƒDü-8ÎĨäf/ĒSŽä‚Ļ�‚C"?øŨĞĘ)Ŧ€1žMŅ�LFDzĄWEŋ~J€���p/ręIM’ ���ú6ntūē`<–ąöÃøRĻĄÎaĨƒïóÉ,yÕôíjD zŋŦ)îR Õcxé‰8ąÝm óžû)đyĘIŽá2úĸė#äDĢ%j~ÝUđ:^ōœœŲĢý‡äápr'Œĸ+}ðn&·lfƆ0ĻŽLZð0Sø(Ó ĻÖsŠnBmâŲžWāÄ{~™ÄÜGza"ą‡%ӞŽiŽ‹$= Ōôë†SįþZ•Ę�§'qƒ%ˆYþ)•›ÛjÁd#ŽúŅ*Įīė Œ‹ĸčĀuų‰ĒĘ ĸvč4įðFļ PmVøþŠíšO ŦŸ―œ#â^ā[M`Ą&šPĸLbrËRų^éįŦ3ΖŊŋVĐæū―ˆ>ë�éņPó|eđäí“ørĢēą ũ›:@8ėo@ÝĪԘ-ásŊe•b˜Wƒ6i° y―öēCˆÚûĨÞņ=š}DVLËM$šĮg|•æ`d–6H*rŸÎUÃeS›#ŠĄĘ|NÓÖĒ< JxE< /E'­0“*3hgÚ?öŸWö(Ú·ĘDBƒfŽ$žŅSbģŨÏIš5 q'{'+Þī0)$@ŽˆØ5ąø�õŅüOãƒÚÉ~ l;‚ī’Í.dÉnuōÉæs§Þvï}§8 Þ,�ÂD­7M/)7 LÃËw+kīŽ31ï&ØĩĖ~(|=þÖ$ÛþĪŲÝËúĖ&9ģi*5zŋÁ‰øįÁÆ;ðŨĘ:―ŸóŒ8Šĩņa,! -āl%„ęĖôa’ģ<ėô^"Úā!Ąt5[Šú79ӋöN˜›æÉ/bEāQīgī@SĻã”―bđW|/( /?gI8#(‡ãĪ–þ<š†bU·<æãdļDQđ.ĻgÏÞL$t_ŽÃÛkt_T a>•1^á8WÆË†} ïm@ãŊËŧ‹îœxĖs’HØ?;Ln{ŌDð―ýíLÎĢs~vė`ū*ŧĘŧ‚§ÉâÞĨĢnŪ‡…éVÐĪ)M§Ų40ÛÉīMâØ ÛŒOÂ#Ï$ΐCŅÂýøāŲôũˆ§ėíĄr-R Ï}Æ1Šė€€€€€€€€€€á退ŸĶ�õk§5Ļđâ&õękĒ­“ĩÃß —q ‘w>0€D†5X1äĒ>ëõ%96ÓbœvŨûŽČðvĘþë@Žpjb­ÖæÂKģD—‹*čŦĐ{|QhdPļÞq6ųn*Æ&Žk•ņ5PtG~!JÏąJÔĪ $ïļ-M‡ÓÐþŸāK\2ËÁ’û‹ŅWÆv‰ïݰ. ‘ųŠ“ cWėí]XĄ4œGĀm‘öÛļüUįË*q;Ē·îúūp?Į‘7ß‚ȈCŠiē—`"ŏŽóëØÉ{Ž_Ũ7ãĘä‡ĸ}ō\ģÕôf*:ũó$ Ō7”ßþ5ëSīgPęÆDž PˆûŅãy&|v4ģ™ +~[šžĸ=3I '2sÔPaÄdÞL—'é79âÂû) 6dMOėÓgÁNķĶŦöWŋ+`þûIĒŌ§žíē� „åi]|­'đmF4b­3)sūy|š”aœNÝ6\Jļ ;J…~ï zl50 ŅLũķšŲ[åþ^ū†‰Oïų!Ĩåč€jpÞĩJŒĻŪ% ~JļŪ”ęĮ]óWū"&Ëü‹c=ï•DˆMøŊßōč8Ĩ#/+!Ō% lDė䅘AGęEĶũ­>F€Í”˜ž)1ĀĶWWMGr]ÚĘ4âšt,Ļļ…€E|&s€ĩhFÅĒ=L”E!ŲÕíīžÖŽ^}ÐNë—c—st2ÆÜíåŽ ^–ŦÔđoþûÍ)ˆ8l A8ãŽXãęįꘝdŽQ`ėĘ ShéÖ0Q!>ĀÐĀ ˆ$�é õņēŌo�ovø‚Sø:Ų•ļœl€€K“MFÎā8ã°Ûš öQ8íóÞËÚŠd71Ųū  Ą‘Ys1Īž&á‚ĪˆÝ ‰čä#^õšÚ0ũ]x_ųūælAĒ �ž-bRúßUW]3fT‹G„›ŽÄrûĖÄéq'°Ã%ÞÖmC›ëË―}ïä3.b_~MābLĨœĀ(EnėųQï{s °‹:Ų<”ĄËŋŽ�ÚýŨ-Þ$C#'dįRƗÁ`9Ũ (šēĩū8,e:pŅĻí•ߒĻĶqŠx^ûB ØŅókĪaķ5!ՋjyÂÓŅęŋ™w†VĀZrÍûąėlDŽM?4aWmŋ-#Ĩ€gs,đFģđ)ÜiŲ&ļ˜āņ ũ—~RŋƒÎœNÅ―ÉKú-ō—„–‰‰þ.mQīė4ÕŨvsRĢ{é]aŽðÍģNĒKč Īd‘ ä.‚Ýc ‘}xÃj|Ø Tįņ�ŪU{[Tĩß\`Df2šD‘iĨÕGŽüÐúĄÔDÉ!VJōsÔzÁˆ^á€]DD›î>FtÖþ1yŦvôņĸHbÚ0”œ‘)ūŨAeU)Ų3Ņö!õ‚FŽĩÍq†ĐR(ýę|â֚=ģž8ˆß  Áðt|WwAûe`ø;’ƒŪ9ĩ~îHø톌ŊĻŅ$wĮĐ ðÅ%ýÁŲyĀ“öÛ=`?&ímvŧA$ûS'HúĨ|Rژ)óĀWĀS+$fŲ\ž&øŊ8|ðtFŊýC„éį˜<O[sÍ)ËŊ›ˆŦÎÝčsŌzj ŋ7+BOc‰ĢÛ§u$KsŅ›―íQ€§Á]·c‡76öiëÅ"˜áô6î=YļŠ^å‘Ȱ`ž‰OöpHō‰@ŧcf[FCĀt`­čgž_îHfÎĐ5šņ_+C,éíĪ+üÎīO·ÂŧÅČÉVîÞøÏb"V�DVS‹wVôN“Ą)4Fįïėn›Č"·ÓųŦ>Ėŋ§ēeL‡ó!O†*°qdSïÁŠŽĨcŒáŊdhz@Xīĸ„îvnҟ+åŒûo�ĸskđqKūú‡Čę0n&{\*D›ā5Ųt8'fĉð�7>G6”ó{<ų|”XæF ޑŠüvÎ—ĶŽ#+ƒĢí7r“Ųå…Č ē"…éē,X •.―‚·IËödøĒôü$*˜ĩŸēxÞGPV#~+3˜Ūƒ*"dúI-üZ Ģi}i>· nxšX|B%ķĶą‚ģšÁ…ÓïŋÆÃķ ÔvĪëÃENBČ"8õ1ýðKôíņ+‘ĘË:dVÄ ïŸ•Ōœ™0™ Ą‡ÄÔ,-aÍ%YlŽŽh–ŋ^vâėb5ÔS8iBOp”Į*Üáqúš ĒŅĮ3Ð{ ŠĪá{„˜  'ŨIĀ )riŨcéðuĨyGęîņíg éĪÅ(„ivüˆˆ~’ĪŊŸĸXpĀë\59†ŋīüÃíó Ö2YU~žˆ<öÞą^ĐœĀļĀtRR/ðŊKĘįĢßûŽšŅĶÛÎ1-õķ?2€ôå§WqzÅËūú{āŽôÓïĖnãý7Uʁ}Ī€ÜElĻŽEüž #ÄFTd…―ô;2ōˆ‘\ëhų"%îzS ŋŧķĀvęDÅØ:;ŠD2—IÓuåU°ÖS}CۉEšĶÛę$Fũ]ŽīžĀ…Å+ߎEnF î·ÁšĻ6é�›Ĩ T dÆvsÏ =”gŨ7ú’Ëķ§6ÖOˆsÛīū3ŧ؏ķï/ÅĒ5lËgÛ~óo's·élnļę+Ëĸ%MnM6ÆM{”ųũ-}ĸtŒNûHšý*�š’î–S–АĢMye#_ €äŲĪĻ&g•^ōœWfąyÎŊú‰X)f<5Ę|ØŦØí (5#'qųn8Šdėí81ÄnÉ­HÉĖW;ŨXEVžž„Œ”ža8ՊxxˆÁ@“Ī4ž sčēWæ›ģ?Ë­ē+ŽH$æ&y9ŊíŦđw:W‘õ {ĶĮÖV`ÆWgŠ! Í3Žæ°šũ°­š˜Ð šæ{ҘŌėŅ ›d/"ÚieįF$PuģōĨrUŒlsüĒŪčįpÝiР“:ûžXÂo†ųrŧm‚Ÿ/š†^'Ü―…ž‡:>.ßY2ŧøïZ0â(uÍ8Gt0ŋÏī6\ [―ōH8øĀÃ@ĘÁÃ{üžęýšÜ=KÝÎJ%úݔ„H•@ÍAL [fÓč}Šd™C!W5˜�óüķÕĀÎwÍjŨ7Š ųåÎ!g,:ež'ũ. ąļĐŌÓ[š6ÔæFa‹ę@æI›đo@ Ļoecfõī ‹páĘvíģĨm§y Ųųę6Trâ3“ÎÝVšÁéÐCoø-@õU· ŅPŨŠ1™ĸW›Îv!ØE>pĩ €`õ$7nĸ}ÝÝ(Œįž•KN8;˜^yÚB IÞŽ_ą§Š(Aį†ĩūYÁãõ+OÉPZkNýCū۝L™Ũ l[‹rp)íÜóJÁoL ÃQ`3ĸ6ĸ|N:!,ÚÜnþGæ-ģ“K)jþãvP6ÏĨÓX{Ā„ó§#edîy%­`üŦ_#ąžÄœ°_pF dQeߌðYiPJhóEz”~õKŒõín_v(ƒqĘŪģ筈BûĪNŒGčÍUOiÜ#úSp B.íkēüŨ`ų4šŽ‹J―Fų1…gÝ{’ÃÃģAƒĨpIm/ú+ŽÝ1:Ï˘ŧ…H‰öäįĶņZ­ņ"Ā,Yįę š~väŲ&~€(ĐX%`ËC~Ļvqđč ę .�­ ąé Í~ŠV,’_Š#ĸövÐĄZũ­NCŒÝPeM\ú͛ó—Ž3ŧXü‡Zę]{Ųī1ŧÞpfAŨ0R­tŒ3dŽ^túĖ2EЃÅnFZf?]ŽWNðÚcōŽxvļҐãš Ņ{+ ĨĀŠŽD‹ßv Nz$M c ÓĶýNÔ'ÂėRŸ�ššØKÏbæ8`}dŌ'ēĮh w§Œ’Sō :€z#œfr]·šæŋĒÆ0zņD!™ Ķ^8ŋ–ß[ŲŽAao݉Þc‘më=eVóĨjäÖĸy(šfÃ>ģĩŠ_wœTų‚PĄšz]v†]Ģyj^+qÐĸ*†X=RZŨ‡2jƒGېh5tkðÏqÖÆ$ pgâT(™b°9vl%îÕ&#·3=ņ&Ī’zÜg„{j s& k‘XŦČ&.ÆsÅ(!ŽHŌ4.' Ææm[b˜|čËd-‹!Vũ„Wýs›H#Týž8‹z�<xFvéÖŒ”k†6Ō1įĮt_ČŋsõŠÃPŠtą Phžŋ%4õXzi ‡Ð<HĖ4ņŠXĐ[„þĻko€EƒðŪ5-g\öüŒn4‰cščÜ­„īĘÁĸ16äOšōɌ“ks^Ō[<}Úl>ųĪ~'™>ƒīuÅPĸs&þéŸxsČÂ$�ڀũQĐ/ōē‹™r‘\ q”ÂG$.LÖfXŌØ3<wŧ!˜·[J‘ā;ígþmĸj1M—`ķ‘Ä›E-‘ÍmÍ,ŸØÍãFQ§°Ŋ€JŦāú!Ïgė„ėWö™+}õB’>öģ2ŨŊškë°Ðūś)9W1ļΉ‚žUÁØÄÞMģúŊëëķ'ĐÞļúŌvŨõ™ëóퟷ7Ú+Ûãšąë™Ë·ŦĪ]ŋyOåwęyõ |ŲËŨķ'ĩïš ŨghgitGŠõï ӝ[å·ĐŸ9æŦĮ/_~"Ŧ†ßΚČ`$i뇁6Eč\âíäĮŧ0&ģ‡_<ļqiü”‰‹ÁŨq}ÚEÖĶ�>TÍ‚MmšNđ'ïrą%;ŨlIŋíó“ã=ÎĀú85m†7Ãũ›mĒūĩ/+ū/“ũVdJŅĄåK―ÅŨ†ˆþ€‘hÖ)~ßÕ ę-ïšQp”Ģ=ŧąŊf \Tƒž@pÄ…pcT€Ų”åĪXü0w ŠāíÖĮUA6 ™Ŋ…1aĘĀ€Gó=ÖĀŋļĘÍø†;ÝĶauÏ/ĮðĮ}™Ú―Ķ[;°_#ƒ˜ÏhøøãĶųOˆx7ó…°SdšÍI~f2TĘēj0[zᇯ‚ŋ<ļn+ Ž øŨ·WbÓãÉī™a8qĩOQdËß@Ú(QiáîV ÏI=sā{ŋũ9%ņ|{Š―ÜD_=ī›WNŸčA~ČIÔJŒqömĸ5ĉũRĻŪĖobžI>åˆÖĪheDÎÕęĸʇÚpMędŧ§Ū]'žõ\„Â1tk-þ3†A`MĄËę·‹å=Þ"4nā Ī4r0Lĸ/c‡ĸÎ@ÉJęJ>“jYõĮĖ€‘ē=ė°’.ŸýY 04ŪÍ&ņ!6š@"ÉnũĘŠĐ+ßĀyû�ô‹_§ą[ˆåzqy'OÐÓŲĶ}Cĩ%.C‘o<°%§m+‚•ĩ€Faý:“ĸ;ąøV~=Ïîi'Ūu#€Žo—ÉŌëÅēâÜÏĄG–’ÁĘĢDJæ˜QËų-_ļŦž‰?Úæ:el�ũ7QÉÁˆz-]Cnģ€õôYƒH‘d­veŪ|Sg[]ôųŌĀņļ>76›i9S~ae3 ,{V9ŠQŧWĢ~›Ų8ÞūĐëBOb75ØĘžÂGE!3)_ņķ„L‰G_ë迃f OœWQ$°I"rėv‡M!\'8Ú3w†$Bà öĶĢ9ĀįXiróó_Č8.XŅuŊĸCÞüp;ûŸC<ðĐ?j"ÎÍtšc|ĄåÞ°n‘IcyAÂWüó%ŧāĘëĩŸ#nĶU&AIu ‡ð�šO˜xCž \xŲĒEé^üđ‚­úĒ‚J]=íōĒĪð€”�ÜðČņ›rķ” �ÛÖÏĸ/ԎIØ54Įf|9‘žÜN―ĢsâĶĢÖ*Ŧ đ u�yÆŌ$ī”uzw)7EuVĪËŎ}ēÄ(Ũžō­juØÄ3eój•Ûėƒ‡›ŊuåþŦä1ĸzPzĘZū.† dd°ģ„­žHÚ„9�æ( 휨N‰^SSå{‘—Ũ4ß<ë!†ŸĄdøÓŧ45<Ö§vËÕyû[!°\ëéd†QÏ oKOą"ĘŽĮOT=þēðđ–ĮLšŸŦ€č‰žýÃŋS!įÜWꙃčDaÁĀ♇{ƒ†,ūDūÂG*9uinŌTŌg()§ž+n]æiĒïžþ­ ĘĻ1ö–tx+ZŽģ€―­ØņmWåە—/Oš}âYŅRÓĸ)‹äé·QÁJ?Ö™ōįf?o0Tƈ[ÅKŒLŧ…ašŠâ―‹žë%ØšwãA „ĸ"ĪRð։ŽĮG™‹ė.Ü@Ó|þpæŋÉ+‹*0efn ™Ų·Ķw‡0jâ‹ðaų4ĐВ<‘8‰l_‡Œ˜q­Þ`Ņ―mVv[*íP˜ÄŊ;Ýz�û„5"_uų/’ĩöïÖŌrų†wĪĮƒíVgâqPĨäh9ôėĒ�’Žð3mA;ü+q~íŨĶs˜raŪĄSîēGØYúLwRŸ–NFík.ŲĸYQF…ŠĩKņÕđÁKŠe>(]éWedŽŸ6ØeĩĻŠÓt―ÅĢð­ËTTŅĶÂŅ�hĶ’Ķžę›4ēô4̘f›ĩß\/XÃ,y—7"ÁãíŪ;œšíĖņŊ^YĶ/Q xō]oÓåíCąÁĶóėÆĘIĶB°‚ĪƒŸW“1MŸ<I<ÃrRÂ;đøUĐÄÉö‘ÏQqF3Ŧ°þöȩЕŨz9š”ëP˜@ŠEû+eIP>‰aÆßĸ�…Ą0IĒïôÝĻÃ2ļY2ŽqÜ?ĪĪo0I_ũüîÏŪ?—aUâîę;ĸjĒ9O`ŦÂ^~ -âÐÞE‰įõ‡Ög˜~xõib‡}ÎmPȁ:3T6Z@XĘŽÜÛ§…š?ĻĒYúé+{́åšĖÜ#pĮ éŠgä §žĨ^Ëógģþ=―ŰT:Š ]Ó Þ‚5â,sĶ1ēĩk5đäzųĒ}Ōžšg†Ú�ÍĐŦ0Ŧ+Roü­%˰zSՊĀ–>Ðxîj/ÜíšV`ĒīŸ úYb°xįWgŠiĮÛnų[(�ā4ï„MC'\?YVúí*sڋqUðĖ]ĘãAÃuÉ|_DÆÁ ïx‡·„z?ÄvîŽĀŨån/V]ũ4ĸ%―HCÉpÕTķSŲ9Ŧ}5. A* ĒđĐNØōânpáĻeĒ"ĻSģūqgcÖ­°ˆFtđrJœĸ7ÔCkUx/mÕë+Gr~ĩĀŨä§AųÄ|ļ�˜ųþM͉Ɯpd[ôĄÕŽ‚ļ`UÁóŒ‹=üMˆŠŲ°›ÃĄšt„ ՚ÔīVT”­+åĸlšþA‘ôøĒ`Ģ pÞöĸϜP4ÆĶŒ€áģq óĢāî#n īūČïØĩû3$ ;,ËN2„ņw+0ēģņƒE…QĶė<�‚Ĩ‘ g)âXƒ@gAG\ÛÔ^Ū} „Q…o##zÜ0igĒæÃ�^ļyðWõíąnŽ ˊKYg'ĨTßü Ē •kDL›4 ōS”ÎĶų=•EōĨˆä†Ų)š•(B�sÎ\&NÉšûyÓéýdGāEīĀj?pÏČŋžgÃđí$ĨŌĐŪĀŦˆ– däĄŸ3ļjŲŌU—ÂęjŊÐĖŦ CB#l’ÉX Ž€&jķ–MÔ+ŽU=ČkaģÏp-üč7į2ú'ŽjäßũqÍ8·wzØÞÜÉ‹ŠŋNÜ;8ėýË;LߜGŊœü=!lŧ…yxĘkoZŅôÓ?›b<ķųVãųEq„ÁF· ]aŽi(b”`ÚđĻsąb;#ī6Ä'ÓÂ@xãáMŦ`ÃĢēŌ@°đ{EÂ#ëzK(ē oÔSž'ú-7Q—L ;g~(aē8FMEVŪ1ƒË<Y”éāe͐9ŧ)ˆœ‰Óđ(ø™KĀÓ%eÁbō@ĘÏ s23=ŧVâŧžĢ^ÁÔ_ĪPåŋÁI|tÞ6“N0Ļļs97ēņōSIÍ,nįŦ Äļ…ÄOlGia0j&ƒ(Ÿcâ"ÎUlcáquJPĸDŪkéJ&ÖļĘü,c@lĻļ­ å7"Įæķ!ĖvŅPÃaŌíü•„áü%õ’ĐmLð”ŲHíXËͧ~F§"ĀšxÆŧŲ ęøēˆ+ČŌ―f�/‹ĪąĖ‚sbw Ļf?œčlv)‰œę·šØä EoĩÞ4ĸ*đ­Á Q ]ēŋ'šúW.ėžËw> Ķģĸ@�‚=ÅqJŌ›įķõ‰ˆĨo‰ģ‹ûïŌ("`ļ‘36EŒŅÜ:ÚexĒ*Ōp�}ûķ pĪ—~YCY- îwV{Ŋpæ22O�uâŊ’LâåāGČ+Â`Vē$ÏNe7đėDZ”ï†� 'ąĪ(88ÔÖÚ%ë§9ęļxk|<+–v›uĻÐ ^){Ĩ(t–A·óQLv ýÖ-OⰉ•éƒøAå øðUõ;y*ŨÐÃPQZ—ÓœMŅcHĀ}ãCSžĢ6å�čĸāޜ€ų:ô!Dš kļ|šĖxb`m&ðLÄN0_ wgMāSæ†Mv‘õ6ˆŊęÁaņ>'Ü`ĀĶacčŊ/3'°Pø―úÍĪč ,Fëõd3ŦOýŠ)|1Á݃ŋ†ķÏ<‰7A‰$ėÜíZNaPļÂôõĒĢJžóó?Đ <į:m­ŦīČtÉČŋYƒ…ōĻ­T=Ģâ1óqm(šīü–$f1ÞSzÖiéÞø‡ŌFb<&όē+ÏÆüå―å &°ģ-ču"ó‡0#ósvė~wtŒk”Ī’P>'ˆåՆSBũÅ7œōí !mR~Ôĸa1ēŪ”mvð),Ҝƒ Mŋ7[�ūymPL"-ĩČ2›°ï­‰“ŌK&pė1L*kŲ“ĸ!Åh.OĻ*§œ%pz§í]ãX^ĪĨsÛVgMœÓĄ”s†,ýĻ›šÁ Æę;ï·ĻgŲÖĢt&Ė–@h{ļh|#Įtô3ZŅ5ŪųK�%FKČŽÅæ•ū„ ũoÁ�8SęâEkėžgf ú '!ĻüŽĸ2ËT}öi?8vđ„|ß1tVFđYũĘŅa–L2ļäIŒq‚ęĮ·7Ķð<Â:š0ö ôÔÁa€|ÚïÚŲšNQą<ļ·{Mc.OĪžk·‡•\Ÿg"$)ðEúšxõtÏëĒ nōJgc\Qln2e\6Ģ�Ú#R1˜ Vl.Š&IãÏËĨNmâ;j9~Ņ”‹Į,(ŽBÃ{ž„ĩĖ\Ģ5€Ģi1k�”· øė^dýÖ…ę%Fô^šPƒ;6Ú§АËŧ͈‚Ŧ;įþė\DŲ}9ÔQuĒšSĮ°íëōš2ÔýxMķg*íiRDŒæs%ÔåðÏšķ ÝąūnŋOęøĩxpÐŊß){;sAd>6ĩ”šRiŲ€‚üæ‰aš—:LBĐ{ß§NAąmųkāŅҰ+" )Z’*6ócÛ\ū}îﯕ­ĮEsoݰÆ/ĮlâKįƒiĶĀýtIZKÞ[ûkĪ`cŅNĄ<—(°ÁHD߈/5v"ī™ŧÅĮ!\ÎėulƒļƒÆš!ēFĘqÜãōQōœš„Ģ‘Î“zĻQîy@FÜŨĢßRŸN{ĀH~ĨÁ3ĮAČ#e ,ČåÉú/ƒ Đ įļÏšˆ„kíG;ÛýËCŽ‚NĘģ|üŽ–—CCŒ`n!ų诐0‚IĄïu°:ėm~šĻģ―7ĩBdØąJšö/yk Īčˆë I`Ÿp=”įņôÃëä~āėnŨĻŌĀ*ėŋƒ=8xú25DŪÕŨOËŅô9 ædZ*Ą™k|ĻL`fHÉ2<ÏSdžî IÄĒyøB™ųz `ĸH‚ô$ß_›NÏebK.˰ævŋõÐ:ÓĪFÛ1lDïē‹ëk ?ÆŽÞ ĐXņ―ežGÄÎĻ0%BBĀ“Üį [NDŠŅĒvŸĐÁõ˜%‚äÉþ%?^UÞPnәk‡oHĻ\™ÖU0kqĐ2æøxąX Ąbá•Ū*Ų“&­õņ`uîazz„ï‚ÎLEĮVĮöðôŨŪ ŧIßa(JČ(n– ē ÆyŠhš}<šúÛĨT~HĀ ž–n> 8Å}]‚ ŅÓ~á{/OjEßA|˜qŸõ|ĻwLĘīÎï- u#›āŦáŽĸ ™k<‹ŅK|—VЋõ& Ņá|Ž=ĄŽGžAôc’õU’VG„VĶBWš‰1-~|„]ʉMŒlŦSųĪĪ’Ti†ląœeHš ôI…4$/Ę1 éåÔ;ĨÄ"Ņß</ãPÏģôþLĩ™äÛnģ+Ä1éڇ;€åüӕį%DŠÏCfņxlĄ…žïc &žĖīĢ‚qVøu/ŋũ①č—Aįė]ZŅiZčķ ÅåÉĶĩEŲį.ϰÍu ZÏUÞĐ;O ‚^0Ŋ`Č.?(‡ŧũūųŽė@ģD.+Åļš„‰ŋ ”øŋą:ĸ96kbï)s6ã“Ý]’˜RÏøðBt%MG`ū―Ļ֘UĐŦ> OpĨ/ h —[)ˆl‹cåŪeŅu!z,æ“6.5KŲ&‹-―óvĩ+ 0Ŋmj°1üĶJûœ‹XÞÏÄ0’x N<uN.‚ĐŲ2BUÝHaUŽūãŽÆ[î5ÍÅX}û·"ĻúęÕ§Įþŋ^&žŸ°xíÍ?ö rcøÍH)܄4ėîŪ-Ä|:pųæ F,ó*( dpŽ'Û·ž–Ö°4"•툍ķm 0%Ų…°ï8š[=!ę$JV-)/č”9G9TŦ)ŽnGĐÖü>š.K[ĢėlHÕC”/JopNHLNóÂså–Pæđ⨖”ÜÆ  0ÄyËâėôģ<EMrl6Hþz ûÚ[ēûð…ÛÓjŋų_ú•Ņm:•°áŊöĐü·hf9tjk” „r·ņÃĢ+ūü뇷‹…īPéė…ũäÂԙÁqËđh=DČwĸJÞþæ˜<`žpÃRóÃÔx؏“/ĒÎ8™@ĘÞ|z>ø‘…íHq8 AĢ6Ođāɘ<‘NAgeôōĐGM3ĢTZ ŧ0Ņũ6ë\øwĪ t‘õ€†ĖČšü.šđÅ:\ē’C8a{dXoZ˜1ÁÝķ—ũĢ9vŊrjŅĄīTRdQ@âÐĮ* ėóĀ/@þ$šžū/wž_К/Š$U’āÛČ\QX ![âĐ.€Â=0lL„ Ū [ž*īũ\GÚĶcĖBÆāßHzZ)vĩMmÎrÚ,kDvP-CąFüų,ÞĒlÎņ‘îÔYޑžrĨ‰Ï–1„öɀĢ j2õÄŌ‘ÃÖŋöĖzT‹ëpŅ·ß…ĖLïŨÓÐĢ\HMÄ―Áoę\quīó3PTicpļÏd'e:˜XŦĩ/…õÜŋzÕĖBu1ĨpšŋmäēęÚĮÞ/Ø14–ØąVēęωMŨÁևZ~Øój![jw‹h:…’‰D<{šāKQE, š/Iéh6.N!°šĘ›õlƒž4A·ð&C[Ĩû8+Q’ÂNI_JÔØbë·a·ņ=ĶEĨÐû4á0ÂEg!†ģŊü'‰€ð†UóPĖÁەNŌFAGSÎÂĸ]Œ\)ŽÅüIũXâþķj/ų a %öî`<—Õj‚Z§$’I$ŧ™c-’›Y•ũ'<Ō|p}ŽØ:ųö%pÐŨęļl\ˆÃŦÜõ„ĸHžAŦ]/ÛY~}ūŨÁɈúáät‘ŋWŨ5ålk?noÁČíSî)šf§Gķ[û§‹;ðųÏžŠüð!ðjú…ø ąžÝõōĮŽÔfŽŨRĖk )Z―J%éëéXßgŠ ųŽzN0}‹ĩ§ė{^ŪĮž@”VA)<u]{†xŠō‚fŪū„KxÂ6|nÎÖĮe9$―fôëŌðeÃĸRŊUķŠ‹íßōÆóƒÂxøí33üųšg˜™ķŅk– b<Hö 6ō…ņO†äpĮ1üäījSgØô{saĐVŦ^a·.rļ­rŽ}]ÂxdLļÄe{ūéKŧšøpYI~łáęWOßÃjKĩ|ęē˜Fy>YÖ ĐdŸĢ0!•Š*Ą„]N6ĸĸLŽ1ęī~pq'•NĨiīŠ]ÂEÉā%`5Ųqž(°ļ,đåđՒąD/SīÚĨø4ÜÍĘڗ {A+ĘÎ?DĢāØ*JQEŦ%j“ĸ+—ôĄöĮĸ}úQ4ápQ`C–XéÛ·Å.ĒwÍŲ]˜Ïí`<†xyä=6Tųb^KĪ-īķ˟B+#”Ó†FėKs&LĪĢÖĩ/•Ė·Ŧ°S5ûž ›&ŅŅ<ĸÕ-Æ&ē&ĖKl‡Ģku1 ĢuđédŲlčB§ĖŪā%Jsę:ėākY,é‰UÆI†GP6Ųæ2·•-]Û7ĢÞ'ĩ(-5Ōģ>HŽÏpßzŦÓn›ŅJ)ÞqÚo ƒ!fL9~Hˆę?ãl ŲãĒI[äĢ)äZšƒˆâocÉqũԟPá_d›q.SCķ]݇*m[ËL�歔ŨuuŧĪüĮåyáØ8 M1Kž“ÛÄÅaœ~3œĻĻ–\ŧŽ3ŠÂ‡ExFũŨ#ģú4až5Æ-ŲĐ09O‰;?2ČĘĪĻb"-I|ë*VB e.þžœœu~TæaĶ‚}kŌ–#ķE ŽAozôT­ÍmjŒŨ§“É2XEÜ}Õ―›.ŅĖÆãD/DDÞóŨŧkuĸSų_‹JÝ)zŨÆB(Ārû^EÅkoüôcfŪ‡ ­T!‹öƒfIþ>ð&ä(—ÐÜ!ü.Yw;v·Į‡…9ŲČąéLâ#vÂ(óq’Ų’ŅjIāëOę‰x傄UL‡ÍČC’[hh[BīA@ãeĘÐbÝšjHS=jĩŌöIčėņdö鞝 8ÕŪ@ŋSķŦtđ F}ŸPŦœJí`m:ĒÞn—JÛ9Ęū'€ČēFõęD-HÍgÏ ð’šĶŧÃ(ZRýA%XĒŅ‚5›Æ“L[ēŦUë$žĖjefeYwXI˔ķökŋ-Üg9Hod{€ŋ %Šö.B(āĩN†Uå\CUZ‰-.ó›WŸF>;HEķq… |—éöĶï&ĶŌâēļ…ûFß0ķ‹ĸ|iÃhø?óûøíþ!sh_GЃ™―ßĀH€―NĘA$é§ÏH“+Ŋ›aÓāˆđ�]ü>oÁ[Ɏ”0ÓÜY•Mȇ€§‹―Ĩv’É^žIūĀ5Ä(CŌ”Ŧ°‡I˜ ŋŽŪŠYã%”ö%OĪ þhíTfŸ8ņÄ-ČĘBAë ™ókĐÔā5 ͰБ}9MžÃá VXŌ§EŸ?žáXœJC2Š5RI ýëE˜aļŽ0üæ~S(ý"LoÂâŲuūï,ūAwīQFŽšGÄg4F°JÏöÝh3}i_FۚÄÃļęv5ā�ŒL›Āļ7ĪĢb5Ą;‰Øk€úΐ Œ0G=Þ'H[oWŠ5tŧÆĒ]Æ@0-fŽåýÅHÂÖ?Ð#ĨKTÁ~ŊП ”;,ų’·â]$Ē?/[+- ŋ�đ1ļÄÔ R‹ ZņÞ.ÚŪĄŦvŠ%dŋ)Z§­7jŸÅĻį"s %ųpČ#jį�Ú+Ԙô Æwæ2d‘ĮMu2―@^’ƒŊĮó+ ‰Œ?åc“HŅŨqÍĀč/‘.w� ũ(ęgnÞūþ,ëeLŽ#w‹­kW hË ][XÝÕoNå:ģ:pÉ}æá^ņŸ€ˆ–ĖʋTË(ëdIApŠÕ™°�֌HRø1“ƒ=nī–^o—"V:Ðđ…ËLÆ­;pWA ĸJŠÂ[6Py `Ŋ{Z‡îÖŧNõ—/-ŸPGtČ䧜-$Ķ†ĢšôTĢo›E€ß›“”V–F=Â,zD3t0öcߓĻe$œį9Îa?"øy `-,R―GĘœæeÆeŦžÖO†°\Á—y�éb ™U4tËĐD§0›œîvņčåÃÆPšyr Ųm95†j‹NÉB _―Ŋk æĢAĶÂ)öï25ð Ü ÖE1nn•ŧĀÓ@‹,Ø―ÐāHeD·Å[ŸĀäü œ“3― ‘.Ā֔ķlžŠÓē{�‚^Ô@}ЈõIB&{D> ūؔPÜGú7݅> 4ĮÖVd–öTî2Ę|ŠĄąpƒ0ąˆV/nƒGŲĀGšAh“#p%ī'tĪZē: þAČpK9qÞtú‰˜ØŲW5å$=„ÛZRl·m9îŪPÃņzF$˜WžžđÂĸ)ó(HĖËŋŸ5o(Č"@~ĒüÖú5ÖG;t]’šÂō`{ĐÏô�j―濨•ó•ÍxČô Įos Û(ŦAÍdÐæŽ1ŸuLŲ‚" L�ˆĖé)>sÔ(–Je t/1ÔÖyõd/āö‹Õš8Îrņh2oþ/<?åØQ•=+ïî=á$z‹ĄÕø—Î.eäË+ýÄ-(Dø~vnÝų+út­)›|°'ŧ -ð=ûÂââO™-§9[ ―8ôŠ}>z“mÃŅiņī­Óózų(ĩ―"ĒÐ(ëĻ3—<Ąš> DFMvóRō‰^Fp*}l$F&šŋ•ŠË2(†nvIF’iml†™ĢLŲTÎ"GjÚ]Į}M{ŠÁSˆƒJąīwĸVnþ|zķÏŲ”Ū^_ĩlYg ŦÐX�ÅdDÁėRīŅ „öžĐŅÜéÝ­ø‚Ýš‡áÖa$DŽblaqu{D;I7UFĖÁA˕î·ÔúP�ēû7}eZ—­mÚ_ bÜŪøÍ­v0Í4É*―qÐķ•ęÝķC,"ŲÛô€―ž°špčã#Ũ§Ņ€:Õ;DžDĸģÝqX%‰BäŊü NF†qDxJ‚Å20Ú./0åƒŲvúÅCģ^!Í#ĢÝžÜûÃįbŽĄkų݆"˜;åH„ŅųAŽzn<üJåt0õeĻīcÔrŽ+\:yÄ_ØuÎj7þŸ;ÆwNmø ,Ž`mz”s^ ?-ƒ†GRėą―p†$t‡„†ZŽÝÏ‹ĐŠ ,:CN/€0–ÚP”dãŽhŊæ-–ųČ đÝ·—žýtýWÎ(g<æ/ŠÄ3°6Ïā'_ŦŊņ ˘‰ É)â,Œ›ôDdÉ�—:"‚Ôđߕï,.‚ōÖRæŌíūũĀ'ŽP`Ęq―vIzŨtl^IRŋEô7ūŧ–ë5zŧ―!AĻŌrIψ‰ GNˆÂĀ Û:Bā3ĪdŒSō íw�GĪ)?iÝÁpïÉäíÅüøþi4zÛi°°ë!ģ‚hsýqTČlåXH@æx7`ũÐÜĩ“PŨ1}`ė h˜ĢĨþ”ßâÁxĮ�éļëØĒŠ M" ,ähī‚ ˜þW<^æŠâ̐ŽNN{M|[)„}ĨėļōwLF ß ‚]`Ļōī/đ D'ø&å/!ÎęōÛ(Ũ(þėK­%if\f{ūtų_Ļ bō0Ļņ —?^ýĘ\€9V SŽ?ØĪÂv+EÝ[ŧbjų;Óđ"S֍z.ā—núšÍų‹X”SÃz?eYʍˆsaÍ&ã[Ŋ}ÄôUŦ&ōuēˆÕŸW`đę‡ Þ€ĶÆēÐûW°­[köĶaģܕ™ÄĀĀâ!û‰šĘD�Ų9?}&órÍ]öaâ @qųŦúƜ<Ε둗ŠÓĨŸšŠ(1åHŒí|‰þ9‚õýļsģïŸßVÛQ+%˜.ęr<â”J^Ž)ĢÔWY@snĩÅwõØ5:―·Ō4f|ûM Ņ8[2Ø üD+ĘVDãá° ØˆČėĒÜĒMTIýŨó–ŠŸÓ=焯72 ĸy‡cÚ!YØ—ĐžpCÃZ`Ū3hēœŧį›dƕč†Ŧé ôû|$§ó”ä%Zŧ„ÉXÐ^š3yōâ7O^Ÿë4;KČæĢ)ókPÂ]Ūî­Í-‹#x暉5mQÖIlūÂūRā)ö݃Ze1ðČh‡“ÛwLüžØxŅlt·nÂ―+ũū…VÉėØÄÃåU Ũ`OTÚyG,/é(SI{U-―O–ũs8rƒówIäĢgMÄjBy}ʀ‚#DŽôÏ'âŽģj•‚ž pĪ·ŽŠĖQ\žĘ8PÞ|_?ķ6 ‹ũHjFÚ=ĖÁ/QÓĸhŨt ^^”zópüī§d, ÅÁZĪQĸ äûŒGdWãĢ?đĻÞĻâ—ä/”/ôŽ %…ģ$vŽ}ÕŪYéÛo@GÔÎ^ūþ|,ĐGų{’/iŋĩR?SˆČXzœæģ…“°|˂~NðÕxfýā’ïëv"ĢGݟ9H(ää€ó(Ý*n. ЉīwĐũZ%—ÆŲ7ó …Ą ķŨŌF‘>ÚÎdRšį·SÆÁŦŲŌžžbíRÏ ĄÛ|á迁Ķ !‚Ę :ðú8K$ĐâLÆwðĢcæHîßžŲ †ŒÚã§GXŨ@ūáZ4ĄSZR”O,ÓEČ'W “KwÏ=Z—ãÖ˅$–QįŨ(aãjíĸũ…4dëþŧ/Ķ5~ļXþņFgYøŸúUÞŠXæā_*YhóËp†·Ĩ—ÔۜĄ1ŪqæęTéɃ<`š$CÛ;“ÖžĖø4ĢūeŨšąÅuؐ,é·1ØĪøđVžS'~`]ˆZ™ÔF[J\Ÿƒųė†%_{TõíĶÄGm‡‰đÖ}ņ-ŲžýÜÉ„ Ų‰ĨÚB*äąÄ’ķˆëæYį+[ėš,?ž@Éûœå uĸė&j�ŦaąYäõíršmRæÖó& —*·@š-_yú0pWš|ŧPøjîTƚ& ž1ˆæ­)ˆvėh=Y4ķؚUĐŒ  ŸŲ:j&LÚXŅøéęÐđ~žïŸ Ļ%€kŸh–GÁrqM)ûōpÏĒŽ„*_üŽŽJ‰O1$>Éą”q/Ŋýk“ņ2‘žÃĒ,…Øģ႐hMô^zK<ÄDÄ= ēĀCĻ=lāëÚSe7å―ÐuúúGŸ;5HßÓį0ƒfÜāēųUĀ-Cä0û[0“LDV _<:·Ž*6æe#Ėōfųr3Aé'š”[ųųJ‡ŸĮ&ø4x°šÁ―ŽVđtŽmtÔÁä~W‡› +īxôQŊ˜|bQEvH6 ī:·Í9á}K‡ 1ŧ §Ös!ķąû’ Ô*‹ŽXHâ ũĶ‘bxs0ČËú%õ••GÛi\ō>—žŦÂmQ:r§ ·đũ#ķkFĻŋah åk@hoģ:†elŌnū aUðkoĨž‡ úžR?đvśCļŪnE~ÔÝLĄöäĩģRĶažʎqõ9ĒMxžąR=0ĮįE‰Fá§šFK(>1ϘL‡„ÉŪąø\Čl“ßJ’U]éGïu*ú#=ęb;k:aϋ4’ēVõ‘ këÕxH‰–žGÆ4ūE)H‰ŠĄƒęfŋÝčŸ ƒö‚ãã!šRŒ‚4‰k$,C‹)3ĮYSbžė)Í<ëÜ3›SßDËø)lK5ö=vÉÖSY6âĒzÜoUg<Bō‰ŠŪąÏ-5ÂkÅŌŽMđóŽŠoŦNË—Ę øX SîĨ O þMž`„ÓeHÅLþøIšՏOÆíŽŅĐÍ5Ļüô6.%ÆUĸKtDgý8ia|ÝàSsŨŨΘ'›ÏbiaVŸŧl=ŸA­gR4Ðņ†Ģąž”ŌĶūŠčqÓÃÁ †‰NLØS#)ĘUʑzŲ:|r_Kû„-\Ĩ)uLDp-RoČzJÎÃÄÚĨæäcHčĘ�yŠM˜Āœô(—ԏ•Šņc$레‡·•8xíĻ#ĮwEd\Ņīę@M;„ãýIWð…r;ŠÁJ/W`ņ nĮkëĪTđ3냚íÂmōįA.e—tģú”D\eŌÓ~ÝL{Ķ<bhĖ_ĩÔÐx‡6Þĸ0V§û?ÏÞ§(Ÿõđ!Qi1ÍņŋyÃ~'æË]Ö;}\Ԃæ1L'øöxbÞJ[�r0Ļ́�ÃĻVķ&æj:ßÕ2ž°–Æ(ëž\?sl„ÝîvõuË'čŅ–ŦĀ7eoM‹"[”ŠUī&æƒáŨ~ÂüDƒŽ˜ģčSIÝŠčŌ™ÁK'/ŲÍ_ķéĀíŅ—ģŌ%|*ÝųOÓĨzŨ―ŠUb=―iį}Q;ønĀžžĻĶz°'ˆžĢĀšĨG(>Æz|† ˆųËŌ8óCĐáSVKëŧ"_ˆé^uœP(4ö  2ÞĨ%ՒōE~ņ8ß$<€€ŌJä(„dô.ƒ‘Į=•:›iÍĀFô„ēlTäôýĄZÐĨØ�:>ŧHôWë"4NŠ?fßl_ƒ“þÜ$qkˆB™MH7ŋü,}Įä/ŅV4MôdáčÛ⃐~%ßЁ;ð/€õĶh "•ü,õœÝÎÕ%1ŊvP.ÓJ ÞáwVrP?˜ƒ/†ŪqØÚQāó5ŧ[?žŽžƒĪ-Âd7ąÖs\ 8Ahę2Ė―Ž…ČmÄĻË ÓäŲ#ˆŪ"ßkЙĻō/ŋð†=‡ŒĀå/*úEŊ™į—Ëyęōųš\'^ŲMˆŸîiR/ÆÞ sŊ‘•Y-Æ^ŒÃ~˜ķ™ÃręÐú,X•jâ\!N,>I[CŦY5öü0™† ĶcҟoæĘø@ØŠ˜Ų"튚€šWø›‡—‡ĪÛį7H&šlI\T”z°VĒY}ŋŦöļĀ=―^­oģVŠ ŋĨĶĶ} Đ'ĪŅ―aēHÐmͰâb"%ęt:—å#ˆRõm߄æÝYDŅi"ĻJčw‰{ ôĘY!}"dzÕîe "ôAšœÖӠϙ|šúáhãc d‘åę‘CæÉü:‡"%h åÁeGþÕí^ß™ß0žßéģŽ„RáÄj7Îęj^šĀ€�Ā�€Ā�€€€Ā@€€€Ā�€�ÔʋÍđŠéEŽģÔvÃäÝð|?FßŌ@ĸ ŌÕŲ#uӗ-ÏÉĢvũYøN‘DÆÆ5X*Ũåjŋ’}<OåWąŽ?j> –ƒš!þÏ01Ņ4ãÛ?ÆÅ øyUŦ‘+Nã ü r°”å ōa&˧—‘ĻdĶ.î~%Č,ã|aT&KyW„ï)UDoØŨaé7|ĩýNē˜mL4õf‰ •Ī˜ aâiĀPléö•B|q·šËá%f9ŧGŽúý…=ūœ ‰’ZÆŦmüąvįt"ЋPr|2AZ~Đ/žĐŨÆÖĢeÍNxjg25ÅWÔ 'ûƒ ę•%ú5`^• ÞŦábĨՃ$Āˈâ'l„péšxÂĐ ™."úŲÖWe”“SFœ^ē’Ėí“JĒ[·üÔÏ[ÃÂïlĐĶ=ĐWãë”B wŽYŠ]Č(Åĸ|iCÔéw’]Ôr-ŠA7nŗ{$ÃzãįĩŽ‹w‘~ŨįŪe�<‘óßæĒŧļˆ(v!íųŨŠd9ÁĖĪ”S‰ÝC{ÔZþ―™Ï\KW7ħ—gD3ÚŅNįÖĖž'ĶóürDĸ/|æJžčŧĩ-Sū·ßģ肒ųöCWÉåI'īČ+óãQfÃóty‰ČíņÄōØn.DtCĢUŽÍ Yɍþ!ŽÆyJrå)Ũ}<æ–ÉrŦ Pč-m>#D~ú­ Ï@6ßļ—;ō8ß―ĘŊéÜļÜÔķķ3ŋóCÞaP4,ÁÏCmĀĻA4Óī  Ä>f]įūLà Ē@ņļ…ĐóÆ BJ0Ūúæ9�<–ŊßLs„ͰôäŽ[ŅRėžksÞîäĻRZ œ$Ճl`°ŋĨ4ōĢ?Žëv"rhĪt 9X>Ж`Ģ’!Š-Q.”Ē*{%†d H‰ĢYp\Ē ŊŪ8}›Ÿ{ÆSÄЎķ B›JC*š §Þ~―0ŊdB–á·įÉ-ŧųė(aÆ)įSžïÜϖÝ_�ÖF…|7ųW Ÿ”Ųˆ– €ĻiŸóķž1éogjúYEwŊwŒĮC ü– TâXđŸĮSdŧ)Y˜úŠOđŒĻĪ-CW3jg(>iIÍį,“ÚįSvÅz)o[ ôéyJgŠũÁÜŨr^Af6� šøõG8dĄĄÍ­-™üĶ|Žþ|ŠizũLĢš| ,••Ä�Ŋ’Nx .›ģtã‹ģüy‡i‘·;ĀĶΜƁiBč°þí•æ9Čc†"kÕÎĀ#~ÓlSTt’|#ęęÉlF‚øãœÆ/›ŅŽBYåïĢ9ÛaŊ/ąäĮïßīJ§CšŦÕ}|ÝÓ6UĩUP_˜YįĸAæ�X.A6z+g%éœvl0e A<€E'Ðl“(,nŽā>Å0oWĸbgŧKNï5$Ģï―ČÏ!FļŠ›•šÛšôŅO°ņŋé‰6é)ã_ÔaÝpįFŽ<˜ÃOØýū)ėßãøēÓ4Ÿî ôx]Ņ _^ŋģMē*Uڜð>ę–ĒDËCå+Į0 lÄ%\ũ“Øu);b%Æ(2fŲuÂÜ-ëČ\Ã|Pŧ:ëÔŪôSÁû]HÃōįđ§Ė‚Z[ßt™,Ú/9Wáń&ĮäH, ҇ Ih€wYõ„IÖĘ }úÅČ2CL5ē‚Z]“5w3“ô0üŠÚ€˜!ĸnþßJ‡Ð�1Î?IƒĄŊΚæ.{í38sšŨ–ļ&Tģa–zýÜPA`ÏKowð·ýõ7ø}ɊOpŽ`rŪjĨŌØīŧ@ĖkĘÅwU“0!‚šÅ‰@•ÚąËQÍG8Ghϊwîļ%i>ĘĶķÏdĸkÕ ‚W -č·“)D<°‰ûĮfp‘ÅwmGĮóé…Dĸg9Úéįo™+‡æ‰QčBcȜÖýÄų û˰Ü" ”Í>yÅf2[d˜•Ę8}ō|y*jlFôÝÖÉ>‘ˆáāÚÄŲ9‚oČąQ6Ÿ+pl5õq}1YÄĪæÄIWO ^Ī^ic_c―/,|ŠŨŨýg)՟Îgēņ° iĸ&ā‡Š3aÄqe9/åO.Ö„ãëpÏÔēĻ8ĸœC]%m—’ €ÓTĨŠ%îv­T-[‚Ó_šĶÂnÕ^BÆ'^ū KĒļÉ Ýˆ5Ž—Ķ>Ā^ÐÄAßÓF736TPŨ}PŽéuĢ"jDøÄåö>…4Iâü‹�}eÛĮ―đ�t—ķûD–øļæúKņĪĻ—›Žýƒ[Æ45뚆fg`DåÞo1…lßųō0Ėä4$-›ú!―ޑ%9Æ–‚Vâ!·ũŧØ-FfO /_‚/Îð$û:§“åG] ÉĶļ ;―ӋXeD%!ĻÛņ―ĘŽ&81Ņ_Ÿî·ČČÄīå(Ëôm\cËwöÆ7ųË3ˆŅÞNžGޟ=Qx*Gō!ÚӒę,ï:YāÄE9-―Ԁ$·ü`5ðjŨ“kØŦų#57ýq�söA@W’ė[xóxūŠē―‰„Qũև4q™ á·ĀV fNæJŽšF‹­Zŧ4Kúd‰ųÅ@<―ĖŨžnđ"fâWdb7îÝ;?Ā›āx åĩ:S õęBĢzB§ā(đnü–Ũ3ļw–ņ~̙ȑÜļCÛķm-ņisâŌ2Ä;‹rôfôĨ/_/“ęÍũ`­{!ņ„ŊũĀ ž› Îërïm&ŋŒŒņBWŪĢČĻI{t#mųáŨņšéÔVĘĒúæ^Ū@BāOːkðÕīnT8\ĮÏ,“>â�ŽäåEĀØåe§Zŋ§ˆ ’]”up)ĨŧwPüÕP•“ö;>›"ÞÉ{ĮSéŋ uPâÁwÂŽč…Šӛž8ðwčņ*ØëœD< ųvBŌŦ0âýŧŸ:ĐdR6ĻYģ0":äm9a6 ûÐ"Š'‘O]—ę8Ļ)Ī>ĪÏÞ7ōžc5ëÎ|LŒ9mąĀ,UCo\HĐCsļ'$ ĀU;GÜ'ög�ĸ[8đ(iĸkEĻ›áÏîyŽ…k íŽð•‘VÕĘÖqÝšûO^žtX‰++ķ̧ũđ "’ÓːĐæRĮÜb‰Éhƒoýø`ïę­RKĻÖĘûp`UÅų‘mĐí\+ŧq?,ņrƒĖdp2PôD/—ģ•óĮ0+;6œ!‘–E[0ąårŸ<ÜÆj§FŨø==\ÝŧØjN.āąkk’8Ī!d‰&›uēOG}~û€ËĘÚ(Hρu“ōövąį)Öã$}óІ­ûQï°v‚,˜S†ųJН–/qø tæģāĮŽd‰č{ģƚ"=}ÄĖŨ‘%ŒoMĖø:ķwląÄ2ęŽ`Ö1šˆŽžåC5,ĪH…Oyā‡ŦÐt -,™#v…ĄNԘģ1$ZD^æ,ē-’øūŊš0-\ę,øÔë=7č}øģ ûéĸnï}ÕaėGé\æ]5Ū–IŨ Eėį&8ëÏ·)?’ö ī>ũaŦõ<$|đíĨNÆ‹'|=aŅŠi†l�Ģz8í™Ũ"Ũ―É4Möð93!~ũTŅž íŸŌō°šWĘiný‹“(Ûs§ŽH=§öïåƒĐØĀ€�€���|;wÃßß\|6‡Ą“~ ü<øt§āšŋäü>Ą|:9ðt›áëĮÁԐ†[M+úc#”īSŋmnėų‹ųÃaŨ(ýüăŦî6Ģ<1ąôBøD*ųn�ZVäL PŧԌūtCÖ@DŅ$cũŪOGįÜ}sĘPŠķu„öŦSÛ^M(Ą YžŪßĩzh~Ė`’Č3bz‚DXr›‹ã|>ÐÃNŠŪž k!MļӊņZk}― ­ˆeR)f Î/IýēSÜ ą<Örälô‚™­,éqj=Í#_0Ŋë†ä‘FHôÂR=pČŨ:œQNTÅÂĨ•‹‘œþ•7ĖAÉ\Íjęōýnjåu)tkŅ>ÚĒnÞ<Īéšŋ-įĩP8Ü�į4ZŜ<åÏŠžĄLĄ$Ķ%Æ î‚<ö'ˆđ€–9œpā&]՜!:ðėӉFMy1íjpóSí8oGЎē‚+ī2+mÖūĖ ]Ë&å|!sýdōƒošPó0vŪxĘÅyQ[ÕÕEZȌ9†þt—CA[ožå™š|û”aX•_É~cŅ ËŸÝ5ÄX ‹€BuJ%ŅUZ9Ÿ|ēŧH893N,˜eūUū\!ŪJĨŲ úþʏ Ā)æRIxdo+óŋ9˧pa ŒZŽ#—!kĨæļݗB%ĻŠæËĮėԝLÍ<TČp�dÞ„ČöˆäĘī^ŸJú<%D%ŸYdšÚ, ĩ#Û(Ž>áKĀå6j<ĐÚ]4éÉ"úÃŊEq iėič>4<ûŋ9ūCĻŽILK‹/hþmŦ7ōč—YŲÝŽNžX"ðŠ&’�ä,F`"!ĨũŊĨY`ŸÅEme^ƒ<˜Ž=ÃîAŠ`†âĮō·œ‘5f)ïebōÎë2Ė;TpQ mƒk”žŅJ\‚“BB>> 7a…ōÐą Ũwļ›T·ļ’ÚYFšUkÐõíä"Đød3• 6mØš+kĩGõTNīĐ|“�žŨĒ „kšUrŠ\·ŪË]NĻ 0úÆŋ.KydKÚ^žĸ;#xŽįĘZ:„č·î<`å+%ū#m=iŽėĀJ? :Ŧ44/ŋpķhqŪ&})æEoGˆĸhYÝŨę]ž•ų%lÜūšãˆAĻ‚élĻß8PZĸ*W ģōæ2qЙjÏʗĀF�.ˆÜČpĶØK Xļó #Ú·­#…d]ŸíwqIз‘Ķšņīģ…žD-NÏ·RN7•čO@Āīč<Ô­Ų€ÓÔï Óķũĸ><ƒMÐ:TNæ8ģßÓ5KpyWĸ}ÓÞÝļ‘lrģ‹*€Ö`ULzÛφÕ Đ‡nr3šæt9ĩ]ˆĨu‘›r/s­`?MĢŧwÕäi˜w흋ÐpFîyl0ii”Wïåmn ܧ'CĮÐ É{‚ËИ\V―�%FύŠXøčEîũėũÂ8ĩŠåōéðÔ5ųÆ�ū&–þ|õ’VīW<AJMyÎ)†Ōq_Ģöžų+ˆŸ1Č-OdˆģŅûz;ĪĨvð>3ũ€-ŠOd~…pƒá*q ïŋo/ˆ†v?‚4ãegįČSJ$e]*f#ī‘f/―ÆeÄŽpoå Óåę/ŋ††Ä ąy\"}ÏŽÂ{ūWxHð äĶĒrųų8%(�îC\%,ŦĒķï|·ĸqƌDJ1·u,Ę.cû?Ø7ŋÂr``qī[˜bAþØÝŊ6ŊýtŠļ›ŲAp›wŪ ĒNÞ;”3i.ßJ45šåÜÕ_{8ßwÔŋC͜šĩĪÓYƒäŋøŒŒŒjŦ71Ąe�pŊÞĒ Œó1.pÓīēvU :~|W<Ëϋ[^yŦūé'ōØîĻPlļocâ]Zp2󠁓šÍ\ÚRó%ž=[FN"áÆMEĄcÍóÅRø€dëûžÍô3?DCļʆs‚FBN,"@UäúéŲîɍœóåAûŌãL<i”}gþĘ]ūS†/g;Ō1ŪðÓĐ`uäųŅyEÄø MaÕa†ČƒŊÖĘx?kéĶHbØlēĄ“RYzš[MTŽë€éß­ŨĪïୌ6ę4Óa#Æ3�xų;$œOĮi ,Yæ’ĄöUÅÎX—3Õ2h •ŪúáÞRô ttðVHŪ!Ņßo·ŽðþŠŅĒ[ Ôô;­0āųK”?cĀĘA&B'ęþ§ķ`:‚ö\UÍÓ%–Ž‘_Čfgø5~%ŲąųWAŪ›ByÝ]ÃLlôXéFʎsŲÕî^xjąŸdÖá9&К2aāä :hĨúfôh-V·4Viōp ų9Žó�’Á@ÓëâÝĄ'úĪĐ ÖýʙVÖÕßą9 āöáFīÐJņæ�rgG3 Ņք]ŠJ8?ãbr,·Éäą'k<Ũp ë…mě—{Ũō—_·öĻï2äJzh-&”°Û2ōâž"Ļ2Čø_ýe~;&ŒýX^Đ ]ÄōĻJz‘īĮäeed äewėõ Qī„ (™C…CSÄĶx!LWĪĘrvŒÎo§;sėŲ5DĘė–rkš˜"^šÛJþmĪVeMaBvóÕx‹áVŽ)ąâÞsŪȞþ,ōIĐp_Usf%ō”œŸĘĖĶ?ÏũÞ[Hđ0>’õ[Ēt&Gx[âpIU$Sž‰.ā“"Lyõ ˆš-ÖxA`þj(˜á öčÚ@"nŒ2ß*ŒaŠ™)dYžE,UĨÝ߆ūĸ8Ũ =įŌ*x͚+@Ž�!Â,Rô%IĐÖõPÅô>P (ŨĨnþüŌ>ŌÖ·wŦ:uą™œqagŒÜÎ0ÎR‹LWu=0ý ļËąT…ũð9][·ũ™ĖŋjÎo[Ŧū$™ āˆxB·yNĖóŸŲ‚ÔÝĀ&.ĩ^:ŸāŠËĪušŧÂa›éŊAįBcŒ•ŦŧsģîĘåKŊāfˆ_ŸŽp_›ĢcšXmK‰ĄÆÂ\ÛJļ}ûFšF@Ŋ†(-qYœēŦŲïDļýōúĮ…ßP_oĨ7Īq7>HŠË?~―šŌÅV†TsÚSx QVm&íßĸ@û*”ō;cðĨēfVzæÐø­r§Ō‹ÖeÓ�ü4 ˆÓ åã―Å Q”—ŦĐŧXļ x~9DHÂĐÅ·X_Õb6ÞKΆCwžâļĐĖ΍ʉēDą)"K°"ÔÝąÞēˆž›ûM#ēįG4svđdßÕmÅ9“­™ÁiïH=ŪfJ�õÖ]ņõĩ#uØl‹WÝëWæ˜^‰Ŋč}ą<„ø<ķŸv?z“ũ?„å‚ ÚîcGÛŃęZü 8ĒN.ÕđV›RuWS$t īũ[5ĮŨĪJï91>Ģ;ČL{ė|Ũ&–đ"hU@Ė;>8}ý3XûáĄøĐN”…ýX>UNä^ĪZĒ /H­7㉔K‡!đЉ'īģũïCâv­ßcÞ ŌF§Đ‡õÝî%ËqÁ™ž$ YŌ ‡8ĖVũ†ŽŦæāiÔ2S\ár3l‡$Ӆ,ĞĘc‚ PĻI+ƒĸ éÚB6Ĩ6–ķ.00ø`QŦņúSXĄŸēÓē{ˈŧ|.sC ē6Ē‹žÉ#āZ éŽsûėv' F h nĐĢr*nÓ{­é/EÓ·ŪėOž*“€IĄœØHÐ"ÎäĐ6iēåį+'‹ ÔJÐ(J}Íäķ^TķĄŲ}P(—| 7 å_ĶjŨÃĩI ;ˆļ‚Ö}”™§Ü-­hÄķ7‹†čĘ͛Äp!.Ō'ĩ‡Œx|äåĀß8hūY?Wg!6í’.ÁÂAšVAÔĶā/;Ó ŋŊŨ2ûÁíĶú•rbŽ”š°Ą˜#Í―Ŧ]m{ïĩ&uDĄá„4hŠąÔD}Œ§ÄQøŸÜ(•Á�ŋĐ$1ZëP+zwįŅBØRéOQ*|žG=ã‘šūZ}Jņũŋ ãÆōõ›QlD_ZąI$+,T2ÞÁ Ýč‘5ö‹*‰cĸę0lqĶ zŠ"õž‹>gqé?Ŋę—.㐞ęÅXūˆ:‚Ý1Š]ûā$1xÃ―C°Ėų9P˜Ï5øåĻ8ånӓIĸĸ_·6óevûzŽôFųö�ĶŌ|Y’fðī[ã†všŅúQļÄĮ‡}]‘yŦB-ûų§ĶdjÛÉa­éLþ‹>ģ·ô1Ëþũ‰ąØÆē‚HߓOœ,„þ―†VąŽ1ë@‚ĩ%áÕ‘ôâÛũa›JÃFīÔ#āÓšG§MŒÛF%žÄšoĪsӒ�ți/þOzž‚ĪūŲ w}&HÖëCī˜mGrĻUŽSŊSÄ(ŋâčq‚šýsÚu#ë‰eÉw9Ųäî™^tŧäęLä™âN4.έāõļ4ŦžęZ–NK•ljÄn-•ĐĪĨĪ]à Ļnõū“Štúē+ôæĮÍófü\(îĸF þzÚoĪ5ĒUҧ>Š Ą?=HQĸIęĐësõĪvI―*éĐ3wˆÕgI JŲzđŪTŋXRlP Eš$öˆŌ/…Ý8éÓE™…Üšđ2ÅîEBoōÎĀMę*ϊĢM!â‘=—­ŨbĒĮ‡C3·OÉ3Ôy2+‡€YūËɍĂ 7ūt€,…đHïĖxZq$úy˜'ŽgþÔ'g“Œ+c’ĖØBü{_įõ”Ąð&üĨ=9âüå\ËVėéį%“Ē™ÁewŨG’"4+ŌDŊ ī.›ÚĖ[90zøQPIT†2žC\‰ÐúW$jšKIFcą˜Ōš3Üeīo KSÎÞúáĐbÝqŽ$lĻū˜ËÐJ·Æ9͞ÕŲ3ģãК ’’BÉíųÖÓģÝĢžw|ž[Ō&AhJę˜ĨŪjÚ|UČÓŦƒ mĩAh{Sņ8=ŌlbóO& 6Y%‘Þ1Ýŋρš�lĄÛý―7bó§gæĘG*Œ2~ßŒÛ `ĘïúïJTęÛsÐ|8FĢXÜ+Cgė_­:nzkÝUZ3”é?xėGƒ–Û8•“ũþXžË֏âũxÐõ]@<Î―Éxģî ôÚY†eÅĪĄoŌÂÅMT”ÁiJpsĸPÉģ~ĪŊ ĩ…tïÖQäš=ΐf“R;ŽŪž§+ܟēðBۄō"Ėï/,rÏãniÂ~‰éÚہE‰T•âĖeĒų‡Ũô ŽŋmŸNx9!—TEîAå 28„ķÎIĄŨ"CĮóZð Î!—ÏĀ>axS—fÁ æ R6‹―ˆÁÍƟMWŪ‚`Ë ĮB–!380°X›7üđžĩĐ{4đū„SõššuԋN˜UÕĪ<Č3ęuUø :ë%Gœö[ŽÎ#ē;ŪpJŲŲ1ÁīǐėØĩ/_ĩðŋĐ eŋ§ Íú‚ðØĮė‚ĩÞŌÜ^o€$WŅyŊ3tH&Ä —đ„Ïå–ût.0ę>ęŨd“’KFiä*(#u+áÔ9ņœ%=ŠóĮBBĢ5SĀOBS\.ųėuÕ –Æą.ü]Ž:é=Ëb>NEšđņšÁ·–,+ČöWuÝï“īšÂRįhžl/R€$æfúULēÄáĸpU>yØ`<ۏÔ2ó]GšKā›š…ZIĸ|‘wĢąNą<eéžZŽĸM N‹jՀDŽR<ø?5 Ŋ•iĖĩÍņéĄ.S‹Ï~i$Ušw„Ú™IÐõFú€y§āOč€=pþVMl°5Ååē{H1=óP&Ô·bŦË^ė{ԔnØA,< Õūú=osåq—ÔM|šŅ €ŦčMÄ(lð…“j €ZŨQĐæsÚMēác?(‚rÂģŨŪÖŨÂĐíXĪŽÏõ=+æˆ.™5ŪYëšjđ‡”–b-œÞņĶKģŠā[øƒE°ņû6ĖČ` ŅIFú‰ŌŦYZ·ÐŽ:1”@ĢđīΜ~—u0BŸŨáĒ*iņ–?ķ]€æŦ;:q_NQėčČqs;Bžnø,.Žfh{ÞÖÉīþ7ī3SûTũd1Ë$ƒih;ôqĒĖqdīĀQ�‡ņŌØĨÂŸŪ@Ð+)Î]jį&  G3 M‰[ÍŨÝ!ƜĄ;f5Ԇk߄Ā—XbðÔy;u‰ āAc§FŊũŦčĄø‡5ũĮDå(ģ7?jũƒė*―@a%ė\ëĖ ?S™ؗš6™&:ôQVĩ:æ°/Ŧtĸ3Ÿ‹ąÞĮ:ī­„ Ÿ3Öð7 Ãé ’, ĻÄ23Î?ë‹I XŊĐAIý‘d*6ŧ_”æ$XOņdŦ OāˆČ9kzIqc apSî”ûŠC­1#°fĻŠņ™ÖŽM0WîÏåsņÃyĩĄŧ 2ÃģY/tũúū!^jo„ī<­OĘĸžÚPŽo(ûöóĪ*r旛/WzCWTįû”Ûß*æŌÁ<ŠaŨЂ­ū]āč>ų/ĶŲï ĸFqøÏÎГēķF+oƒ Úmėž>0Õvyfۊ:^ėkĢBÄyFĮüý(dSb>] ;Ÿ›‘°ĸ8ēfÛ(ۜ0õ!ŽÁ!Ä4Å9óÕøŧMÍÆß[]ŽÝ"QĶ›'9ĸ (3�SuuK æoĻ{’<ĨÄöîj~Y0―’ę;Ũ"9ēSö•?cũœQûĶŋœ™oĄŲ9ü‚`s<"01kðþ$°ˆŒ‘ĪÎßïTƒr@Páđþäęú%*ųy؝Š&A(#nå>–Į’Þâ<•ēígŨ”ōó*($˜þ‰% SÐČ,K‘4Ũią�暒áøuŦ·ļ]ąü:Ïáïk―YwąĸŅ<_ĶSūŨAßf!ðúm|>ĒþNāüŧōuáÝnęØ.é_‡wü>„þŅŧ؟‡Ņl‡ŨÃîlûmūģþTŋķ?'u>Nŧáwd—o…Úûŧ'áîk―{ø{3ðú …ßFšwÚ;čŨáôŌfŅ}=]öl8Oĸ\â›OĪčÞ%t›ž2ŠOėãœ2ĐũøSSŽM–ݧx-ëĶĄŦūþĀþÝ>aĒvöāõ°ōŽï>ÐĨ”EĘPmėV5—õĮþŽĒæėØŦāÚNv~īķôĐ$'–†zæe,1Î^ƒüņGĪ3?‚Ŧb7GœŦVŌĪŪådŋļbžWŌ5Síã>þ đMęBbvũw5ųI"ö<Ų=jÄu#â•āč^ŋ]o•ŊCŋWô�ŠŽ(å_ĒÆƒĄõÛá&ŒF-ÛÜ8ž�ŸĢūH4s:,"įu4ĮápÛzÖA"V3ūøx|œŒĘ?@ĻoÃ2•]2ēM~æG#Háx”ĖQ‰ĸSîUEĢnQE:dÆįŦŽ9‚Ë™$ģäƒôī―^ãVkžcĄ1˜h/ð_"į0Qž_Ī.*jCgžĒgG#™đ™ėŌū°"0OĻ1™?IŸÍ$5UaœôÂ-*îÂė–ø‹VÜNIĸzŸ‰ũ„n#· cÅÃj[㏭Æ#°,ÔÕxā•Šā›håæī—ĪŠP’ŠŧØØðŧÅŧųðÂv'Ō#jƒcYüHĮĶ’M’%9KaŽ‰ž%Å�9Ė)ĘXIž9ØÕGM40GX'hæ^}S§ô·wRdfuQûóDß&ϝ4 V„xŽ 'Ջ7~ v‘íWBÏ*ãóēl3'ð1F„1QaįāY˜š·m; *"‰ŠÔ7ū@éą ÔĀVÖėch”ņž&̀Dž+ûžvƎÓ$ķ`ƒ§6ÃļÚHĮÖ,vE–~ÜÞ{8Īßh^ Ūúk9—%Cãŧû·ŠĸĻlW˜žĀI+fÝüuœWe&_>Ã5ü:ˆG°ģâo—„Âī°Ý IÛ5ƒÐ’Aœ€4Þ$“ã4ž„Ü݌Fą‹7D:*…vđ‘ĪT‹ėN3Ü"Į7éķaf#ÞķŠöa§(ë<�T ĒýúdsÎYNUį·•{*~Ÿæ*Pš$;Ōî>+ þa°v-|™–Ėi—q?@k m&·`DŲLˆĪÅ؟úŽęûŦό…Īrå˜Ï ݊.0TÐ5Šüú2ôãíUīsāš]ząÉ:âũŲ1zjK4Cq;cĪ€ãŧ“7Œ"ÝÉDĖOwģũÆīÔ4ݍÓS§âĢ6ČŅą6#ËBōÝaÆ7Û4ąÝMųÏņ>1ŸæzPc€wÐ îŪ3€ŽƂ,3°™ÜŠˆv_ę…Ęųnē†h‡wÎrƒ"Ũ~7Wĸ}�ÂŌŋ_Ũ–I,ö|Y ōx./ąĻÅbķVōiŠoz ^•QÐqXžOFīíeyÞX\ŪxLQŧĮHņáī'K^“(§Oü%øwS!3A­s Ð2p6š‡ĩŅ}݀…0ŨYB”"ĻŅ6WĪā`2ŽĶlĶÂZ)ŽE7^TæĨfæ$Ĩ\ÜP<ũČð?‡ 2―ü“tp&īTfTT—°æąą~ŧTŌāpũš†bgŊÍüįã”ōãM3bĨƒĒؒnRcŨ|ó܄ÂN2BQÄ]Ž` '5…U ^M13ūâ<Փ%äØáÍĀd†uÅNīڞ(·pÄÐÕۊcgÄ ýŠ[Õ3īpę’}Ž]~AņzK9sz•ö,čÜē(Ār:Šĸ;É'đ;~ĐŽ`\°­$ZÁ…ˆ^ûØOŅtW”<bM―Ž aßlĢNĀutļÆđhKR#'1—Œ1&Ũ)īfG‚ĒLčTbĪUĨËKÖ\·‰.Î3šÏ1.†~·ĶwũJ}ãA>vš_ÚĢˀšˆķÔ―Ãl7xī(ģ‡Ä†w’Õ•ū…ýl={HƊPËFA0}kāžļb˜oŪ•|yp*ômR!IÉwŅĩĒ‚q†`įš{é‡įĶâ6a‡áG^Ü*,訓ð$"AŒYËÂOœĪ"úˆ ÎŪ„ÝG3!zĖÂRŸŒŦ—AĒ,ēŧåVö’E#wU2Ĩ4ÂkˆI—rkSį8 –Cd~õ!AĶ­9ˆŋŸ Ę',TÐ=yšt‚u#�Ē•.YüQ–Ž ĮIĨ5q1GäISĀkķþŠįũߖ6ÔZđCk6zíōY967äW\s’€ *Œïƒá 5û0―[yâÜnįņ_ݞāL“/?ØÏF{ ‡[<āhœÐØíķÚû(  ÅîððeĮeôŌ~.~ĻÂũHbMĻ~Tû8ĸ`ty „ðāÜxôC›ō8ĶÕÛt+jāÛ-ļōkčãd W‚@ģ‚ˆQ|3\wčVĢÎäi™7žq…čˆĮŋYqeŠ#•KŲip<Ï]G𙑷ī\å`ÛË}mā>bo4ŒyýĢ%āý<ŠØwJ3šāgÆtŅĻÔ&ŽĖ~bHEŦ2û  aƒuLž†5ëV„˜äĨãĐđ €OUƒŸÛĩ9ü”FKKjĢcũGc­ïŠwãČŽÖ6ˌŌÕâxŽō:§LĨj•ŋaā˜ĒŪHã4ŽĢIÔ~]Æŋõžp9œÓÏds@wã―&E§ZŸ Îæƒ8x%áŒFt%–Ū.BŅVh%ŪĩŸäÂŨĘ'.ýDbxęŧ…ÄųE·ZĶ5öNŪÕ/%4ęZ“Ëߖ \fÛ,oĢ―'3­’úæTӊöĘ%jŨq–.p^‚úG™‘ð›°hD°ðÕ�|?ƎÚrū0D‚rôeƒhÃzāįUlQM&ŦÎąîgkũ,æ&·ēr=6ŦÏG=fôõŽb홷Ü�!ū“.xÐŋtĩÔbtš“P#7œĩæHĸgīzAģFyŸãŧō1ø ŋ2)bHbÄú]Ï—Ū›^ũôð€ąë―ŽĖ ĩęƒ$ĮcŧÐL„ŽcZ”Ô5>Ũܗ §îtīmĻse�ËyŠŽ 'ëļdÁÛïŋƒž;}øį"Á)ô ßÖüŽÞ>ōĀ[3ü;ā6"Ķ E͗|Ä{΁]`ԙšÆXŋwÏš0ģX:mœ’øø€ŋȧwKōā­—>røžT·ŅÁRĀ6OF6ŠýÛ*q#ýOĐĻ#Īx*(Ý Es‹>[З|#gĻ'ŒL3FĨE†AĄd7/čķ°a Öčw­Ō@eیr§{NÛt6F9=@ ÉŲûžáo#―Ÿ2Ģę•·OöÔb!t§þĄ&ĀīÁ ēāƒÓ ÛęĢ·þLūÝ―•ēÃd<â€ļÍoŅ7\ʔ‘Ÿ}ĖĀ4lÛí]*zČðČ5`’ƘóÝYFni-ęģXfš&PV8[BJ!b0D~įÐAžs1–Í]ÆĐÏĄ%å{[9ãgæÉĐ58ĄAŽ`ðÄģÔo3OŌēî3€ĸĸsÍËĸ ÍĐ"‡îîųÃū6įïaV[§î'ÅéXw˜ë]hĨāTĀųï{'œpétēÞE\1°_Кųī zĮh‡�RÁØRlēęïėĄĸG―ŪGï5/ŧŅ2–§ŒęƧZz^QRKĐã>Āâ~b”ˁJĻVklUö8l+\ī5Ģ‹IA֐ӷ+&ΐ>é 4VöĨ%m[Qóāýߍ-{Fļ’Ënū·đũ+PģjĖd’Ô͌yAač‚Ó:ĀĢ$ķŽ<ĻQĒâcrH` zl"ėÉœėœ8ŸĖf>·;ĢßéEĀ„Są Ũūj^aáŊ™/;#|Ó-H"9„/BPߎÃDFL “6ô&öæ,jųø á°ÉÏ3ôP åōW5āŊŽķHĩZ™ŊCz17ðūZˆ- cJ›ū-Uø>žŠoō^Ęō$Į”ÕMï=ā~ü*&ĻūX)ô+Q”°†æ õĩ<æÍŲĪúHōūëžpëßĩŋzâdÚ^üjŠtXZYKäpÜÓÓlŌŋu›BŠ! ― ōņT ­yņc 4Ãž"fÞÝėN”‹=‹ōhn ĸ76^K ēĊū2âã-�ð$֊ãŽN“™o#îúč8@_W-þÅó�‚Į˜Bgb–+cĒĶ"V0§/ēuĒíUęo‹eb”ŽWËų1ū‚6†TmË ŅÎnčh7ĘâęĢ&)ÂZĪÁīälÅō™MW˜Â_Ãö/Ą€p°b•°\Ą H=˜Pā˜T{BVÚoÖ (N(Ø…Ã�Ú2b]X—ĀŠ nę*&TĀüŋŌY�đ: aŦSSƒBŸÞޑĖÚ‘ģŊšĪŠ0Î^Öļ―Æ~xNRēŸ­äŽĘāš;Ō0@Ï9^j’b–[xåĢ}R-&Ē|Äý_:…ŧ éļņÄxã;—]…‡ÝĪ`g)8Øö“L5l "=Hð7āpųCû™"ąï™*Ҙ 3ÁéDęŧTr š.%Ū2ēeÜt?ē7PhKdģKóŅĨcāČŽÂz""ĀÐÏ?þĩē1åŽÓɄˆ>?ô Ó5ķ ~Åņvĸ$BŧS·+{Ž<܏R3+ýr5ą‡Î’ĒĨ/…dZíŲ·4áĮ>ãDRl’^ĐŅÂûlÉ) ‚6îi‡ļEd/gwݜŌðHĻ`—PÛrîeĮß8;ûϔ”gŠ3ŠĄûtŠÄ#ŠcŊ6'+Já]SOöf\‚ozûlPf<ī‚—7GblxĒđYđõ )á Uð8Ǝč$ė·°|šÔE>Gžõ7QÎ6ZLŦ†;ĀæŸūVŧŸ4mũÄŋĄûÐ"—é(X;XÍÜō·MÎýPîüø°™° ڇpįËYj ZËPiđ—›Åâö^Z;œ@,JГÅUk="ˍˆŸv3eęT^‹f5 {ĸ[6ĐÕ|Ã6þãŨ_ú”ŦŠTGzķŌcļý1î_ļCÖŽŠŧ@+MTĒĪāĻåÜšĒOwžFd�čKŠĄĻŸtĄÜĨ!Q›tēĮE–l#_gîÁ*æBcný ïŨÁČ藛˜Y2.čįĻOž:ƒ 9žē!0Ĩh<LōĮ+œ1:ĐøđĒ(̃! Mōî `–”8.<xŒ;"„Ów4vý=jBKˆ\ye„ŋ”„ũO†Ŧ2ƒ―/đVĶʀĸ=tõ”c$•bëŠvPÜæB“ē9+GēBT‘øâî딎C5xō‘‚>ąęÎlžĻ‹ë‘'œš'óÕųĒp(v�õÚtĄŊÏFTūÎ/qUōi<ĨiũƒólÁŪ_‘8ëdƒUÏÖš„ÐĸŊëf:Ng(IGM0`ĶŌæewÄ"/ðėžĖr? Ü&9 BŨŲš4Ō`&rĐ/ĒðĢM#–Ā!O"eđ·ß&ë�ÃU‚/z™ž˜SŸb} ûáīÄ äï}ÆTØn‡ ęþÅ G@‹dÍ$Ni'âDÄģŸr†’ŋĨŋr“gŪ—Ygž6šwJĨŋ{œ―ō$āö”Ī­·ã–\°įy ÅĖ]lbF)o ˆXs”5-%ņ&8p„>!Ų―ÆNoĩ IĶ_ŅįÕ ũ=ÏQĒig™žöZV-õŸ†Vn‘"āܑa8 gÍČf‘‡Þ†FāËIâ”Zģ vÛΆ ‡îïãnÉč ÂZgĮä–n'Åv•ĻIđ@ýėHCVčĩ Į”RË·H9(Ã}ĪÜđM„Į|Œ Ķ―/GIpSMS!˛uŒ”<[”―*>ôŸųÏ,ÁĪýï•~HyÚŦKP˜žĐD Ļ˜―Ģ<žØÁgQĪãþ­{ķÛ!Ake4™pĸ “:ŌÓu=Xï*늊ÍėO94Yw1ĩ9õ5cĪ'hë?öģŒ!wB|$ÜŌ?īĢ(Tģ]ÉÎ ÛīÅ?điNŪÝ@åÖËĘtÃcBJu0Do°óÐ_U•54øBĨĖ [ēhôČˈŠj6Îãi4Oüđ ú3MQĪO fOÝÎðŌzį Íģ}SzŒĒVˆÔCU–Ē;':x!lï‘ė+aŲÕï―UBÛ>†Þ]š>ŊqŅF>ĩd!žģĄB7É)ūŦkÂ_WÆ!ŧ$œōZ―ßŋæž―ö[9)ŪÓQ!á{GT鎖Ëé;wëEĄŊOlkDKą{tų*‚o9ɄjG\―xžöKāĒĨ!rXŦß2 đaĘķĸCœą4Œã Aö%žÐūz؃˜ mÁéQ ûnĩ:­‹ŧĩžęÐ6Žūa]6Ōę2ßÚJ+ýŪ@–ÍÚp“úÞ 7žÐŧUüĸÚŨ Ōŧur@K M&„߅ĨæĮŽégNąęÅØ0ĨΒ/}Ī;Ú*ČPmËķ‡ÍÞúƒ]§ÎžÏÅæŠgCÍŽdĩ*ĨÞTҁ9Yģ„O3Rníų› FĶ+ī>ūp‡3ų>ęPČ WÎ{Ÿ‹áaX(Ķä,‚váĄā5å JæUïX‡Į„zÁv>k̰Šņ2,ų•xTƒY|Œ˜ž`Y"Ų‡mïÆ%•ę^ļ“:yL˜WᩋáņlĄtéĀAåmIš­ÚEĒ-€—r-ŋŅw]RÃé 7z îLĄáxŨQ[‰ĩŲ;‚ŪOïÅũ_vįŋvÐ;ÂOúšXĶTĢ­–ÍLĐwä! (æ(ˆ?ÓIžM'xc։ 6Û·Z‹@ã ý�ÓîÐ?§TxŽÐ)·MÆŨ>]nH˜)Üēû6*dŲō*ŊoŅŦƒ_ûN/ģýEÁó$‰ÚŸ/.„û&ądckt&·„Á4ä +ë’Lƒ�žzŸïdaĨä}­þÜŊō ōĀĨ6īcžāÜŅéƒÓ1› „ÎM1ûW<6v!,EEeč°Ūïē9—\ðÍ{û…’āMǰðVį'ū^R�—ęēírӒ;Ņ•ũ”ĪVŠ^Ú@ļ$YŋÔŪGMjðÏņŧŠLãÂ�ę/ŠÔíå’m2aū9ï$ðeŲdkøĮÚĘĨ—ō·’NDäUmeN)�ȧŊâïŦē„ûĪ:i<žČí%a€3rūNöuüĢĒĘ@‹„ÃúÓÁQö í;ô!Ēž3š=@WäËdÓŽœ&åë=PĪxĀþ"AýđEąũ j”HđM$V™ËŲ Â›ŋ|&Ÿ8ō”ÎŨ9n1äŦō‡ÃŪoÝĒĢĐÍåp9qVL“ éÉžîĘČ0В CbØÅ‚œ€6ÆsYëVýše†―qe/,bØšýđŪCï ēÁÖiåÝEå4`öņyĒŨEâj§7ÄĀĒƒ‹ĖO‰ų|EGįh‹‰:ýd{y%yė–Ė+?·ÖïxĪå\�\Óėģũ՟å"[(†Ķ ‰Ņz~x)’ Öà J0@4Ý0UĮþŠ,uĩĩÆ/›QÉōĶþAoi·EÉÝ+å0RÐŪinkz؆PwlXLÐŲVä5…(™”…Ô nÎWw\†_ÛRƒcø7ÉLdj#›€–V(ųŊïā-Į$Øų…]Ž^bŪoÄþtõ ”Š2!NBô x*˜ŊĶÉÓēĶUÏ―ĒøH°éŦēņŠNŲj5ėĪ~āÁéÛyƒėmŦļ—Ę“Æ�Ðþ†’jƒ‡‚üiđL:a‡đŋó\ÔNŨÁˆÖīZķ‰;þÏ ãMjûÍŧÖĨ(˜ƒ2jU·�|ZžYÝý™Ū~Ĩ7 ĮCŅuðÃâ{öҐÜhŲ\ĮŪ4F"^<ŊYö›•=ķŁĪD|Ž"Ý­yC8Ëýe녡[Š.MŪ{Đ― ƒWJ[ĨūÕ|QZņŌÔbyË'āïŨ$!–qēØÜCãŋ;ĪL^Û čŽ`-@vb:ķ†ģ“QēžĪėŽJnĮDøkļ‚ĪíÝ-É&ū―zv·ŦPÔ3Úėƒ‘gXĶų•å” “đLŸ‚b§QįjÎjÆdČæŊW{$ĸBSĩSĘŠ �ų8q,ĒUs‡Nw+ŽâG!æ&e6Ęc=―1ÐČîį>$õNâfĻ<ĩži CdG™ÐÚÎĻl—ėš—Ü;B^$üķ^Ý`ļ.°ZÕtīˆ 3…?Ėņŧ— h˜ųq„ŌFäóę,iHu<h]Įųaž\­Ý)3ÓäA“-Ė”ÔbĘ''1;ËíÝ `TLĮ·ÁÅ$ļ%i[Š#ÁžĒô_–ĖÆĸ%-5äõŋ†éG‰Ķ žŠ!š|ÍĐv'aðëðp“>ËėpYĶ }t4ņuKŒ€t`Á%Þ ąÃĻß<BōïĐ/be°—šx›š>“ŦuüĨ)Đ6…ðâWë4?Q‰Ôgč‰s8[.e}ĸ·KøÔã…P`.5ðLŦš‹ß"įtÝûþS}ŠķĻØīËĻŊ`üŅcN;‹•„Õņ§ âïA)ۜņ0ü•ökķMŸIŪ=3Žņ0þr[þ “˜Š^JˆÍ!(/$ ŒaĖA!ōuķož é?íįČČ@ĪįPwsó‚˜-Q�i„ōĪR‹þ§đų�įĐwcQΈPŧafwDXŌ;)ûÄðDë%îlaBšþ‹F‰evv5(Ã~†Ļã`PŸT•RHOoký#€=Øīc‘ĪðHær’?vp|Â…ėJĢY7!TŪópK îyĖD ‹IRgŅ|‡š–OœĻ‹z}ßgB˜T<Ē ĸBųj‰žŧh4hŊØ}Gú^;D=0ÉVŠ[˜ĒŠËg0î-XČhV‚Ó"͌L)č_[;l—=›ŧ 1"Ŧ2ÚÐtÖõsŨÜĘgŧSÖ-+EŲz€Î–|§€äŠ­úq:Ð*ZtŧÎ� õ{°Ą|ôJM3qtĮķæcēœáŒdēÜx+å=ÓCāĮ֓ãAYd1qŊÛũâ Ž‘ŦFo?MĪûÏa(ĸŨ0ZQ”-YOPbņ ŋÎ=ŋK?J<ÖCĀČŊ2؞ju3v’í9SäðBAÄ{S­ÔdũTŽœQø9^a-Ļ* u8ß">úCƒņ1B|ʉįļÆo’ŠĨ—‰<Š ÏÜöėė2‘ŲÄMڅō0Ó>ŽcW”ãĨÏÝž ˜Ļ8ð!—ę?`BŧڌļÐōīū/ŋqč.ˆ―§˜ÖAŦ;Î―ðĸMZBăāGŒeõëöŽ‘ŋ―ũ„9)Ĩrö!ņ‰8â)îŧR‹O(1BŒœ]™ŽaáãDü•b ~Đq)`AúË gĩV”øY=5Š+‚§Øõ2á;‰Ø&VĖ’ö—–X@ "PĶHkxĘOZģų}îŊûņĐp=đœß‡dÃ<%ņō†—·Ļ€7n•Äb(―YS˜/ķýïųŽÐoSY†‡Ø$)ōiŌæ1-˜NA€Ð&Đ,,ÄTu!cïíĶÛxœÃ6‘SÓō1ŠáĢÒDŽĶ9(6ę8ĪIæÐõåTļoÓ°;ïēxžîo ĄęqūÚČ9Āļ�bXïaføŸ_>šâ uvįq›ō ąšøā=―\„{m’Ģƒ&―ĮŽZ_ą5˜ŧŪë=gÞuŅ0&Æ2:ë…ę"‚)ÝDđ―žã=ÞHŊo“ęē sÁŠ\ã$É37A ÔņŒ­�―šRëé‰`t€šR44*Þ­Ī™ÜÕâą'`’ëič™iJ*ŠĶũļf]lxhÛą@–|ēÓē ëN6‡3\Yū§6đGŧN3F A›h™ ēņÉ8y€ MïaŠ‹ŊsQ@ÄÜ îbū3…fĘĖIŠ,}Įč]&Ū— žob;\owM_߀WnÔ5i&Ą#g­ys‘(CÁtAUBmÎŪÍW·Û=„FN€ĶEx4ÂĖ#TȍACÜZ“[äĖoųäēŧáö8‰‡ËYī­ō3L )·ČŽlÐäôF“Pē·-0―ūĒōGu?œš=dÚķ(mūðïįa3}u/ É9™ųísnʘ*ŅyåTû Oņ�Ų)bŦéB.z;ÓüíĸSâŠ3âCB&<\ÝQœĮZčð”ZX>E3"ˆOƒ9a9œj*7KoĒ‹ėËjĶ”Œŧ-;ÂÖųŅ~Äír%ĐqTĩ‰HÂÞ:Z4xŒĸ~C€úČDŸ [‡zkķD4O ŨˁģóÛqjépð\厛BüÆ8m_‚Ï… ˗Č+0}ņ%Ũ—‹Ū•–xpŽAĢ( 4Ûď“ðl―ïĖt{?}CŠëģŽîŽøĀšđáš~/ĘĢēiŠÚ ß(#sz9‘Ð⊎+ĸ æEų*:^æŽ"Öš’žĐ<ÏĐōv ɋ/;í%Y2w"xtrN_}“°�yž U-ËÞĨ?t•īöVņĨ,”-°íýJ°`äĨ .§?īŪYą"hî{žķŽL‰>`”SųĀj'ŠÏ–iēĶĒõ_ŽJOæļÓý"Hc‹˜ĶÃËÐd―lCŦŪ떓ŧ5Qiœ  Ē“VjІĢӏšžP�ZĮÍZ8ޝeŪæļ˜zÜ­~ÝwŨdgāŪ*ŠRƒoXM§]ČęR_cOÛjÞ2dēČÝ<>KJž­ŸJúĀ’ íHãI§þąĢ­Å ĻĩĄb ņČuRkz�Rϐ―`Ũį›NÎĀËĸRs*’Dr֝wÓŽąQĐ@’jÐt‡øLĩũFaĘŋmb<N{ųR›°,9Ŋ?Ą·!^“؝ ÝHĻÍiŌ…>ƒŽšŨ§8ũ\ýĢÆwÅóW^įC-’ĒHÆÏ"îz·hģÃ9îČ\ÔŠ>&ē][Û6Š`Sû9tAxį—ųûđ˜pëĩgũZB™Ļp;ĒČ1d�ØXNóŌ8ī$Њ WËĢģð‹›í.E-Ïð$$ĢÓß;xelÄĩHâžUš<CĖ9ß―žþūriú�bU―ãÂ%Ę Eņ ­ĮðđâúÚĮā4o7_IM1Weæ*Ū âbŽĒ’zĒ/.ëy*>*ž* ÜĨöÔÉ,ü0žŦĮāŽę”ĐpéŋjLČQ&�|ßĀ2/? „TöšþF™Šą~1šŅÜVxOýÍÆēSūáĀēŲ !a Jäąāßģ ĀŲq”‹ đú†ärú-ƒrļhvYŽĻ‘åCĶüĶCaÚp·Ôæ`ÅV|ĩĄÕ K„b„VMiþïéãĩKĐï°{ÛŠ„ÂŽņØi<žÝvOúÓũ<ŽŌxbĸ?ņsðƒÝy3īåSÜâĶnņ'ۙž  mą{/Šō—Ķ—ÂĻú‘]E˜ W-E‚Ūa&79 e`*ôlŠBŽ„Ū:%NЌķ@I@Ļ*ɛ 7%ė§ÖĮÆjÉŲĒÎŧƒlWë,änh,Ä9rú›@Öė†ÂĻ’ ŠýĪa —ŒÖ ›đÐzÎ!’-2­„ĀïÄNzó‹ĀmáoĨ‡hóü@;ßKÃÉBļ’˜›nĀ�ĨiÃ%wAz“ð m6ædŨÄų­õrŨßyåŒŪe„l]Æ'ÞëõâåVĨå]AÂhÜPhĄB…ėeĻAŨÐïDŽ=\užį3Ý%l(Œ?YQÎ Ð3ŨÏ(ĶÜ}ĘĨ‡ōėč!§$šLwq5õnNŧ{ÜffĖ3(é›4zše2n„ļ ĶíæÞ ôܗųČ B8AôĒ%juÝ‰ ę}Ükš[€/ĨýŨŅķjNĀï™{øģþĸ;°BJ‹/.B3Æē_JR7 þ xûß!ôĪ ’O…ø8þ^o^1Žû™d.üĪ)”įôÛåĖv4ŋ~óƒŠ>Š rdéīƒĖ lpVõ1Šũš„“„‘Ój!XŅŧ@čþ  ā°û“{p―AÕÚÃųÏï…Kžâď˜Å2ôų^äaļļO þmzē•%tdIá˜åJĢ‘ˆ�V Ļ$Ĩ9R##.†Ŧ‹Ã§ŒZKE ›ü(Nîj Q}Wŋōä́õOšŽĪWŧ|(Ymsģƒ§ĄOÆdøŊ7 VũĀW™ĩWTB †›ÝpÂRģG&­ß}ŊÆ šsTŸ <pfӏŽþWĒRætŲ/‡jŠVXÔK+tŜÐä§­L–ļ1"ÄxĶ jũ8k·c“)v,vĒŋUąĒýôRIhS‘Õ‹|ĐXáî8ä>VŒ“ĪU’ÄUūaaÅfŒ>œÓ”ëmŽ{{ƒė‰uZ}ĸ ÃÝá°~n*ˆëá֞ßā^wðūa}ŌgsÉAâ\qČv=Mï\>Į,õ(ū\~nÏN[ð ˆDÄųĘt7āeãŲäJG>zĘÍŊT+4~īó”ð!)́�va 69lĸh-ņ§Ôęžį „ŊČ~ø‡ÂÏF�Č`Å_HÝļūb―°ęÃŋî?|T‚+Íą8ÉĨiY>VR3Ds-c‹Ô–öYK+|―o+noÛÍqŅÆũFDĀēúŸÍģy–ã?*ĩm:Š<ËĮēļ“4ąž§<KÉȃrY?šRi” p`~9ĩv”S_vŠF+Öa—;ĒØ9~ŠÐJ Zwōņ%ÝF,wåāžĨ~J~Ÿ3-h‚;•PÞ^KRæóĻĻĪčļĐ8Z`ūóĸc‘I…Ī^ã9˜ĀĪ. Ø>*œlpŋFoöí;ˆîŧfD Q0. €°õ“ĨK+đï°ŅRūMŊ W ?Ma;ïC„âyo{UĻgÕ­–Ã�Ļ<ۃëÛĩē/Vc+ o™*Ã;ó(žČ/5/ļúüq;lû0õ kœš9)ó°‚ē VáuĀU‡J ļ•|Ø@ NJbōKsr€―Õž%ũ# KÖv/žBs"Ļ‹,ˆ%lä5ī­íķÏäŊĢC`ĩ}‡‘BtCîTôčïmÄ%zĨC<Ū0tĪ'G—"$!)Ķģ>ö Bþaâ_Uĸ[ëÖ·Y^Ķ.•ũYĘ&Bï�ÞEEųsô$é�ŅĩĸN ļI1ïŠvŠ;„ķ˜Ĩ/ã6ŅMÍŸNre —ĩŊÛš3Ō 1Ė:~ÚČ迯[Јaûæ~ÖÕKWęŊÍ Ėá f3!įé<°ÉifŽ}Éh#K‰Ä”šÃ„„x—€/øãyĩĒá] ·_dŌ/iý[BčŦ­·ƒóížž;\tm( ŸoÃ‰ŲÆv<Ģ‘MĪģ6ū.‰„Ā'SY˜ČŦ čû~mĄX‰ Ė Ý/9:·đï E%ĻiDŋ/P;!øž§ļō-ž―!?Ģũ§ŊĢmðę;[GĢ ĘÂ΅uj�Ó ŽŅ朇Ûëmq”Aæü þ.!!öĄjGˆtą„’<ĸŋ`í9―Ј@{̈́č\ųęó)é(‰c!aĸJEéDŲØŠĘC‡óΟc …3ŒWš]$ö$*‚pÓwہ•ēkõÄ3Mō ŲA%ĻlīEEa}~Y0+ÄđŽŊpøÑļĸP ųÄ åoÍ*—ÃÚĶĀĒ ļg#&įEëčSI•đ^‰~EĘoũ‰7tŧ<í ܓâ“ų›Ý‚tïî̆W‡Č2īĄÂģŲ•ŋėî&\ĨĖOijF­ŸHŊį"ŧĀH„p ·úwFsUzÉē 71*—üSޗOĐiŽÅcæ+3îÛ#u.ū[3íðJ47 <(ßļjÖ<Ė5�Ïnۋ­7(JNvmãGu9ø;īĒŌKæ+4Jø;—ã"%�T”‚:W—Gý Rl Ëɗ`þ’õâŽĀĩĩ>§)ūä:vŦGIĻsčoÕËŋą Ãĸ*­ĮgCGsã˜yuÐÁģk@ĘUí'“ģ=ŒļTģ1Í―€JGĶæVoaņÍÜāˆđęWĖŽßHg Đķ(f˜°æ)2ó/Óh1’Į>84ï)Vo,­GTí(„AŊrðŋč‡zY†eô>KŒžČۉ�lzØã†ņžŲ}ØÛ …(—ý|tCÃ+ÆųBĩ™#ā3#ģëý �˜95‚Úxƒø"Œįƒjw‚A'I5Oâ |ų’6™bCnüĩĨlûūŧ—oïÎÂę~!1ņgW#pé­ĒŒ6}6Aw ĪÞðY=dL/QËØƒÝ ášs…ė8 ‹Ë0ČÅOÕõaÖÂČ/‘fÓ/!“æ‘°č#W\Î9ïA$*å{ĀČ8Ž’$C!āa°·ŧMi8ذoöĪČP î‹ėŦÆx·Ļ…ëé!|“ĩ“úëØAũ!š\ečõpĢÎÂĸ/1ĩ‹'ŽŠōĐģ_Ž)B$eæ'ĶÖVC‚­ÝģŪo\ā„awlˆsą9=a™ Ēīęø<˜†­ÍŪЕŌë4ũKŅq}ŒĀŽj˜0ĶÐđē3ĻCĩ ūīU—ō>ˆFųč$nY)žIOØįFũ%E ņ*Ÿ6ŋdðe^;ôCÏJWŦÄ#žŠ$þü‹ƒ?ĸíˆvLTŋjæą4S}HAąƒŌ™9‹)ÞÁŌdĢYÔđÉ C9‚TE  MðĖĩæÆ7ÕáķI(hf`ïüþ:iĶâÖ_ânžs@ëŒÓ mētNՎ~Ž(–ædĖKĀ™Ũ̘\đ‘ābρåôÛøČwS·H–]›YÛŨ˜•QÞn=gūS\Dq?sčŧN'#L~čĀ}ēt§ũB]oĒŠÎ]ļĘ<ÖŠŠ|K,eÂó“Á7•kŧ áÍödåV89 %\õēÃ4ė„öbxšĪ„!)RéĨô�PW9ģi•"Ģ`yÝŸ!|Ä|wšôĢât,čļúÕį‹ā.dÜ>8同č͎čäd‹ÐGüœŒ–`0jÆĐ aîėH å ūZ<ßΧzzÉzčր―qŧuëā.R6†d‰=‰Õ uëô-06~ZņNTER|zpĶU—LbOϑŸŒYč” ÉŲũ|ã(,2ē–°Ķ.ķI–Ÿ}d5E–’]o“ģšđ\W­f%3(#bGZ’â °ÆÞēį‘@Ó§z.yëŋWÛNĄŅ›ŊAĐē^)šw!Ddį�NZîĄũQrõiŊ]i0‡zâíÓM=6 Ę%Ø 2·Ï*ÔIÚ:E�Đš!‰ĶZø―īžĀõÅϒD>ÓKõģĀ%ÖTؘĸ"ŽæjfJĪ"ũœðÔTК&“Œ—íˆĮé\ÜÍŲũŸ57%Č8ĸn›ÆÔKŒÆŒįb ÝÜ&õ‘Ē™FÁÕæÐ #ÚÅEϘ4›ÏęE~Iš;r"ŨĸpâÝlЉĢÔEupĶmMV5cØÉPý)š—ĢDÛĖø&ņøŲrį3*čXO.`ݟCģãÜą–ïįq i7yķ(‰ …ļĩ?ÕbũX_Ð ž€nZûüļ6YxęáÄ[‘kGßŧ|ï‘]ðʝ—ÏōG5Ø-#Ï&GÐXûéŊÓu@žëË/3:äÆXSgâĀӋŧ‚ļl‘ ęĨƒ7Ļ€ĻĖX+rä˜_ËۊĄØHĖž―ÍÓĘ? Úš†”å”\]Ęæ1(ę“ðl=uųî&'ëÅëev§ïGPĻÆŸģmÓý‹b;DëþO3vs„…L‰wšþ–į€öE_8ĶßúrČ ŠÏÜĄ,%e`'Ĩðé7Føþ{Jq&xHIWĨøz@'D`$ÈÆĒ$‡~ĩųÄûc<ųëķÐēž3ÉĪ6øû=Œëˆaý§K+ûÜ9ŠÄí°S{oԆÛ.mŨÕ8Ÿ]•Ē˰ĶčõĶMw‰BÝšŊC\“`‰įWÕY™ /]6öš=ú\ōOï„ĸ]-OÆðÏŪ@˜{ųDŒbŠÜÁ[?ŽÞ•§gđ(cCß­­ŅHNéĢ―Đč6ˆžļž/3O|Ė#sļFēĸ8Õ�ۚļQčū•°Ąš*‰'ë™hˆqÔ#–ÄïČ>G›ŊČĸqÎl쿀Jþā‘ĄöϗŽũĘ3Į Â^uĢNHcÛÐEFāĄŊīŠđ-#M tąÁ™LÕIÁ€·þ™—L�­”7üWöýĮŲ|dŠFĨ(>,§Z%ï%\âĄéq�šRïŸ)―.| ß\šMӍ+Icdógy7~–Vfžęð`ûųVįFŸņŲüUŅfĩXeÍÄđŽąR*~č‚ūÕîâé›F^+ë(GKŅqßŪäVōŋŠ- n,q<ŽŲŊd{ā' ›X.SŽÓïŠÃÃÝŧČÄ<·B:Â@ĐpJĶ1 MFE%õ9ûēƒļ‚0ÖŪBŧ†`"šô&ÄŠÞŲs‹š{ݙ]ëJŦ3+‡…5eÂDČZ—]Ú‰UƒĀŸWĩô Õ#ÝĢ-õu ­ÔˆÛÄ +9V8$ëX,h†jÕ2°\xžžîŠLoĄņãsÐXHíYĻ·5æüĮ+ƒƒŠLbÝáųėã; &zĶv\-ĘBøïös?ž‘6/eQmdf)ė§åŌ\Åė-^ðËã.˜ë€ŌŽLcL‰ĸ]ܚŸRWņ;=°a|žÂõËFđ傧ųrję›Y9—"Ûa•nå _°E!,…~qÓ“`%^ŽīaŲîL9’jmNmó4kŪzF8Ēó}Ē-4güĒ4˜ÎØ>?1Ú{žNÍļÄ W!Ļ―Đt,b2F1iˆ"1)ąNŠļ‚cĩĖü­0îĸjýĘđ*Xî …I=Ē𠟂e°%‰Q5ņŽęԒš™ÅŲĮ`kæ(€ëˆ Qõ–æ§4jâÚn'wŸ8@`Óãå y<ŧāëJ!Ųtąîu*–ÚĨļ*PĐÆd Ýŧņ°ŧ8ŨwŸēÜUíîėÝŠo2ūŋ4}āïdCaį4‘8lœ‹Ó37ÚČó;ZnwWmõĻÐ1æÄĒ–a ūņc)kÎ ĨOŠŽ°ģ=Ž<[ŋ2ĩ7šFj0�ðYą™$ûeW}-ĀFVj34Ÿm=kęî�YU““îëĸ4T`öžæõÝVš%'ø=ũ,}øîĖãsūÛC)/€+ˉ[”ƒ=#5“D<ĮÃCmu‡Ō"Pŧėņí ÁĢ)rč%Š=Ŧå]ōVW !ö°ÎaßÂëóŲ0Z…TđÓčNöģÜŽĄõãžļqũĮĢũ(3aiîāï°Wvû$$ÂK]įĨVÏæ8ûģđÃá ôšö#h(įßmúhœû &øĒŅōc―hp ņSéÜ― Ũ!@ãKļī•ČOó’8Ö?ëĒÃL–m$ĸOĄ˜ ð™GöŪŠÛõëyũĮLŨļÉ"7”ôO0øÛķmRýZfÖ,‚Dû;æ-3ôíņsÂl…ū`üwÔ# r·šhÃvÖ3Ō!vAŨ…ŋ ōkO3œ�ïO…Ā8Pޕ!6]ėq§Ó ØðĄ~ó“ÏÖeā;7ĄHĩ°lýÔMoąÎ°øĶÄÛu5“3ķ1J”?ŌŋÁ@ @  ‚��A�AõqōĸŲ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/installer.ico�����������������������������0100777�0000000�0000000�00000061176�13761647206�023333� 0����������������������������������������������������������������������������������������������������ustar�00���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �00���h��–��� ���č��þ�����(��æ ��00����Ļ�� �� ����Ļ��ķ������h��^"��00��� �Ļ%��Æ'�� ��� �Ļ��nM����� �h��^��(���0���`��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ���ww�����xx‡wwp�www�ˆĸø‡ww��xˆˆˆw�xˆĸĸĸĸ‡wwččøøøˆwˆˆĸĸĸĸøˆ‡~ŽŽĸøpˆˆĸĸĸĸˆˆxččččøĸĸĸ‡ˆˆĸwĸˆ‡xŪŽŽĸĸøpˆˆĸ""'xwŠĻčččøĸĸĸĸ‡ˆˆĸ""""zŠŠŽŽŽĸĸĸũˆˆĸ"""'zŠŠĻččøĸĸĸĸøpˆˆĸ"""'ŠŠŠŠŽŽĸĸĸĸĸpˆˆĸ**"'ˆŠŠŠĻĸĸĸĸĸĸĸ‡ˆˆĸĒĒ"gˆˆˆŠĸĸĸĸĸĸø‡ˆˆĸ**"xˆˆˆˆĸˆˆĸĸ‡ˆˆĸĒĒ"xøøøøp�ĸøøøũˆˆĸ**"xøøĸ‡ˆˆ~þĒĒĢxøøøĸøˆĸøøøũˆˆï*Šđxø‡ĸ‡ˆˆ~þŦ››xøøøĸĸp�xøččøũˆˆïđđđwĸĸĸøˆþŽŽ‡ˆˆ~þ›››wĸĸĸĸĸĸĸĻčččįˆˆïéđđ·ĸĸĸĸĸĸøŠŽŽŽ‡ˆˆ~þþþþwĸĸĸĸøøˆŠĻččpˆˆïïïïîxĸĸĸĸˆŠŠŽŽpˆˆ~îîîîîįĸĸĸøøøøˆŠĻįˆˆ~îîîîîįĸĸˆˆŠŠ‡ˆˆ~îîîîîîxĸĸøøøøˆŠŠpˆˆ~îînîîîįĸˆˆ§ˆˆ~ææææææîwøøøøøøˆpˆˆ~nnnnnnngxˆ€ˆˆvæ��æææææwwˆˆˆ�ˆˆ~gĸø���nnngwwpˆˆxĸĸĸĸø���æææpˆˆwĸĸĸĸĸĸĸĸø������ˆ‡‡wwwxĸĸĸĸĸĸĸĸø‡wwwwwwwwˆĸĸĸĸĸ€ũwwwwwwwwwxˆˆ‡xxĸũĸĸˆwwwwwwx‡wpĸũĸĸĸĸø‡wwwwĸĸ€ĸĸĸĸĸĸĸĸĸĸøĸĸĸ‡ĸøĸĸĸĸĸĸĸĸøĸĸĸũĸwĸĸĸĸĸĸĸĸĸøxĸĸĸøpwˆĸĸĸĸĸĸĸĸøxĸĸĸĸpwwwˆĸĸĸĸĸĸĸøwĸĸˆ‡wwwxĸĸĸøqxˆˆwqwwwwwwwĸĸĸĸĸ��þ�øĸ��ü�āĸ��ø��€�ĸ��ð������ā����?��ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā����?��ā������ā���ĸ��ā���ĸ��ā���ĸ��ā����ĸ��ā���ĸ��ā���ĸ��ā���ĸ��Ā���ĸ��Ā���ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ��0���ĸ��ĸ��ĸ��ĸþ�8?ĸ��ĸĸĸĸĸĸ��(��� ���@��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ��wwp����‡ø‡wp��xˆw�x‡ĸĸĸ‡wxˆøø‡ˆ‡ĸĸĸˆxŽĸpˆ‡ø'ˆˆxččøøĸũˆ‡ø""'ŠŽŽĸøpˆ‡ø""jŠĻččĸĸĸ€ˆ‡ø""xŠŠŽĸĸĸĸũˆ‡ø*"xˆŠĸˆĸĸøũˆ‡øĒĒxˆˆø�ĸˆˆ‡Ž*#xˆðˆøøøˆ‡čĒđxøøðˆþˆˆ‡č››ĸ�ččøˆ‡ŽđđxøøĸøúŽŽˆˆ‡î››xĸĸŠĻčįˆ‡îîé·øĸĸˆŠŽ€ˆ‡îîîîĸĸøøŠŠpˆ‡ææîîxĸĸˆŠĻˆ‡nnnnįĸøøˆ ˆ‡ā�æææw€ˆ‡ĸ��nnwwwˆ‡ĸĸĸĸ��ææįpˆwwwĸĸĸ����wũwwwwxĸˆˆũwwwwwxˆ‡pĸũĸĸˆ‡wx‡€ĸĸĸĸĸøxĸũwĸĸĸĸĸĸũĸĸũwĸĸĸĸĸĸĸũĸũwwwwĸĸĸũø‡wwwqwqøĸĸðĀĸā��?Ā��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��?€��?€��€��ĸ€��ĸ���������€��ĸĀaĸ(������ ��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ���wpwpĸ‡ˆ‡"xïøpĒzŽĸpŠxĻ�ˆ€đxˆp›úþpŽxĸøĻčįĸø€ŽŽwwĸĸˆ€wwwwpxũˆˆˆðĸĸøwwwwwwᇇøĀxŠ€ĸĸ€�ũ€�‡ø€�xˆ€�ˆĸ€�ũ€‡ø€xˆ€�€ˆ€‡Ž�xˆ�ˆ�ø(���0���`�����������������������������zf‚�����ĸðĸ�ĸúĸ�ĸýĸ�ĸÞý�ĸËõ�Œ‡ˆ�ĸÅÎ�ĸžÅ�ĸĐģ�ýĖŌ�ĸģđ�ĸäæ�ĸģķ�˜op�ôšŧ�ĸ™™�ĸ››�ō““�ĸžž�ĸĄ �ų�Ė‚‚�ĸĪĪ�Ũ‹Š�ĸ§§�ųĨĨ�ĸŠŠ�晙�™ff�ĸ­­�ōĪĪ�•ee�ųŠŠ�‰^^�ĸ°°�Īqq�ĸģģ�yUU�ĸĩĩ�Žzz�Ÿqq�ĩ‚‚�ĸđđ�ōŊŊ�ĸšš�ŒŒ�Ķyy�üđđ�“mm�ĸūū�ĸĀĀ�ĸÅÅ�ĸĮĮ�ZFF�·�ĸËË�ĸĖĖ�ĸÐÐ�ōÅÅ�ĸŌŌ�ĘĶĶ�ū�Ŋ’’�I==�ĸÖÖ�xee�čÄÄ�ĸŲŲ�ĸÝÝ�Ō··�ĸââ�ndd�ĸéé�ŲÆÆ�úįį�ĸîî�ôãã�ÞÐÐ�æŲŲ�âÕÕ�ĸõõ�ĸųų�ĸüü�JII�įåå�VUU�üûû�ũöö�ŌŅŅ�Ÿlk�Ŧut�ԝ›�Į“’�ųÁĀ�ųÆÅ�ųËĘ�óÓŌ�Ģol�ĩ|�ŧ†ƒ�‰fd�­ƒ�ÚŠĻ�æ―ŧ�öÏÍ�îŨÖ�Ōŋū�į°Ž�Îē°�™kf�ĸĖĮ�îäã�Ęķģ�ôíė�ĸĖÂ�đŦĻ�ęÜŲ�ð―­�Ŧub�ĸĖŧ�ôÁŽ�ߎ”�Žy`�ĸĖģ�ĮÃÁ�æäã�ĩ~^�Ė’p�ĸš‘�ĸĖŽ�ÉŠ˜�åŋĶ�ģĨœ�đķī�íķ�ĸř�ėÄĶ�ØđĄ�ũ—�ĸĖĪ�Ėēœ�ĸə�…~x�ëāÖ�ĸʔ�ĸĖ™�ĸ͞�þÓ§�ĸÚĩ�æĖģ�ĸęÕ�ĸðá�îâÖ�ĸųó�öņė�ėčä�Ũ—S�ĸƇ�ĸāĀ�þäÉ�Š�ĸõę�Üx�ĸži�ĸūp�ō·n�æŽi�ĸĀu�ĸÂ{�ę·y�üˏ�áÁ›�ôâĖ�äÞŨ�éäÞ�üēM�þķY�ĸŧd�ûŅ™�įÐē�íÞĘ�ÕÉđ�ų•�ĸĒ�ûŠ4�ōŋu�ũÄx�ûČ|�öϖ�ë˛�ėÓŪ�õÛķ�ĸýú�ëđm�þøî�óíã�―žš�ÃŪ{�ŲØÕ�juH�ēV�ŋÝŪ�M€3�XēF�€Æt�&Œ�š�Ļ�°#�#·0�(Á<�5ÎQ�Hám�[ņ�§ßá�RÍÔ� Đ�IŪü�ŠąŨ�5•ų�Llš�ĸĸĸ�ųųų�ōōō�îîî�ëëë�ééé�æææ�äää�âââ�āāā�ÞÞÞ�ÜÜÜ�ÚÚÚ�ÖÖÖ�ĖĖĖ�ÆÆÆ�ÁÁÁ�ūūū�ŧŧŧ�đđđ�ĩĩĩ�ŊŊŊ�ĒĒĒ�”””�}}}�rrr�ggg�ddd�]]]�===�666�000�����ĸĸĸĸĸĸĸĸĸWúúĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúûWUüþüúúúĸĸĸĸĸĸĸĸĸĸĸĸøøúúúøøĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúũëZóúWUüýþWúúĸĸĸĸĸĸW7'''''7AþUĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúöíVÂÂÂÂČÆöũûWUýþüøĸC#[/>iiD>8!#7þWĸĸĸĸĸĸĸĸĸĸĸĸųôZZSSSSSSSS~ǐųWU'%]469=EFHJNl0#AþĸĸĸĸĸĸĸĸĸĸîZíí›››››››››˜““”Į!d"(.469=EFHJMTr7þĸĸĸĸĸĸĸĸĸõėņõï°ĢĢĢĢĢĢĢĢĢ”ˆ[$(.469=EFHJßßq*7þĸĸĸĸĸĸĸĸõóõîZ°ĢĢĢÍÎËœĢĄŒc$(.469=EFMßßßq*7üĸĸĸĸĸĸĸõííôņ°™™™ÐÐÐÐÓÍĘĮ\$(.469=ETßßßßP!AWĸĸĸĸĸĸõïöóZ‘™™™ŅŅŅŅŅÐÐÐ $(.469Fßßßßßßr#þĸĸĸĸĸĸõîZëČŊ˜˜˜ŌŌŌŌŅÐÐÉe&$(.46Jßßßßßßß07UĸĸĸĸĸõęęęëŊ˜˜˜ÓÓÓÓŅÐÐfm,& .5ßßßßßßßßK#þĸĸĸĸĸôéęęęŊ˜˜˜ÔÔÔÔŌÐÏ%53,&  ßßßßßßßß0AũĸĸĸĸôčéęęŊĄĄĄÕÕÕÕŌÐĖ/953,& ßßßßßßß>'UĸĸĸĸôįčéęŊĄĄĄÕÕÕÕÓÐÉ]:953,&3 ßXYYYYO#þĸĸĸĸôįįčéŊ   ÖÖÖÖÓÐÉi=:953,&H d*gKYsssssssþũĸĸĸôæįįčŊ   ÖÖÖÖÔÐÉi=;:953,MØ „*sœqqqqqqq)Aũĸĸĸôåæįį‘–––ŨŨŨŨÕÚ�m:::::::Rmؖ–ksvvvvvvvgAũĸĸĸôååæį‘–––ŨŨŨŨŲÝ�]:::::::M *ؖŠB$1_`ajbgAũĸĸĸôåååæ‘–––ŨŲÛÛÛÝÞ^::::::;MK[d[ 6$(.469+Aũĸĸĸóäåå呕••ÝÛÛÛÛÝÞ)::::EMTß</ R$(.46%Aĸĸĸĸóãäå呕••ÝÝÛÛÛÝÞ`=JSßßßß3$(.WĸĸĸĸóãķšĀ‘ÜÛÝÛÛÝÝ�Gßßßßßßßß $(]#ĸĸĸĸó•ļļš””””””·ðÜÞÞ0ßßßßßßßßßB &$e'ĸĸĸĸĸōžļļĩš“““““““““‰cKßßßßßßßR:953,&ĸĸĸĸĸōŧļĪĩš’’’’’’’’’’‚*Yßßßßßß =:953,&'ĸĸĸĸĸĸņŦĪĪĩšŸŸŸŸŸŸŸŸŸŸŸ‚\8ßßßßßTFB=:953,&[ĸĸĸĸĸĸņŦĪĪ—ŪŠŠŠŠŠŠŠŠŠŠŠŠˆc?ßßßßRHEB=:953,&\fĸĸĸĸĸĸĸņŦĪ­âŪĶĶĶĶĶĶĶĶĶĶĶĶĶĻo?ßßßM HEB=:953,&"\fĸĸĸĸĸĸĸĸðķ°îėŪģģģģģģģģģģģģģģĻxgsTMJ HEB=:953-\2ĸĸĸĸĸĸĸĸĸðZõôåŪēēļđđššąēēēēēēēē€nNMJ HEB=:`^[@ĸĸĸĸĸĸĸĸĸĸïëëîîŪąđīÅÁūžšđļđšššąąąž|8nDDbih/[gĸĸĸĸĸĸĸĸĸĸĸĸïėõôæŪš―YYááââããĀŋŧąšļđ𹹞€x!!ffĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸïęįāYĄģāāYYááââããäåæįčĩŋÃąšļđđđøüúúĸĸĸĸĸĸĸĸĸĸĸĸĸîXāāāķÄXāāYYááââããäåæįčééęëė·­ÃõúWUøĸĸĸĸĸĸĸĸĸĸĸîXXãė?[8?GOQYááââããäåæįčééęëėėėZZíôöĸĸĸĸĸĸĸĸĸĸĸĸîáęėė0c%%\\))8?GlQVãäåæįčééęëėėėZôôĸĸĸĸĸĸĸĸĸĸĸĸĸîęęęlc%%\\))dd++ee//>nléįčééęëėZõöĸĸĸĸĸĸĸĸĸĸĸĸĸņįįįሁed))dd++ee///^^^OäáYYáâöýĸĸĸĸĸĸĸĸĸĸĸĸĸĸōäää°ģĨП’“Œˆ{{]^///^^^^QáāßSMJJôýĸĸĸĸĸĸĸĸĸĸĸĸĸðæâââÁĨП’“””ƒƒƒ}zwmmhvLHFFHJMZûUĸĸĸĸĸĸĸĸĸĸĸĸņYYYYŽĐŸ’“””ƒƒƒ}}}yyyti=BF JMRSþĸĸĸĸĸĸĸĸĸĸĸĸðX› īП’“””ƒƒƒ}}}yyytt†DF JMRSßíUøĸĸĸĸĸĸĸĸĸĸððōēĨП’“””ƒƒƒ}}}yyyttpøu JMRTßßáøþĸĸĸĸĸĸĸĸĸĸððô§ĐŸ’“””ƒƒƒ}}}yyyttpDûîOMRTßßßßōûúĸĸĸĸĸĸĸĸĸĸĸððōôr††ŽŽ‹……ƒ}}}yyyttppGWĸôRTßßåZðōĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸððððððððð‡luunniiDuøĸĸðîîîîĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸððððððððððĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ��þ�øĸ��ü�āĸ��ø��€�ĸ��ð������ā����?��ā������ā������ā������ā������ā������ā������ā������ā������ā������ā�������ā�������ā�������ā�������ā�������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā����?��ā������ā���ĸ��ā���ĸ��ā���ĸ��ā����ĸ��ā���ĸ��ā���ĸ��ā���ĸ��Ā���ĸ��Ā���ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ������ĸ��Ā��ĸ��þ��?ĸ��ĸĸ�?ĸĸ��(��� ���@�����������������������������vfˆ�����ĸøĸ�ĸüĸ�ą°ą�þæý�ĸôþ�ĸÍņ�}Ž�öĩÎ�ýÄŲ�ØÃË�õōó�óāä�ĸôö�ė§°�þÓŲ��ݔ˜�ĸËÎ�ĸáã�š Ą�ĸœ�Į|~�ü§Ļ�ĸŠŦ�Ɔ‡�ĸÂÃ�ԕ�ĸÔÕ�ĸ™™�ĸž�ĸžž�ĸĄĄ�ĸ§Ķ�·zz�坝�ĸą°�ĸēē�ýēē�ĸķĩ�°~~�Ĩww�rRR�ĸšđ��—nn�úļ·�ķ……�ĸū―�ĸÆÆ�ëķķ�ÖĻĻ�F77�É  �ĸĖĖ�ĸÐÐ�ûĖĖ�|hh�ĸŨŨ�ĸÛÛ�ĮŦŦ��ûÚÚ�QGG�Íĩĩ�4//�ĸčč�ÚĮĮ�ōßß�-**�ĸïï�ÛÏÏ�äÛÛ�čßß�ÓËË�wss�ĸųų�ðęę�ßŲŲ�ƒ€€�ÕŅŅ�jhh�ûøø�ŅÎÎ�CBB�ĸýý�ýüü�ÞÝÝ�ŌŅŅ�ʖ•�ĸÄÃ�ĸËĘ�öĘÉ�Ԋ†�óÄÂ�øÖÔ�ņÐÎ�ēvq�ĸÎÉ�Õš·�ą|u�Μ•�Ĝ–�ýËÂ�óÁ·�ûũö�ū‘…�øÅ·�ðÅš�Õ·Ŋ�ÛĻ—�ĸÍŧ�ëÂģ�ĸųũ�đ{�§‹�―…i�ĸÍī�õïė�ëåâ�Ӟ‚�áĀŪ�ðéå�æķ•�âØŅ�ĸÎŦ�ėčå�ƊZ�öØ�ĸÍĨ�ŌÅš�Ȁ=�ĸïā�ęãÝ�ĸ͚�ĸ͝�óɟ�ōĖĶ�‡s_�Ë·Ģ�ņāÏ�éßÕ�íėë�Ýq��þÂ�ā­x�ĸɎ�þĖ–�ÛĮē�zqg�ûęŨ�þžj�âĻb�ĸĀv�ĸÄ{�ĸÂ{�ĸŌž�ųÞ―�ĸæČ�ó‡��ĸąH�ýļZ�ĸšd�é°b�öʓ�ũÖŽ�üÝķ�þöė�þĐ*�ė/�þŪ>�îŦI�ôđc�ôŋq�îĮŽ�åŅģ�―ī§�ōūl�ōʍ�ÆÂŧ�Ųě�ÚÏš�ŨÓË�ĖËČ�{{U�ĸĸú�įįæ�ŲáŽ�ŅßŪ�ÉÞ°�Îâš�A|,�°ŲĨ�/š�€Įx�<Ž5�™�Ŋ�đ-�(ĮA�5ÕU�Jčs� …B�Yũ“�ĨĐĻ�ĒĖĖ�üĸĸ�ęëë�ÛÜÜ�FĘŅ�äįč�íïð�ęėí�áäæ�JŽų�ˆķÜ�1ō�ĮĘÍ�ŧ―ŋ�øúü�õũų�áãå�ÚÛÜ�ŲÚÛ�ŨØŲ�éíō�öųý�ßáä�ÔÖŲ�ŲÞæ�îóü�ÉĖŅ�DUĢ�üüþ�ŲŲÚ�ĸĸĸ�ééé�âââ�ÚÚÚ�ŲŲŲ�ÔÔÔ�ŌŌŌ�ÐÐÐ�ÎÎÎ�ËËË�ÁÁÁ�···��sss�ppp�\\\�MMM�999�&&&�����ĸĸĸĸĸPüû.ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸPLûUBFUûúĸĸĸĸĸR@55BýûĸĸĸĸĸĸĸĸĸĸR͏ XöøRüýFþü:+.46*+5þRĸĸĸĸĸĸĸøÛņššššrŒt–+#-28<CE=+FUĸĸĸĸĸĸÛöũxĻĻĻrV…s^(,7<Cėx.BUĸĸĸĸóũũö†ĻŋÄÃÁĩŊy!&,[7VėN.FúĸĸĸóÛö†ĻūÅÅÅÅÂe !&,[\CėėėI+þĸĸĸóöá뎅ūÆĮÆÅĀ$(" !"%,[Mėėėė5ųĸĸóõîߎ—―ĮČĮÅđ,%" ėėėėėN+ýĸĸóõîŅŽŸ―ČÉĮÅt,%" ėėWWWtF>ĸYôŧXŽŸ―ÉĘČÅg\(1eedSwwwj=B>ĸōóŧ䎞žĘĘÉË67\8Ξ) †††{A5>ĸōYíލ§žĖĖŌŲ777\;4ÍĶe/_]`n5>ĸņōÐӍĶķŌŨŨŲ\\\;C6b2"&,\45>ĸņåԆƒŲŲŨŲ�hVė  &ZUĸĸņ·Ē­ˆŠÛØØŨéAėėėėė !'*Lĸĸåĩ Ī”‡””‡‰$) ėėėėC2(%" !$+ĸĸĸáĩ ™“““““““^ėėėV<8\,%" #Pĸĸĸáĩ’šœœœœœ›‘uAėėr;8\,%^:ĸĸĸĸá•|ðžĢ˜Ģ˜˜˜˜˜˜u=ęrC;8721^.ĸĸĸĸĸáōÛč§ĄĐŦŦŦŦŦĄĒĒ€0 C<930>ĸĸĸĸĸĸðYÛÚĶŦ—wĶģŪ­ŦĐĐŠ„uk0.>ĸĸĸĸĸĸĸĸðáî㧟ÏÜÝįįâŧŽ}°ŊēŽŠŠ‹BýüĸĸĸĸĸĸĸðíėÐAADINÝ ÔÔÕÓÖäææáķīøøĸĸĸĸĸĸĸïXîå*.**)6AD}IIîXïáåāöĸĸĸĸĸĸĸĸõXÖķuee*))))006OÕÔíŧÍüĸĸĸĸĸĸĸĸĸÛÔâĨĢ‘”||offZZZJjGGþĸĸĸĸĸĸĸĸļÐãw›‘”ˆˆ‚~~vvvlia<<GNüûĸĸĸĸĸĸĸļw§“‘”ˆˆ‚‚~~vvphh?CGMėøþĸĸĸĸĸĸĸļąĒ‘”ˆˆ‚~~vvpphc_ûHVėėXųĸĸĸĸĸĸĸĸļYƒdnzzqqmhcdøõNíðõôKĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸKKKKQKTĸĸKKKKĸĸĸĸĸĸĸĸĸøĸĸðĀā��Ā��Ā��€��€��€��€��€���€���€���€���€���€��€��€��€��€��€��€��€��€��?€��?€��€��ĸ€��ĸ���������€��ĸĀaĸ(������ �����������������������������éčð�§ĄÃ�íéî�����ĸóĸ�ëäę�äÕß�|~�ōūÜ�ÆĨļ�üŧÐ�æĮŅ�ĸóũ�ŲĖÐ�ĸōö�ņāä�ýÁË�ĸËŌ�ĸąš�ĸ·―�˧Š�ĸĪ�ĸÉĖ�ĸÛÝ�ėÚÛ�ũĐŦ�ĸģī�―†‡�ĸÉĘ�ŞŸ�íËĖ�ĸÝÞ�ĸŸž�ĸ  �ĸĄ �üŸŸ�ĸĢĒ�ĸ­Ž�ē||�ĸģģ�üķķ�ĸū―�ŧ�‚cc�`II�ˆii�ĸÆÆ�·‘‘�}}�N>>�ĸÎÎ�ÍĨĨ�tt�ûËË�oZZ�|ee�=22�;11�ĸŲŲ�ĸęę�ÕÃÃ�ÔÃÃ�þėė�þîî�ĸðð�ÔÏÏ�ĸûû�îęę�ėéé�^]]�ĸþþ�úËĘ�ĀĶĨ�ģƒ€�ĸÏÍ�Į°Ŋ�ÉŊ­�ÛĖË�Ɔ�ėÄĀ�čâá�į°Ĩ�ËĶž�ĩ€t�843�ėäâ�ĸÔĮ�ĸõō�qfb�øõô�ė·Ģ�šĢš�ĸÐŧ�įūŽ�ãÐĮ�øôō�ĶĪĢ�ŨÕÔ�ō― �Ō·�ĸÎą�Č­�ØÄļ�âķ˜�øÄ�ĸÎĐ�íåß�îÁ�þĖĄ�ՙ]�öɛ�ĸŌĶ�õŌŊ�éåá�BA@�üķh�ýŋ�ûĮŽ�㷈�ČŠ‰�ü͓�ÝÂĢ�ũ°P�ōŦQ�ĸđ^�ĸÂv�Ō§m�ô˖�ĸĀh�üŋh�úÄx�āąp�áđ€�öÚģ�ĸĮq�û˂�ØŅÆ�óÜģ�įÔī�óáū�æâŲ�ņåÉ�ųóá�ðëÓ�ĸýō�œšc�Ÿt�âōÖ�)Š!�!­%�� �ą,�1ÃB�Sæk�]āĩ�lmm�§ĻĻ�6ĶĘ�a­õ�ęņø�žŋÂ�ÕÖŨ�:–û�âäé�ąąē�ĸĸĸ�ÆÆÆ�ūūū�����“““�ŽŽŽ�ŒŒŒ�„„„�}}}�vvv�sss�nnn�bbb�WWW�PPP�KKK�:::�444�///�...�---�ĸĸĸ�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ĻĻĻąģŊŊĻĻŊŪ°ŊĻĻĻĻĻŽ`ErT,-468đĻĻϜa“ŽkN.:><1ļĻĻĪA•”‘!%);Ĩ=9ŊĻĪP˜–’" ĨĨ7ķĻĪU‹™—e KY_H·ĻĪC‰š J[5G3ĩĻĪ…pžĒWB 'ŊĻ~{onyRĨ@$#+ĻĻwv}|€sc2(&ĻĻĻ ˆ†‡‚zmg]/0ĻĻĻĻĄj^�DqŒŠ„ƒXĻĻĻĻĻMfSI* ŸĢ›ĻĻĻĻMˆxthbZQO;?ēīĻĻĻMulid\VLFͧĻĻĻMMMMMMMMMMMMĻĻĻĻá‡õîĀ—―€Įŀ�,%€� €�ė€�ėė€�ýĸ€õ―€Įŀ,€��WW�F>(���0���`���� ����������������������������������������������������������K���p���m���X���?���+��������� ������������������������������������������� ������������������������ ����������������������������������������������������������������� ���&888’ZZZėHHHá666Ō·���œ���Ž���y���`���F���1���#���������������������������&���@���]���p���y���z���y���o���Y���?���&�������������������������������������������������������� ���3HHH·zzzĸŲŲŲĸÏÏÏĸģģģĸĸbbbûSSSî===Ú"""ŋ Ķ���”���€���g���Q���:���(���������(���S0 ™_@@ÍvNNä|SSë|RRė|RRėtMMįR66Ō(ļ���š������S���'��� �����������������������������������������LUUUŨ•••ĸÎÎÎĸæåäĸĸýúĸĸýúĸĸýúĸĸýúĸŲØÕĸ―žšĸ—–•ĸ{zzĸYYYóCCCß111ĖŊ���š���‹���t���gU99­Œ^^óœllĸŋ‹‹ĸÏĒĒĸæŧŧĸæŋŋĸæÃÃĸƧ§ĸķĸ–ffĸŠ\\ũF//Ņ���Ą���z���C�������������������������������������;;;UeeeįąąąĸŅŅŅĸÐÐÐĸįäâĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸėčäĸĮÃÁĸŠĸ…~xĸdddûOOOé?77Ô}SSęĶppĸؚšĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸččĸõååĸŲūūĸĶxxĸ‚WWó&Ā���’���T������������������������������SSS)}}}óĮĮĮĸÓÓÓĸËËËĸĘĘĘĸčäáĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸįÐĸĸĖ™ĸĸĖ™ĸĸΟĸÆ ƒĸ–ffĸžĸųŦŦĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸččĸĸîîĸĸûûĸĖģģĸ™ffĸF..Ó���˜���V��������������������������```HĄĄĄĸÖÖÖĸŧŧŧĸĸĀĀĀĸčäßĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸóįĸĸĖžĸĸʙĸĸʙĸė·ĸŸliĸŲ‰‰ĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸééĸĸĸĸĸĸĸĸĸėââĸŸppĸF..Ó���—���S����������������������aaaHĢĢĢĸĩĩĩĸĄĄĄĸÆÆÆĸÓÓÓĸéãÝĸĸóčĸĸóčĸĸóčĸPĩIĸ€ÆtĸŋÝŪĸöņéĸĸóčĸĸãĘĸĸșĸĸșĸų–ĸĶrlĸĖ€€ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸîîĸĸĸĸĸĸĸĸĸĸĸĸĸėââĸŸppĸF..Ó���Ž���A��� ����������������bbbHĪĪĪĸÍÍÍĸĖĖĖĸ°°°ĸŧŧŧĸéâÛĸĸņãĸĸņãĸĸņãĸĸĸĸĸ4Ū1ĸ`ŊCĸēVĸŋŧsĸƐ|ĸģvvĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸûûĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸæŲŲĸ’aaû&Ā���y���'���������������cccHĨĨĨĸÂÂÂĸ™™™ĸĩĩĩĸŌŌŌĸęâÚĸĸïßĸĸïßĸĸïßĸĻĸĻĸĻĸĻĸ Ķĸ�™�ĸ�™�ĸ“ ĸ™ffĸōĪĪĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸÝÝĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖģģĸ‚WWó���Ą���S���������������dddHĶĶĶĸĮĮĮĸŌŌŌĸŲŲŲĸØØØĸæßØĸĸėÚĸĸėÚĸĸėÚĸ°#ĸ°#ĸ°#ĸ°#ĸŠĸ�™�ĸ�™�ĸ`y@ĸŋ……ĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸëëĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĶyyĸF//Ņ������(�����������eeeH§§§ĸÜÜÜĸÜÜÜĸÛÛÛĸŲŲŲĸâÝŨĸĸęÕĸĸęÕĸĸęÕĸ đ0ĸ đ0ĸ đ0ĸ đ0ĸĐĸ�™�ĸ�™�ĸi`ĸė­­ĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸģđĸĸšÄĸĸššĸĸÄÄĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŲÆÆĸŠ\\ũ������F��� ��������eeeHĐĐĐĸÞÞÞĸÜÜÜĸÜÜÜĸÛÛÛĸãÝŨĸĸčŅĸĸčŅĸĸčŅĸ(Á=ĸ(Á=ĸ(Á=ĸ(Á=ĸ­ĸ�™�ĸ&ŒĸĶssĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸ―ÉĸĸÓôĸĸĖĸĸĸÏĸĸĸÖûĸĸßîĸĸþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĶyyĸ2""Â���j�����������fffHŠŠŠĸāāāĸÞÞÞĸÜÜÜĸÜÜÜĸäÝŨĸĸåĖĸĸåĖĸĸåĖĸ1ĘIĸ1ĘIĸ1ĘIĸ1ĘIĸą%ĸ�™�ĸM€3ĸŋŒŒĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸĖÓĸĸåĸĸĸŲĸĸĸÄíĸĸÅęĸĸÖúĸĸãĸĸĸðĸĸĸþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÆĐĐĸkGGä���…���$��������gggHŦŦŦĸáááĸāāāĸÞÞÞĸÜÜÜĸåÞŨĸĸãĮĸĸãĮĸĸãĮĸ;ÔYĸ;ÔYĸ;ÔYĸ;ÔYĸ·-ĸ�™�ĸcvFĸĖ››ĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ――ĸĸōĸĸĸāųĸĸĐģĸߍĸԊŠĸōšžĸĸėĸĸĸîĸĸĸúĸĸĸĸĸĸþþþĸüúúĸúũũĸųõõĸųõõĸųõõĸáŅŅĸŠ\\ũ���”���.��������iiiH­­­ĸâââĸáááĸāāāĸÞÞÞĸåÞÖĸĸáÃĸĸáÃĸĸáÃĸDÝfĸDÝfĸDÝfĸDÝfĸ"ŧ3ĸ�™�ĸssMĸæđđĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸááĸĸōĸĸĸšÄĸŋzzĸŸvuĸŊ…}ĸ™ffĸŲÆÆĸĸņĸĸĸúĸĸųöõĸôîėĸôíëĸôíëĸôíëĸôíëĸôíëĸôíëĸ™ffĸ������?��������jjjHŪŪŪĸäääĸâââĸáááĸāāāĸæÞÖĸĸßūĸĸßūĸĸßūĸLåsĸLåsĸLåsĸLåsĸ&ŋ:ĸ�™�ĸssMĸæļļĸĸŌŌĸĸÐÐĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸėėĸĸōĸĸ雛ĸ˜opĸĐäåĸĸßūĸÉŠ˜ĸŸppĸũíðĸĸúĸĸöņïĸïåãĸïåãĸïåãĸïåãĸïåãĸïåãĸïåãĸĐ~}ĸ5$$ļ���E��������kkkHŊŊŊĸåååĸäääĸâââĸáááĸčßÖĸĸÜđĸĸÜđĸĸÜđĸWðƒĸWðƒĸWðƒĸWðƒĸ/ÅQĸ Đĸ|i†ĸæģģĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸōōĸĸōĸĸ掎ĸ–€ƒĸĶęîĸĸÜđĸĸÜđĸ™ffĸîŨÖĸĸúĸĸôíėĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸ­ƒƒĸ5$$ļ���E��������lllH°°°ĸæææĸåååĸäääĸâââĸéßÖĸĸÚĩĸĸÚĩĸĸÚĩĸ_øĸ_øĸ_øĸ[ęĒĸOÅÛĸ0ųĸvi†ĸԟŸĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸïïĸĸōĸĸųÏŌĸŸppĸ§ÎÐĸĸÚĩĸėÄĶĸ™ffĸĸģķĸĸúĸĸĸÕÕĸĸ°°ĸüđđĸųÁĀĸųÆÅĸųËĘĸöÏÍĸóÔŌĸŊ‚‚ĸ5$$ļ���E��������mmmHąąąĸįįįĸæææĸåååĸäääĸęāÖĸĸذĸĸذĸĸذĸ\čģĸUÕĖĸOūėĸMģĸĸMģĸĸ0ųĸ`mĶĸƓ“ĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸÏÏĸĸėėĸĸōĸĸĸðĸĸŲÆÆĸŸmkĸģƒyĸŸmkĸĖ€€ĸĸĘŌĸĸúĸĸĸĮĮĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸ쁁ĸ6$$ķ���?��������mmmHēēēĸéééĸįįįĸæææĸåååĸëāÖĸĸÕŽĸĸÕŽĸĸÕŽĸ<Ēĸĸ@ĶĸĸEŦĸĸJ°ĸĸMģĸĸ2‘ųĸNnĩĸŽyyĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸŲŲĸĸėėĸĸüüĸĸĸĸĸĸôĸĸĸåĸĸĸîĸĸōÅÅĸƋ‹ĸ◗ĸĸšÄĸĸîĸĸĸôųĸĸĪĪĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĢrrĸ8&&Ū���.��������nnnHīīīĸęęęĸéééĸįįįĸæææĸëāÕĸĸÓ§ĸĸÓ§ĸĸÓ§ĸ9Ÿĸĸ<Ēĸĸ@ĶĸĸEŦĸĸJ°ĸĸ7—ųĸ0mŌĸ™ffĸųÆÆĸĸŌŌĸĸééĸĸųųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸýĸĸĸįĸĸĸŲĸĸĸÉõĸĸÆįĸĸÐïĸĸãĸĸĸîĸĸĸ―Āĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸõššĸ™ffĸ������"��������oooHĩĩĩĸëëëĸíāÍĸų­:ĸėÓ­ĸėáÕĸĸŅĒĸĸŅĒĸĸŅĒĸŊÜĸ^Ļîĸ<Ēĸĸ@ĶĸĸEŦĸĸ<œųĸ#ißĸ{ayĸŌķķĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúĸĸĸßûĸĸĖĸĸĸÏĸĸĸŲĸĸĸÜõĸĸžÂĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸܟŸĸ…XXï���c�����������pppHķķķĸóÓĢĸĸ™�ĸũ‘�ĸëŅŪĸíáÕĸĸΞĸĸΞĸĸΞĸĸΞĸĸΞĸĸΞĸÏÄķĸđĀÂĸ’ģŅĸZ~ÎĸFVĶĸĶyyĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÕÕĸĸÆĖĸĸÃÏĸĸŋĮĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸŋƒƒĸhFFŌ���@��� ��������rrrHļļļĸũÄxĸũ‘�ĸíˆ�ĸéаĸîâÕĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸřĸĸĶ™ĸĶnlĸŲÆÆĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸööĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸųĨĨĸŸkkĸ4""���!�����������sssHđđđĸōŋxĸíˆ�ĸä�ĸčϰĸðâÕĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸŧ”ĸԌ†ĸŸppĸųõõĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸååĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĖ……ĸ€UUå���C��� ������������tttHšššĸíŧxĸä�ĸÛu�ĸįÎēĸðâÓĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸļĸŽusĸ쌌ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸýýĸĸÞÞĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸō““ĸŸjjĸ:&&€������������������uuuHŧŧŧĸëļyĸÛu�ĸŅk�ĸæĖģĸōâŅĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸųą‚ĸĢojĸŋŸŸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõõĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸųĸŽppĸqKKÂ���)�������������������vvvHžžžĸæģzĸÖ|ĸã―–ĸïïïĸóãÏĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸæ­mĸ™kfĸŋŸŸĸĸĸĸĸĸĸĸĸĸĸĸĸĸîîĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸųĐĐĸŽrrĸ„XXÝ���2��� ��������������������vvvHūūūĸîÛĮĸëåÞĸÅÅÅĸÕÕÕĸóâÍĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸæŦdĸŽveĸރƒĸōėėĸĸüüĸĸïïĸĸééĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸōŊŊĸŽttĸ‰^^â,8��� �����������������������wwwHŋŋŋĸÓÓÓĸŸŸŸĸ°°°ĸįįįĸôâËĸĸ·ZĸĸĩTĸĸ ĸĸŸĸĸĢĸĸĐ.ĸĸŽ9ĸĸ°Dĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·ZĸõēZĸģaĸ™ffĸ˰°ĸōááĸĸïïĸĸééĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸųÅÅĸĖ••ĸŸkkĸ~TTŪ����������������������������������xxxHĀĀĀĸÚÚÚĸŲŲŲĸĮĮĮĸÆÆÆĸõâÉĸĸģOĸĸĨ#ĸųŌ™ĸóíãĸõÛĩĸöϖĸöÃwĸúŪ;ĸýĢĸĸ ĸĸ ĸĸ§)ĸĸŠ2ĸĸ­<ĸĸģOĸĸģOĸĸģOĸߟSĸŽy`ĸ™ffĸđ‘‘ĸŌēēĸæČČĸæÄÄĸōŅŅĸæūūĸŲŽŽĸŋŽŽĸŸllĸ^^ÏnIIY��� �����������������������������������yyyHÁÁÁĸÕÕÕĸŸŸŸĸ°°°ĸäääĸöãČĸĸŽ8ĸûČ|ĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸîÔŪĸîΞĸōŋrĸö°Gĸų§*ĸĸœ ĸĸŸĸĸĨ$ĸĸĻ,ĸïĄ7ĸϏRĸķ}[ĸĐt_ĸ“ffĸ–ffĸŠccû~VVãpNN§N;;S������ ���������������������������������������{{{HÂÂÂĸÜÜÜĸáááĸøøøĸöööĸøãÆĸþ―^ĸúúúĸøøøĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸåŅĩĸčȘĸíšnĸņąRĸõĐ6ĸĸœĸĸŸĸĸĢĸĸĨ%ĸoooî���Ķ���€���c���O���1��� �����������������������������������|||HÄÄÄĸûûûĸúúúĸųųųĸøøøĸëÞËĸþøîĸüüüĸúúúĸøøøĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÛÎŧĸßşĸé·lĸŸŸŸû‚‚‚îWWWŲCCCČ666Ĩ���O��������������������������������������{{{IÅÅÅĸüüüĸûûûĸëëëĸÕÕÕĸķĸŸllĸļ’’ĸŋœœĸÐķķĸßÏÏĸãÖÖĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÕÕÕĸÔÔÔĸŌŌŌĸÐÐÐĸÎÎÎĸ°°°ĸxxxĖ---2��������������������������������������wwwLÆÆÆĸðððĸÛÛÛĸÖÖÖĸÖÖÖĸĶyyĸĄnnĸĢppĸĨrrĸĻuuĸŠwwĸŽyyĸŪ{{ĸđŒŒĸœœĸŌđđĸÖĀĀĸāÓÓĸčååĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÕÕÕĸÔÔÔĸŌŌŌĸŊŊŊĸggg™���������������������������������������������ssscÄÄÄĸÜÜÜĸÜÜÜĸÜÜÜĸÍĀĀĸĄnnĸĢppĸĨrrĸĻuuĸŠwwĸŽyyĸŪ{{ĸ°}}ĸēĸĸ탃ĸļ……ĸš‡‡ĸž‰‰ĸŋŒŒĸËĨĨĸŅąąĸÕŧŧĸāÝÝĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸŅŅŅĸŸŸŸųOOOt�������������������������������������������������ˆˆˆēâââĸâââĸâââĸâââĸⷊĸŅ“dĸĖ“pĸ―ˆwĸīxĸŽyyĸŪ{{ĸ°}}ĸēĸĸ탃ĸļ……ĸš‡‡ĸž‰‰ĸŋŒŒĸÁŽŽĸАĸđ‘ĸĮ””ĸÛÎÎĸéééĸņņņĸöööĸũũũĸðððĸíííĸåããĸũŸ���9�����������������������������������������������III ···ĸéééĸéééĸéééĸęåßĸýđaĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸõ˜ĸėđ—ĸ㰕ĸÚ§“ĸԟ’ĸ˘ĸĀ‹ĸŋŒŒĸÁŽŽĸАĸđ‘ĸĮ””ĸɖ–ĸâÕÕĸņņņĸųųųĸĸĸĸĸĸøøĸĸððĸĸęęĸĸįįĸŽĻĻĸ­���[����������������������������������������������xxxuäääĸïïïĸïïïĸïïïĸõÚ·ĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸôÁŽĸð―­ĸæģĐĸäąĐĸÛĻĪĸíÝÜĸúįįĸĸããĸĸÜÜĸĸÝÝĸĸããĸĸččĸĸîîĸÖÏÏĸLLLÖ���‚���(������������������������������������������ ĻĻĻÚöööĸöööĸöööĸöööĸüˏĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸäūđĸĸÓÓĸĸŨŨĸĸÞÞĸĸääĸĸččĸĸïïĸĸõõĸĸųųĸ‹‹‹ũ���ž���H��� ������������������������������������bbb1ÕÕÕĸüüüĸüũōĸüáūĸýЙĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸŊĒ ĸäĮĮĸĸÞÞĸĸääĸĸččĸĸïïĸĸõõĸĸųųĸĸĸĸĸÉÉÉĸ000Ä���r��������������������������������������–ØØØĸ···ĸĸķWĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸsssãŠĄĄėĸääĸĸééĸĸððĸĸõõĸĸûûĸĸĸĸĸĸĸĸĸōōōĸqqqé���Ž���4�����������������������������������”””‚‚‚‚J’’’Æō·nĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸëÂŋĸUUUÆjjj‡ÞŅŅĸĸððĸĸööĸĸüüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ···ĸ%%%ƒ���2��� ����������������������������������������”””b†‘‘‘ķ’’’ÆŠŸ’ĮēĨ™ĸļϚĸĖēœĸĖēžĸØđĄĸåŋĨĸåŋĶĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸĸĖČĸŌĩīĸ###‹���$ĨĢĢáĸööĸĸüüĸĸĸĸĸĸĸĸĸåååĸŌŌŌĸŋŋŋĸ   Øxxxe������������������������������������������������������������������������“““B‰‰‰GŠŠŠX‡ŽŽŽ‰‘‘‘§›—–ÆīĢĮģĨĄņŋŽĶĸĖģ­ĸĖģŪĸæŋŧĸæŋžĸėÂÂĸīĢĢę���=���•••bŋūūĸĀĀĀņĐĐĐɊŠŠ„„„o€€€L��� ����������������������������������������������������������������������������������������������������������������������������”””BŠŠŠG‹‹‹X‘‘‘‡………\��� ���������������������������������������������������������������������������ü�āĸ��ð����ĸ��ā����?��Ā������Ā������Ā������Ā������Ā������Ā������Ā������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā������Ā������Ā������Ā������Ā������Ā������Ā����?��Ā������Ā����?��Ā����?��Ā����?��Ā����ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ������ĸ�������ĸ�������ĸ�������ĸ��Ā����ĸ��ð���ĸ��ĸþ�?ĸ��(��� ���@���� ����������������������������������������������N���s���n���X���D���1���"������������������ ������.���<���@���=���0������������������������������������������&;;;™vvví]]]ä555Ð―§���Œ���y���d���L���5���%���&���C{0 Ē/Ŋ.ąĨ���Œ���s���L���"��� �������������������������&LLLķĢĢĢĸíėëĸôôōĸÝÝÜĸÃÂĀĸ‘ũfffíCDDÝ**+ÆŽ—���„6##›wPPݟqqôĖ–ýŅĶĶþÆ  þ {{ũyRRė=((Ę������p���6������������������BBBoooÅūūūĸÔÔÔĸëčåĸĸĸųĸĸĸûĸĸĸûĸĸýøĸĸûöĸíčäĸË·Ģĸ§”ĸzpeóaJJčķ{{ýĸĸÆÆĸĸÏÏĸĸÚÚĸĸááĸĸééĸōßßĸČĐĐĸvPPëķ������<��� �����������ccc_ūūūĸÁÁÁĸ···ĸëįáĸĸøîĸþöėĸýöëĸĸųöĸĸüüĸĸðáĸĸПĸĸӜĸđ{ĸŅ„…ĸĸŦŦĸĸĩĩĸĸššĸĸÃÃĸĸĖĖĸĸÕÕĸĸÝÝĸĸįįĸĸĸĸĸëââĸ“mmöŧ���~���3�����������iiic···ĸķķķĸÁÂÂĸëäÝĸĸöîĸÎâšĸ<Ž5ĸ€Įxĸ°ŲĨĸŅΗĸïÆĸӞ‚ĸĮ|~ĸĸœĸĸĄĄĸĸŠŠĸĸēēĸĸššĸĸÄÄĸĸĖĖĸĸÔÔĸĸããĸĸþþĸĸĸĸĸņęęĸ‘iiõ ą���k����������jjjbŧŧŧĸąąąĸŋĀĀĸíäÛĸĸóčĸÆÞ°ĸ��ĸ� ĸĄĸœ ĸ/šĸ°zuĸü§ĻĸĸŸŸĸĸ™™ĸĸ  ĸĸŠŠĸĸģģĸĸšđĸĸÄÃĸĸËËĸĸęęĸĸĸĸĸĸĸĸĸĸĸĸĸ娨ĸoJJč���˜���F��� ����kkkbŋŋŋĸØØØĸŲŲÚĸéāØĸĸîßĸËÞ°ĸ °ĸī)ĸ­ĸ�œ�ĸA|,ĸ⚟ĸĸĩĩĸĸ§§ĸĸžžĸĸ™™ĸĸ  ĸĸ§Ĩĸĸą°ĸĸđđĸĸÅÃĸĸųųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸūŸŸþ3!!Ã���m�������kkkbĘĘĘĸáááĸÚÛÜĸčßÖĸĸęŨĸÎßŊĸ―1ĸ)Â=ĸī'ĸ�˜�ĸ{{Uĸĸ―Äĸĸđđĸĸ°°ĸĸ§§ĸĸĸĸ›šĸĸÁŅĸĸËôĸĸÎõĸĸÚęĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņęęĸnJJæ���‹���.����lllbËËËĸãããĸÛÜÜĸéßÕĸĸæÎĸŅßŪĸ'ĖGĸ7ÐRĸ ū4ĸ ĸ͈yĸĸËÎĸĸÃÃĸĸđđĸĸ°°ĸĸĶĨĸĸŅŲĸĸáûĸøąĖĸôļÏĸĸįĸĸĸõĸĸĸĸĸĸĸĸĸĸýüýĸýüüĸüûûĸІ†ú Ī���=����nnnbÍÍÍĸåååĸÞÞßĸęÞÓĸĸáÅĸÔāŪĸ6Ü^ĸFßhĸ(Č@ĸŠĸĜ–ĸĸÓÕĸĸËËĸĸÃÃĸĸķķĸĸū―ĸĸóýĸė§°ĸ°}wĸą~uĸÓķŧĸĸųĸĸûøøĸöðîĸõîíĸõîėĸûũõĸÉŽŦĸ#°���I����ooobÏÏÏĸįįįĸßāâĸëÞŌĸĸÝžĸŨā­ĸEęuĸTî}ĸ2ÓOĸ …Bĸ˜ŸĸĸÓÔĸĸÍÍĸĸËËĸĸÃÃĸĸŅÐĸĸôüĸƆ‡ĸĒĖĖĸũāūĸ­‚|ĸũîōĸũóōĸęâßĸëâßĸëâßĸðéåĸÏĩīĸB++Â���M����qqqbŅŅŅĸéééĸâãäĸíÞÐĸĸŲīĸÛâŦĸTûŒĸ^ō™ĸLŅÁĸ<ØĸŧŒ•ĸĸÍĖĸĸĖĖĸĸĖĖĸĸÉÉĸĸŨÖĸĸũĸĸÖŦ­ĸ ŽŦĸóÓ°ĸēzsĸüÔŲĸýâãĸúļ·ĸöÄÃĸöĘÉĸøÖÔĸÔ°ŊĸA++Ā���I����rrrbŌŌŌĸęëëĸãæčĸïßÏĸĸŨŠĸÖÔ·ĸ@ÂāĸJģûĸLģĸĸ6†éĸ}ŽĸĸËČĸĸĘĘĸĸËËĸĸÖÖĸĸęéĸĸõĸĸûėûĸËĄžĸēvqĸݔ˜ĸĸðũĸĸÅÆĸĸĶĨĸĸēēĸĸššĸĸĘĘĸÚĶĶĸD--―���=����tttbÔÖØĸíïņĸįãÚĸïÞÍĸĸÔ ĸŌÆžĸ'˜ĸĸ3Ģĸĸ@Ūĸĸ)ŒųĸvfˆĸüÉÃĸĸããĸĸõõĸĸýýĸĸĸĸĸĸüĸĸĸįĸĸĸŅúĸúÂáĸĸãýĸĸÞįĸĸžĸĸŸŸĸĸŠŠĸĸēēĸĸĀĀĸɓ“ĸ)Ÿ���-����uvwbŨÓËĸúŧ[ĸōļeĸïßŅĸĸϜĸōĖĶĸ°ŧÅĸ”ķÔĸ{ķãĸQšëĸDUĢĸÎĩĩĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸóũĸĸËčĸĸĖëĸĸÉØĸĸŠŦĸĸœœĸĸ™™ĸĸ  ĸĸŠŠĸýēēĸĶssũu�������wz€bÞĞĸûŒ�ĸé°bĸņáŅĸĸ˖ĸĸ͙ĸĸϔĸĸϔĸĸ˚ĸóɟĸāĄšĸ瀂ĸũôôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸčæĸĸĮÅĸĸÂÁĸĸ·ĩĸĸ°°ĸĸĻĻĸĸžžĸĸ™™ĸĸĒĒĸĸsLLŨA��� ����y}bÛÁĸë�ĸâĻbĸóáÏĸĸĮŠĸĸɏĸĸɏĸĸɏĸĸɎĸĸʎĸĸɐĸŌ|ĸū ĪĸĸĸĸĸĸĸĸĸĸĸĸĸĸþþĸĸÜÜĸĸÏÏĸĸËĘĸĸÃÃĸĸššĸĸąąĸĸ§§ĸĸžžĸĸœœĸđxxý<((€����������{‚bØ―›ĸÝq�ĸā­xĸõáÉĸĸĀvĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÄ{ĸĸÁĸžlĸÉīļĸĸĸĸĸĸĸĸĸĸũũĸĸßßĸĸŨŨĸĸÐÐĸĸËËĸĸÃÃĸĸđđĸĸąąĸĸŽŽĸԆ†ĸmIIŧ���(�����������|bÛĮēĸ⚏ĸŲŲŲĸõÝūĸĸšdĸĸžhĸĸŧgĸĸžhĸĸžjĸĸ―lĸĸ―lĸĸūkĸųšiĸļ‚dĸÅŦ­ĸüüþĸĸũũĸĸččĸĸááĸĸØØĸĸÐÐĸĸĖĖĸĸÆÆĸĸ――ĸŌĸ€WWÍ *��������������€€€bŌŌŌĸšŋÃĸÉĖŅĸũÛļĸĸ°FĸþŠ/ĸýŊ@ĸþŊ@ĸþ­;ĸĸ­=ĸĸŪ?ĸĸēJĸĸķSĸþļ[ĸƊZĸ牅ĸØÃËĸóāäĸþæįĸĸããĸĸÚÚĸûĖĖĸëķķĸ큁øzRRĒ������������������bŅŅŅĸŧŧŧĸĮĘÍĸũŨ­ĸþ­9ĸöęÖĸóņïĸōãÎĸōÖŠĸōʍĸôŋqĸöđ`ĸúŪAĸþĻ,ĸĸĻ"ĸí1ĸȀ=ĸŋ‰jĸū‘…ĸķĸ牉ý–llėmLLļO44`��������������������������‚‚‚bŨŨŨĸâââĸöøûĸýá·ĸĸėÅĸüĸĸĸøúüĸôũûĸïôûĸėōüĸéíóĸččįĸæáŲĸãÛÎĸåŅģĸíĮŽĸōūlĸîŦIĸëž1ĸė+ĸˆr\ōž���‘���d���,�����������������������bčččĸĸĸĸĸęëëĸĘ·ēĸÍīĩĸÚĮĮĸįÜÜĸïęęĸõũũĸōóóĸïņņĸėîîĸęėíĸåįčĸáäæĸÞáåĸÛßåĸŨÝæĸÖØÚĸÜÏŧĸĮÃŧþ°īĩø‘““éQRR‹�������������������������{{{fÝÝÝĸáááĸÔÖØĸĄv{ĸ›dgĸĪqqĸŦyyĸ°ĸĸÅĒĒĸŅĩĩĸŲĮĮĸāÔÔĸâÛÛĸâÝÝĸáááĸÞÝÝĸÚÚÚĸŨØŲĸÔÖÚĸŲÚÛĸÂÂÂĸnnnĪ...'�������������������������‡‡‡™ßÞÞĸāãæĸÝËžĸ†iĸķrĸ­zvĸŦxxĸ­z{ĸ°|}ĸą}~ĸģ~ĸ큂ĸŧ„…ĸӔĸƟŸĸßŲŲĸęėėĸíïïĸéęęĸįææĸŦŦŦø111­���8���������������������������(((đđđëîïïĸéėðĸöʓĸĸđbĸýÁĸûȕĸöØĸėđ˜ĸ㰗ĸÛĻ—ĸҟ”ĸΛ•ĸĖ™•ĸ˗•ĸʗ–ĸčßßĸúööĸĸööĸĸîîĸĸîîĸĩŽŽúĨ���U���������������������������dęëėýõųþĸõïčĸýÃ{ĸĸÃ~ĸĸĖ—ĸĸ˜ĸĸ͟ĸĸÎĪĸĸÏĐĸĸÏ­ĸĸŅąĸĸÏĩĸýĘķĸøÅ·ĸóÁ·ĸņÐÎĸĸÛÛĸĸÜÜĸĸääĸĸððĸïččĸKLLÓ���|���&�����������������������ģģī·óïëĸþÞķĸþˍĸĸÃ~ĸĸ˗ĸĸ˜ĸĸ˟ĸĸĖĪĸĸ˧ĸĸĖŦĸĸĖŊĸĸĖģĸĸĖ·ĸĸÍžĸĸÍÁĸûĘÁĸīĒĄüûÚÚĸĸččĸĸïïĸĸųųĸĸĸĸĸ———í‘���;��� ��������������������žŸĄ‹ŦŸ‘Öþ·^ĸþÂ~ĸþ˖ĸþ˜ĸĸ˟ĸĸÎĪĸĸÎĻĸĸÎŽĸĸΰĸĸÎīĸĸÎļĸĸÍžĸĸÍĀĸĸÍÅĸðÄĀþ\]]ÂÎÂÂëĸõõĸĸýýĸĸĸĸĸĸĸĸĸÝÝÝĸFFFŽ���/��� ������������������������=’‘x–“ŽŸ’ŠļĨ“žŋЖÉÂŦ›Ó˰žáÛļĨëā―ŠøęÁąĸëÂīĸðÅšĸúĘÂĸĸÎÉĸÚđļýO•””›ïëëĸéééĸÓÔÔéžžžÕ­­­ŧwwwX��� ������������������������������������������������€ƒ† ‡‰‹ƒˆŠ%‡‡ˆ9Ą”DĶ™•XŪžšeŸ˜˜…Ļ›››š““���sss§§§ZDooo'MMM ����������������������������������ā��€��€��€��€��€���€���€���€���€���€���€���€���€���€���€���€���€���€��€��€��€��€��€��������?���?���������€��ð��(������ ���� ����������������������������������?���m���{���p���_���O���H���W���j���m���^���;������GGGZ‰‰‰ÜЧ§ï|~åYXXŨ543Å$ķ\>?ȌhhޓssämTTŲ*ŧ���Œ���O���XXXĄĒĒņŨÕÔĸĸýōĸâōÖĸųóáĸîÁĸƆ~þũĐŦĸĸÆÆĸĸŲŲĸþėėĸÖÃÃýB--Ð������=ccc#ŊŊ°ųÔÏÏĸðëÓĸ!­%ĸ)Š!ĸœšcĸĸĪĸĸ  ĸĸ­Žĸĸū―ĸĸęęĸĸĸĸĸÕÃÃý&ŧ���heee"―――öčâáĸņåÉĸ1ÃBĸ� ĸŸtĸĸ·―ĸĸĄ ĸĸąšĸüŧÐĸĸóũĸĸĸĸĸĸĸĸĸz``ã���‡hhh"ÂÂÃöėäâĸóáūĸSækĸą,ĸČ­ĸĸÉĖĸĸÉĘĸæĮŅĸĮ°ŊĸņāäĸøõôĸøôōĸĀĶĪû���Žlkk"ÅČËöîęęĸóÜģĸ]āĩĸ6ĶĘĸÆĨļĸĸÏÍĸĸÝÞĸäÕßĸšĢšĸíËĖĸûËËĸúËĘĸÎĨĨü���ƒmno"ËÅšööÚģĸõŌŊĸa­õĸ:–ûĸ§ĄÃĸĸõōĸĸûûĸĸóĸĸōūÜĸýÁËĸĸŸžĸĸģģĸˆˆũ���_qv}"ÏĢföōŦQĸĸŌĶĸöɛĸÝÂĢĸËĶžĸíéîĸĸĸĸĸĸððĸĸËŌĸĸģīĸĸĢĒĸüŸŸĸ{RRŋ���.uy}"ŧ„ö㷈ĸĸÂvĸĸđ^ĸĸĀhĸüķhĸŌ·ĸëäęĸĸōöĸĸÛÝĸĸÎÎĸüķķĸŪppâ0 D��� www#đžūöØŅÆĸĸĮqĸû˂ĸúÄxĸüŋhĸũ°Pĸՙ]ĸâķ˜ĸįūŽĸš’’ō‡^^É5""G��� ���lll$ŌŌÓũíåßĸãÐĮĸéčðĸėééĸéåáĸæâŲĸįÔīĸáđ€ĸāąpĸqd`Ý"w����������ooo5ØÛÞúØÄļĸĩ€tĸģƒ€ĸŧĸŞŸĸ˧ŠĸŲĖÐĸęņøĸâäéĸlmmŲl����������ĄĄĒvôōîĸü͓ĸýŋĸøÄĸō― ĸė·Ģĸį°ĨĸėÄĀĸĸęęĸþîîĸSRRŋ���g����������ĻĶ̐óȒøûĮŽþþĖĄĸĸÎĐĸĸÎąĸĸÐŧĸĸÔĮĸÉ­ŠęėÚÛþĸþþĸĀĀĀáC����������ˆˆ‡ —’‹2ŦG§šY –jĩĄ™yÂĐĒūϧۈƒƒcŸŸŸhģģģv˜˜˜TEEE�����������������kb��Ęĸ��áĸ��Üĸ��Öĸ��Ũĸ��Ŋĸ��1ĸ��=ĸ��'ĸ��ĸ�Uĸ�Äĸ�đĸ�°ĸ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/installer.png�����������������������������0100777�0000000�0000000�00000007574�13761647206�023347� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���0���0���Wų‡��CIDAThĨšil\ŨuĮo}8ÃĄļŠ-R”eZKDÉ"% RT–;čÅčŧA"E[ļŸÔAë5`8hęÄ2 ĢŠ?ĪiļąTķĨ Žck1―ŅĶ8ĒHũCr†g{3ó^?ž’Ã]ÍÞ{ũ‚wþĸ{ÎđįÜs)ðÛ5a―ÎóįÏ5+‚ xUU=ļļļØųôÓOĸH�Ų_|Ņûä“OF�cşëÍĩU“· ęĨ—^*�Ĩëš(IRĒÚwYœ‚,ũ(§Ûbq!�.g% J*ÃÃÏ�Àĸå—_þƒ}ûîųũ>ø`! vßŌ4­#“Éô?óĖ3ï)@ß.Ą%įϟĸv&“Đᐠ\å‚Eĩ6 ’Šh/AÜ'ējīš*‘�rēō=ĸ-ÞâšuuußčïïŸtŧ=ĸØÜ|UÅ-IÜÜ711A(âÔĐS ũtwwĸËóÏ?ĸ:°d7%pþüųgÃáðĮšŪĸÅĀÞo·Xl.ŠðŠĶ.ō VƒÚtÖUÍáŠāðáÃ'xāĖ-5šföŦ*HTVVRYY Āå˗ũ>ũÜs5@ЅivH§Ó%įΝ{gpp†‹âĖō`žÄoÛ,öjjjŠ8ö„ÏwДŲo& 9gŅh”+WŪLũöö:0ŨIßjnĐŠŠjĒđđų/ïŧï>Ž1ðZMӛŒ €EAXËcģïõÆ)îÞÛÐl·ŲÜčš9ožˆ$Á͛7yéĨ—Ú§ĶĶ>>Â[_{íĩnŋßßŦiēĄŅžCãÏRT:ēDŌ0§AÆ0MFĮ|æE_Õ·Ņ{ĻØy§ģŠT 4 2 Þ5 Ū^―šloo�·sā·tdHķ··ĸÛýũßĸ‚ÃáXļŧČ ą/}߉9Ĩb1„L†L<šN:‘ ųh1{šLF!•2Á9x†@~øá 0 ņíü– 7oÞüoŋßĸÂáǗ 8Ōžžĩbšb!‰L<Ž‘H įÄH&ŅS)Ōą‚a Š"Ē("’$!Š"ĐĪ…%2VŦŠŠĪRLš+ŸJAOÏmŪ^―Úô�3lsŸ.]š4~ęÔЋä$`Ÿ>N 0Gš4ŅX„ÅT!™\ļ‘ä›(Šdģ&ŽT*E2™ ›Í"B’ēĪRI&'G“‚ ,�˜Ûįķš”{īWVV~Ãfģ‘ÍfÉfģļaúnt ˇ0â1ÓX·ŲA ŽĖNiНŠ V C'‘HF‰FĢÄb1bąĐT’ššųāÁƒũ�―===·€4Ûô�C–å (Š”””033C:ĶīÔ†ÃĄ‹Ĩ7œ ĻȆĮcĢšÚƒÅ"ãóŲ).ķĒ("šŪŊ+†aŽé“$‰ĶĶ&Õãņü žž|ÏŦŊūúOĀ4°éŠ-EbY–ģ†aāt:q8ĖÏÏ3==M}―‡/ŋ R__†ÝnĄēŌKEE‹ĖŪ]ÅÛļŲØĘū]ŧvņāƒ~Įëõ6―óÎ;ßņûý€ķ‘6–‚`†A^Ün7.—‹ļ­”ßĸny{ ïüXBf,!Óķ`§ięÝĖččhīģģsfvvv.öûýþjĖ]ifK ä'FQĘĘĘÐuīââÉpáäĸ|gDa4!q{A1A'e:Ēvlļd°ˆ ĩ·GôĢ]Ā(0 Œ°U*‘ÉHĨR\ŧv ŊŨˑ#G)&0'ðė`sðŨ§eæ5ļ‘éŒČŒ&$†b*6É܂­8Róė ØžDNDą,L‹Ų*Ũđsĸp2™\BĄĸĸó)ÍØÐ™ 4`ŠĒpüøqÂá0###H;―”Yāgý2Õv‡Š4:Â"ËËp}Ff$&ÖDø,`“Ā.Á§)�ōėŪ@j(Dcc-wÝIii ™ ļ\NBĄE9Žî™xt``čŅššSí33Ã/\šôã·1ƒÚšqa)ķ>õÔSgϞ={ĐĪĪ„Ï?ĸŊŨËącĮKŧøŨNš—§@Á)ƒG‡J-›č8ĮŌö>Ęä=ÔÄWūŌ€ÛíZJ!ōiD:―üžJiī·ûđ}ÛO08øÖ/~ņėßbîHÚęéóq€'NÔŨŨŨĸĐák ņî=čé$†aĩŅ1gšÁþ"ļĮ õNØiƒRŦiŠļū( “Ļĸ†Z[–ï}ïũ8p A°l Þ0 ›•ðz+ĐŠŠ#]ÜW_ßôÍpxęúÂÂt˜UÛŠļōCŨu.v'9ýĘ 7“5TVV" đ•ūCą.L"~p‘ãû||ĸûˆÏįB’L€›Ï§é4Čē‹ĢGĄĪĪŪúĉGĸļ°ŪK`i UFR õf˜ëý DÃĀ!sGRÕČ^ý5-GxüņÓ*·Xķ^ÓLŅu•ÆÆG(/ŋ{ũŨŋþw/ĩ€šŸo’v›Ų' ˆčļ•Ml|U“#0qý"ŧŦ=kĀX­ÍnüJuugÐīčɆ†ãß >š�L�ú +`ģÝ†.ˆÜé,Bꖟl:Ęwŋ{f]‚ĒXĻ…­Ā›ĀápQUĩŸƒÏ<ėė뚊6ŧIB�EdkIƒ2#·8wî8vŧš.�ŊũÎĀ+ŠyôŽ­ÝOiéŪĘÝŧ< ė�Ă@Ķë:E°š›·.,‚a ˆë)·ãĖLSí!ûŲĮtwÏâŠ{œ––† Áƒđ66$"`ŨA ķxSTĘËkĐŊ?ōĩÏŨøĀŲō$mhüM›C�YZþņãÏRœęĮŦ ˜§qEA‹$˜˜™Äïx”“'ïÝ<�ih°ƒœĀÜČí— mĮ7o~ïÜYMqqu5fÕâöZ'6 vÚ2žq<ŒaĖiJęæ/›'ðxŌ De!Ĩg/~?”•ĮcþpAӁČÄģ° U�N]€žūõÁ+ TUUāv—x€€ģĀV&dy2…ķūž$–fTĻÁįóĄŠ*šĢĢāũC �Ąđó�ffĢ; =å§7Zųyë(7šĖá–cāpŽ^UÁåēãtÚihh>ˆ™,·Õā ÃXcBoŸĐĨ"”Ē6Ļá‹åĘ6†NÄ(^*N­lŅĻ)’ÕÕāSīÞð_?ĸwi C#=ƒûq{šØęęĖX Þb1ŨŪĻȃŪëVĀŧŪ åEŨõ5NðHôyė\Ŧģã[ČÐŌŧHM? eJĐp:Ũ5y05 åÂ?Ļņúëņğ[w>Ld:Ä?yƒą`û·ÛlģeąXģËʖģ(JAČ�†ĻČk äss€EÞbˆG‰�*%%%€eþ>O‚š‚ ā+ũP[?x)+!YbÎ#Ëŧu Ž4# e… ÍĮ 'j ūeâ{‚Ã9UëšĻÖÛįQanN"4'’Ð$ Ÿ}ŠÝŪRYjf�’,â°mGīôr>·†ĀJðšnVđWšPt…�R+*ųRáFāc1Óöí*epp//þxkŅ/ Oóøã§)’Í<MU$l6eĐðĩš§æéëûlÐÖē•āu]G)0ĄhĒð„§åĪĪyFF&ðų*6Œ°}}PsŽ6ĀÜÜicCdģQNýŅŨhip-Yė6›U!“ŅÉfut}™I_ßņx$‰đŸÍmhBæę쯉įã…ŋdŪVēO‰D7MÆÆāVÜ[‚pU-Y<ÞK6!Š"ĄŽī_ ŧ{œ™™áâëšPža >°ļJyštö099đenóQÄ륹Š­€džPæ2āuģeýĩ―}ˆÞÞÖ`ˆāÕāu]ąpZíyšpõ™š átú6MĖz'a8E6pXĖŊÝ'j7ßÚ`tt,90ðE/ÐDŨdĢ333Äãņ%Dđ G‰…å%ōÜĪŧÛŋeV™—Œh‚ÏßÔĖÎnNāâÅ6üþũ˜ĩĒ ą†@:Ķĩĩ•ūū>4MC”d‰%‰&“ērjŦžČðp€H$š%øõ"ėÂÂÆāß~ŧūś7Ŋī@ČŪņ‡ÃASScccƒAj=e&Yîņâí^|ŌAŠm‡°e-tt|HcãÃwÞbY>ĨɆ Ā$oūųQæÚĩŸķÝĀ-˚ŅÚ8055Åėė,{öėÁår! ėBŋSþ0ÞC/;ʼn’cĒ‘yørÜÏÖļ=ōƒƒmTT4m|~,5<ų6:â•Wþ—ķķ·ŧ'&_�c:pf ]ŨđëŪŧPU•ŪŪ.ęęępzw$sĸņÕ·ÖĻ·Ú·‚ÖAēŠÔýîï\ÄfsQUÕ°mðŠjja%øþð"ïŋĸģ[WŪ7€NVÜÞ,AŦŦŦS$IzŽĶĶF-..ÆįóĄ( .W‡I`CQ$°)0ūāpŲ1ĪC­hÚee;ąZĨ-ÁŊ|ūûn.üškŨ^ŋÕŅqåð›ÜęÜÞ,čęęZČfģ=ccc'wėØáôų|H’„ÝîĀåܜ@d.Äd_#·[ûôWôžĸ“L_ەŲþþķĄd!™qX­JK}›‚ÏfãtvráÂŪ^ýdņ―ũ^míëûô“øV`ŠU…­Õ·ĢEĨĨĨũŸ:uę§OŸūŧĨĨ…ŌērJË+ LĶ·7ĀøØ―ó988°8===‡C###ĢĄPh3RhKË7ÏėŲsėŒÛíqîÚUGY™‡ŠŠ2dŲ$366ÄÔÔ<]]CÄã‹Iŋĸ―@n·é>ÁtÚÐjðŦ €YĨp� gϞýįÇŸ}ėąĮˆĮ㌍čėėĖD"‘čôôôėøøøøÔÔÔd<c–Ã'1k˜AĖkŌæU‘hŽ­=tĶķöā·ŧŽLQTKîĀG:Lƒ3ãã·'ÆĮŧGrót䀏įl~ÝKïõ·€YūŦnnnþëÝŧwĸq8Ž…ÃáČxŪ ˜ķ8‰Y`šÉõÅ1ģš……X 3ÓŲTՀ°å~ÏČýítnūÉܜŅõV}+ųĶ�åĀ`ĶãäAÏbÞ$æ'YvŽÍ.æDĖÅąįž+3ĩLnž8Ëĸąēeû?öŽÓ7͉����IENDŪB`‚������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/installer.qrc�����������������������������0100777�0000000�0000000�00000000467�13761647206�023342� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<RCC> <qresource prefix="/"> <file>installer.png</file> <file>installer.ico</file> <file>installer.icns</file> <file>install.png</file> <file>uninstall.png</file> <file>keepinstalled.png</file> <file>keepuninstalled.png</file> </qresource> </RCC> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/keepinstalled.png�������������������������0100777�0000000�0000000�00000000357�13761647206�024166� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������;֕J���bKGD�ĸ�ĸ�ĸ ―§“��� pHYs�� �� �šœ���tIMEÞ  # ˆëūC���iTXtComment�����Created with GIMPd.e���SIDAT(Ï­Ō1� Ājü7OĮʼn@‘Ec<RĒ@ĢÆYĩaËX`vbW°D Õė%€âĐäĒ8 Cl—„b˜Â`Ów^ũHėüËß~Š É!äþBâ����IENDŪB`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/keepuninstalled.png�����������������������0100777�0000000�0000000�00000000313�13761647206�024521� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������;֕J���bKGD�ĸ�ĸ�ĸ ―§“��� pHYs�� �� �šœ���tIMEÞ  #*ģ…ž‹���iTXtComment�����Created with GIMPd.e���/IDAT(Ïc` �0Béĸč%Yó&Jœ=ŠyČhfAxJÁbÅВķÉ�ëÐä+­ï����IENDŪB`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/resources/uninstall.png�����������������������������0100777�0000000�0000000�00000000360�13761647206�023345� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������;֕J���bKGD�ĸ�ĸ�ĸ ―§“��� pHYs�� �� �šœ���tIMEÞ  "vHĒ���iTXtComment�����Created with GIMPd.e���TIDAT(Ïc` �0Béĸč%Yó&JœM‘ftizjõļg]šÕˆW3C*ÛŋtąŲŋ˜ڌK!ÁКĄýŸ ā?ąâTIÛd�ÜŅ+V­����IENDŪB`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/runextensions.h�������������������������������������0100777�0000000�0000000�00000036153�13761647206�021722� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QTCONCURRENT_RUNEX_H #define QTCONCURRENT_RUNEX_H #include <qrunnable.h> #include <qfutureinterface.h> #include <qthreadpool.h> QT_BEGIN_NAMESPACE namespace QtConcurrent { template <typename T, typename FunctionPointer> class StoredInterfaceFunctionCall0 : public QRunnable { public: StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &)) : fn(fn) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; }; template <typename T, typename FunctionPointer, typename Class> class StoredInterfaceMemberFunctionCall0 : public QRunnable { public: StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object) : fn(fn), object(object) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; }; template <typename T, typename FunctionPointer, typename Arg1> class StoredInterfaceFunctionCall1 : public QRunnable { public: StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), const Arg1 &arg1) : fn(fn), arg1(arg1) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Arg1 arg1; }; template <typename T, typename FunctionPointer, typename Class, typename Arg1> class StoredInterfaceMemberFunctionCall1 : public QRunnable { public: StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, const Arg1 &arg1) : fn(fn), object(object), arg1(arg1) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; }; template <typename T, typename FunctionPointer, typename Arg1, typename Arg2> class StoredInterfaceFunctionCall2 : public QRunnable { public: StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) : fn(fn), arg1(arg1), arg2(arg2) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; }; template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2> class StoredInterfaceMemberFunctionCall2 : public QRunnable { public: StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) : fn(fn), object(object), arg1(arg1), arg2(arg2) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; }; template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3> class StoredInterfaceFunctionCall3 : public QRunnable { public: StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3> class StoredInterfaceMemberFunctionCall3 : public QRunnable { public: StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4> class StoredInterfaceFunctionCall4 : public QRunnable { public: StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4> class StoredInterfaceMemberFunctionCall4 : public QRunnable { public: StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> class StoredInterfaceFunctionCall5 : public QRunnable { public: StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> class StoredInterfaceMemberFunctionCall5 : public QRunnable { public: StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture<T> start() { futureInterface.reportStarted(); QFuture<T> future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface<T> futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template <typename T> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &)) { return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start(); } template <typename T, typename Arg1> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), const Arg1 &arg1) { return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start(); } template <typename T, typename Arg1, typename Arg2> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start(); } template <typename T, typename Arg1, typename Arg2, typename Arg3> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start(); } template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start(); } template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); } template <typename Class, typename T> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object) { return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start(); } template <typename Class, typename T, typename Arg1> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1) { return (new StoredInterfaceMemberFunctionCall1<T, void (Class::*)(QFutureInterface<T> &, Arg1), Class, Arg1>(fn, object, arg1))->start(); } template <typename Class, typename T, typename Arg1, typename Arg2> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceMemberFunctionCall2<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start(); } template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceMemberFunctionCall3<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start(); } template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceMemberFunctionCall4<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start(); } template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceMemberFunctionCall5<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } } // namespace QtConcurrent QT_END_NAMESPACE #endif // QTCONCURRENT_RUNEX_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/scriptengine.cpp������������������������������������0100777�0000000�0000000�00000060042�13761647206�022015� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "scriptengine.h" #include "messageboxhandler.h" #include "errors.h" #include "scriptengine_p.h" #include "systeminfo.h" #include <QMetaEnum> #include <QQmlEngine> #include <QUuid> #include <QWizard> namespace QInstaller { /*! \class QInstaller::ScriptEngine \inmodule QtInstallerFramework \brief The ScriptEngine class is used to prepare and run the component scripts. */ /*! \fn QInstaller::ScriptEngine::globalObject() const Returns a global object. */ /*! \inmodule QtInstallerFramework \class QInstaller::ConsoleProxy \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::InstallerProxy \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::QDesktopServicesProxy \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::QFileDialogProxy \internal */ QJSValue InstallerProxy::components() const { if (m_core) { const QList<Component*> all = m_core->components(PackageManagerCore::ComponentType::All); QJSValue scriptComponentsObject = m_engine->newArray(all.count()); for (int i = 0; i < all.count(); ++i) { Component *const component = all.at(i); QQmlEngine::setObjectOwnership(component, QQmlEngine::CppOwnership); scriptComponentsObject.setProperty(i, m_engine->newQObject(component)); } return scriptComponentsObject; } return m_engine->newArray(); } QJSValue InstallerProxy::componentByName(const QString &componentName) { if (m_core) return m_engine->newQObject(m_core->componentByName(componentName)); return QJSValue(); } QJSValue QDesktopServicesProxy::findFiles(const QString &path, const QString &pattern) { QStringList result; findRecursion(path, pattern, &result); QJSValue scriptComponentsObject = m_engine->newArray(result.count()); for (int i = 0; i < result.count(); ++i) { scriptComponentsObject.setProperty(i, result.at(i)); } return scriptComponentsObject; } void QDesktopServicesProxy::findRecursion(const QString &path, const QString &pattern, QStringList *result) { QDir currentDir(path); const QString prefix = path + QLatin1Char('/'); foreach (const QString &match, currentDir.entryList(QStringList(pattern), QDir::Files | QDir::NoSymLinks)) result->append(prefix + match); foreach (const QString &dir, currentDir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)) findRecursion(prefix + dir, pattern, result); } GuiProxy::GuiProxy(ScriptEngine *engine, QObject *parent) : QObject(parent), m_engine(engine), m_gui(nullptr) { } void GuiProxy::setPackageManagerGui(PackageManagerGui *gui) { if (m_gui) { disconnect(m_gui, &PackageManagerGui::interrupted, this, &GuiProxy::interrupted); disconnect(m_gui, &PackageManagerGui::languageChanged, this, &GuiProxy::languageChanged); disconnect(m_gui, &PackageManagerGui::finishButtonClicked, this, &GuiProxy::finishButtonClicked); disconnect(m_gui, &PackageManagerGui::gotRestarted, this, &GuiProxy::gotRestarted); disconnect(m_gui, &PackageManagerGui::settingsButtonClicked, this, &GuiProxy::settingsButtonClicked); } m_gui = gui; if (m_gui) { connect(m_gui, &PackageManagerGui::interrupted, this, &GuiProxy::interrupted); connect(m_gui, &PackageManagerGui::languageChanged, this, &GuiProxy::languageChanged); connect(m_gui, &PackageManagerGui::finishButtonClicked, this, &GuiProxy::finishButtonClicked); connect(m_gui, &PackageManagerGui::gotRestarted, this, &GuiProxy::gotRestarted); connect(m_gui, &PackageManagerGui::settingsButtonClicked, this, &GuiProxy::settingsButtonClicked); } } /*! Returns the installer page specified by \a id. The values of \c id for the available installer pages are provided by QInstaller::WizardPage. */ QJSValue GuiProxy::pageById(int id) const { if (!m_gui) return QJSValue(); return m_engine->newQObject(m_gui->pageById(id)); } /*! Returns the installer page specified by \a name. The value of \c name is the object name set in the UI file that defines the installer page. */ QJSValue GuiProxy::pageByObjectName(const QString &name) const { if (!m_gui) return QJSValue(); return m_engine->newQObject(m_gui->pageByObjectName(name)); } /*! Returns the current wizard page. */ QJSValue GuiProxy::currentPageWidget() const { if (!m_gui) return QJSValue(); return m_engine->newQObject(m_gui->currentPageWidget()); } QJSValue GuiProxy::pageWidgetByObjectName(const QString &name) const { if (!m_gui) return QJSValue(); return m_engine->newQObject(m_gui->pageWidgetByObjectName(name)); } QString GuiProxy::defaultButtonText(int wizardButton) const { if (!m_gui) return QString(); return m_gui->defaultButtonText(wizardButton); } /*! Automatically clicks the button specified by \a wizardButton after a delay in milliseconds specified by \a delayInMs. */ void GuiProxy::clickButton(int wizardButton, int delayInMs) { if (m_gui) m_gui->clickButton(wizardButton, delayInMs); } /*! Automatically clicks the button specified by \a objectName after a delay in milliseconds specified by \a delayInMs. */ void GuiProxy::clickButton(const QString &objectName, int delayInMs) const { if (m_gui) m_gui->clickButton(objectName, delayInMs); } bool GuiProxy::isButtonEnabled(int wizardButton) { if (!m_gui) return false; return m_gui->isButtonEnabled(wizardButton); } void GuiProxy::showSettingsButton(bool show) { if (m_gui) m_gui->showSettingsButton(show); } void GuiProxy::setSettingsButtonEnabled(bool enable) { if (m_gui) m_gui->setSettingsButtonEnabled(enable); } /*! Returns the first descendant of \a parent that has \a objectName as name. \sa QObject::findChild */ QJSValue GuiProxy::findChild(QObject *parent, const QString &objectName) { return m_engine->newQObject(parent->findChild<QObject*>(objectName)); } /*! Returns all descendants of \a parent that have \a objectName as name. \sa QObject::findChildren */ QList<QJSValue> GuiProxy::findChildren(QObject *parent, const QString &objectName) { QList<QJSValue> children; foreach (QObject *child, parent->findChildren<QObject*>(objectName)) children.append(m_engine->newQObject(child)); return children; } /*! Hides the GUI when \a silent is \c true. */ void GuiProxy::setSilent(bool silent) { if (m_gui) m_gui->setSilent(silent); } void GuiProxy::setTextItems(QObject *object, const QStringList &items) { if (m_gui) m_gui->setTextItems(object, items); } void GuiProxy::cancelButtonClicked() { if (m_gui) m_gui->cancelButtonClicked(); } void GuiProxy::reject() { if (m_gui) m_gui->reject(); } void GuiProxy::rejectWithoutPrompt() { if (m_gui) m_gui->rejectWithoutPrompt(); } void GuiProxy::showFinishedPage() { if (m_gui) m_gui->showFinishedPage(); } void GuiProxy::setModified(bool value) { if (m_gui) m_gui->setModified(value); } QFileDialogProxy::QFileDialogProxy(PackageManagerCore *core): m_core(core) { } QString QFileDialogProxy::getExistingDirectory(const QString &caption, const QString &dir, const QString &identifier) { if (m_core->isCommandLineInstance()) { return getExistingFileOrDirectory(caption, identifier, true); } else { return QFileDialog::getExistingDirectory(0, caption, dir); } } QString QFileDialogProxy::getOpenFileName(const QString &caption, const QString &dir, const QString &filter, const QString &identifier) { if (m_core->isCommandLineInstance()) { return getExistingFileOrDirectory(caption, identifier, false); } else { return QFileDialog::getOpenFileName(0, caption, dir, filter); } } QString QFileDialogProxy::getExistingFileOrDirectory(const QString &caption, const QString &identifier, bool isDirectory) { QHash<QString, QString> autoAnswers = m_core->fileDialogAutomaticAnswers(); QString selectedDirectoryOrFile; QString errorString; if (autoAnswers.contains(identifier)) { selectedDirectoryOrFile = autoAnswers.value(identifier); QFileInfo fileInfo(selectedDirectoryOrFile); if (isDirectory ? fileInfo.isDir() : fileInfo.isFile()) { qCDebug(QInstaller::lcInstallerInstallLog).nospace() << "Automatic answer for "<< identifier << ": " << selectedDirectoryOrFile; } else { if (isDirectory) errorString = QString::fromLatin1("Automatic answer for %1: Directory '%2' not found.") .arg(identifier, selectedDirectoryOrFile); else errorString = QString::fromLatin1("Automatic answer for %1: File '%2' not found.") .arg(identifier, selectedDirectoryOrFile); selectedDirectoryOrFile = QString(); } } else { qDebug().nospace().noquote() << identifier << ": " << caption << ": "; QTextStream stream(stdin); stream.readLineInto(&selectedDirectoryOrFile); QFileInfo fileInfo(selectedDirectoryOrFile); if (isDirectory ? !fileInfo.isDir() : !fileInfo.isFile()) { if (isDirectory) errorString = QString::fromLatin1("Directory '%1' not found.") .arg(selectedDirectoryOrFile); else errorString = QString::fromLatin1("File '%1' not found.") .arg(selectedDirectoryOrFile); selectedDirectoryOrFile = QString(); } } if (!errorString.isEmpty()) qCWarning(QInstaller::lcInstallerInstallLog).nospace() << errorString; return selectedDirectoryOrFile; } /*! Constructs a script engine with \a core as parent. */ ScriptEngine::ScriptEngine(PackageManagerCore *core) : QObject(core), m_guiProxy(new GuiProxy(this, this)) { QJSValue global = m_engine.globalObject(); global.setProperty(QLatin1String("console"), m_engine.newQObject(new ConsoleProxy)); global.setProperty(QLatin1String("QFileDialog"), m_engine.newQObject(new QFileDialogProxy(core))); const QJSValue proxy = m_engine.newQObject(new InstallerProxy(this, core)); global.setProperty(QLatin1String("InstallerProxy"), proxy); global.setProperty(QLatin1String("print"), m_engine.newQObject(new ConsoleProxy) .property(QLatin1String("log"))); #if QT_VERSION < 0x050400 global.setProperty(QLatin1String("qsTr"), m_engine.newQObject(new QCoreApplicationProxy) .property(QStringLiteral("qsTr"))); #else m_engine.installTranslatorFunctions(); #endif global.setProperty(QLatin1String("systemInfo"), m_engine.newQObject(new SystemInfo)); global.setProperty(QLatin1String("QInstaller"), generateQInstallerObject()); global.setProperty(QLatin1String("buttons"), generateWizardButtonsObject()); global.setProperty(QLatin1String("QMessageBox"), generateMessageBoxObject()); global.setProperty(QLatin1String("QDesktopServices"), generateDesktopServicesObject()); if (core) { setGuiQObject(core->guiObject()); QQmlEngine::setObjectOwnership(core, QQmlEngine::CppOwnership); global.setProperty(QLatin1String("installer"), m_engine.newQObject(core)); connect(core, &PackageManagerCore::guiObjectChanged, this, &ScriptEngine::setGuiQObject); } else { global.setProperty(QLatin1String("installer"), m_engine.newQObject(new QObject)); } global.setProperty(QLatin1String("gui"), m_engine.newQObject(m_guiProxy)); global.property(QLatin1String("installer")).setProperty(QLatin1String("components"), proxy.property(QLatin1String("components"))); global.property(QLatin1String("installer")).setProperty(QLatin1String("componentByName"), proxy.property(QLatin1String("componentByName"))); } /*! Creates a JavaScript object that wraps the given QObject \a object. Signals and slots, properties and children of \a object are available as properties of the created QJSValue. In addition some helper methods and properties are added: \list \li findChild(), findChildren() recursively search for child objects with the given object name. \li Direct child objects are made accessible as properties under their respective object names. \endlist */ QJSValue ScriptEngine::newQObject(QObject *object) { QJSValue jsValue = m_engine.newQObject(object); if (!jsValue.isQObject()) return jsValue; QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); // add findChild(), findChildren() methods known from QtScript QJSValue findChild = m_engine.evaluate( QLatin1String("(function() { return gui.findChild(this, arguments[0]); })")); QJSValue findChildren = m_engine.evaluate( QLatin1String("(function() { return gui.findChildren(this, arguments[0]); })")); jsValue.setProperty(QLatin1String("findChild"), findChild); jsValue.setProperty(QLatin1String("findChildren"), findChildren); // add all named children as properties foreach (QObject *const child, object->children()) { if (child->objectName().isEmpty()) continue; jsValue.setProperty(child->objectName(), m_engine.newQObject(child)); newQObject(child); } return jsValue; } /*! Creates a JavaScript object of class Array with the specified \a length. */ QJSValue ScriptEngine::newArray(uint length) { return m_engine.newArray(length); } /*! Evaluates \a program, using \a lineNumber as the base line number, and returns the results of the evaluation. \a fileName is used for error reporting. */ QJSValue ScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber) { return m_engine.evaluate(program, fileName, lineNumber); } /*! Registers QObject \a object in the engine, and makes it globally accessible under its object name. */ void ScriptEngine::addToGlobalObject(QObject *object) { if (!object || object->objectName().isEmpty()) return; QJSValue value = newQObject(object); globalObject().setProperty(object->objectName(), value); } /*! Removes the \a object name from the global object. */ void ScriptEngine::removeFromGlobalObject(QObject *object) { globalObject().deleteProperty(object->objectName()); } /*! Loads a script into the given \a context at \a fileName inside the ScriptEngine. The installer and all its components as well as other useful stuff are being exported into the script. For more information, see \l {Component Scripting}. Throws Error when either the script at \a fileName could not be opened, or the QScriptEngine could not evaluate the script. TODO: document \a scriptInjection. */ QJSValue ScriptEngine::loadInContext(const QString &context, const QString &fileName, const QString &scriptInjection) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { throw Error(tr("Cannot open script file at %1: %2") .arg(fileName, file.errorString())); } // Create a closure. Put the content in the first line to keep line number order in case of an // exception. Script content will be added as the last argument to the command to prevent wrong // replacements of %1, %2 or %3 inside the javascript code. const QString scriptContent = QLatin1String("(function() {") + scriptInjection + QString::fromUtf8(file.readAll()) + QString::fromLatin1("\n" " if (typeof %1 != \"undefined\")" " return new %1;" " else" " throw \"Missing Component constructor. Please check your script.\";" "})();").arg(context); QString copiedFileName = fileName; #ifdef Q_OS_WIN // Workaround bug reported in QTBUG-70425 by appending "file://" when passing a filename to // QJSEngine::evaluate() to ensure it sees it as a valid URL when qsTr() is used. if (!copiedFileName.startsWith(QLatin1String("qrc:/")) && !copiedFileName.startsWith(QLatin1String(":/"))) { copiedFileName = QLatin1String("file://") + fileName; } #endif QJSValue scriptContext = evaluate(scriptContent, copiedFileName); scriptContext.setProperty(QLatin1String("Uuid"), QUuid::createUuid().toString()); if (scriptContext.isError()) { throw Error(tr("Exception while loading the component script \"%1\": %2").arg( QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()), scriptContext.toString().isEmpty() ? tr("Unknown error.") : scriptContext.toString() + QStringLiteral(" ") + tr("on line number: ") + scriptContext.property(QStringLiteral("lineNumber")).toString())); } return scriptContext; } /*! Tries to call the method specified by \a methodName with the arguments specified by \a arguments within the script and returns the result. If the method does not exist or is not callable, an undefined result is returned. If the call to the method succeeds and the return value is still undefined, a null value will be returned instead. If the method call has an exception, its string representation is thrown as an Error exception. \note The method is not called if \a scriptContext is the same method, to avoid infinite recursion. */ QJSValue ScriptEngine::callScriptMethod(const QJSValue &scriptContext, const QString &methodName, const QJSValueList &arguments) { // don't allow a recursion const QString key = scriptContext.property(QLatin1String("Uuid")).toString(); QStringList stack = m_callstack.value(key); if (m_callstack.contains(key) && stack.value(stack.size() - 1).startsWith(methodName)) return QJSValue(QJSValue::UndefinedValue); stack.append(methodName); m_callstack.insert(key, stack); QJSValue method = scriptContext.property(methodName); if (!method.isCallable()) return QJSValue(QJSValue::UndefinedValue); if (method.isError()) { throw Error(method.toString().isEmpty() ? QString::fromLatin1("Unknown error.") : method.toString()); } const QJSValue result = method.call(arguments); if (result.isError()) { throw Error(result.toString().isEmpty() ? QString::fromLatin1("Unknown error.") : result.toString()); } stack.removeLast(); m_callstack.insert(key, stack); return result.isUndefined() ? QJSValue(QJSValue::NullValue) : result; } // -- private slots void ScriptEngine::setGuiQObject(QObject *guiQObject) { m_guiProxy->setPackageManagerGui(qobject_cast<PackageManagerGui*>(guiQObject)); } // -- private #undef SETPROPERTY #define SETPROPERTY(a, x, t) a.setProperty(QLatin1String(#x), QJSValue(t::x)); QJSValue ScriptEngine::generateWizardButtonsObject() { QJSValue buttons = m_engine.newArray(); SETPROPERTY(buttons, BackButton, QWizard) SETPROPERTY(buttons, NextButton, QWizard) SETPROPERTY(buttons, CommitButton, QWizard) SETPROPERTY(buttons, FinishButton, QWizard) SETPROPERTY(buttons, CancelButton, QWizard) SETPROPERTY(buttons, HelpButton, QWizard) SETPROPERTY(buttons, CustomButton1, QWizard) SETPROPERTY(buttons, CustomButton2, QWizard) SETPROPERTY(buttons, CustomButton3, QWizard) return buttons; } /*! \internal generates QMessageBox::StandardButton enum as an QScriptValue array */ QJSValue ScriptEngine::generateMessageBoxObject() { QJSValue messageBox = m_engine.newQObject(MessageBoxHandler::instance()); const QMetaObject &messageBoxMetaObject = QMessageBox::staticMetaObject; const int index = messageBoxMetaObject.indexOfEnumerator("StandardButtons"); QJSValue value = m_engine.newArray(); value.setProperty(QLatin1String("NoButton"), QJSValue(QMessageBox::NoButton)); const QMetaEnum metaEnum = messageBoxMetaObject.enumerator(index); for (int i = 0; i < metaEnum.keyCount(); i++) { const int enumValue = metaEnum.value(i); if (enumValue >= QMessageBox::FirstButton) value.setProperty(QLatin1String(metaEnum.valueToKey(enumValue)), QJSValue(enumValue)); if (enumValue == QMessageBox::LastButton) break; } messageBox.setPrototype(value); return messageBox; } QJSValue ScriptEngine::generateDesktopServicesObject() { QJSValue desktopServices = m_engine.newArray(); SETPROPERTY(desktopServices, DesktopLocation, QStandardPaths) SETPROPERTY(desktopServices, DocumentsLocation, QStandardPaths) SETPROPERTY(desktopServices, FontsLocation, QStandardPaths) SETPROPERTY(desktopServices, ApplicationsLocation, QStandardPaths) SETPROPERTY(desktopServices, MusicLocation, QStandardPaths) SETPROPERTY(desktopServices, MoviesLocation, QStandardPaths) SETPROPERTY(desktopServices, PicturesLocation, QStandardPaths) SETPROPERTY(desktopServices, TempLocation, QStandardPaths) SETPROPERTY(desktopServices, HomeLocation, QStandardPaths) SETPROPERTY(desktopServices, DataLocation, QStandardPaths) SETPROPERTY(desktopServices, CacheLocation, QStandardPaths) SETPROPERTY(desktopServices, GenericDataLocation, QStandardPaths) SETPROPERTY(desktopServices, RuntimeLocation, QStandardPaths) SETPROPERTY(desktopServices, ConfigLocation, QStandardPaths) SETPROPERTY(desktopServices, DownloadLocation, QStandardPaths) SETPROPERTY(desktopServices, GenericCacheLocation, QStandardPaths) SETPROPERTY(desktopServices, GenericConfigLocation, QStandardPaths) QJSValue object = m_engine.newQObject(new QDesktopServicesProxy(this)); object.setPrototype(desktopServices); // attach the properties return object; } QJSValue ScriptEngine::generateQInstallerObject() { // register ::WizardPage enum in the script connection QJSValue qinstaller = m_engine.newArray(); SETPROPERTY(qinstaller, Introduction, PackageManagerCore) SETPROPERTY(qinstaller, LicenseCheck, PackageManagerCore) SETPROPERTY(qinstaller, TargetDirectory, PackageManagerCore) SETPROPERTY(qinstaller, ComponentSelection, PackageManagerCore) SETPROPERTY(qinstaller, StartMenuSelection, PackageManagerCore) SETPROPERTY(qinstaller, ReadyForInstallation, PackageManagerCore) SETPROPERTY(qinstaller, PerformInstallation, PackageManagerCore) SETPROPERTY(qinstaller, InstallationFinished, PackageManagerCore) SETPROPERTY(qinstaller, End, PackageManagerCore) // register ::Status enum in the script connection SETPROPERTY(qinstaller, Success, PackageManagerCore) SETPROPERTY(qinstaller, Failure, PackageManagerCore) SETPROPERTY(qinstaller, Running, PackageManagerCore) SETPROPERTY(qinstaller, Canceled, PackageManagerCore) SETPROPERTY(qinstaller, Unfinished, PackageManagerCore) SETPROPERTY(qinstaller, ForceUpdate, PackageManagerCore) return qinstaller; } #undef SETPROPERTY } // namespace QInstaller ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/scriptengine.h��������������������������������������0100777�0000000�0000000�00000005160�13761647206�021462� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SCRIPTENGINE_H #define SCRIPTENGINE_H #include "installer_global.h" #include <QJSValue> #include <QJSEngine> namespace QInstaller { class PackageManagerCore; class GuiProxy; class INSTALLER_EXPORT ScriptEngine : public QObject { Q_OBJECT Q_DISABLE_COPY(ScriptEngine) public: explicit ScriptEngine(PackageManagerCore *core = 0); QJSValue globalObject() const { return m_engine.globalObject(); } QJSValue newQObject(QObject *object); QJSValue newArray(uint length = 0); QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); void addToGlobalObject(QObject *object); void removeFromGlobalObject(QObject *object); QJSValue loadInContext(const QString &context, const QString &fileName, const QString &scriptInjection = QString()); QJSValue callScriptMethod(const QJSValue &context, const QString &methodName, const QJSValueList &arguments = QJSValueList()); private slots: void setGuiQObject(QObject *guiQObject); private: QJSValue generateMessageBoxObject(); QJSValue generateQInstallerObject(); QJSValue generateWizardButtonsObject(); QJSValue generateDesktopServicesObject(); private: QJSEngine m_engine; QHash<QString, QStringList> m_callstack; GuiProxy *m_guiProxy; }; } Q_DECLARE_METATYPE(QInstaller::ScriptEngine*) #endif // SCRIPTENGINE_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/scriptengine_p.h������������������������������������0100777�0000000�0000000�00000014123�13761647206�022000� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SCRIPTENGINE_P_H #define SCRIPTENGINE_P_H #include "component.h" #include "packagemanagercore.h" #include "packagemanagergui.h" #include "globals.h" #include <QDebug> #include <QDesktopServices> #include <QFileDialog> #include <QStandardPaths> namespace QInstaller { class ConsoleProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(ConsoleProxy) public: ConsoleProxy() {} public slots : void log(const QString &log) { qCDebug(QInstaller::lcInstallerInstallLog).noquote() << log; } }; class InstallerProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(InstallerProxy) public: InstallerProxy(ScriptEngine *engine, PackageManagerCore *core) : m_engine(engine), m_core(core) {} public slots: QJSValue components() const; QJSValue componentByName(const QString &componentName); private: ScriptEngine *m_engine; PackageManagerCore *m_core; }; class QFileDialogProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(QFileDialogProxy) public: QFileDialogProxy(PackageManagerCore *core); public slots : QString getExistingDirectory(const QString &caption, const QString &dir, const QString &identifier = QLatin1String("GetExistingDirectory")); QString getOpenFileName(const QString &caption, const QString &dir, const QString &filter, const QString &identifier = QLatin1String("GetExistingFile")); private: QString getExistingFileOrDirectory(const QString &caption, const QString &identifier, bool isDirectory); private: PackageManagerCore *m_core; }; class QDesktopServicesProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(QDesktopServicesProxy) public: QDesktopServicesProxy(ScriptEngine *engine) : m_engine(engine){} public slots : bool openUrl(const QString &url) const { QString urlToOpen = url; urlToOpen.replace(QLatin1String("\\\\"), QLatin1String("/")); urlToOpen.replace(QLatin1String("\\"), QLatin1String("/")); return QDesktopServices::openUrl(QUrl::fromUserInput(urlToOpen)); } QString displayName(qint32 location) const { return QStandardPaths::displayName(QStandardPaths::StandardLocation(location)); } QString storageLocation(qint32 location) const { return QStandardPaths::writableLocation(QStandardPaths::StandardLocation(location)); } QJSValue findFiles(const QString &path, const QString &pattern); private: void findRecursion(const QString &path, const QString &pattern, QStringList *result); private: ScriptEngine *m_engine; }; #if QT_VERSION < 0x050400 class QCoreApplicationProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(QCoreApplicationProxy) public: QCoreApplicationProxy() {} public slots: QString qsTr(const QString &text = QString(), const QString &disambiguation = QString(), int n = -1) const { return QCoreApplication::translate(QCoreApplication::applicationName().toUtf8().constData(), text.toUtf8().constData(), disambiguation.toUtf8().constData(), n); } }; #endif class GuiProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(GuiProxy) public: GuiProxy(ScriptEngine *engine, QObject *parent); void setPackageManagerGui(PackageManagerGui *gui); Q_INVOKABLE QJSValue pageById(int id) const; Q_INVOKABLE QJSValue pageByObjectName(const QString &name) const; Q_INVOKABLE QJSValue currentPageWidget() const; Q_INVOKABLE QJSValue pageWidgetByObjectName(const QString &name) const; Q_INVOKABLE QString defaultButtonText(int wizardButton) const; Q_INVOKABLE void clickButton(int wizardButton, int delayInMs = 0); Q_INVOKABLE void clickButton(const QString &objectName, int delayInMs = 0) const; Q_INVOKABLE bool isButtonEnabled(int wizardButton); Q_INVOKABLE void showSettingsButton(bool show); Q_INVOKABLE void setSettingsButtonEnabled(bool enable); Q_INVOKABLE QJSValue findChild(QObject *parent, const QString &objectName); Q_INVOKABLE QList<QJSValue> findChildren(QObject *parent, const QString &objectName); Q_INVOKABLE void setSilent(bool silent); Q_INVOKABLE void setTextItems(QObject *object, const QStringList &items); signals: void interrupted(); void languageChanged(); void finishButtonClicked(); void gotRestarted(); void settingsButtonClicked(); public slots: void cancelButtonClicked(); void reject(); void rejectWithoutPrompt(); void showFinishedPage(); void setModified(bool value); private: ScriptEngine *m_engine; PackageManagerGui *m_gui; }; } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::ConsoleProxy*) Q_DECLARE_METATYPE(QInstaller::InstallerProxy*) Q_DECLARE_METATYPE(QInstaller::QFileDialogProxy*) Q_DECLARE_METATYPE(QInstaller::QDesktopServicesProxy*) #if QT_VERSION < 0x050400 Q_DECLARE_METATYPE(QInstaller::QCoreApplicationProxy*) #endif #endif // SCRIPTENGINE_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/selfrestartoperation.cpp����������������������������0100777�0000000�0000000�00000005212�13761647206�023600� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "selfrestartoperation.h" #include "packagemanagercore.h" #include "selfrestarter.h" using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::SelfRestartOperation \internal */ SelfRestartOperation::SelfRestartOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("SelfRestart")); } void SelfRestartOperation::backup() { setValue(QLatin1String("PreviousSelfRestart"), SelfRestarter::restartOnQuit()); } bool SelfRestartOperation::performOperation() { PackageManagerCore *const core = packageManager(); if (!core) { setError(UserDefinedError); setErrorString(tr("Installer object needed in operation %1 is empty.").arg(name())); return false; } if (!core->isMaintainer()) { setError(UserDefinedError); setErrorString(tr("Self Restart: Only valid within updater or packagemanager mode.")); return false; } if (!arguments().isEmpty()) { setError(InvalidArguments); setErrorString(tr("Self Restart: Invalid arguments")); return false; } SelfRestarter::setRestartOnQuit(true); return SelfRestarter::restartOnQuit(); } bool SelfRestartOperation::undoOperation() { SelfRestarter::setRestartOnQuit(value(QLatin1String("PreviousSelfRestart")).toBool()); return true; } bool SelfRestartOperation::testOperation() { return true; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/selfrestartoperation.h������������������������������0100777�0000000�0000000�00000003232�13761647206�023245� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SELFRESTARTOPERATION_H #define SELFRESTARTOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT SelfRestartOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::SelfRestartOperation) public: explicit SelfRestartOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/serverauthenticationdialog.cpp����������������������0100777�0000000�0000000�00000004350�13761647206�024751� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "serverauthenticationdialog.h" #include "downloadfiletask.h" #include "ui_serverauthenticationdialog.h" #include <QAuthenticator> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::ServerAuthenticationDialog \internal */ ServerAuthenticationDialog::ServerAuthenticationDialog(const QString &m, const FileTaskItem &item) : ui(new Ui::ServerAuthenticationDialog) { ui->setupUi(this); ui->siteDescription->setText(m); setWindowFlags(windowFlags() &~Qt::WindowContextHelpButtonHint); const QAuthenticator auth = item.value(TaskRole::Authenticator).value<QAuthenticator>(); ui->userEdit->setText(auth.user()); ui->passwordEdit->setText(auth.password()); } ServerAuthenticationDialog::~ServerAuthenticationDialog() { delete ui; } QString ServerAuthenticationDialog::user() const { return ui->userEdit->text(); } QString ServerAuthenticationDialog::password() const { return ui->passwordEdit->text(); } } // namespace QInstaller ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/serverauthenticationdialog.h������������������������0100777�0000000�0000000�00000003516�13761647206�024421� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SERVERAUTHENTICATIONDIALOG_H #define SERVERAUTHENTICATIONDIALOG_H #include <QDialog> namespace QInstaller { namespace Ui { class ServerAuthenticationDialog; } class FileTaskItem; class ServerAuthenticationDialog : public QDialog { Q_OBJECT Q_DISABLE_COPY(ServerAuthenticationDialog) public: explicit ServerAuthenticationDialog(const QString &message, const FileTaskItem &item); ~ServerAuthenticationDialog(); QString user() const; QString password() const; private: Ui::ServerAuthenticationDialog *ui; }; } // QInstaller #endif // SERVERAUTHENTICATIONDIALOG_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/serverauthenticationdialog.ui�����������������������0100777�0000000�0000000�00000006404�13761647206�024606� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QInstaller::ServerAuthenticationDialog</class> <widget class="QDialog" name="QInstaller::ServerAuthenticationDialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>330</width> <height>137</height> </rect> </property> <property name="windowTitle"> <string>Server Requires Authentication</string> </property> <layout class="QGridLayout"> <item row="0" column="0" colspan="2"> <widget class="QLabel" name="label"> <property name="text"> <string>You need to supply a username and password to access this site.</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Username:</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QLineEdit" name="userEdit"/> </item> <item row="3" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Password:</string> </property> </widget> </item> <item row="3" column="1"> <widget class="QLineEdit" name="passwordEdit"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> <item row="5" column="0" colspan="2"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string/> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="siteDescription"> <property name="font"> <font> <weight>75</weight> <bold>true</bold> </font> </property> <property name="text"> <string>%1 at %2</string> </property> <property name="wordWrap"> <bool>true</bool> </property> </widget> </item> <item row="4" column="0"> <spacer> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> </layout> </widget> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>accepted()</signal> <receiver>QInstaller::ServerAuthenticationDialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>165</x> <y>116</y> </hint> <hint type="destinationlabel"> <x>165</x> <y>68</y> </hint> </hints> </connection> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>QInstaller::ServerAuthenticationDialog</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>165</x> <y>116</y> </hint> <hint type="destinationlabel"> <x>165</x> <y>68</y> </hint> </hints> </connection> </connections> </ui> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/settings.cpp����������������������������������������0100777�0000000�0000000�00000076751�13761647206�021201� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "settings.h" #include "errors.h" #include "qinstallerglobal.h" #include "repository.h" #include "repositorycategory.h" #include "globals.h" #include <QtCore/QFileInfo> #include <QtCore/QStringList> #include <QtGui/QFontMetrics> #include <QtWidgets/QApplication> #include <QRegularExpression> #include <QXmlStreamReader> using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::Settings \internal */ /*! \typedef QInstaller::RepoHash Synonym for QHash<QString, QPair<Repository, Repository> >. Describes a repository update with the supported key strings being \e{replace}, \e{remove}, and \e{add}. */ static const QLatin1String scInstallerApplicationIcon("InstallerApplicationIcon"); static const QLatin1String scInstallerWindowIcon("InstallerWindowIcon"); static const QLatin1String scLogo("Logo"); static const QLatin1String scPrefix("Prefix"); static const QLatin1String scWatermark("Watermark"); static const QLatin1String scBanner("Banner"); static const QLatin1String scProductUrl("ProductUrl"); static const QLatin1String scBackground("Background"); static const QLatin1String scPageListPixmap("PageListPixmap"); static const QLatin1String scAdminTargetDir("AdminTargetDir"); static const QLatin1String scMaintenanceToolName("MaintenanceToolName"); static const QLatin1String scUserRepositories("UserRepositories"); static const QLatin1String scTmpRepositories("TemporaryRepositories"); static const QLatin1String scMaintenanceToolIniFile("MaintenanceToolIniFile"); static const QLatin1String scRemoteRepositories("RemoteRepositories"); static const QLatin1String scRepositoryCategories("RepositoryCategories"); static const QLatin1String scDependsOnLocalInstallerBinary("DependsOnLocalInstallerBinary"); static const QLatin1String scTranslations("Translations"); static const QLatin1String scCreateLocalRepository("CreateLocalRepository"); static const QLatin1String scInstallActionColumnVisible("InstallActionColumnVisible"); static const QLatin1String scFtpProxy("FtpProxy"); static const QLatin1String scHttpProxy("HttpProxy"); static const QLatin1String scProxyType("ProxyType"); const char scControlScript[] = "ControlScript"; template <typename T> static QSet<T> variantListToSet(const QVariantList &list) { QSet<T> set; foreach (const QVariant &variant, list) set.insert(variant.value<T>()); return set; } static void raiseError(QXmlStreamReader &reader, const QString &error, Settings::ParseMode parseMode) { if (parseMode == Settings::StrictParseMode) { reader.raiseError(error); } else { QFile *xmlFile = qobject_cast<QFile*>(reader.device()); if (xmlFile) { qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Ignoring following settings reader error in " << xmlFile->fileName() << ", line " << reader.lineNumber() << ", column " << reader.columnNumber() << ": " << error; } else { qCWarning(QInstaller::lcInstallerInstallLog) << "Ignoring following settings reader error: " << qPrintable(error); } } } static QStringList readArgumentAttributes(QXmlStreamReader &reader, Settings::ParseMode parseMode, const QString &tagName, bool lc = false) { QStringList arguments; while (QXmlStreamReader::TokenType token = reader.readNext()) { switch (token) { case QXmlStreamReader::StartElement: { if (!reader.attributes().isEmpty()) { raiseError(reader, QString::fromLatin1("Unexpected attribute for element \"%1\".") .arg(reader.name().toString()), parseMode); return arguments; } else { if (reader.name().toString() == tagName) { (lc) ? arguments.append(reader.readElementText().toLower()) : arguments.append(reader.readElementText()); } else { raiseError(reader, QString::fromLatin1("Unexpected element \"%1\".").arg(reader.name() .toString()), parseMode); return arguments; } } } break; case QXmlStreamReader::Characters: { if (reader.isWhitespace()) continue; arguments.append(reader.text().toString().split(QRegularExpression(QLatin1String("\\s+")), QString::SkipEmptyParts)); } break; case QXmlStreamReader::EndElement: { return arguments; } default: break; } } return arguments; } static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefault, Settings::ParseMode parseMode, QString *displayName = nullptr, bool *preselected = nullptr, QString *tooltip = nullptr) { QSet<Repository> set; while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("DisplayName")) { //remote repository can have also displayname. Needed when creating archive repositories *displayName = reader.readElementText(); } else if (reader.name() == QLatin1String("Repository")) { Repository repo(QString(), isDefault); while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("Url")) { repo.setUrl(reader.readElementText()); } else if (reader.name() == QLatin1String("Username")) { repo.setUsername(reader.readElementText()); } else if (reader.name() == QLatin1String("Password")) { repo.setPassword(reader.readElementText()); } else if (reader.name() == QLatin1String("DisplayName")) { repo.setDisplayName(reader.readElementText()); } else if (reader.name() == QLatin1String("Enabled")) { repo.setEnabled(bool(reader.readElementText().toInt())); } else { raiseError(reader, QString::fromLatin1("Unexpected element \"%1\".").arg(reader.name() .toString()), parseMode); } if (!reader.attributes().isEmpty()) { raiseError(reader, QString::fromLatin1("Unexpected attribute for element \"%1\".") .arg(reader.name().toString()), parseMode); } } if (displayName && !displayName->isEmpty()) repo.setCategoryName(*displayName); set.insert(repo); } else if (reader.name() == QLatin1String("Tooltip")) { *tooltip = reader.readElementText(); } else if (reader.name() == QLatin1String("Preselected")) { *preselected = (reader.readElementText() == QLatin1String("true") ? true : false); } else { raiseError(reader, QString::fromLatin1("Unexpected element \"%1\".").arg(reader.name().toString()), parseMode); } if (!reader.attributes().isEmpty()) { raiseError(reader, QString::fromLatin1("Unexpected attribute for element \"%1\".").arg(reader .name().toString()), parseMode); } } return set; } static QSet<RepositoryCategory> readRepositoryCategories(QXmlStreamReader &reader, bool isDefault, Settings::ParseMode parseMode, QString *repositoryCategoryName) { QSet<RepositoryCategory> archiveSet; while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("RemoteRepositories")) { RepositoryCategory archiveRepo; QString displayName; QString tooltip; bool preselected = false; archiveRepo.setRepositories(readRepositories(reader, isDefault, parseMode, &displayName, &preselected, &tooltip)); archiveRepo.setDisplayName(displayName); archiveRepo.setTooltip(tooltip); archiveRepo.setEnabled(preselected); archiveSet.insert(archiveRepo); } else if (reader.name() == QLatin1String("RepositoryCategoryDisplayname")) { *repositoryCategoryName = reader.readElementText(); } } return archiveSet; } // -- Settings::Private class Settings::Private : public QSharedData { public: Private() : m_replacementRepos(false) {} QVariantHash m_data; bool m_replacementRepos; QString absolutePathFromKey(const QString &key, const QString &suffix = QString()) const { const QString value = m_data.value(key).toString(); if (value.isEmpty()) return QString(); const QString path = value + suffix; if (QFileInfo(path).isAbsolute()) return path; return m_data.value(scPrefix).toString() + QLatin1String("/") + path; } }; // -- Settings Settings::Settings() : d(new Private) { } Settings::~Settings() { } Settings::Settings(const Settings &other) : d(other.d) { } Settings& Settings::operator=(const Settings &other) { Settings copy(other); std::swap(d, copy.d); return *this; } /* static */ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix, ParseMode parseMode) { QFile file(path); QFile overrideConfig(QLatin1String(":/overrideconfig.xml")); if (overrideConfig.exists()) file.setFileName(overrideConfig.fileName()); if (!file.open(QIODevice::ReadOnly)) throw Error(tr("Cannot open settings file %1 for reading: %2").arg(path, file.errorString())); QXmlStreamReader reader(&file); if (reader.readNextStartElement()) { if (reader.name() != QLatin1String("Installer")) { reader.raiseError(QString::fromLatin1("Unexpected element \"%1\" as root element.").arg(reader .name().toString())); } } QStringList elementList; elementList << scName << scVersion << scTitle << scPublisher << scProductUrl << scTargetDir << scAdminTargetDir << scInstallerApplicationIcon << scInstallerWindowIcon << scLogo << scWatermark << scBanner << scBackground << scPageListPixmap << scStartMenuDir << scMaintenanceToolName << scMaintenanceToolIniFile << scRemoveTargetDir << scRunProgram << scRunProgramArguments << scRunProgramDescription << scDependsOnLocalInstallerBinary << scAllowSpaceInPath << scAllowNonAsciiCharacters << scDisableAuthorizationFallback << scDisableCommandLineInterface << scWizardStyle << scStyleSheet << scTitleColor << scWizardDefaultWidth << scWizardDefaultHeight << scWizardShowPageList << scProductImages << scRepositorySettingsPageVisible << scTargetConfigurationFile << scRemoteRepositories << scTranslations << scUrlQueryString << QLatin1String(scControlScript) << scCreateLocalRepository << scInstallActionColumnVisible << scSupportsModify << scAllowUnstableComponents << scSaveDefaultRepositories << scRepositoryCategories; Settings s; s.d->m_data.insert(scPrefix, prefix); while (reader.readNextStartElement()) { const QString name = reader.name().toString(); if (!elementList.contains(name)) raiseError(reader, QString::fromLatin1("Unexpected element \"%1\".").arg(name), parseMode); if (!reader.attributes().isEmpty()) { raiseError(reader, QString::fromLatin1("Unexpected attribute for element \"%1\".").arg(name), parseMode); } if (s.d->m_data.contains(name)) reader.raiseError(QString::fromLatin1("Element \"%1\" has been defined before.").arg(name)); if (name == scTranslations) { s.setTranslations(readArgumentAttributes(reader, parseMode, QLatin1String("Translation"), true)); } else if (name == scRunProgramArguments) { s.setRunProgramArguments(readArgumentAttributes(reader, parseMode, QLatin1String("Argument"))); } else if (name == scProductImages) { s.setProductImages(readArgumentAttributes(reader, parseMode, QLatin1String("Image"))); } else if (name == scRemoteRepositories) { s.addDefaultRepositories(readRepositories(reader, true, parseMode)); } else if (name == scRepositoryCategories) { QString repositoryCategoryName; s.addRepositoryCategories(readRepositoryCategories(reader, true, parseMode, &repositoryCategoryName)); if (!repositoryCategoryName.isEmpty()) { s.setRepositoryCategoryDisplayName(repositoryCategoryName); } } else { s.d->m_data.insert(name, reader.readElementText(QXmlStreamReader::SkipChildElements)); } } if (reader.error() != QXmlStreamReader::NoError) { throw Error(QString::fromLatin1("Error in %1, line %2, column %3: %4").arg(path).arg(reader .lineNumber()).arg(reader.columnNumber()).arg(reader.errorString())); } if (s.d->m_data.value(scName).isNull()) throw Error(QString::fromLatin1("Missing or empty <Name> tag in %1.").arg(file.fileName())); if (s.d->m_data.value(scVersion).isNull()) throw Error(QString::fromLatin1("Missing or empty <Version> tag in %1.").arg(file.fileName())); // Add some possible missing values if (!s.d->m_data.contains(scInstallerApplicationIcon)) s.d->m_data.insert(scInstallerApplicationIcon, QLatin1String(":/installer")); if (!s.d->m_data.contains(scInstallerWindowIcon)) { s.d->m_data.insert(scInstallerWindowIcon, QString(QLatin1String(":/installer") + s.systemIconSuffix())); } if (!s.d->m_data.contains(scRemoveTargetDir)) s.d->m_data.insert(scRemoveTargetDir, scTrue); if (s.d->m_data.value(scMaintenanceToolName).toString().isEmpty()) { s.d->m_data.insert(scMaintenanceToolName, // TODO: Remove deprecated 'UninstallerName'. s.d->m_data.value(QLatin1String("UninstallerName"), QLatin1String("maintenancetool")) .toString()); } if (s.d->m_data.value(scTargetConfigurationFile).toString().isEmpty()) s.d->m_data.insert(scTargetConfigurationFile, QLatin1String("components.xml")); if (s.d->m_data.value(scMaintenanceToolIniFile).toString().isEmpty()) { s.d->m_data.insert(scMaintenanceToolIniFile, // TODO: Remove deprecated 'UninstallerIniFile'. s.d->m_data.value(QLatin1String("UninstallerIniFile"), QString(s.maintenanceToolName() + QLatin1String(".ini"))).toString()); } if (!s.d->m_data.contains(scDependsOnLocalInstallerBinary)) s.d->m_data.insert(scDependsOnLocalInstallerBinary, false); if (!s.d->m_data.contains(scRepositorySettingsPageVisible)) s.d->m_data.insert(scRepositorySettingsPageVisible, true); if (!s.d->m_data.contains(scCreateLocalRepository)) s.d->m_data.insert(scCreateLocalRepository, false); if (!s.d->m_data.contains(scInstallActionColumnVisible)) s.d->m_data.insert(scInstallActionColumnVisible, false); if (!s.d->m_data.contains(scAllowUnstableComponents)) s.d->m_data.insert(scAllowUnstableComponents, false); if (!s.d->m_data.contains(scSaveDefaultRepositories)) s.d->m_data.insert(scSaveDefaultRepositories, true); return s; } QString Settings::logo() const { return d->absolutePathFromKey(scLogo); } QString Settings::title() const { return d->m_data.value(scTitle).toString(); } QString Settings::applicationName() const { return d->m_data.value(scName).toString(); } QString Settings::version() const { return d->m_data.value(scVersion).toString(); } QString Settings::publisher() const { return d->m_data.value(scPublisher).toString(); } QString Settings::url() const { return d->m_data.value(scProductUrl).toString(); } QString Settings::watermark() const { return d->absolutePathFromKey(scWatermark); } QString Settings::banner() const { return d->absolutePathFromKey(scBanner); } QString Settings::background() const { return d->absolutePathFromKey(scBackground); } QString Settings::pageListPixmap() const { return d->absolutePathFromKey(scPageListPixmap); } QString Settings::wizardStyle() const { return d->m_data.value(scWizardStyle).toString(); } QString Settings::styleSheet() const { return d->absolutePathFromKey(scStyleSheet); } QString Settings::titleColor() const { return d->m_data.value(scTitleColor).toString(); } static int lengthToInt(const QVariant &variant) { QString length = variant.toString().trimmed(); if (length.endsWith(QLatin1String("em"), Qt::CaseInsensitive)) { length.chop(2); return qRound(length.toDouble() * QApplication::fontMetrics().height()); } if (length.endsWith(QLatin1String("ex"), Qt::CaseInsensitive)) { length.chop(2); return qRound(length.toDouble() * QApplication::fontMetrics().xHeight()); } if (length.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) { length.chop(2); } return length.toInt(); } int Settings::wizardDefaultWidth() const { // Add a bit more sensible default width in case the page list widget is shown // as it can take quite a lot horizontal space. A vendor can always override // the default value. return lengthToInt(d->m_data.value(scWizardDefaultWidth, wizardShowPageList() ? 800 : 0)); } int Settings::wizardDefaultHeight() const { return lengthToInt(d->m_data.value(scWizardDefaultHeight)); } bool Settings::wizardShowPageList() const { return d->m_data.value(scWizardShowPageList, true).toBool(); } QStringList Settings::productImages() const { const QVariant variant = d->m_data.value(scProductImages); QStringList imagePaths; if (variant.canConvert<QStringList>()) { foreach (const QString &imagePath, variant.value<QStringList>()) { QFileInfo(imagePath).isAbsolute() ? imagePaths.append(imagePath) : imagePaths.append(d->m_data.value(scPrefix).toString() + QLatin1Char('/') + imagePath); } } return imagePaths; } void Settings::setProductImages(const QStringList &images) { d->m_data.insert(scProductImages, images); } QString Settings::installerApplicationIcon() const { return d->absolutePathFromKey(scInstallerApplicationIcon, systemIconSuffix()); } QString Settings::installerWindowIcon() const { return d->absolutePathFromKey(scInstallerWindowIcon); } QString Settings::systemIconSuffix() const { #if defined(Q_OS_MACOS) return QLatin1String(".icns"); #elif defined(Q_OS_WIN) return QLatin1String(".ico"); #endif return QLatin1String(".png"); } QString Settings::removeTargetDir() const { return d->m_data.value(scRemoveTargetDir).toString(); } QString Settings::maintenanceToolName() const { return d->m_data.value(scMaintenanceToolName).toString(); } QString Settings::maintenanceToolIniFile() const { return d->m_data.value(scMaintenanceToolIniFile).toString(); } QString Settings::runProgram() const { return d->m_data.value(scRunProgram).toString(); } QStringList Settings::runProgramArguments() const { const QVariant variant = d->m_data.value(scRunProgramArguments); if (variant.canConvert<QStringList>()) return variant.value<QStringList>(); return QStringList(); } void Settings::setRunProgramArguments(const QStringList &arguments) { d->m_data.insert(scRunProgramArguments, arguments); } QString Settings::runProgramDescription() const { return d->m_data.value(scRunProgramDescription).toString(); } QString Settings::startMenuDir() const { return d->m_data.value(scStartMenuDir).toString(); } QString Settings::targetDir() const { return d->m_data.value(scTargetDir).toString(); } QString Settings::adminTargetDir() const { return d->m_data.value(scAdminTargetDir).toString(); } QString Settings::configurationFileName() const { return d->m_data.value(scTargetConfigurationFile).toString(); } bool Settings::createLocalRepository() const { return d->m_data.value(scCreateLocalRepository).toBool(); } bool Settings::installActionColumnVisible() const { return d->m_data.value(scInstallActionColumnVisible, false).toBool(); } bool Settings::allowSpaceInPath() const { return d->m_data.value(scAllowSpaceInPath, true).toBool(); } bool Settings::allowNonAsciiCharacters() const { return d->m_data.value(scAllowNonAsciiCharacters, false).toBool(); } bool Settings::disableAuthorizationFallback() const { return d->m_data.value(scDisableAuthorizationFallback, false).toBool(); } bool Settings::disableCommandLineInterface() const { return d->m_data.value(scDisableCommandLineInterface, false).toBool(); } bool Settings::dependsOnLocalInstallerBinary() const { return d->m_data.value(scDependsOnLocalInstallerBinary).toBool(); } bool Settings::hasReplacementRepos() const { return d->m_replacementRepos; } QSet<Repository> Settings::repositories() const { if (d->m_replacementRepos) return variantListToSet<Repository>(d->m_data.values(scTmpRepositories)); return variantListToSet<Repository>(d->m_data.values(scRepositories) + d->m_data.values(scUserRepositories) + d->m_data.values(scTmpRepositories)); } QSet<Repository> Settings::defaultRepositories() const { return variantListToSet<Repository>(d->m_data.values(scRepositories)); } QSet<RepositoryCategory> Settings::repositoryCategories() const { return variantListToSet<RepositoryCategory>(d->m_data.values(scRepositoryCategories)); } QMap<QString, RepositoryCategory> Settings::organizedRepositoryCategories() const { QSet<RepositoryCategory> categories = repositoryCategories(); QMap<QString, RepositoryCategory> map; foreach (const RepositoryCategory &category, categories) { map.insert(category.displayname(), category); } return map; } void Settings::setDefaultRepositories(const QSet<Repository> &repositories) { d->m_data.remove(scRepositories); addDefaultRepositories(repositories); } void Settings::addDefaultRepositories(const QSet<Repository> &repositories) { foreach (const Repository &repository, repositories) d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } void Settings::setRepositoryCategories(const QSet<RepositoryCategory> &repositories) { d->m_data.remove(scRepositoryCategories); addRepositoryCategories(repositories); } void Settings::addRepositoryCategories(const QSet<RepositoryCategory> &repositories) { foreach (const RepositoryCategory &repository, repositories) d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository)); } Settings::Update Settings::updateRepositoryCategories(const RepoHash &updates) { if (updates.isEmpty()) return Settings::NoUpdatesApplied; QSet<RepositoryCategory> categories = repositoryCategories(); QList<RepositoryCategory> categoriesList = categories.values(); QPair<Repository, Repository> updateValues = updates.value(QLatin1String("replace")); bool update = false; foreach (RepositoryCategory category, categoriesList) { QSet<Repository> repositories = category.repositories(); if (repositories.contains(updateValues.first)) { update = true; repositories.remove(updateValues.first); repositories.insert(updateValues.second); category.setRepositories(repositories, true); categoriesList.replace(categoriesList.indexOf(category), category); } } if (update) { categories = categoriesList.toSet(); setRepositoryCategories(categories); } return update ? Settings::UpdatesApplied : Settings::NoUpdatesApplied; } static bool apply(const RepoHash &updates, QHash<QUrl, Repository> *reposToUpdate) { bool update = false; QList<QPair<Repository, Repository> > values = updates.values(QLatin1String("replace")); for (int a = 0; a < values.count(); ++a) { const QPair<Repository, Repository> data = values.at(a); if (reposToUpdate->contains(data.first.url())) { update = true; reposToUpdate->remove(data.first.url()); reposToUpdate->insert(data.second.url(), data.second); } } values = updates.values(QLatin1String("remove")); for (int a = 0; a < values.count(); ++a) { const QPair<Repository, Repository> data = values.at(a); if (reposToUpdate->contains(data.first.url())) { update = true; reposToUpdate->remove(data.first.url()); } } values = updates.values(QLatin1String("add")); for (int a = 0; a < values.count(); ++a) { const QPair<Repository, Repository> data = values.at(a); if (!reposToUpdate->contains(data.first.url())) { update = true; reposToUpdate->insert(data.first.url(), data.first); } } return update; } Settings::Update Settings::updateDefaultRepositories(const RepoHash &updates) { if (updates.isEmpty()) return Settings::NoUpdatesApplied; QHash <QUrl, Repository> defaultRepos; foreach (const QVariant &variant, d->m_data.values(scRepositories)) { const Repository repository = variant.value<Repository>(); defaultRepos.insert(repository.url(), repository); } const bool updated = apply(updates, &defaultRepos); if (updated) setDefaultRepositories(defaultRepos.values().toSet()); return updated ? Settings::UpdatesApplied : Settings::NoUpdatesApplied; } QSet<Repository> Settings::temporaryRepositories() const { return variantListToSet<Repository>(d->m_data.values(scTmpRepositories)); } void Settings::setTemporaryRepositories(const QSet<Repository> &repositories, bool replace) { d->m_data.remove(scTmpRepositories); addTemporaryRepositories(repositories, replace); } void Settings::addTemporaryRepositories(const QSet<Repository> &repositories, bool replace) { d->m_replacementRepos = replace; foreach (const Repository &repository, repositories) d->m_data.insertMulti(scTmpRepositories, QVariant().fromValue(repository)); } QSet<Repository> Settings::userRepositories() const { return variantListToSet<Repository>(d->m_data.values(scUserRepositories)); } void Settings::setUserRepositories(const QSet<Repository> &repositories) { d->m_data.remove(scUserRepositories); addUserRepositories(repositories); } void Settings::addUserRepositories(const QSet<Repository> &repositories) { foreach (const Repository &repository, repositories) d->m_data.insertMulti(scUserRepositories, QVariant().fromValue(repository)); } Settings::Update Settings::updateUserRepositories(const RepoHash &updates) { if (updates.isEmpty()) return Settings::NoUpdatesApplied; QHash <QUrl, Repository> reposToUpdate; foreach (const QVariant &variant, d->m_data.values(scUserRepositories)) { const Repository repository = variant.value<Repository>(); reposToUpdate.insert(repository.url(), repository); } const bool updated = apply(updates, &reposToUpdate); if (updated) setUserRepositories(reposToUpdate.values().toSet()); return updated ? Settings::UpdatesApplied : Settings::NoUpdatesApplied; } bool Settings::containsValue(const QString &key) const { return d->m_data.contains(key); } QVariant Settings::value(const QString &key, const QVariant &defaultValue) const { return d->m_data.value(key, defaultValue); } QVariantList Settings::values(const QString &key, const QVariantList &defaultValue) const { QVariantList list = d->m_data.values(key); return list.isEmpty() ? defaultValue : list; } bool Settings::repositorySettingsPageVisible() const { return d->m_data.value(scRepositorySettingsPageVisible, true).toBool(); } void Settings::setRepositorySettingsPageVisible(bool visible) { d->m_data.insert(scRepositorySettingsPageVisible, visible); } Settings::ProxyType Settings::proxyType() const { return Settings::ProxyType(d->m_data.value(scProxyType, Settings::NoProxy).toInt()); } void Settings::setProxyType(Settings::ProxyType type) { d->m_data.insert(scProxyType, type); } QNetworkProxy Settings::ftpProxy() const { const QVariant variant = d->m_data.value(scFtpProxy); if (variant.canConvert<QNetworkProxy>()) return variant.value<QNetworkProxy>(); return QNetworkProxy(); } void Settings::setFtpProxy(const QNetworkProxy &proxy) { d->m_data.insert(scFtpProxy, QVariant::fromValue(proxy)); } QNetworkProxy Settings::httpProxy() const { const QVariant variant = d->m_data.value(scHttpProxy); if (variant.canConvert<QNetworkProxy>()) return variant.value<QNetworkProxy>(); return QNetworkProxy(); } void Settings::setHttpProxy(const QNetworkProxy &proxy) { d->m_data.insert(scHttpProxy, QVariant::fromValue(proxy)); } QStringList Settings::translations() const { const QVariant variant = d->m_data.value(scTranslations); if (variant.canConvert<QStringList>()) return variant.value<QStringList>(); return QStringList(); } void Settings::setTranslations(const QStringList &translations) { d->m_data.insert(scTranslations, translations); } QString Settings::controlScript() const { return d->m_data.value(QLatin1String(scControlScript)).toString(); } bool Settings::supportsModify() const { return d->m_data.value(scSupportsModify, true).toBool(); } bool Settings::allowUnstableComponents() const { return d->m_data.value(scAllowUnstableComponents, true).toBool(); } void Settings::setAllowUnstableComponents(bool allow) { d->m_data.insert(scAllowUnstableComponents, allow); } bool Settings::saveDefaultRepositories() const { return d->m_data.value(scSaveDefaultRepositories, true).toBool(); } void Settings::setSaveDefaultRepositories(bool save) { d->m_data.insert(scSaveDefaultRepositories, save); } QString Settings::repositoryCategoryDisplayName() const { QString displayName = d->m_data.value(QLatin1String(scRepositoryCategoryDisplayName)).toString(); return displayName.isEmpty() ? tr("Select Categories") : displayName; } void Settings::setRepositoryCategoryDisplayName(const QString& name) { d->m_data.insert(scRepositoryCategoryDisplayName, name); } �����������������������qt-installer-framework-4.0.1/src/libs/installer/settings.h������������������������������������������0100777�0000000�0000000�00000014015�13761647206�020627� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SETTINGS_H #define SETTINGS_H #include "constants.h" #include "installer_global.h" #include "repositorycategory.h" #include <QtCore/QCoreApplication> #include <QtCore/QSharedDataPointer> #include <QtCore/QStringList> #include <QtCore/QVariant> #include <QtNetwork/QNetworkProxy> namespace QInstaller { class Repository; typedef QHash<QString, QPair<Repository, Repository> > RepoHash; class INSTALLER_EXPORT Settings { Q_DECLARE_TR_FUNCTIONS(Settings) public: enum Update { UpdatesApplied, NoUpdatesApplied }; enum ProxyType { NoProxy, SystemProxy, UserDefinedProxy }; enum ParseMode { StrictParseMode, RelaxedParseMode }; explicit Settings(); ~Settings(); Settings(const Settings &other); Settings &operator=(const Settings &other); static Settings fromFileAndPrefix(const QString &path, const QString &prefix, ParseMode parseMode = StrictParseMode); QString logo() const; QString title() const; QString publisher() const; QString url() const; QString watermark() const; QString banner() const; QString background() const; QString pageListPixmap() const; QString installerApplicationIcon() const; QString installerWindowIcon() const; QString systemIconSuffix() const; QString wizardStyle() const; QString styleSheet() const; QString titleColor() const; int wizardDefaultWidth() const; int wizardDefaultHeight() const; bool wizardShowPageList() const; QStringList productImages() const; void setProductImages(const QStringList &images); QString applicationName() const; QString version() const; QString runProgram() const; QStringList runProgramArguments() const; void setRunProgramArguments(const QStringList &arguments); QString runProgramDescription() const; QString startMenuDir() const; QString targetDir() const; QString adminTargetDir() const; QString removeTargetDir() const; QString maintenanceToolName() const; QString maintenanceToolIniFile() const; QString configurationFileName() const; bool createLocalRepository() const; bool installActionColumnVisible() const; bool dependsOnLocalInstallerBinary() const; bool hasReplacementRepos() const; QSet<Repository> repositories() const; QSet<Repository> defaultRepositories() const; void setDefaultRepositories(const QSet<Repository> &repositories); void addDefaultRepositories(const QSet<Repository> &repositories); Settings::Update updateDefaultRepositories(const RepoHash &updates); QSet<RepositoryCategory> repositoryCategories() const; QMap<QString, RepositoryCategory> organizedRepositoryCategories() const; void setRepositoryCategories(const QSet<RepositoryCategory> &repositories); void addRepositoryCategories(const QSet<RepositoryCategory> &repositories); Settings::Update updateRepositoryCategories(const RepoHash &updates); QSet<Repository> temporaryRepositories() const; void setTemporaryRepositories(const QSet<Repository> &repositories, bool replace); void addTemporaryRepositories(const QSet<Repository> &repositories, bool replace); QSet<Repository> userRepositories() const; void setUserRepositories(const QSet<Repository> &repositories); void addUserRepositories(const QSet<Repository> &repositories); Settings::Update updateUserRepositories(const RepoHash &updates); bool allowSpaceInPath() const; bool allowNonAsciiCharacters() const; bool disableAuthorizationFallback() const; bool disableCommandLineInterface() const; bool containsValue(const QString &key) const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; QVariantList values(const QString &key, const QVariantList &defaultValue = QVariantList()) const; bool repositorySettingsPageVisible() const; void setRepositorySettingsPageVisible(bool visible); Settings::ProxyType proxyType() const; void setProxyType(Settings::ProxyType type); QNetworkProxy ftpProxy() const; void setFtpProxy(const QNetworkProxy &proxy); QNetworkProxy httpProxy() const; void setHttpProxy(const QNetworkProxy &proxy); QStringList translations() const; void setTranslations(const QStringList &translations); QString controlScript() const; bool supportsModify() const; bool allowUnstableComponents() const; void setAllowUnstableComponents(bool allow); bool saveDefaultRepositories() const; void setSaveDefaultRepositories(bool save); QString repositoryCategoryDisplayName() const; void setRepositoryCategoryDisplayName(const QString &displayName); private: class Private; QSharedDataPointer<Private> d; }; } Q_DECLARE_METATYPE(QInstaller::Settings) #endif // SETTINGS_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/settingsoperation.cpp�������������������������������0100777�0000000�0000000�00000017065�13761647206�023113� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "settingsoperation.h" #include "packagemanagercore.h" #include "updateoperations.h" #include "qsettingswrapper.h" #include "globals.h" #include <QDir> #include <QDebug> using namespace QInstaller; /*! \inmodule QtInstallerFramework \class QInstaller::SettingsOperation \internal */ SettingsOperation::SettingsOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Settings")); } void SettingsOperation::backup() { } bool SettingsOperation::checkArguments() { const QString path = argumentKeyValue(QLatin1String("path")); const QString method = argumentKeyValue(QLatin1String("method")); const QString key = argumentKeyValue(QLatin1String("key")); const QString aValue = argumentKeyValue(QLatin1String("value")); QStringList missingArguments; if (path.isEmpty()) missingArguments << QLatin1String("path"); if (method.isEmpty()) missingArguments << QLatin1String("method"); if (key.isEmpty()) missingArguments << QLatin1String("key"); if (method != QLatin1String("remove") && aValue.isEmpty()) missingArguments << QLatin1String("value"); if (!missingArguments.isEmpty()) { setError(InvalidArguments); setErrorString(tr("Missing argument(s) \"%1\" calling %2 with arguments \"%3\".").arg( missingArguments.join(QLatin1String("; ")), name(), arguments().join(QLatin1String("; ")))); return false; } QStringList possibleMethodValues; possibleMethodValues << QLatin1String("set") << QLatin1String("remove") << QLatin1String("add_array_value") << QLatin1String("remove_array_value"); if (!possibleMethodValues.contains(method)) { setError(InvalidArguments); setErrorString(tr("Current method argument calling \"%1\" with arguments \"%2\" is not " "supported. Please use set, remove, add_array_value or remove_array_value.").arg(name(), arguments().join(QLatin1String("; ")))); return false; } return true; } bool SettingsOperation::performOperation() { // Arguments: // 1. path=settings file path or registry path // 2. method=set|remove|add_array_value|remove_array_value // 3. key=can be prepended by a category name separated by slash // 4. value=just the value // optional arguments are // formate=native or ini TODO // backup=true or false (default is true) TODO // NOTE: remove and remove_array_value will do nothing at the undostep if (!checkArguments()) return false; const QString path = argumentKeyValue(QLatin1String("path")); const QString method = argumentKeyValue(QLatin1String("method")); const QString key = argumentKeyValue(QLatin1String("key")); const QString aValue = argumentKeyValue(QLatin1String("value")); // use MkdirOperation to get the path so it can remove it with MkdirOperation::undoOperation later KDUpdater::MkdirOperation mkDirOperation; mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath()); mkDirOperation.backup(); if (!mkDirOperation.performOperation()) { setError(mkDirOperation.error()); setErrorString(mkDirOperation.errorString()); return false; } setValue(QLatin1String("createddir"), mkDirOperation.value(QLatin1String("createddir"))); QSettingsWrapper settings(path, QSettingsWrapper::IniFormat); if (method == QLatin1String("set")) settings.setValue(key, aValue); else if (method == QLatin1String("remove")) settings.remove(key); else if (method == QLatin1String("add_array_value")) { QVariant valueVariant = settings.value(key); if (valueVariant.canConvert<QStringList>()) { QStringList array = valueVariant.toStringList(); array.append(aValue); settings.setValue(key, array); } else { settings.setValue(key, aValue); } } else if (method == QLatin1String("remove_array_value")) { QVariant valueVariant = settings.value(key); if (valueVariant.canConvert<QStringList>()) { QStringList array = valueVariant.toStringList(); array.removeOne(aValue); settings.setValue(key, array); } else { settings.remove(key); } } return true; } bool SettingsOperation::undoOperation() { if (!checkArguments()) return false; const QString path = argumentKeyValue(QLatin1String("path")); const QString method = argumentKeyValue(QLatin1String("method")); const QString key = argumentKeyValue(QLatin1String("key")); const QString aValue = argumentKeyValue(QLatin1String("value")); if (method.startsWith(QLatin1String("remove"))) return true; bool cleanUp = false; { // kill the scope to kill settings object, else remove file will not work QSettingsWrapper settings(path, QSettingsWrapper::IniFormat); if (method == QLatin1String("set")) { settings.remove(key); } else if (method == QLatin1String("add_array_value")) { QVariant valueVariant = settings.value(key); if (valueVariant.canConvert<QStringList>()) { QStringList array = valueVariant.toStringList(); array.removeOne(aValue); if (array.isEmpty()) settings.remove(key); else settings.setValue(key, array); } else { settings.setValue(key, aValue); } } settings.sync(); // be safe cleanUp = settings.allKeys().isEmpty(); } if (cleanUp) { QFile settingsFile(path); if (!settingsFile.remove()) qCWarning(QInstaller::lcInstallerInstallLog).noquote() << settingsFile.errorString(); if (!value(QLatin1String("createddir")).toString().isEmpty()) { KDUpdater::MkdirOperation mkDirOperation(packageManager()); mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath()); mkDirOperation.setValue(QLatin1String("createddir"), value(QLatin1String("createddir"))); if (!mkDirOperation.undoOperation()) { qCWarning(QInstaller::lcInstallerInstallLog).noquote() << mkDirOperation.errorString(); } } } return true; } bool SettingsOperation::testOperation() { return true; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/settingsoperation.h���������������������������������0100777�0000000�0000000�00000003337�13761647206�022555� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SETTINGSOPERATION_H #define SETTINGSOPERATION_H #include "qinstallerglobal.h" namespace QInstaller { class INSTALLER_EXPORT SettingsOperation : public Operation { Q_DECLARE_TR_FUNCTIONS(QInstaller::SettingsOperation) public: explicit SettingsOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); private: bool checkArguments(); }; } // namespace QInstaller #endif // SETTINGSOPERATION_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/simplemovefileoperation.cpp�������������������������0100777�0000000�0000000�00000007323�13761647206�024267� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "simplemovefileoperation.h" #include <QDir> #include <QtCore/QFileInfo> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::SimpleMoveFileOperation \internal */ SimpleMoveFileOperation::SimpleMoveFileOperation(PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("SimpleMoveFile")); } void SimpleMoveFileOperation::backup() { } bool SimpleMoveFileOperation::performOperation() { if (!checkArgumentCount(2)) return false; const QStringList args = arguments(); const QString source = args.at(0); const QString target = args.at(1); if (source.isEmpty() || target.isEmpty()) { setError(UserDefinedError); setErrorString(tr("None of the arguments can be empty: source \"%1\", target \"%2\".") .arg(QDir::toNativeSeparators(source), QDir::toNativeSeparators(target))); return false; } // If destination file exists, then we cannot use QFile::copy() because it does not overwrite an existing // file. So we remove the destination file. QFile file(target); if (file.exists()) { if (!file.remove()) { setError(UserDefinedError); setErrorString(tr("Cannot move file from \"%1\" to \"%2\", because the target path exists and is " "not removable.").arg(QDir::toNativeSeparators(source), QDir::toNativeSeparators(target))); return false; } } file.setFileName(source); if (!file.rename(target)) { setError(UserDefinedError); setErrorString(tr("Cannot move file \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(source), QDir::toNativeSeparators(target), file.errorString())); return false; } emit outputTextChanged(tr("Moving file \"%1\" to \"%2\".").arg(QDir::toNativeSeparators(source), QDir::toNativeSeparators(target))); return true; } bool SimpleMoveFileOperation::undoOperation() { const QString source = arguments().at(0); const QString target = arguments().at(1); QFile(target).rename(source); emit outputTextChanged(tr("Moving file \"%1\" to \"%2\".").arg(QDir::toNativeSeparators(target), QDir::toNativeSeparators(source))); return true; } bool SimpleMoveFileOperation::testOperation() { return true; } } // namespace QInstaller �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/simplemovefileoperation.h���������������������������0100777�0000000�0000000�00000003377�13761647206�023741� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SIMPLEMOVEFILEOPERATION_H #define SIMPLEMOVEFILEOPERATION_H #include "qinstallerglobal.h" #include <QtCore/QObject> namespace QInstaller { class INSTALLER_EXPORT SimpleMoveFileOperation : public QObject, public Operation { Q_OBJECT public: explicit SimpleMoveFileOperation(PackageManagerCore *core); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); Q_SIGNALS: void outputTextChanged(const QString &progress); }; } #endif //SIMPLEMOVEFILEOPERATION_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/sysinfo_win.cpp�������������������������������������0100777�0000000�0000000�00000015562�13761647206�021701� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "sysinfo.h" #include "link.h" #ifdef Q_CC_MINGW # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0501 # endif #endif #include <qt_windows.h> #include <psapi.h> #include <tlhelp32.h> #include <winbase.h> #include <winnetwk.h> #ifndef Q_CC_MINGW #pragma comment(lib, "mpr.lib") #endif #include <QDebug> #include <QDir> #include <QLibrary> namespace KDUpdater { VolumeInfo updateVolumeSizeInformation(const VolumeInfo &info) { ULARGE_INTEGER bytesTotal; ULARGE_INTEGER freeBytesPerUser; VolumeInfo update = info; if (GetDiskFreeSpaceExA(qPrintable(info.volumeDescriptor()), &freeBytesPerUser, &bytesTotal, nullptr)) { update.setSize(bytesTotal.QuadPart); update.setAvailableSize(freeBytesPerUser.QuadPart); } return update; } /*! Returns a list of volume info objects that are mounted as network drive shares. */ QList<VolumeInfo> networkVolumeInfosFromMountPoints() { QList<VolumeInfo> volumes; QFileInfoList drives = QDir::drives(); foreach (const QFileInfo &drive, drives) { const QString driveLetter = QDir::toNativeSeparators(drive.canonicalPath()); const uint driveType = GetDriveTypeA(qPrintable(driveLetter)); switch (driveType) { case DRIVE_REMOTE: { char buffer[1024] = ""; DWORD bufferLength = 1024; UNIVERSAL_NAME_INFOA *universalNameInfo = (UNIVERSAL_NAME_INFOA*) &buffer; if (WNetGetUniversalNameA(qPrintable(driveLetter), UNIVERSAL_NAME_INFO_LEVEL, LPVOID(universalNameInfo), &bufferLength) == NO_ERROR) { VolumeInfo info; info.setMountPath(driveLetter); info.setVolumeDescriptor(QLatin1String(universalNameInfo->lpUniversalName)); volumes.append(info); } } break; default: break; } } return volumes; } /*! Returns a list of volume info objects based on the given \a volumeGUID. The function also solves mounted volume folder paths. It does not return any network drive shares. */ QList<VolumeInfo> localVolumeInfosFromMountPoints(PTCHAR volumeGUID) { #ifndef UNICODE #define fromWCharArray fromLatin1 #endif QList<VolumeInfo> volumes; DWORD bufferSize; TCHAR volumeNames[MAX_PATH + 1] = { 0 }; if (GetVolumePathNamesForVolumeName(volumeGUID, volumeNames, MAX_PATH, &bufferSize)) { QStringList mountedPaths = QString::fromWCharArray(volumeNames, bufferSize).split(QLatin1Char(char(0)), QString::SkipEmptyParts); foreach (const QString &mountedPath, mountedPaths) { VolumeInfo info; info.setMountPath(mountedPath); info.setVolumeDescriptor(QString::fromWCharArray(volumeGUID)); volumes.append(info); } } return volumes; #ifndef UNICODE #undef fromWCharArray #endif } QList<VolumeInfo> mountedVolumes() { // suppress message box shown while accessing possible unmounted devices const UINT old = SetErrorMode(SEM_FAILCRITICALERRORS); QList<VolumeInfo> tmp; TCHAR volumeGUID[MAX_PATH + 1] = { 0 }; HANDLE handle = FindFirstVolume(volumeGUID, MAX_PATH); if (handle != INVALID_HANDLE_VALUE) { tmp += localVolumeInfosFromMountPoints(volumeGUID); while (FindNextVolume(handle, volumeGUID, MAX_PATH)) { tmp += localVolumeInfosFromMountPoints(volumeGUID); } FindVolumeClose(handle); } tmp += networkVolumeInfosFromMountPoints(); QList<VolumeInfo> volumes; while (!tmp.isEmpty()) // update volume size information volumes.append(updateVolumeSizeInformation(tmp.takeFirst())); SetErrorMode(old); // reset error mode return volumes; } bool pathIsOnLocalDevice(const QString &path) { if (!QFileInfo(path).exists()) return false; if (path.startsWith(QLatin1String("\\\\"))) return false; QDir dir(path); do { if (QFileInfo(dir, QString()).isSymLink()) { QString currentPath = QFileInfo(dir, QString()).absoluteFilePath(); return pathIsOnLocalDevice(Link(currentPath).targetPath()); } } while (dir.cdUp()); const UINT DRIVE_REMOTE_TYPE = 4; if (path.contains(QLatin1Char(':'))) { const QLatin1Char nullTermination('\0'); // for example "c:\" const QString driveSearchString = path.left(3) + nullTermination; WCHAR wCharDriveSearchArray[4]; driveSearchString.toWCharArray(wCharDriveSearchArray); UINT type = GetDriveType(wCharDriveSearchArray); if (type == DRIVE_REMOTE_TYPE) return false; } return true; } bool CALLBACK TerminateAppEnum(HWND hwnd, LPARAM lParam) { DWORD dwID; GetWindowThreadProcessId(hwnd, &dwID); if (dwID == (DWORD)lParam) PostMessage(hwnd, WM_CLOSE, 0, 0); return true; } bool killProcess(const ProcessInfo &process, int msecs) { DWORD dwTimeout = msecs; if (msecs == -1) dwTimeout = INFINITE; // If we can't open the process with PROCESS_TERMINATE rights, then we give up immediately. HANDLE hProc = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, false, process.id); if (hProc == nullptr) return false; // TerminateAppEnum() posts WM_CLOSE to all windows whose PID matches your process's. EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM)process.id); // Wait on the handle. If it signals, great. If it times out, then kill it. bool returnValue = false; if (WaitForSingleObject(hProc, dwTimeout) != WAIT_OBJECT_0) returnValue = TerminateProcess(hProc, 0); CloseHandle(hProc); return returnValue; } } ����������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/systeminfo.cpp��������������������������������������0100777�0000000�0000000�00000011615�13761647206�021525� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "systeminfo.h" #include <QSysInfo> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::SystemInfo \brief Provides information about the operating system. */ /*! Creates a system info object with the parent \a parent. */ SystemInfo::SystemInfo(QObject *parent) : QObject(parent) { } /*! \property SystemInfo::currentCpuArchitecture The architecture of the CPU that the application is running on, in text format. Possible values include: \list \li "i386" \li "x86_64" \endlist \note This function depends on what the OS will report and may not detect the actual CPU architecture if the OS hides that information or is unable to provide it. For example, a 32-bit OS running on a 64-bit CPU is usually unable to determine whether the CPU is actually capable of running 64-bit programs. \sa QSysInfo::currentCpuArchitecture() */ QString SystemInfo::currentCpuArchitecture() const { return QSysInfo::currentCpuArchitecture(); } /*! \property SystemInfo::kernelType The type of the operating system kernel the installer was compiled for. It is also the kernel the installer is running on, unless the host operating system is running a form of compatibility or virtualization layer. For Windows, Linux, and macOS this will return: \list \li "winnt" \li "linux" \li "darwin" \endlist On Unix systems, it returns the same as the output of \c {uname -s} (lowercased). \sa QSysInfo::kernelType() */ QString SystemInfo::kernelType() const { return QSysInfo::kernelType(); } /*! \property SystemInfo::kernelVersion The release version of the operating system kernel. On Windows, it returns the version of the NT or CE kernel. On Unix systems, including macOS, it returns the same as the \c {uname -r} command would return. Example values are: \list \li "6.1.7601" for Windows 7 with Service Pack 1 \li "3.16.6-2-desktop" for openSUSE 13.2 kernel 3.16.6-2 \li "12.5.0" last release of OS X "Mountain Lion" \endlist \sa QSysInfo::kernelVersion() */ QString SystemInfo::kernelVersion() const { return QSysInfo::kernelVersion(); } /*! \property SystemInfo::productType The product name of the operating system this application is running in. Example values are: \list \li "windows" \li "opensuse" (for the Linux openSUSE distribution) \li "osx" \endlist \sa QSysInfo::productType() */ QString SystemInfo::productType() const { return QSysInfo::productType(); } /*! \property SystemInfo::productVersion The product version of the operating system in string form. If the version could not be determined, this function returns "unknown". Example values are: \list \li "7" for Windows 7 \li "13.2" for openSUSE 13.2 \li "10.8" for OS X Mountain Lion \endlist \sa QSysInfo::productVersion() */ QString SystemInfo::productVersion() const { return QSysInfo::productVersion(); } /*! \property SystemInfo::prettyProductName A prettier form of SystemInfo::productType and SystemInfo::productVersion, containing other tokens like the operating system type, codenames and other information. The result of this function is suitable for displaying to the user. Example values are: \list \li "Windows 7" \li "openSUSE 13.2 (Harlequin) (x86_64)" \li "OS X Mountain Lion (10.8)" \endlist \sa QSysInfo::prettyProductName() */ QString SystemInfo::prettyProductName() const { return QSysInfo::prettyProductName(); } } // namespace QInstaller �������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/systeminfo.h����������������������������������������0100777�0000000�0000000�00000004176�13761647206�021176� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SYSTEMINFO_H #define SYSTEMINFO_H #include <QObject> namespace QInstaller { class SystemInfo : public QObject { Q_OBJECT Q_DISABLE_COPY(SystemInfo) Q_PROPERTY(QString currentCpuArchitecture READ currentCpuArchitecture CONSTANT) Q_PROPERTY(QString kernelType READ kernelType CONSTANT) Q_PROPERTY(QString kernelVersion READ kernelVersion CONSTANT) Q_PROPERTY(QString productType READ productType CONSTANT) Q_PROPERTY(QString productVersion READ productVersion CONSTANT) Q_PROPERTY(QString prettyProductName READ prettyProductName CONSTANT) public: explicit SystemInfo(QObject *parent = 0); QString currentCpuArchitecture() const; QString kernelType() const; QString kernelVersion() const; QString productType() const; QString productVersion() const; QString prettyProductName() const; }; } // namespace QInstaller #endif // SYSTEMINFO_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/testrepository.cpp����������������������������������0100777�0000000�0000000�00000014341�13761647206�022443� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "testrepository.h" #include "packagemanagercore.h" #include "packagemanagerproxyfactory.h" #include "proxycredentialsdialog.h" #include "serverauthenticationdialog.h" #include <QFile> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::TestRepository \internal */ TestRepository::TestRepository(PackageManagerCore *parent) : Job(parent) , m_core(parent) { setAutoDelete(false); setCapabilities(Cancelable); connect(&m_timer, &QTimer::timeout, this, &TestRepository::onTimeout); connect(&m_xmlTask, &QFutureWatcherBase::finished, this, &TestRepository::downloadCompleted); } TestRepository::~TestRepository() { reset(); } Repository TestRepository::repository() const { return m_repository; } void TestRepository::setRepository(const Repository &repository) { reset(); m_repository = repository; } void TestRepository::doStart() { reset(); if (!m_core) { emitFinishedWithError(Job::Canceled, tr("Missing package manager core engine.")); return; // We can't do anything here without core, so avoid tons of !m_core checks. } const QUrl url = m_repository.url(); if (url.isEmpty()) { emitFinishedWithError(QInstaller::InvalidUrl, tr("Empty repository URL.")); return; } QAuthenticator auth; auth.setUser(m_repository.username()); auth.setPassword(m_repository.password()); FileTaskItem item(m_repository.url().toString() + QLatin1String("/Updates.xml?") + QString::number(qrand() * qrand())); item.insert(TaskRole::Authenticator, QVariant::fromValue(auth)); m_timer.start(10000); DownloadFileTask *const xmlTask = new DownloadFileTask(item); if (m_core) xmlTask->setProxyFactory(m_core->proxyFactory()); m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask)); } void TestRepository::doCancel() { reset(); emitFinishedWithError(Job::Canceled, tr("Download canceled.")); } void TestRepository::onTimeout() { reset(); emitFinishedWithError(Job::Canceled, tr("Timeout while testing repository \"%1\".") .arg(m_repository.displayname())); } void TestRepository::downloadCompleted() { if (error() != Job::NoError) return; try { m_xmlTask.waitForFinished(); m_timer.stop(); QFile file(m_xmlTask.future().results().value(0).target()); if (file.open(QIODevice::ReadOnly)) { QDomDocument doc; QString errorMsg; if (!doc.setContent(&file, &errorMsg)) { emitFinishedWithError(QInstaller::InvalidUpdatesXml, tr("Cannot parse Updates.xml: %1").arg(errorMsg)); } else { emitFinishedWithError(Job::NoError, QString(/*Success*/)); // OPK } } else { emitFinishedWithError(QInstaller::DownloadError, tr("Cannot open Updates.xml for reading: %1").arg(file.errorString())); } } catch (const AuthenticationRequiredException &e) { m_timer.stop(); if (e.type() == AuthenticationRequiredException::Type::Server) { ServerAuthenticationDialog dlg(e.message(), e.taskItem()); if (dlg.exec() == QDialog::Accepted) { m_repository.setUsername(dlg.user()); m_repository.setPassword(dlg.password()); QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); } else { QMetaObject::invokeMethod(this, "doCancel", Qt::QueuedConnection); } return; } else if (e.type() == AuthenticationRequiredException::Type::Proxy) { const QNetworkProxy proxy = e.proxy(); ProxyCredentialsDialog proxyCredentials(proxy); if (proxyCredentials.exec() == QDialog::Accepted) { PackageManagerProxyFactory *factory = m_core->proxyFactory(); factory->setProxyCredentials(proxy, proxyCredentials.userName(), proxyCredentials.password()); m_core->setProxyFactory(factory); } QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); return; } else { emitFinishedWithError(QInstaller::DownloadError, tr("Authentication failed.")); } } catch (const TaskException &e) { m_timer.stop(); emitFinishedWithError(QInstaller::DownloadError, e.message()); } catch (const QUnhandledException &e) { m_timer.stop(); emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what())); } catch (...) { m_timer.stop(); emitFinishedWithError(QInstaller::DownloadError, tr("Unknown error while testing repository \"%1\".").arg(m_repository.displayname())); } } // -- private void TestRepository::reset() { m_timer.stop(); setError(NoError); setErrorString(QString()); try { if (m_xmlTask.isRunning()) m_xmlTask.cancel(); } catch (...) {} } } // namespace QInstaller �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/testrepository.h������������������������������������0100777�0000000�0000000�00000004063�13761647206�022110� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef TESTREPOSITORY_H #define TESTREPOSITORY_H #include "downloadfiletask.h" #include "job.h" #include "repository.h" #include <QFutureWatcher> #include <QTimer> namespace QInstaller { class PackageManagerCore; class INSTALLER_EXPORT TestRepository : public Job { Q_OBJECT Q_DISABLE_COPY(TestRepository) public: explicit TestRepository(PackageManagerCore *parent = 0); ~TestRepository(); Repository repository() const; void setRepository(const Repository &repository); private slots: void doStart(); void doCancel(); void onTimeout(); void downloadCompleted(); private: void reset(); private: PackageManagerCore *m_core; QTimer m_timer; Repository m_repository; QFutureWatcher<FileTaskResult> m_xmlTask; }; } // namespace QInstaller #endif // TESTREPOSITORY_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/uninstallercalculator.cpp���������������������������0100777�0000000�0000000�00000011572�13761647206�023741� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "uninstallercalculator.h" #include "component.h" #include "packagemanagercore.h" #include "globals.h" #include <QDebug> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::UninstallerCalculator \internal */ UninstallerCalculator::UninstallerCalculator(const QList<Component *> &installedComponents) : m_installedComponents(installedComponents) { } QSet<Component *> UninstallerCalculator::componentsToUninstall() const { return m_componentsToUninstall; } void UninstallerCalculator::appendComponentToUninstall(Component *component) { if (!component) return; if (!component->isInstalled()) return; PackageManagerCore *core = component->packageManagerCore(); // remove all already resolved dependees QSet<Component *> dependees = core->dependees(component).toSet() .subtract(m_componentsToUninstall); foreach (Component *dependee, dependees) appendComponentToUninstall(dependee); m_componentsToUninstall.insert(component); } void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components) { foreach (Component *component, components) appendComponentToUninstall(component); QList<Component*> autoDependOnList; // All regular dependees are resolved. Now we are looking for auto depend on components. foreach (Component *component, m_installedComponents) { // If a components is installed and not yet scheduled for un-installation, check for auto depend. if (component->isInstalled() && !m_componentsToUninstall.contains(component)) { QStringList autoDependencies = PackageManagerCore::parseNames(component->autoDependencies()); if (autoDependencies.isEmpty()) continue; // This code needs to be enabled once the scripts use isInstalled, installationRequested and // uninstallationRequested... if (autoDependencies.first().compare(scScript, Qt::CaseInsensitive) == 0) { //QScriptValue valueFromScript; //try { // valueFromScript = callScriptMethod(QLatin1String("isAutoDependOn")); //} catch (const Error &error) { // // keep the component, should do no harm // continue; //} //if (valueFromScript.isValid() && !valueFromScript.toBool()) // autoDependOnList.append(component); continue; } foreach (Component *c, m_installedComponents) { const QString replaces = c->value(scReplaces); const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(), QString::SkipEmptyParts) << c->name(); foreach (const QString &possibleName, possibleNames) { Component *cc = PackageManagerCore::componentByName(possibleName, m_installedComponents); if (cc && (cc->installAction() != ComponentModelHelper::AutodependUninstallation)) { autoDependencies.removeAll(possibleName); } } } // A component requested auto uninstallation, keep it to resolve their dependencies as well. if (!autoDependencies.isEmpty()) { autoDependOnList.append(component); component->setInstallAction(ComponentModelHelper::AutodependUninstallation); } } } if (!autoDependOnList.isEmpty()) appendComponentsToUninstall(autoDependOnList); } } // namespace QInstaller ��������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/uninstallercalculator.h�����������������������������0100777�0000000�0000000�00000003615�13761647206�023405� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef UNINSTALLERCALCULATOR_H #define UNINSTALLERCALCULATOR_H #include "installer_global.h" #include <QHash> #include <QList> #include <QSet> #include <QString> namespace QInstaller { class Component; class INSTALLER_EXPORT UninstallerCalculator { public: UninstallerCalculator(const QList<Component *> &installedComponents); QSet<Component*> componentsToUninstall() const; void appendComponentsToUninstall(const QList<Component*> &components); private: void appendComponentToUninstall(Component *component); QList<Component *> m_installedComponents; QSet<Component *> m_componentsToUninstall; }; } #endif // UNINSTALLERCALCULATOR_H �������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/unziptask.cpp���������������������������������������0100777�0000000�0000000�00000021411�13761647206�021350� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "unziptask.h" #include "lib7z_facade.h" #ifdef Q_OS_UNIX # include "StdAfx.h" #endif #include "Common/ComTry.h" // TODO: include once we switch from lib7z_fascade.h //#include "Common/MyInitGuid.h" #include "7zip/Archive/IArchive.h" #include "7zip/Common/FileStreams.h" #include "7zip/UI/Common/OpenArchive.h" #include "Windows/FileDir.h" #include "Windows/PropVariant.h" #include <QDir> namespace QInstaller { /*! \inmodule QtInstallerFramework \class QInstaller::UnzipTask \internal */ class ArchiveExtractCallback : public IArchiveExtractCallback, public CMyUnknownImp { public: MY_UNKNOWN_IMP ArchiveExtractCallback(const QString &target, const CArc &arc, QFutureInterface<QString> &fi) : m_target(target) , m_arc(arc) { m_futureInterface = &fi; } // -- IProgress STDMETHOD(SetTotal)(UInt64 total) { COM_TRY_BEGIN m_totalUnpacked = 0; m_totalUnpackedExpected = total; return S_OK; COM_TRY_END } STDMETHOD(SetCompleted)(const UInt64 *completeValue) { COM_TRY_BEGIN Q_UNUSED(completeValue) return S_OK; // return S_OK here as we do not support sub archive extracting COM_TRY_END } // -- IArchiveExtractCallback STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) { if (m_futureInterface->isCanceled()) return E_FAIL; if (m_futureInterface->isPaused()) m_futureInterface->waitForResume(); COM_TRY_BEGIN *outStream = nullptr; m_currentIndex = index; if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) return E_FAIL; bool isDir = false; if (Archive_IsItem_Folder(m_arc.Archive, m_currentIndex, isDir) != S_OK) return E_FAIL; bool isEncrypted = false; if (Archive_GetItemBoolProp(m_arc.Archive, m_currentIndex, kpidEncrypted, isEncrypted) != S_OK) return E_FAIL; if (isDir || isEncrypted) return E_FAIL; UString itemPath; if (m_arc.GetItemPath(m_currentIndex, itemPath) != S_OK) return E_FAIL; QDir().mkpath(m_target); m_currentTarget = m_target + QLatin1Char('/') + QString::fromStdWString((const wchar_t*)(itemPath)) .replace(QLatin1Char('\\'), QLatin1Char('/')); m_outFileStream = new COutFileStream; CMyComPtr<ISequentialOutStream> scopedPointer(m_outFileStream); if (!m_outFileStream->Open((wchar_t*)(m_currentTarget.utf16()), CREATE_ALWAYS)) return E_FAIL; m_outFileStreamComPtr = scopedPointer; *outStream = scopedPointer.Detach(); return S_OK; COM_TRY_END } STDMETHOD(PrepareOperation)(Int32 askExtractMode) { COM_TRY_BEGIN Q_UNUSED(askExtractMode) m_futureInterface->setProgressValueAndText(0, QLatin1String("Started to extract archive.")); return S_OK; // return S_OK here as we do not need to prepare anything COM_TRY_END } STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) { COM_TRY_BEGIN switch (resultEOperationResult) { case NArchive::NExtract::NOperationResult::kOK: break; default: // fall through and bail case NArchive::NExtract::NOperationResult::kCRCError: case NArchive::NExtract::NOperationResult::kDataError: case NArchive::NExtract::NOperationResult::kUnsupportedMethod: m_outFileStream->Close(); m_outFileStreamComPtr.Release(); return E_FAIL; } UInt32 attributes; if (GetAttributes(&attributes)) NWindows::NFile::NDir::SetFileAttrib((wchar_t*)(m_currentTarget.utf16()), attributes); FILETIME accessTime, creationTime, modificationTime; const bool writeAccessTime = GetTime(kpidATime, &accessTime); const bool writeCreationTime = GetTime(kpidCTime, &creationTime); const bool writeModificationTime = GetTime(kpidMTime, &modificationTime); m_outFileStream->SetTime((writeCreationTime ? &creationTime : nullptr), (writeAccessTime ? &accessTime : nullptr), (writeModificationTime ? &modificationTime : nullptr)); m_totalUnpacked += m_outFileStream->ProcessedSize; m_outFileStream->Close(); m_outFileStreamComPtr.Release(); m_futureInterface->reportResult(m_currentTarget); m_futureInterface->setProgressValueAndText(100 * m_totalUnpacked / m_totalUnpackedExpected, m_currentTarget); return S_OK; COM_TRY_END } private: bool GetAttributes(UInt32 *attributes) const { *attributes = 0; NWindows::NCOM::CPropVariant property; if (m_arc.Archive->GetProperty(m_currentIndex, kpidAttrib, &property) != S_OK) return false; if (property.vt != VT_UI4) return false; *attributes = property.ulVal; return (property.vt == VT_UI4); } bool GetTime(PROPID propertyId, FILETIME *filetime) const { if (!filetime) return false; filetime->dwLowDateTime = 0; filetime->dwHighDateTime = 0; NWindows::NCOM::CPropVariant property; if (m_arc.Archive->GetProperty(m_currentIndex, propertyId, &property) != S_OK) return false; if (property.vt != VT_FILETIME) return false; *filetime = property.filetime; return (filetime->dwHighDateTime != 0 || filetime->dwLowDateTime != 0); } private: QString m_target; const CArc &m_arc; QFutureInterface<QString> *m_futureInterface; UInt32 m_currentIndex; QString m_currentTarget; UInt64 m_totalUnpacked; UInt64 m_totalUnpackedExpected; COutFileStream *m_outFileStream; CMyComPtr<ISequentialOutStream> m_outFileStreamComPtr; }; // -- UnzipTask UnzipTask::UnzipTask(const QString &source, const QString &target) : m_source(source) , m_target(target) { Lib7z::initSevenZ(); } void UnzipTask::doTask(QFutureInterface<QString> &fi) { fi.reportStarted(); CCodecs codecs; if (codecs.Load() != S_OK) return; COpenOptions op; op.codecs = &codecs; CObjectVector<COpenType> types; op.types = &types; // Empty, because we use a stream. CIntVector excluded; op.excludedFormats = &excluded; const CMyComPtr<CInFileStream> fileStream = new CInFileStream; fileStream->Open((wchar_t*) (m_source.utf16())); op.stream = fileStream; // CMyComPtr is needed, otherwise it crashes in OpenStream(). CObjectVector<CProperty> properties; op.props = &properties; CArchiveLink archiveLink; if (archiveLink.Open2(op, nullptr) != S_OK) return; UINT32 count = 0; for (unsigned i = 0; i < archiveLink.Arcs.Size(); ++i) { const CArc& arc = archiveLink.Arcs[i]; UInt32 numItems = 0; if (arc.Archive->GetNumberOfItems(&numItems) != S_OK) break; count += numItems; } fi.setExpectedResultCount(count); for (unsigned i = 0; i < archiveLink.Arcs.Size(); ++i) { if (fi.isCanceled()) break; if (fi.isPaused()) fi.waitForResume(); const UInt32 extractAll = UInt32(-1); const CArc &arc = archiveLink.Arcs[i]; arc.Archive->Extract(0, extractAll, NArchive::NExtract::NAskMode::kExtract, new ArchiveExtractCallback(m_target, arc, fi)); } fi.reportFinished(); } } // namespace QInstaller �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/unziptask.h�����������������������������������������0100777�0000000�0000000�00000003447�13761647206�021026� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef UNZIPTASK_H #define UNZIPTASK_H #include "abstracttask.h" #include "installer_global.h" namespace QInstaller { class INSTALLER_EXPORT UnzipTask : public AbstractTask<QString> { public: UnzipTask() {} UnzipTask(const QString &source, const QString &target); void doTask(QFutureInterface<QString> &fi); private: void setBytesToExtract(qint64 bytes); void addBytesExtracted(qint64 bytes); private: QString m_source; QString m_target; friend class ArchiveExtractCallback; }; } // namespace QInstaller #endif // UNZIPTASK_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/utils.cpp�������������������������������������������0100777�0000000�0000000�00000036556�13761647206�020500� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "utils.h" #include "fileutils.h" #include <QCoreApplication> #include <QDateTime> #include <QDir> #include <QProcessEnvironment> #include <QThread> #include <QVector> #if defined(Q_OS_WIN) || defined(Q_OS_WINCE) # include "qt_windows.h" #endif #include <fstream> #include <iostream> #include <sstream> #ifdef Q_OS_UNIX #include <errno.h> #include <signal.h> #include <time.h> #endif /*! \inmodule QtInstallerFramework \class QInstaller::PlainVerboseWriterOutput \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::VerboseWriterOutput \internal */ /*! \inmodule QtInstallerFramework \class QInstaller::VerboseWriter \internal */ /*! \internal */ void QInstaller::uiDetachedWait(int ms) { QTime timer; timer.start(); do { QCoreApplication::processEvents(QEventLoop::AllEvents, ms); QThread::msleep(10UL); } while (timer.elapsed() < ms); } /*! Starts the program \a program with the arguments \a arguments in a new process, and detaches from it. Returns true on success; otherwise returns false. If the calling process exits, the detached process will continue to live. Note that arguments that contain spaces are not passed to the process as separate arguments. Unix: The started process will run in its own session and act like a daemon. Windows: Arguments that contain spaces are wrapped in quotes. The started process will run as a regular standalone process. The process will be started in the directory \a workingDirectory. If the function is successful then \a pid is set to the process identifier of the started process. Additional note: The difference in using this function over its equivalent from QProcess appears on Windows. While this function will truly detach and not show a GUI window for the started process, the QProcess version will. */ bool QInstaller::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) { bool success = false; #ifdef Q_OS_WIN PROCESS_INFORMATION pinfo; STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), nullptr, nullptr, nullptr, static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT), 0, 0, 0, STARTF_USESHOWWINDOW, SW_HIDE, 0, nullptr, nullptr, nullptr, nullptr }; // That's the difference over QProcess::startDetached(): STARTF_USESHOWWINDOW, SW_HIDE. const QString commandline = QInstaller::createCommandline(program, arguments); if (CreateProcessW(nullptr, (wchar_t*) commandline.utf16(), nullptr, nullptr, false, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, nullptr, workingDirectory.isEmpty() ? nullptr : (wchar_t*) workingDirectory.utf16(), &startupInfo, &pinfo)) { success = true; CloseHandle(pinfo.hThread); CloseHandle(pinfo.hProcess); if (pid) *pid = pinfo.dwProcessId; } #else success = QProcess::startDetached(program, arguments, workingDirectory, pid); #endif return success; } /*! \internal Returns ["en-us", "en"] for "en-us". */ QStringList QInstaller::localeCandidates(const QString &locale_) { QStringList candidates; QString locale = locale_; candidates.reserve(locale.count(QLatin1Char('-'))); forever { candidates.append(locale); int r = locale.lastIndexOf(QLatin1Char('-')); if (r <= 0) break; locale.truncate(r); } return candidates; } static uint verbLevel = 0; /*! Sets to verbose output if \a v is set to \c true. Calling this multiple times increases or decreases the verbosity level accordingly. */ void QInstaller::setVerbose(bool v) { if (v) verbLevel++; else if (verbLevel > 0) verbLevel--; } /*! Returns \c true if the installer is set to verbose output. */ bool QInstaller::isVerbose() { return verbLevel > 0 ? true : false; } /*! Returns the current verbosity level. */ uint QInstaller::verboseLevel() { return verbLevel; } /*! Returns a list of mutually exclusive options passed to the \a parser, if there is at least one mutually exclusive pair of options set. Otherwise returns an empty \c QStringList. The options considered mutual are provided with \a options. */ QStringList QInstaller::checkMutualOptions(CommandLineParser &parser, const QStringList &options) { QStringList mutual; foreach (const QString &option, options) { if (parser.isSet(option)) mutual << option; } return mutual.count() > 1 ? mutual : QStringList(); } /*! \internal */ std::ostream &QInstaller::operator<<(std::ostream &os, const QString &string) { return os << qPrintable(string); } /*! \internal */ QByteArray QInstaller::calculateHash(QIODevice *device, QCryptographicHash::Algorithm algo) { Q_ASSERT(device); QCryptographicHash hash(algo); static QByteArray buffer(1024 * 1024, '\0'); while (true) { const qint64 numRead = device->read(buffer.data(), buffer.size()); if (numRead <= 0) return hash.result(); hash.addData(buffer.constData(), numRead); } return QByteArray(); // never reached } /*! \internal */ QByteArray QInstaller::calculateHash(const QString &path, QCryptographicHash::Algorithm algo) { QFile file(path); if (!file.open(QIODevice::ReadOnly)) return QByteArray(); return calculateHash(&file, algo); } /*! \internal */ QString QInstaller::replaceVariables(const QHash<QString, QString> &vars, const QString &str) { QString res; int pos = 0; while (true) { int pos1 = str.indexOf(QLatin1Char('@'), pos); if (pos1 == -1) break; int pos2 = str.indexOf(QLatin1Char('@'), pos1 + 1); if (pos2 == -1) break; res += str.mid(pos, pos1 - pos); QString name = str.mid(pos1 + 1, pos2 - pos1 - 1); res += vars.value(name); pos = pos2 + 1; } res += str.mid(pos); return res; } /*! \internal */ QString QInstaller::replaceWindowsEnvironmentVariables(const QString &str) { const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString res; int pos = 0; while (true) { int pos1 = str.indexOf(QLatin1Char( '%'), pos); if (pos1 == -1) break; int pos2 = str.indexOf(QLatin1Char( '%'), pos1 + 1); if (pos2 == -1) break; res += str.mid(pos, pos1 - pos); QString name = str.mid(pos1 + 1, pos2 - pos1 - 1); res += env.value(name); pos = pos2 + 1; } res += str.mid(pos); return res; } QInstaller::VerboseWriter::VerboseWriter() { preFileBuffer.open(QIODevice::ReadWrite); stream.setDevice(&preFileBuffer); currentDateTimeAsString = QDateTime::currentDateTime().toString(); } QInstaller::VerboseWriter::~VerboseWriter() { if (preFileBuffer.isOpen()) { PlainVerboseWriterOutput output; (void)flush(&output); } } bool QInstaller::VerboseWriter::flush(VerboseWriterOutput *output) { stream.flush(); if (logFileName.isEmpty()) // binarycreator return true; if (!preFileBuffer.isOpen()) return true; //if the installer installed nothing - there is no target directory - where the logfile can be saved if (!QFileInfo(logFileName).absoluteDir().exists()) return true; QString logInfo; logInfo += QLatin1String("************************************* Invoked: "); logInfo += currentDateTimeAsString; logInfo += QLatin1String("\n"); QBuffer buffer; buffer.open(QIODevice::WriteOnly); buffer.write(logInfo.toLocal8Bit()); buffer.write(preFileBuffer.data()); buffer.close(); if (output->write(logFileName, QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text, buffer.data())) { preFileBuffer.close(); stream.setDevice(nullptr); return true; } return false; } void QInstaller::VerboseWriter::setFileName(const QString &fileName) { logFileName = fileName; } Q_GLOBAL_STATIC(QInstaller::VerboseWriter, verboseWriter) QInstaller::VerboseWriter *QInstaller::VerboseWriter::instance() { return verboseWriter(); } void QInstaller::VerboseWriter::appendLine(const QString &msg) { stream << msg << endl; } QInstaller::VerboseWriterOutput::~VerboseWriterOutput() { } bool QInstaller::PlainVerboseWriterOutput::write(const QString &fileName, QIODevice::OpenMode openMode, const QByteArray &data) { QFile output(fileName); if (output.open(openMode)) { output.write(data); setDefaultFilePermissions(&output, DefaultFilePermissions::NonExecutable); return true; } return false; } #ifdef Q_OS_WIN // taken from qcoreapplication_p.h template<typename Char> static QVector<Char*> qWinCmdLine(Char *cmdParam, int length, int &argc) { QVector<Char*> argv(8); Char *p = cmdParam; Char *p_end = p + length; argc = 0; while (*p && p < p_end) { // parse cmd line arguments while (QChar((short)(*p)).isSpace()) // skip white space p++; if (*p && p < p_end) { // arg starts int quote; Char *start, *r; if (*p == Char('\"') || *p == Char('\'')) { // " or ' quote quote = *p; start = ++p; } else { quote = 0; start = p; } r = start; while (*p && p < p_end) { if (quote) { if (*p == quote) { p++; if (QChar((short)(*p)).isSpace()) break; quote = 0; } } if (*p == '\\') { // escape char? p++; if (*p == Char('\"') || *p == Char('\'')) ; // yes else p--; // treat \ literally } else { if (!quote && (*p == Char('\"') || *p == Char('\''))) { // " or ' quote quote = *p++; continue; } else if (QChar((short)(*p)).isSpace() && !quote) break; } if (*p) *r++ = *p++; } if (*p && p < p_end) p++; *r = Char('\0'); if (argc >= (int)argv.size()-1) // expand array argv.resize(argv.size()*2); argv[argc++] = start; } } argv[argc] = nullptr; return argv; } /*! \internal */ QStringList QInstaller::parseCommandLineArgs(int argc, char **argv) { Q_UNUSED(argc) Q_UNUSED(argv) QStringList arguments; QString cmdLine = QString::fromWCharArray(GetCommandLine()); QVector<wchar_t*> args = qWinCmdLine<wchar_t>((wchar_t *)cmdLine.utf16(), cmdLine.length(), argc); for (int a = 0; a < argc; ++a) arguments << QString::fromWCharArray(args[a]); return arguments; } #else QStringList QInstaller::parseCommandLineArgs(int argc, char **argv) { QStringList arguments; for (int a = 0; a < argc; ++a) arguments << QString::fromLocal8Bit(argv[a]); return arguments; } #endif #ifdef Q_OS_WIN // taken from qprocess_win.cpp static QString qt_create_commandline(const QString &program, const QStringList &arguments) { QString args; if (!program.isEmpty()) { QString programName = program; if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' '))) { programName = QLatin1Char('\"') + programName + QLatin1Char('\"'); } programName.replace(QLatin1Char('/'), QLatin1Char('\\')); // add the program as the first arg ... it works better args = programName + QLatin1Char(' '); } for (int i = 0; i < arguments.size(); ++i) { QString tmp = arguments.at(i); // in the case of \" already being in the string the \ must also be escaped tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\"")); // escape a single " because the arguments will be parsed tmp.replace(QLatin1Char('\"'), QLatin1String("\\\"")); if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { // The argument must not end with a \ since this would be interpreted // as escaping the quote -- rather put the \ behind the quote: e.g. // rather use "foo"\ than "foo\" QString endQuote(QLatin1Char('\"')); int i = tmp.length(); while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) { --i; endQuote += QLatin1Char('\\'); } args += QLatin1String(" \"") + tmp.left(i) + endQuote; } else { args += QLatin1Char(' ') + tmp; } } return args; } /*! \internal */ QString QInstaller::createCommandline(const QString &program, const QStringList &arguments) { return qt_create_commandline(program, arguments); } /*! \internal Copied from qsystemerror.cpp in Qt. */ QString QInstaller::windowsErrorString(int errorCode) { QString ret; wchar_t *string = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &string, 0, nullptr); ret = QString::fromWCharArray(string); LocalFree((HLOCAL) string); if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND) ret = QCoreApplication::translate("QInstaller", "The specified module could not be found."); ret.append(QLatin1String(" (0x")); ret.append(QString::number(uint(errorCode), 16).rightJustified(8, QLatin1Char('0'))); ret.append(QLatin1String(")")); return ret; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/installer/utils.h���������������������������������������������0100777�0000000�0000000�00000007305�13761647206�020133� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_UTILS_H #define QINSTALLER_UTILS_H #include "installer_global.h" #include "commandlineparser.h" #include <QtCore/QBuffer> #include <QtCore/QCryptographicHash> #include <QtCore/QHash> #include <QtCore/QUrl> #include <QtCore/QTextStream> #include <ostream> QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE namespace QInstaller { void INSTALLER_EXPORT uiDetachedWait(int ms); bool INSTALLER_EXPORT startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid = 0); QByteArray INSTALLER_EXPORT calculateHash(QIODevice *device, QCryptographicHash::Algorithm algo); QByteArray INSTALLER_EXPORT calculateHash(const QString &path, QCryptographicHash::Algorithm algo); QString INSTALLER_EXPORT replaceVariables(const QHash<QString,QString> &vars, const QString &str); QString INSTALLER_EXPORT replaceWindowsEnvironmentVariables(const QString &str); QStringList INSTALLER_EXPORT parseCommandLineArgs(int argc, char **argv); #ifdef Q_OS_WIN QString windowsErrorString(int errorCode); QString createCommandline(const QString &program, const QStringList &arguments); #endif QStringList INSTALLER_EXPORT localeCandidates(const QString &locale); void INSTALLER_EXPORT setVerbose(bool v); bool INSTALLER_EXPORT isVerbose(); uint INSTALLER_EXPORT verboseLevel(); QStringList INSTALLER_EXPORT checkMutualOptions(CommandLineParser &parser, const QStringList &options); INSTALLER_EXPORT std::ostream& operator<<(std::ostream &os, const QString &string); class INSTALLER_EXPORT VerboseWriterOutput { public: virtual bool write(const QString &fileName, QIODevice::OpenMode openMode, const QByteArray &data) = 0; protected: ~VerboseWriterOutput(); }; class INSTALLER_EXPORT PlainVerboseWriterOutput : public VerboseWriterOutput { public: virtual bool write(const QString &fileName, QIODevice::OpenMode openMode, const QByteArray &data); }; class INSTALLER_EXPORT VerboseWriter { public: VerboseWriter(); ~VerboseWriter(); static VerboseWriter *instance(); bool flush(VerboseWriterOutput *output); void appendLine(const QString &msg); void setFileName(const QString &fileName); private: QTextStream stream; QBuffer preFileBuffer; QString logFileName; QString currentDateTimeAsString; }; } #endif // QINSTALLER_UTILS_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/������������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�016277� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/authenticationdialog.ui�������������������������������0100777�0000000�0000000�00000006205�13761647206�023040� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<ui version="4.0" > <class>Dialog</class> <widget class="QDialog" name="Dialog" > <property name="geometry" > <rect> <x>0</x> <y>0</y> <width>389</width> <height>243</height> </rect> </property> <property name="windowTitle" > <string>Http authentication required</string> </property> <layout class="QGridLayout" > <item row="0" column="0" colspan="2" > <widget class="QLabel" name="label" > <property name="text" > <string>You need to supply a Username and Password to access this site.</string> </property> <property name="wordWrap" > <bool>false</bool> </property> </widget> </item> <item row="2" column="0" > <widget class="QLabel" name="label_2" > <property name="text" > <string>Username:</string> </property> </widget> </item> <item row="2" column="1" > <widget class="QLineEdit" name="userEdit" /> </item> <item row="3" column="0" > <widget class="QLabel" name="label_3" > <property name="text" > <string>Password:</string> </property> </widget> </item> <item row="3" column="1" > <widget class="QLineEdit" name="passwordEdit"> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> <item row="5" column="0" colspan="2" > <widget class="QDialogButtonBox" name="buttonBox" > <property name="orientation" > <enum>Qt::Horizontal</enum> </property> <property name="standardButtons" > <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> <item row="1" column="0" > <widget class="QLabel" name="label_4" > <property name="text" > <string></string> </property> </widget> </item> <item row="1" column="1" > <widget class="QLabel" name="siteDescription" > <property name="font" > <font> <weight>75</weight> <bold>true</bold> </font> </property> <property name="text" > <string>%1 at %2</string> </property> <property name="wordWrap" > <bool>true</bool> </property> </widget> </item> <item row="4" column="0" > <spacer> <property name="orientation" > <enum>Qt::Vertical</enum> </property> <property name="sizeHint" > <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> </layout> </widget> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>accepted()</signal> <receiver>Dialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel" > <x>248</x> <y>254</y> </hint> <hint type="destinationlabel" > <x>157</x> <y>274</y> </hint> </hints> </connection> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>Dialog</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel" > <x>316</x> <y>260</y> </hint> <hint type="destinationlabel" > <x>286</x> <y>274</y> </hint> </hints> </connection> </connections> </ui> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/environment.cpp���������������������������������������0100777�0000000�0000000�00000004542�13761647206�021354� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "environment.h" #include <QHash> #include <QProcess> #include <QProcessEnvironment> using namespace KDUpdater; Environment &Environment::instance() { static Environment s_instance; return s_instance; } QString Environment::value(const QString &key, const QString &defvalue) const { const QHash<QString, QString>::ConstIterator it = m_tempValues.constFind(key); if (it != m_tempValues.constEnd()) return *it; return QProcessEnvironment::systemEnvironment().value(key, defvalue); } void Environment::setTemporaryValue(const QString &key, const QString &value) { m_tempValues.insert(key, value); } QProcessEnvironment Environment::applyTo(const QProcessEnvironment &qpe_) const { QProcessEnvironment qpe(qpe_); QHash<QString, QString>::ConstIterator it = m_tempValues.constBegin(); const QHash<QString, QString>::ConstIterator end = m_tempValues.constEnd(); for ( ; it != end; ++it) qpe.insert(it.key(), it.value()); return qpe; } void Environment::applyTo(QProcess *proc) { proc->setProcessEnvironment(applyTo(proc->processEnvironment())); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/environment.h�����������������������������������������0100777�0000000�0000000�00000003760�13761647206�021022� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef ENVIRONMENT_H #define ENVIRONMENT_H #include "kdtoolsglobal.h" #include <QString> #include <QHash> QT_BEGIN_NAMESPACE class QProcess; class QProcessEnvironment; QT_END_NAMESPACE namespace KDUpdater { class KDTOOLS_EXPORT Environment { public: static Environment &instance(); ~Environment() {} QString value(const QString &key, const QString &defaultValue = QString()) const; void setTemporaryValue(const QString &key, const QString &value); QProcessEnvironment applyTo(const QProcessEnvironment &qpe) const; void applyTo(QProcess *process); private: Environment() {} private: Q_DISABLE_COPY(Environment) QHash<QString, QString> m_tempValues; }; } // namespace KDUpdater #endif // ENVIRONMENT_H ����������������qt-installer-framework-4.0.1/src/libs/kdtools/filedownloader.cpp������������������������������������0100777�0000000�0000000�00000130660�13761647206�022007� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filedownloader_p.h" #include "filedownloaderfactory.h" #include "ui_authenticationdialog.h" #include "fileutils.h" #include <QDialog> #include <QDir> #include <QFile> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkProxyFactory> #include <QPointer> #include <QUrl> #include <QTemporaryFile> #include <QFileInfo> #include <QThreadPool> #include <QDebug> #include <QSslError> #include <QBasicTimer> #include <QTimerEvent> #include <QLoggingCategory> #include <globals.h> #include <QHostInfo> using namespace KDUpdater; using namespace QInstaller; static double calcProgress(qint64 done, qint64 total) { return total ? (double(done) / double(total)) : 0; } // -- KDUpdater::FileDownloader /*! \inmodule kdupdater \class KDUpdater::FileDownloader \brief The FileDownloader class is the base class for file downloaders used in KDUpdater. File downloaders are used by the KDUpdater::Update class to download update files. Each subclass of FileDownloader can download files from a specific category of sources (such as \c local, \c ftp, \c http). This is an internal class, not a part of the public API. Currently we have the following subclasses of FileDownloader: \list \li HttpDownloader to download files over FTP, HTTP, or HTTPS if Qt is built with SSL. \li LocalFileDownloader to copy files from the local file system. \li ResourceFileDownloader to download resource files. \endlist */ /*! \property KDUpdater::FileDownloader::autoRemoveDownloadedFile \brief Whether the downloaded file should be automatically removed after it is downloaded and the class goes out of scope. */ /*! \property KDUpdater::FileDownloader::url \brief The URL to download files from. */ /*! \property KDUpdater::FileDownloader::scheme \brief The scheme to use for downloading files. */ /*! \fn KDUpdater::FileDownloader::authenticatorChanged(const QAuthenticator &authenticator) This signal is emitted when the authenticator changes to \a authenticator. */ /*! \fn KDUpdater::FileDownloader::canDownload() const = 0 Returns \c true if the file exists and is readable. */ /*! \fn KDUpdater::FileDownloader::clone(QObject *parent=0) const = 0 Clones the local file downloader and assigns it the parent \a parent. */ /*! \fn KDUpdater::FileDownloader::downloadCanceled() This signal is emitted if downloading a file is canceled. */ /*! \fn KDUpdater::FileDownloader::downloadedFileName() const = 0 Returns the file name of the downloaded file. */ /*! \fn KDUpdater::FileDownloader::downloadProgress(double progress) This signal is emitted with the current download \a progress. */ /*! \fn KDUpdater::FileDownloader::downloadProgress(qint64 bytesReceived, qint64 bytesToReceive) This signal is emitted with the download progress as the number of received bytes, \a bytesReceived, and the total size of the file to download, \a bytesToReceive. */ /*! \fn KDUpdater::FileDownloader::downloadSpeed(qint64 bytesPerSecond) This signal is emitted with the download speed in bytes per second as \a bytesPerSecond. */ /*! \fn KDUpdater::FileDownloader::downloadStarted() This signal is emitted when downloading a file starts. */ /*! \fn KDUpdater::FileDownloader::downloadStatus(const QString &status) This signal is emitted with textual representation of the current download \a status in the following format: "100 MiB of 150 MiB - (DAYS) (HOURS) (MINUTES) (SECONDS) remaining". */ /*! \fn KDUpdater::FileDownloader::downloadCompleted() This signal is emitted when downloading a file ends. */ /*! \fn KDUpdater::FileDownloader::downloadAborted(const QString &errorMessage) This signal is emitted when downloading a file is aborted with \a errorMessage. */ /*! \fn KDUpdater::FileDownloader::estimatedDownloadTime(int seconds) This signal is emitted with the estimated download time in \a seconds. */ /*! \fn KDUpdater::FileDownloader::isDownloaded() const = 0 Returns \c true if the file is downloaded. */ /*! \fn KDUpdater::FileDownloader::onError() = 0 Closes the destination file if an error occurs during copying and stops the download speed timer. */ /*! \fn KDUpdater::FileDownloader::onSuccess() = 0 Closes the destination file after it has been successfully copied and stops the download speed timer. */ /*! \fn KDUpdater::FileDownloader::setDownloadedFileName(const QString &name) = 0 Sets the file name of the downloaded file to \a name. */ struct KDUpdater::FileDownloader::Private { Private() : m_hash(QCryptographicHash::Sha1) , m_assumedSha1Sum("") , autoRemove(true) , m_speedTimerInterval(100) , m_downloadDeadlineTimerInterval(30000) , m_downloadPaused(false) , m_downloadResumed(false) , m_bytesReceived(0) , m_bytesToReceive(0) , m_bytesBeforeResume(0) , m_totalBytesBeforeResume(0) , m_currentSpeedBin(0) , m_sampleIndex(0) , m_downloadSpeed(0) , m_factory(0) , m_ignoreSslErrors(false) { memset(m_samples, 0, sizeof(m_samples)); } ~Private() { delete m_factory; } QUrl url; QString scheme; QCryptographicHash m_hash; QByteArray m_assumedSha1Sum; QString errorString; bool autoRemove; bool followRedirect; QBasicTimer m_speedIntervalTimer; int m_speedTimerInterval; QBasicTimer m_downloadDeadlineTimer; int m_downloadDeadlineTimerInterval; bool m_downloadPaused; bool m_downloadResumed; qint64 m_bytesReceived; qint64 m_bytesToReceive; qint64 m_bytesBeforeResume; qint64 m_totalBytesBeforeResume; mutable qint64 m_samples[50]; mutable qint64 m_currentSpeedBin; mutable quint32 m_sampleIndex; mutable qint64 m_downloadSpeed; QAuthenticator m_authenticator; FileDownloaderProxyFactory *m_factory; bool m_ignoreSslErrors; }; /*! Creates a file downloader with the scheme \a scheme and parent \a parent. */ KDUpdater::FileDownloader::FileDownloader(const QString &scheme, QObject *parent) : QObject(parent) , d(new Private) { d->scheme = scheme; d->followRedirect = false; } /*! Destroys the file downloader. */ KDUpdater::FileDownloader::~FileDownloader() { delete d; } void KDUpdater::FileDownloader::setUrl(const QUrl &url) { d->url = url; } QUrl KDUpdater::FileDownloader::url() const { return d->url; } /*! Returns the SHA-1 checksum of the downloaded file. */ QByteArray KDUpdater::FileDownloader::sha1Sum() const { return d->m_hash.result(); } /*! Returns the assumed SHA-1 checksum of the file to download. */ QByteArray KDUpdater::FileDownloader::assumedSha1Sum() const { return d->m_assumedSha1Sum; } /*! Sets the assumed SHA-1 checksum of the file to download to \a sum. */ void KDUpdater::FileDownloader::setAssumedSha1Sum(const QByteArray &sum) { d->m_assumedSha1Sum = sum; } /*! Returns an error message. */ QString FileDownloader::errorString() const { return d->errorString; } /*! Sets the human readable description of the last error that occurred to \a error. Emits the downloadStatus() and downloadAborted() signals. */ void FileDownloader::setDownloadAborted(const QString &error) { d->errorString = error; emit downloadStatus(error); emit downloadAborted(error); } /*! Sets the download status to \c completed and displays a status message. If an assumed SHA-1 checksum is set and the actual calculated checksum does not match it, sets the status to \c error. If no SHA-1 is assumed, no check is performed, and status is set to \c success. Emits the downloadCompleted() and downloadStatus() signals on success. */ void KDUpdater::FileDownloader::setDownloadCompleted() { if (d->m_assumedSha1Sum.isEmpty() || (d->m_assumedSha1Sum == sha1Sum())) { onSuccess(); emit downloadCompleted(); emit downloadStatus(tr("Download finished.")); } else { onError(); setDownloadAborted(tr("Cryptographic hashes do not match.")); } } /*! Emits the downloadCanceled() and downloadStatus() signals. */ void KDUpdater::FileDownloader::setDownloadCanceled() { emit downloadCanceled(); emit downloadStatus(tr("Download canceled.")); } QString KDUpdater::FileDownloader::scheme() const { return d->scheme; } void KDUpdater::FileDownloader::setScheme(const QString &scheme) { d->scheme = scheme; } void KDUpdater::FileDownloader::setAutoRemoveDownloadedFile(bool val) { d->autoRemove = val; } /*! Determines that redirects should be followed if \a val is \c true. */ void KDUpdater::FileDownloader::setFollowRedirects(bool val) { d->followRedirect = val; } /*! Returns whether redirects should be followed. */ bool KDUpdater::FileDownloader::followRedirects() const { return d->followRedirect; } bool KDUpdater::FileDownloader::isAutoRemoveDownloadedFile() const { return d->autoRemove; } /*! Downloads files. */ void KDUpdater::FileDownloader::download() { QMetaObject::invokeMethod(this, "doDownload", Qt::QueuedConnection); } /*! Cancels file download. */ void KDUpdater::FileDownloader::cancelDownload() { // Do nothing } /*! Starts the download speed timer. */ void KDUpdater::FileDownloader::runDownloadSpeedTimer() { if (!d->m_speedIntervalTimer.isActive()) d->m_speedIntervalTimer.start(d->m_speedTimerInterval, this); } /*! Stops the download speed timer. */ void KDUpdater::FileDownloader::stopDownloadSpeedTimer() { d->m_speedIntervalTimer.stop(); } /*! Restarts the download deadline timer. */ void KDUpdater::FileDownloader::runDownloadDeadlineTimer() { stopDownloadDeadlineTimer(); d->m_downloadDeadlineTimer.start(d->m_downloadDeadlineTimerInterval, this); } /*! Stops the download deadline timer. */ void KDUpdater::FileDownloader::stopDownloadDeadlineTimer() { d->m_downloadDeadlineTimer.stop(); } /*! Sets the download into a \a paused state. */ void KDUpdater::FileDownloader::setDownloadPaused(bool paused) { d->m_downloadPaused = paused; } /*! Returns the download paused state. */ bool KDUpdater::FileDownloader::isDownloadPaused() { return d->m_downloadPaused; } /*! Sets the download into a \a resumed state. */ void KDUpdater::FileDownloader::setDownloadResumed(bool resumed) { d->m_downloadResumed = resumed; } /*! Returns the download resumed state. */ bool KDUpdater::FileDownloader::isDownloadResumed() { return d->m_downloadResumed; } /*! Gets the amount of bytes downloaded before download resume. */ qint64 KDUpdater::FileDownloader::bytesDownloadedBeforeResume() { return d->m_bytesBeforeResume; } /*! Gets the total amount of bytes downloaded before download resume. */ qint64 KDUpdater::FileDownloader::totalBytesDownloadedBeforeResume() { return d->m_totalBytesBeforeResume; } /*! Clears the amount of bytes downloaded before download resume. */ void KDUpdater::FileDownloader::clearBytesDownloadedBeforeResume() { d->m_bytesBeforeResume = 0; d->m_totalBytesBeforeResume = 0; } /*! Updates the amount of \a bytes downloaded before download resumes. */ void KDUpdater::FileDownloader::updateBytesDownloadedBeforeResume(qint64 bytes) { d->m_bytesBeforeResume += bytes; } /*! Updates the total amount of bytes downloaded before download resume. */ void KDUpdater::FileDownloader::updateTotalBytesDownloadedBeforeResume() { d->m_totalBytesBeforeResume = d->m_bytesBeforeResume; } /*! Adds \a sample to the current speed bin. */ void KDUpdater::FileDownloader::addSample(qint64 sample) { d->m_currentSpeedBin += sample; } /*! Returns the download speed timer ID. */ int KDUpdater::FileDownloader::downloadSpeedTimerId() const { return d->m_speedIntervalTimer.timerId(); } /*! Returns the download deadline timer ID. */ int KDUpdater::FileDownloader::downloadDeadlineTimerId() const { return d->m_downloadDeadlineTimer.timerId(); } /*! Sets the file download progress to the number of received bytes, \a bytesReceived, and the number of total bytes to receive, \a bytesToReceive. */ void KDUpdater::FileDownloader::setProgress(qint64 bytesReceived, qint64 bytesToReceive) { d->m_bytesReceived = bytesReceived; d->m_bytesToReceive = bytesToReceive; } /*! Calculates the download speed in bytes per second and emits the downloadSpeed() signal. */ void KDUpdater::FileDownloader::emitDownloadSpeed() { unsigned int windowSize = sizeof(d->m_samples) / sizeof(qint64); // add speed of last time bin to the window d->m_samples[d->m_sampleIndex % windowSize] = d->m_currentSpeedBin; d->m_currentSpeedBin = 0; // reset bin for next time interval // advance the sample index d->m_sampleIndex++; d->m_downloadSpeed = 0; // dynamic window size until the window is completely filled if (d->m_sampleIndex < windowSize) windowSize = d->m_sampleIndex; for (unsigned int i = 0; i < windowSize; ++i) d->m_downloadSpeed += d->m_samples[i]; d->m_downloadSpeed /= windowSize; // computer average d->m_downloadSpeed *= 1000.0 / d->m_speedTimerInterval; // rescale to bytes/second emit downloadSpeed(d->m_downloadSpeed); } /*! Builds a textual representation of the download status in the following format: "100 MiB of 150 MiB - (DAYS) (HOURS) (MINUTES) (SECONDS) remaining". Emits the downloadStatus() signal. */ void KDUpdater::FileDownloader::emitDownloadStatus() { QString status; if (d->m_bytesToReceive > 0) { QString bytesReceived = humanReadableSize(d->m_bytesReceived); const QString bytesToReceive = humanReadableSize(d->m_bytesToReceive); // remove the unit from the bytesReceived value if bytesToReceive has the same const QString tmp = bytesToReceive.mid(bytesToReceive.indexOf(QLatin1Char(' '))); if (bytesReceived.endsWith(tmp)) bytesReceived.chop(tmp.length()); status = tr("%1 of %2").arg(bytesReceived).arg(bytesToReceive); } else { if (d->m_bytesReceived > 0) status = tr("%1 downloaded.").arg(humanReadableSize(d->m_bytesReceived)); } status += QLatin1Char(' ') + tr("(%1/sec)").arg(humanReadableSize(d->m_downloadSpeed)); if (d->m_bytesToReceive > 0 && d->m_downloadSpeed > 0) { const qint64 time = (d->m_bytesToReceive - d->m_bytesReceived) / d->m_downloadSpeed; int s = time % 60; const int d = time / 86400; const int h = (time / 3600) - (d * 24); const int m = (time / 60) - (d * 1440) - (h * 60); QString days; if (d > 0) days = tr("%n day(s), ", "", d); QString hours; if (h > 0) hours = tr("%n hour(s), ", "", h); QString minutes; if (m > 0) minutes = tr("%n minute(s)", "", m); QString seconds; if (s >= 0 && minutes.isEmpty()) { s = (s <= 0 ? 1 : s); seconds = tr("%n second(s)", "", s); } status += tr(" - %1%2%3%4 remaining.").arg(days).arg(hours).arg(minutes).arg(seconds); } else { status += tr(" - unknown time remaining."); } emit downloadStatus(status); } /*! Emits dowload progress. */ void KDUpdater::FileDownloader::emitDownloadProgress() { emit downloadProgress(d->m_bytesReceived, d->m_bytesToReceive); } /*! Emits the estimated download time. */ void KDUpdater::FileDownloader::emitEstimatedDownloadTime() { if (d->m_bytesToReceive <= 0 || d->m_downloadSpeed <= 0) { emit estimatedDownloadTime(-1); return; } emit estimatedDownloadTime((d->m_bytesToReceive - d->m_bytesReceived) / d->m_downloadSpeed); } /*! \overload addCheckSumData() */ void KDUpdater::FileDownloader::addCheckSumData(const QByteArray &data) { d->m_hash.addData(data); } /*! Adds the \a length of characters of \a data to the cryptographic hash of the downloaded file. */ void KDUpdater::FileDownloader::addCheckSumData(const char *data, int length) { d->m_hash.addData(data, length); } /*! Resets SHA-1 checksum data of the downloaded file. */ void KDUpdater::FileDownloader::resetCheckSumData() { d->m_hash.reset(); } /*! Returns a copy of the proxy factory that this FileDownloader object is using to determine the proxies to be used for requests. */ FileDownloaderProxyFactory *KDUpdater::FileDownloader::proxyFactory() const { if (d->m_factory) return d->m_factory->clone(); return 0; } /*! Sets the proxy factory for this class to be \a factory. A proxy factory is used to determine a more specific list of proxies to be used for a given request, instead of trying to use the same proxy value for all requests. This might only be of use for HTTP or FTP requests. */ void KDUpdater::FileDownloader::setProxyFactory(FileDownloaderProxyFactory *factory) { delete d->m_factory; d->m_factory = factory; } /*! Returns a copy of the authenticator that this FileDownloader object is using to set the username and password for a download request. */ QAuthenticator KDUpdater::FileDownloader::authenticator() const { return d->m_authenticator; } /*! Sets the authenticator object for this class to be \a authenticator. An authenticator is used to pass on the required authentication information. This might only be of use for HTTP or FTP requests. Emits the authenticator changed signal with the new authenticator in use. */ void KDUpdater::FileDownloader::setAuthenticator(const QAuthenticator &authenticator) { if (d->m_authenticator.isNull() || (d->m_authenticator != authenticator)) { d->m_authenticator = authenticator; emit authenticatorChanged(authenticator); } } /*! Returns \c true if SSL errors should be ignored. */ bool KDUpdater::FileDownloader::ignoreSslErrors() { return d->m_ignoreSslErrors; } /*! Determines that SSL errors should be ignored if \a ignore is \c true. */ void KDUpdater::FileDownloader::setIgnoreSslErrors(bool ignore) { d->m_ignoreSslErrors = ignore; } // -- KDUpdater::LocalFileDownloader /*! \inmodule kdupdater \class KDUpdater::LocalFileDownloader \brief The LocalFileDownloader class is used to copy files from the local file system. The user of KDUpdater might be simultaneously downloading several files; sometimes in parallel to other file downloaders. If copying a local file takes a long time, it will make the other downloads hang. Therefore, a timer is used and one block of data is copied per unit time, even though QFile::copy() does the task of copying local files from one place to another. */ struct KDUpdater::LocalFileDownloader::Private { Private() : source(0) , destination(0) , downloaded(false) , timerId(-1) {} QFile *source; QFile *destination; QString destFileName; bool downloaded; int timerId; }; /*! Creates a local file downloader with the parent \a parent. */ KDUpdater::LocalFileDownloader::LocalFileDownloader(QObject *parent) : KDUpdater::FileDownloader(QLatin1String("file"), parent) , d (new Private) { } /*! Destroys the local file downloader. */ KDUpdater::LocalFileDownloader::~LocalFileDownloader() { if (this->isAutoRemoveDownloadedFile() && !d->destFileName.isEmpty()) QFile::remove(d->destFileName); delete d; } /*! Returns \c true if the file exists and is readable. */ bool KDUpdater::LocalFileDownloader::canDownload() const { QFileInfo fi(url().toLocalFile()); return fi.exists() && fi.isReadable(); } /*! Returns \c true if the file is copied. */ bool KDUpdater::LocalFileDownloader::isDownloaded() const { return d->downloaded; } void KDUpdater::LocalFileDownloader::doDownload() { // Already downloaded if (d->downloaded) return; // Already started downloading if (d->timerId >= 0) return; // Open source and destination files QString localFile = this->url().toLocalFile(); d->source = new QFile(localFile, this); if (!d->source->open(QFile::ReadOnly)) { setDownloadAborted(tr("Cannot open file \"%1\" for reading: %2").arg(QFileInfo(localFile) .fileName(), d->source->errorString())); onError(); return; } if (d->destFileName.isEmpty()) { QTemporaryFile *file = new QTemporaryFile(this); file->open(); d->destination = file; } else { d->destination = new QFile(d->destFileName, this); d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate); } if (!d->destination->isOpen()) { setDownloadAborted(tr("Cannot open file \"%1\" for writing: %2") .arg(QFileInfo(d->destination->fileName()).fileName(), d->destination->errorString())); onError(); return; } runDownloadSpeedTimer(); // Start a timer and kickoff the copy process d->timerId = startTimer(0); // as fast as possible emit downloadStarted(); emit downloadProgress(0); } /*! Returns the file name of the copied file. */ QString KDUpdater::LocalFileDownloader::downloadedFileName() const { return d->destFileName; } /*! Sets the file name of the copied file to \a name. */ void KDUpdater::LocalFileDownloader::setDownloadedFileName(const QString &name) { d->destFileName = name; } /*! Clones the local file downloader and assigns it the parent \a parent. Returns the new local file downloader. */ KDUpdater::LocalFileDownloader *KDUpdater::LocalFileDownloader::clone(QObject *parent) const { return new LocalFileDownloader(parent); } /*! Cancels copying the file. */ void KDUpdater::LocalFileDownloader::cancelDownload() { if (d->timerId < 0) return; killTimer(d->timerId); d->timerId = -1; onError(); setDownloadCanceled(); } /*! Called when the download timer event \a event occurs. */ void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent *event) { if (event->timerId() == d->timerId) { if (!d->source || !d->destination) return; const qint64 blockSize = 32768; QByteArray buffer; buffer.resize(blockSize); const qint64 numRead = d->source->read(buffer.data(), buffer.size()); qint64 toWrite = numRead; while (toWrite > 0) { const qint64 numWritten = d->destination->write(buffer.constData() + numRead - toWrite, toWrite); if (numWritten < 0) { killTimer(d->timerId); d->timerId = -1; setDownloadAborted(tr("Writing to file \"%1\" failed: %2").arg( QDir::toNativeSeparators(d->destination->fileName()), d->destination->errorString())); onError(); return; } toWrite -= numWritten; } addSample(numRead); addCheckSumData(buffer.data(), numRead); if (numRead > 0) { setProgress(d->source->pos(), d->source->size()); emit downloadProgress(calcProgress(d->source->pos(), d->source->size())); return; } d->destination->flush(); killTimer(d->timerId); d->timerId = -1; setDownloadCompleted(); } else if (event->timerId() == downloadSpeedTimerId()) { emitDownloadSpeed(); emitDownloadStatus(); emitDownloadProgress(); emitEstimatedDownloadTime(); } } /*! Closes the destination file after it has been successfully copied and stops the download speed timer. */ void LocalFileDownloader::onSuccess() { d->downloaded = true; d->destFileName = d->destination->fileName(); if (QTemporaryFile *file = dynamic_cast<QTemporaryFile *>(d->destination)) file->setAutoRemove(false); d->destination->close(); delete d->destination; d->destination = 0; delete d->source; d->source = 0; stopDownloadSpeedTimer(); } /*! Clears the destination file if an error occurs during copying and stops the download speed timer. */ void LocalFileDownloader::onError() { d->downloaded = false; d->destFileName.clear(); delete d->destination; d->destination = 0; delete d->source; d->source = 0; stopDownloadSpeedTimer(); } // -- ResourceFileDownloader /*! \inmodule kdupdater \class KDUpdater::ResourceFileDownloader \brief The ResourceFileDownloader class can be used to download resource files. */ struct KDUpdater::ResourceFileDownloader::Private { Private() : timerId(-1) , downloaded(false) {} int timerId; QFile destFile; bool downloaded; }; /*! Creates a resource file downloader with the parent \a parent. */ KDUpdater::ResourceFileDownloader::ResourceFileDownloader(QObject *parent) : KDUpdater::FileDownloader(QLatin1String("resource"), parent) , d(new Private) { } /*! Destroys the resource file downloader. */ KDUpdater::ResourceFileDownloader::~ResourceFileDownloader() { delete d; } /*! Returns \c true if the file exists and is readable. */ bool KDUpdater::ResourceFileDownloader::canDownload() const { const QFileInfo fi(QInstaller::pathFromUrl(url())); return fi.exists() && fi.isReadable(); } /*! Returns \c true if the file is downloaded. */ bool KDUpdater::ResourceFileDownloader::isDownloaded() const { return d->downloaded; } /*! Downloads a resource file. */ void KDUpdater::ResourceFileDownloader::doDownload() { // Already downloaded if (d->downloaded) return; // Already started downloading if (d->timerId >= 0) return; // Open source and destination files QUrl url = this->url(); url.setScheme(QString::fromLatin1("file")); d->destFile.setFileName(QString::fromLatin1(":%1").arg(url.toLocalFile())); emit downloadStarted(); emit downloadProgress(0); d->destFile.open(QIODevice::ReadOnly); d->timerId = startTimer(0); // start as fast as possible } /*! Returns the file name of the downloaded file. */ QString KDUpdater::ResourceFileDownloader::downloadedFileName() const { return d->destFile.fileName(); } /*! Sets the file name of the downloaded file to \a name. */ void KDUpdater::ResourceFileDownloader::setDownloadedFileName(const QString &/*name*/) { // Not supported! } /*! Clones the resource file downloader and assigns it the parent \a parent. Returns the new resource file downloader. */ KDUpdater::ResourceFileDownloader *KDUpdater::ResourceFileDownloader::clone(QObject *parent) const { return new ResourceFileDownloader(parent); } /*! Cancels downloading the file. */ void KDUpdater::ResourceFileDownloader::cancelDownload() { if (d->timerId < 0) return; killTimer(d->timerId); d->timerId = -1; setDownloadCanceled(); } /*! Called when the download timer event \a event occurs. */ void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent *event) { if (event->timerId() == d->timerId) { if (!d->destFile.isOpen()) { killTimer(d->timerId); emit downloadProgress(1); setDownloadAborted(tr("Cannot read resource file \"%1\": %2").arg(downloadedFileName(), d->destFile.errorString())); onError(); return; } QByteArray buffer; buffer.resize(32768); const qint64 numRead = d->destFile.read(buffer.data(), buffer.size()); addSample(numRead); addCheckSumData(buffer.data(), numRead); if (numRead > 0) { setProgress(d->destFile.pos(), d->destFile.size()); emit downloadProgress(calcProgress(d->destFile.pos(), d->destFile.size())); return; } killTimer(d->timerId); d->timerId = -1; setDownloadCompleted(); } else if (event->timerId() == downloadSpeedTimerId()) { emitDownloadSpeed(); emitDownloadStatus(); emitDownloadProgress(); emitEstimatedDownloadTime(); } } /*! Closes the destination file after it has been successfully copied and stops the download speed timer. */ void KDUpdater::ResourceFileDownloader::onSuccess() { d->destFile.close(); d->downloaded = true; stopDownloadSpeedTimer(); } /*! Closes the destination file if an error occurs during copying and stops the download speed timer. */ void KDUpdater::ResourceFileDownloader::onError() { d->destFile.close(); d->downloaded = false; stopDownloadSpeedTimer(); d->destFile.setFileName(QString()); } // -- KDUpdater::HttpDownloader /*! \inmodule kdupdater \class KDUpdater::HttpDownloader \brief The HttpDownloader class is used to download files over FTP, HTTP, or HTTPS. HTTPS is supported if Qt is built with SSL. */ struct KDUpdater::HttpDownloader::Private { explicit Private(HttpDownloader *qq) : q(qq) , http(0) , destination(0) , downloaded(false) , aborted(false) , m_authenticationCount(0) {} HttpDownloader *const q; QNetworkAccessManager manager; QNetworkReply *http; QUrl sourceUrl; QFile *destination; QString destFileName; bool downloaded; bool aborted; int m_authenticationCount; void shutDown(bool closeDestination = true) { if (http) { disconnect(http, &QNetworkReply::finished, q, &HttpDownloader::httpReqFinished); disconnect(http, &QNetworkReply::downloadProgress, q, &HttpDownloader::httpReadProgress); void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error; disconnect(http, errorSignal, q, &HttpDownloader::httpError); http->deleteLater(); } http = 0; if (closeDestination) { destination->close(); destination->deleteLater(); destination = 0; q->resetCheckSumData(); } } }; /*! Creates an HTTP downloader with the parent \a parent. */ KDUpdater::HttpDownloader::HttpDownloader(QObject *parent) : KDUpdater::FileDownloader(QLatin1String("http"), parent) , d(new Private(this)) { #ifndef QT_NO_SSL connect(&d->manager, &QNetworkAccessManager::sslErrors, this, &HttpDownloader::onSslErrors); #endif connect(&d->manager, &QNetworkAccessManager::authenticationRequired, this, &HttpDownloader::onAuthenticationRequired); connect(&d->manager, &QNetworkAccessManager::networkAccessibleChanged, this, &HttpDownloader::onNetworkAccessibleChanged); } /*! Destroys an HTTP downloader. Removes the downloaded file if FileDownloader::isAutoRemoveDownloadedFile() returns \c true or FileDownloader::setAutoRemoveDownloadedFile() was called with \c true. */ KDUpdater::HttpDownloader::~HttpDownloader() { if (this->isAutoRemoveDownloadedFile() && !d->destFileName.isEmpty()) QFile::remove(d->destFileName); delete d; } /*! Returns \c true if the file exists and is readable. */ bool KDUpdater::HttpDownloader::canDownload() const { // TODO: Check whether the http file actually exists or not. return true; } /*! Returns \c true if the file is downloaded. */ bool KDUpdater::HttpDownloader::isDownloaded() const { return d->downloaded; } void KDUpdater::HttpDownloader::doDownload() { if (d->downloaded) return; if (d->http) return; startDownload(url()); runDownloadSpeedTimer(); runDownloadDeadlineTimer(); } /*! Returns the file name of the downloaded file. */ QString KDUpdater::HttpDownloader::downloadedFileName() const { return d->destFileName; } /*! Sets the file name of the downloaded file to \a name. */ void KDUpdater::HttpDownloader::setDownloadedFileName(const QString &name) { d->destFileName = name; } /*! Clones the HTTP downloader and assigns it the parent \a parent. Returns the new HTTP downloader. */ KDUpdater::HttpDownloader *KDUpdater::HttpDownloader::clone(QObject *parent) const { return new HttpDownloader(parent); } void KDUpdater::HttpDownloader::httpReadyRead() { if (d->http == 0 || d->destination == 0) return; static QByteArray buffer(16384, '\0'); while (d->http->bytesAvailable()) { const qint64 read = d->http->read(buffer.data(), buffer.size()); qint64 written = 0; while (written < read) { const qint64 numWritten = d->destination->write(buffer.data() + written, read - written); if (numWritten < 0) { const QString error = d->destination->errorString(); const QString fileName = d->destination->fileName(); d->shutDown(); setDownloadAborted(tr("Cannot download %1. Writing to file \"%2\" failed: %3") .arg(url().toString(), fileName, error)); return; } written += numWritten; } addSample(written); addCheckSumData(buffer.data(), read); updateBytesDownloadedBeforeResume(written); } } void KDUpdater::HttpDownloader::httpError(QNetworkReply::NetworkError) { if (!d->aborted) httpDone(true); } /*! Cancels downloading the file. */ void KDUpdater::HttpDownloader::cancelDownload() { d->aborted = true; if (d->http) { d->http->abort(); httpDone(true); } } void KDUpdater::HttpDownloader::httpDone(bool error) { if (error) { if (isDownloadResumed()) { d->shutDown(false); return; } QString err; if (d->http) { err = d->http->errorString(); d->http->deleteLater(); d->http = 0; onError(); } if (d->aborted) { d->aborted = false; setDownloadCanceled(); } else { setDownloadAborted(err); return; } } setDownloadResumed(false); } /*! Closes the destination file if an error occurs during copying and stops the download speed timer. */ void KDUpdater::HttpDownloader::onError() { d->downloaded = false; d->destFileName.clear(); delete d->destination; d->destination = 0; stopDownloadSpeedTimer(); stopDownloadDeadlineTimer(); } /*! Closes the destination file after it has been successfully copied and stops the download speed timer. */ void KDUpdater::HttpDownloader::onSuccess() { d->downloaded = true; if (d->destination) { d->destFileName = d->destination->fileName(); if (QTemporaryFile *file = dynamic_cast<QTemporaryFile *>(d->destination)) file->setAutoRemove(false); } delete d->destination; d->destination = 0; stopDownloadSpeedTimer(); stopDownloadDeadlineTimer(); setDownloadResumed(false); } void KDUpdater::HttpDownloader::httpReqFinished() { const QVariant redirect = d->http == 0 ? QVariant() : d->http->attribute(QNetworkRequest::RedirectionTargetAttribute); const QUrl redirectUrl = redirect.toUrl(); if (followRedirects() && redirectUrl.isValid()) { d->shutDown(); // clean the previous download startDownload(redirectUrl); } else { if (d->http == 0) return; const QUrl url = d->http->url(); if (url.isValid() && QInstaller::lcServer().isDebugEnabled()){ const QFileInfo fi(d->http->url().toString()); if (fi.suffix() != QLatin1String("sha1")){ const QString hostName = url.host(); QHostInfo info = QHostInfo::fromName(hostName); QStringList hostAddresses; foreach (const QHostAddress &address, info.addresses()) hostAddresses << address.toString(); qCDebug(QInstaller::lcServer) << "Using host:" << hostName << "for" << url.fileName() << "\nIP:" << hostAddresses; } } httpReadyRead(); if (d->destination) d->destination->flush(); setDownloadCompleted(); if (d->http) d->http->deleteLater(); d->http = 0; } } void KDUpdater::HttpDownloader::httpReadProgress(qint64 done, qint64 total) { if (d->http) { const QUrl redirectUrl = d->http->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (followRedirects() && redirectUrl.isValid()) return; // if we are a redirection, do not emit the progress } if (isDownloadResumed()) setProgress(done + totalBytesDownloadedBeforeResume(), total + totalBytesDownloadedBeforeResume()); else setProgress(done, total); runDownloadDeadlineTimer(); if (isDownloadResumed()) emit downloadProgress(calcProgress(done + totalBytesDownloadedBeforeResume(), total + totalBytesDownloadedBeforeResume())); else emit downloadProgress(calcProgress(done, total)); } /*! Called when the download timer event \a event occurs. */ void KDUpdater::HttpDownloader::timerEvent(QTimerEvent *event) { if (event->timerId() == downloadSpeedTimerId()) { emitDownloadSpeed(); emitDownloadStatus(); emitDownloadProgress(); emitEstimatedDownloadTime(); } else if (event->timerId() == downloadDeadlineTimerId()) { d->shutDown(false); resumeDownload(); } } void KDUpdater::HttpDownloader::startDownload(const QUrl &url) { d->sourceUrl = url; d->m_authenticationCount = 0; d->manager.setProxyFactory(proxyFactory()); clearBytesDownloadedBeforeResume(); d->http = d->manager.get(QNetworkRequest(url)); connect(d->http, &QIODevice::readyRead, this, &HttpDownloader::httpReadyRead); connect(d->http, &QNetworkReply::downloadProgress, this, &HttpDownloader::httpReadProgress); connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished); void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error; connect(d->http, errorSignal, this, &HttpDownloader::httpError); if (d->destFileName.isEmpty()) { QTemporaryFile *file = new QTemporaryFile(this); file->open(); d->destination = file; } else { d->destination = new QFile(d->destFileName, this); d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate); } if (!d->destination->isOpen()) { const QString error = d->destination->errorString(); const QString fileName = d->destination->fileName(); d->shutDown(); setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg( url.toString(), fileName, error)); } } void KDUpdater::HttpDownloader::resumeDownload() { updateTotalBytesDownloadedBeforeResume(); d->m_authenticationCount = 0; QNetworkRequest request(d->sourceUrl); request.setRawHeader(QByteArray("Range"), QString(QStringLiteral("bytes=%1-")) .arg(bytesDownloadedBeforeResume()) .toLatin1()); setDownloadResumed(true); d->http = d->manager.get(request); connect(d->http, &QIODevice::readyRead, this, &HttpDownloader::httpReadyRead); connect(d->http, &QNetworkReply::downloadProgress, this, &HttpDownloader::httpReadProgress); connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished); void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error; connect(d->http, errorSignal, this, &HttpDownloader::httpError); runDownloadSpeedTimer(); runDownloadDeadlineTimer(); } void KDUpdater::HttpDownloader::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { Q_UNUSED(reply) // first try with the information we have already if (d->m_authenticationCount == 0) { d->m_authenticationCount++; authenticator->setUser(this->authenticator().user()); authenticator->setPassword(this->authenticator().password()); } else if (d->m_authenticationCount == 1) { // we failed to authenticate, ask for new credentials QDialog dlg; Ui::Dialog ui; ui.setupUi(&dlg); dlg.adjustSize(); ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm()).arg(url().host())); ui.userEdit->setText(this->authenticator().user()); ui.passwordEdit->setText(this->authenticator().password()); if (dlg.exec() == QDialog::Accepted) { authenticator->setUser(ui.userEdit->text()); authenticator->setPassword(ui.passwordEdit->text()); // update the authenticator we used initially QAuthenticator auth; auth.setUser(ui.userEdit->text()); auth.setPassword(ui.passwordEdit->text()); emit authenticatorChanged(auth); } else { d->shutDown(); setDownloadAborted(tr("Authentication request canceled.")); emit downloadCanceled(); } d->m_authenticationCount++; } } void KDUpdater::HttpDownloader::onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible) { if (accessible == QNetworkAccessManager::NotAccessible) { d->shutDown(false); setDownloadPaused(true); setDownloadResumed(false); stopDownloadDeadlineTimer(); } else if (accessible == QNetworkAccessManager::Accessible) { if (isDownloadPaused()) { setDownloadPaused(false); resumeDownload(); } } } #ifndef QT_NO_SSL #include "messageboxhandler.h" void KDUpdater::HttpDownloader::onSslErrors(QNetworkReply* reply, const QList<QSslError> &errors) { Q_UNUSED(reply) QString errorString; foreach (const QSslError &error, errors) { if (!errorString.isEmpty()) errorString += QLatin1String(", "); errorString += error.errorString(); } qCWarning(QInstaller::lcInstallerInstallLog) << errorString; const QStringList arguments = QCoreApplication::arguments(); if (arguments.contains(QLatin1String("--script")) || arguments.contains(QLatin1String("Script")) || ignoreSslErrors()) { reply->ignoreSslErrors(); return; } // TODO: Remove above code once we have a proper implementation for message box handler supporting // methods used in the following code, right now we return here cause the message box is not scriptable. QMessageBox msgBox(MessageBoxHandler::currentBestSuitParent()); msgBox.setDetailedText(errorString); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowModality(Qt::WindowModal); msgBox.setWindowTitle(tr("Secure Connection Failed")); msgBox.setText(tr("There was an error during connection to: %1.").arg(url().toString())); msgBox.setInformativeText(QString::fromLatin1("<ul><li>%1</li><li>%2</li></ul>").arg(tr("This could be " "a problem with the server's configuration, or it could be someone trying to impersonate the " "server."), tr("If you have connected to this server successfully in the past or trust this server, " "the error may be temporary and you can try again."))); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); msgBox.setButtonText(QMessageBox::Yes, tr("Try again")); msgBox.setDefaultButton(QMessageBox::Cancel); if (msgBox.exec() == QMessageBox::Cancel) { if (!d->aborted) httpDone(true); } else { reply->ignoreSslErrors(); KDUpdater::FileDownloaderFactory::instance().setIgnoreSslErrors(true); } } #endif ��������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/filedownloader.h��������������������������������������0100777�0000000�0000000�00000011317�13761647206�021451� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FILEDOWNLOADER_H #define FILEDOWNLOADER_H #include "kdtoolsglobal.h" #include <QtCore/QObject> #include <QtCore/QUrl> #include <QtNetwork/QAuthenticator> namespace KDUpdater { class FileDownloaderProxyFactory; class KDTOOLS_EXPORT FileDownloader : public QObject { Q_OBJECT Q_PROPERTY(bool autoRemoveDownloadedFile READ isAutoRemoveDownloadedFile WRITE setAutoRemoveDownloadedFile) Q_PROPERTY(QUrl url READ url WRITE setUrl) Q_PROPERTY(QString scheme READ scheme WRITE setScheme) public: explicit FileDownloader(const QString &scheme, QObject *parent = 0); ~FileDownloader(); QUrl url() const; void setUrl(const QUrl &url); QByteArray sha1Sum() const; QByteArray assumedSha1Sum() const; void setAssumedSha1Sum(const QByteArray &sha1); QString scheme() const; void setScheme(const QString &scheme); QString errorString() const; virtual bool canDownload() const = 0; virtual bool isDownloaded() const = 0; virtual QString downloadedFileName() const = 0; virtual void setDownloadedFileName(const QString &name) = 0; virtual FileDownloader *clone(QObject *parent=0) const = 0; void download(); void setAutoRemoveDownloadedFile(bool val); bool isAutoRemoveDownloadedFile() const; void setFollowRedirects(bool val); bool followRedirects() const; FileDownloaderProxyFactory *proxyFactory() const; void setProxyFactory(FileDownloaderProxyFactory *factory); QAuthenticator authenticator() const; void setAuthenticator(const QAuthenticator &authenticator); bool ignoreSslErrors(); void setIgnoreSslErrors(bool ignore); public Q_SLOTS: virtual void cancelDownload(); protected: virtual void onError() = 0; virtual void onSuccess() = 0; Q_SIGNALS: void downloadStarted(); void downloadCanceled(); void downloadProgress(double progress); void estimatedDownloadTime(int seconds); void downloadSpeed(qint64 bytesPerSecond); void downloadStatus(const QString &status); void downloadProgress(qint64 bytesReceived, qint64 bytesToReceive); void authenticatorChanged(const QAuthenticator &authenticator); void downloadCompleted(); void downloadAborted(const QString &errorMessage); protected: void setDownloadCanceled(); void setDownloadCompleted(); void setDownloadAborted(const QString &error); void runDownloadSpeedTimer(); void stopDownloadSpeedTimer(); void runDownloadDeadlineTimer(); void stopDownloadDeadlineTimer(); void setDownloadPaused(bool paused); bool isDownloadPaused(); void setDownloadResumed(bool resumed); bool isDownloadResumed(); qint64 bytesDownloadedBeforeResume(); qint64 totalBytesDownloadedBeforeResume(); void clearBytesDownloadedBeforeResume(); void updateBytesDownloadedBeforeResume(qint64 bytes); void updateTotalBytesDownloadedBeforeResume(); void addSample(qint64 sample); int downloadSpeedTimerId() const; int downloadDeadlineTimerId() const; void setProgress(qint64 bytesReceived, qint64 bytesToReceive); void emitDownloadSpeed(); void emitDownloadStatus(); void emitDownloadProgress(); void emitEstimatedDownloadTime(); void addCheckSumData(const QByteArray &data); void addCheckSumData(const char *data, int length); void resetCheckSumData(); private Q_SLOTS: virtual void doDownload() = 0; private: struct Private; Private *d; }; } // namespace KDUpdater #endif // FILEDOWNLOADER_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/filedownloaderfactory.cpp�����������������������������0100777�0000000�0000000�00000014247�13761647206�023401� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filedownloaderfactory.h" #include "filedownloader_p.h" #include "globals.h" #include <QtNetwork/QSslSocket> using namespace KDUpdater; /*! \inmodule kdupdater \class KDUpdater::FileDownloaderFactory \brief The FileDownloaderFactory class acts as a factory for KDUpdater::FileDownloader. You can register one or more file downloaders with this factory and query them based on their scheme. The class follows the singleton design pattern. Only one instance of this class can be created and its reference can be fetched from the instance() method. */ /*! Returns the file downloader factory instance. */ FileDownloaderFactory& FileDownloaderFactory::instance() { static KDUpdater::FileDownloaderFactory theFactory; return theFactory; } /*! Constructs a file downloader factory and registers the default file downloader set. */ FileDownloaderFactory::FileDownloaderFactory() : d (new FileDownloaderFactoryData) { // Register the default file downloader set registerFileDownloader<LocalFileDownloader>( QLatin1String("file")); registerFileDownloader<HttpDownloader>(QLatin1String("ftp")); registerFileDownloader<HttpDownloader>(QLatin1String("http")); registerFileDownloader<ResourceFileDownloader >(QLatin1String("resource")); #ifndef QT_NO_SSL if (QSslSocket::supportsSsl()) registerFileDownloader<HttpDownloader>(QLatin1String("https")); else qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot register file downloader for https protocol: QSslSocket::supportsSsl() returns false"; #endif d->m_followRedirects = false; } /*! Returns whether redirects should be followed. */ bool FileDownloaderFactory::followRedirects() { return FileDownloaderFactory::instance().d->m_followRedirects; } /*! Determines that redirects should be followed if \a val is \c true. */ void FileDownloaderFactory::setFollowRedirects(bool val) { FileDownloaderFactory::instance().d->m_followRedirects = val; } /*! Sets \a factory as the file downloader proxy factory. */ void FileDownloaderFactory::setProxyFactory(FileDownloaderProxyFactory *factory) { delete FileDownloaderFactory::instance().d->m_factory; FileDownloaderFactory::instance().d->m_factory = factory; } /*! Returns \c true if SSL errors should be ignored. */ bool FileDownloaderFactory::ignoreSslErrors() { return FileDownloaderFactory::instance().d->m_ignoreSslErrors; } /*! Determines that SSL errors should be ignored if \a ignore is \c true. */ void FileDownloaderFactory::setIgnoreSslErrors(bool ignore) { FileDownloaderFactory::instance().d->m_ignoreSslErrors = ignore; } /*! Destroys the file downloader factory. */ FileDownloaderFactory::~FileDownloaderFactory() { delete d; } /*! Returns a list of supported schemes. */ QStringList FileDownloaderFactory::supportedSchemes() { return FileDownloaderFactory::instance().d->m_supportedSchemes; } /*! Returns \c true if \a scheme is a supported scheme. */ bool FileDownloaderFactory::isSupportedScheme(const QString &scheme) { return FileDownloaderFactory::instance().d->m_supportedSchemes.contains(scheme , Qt::CaseInsensitive); } /*! Returns a new instance of a KDUpdater::FileDownloader subclass. The instantiation of a subclass depends on the communication protocol string stored in \a scheme with the parent \a parent. \note Ownership of the created object remains with the programmer. */ FileDownloader *FileDownloaderFactory::create(const QString &scheme, QObject *parent) const { FileDownloader *downloader = GenericFactory<FileDownloader, QString, QObject*>::create(scheme, parent); if (downloader != 0) { downloader->setFollowRedirects(d->m_followRedirects); downloader->setIgnoreSslErrors(d->m_ignoreSslErrors); if (d->m_factory) downloader->setProxyFactory(d->m_factory->clone()); } return downloader; } /*! \fn void KDUpdater::FileDownloaderFactory::registerFileDownloader(const QString &scheme) Registers a new file downloader with the factory based on \a scheme. If there is already a downloader with the same scheme, the downloader is replaced. When create() is called with that \a scheme, the file downloader is constructed using its default constructor. */ /*! \inmodule kdupdater \class KDUpdater::FileDownloaderProxyFactory \brief The FileDownloaderProxyFactory class provides fine-grained proxy selection. File downloader objects use a proxy factory to determine a more specific list of proxies to be used for a given request, instead of trying to use the same proxy value for all requests. This might only be of use for HTTP or FTP requests. */ /*! \fn KDUpdater::FileDownloaderProxyFactory::~FileDownloaderProxyFactory() Destroys the file downloader proxy factory. */ /*! \fn KDUpdater::FileDownloaderProxyFactory::clone() const Clones a file downloader proxy factory. */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/filedownloaderfactory.h�������������������������������0100777�0000000�0000000�00000006103�13761647206�023036� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FILEDOWNLOADERFACTORY_H #define FILEDOWNLOADERFACTORY_H #include "genericfactory.h" #include "updater.h" #include <QtCore/QStringList> #include <QtCore/QUrl> #include <QtNetwork/QNetworkProxyFactory> QT_BEGIN_NAMESPACE class QObject; QT_END_NAMESPACE namespace KDUpdater { class FileDownloader; class KDTOOLS_EXPORT FileDownloaderProxyFactory : public QNetworkProxyFactory { public: virtual ~FileDownloaderProxyFactory() {} virtual FileDownloaderProxyFactory *clone() const = 0; }; class KDTOOLS_EXPORT FileDownloaderFactory : public GenericFactory<FileDownloader, QString, QObject*> { Q_DISABLE_COPY(FileDownloaderFactory) struct FileDownloaderFactoryData { FileDownloaderFactoryData() : m_factory(0) {} ~FileDownloaderFactoryData() { delete m_factory; } bool m_followRedirects; bool m_ignoreSslErrors; QStringList m_supportedSchemes; FileDownloaderProxyFactory *m_factory; }; public: static FileDownloaderFactory &instance(); ~FileDownloaderFactory(); template<typename T> void registerFileDownloader(const QString &scheme) { registerProduct<T>(scheme); d->m_supportedSchemes.append(scheme); } FileDownloader *create(const QString &scheme, QObject *parent = 0) const; static bool followRedirects(); static void setFollowRedirects(bool val); static void setProxyFactory(FileDownloaderProxyFactory *factory); static bool ignoreSslErrors(); static void setIgnoreSslErrors(bool ignore); static QStringList supportedSchemes(); static bool isSupportedScheme(const QString &scheme); private: FileDownloaderFactory(); private: FileDownloaderFactoryData *d; }; } // namespace KDUpdater #endif // FILEDOWNLOADERFACTORY_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/filedownloader_p.h������������������������������������0100777�0000000�0000000�00000007475�13761647206�022002� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FILEDOWNLOADER_P_H #define FILEDOWNLOADER_P_H #include "filedownloader.h" #include <QtNetwork/QNetworkReply> #include <QNetworkAccessManager> // these classes are not a part of the public API namespace KDUpdater { class LocalFileDownloader : public FileDownloader { Q_OBJECT public: explicit LocalFileDownloader(QObject *parent = 0); ~LocalFileDownloader(); bool canDownload() const; bool isDownloaded() const; QString downloadedFileName() const; void setDownloadedFileName(const QString &name); LocalFileDownloader *clone(QObject *parent = 0) const; public Q_SLOTS: void cancelDownload(); protected: void timerEvent(QTimerEvent *te); void onError(); void onSuccess(); private Q_SLOTS: void doDownload(); private: struct Private; Private *d; }; class ResourceFileDownloader : public FileDownloader { Q_OBJECT public: explicit ResourceFileDownloader(QObject *parent = 0); ~ResourceFileDownloader(); bool canDownload() const; bool isDownloaded() const; QString downloadedFileName() const; void setDownloadedFileName(const QString &name); ResourceFileDownloader *clone(QObject *parent = 0) const; public Q_SLOTS: void cancelDownload(); protected: void timerEvent(QTimerEvent *te); void onError(); void onSuccess(); private Q_SLOTS: void doDownload(); private: struct Private; Private *d; }; class HttpDownloader : public FileDownloader { Q_OBJECT public: explicit HttpDownloader(QObject *parent = 0); ~HttpDownloader(); bool canDownload() const; bool isDownloaded() const; QString downloadedFileName() const; void setDownloadedFileName(const QString &name); HttpDownloader *clone(QObject *parent = 0) const; public Q_SLOTS: void cancelDownload(); protected: void onError(); void onSuccess(); void timerEvent(QTimerEvent *event); private Q_SLOTS: void doDownload(); void httpReadyRead(); void httpReadProgress(qint64 done, qint64 total); void httpError(QNetworkReply::NetworkError); void httpDone(bool error); void httpReqFinished(); void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator); void onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible); #ifndef QT_NO_SSL void onSslErrors(QNetworkReply* reply, const QList<QSslError> &errors); #endif private: void startDownload(const QUrl &url); void resumeDownload(); private: struct Private; Private *d; }; } // namespace KDUpdater #endif // FILEDOWNLOADER_P_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/genericfactory.cpp������������������������������������0100777�0000000�0000000�00000013566�13761647206�022022� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "genericfactory.h" /*! \inmodule kdupdater \namespace KDUpdater \brief The KDUpdater classes provide functions to automatically detect updates to applications, to retrieve them from external repositories, and to install them. KDUpdater classes are a fork of KDAB's general \l{http://docs.kdab.com/kdtools/2.2.2/group__kdupdater.html}{KDUpdater module}. */ /*! \inmodule kdupdater \class GenericFactory \brief The GenericFactory class implements a template-based generic factory. GenericFactory is an implementation of the factory pattern. It can be used to produce instances of different classes having a common superclass \c BASE. The user of the factory registers those producible classes in the factory by using the identifier \c IDENTIFIER. That identifier can then be used to produce as many instances of the registered product as the user wants. One factory instance is able to produce instances of different types of DERIVED classes only when the constructor of DERIVED or the registered generator function have a common signature for all DERIVED classes. This signature is described by the declaration order of ARGUMENTS. It is referred to as SIGNATURE in the following paragraphs. If a class derived from BASE does not contain a SIGNATURE matching the registered one for the constructor or the generator function, it is not possible to create instances of it using one instance of GenericFactory subclass. In that case, more than one GenericFactory subclass and instance are needed. It is possible to register a subclass of BASE inside an instance of GenericFactory subclass using the registerProduct() function. At least one of the following conditions needs to be met: \list \li A global or static function with SIGNATURE exists. \li The DERIVED class has a constructor with SIGNATURE. \li The DERIVED class has a static function with SIGNATURE. \endlist To get a new instance of DERIVED, one needs to call the create() function. The value of IDENTIFIER determines the product's subclass registered in the factory, while the values of SIGNATURE are the actual arguments passed to the class constructor or the registered generator function. */ /*! \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::GenericFactory() Creates the generic factory. */ /*! \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::~GenericFactory() Destroys the generic factory. */ /*! \typedef GenericFactory::FactoryFunction This typedef defines a factory function producing an object of type BASE. */ /*! \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::registerProduct(const IDENTIFIER &id) Registers a type DERIVED, identified by \a id in the factory. Any type with the same id gets unregistered. */ /*! \overload \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::registerProduct(const IDENTIFIER &id, FactoryFunction func) Registers a function \a func that can create the type DERIVED, identified by \a id in the factory. Any type with the same id gets unregistered. */ /*! \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::containsProduct(const IDENTIFIER &id) const Returns \c true if the factory contains a type with the \a id; otherwise returns false. */ /*! \fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> BASE *GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::create(const IDENTIFIER &id, ARGUMENTS... args) const Creates and returns the type identified by \a id, but automatically upcasted to BASE. Ownership of the type is transferred to the caller. */ ������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/genericfactory.h��������������������������������������0100777�0000000�0000000�00000006254�13761647206�021463� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERICFACTORY_H #define GENERICFACTORY_H #include "kdtoolsglobal.h" #include <QtCore/QHash> template <typename BASE, typename IDENTIFIER = QString, typename... ARGUMENTS> class GenericFactory { public: virtual ~GenericFactory() {} typedef BASE *(*FactoryFunction)(ARGUMENTS...); template <typename DERIVED> void registerProduct(const IDENTIFIER &id) { m_hash.insert(id, &GenericFactory::create<DERIVED>); } void registerProduct(const IDENTIFIER &id, FactoryFunction func) { m_hash.insert(id, func); } bool containsProduct(const IDENTIFIER &id) const { return m_hash.contains(id); } BASE *create(const IDENTIFIER &id, ARGUMENTS... args) const { const auto it = m_hash.constFind(id); if (it == m_hash.constEnd()) return 0; return (*it)(std::forward<ARGUMENTS>(args)...); } protected: GenericFactory() = default; private: template <typename DERIVED> static BASE *create(ARGUMENTS... args) { return new DERIVED(std::forward<ARGUMENTS>(args)...); } GenericFactory(const GenericFactory &) = delete; GenericFactory &operator=(const GenericFactory &) = delete; private: QHash<IDENTIFIER, FactoryFunction> m_hash; }; #endif // GENERICFACTORY_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/job.cpp�����������������������������������������������0100777�0000000�0000000�00000011725�13761647206�017563� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "job.h" #include <QDebug> #include <QEventLoop> #include <QTimer> #include "globals.h" // -- Job::Private class Job::Private { Job *const q; public: explicit Private(Job *qq) : q(qq) , error(Job::NoError) , caps(Job::NoCapabilities) , autoDelete(true) , totalAmount(100) , processedAmount(0) , m_timeout(-1) { connect(&m_timer, &QTimer::timeout, q, &Job::cancel); } ~Private() { m_timer.stop(); } void delayedStart() { q->doStart(); emit q->started(q); } void waitForSignal(const char *sig) { QEventLoop loop; q->connect(q, sig, &loop, SLOT(quit())); if (m_timeout >= 0) m_timer.start(m_timeout); else m_timer.stop(); loop.exec(); } int error; QString errorString; Job::Capabilities caps; bool autoDelete; quint64 totalAmount; quint64 processedAmount; int m_timeout; QTimer m_timer; }; // -- Job Job::Job(QObject *parent) : QObject(parent), d(new Private(this)) { connect(this, &Job::finished, this, &Job::onFinished); } Job::~Job() { delete d; } bool Job::autoDelete() const { return d->autoDelete; } void Job::setAutoDelete(bool autoDelete) { d->autoDelete = autoDelete; } int Job::error() const { return d->error; } QString Job::errorString() const { return d->errorString; } void Job::emitFinished() { emit finished(this); } void Job::emitFinishedWithError(int error, const QString &errorString) { d->error = error; d->errorString = errorString; emitFinished(); } void Job::setError(int error) { d->error = error; } void Job::setErrorString(const QString &errorString) { d->errorString = errorString; } void Job::waitForStarted() { d->waitForSignal(SIGNAL(started(Job*))); } void Job::waitForFinished() { d->waitForSignal(SIGNAL(finished(Job*))); } Job::Capabilities Job::capabilities() const { return d->caps; } bool Job::hasCapability(Capability c) const { return d->caps.testFlag(c); } void Job::setCapabilities(Capabilities c) { d->caps = c; } void Job::start() { QMetaObject::invokeMethod(this, "delayedStart", Qt::QueuedConnection); } void Job::cancel() { if (d->caps & Cancelable) { doCancel(); if (error() == NoError) { setError(Canceled); setErrorString(tr("Canceled")); } emitFinished(); } else { qCDebug(QInstaller::lcInstallerInstallLog) << "The current job cannot be canceled, " "missing \"Cancelable\" capability."; } } quint64 Job::totalAmount() const { return d->totalAmount; } quint64 Job::processedAmount() const { return d->processedAmount; } void Job::setTotalAmount(quint64 amount) { d->totalAmount = amount; emit totalProgress(d->totalAmount); } /*! Returns the timeout in milliseconds before the job's cancel slot gets triggered. A return value of -1 means there is currently no timeout used for the job. */ int Job::timeout() const { return d->m_timeout; } /*! Sets the timeout in \a milliseconds before the job's cancel slot gets triggered. \note Only jobs that have the \c Job::Cancelable capability can be canceled by a timeout. A value of -1 will stop the timeout mechanism. */ void Job::setTimeout(int milliseconds) { d->m_timeout = milliseconds; } void Job::setProcessedAmount(quint64 amount) { if (d->processedAmount == amount) return; d->processedAmount = amount; emit progress(this, d->processedAmount, d->totalAmount); } void Job::onFinished() { d->m_timer.stop(); if (d->autoDelete) deleteLater(); } #include "moc_job.cpp" �������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/job.h�������������������������������������������������0100777�0000000�0000000�00000006052�13761647206�017225� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef JOB_H #define JOB_H #include "kdtoolsglobal.h" #include <QtCore/QObject> class KDTOOLS_EXPORT Job : public QObject { Q_OBJECT class Private; Q_PROPERTY(int timeout READ timeout WRITE setTimeout) Q_PROPERTY(bool autoDelete READ autoDelete WRITE setAutoDelete) public: explicit Job(QObject *parent = 0); ~Job(); enum Error { NoError = 0, Canceled = 1, UserDefinedError = 128 }; enum Capability { NoCapabilities = 0x0, Cancelable = 0x1 }; Q_DECLARE_FLAGS(Capabilities, Capability) int error() const; QString errorString() const; bool autoDelete() const; void setAutoDelete(bool autoDelete); Capabilities capabilities() const; bool hasCapability(Capability c) const; void waitForStarted(); void waitForFinished(); quint64 totalAmount() const; quint64 processedAmount() const; int timeout() const; void setTimeout(int milliseconds); public Q_SLOTS: void start(); void cancel(); Q_SIGNALS: void started(Job *job); void finished(Job *job); void infoMessage(Job *job, const QString &message); void progress(Job *job, quint64 processed, quint64 total); void totalProgress(quint64 total); protected: virtual void doStart() = 0; virtual void doCancel() = 0; void setCapabilities(Capabilities c); void setTotalAmount(quint64 amount); void setProcessedAmount(quint64 amount); void setError(int error); void setErrorString(const QString &errorString); void emitFinished(); void emitFinishedWithError(int error, const QString &errorString); private Q_SLOTS: void onFinished(); private: Private *d; Q_PRIVATE_SLOT(d, void delayedStart()) }; Q_DECLARE_OPERATORS_FOR_FLAGS(Job::Capabilities) #endif // JOB_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/kdsysinfo_win.cpp�������������������������������������0100777�0000000�0000000�00000010670�13761647206�021675� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sysinfo.h" #include <QLibrary> #include <QStringList> #include <qt_windows.h> #include <psapi.h> #include <tlhelp32.h> const int KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; namespace KDUpdater { quint64 installedMemory() { MEMORYSTATUSEX status; status.dwLength = sizeof(status); GlobalMemoryStatusEx(&status); return quint64(status.ullTotalPhys); } struct EnumWindowsProcParam { QList<ProcessInfo> processes; QList<quint32> seenIDs; }; typedef BOOL (WINAPI *QueryFullProcessImageNamePtr)(HANDLE, DWORD, char *, PDWORD); typedef DWORD (WINAPI *GetProcessImageFileNamePtr)(HANDLE, char *, DWORD); QList<ProcessInfo> runningProcesses() { EnumWindowsProcParam param; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (!snapshot) return param.processes; QStringList deviceList; const DWORD bufferSize = 1024; char buffer[bufferSize + 1] = { 0 }; if (QSysInfo::windowsVersion() <= QSysInfo::WV_5_2) { const DWORD size = GetLogicalDriveStringsA(bufferSize, buffer); deviceList = QString::fromLatin1(buffer, size).split(QLatin1Char(char(0)), QString::SkipEmptyParts); } QLibrary kernel32(QLatin1String("Kernel32.dll")); kernel32.load(); QueryFullProcessImageNamePtr pQueryFullProcessImageNamePtr = (QueryFullProcessImageNamePtr) kernel32 .resolve("QueryFullProcessImageNameA"); QLibrary psapi(QLatin1String("Psapi.dll")); psapi.load(); GetProcessImageFileNamePtr pGetProcessImageFileNamePtr = (GetProcessImageFileNamePtr) psapi .resolve("GetProcessImageFileNameA"); PROCESSENTRY32 processStruct; processStruct.dwSize = sizeof(PROCESSENTRY32); bool foundProcess = Process32First(snapshot, &processStruct); while (foundProcess) { HANDLE procHandle = OpenProcess(QSysInfo::windowsVersion() > QSysInfo::WV_5_2 ? KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION, false, processStruct .th32ProcessID); bool succ = false; QString executablePath; DWORD bufferSize = 1024; if (QSysInfo::windowsVersion() > QSysInfo::WV_5_2) { succ = pQueryFullProcessImageNamePtr(procHandle, 0, buffer, &bufferSize); executablePath = QString::fromLatin1(buffer); } else if (pGetProcessImageFileNamePtr) { succ = pGetProcessImageFileNamePtr(procHandle, buffer, bufferSize); executablePath = QString::fromLatin1(buffer); for (int i = 0; i < deviceList.count(); ++i) { executablePath.replace(QString::fromLatin1( "\\Device\\HarddiskVolume%1\\" ).arg(i + 1), deviceList.at(i)); } } if (succ) { const quint32 pid = processStruct.th32ProcessID; param.seenIDs.append(pid); ProcessInfo info; info.id = pid; info.name = executablePath; param.processes.append(info); } CloseHandle(procHandle); foundProcess = Process32Next(snapshot, &processStruct); } if (snapshot) CloseHandle(snapshot); kernel32.unload(); return param.processes; } } // namespace KDUpdater ������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/kdtools.pri�������������������������������������������0100777�0000000�0000000�00000002540�13761647206�020473� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDEPATH += $$PWD DEFINES += BUILD_SHARED_KDTOOLS FORMS += $$PWD/authenticationdialog.ui HEADERS += $$PWD/kdtoolsglobal.h \ $$PWD/job.h \ $$PWD/genericfactory.h \ $$PWD/selfrestarter.h \ $$PWD/runoncechecker.h \ $$PWD/lockfile.h \ $$PWD/sysinfo.h SOURCES += $$PWD/job.cpp \ $$PWD/selfrestarter.cpp \ $$PWD/runoncechecker.cpp \ $$PWD/lockfile.cpp \ $$PWD/sysinfo.cpp HEADERS += $$PWD/updater.h \ $$PWD/filedownloader.h \ $$PWD/filedownloader_p.h \ $$PWD/filedownloaderfactory.h \ $$PWD/localpackagehub.h \ $$PWD/update.h \ $$PWD/updateoperation.h \ $$PWD/updateoperationfactory.h \ $$PWD/updateoperations.h \ $$PWD/task.h \ $$PWD/updatefinder.h \ $$PWD/updatesinfo_p.h \ $$PWD/environment.h \ $$PWD/updatesinfodata_p.h SOURCES += $$PWD/filedownloader.cpp \ $$PWD/filedownloaderfactory.cpp \ $$PWD/localpackagehub.cpp \ $$PWD/update.cpp \ $$PWD/updateoperation.cpp \ $$PWD/updateoperationfactory.cpp \ $$PWD/updateoperations.cpp \ $$PWD/task.cpp \ $$PWD/updatefinder.cpp \ $$PWD/updatesinfo.cpp \ $$PWD/environment.cpp win32 { SOURCES += $$PWD/lockfile_win.cpp \ $$PWD/kdsysinfo_win.cpp } unix { SOURCES += $$PWD/lockfile_unix.cpp osx: SOURCES += $$PWD/sysinfo_mac.cpp else: SOURCES += $$PWD/sysinfo_x11.cpp } ����������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/kdtoolsglobal.h���������������������������������������0100777�0000000�0000000�00000003110�13761647206�021303� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef KDTOOLSGLOBAL_H #define KDTOOLSGLOBAL_H #include <QtCore/QtGlobal> #ifndef QT_STATIC # ifdef BUILD_SHARED_KDTOOLS # define KDTOOLS_EXPORT Q_DECL_EXPORT # else # define KDTOOLS_EXPORT Q_DECL_IMPORT # endif #else // KDTOOLS_SHARED # define KDTOOLS_EXPORT #endif // KDTOOLS_SHARED #endif // KDTOOLSGLOBAL_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/LICENSE.LGPL������������������������������������������0100777�0000000�0000000�00000062127�13761647206�020051� 0����������������������������������������������������������������������������������������������������ustar�00������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� The KD Tools Library is Copyright (C) 2001-2009 KlarÃĪlvdalens Datakonsult AB. You may use, distribute and copy the KD Tools Library under the terms of GNU Library General Public License version 2, which is displayed below. ------------------------------------------------------------------------- GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 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. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Library 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/localpackagehub.cpp�����������������������������������0100777�0000000�0000000�00000044533�13761647206�022121� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "localpackagehub.h" #include "fileutils.h" #include "globals.h" #include "constants.h" #include <QDomDocument> #include <QDomElement> #include <QFileInfo> using namespace KDUpdater; using namespace QInstaller; /*! \inmodule kdupdater \class KDUpdater::LocalPackageHub \brief The LocalPackageHub class provides access to information about packages installed on the application side. This class parses the \e {installation information} XML file specified via the setFileName() method and provides access to the information defined within the file through an API. You can: \list \li Get the application name via the applicationName() method. \li Get the application version via the applicationVersion() method. \li Get information about the number of packages installed and their meta-data via the packageInfoCount() and packageInfo() methods. \endlist */ /*! \enum LocalPackageHub::Error Error codes related to retrieving information about installed packages: \value NoError No error occurred. \value NotYetReadError The installation information was not parsed yet from the XML file. \value CouldNotReadPackageFileError The specified installation information file could not be read (does not exist or is not readable). \value InvalidXmlError The installation information file contains invalid XML. \value InvalidContentError The installation information file contains valid XML, but does not match the expected format for package descriptions. */ struct LocalPackageHub::PackagesInfoData { PackagesInfoData() : error(LocalPackageHub::NotYetReadError), modified(false) {} QString errorMessage; LocalPackageHub::Error error; QString fileName; QString applicationName; QString applicationVersion; bool modified; QMap<QString, LocalPackage> m_packageInfoMap; void addPackageFrom(const QDomElement &packageE); void setInvalidContentError(const QString &detail); }; void LocalPackageHub::PackagesInfoData::setInvalidContentError(const QString &detail) { error = LocalPackageHub::InvalidContentError; errorMessage = tr("%1 contains invalid content: %2").arg(fileName, detail); } /*! Constructs a local package hub. To fully setup the class you have to call setFileName(). \sa setFileName */ LocalPackageHub::LocalPackageHub() : d(new PackagesInfoData()) { } /*! Destructor */ LocalPackageHub::~LocalPackageHub() { writeToDisk(); delete d; } /*! Returns \c true if LocalPackageHub is valid; otherwise returns \c false. You can use the errorString() method to receive a descriptive error message. */ bool LocalPackageHub::isValid() const { return d->error <= NotYetReadError; } /*! Returns a list of all local installed packages. */ QStringList LocalPackageHub::packageNames() const { return d->m_packageInfoMap.keys(); } /*! Returns a human-readable description of the last error that occurred. */ QString LocalPackageHub::errorString() const { return d->errorMessage; } /*! Returns the error that was found during the processing of the installation information XML file. If no error was found, returns NoError. */ LocalPackageHub::Error LocalPackageHub::error() const { return d->error; } /*! Sets the complete file name of the installation information XML file to \a fileName. The function also issues a call to refresh() to reload installation information from the XML file. */ void LocalPackageHub::setFileName(const QString &fileName) { if (d->fileName == fileName) return; d->fileName = fileName; refresh(); } /*! Returns the name of the installation information XML file that this class refers to. */ QString LocalPackageHub::fileName() const { return d->fileName; } /*! Sets the application name to \a name. By default, this is the name specified in the \c <ApplicationName> element of the installation information XML file. */ void LocalPackageHub::setApplicationName(const QString &name) { d->applicationName = name; } /*! Returns the application name. */ QString LocalPackageHub::applicationName() const { return d->applicationName; } /*! Sets the application version to \a version. By default, this is the version specified in the \c <ApplicationVersion> element of the installation information XML file. */ void LocalPackageHub::setApplicationVersion(const QString &version) { d->applicationVersion = version; } /*! Returns the application version. */ QString LocalPackageHub::applicationVersion() const { return d->applicationVersion; } /*! Returns the number of KDUpdater::LocalPackage objects contained in this class. */ int LocalPackageHub::packageInfoCount() const { return d->m_packageInfoMap.count(); } /*! Returns the package info structure whose name is \a pkgName. If no such package was found, this function returns a \l{default-constructed value}. */ LocalPackage LocalPackageHub::packageInfo(const QString &pkgName) const { return d->m_packageInfoMap.value(pkgName); } /*! Returns all package info structures. */ QList<LocalPackage> LocalPackageHub::packageInfos() const { return d->m_packageInfoMap.values(); } /*! Re-reads the installation information XML file and updates itself. Changes to applicationName() and applicationVersion() are lost after this function returns. The function emits a reset() signal after completion. */ void LocalPackageHub::refresh() { // First clear internal variables d->applicationName.clear(); d->applicationVersion.clear(); d->m_packageInfoMap.clear(); d->modified = false; QFile file(d->fileName); // if the file does not exist then we just skip the reading if (!file.exists()) { d->error = NotYetReadError; d->errorMessage = tr("The file %1 does not exist.").arg(d->fileName); return; } // Open Packages.xml if (!file.open(QFile::ReadOnly)) { d->error = CouldNotReadPackageFileError; d->errorMessage = tr("Cannot open %1.").arg(d->fileName); return; } // Parse the XML document QDomDocument doc; QString parseErrorMessage; int parseErrorLine; int parseErrorColumn; if (!doc.setContent(&file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn)) { d->error = InvalidXmlError; d->errorMessage = tr("Parse error in %1 at %2, %3: %4") .arg(d->fileName, QString::number(parseErrorLine), QString::number(parseErrorColumn), parseErrorMessage); return; } file.close(); // Now populate information from the XML file. QDomElement rootE = doc.documentElement(); if (rootE.tagName() != QLatin1String("Packages")) { d->setInvalidContentError(tr("Root element %1 unexpected, should be 'Packages'.") .arg(rootE.tagName())); return; } QDomNodeList childNodes = rootE.childNodes(); for (int i = 0; i < childNodes.count(); i++) { QDomNode childNode = childNodes.item(i); QDomElement childNodeE = childNode.toElement(); if (childNodeE.isNull()) continue; if (childNodeE.tagName() == QLatin1String("ApplicationName")) d->applicationName = childNodeE.text(); else if (childNodeE.tagName() == QLatin1String("ApplicationVersion")) d->applicationVersion = childNodeE.text(); else if (childNodeE.tagName() == QLatin1String("Package")) d->addPackageFrom(childNodeE); } d->error = NoError; d->errorMessage.clear(); } /*! Marks the package specified by \a name as installed. Sets the values of \a version, \a title, \a description, \a dependencies, \a autoDependencies, \a forcedInstallation, \a virtualComp, \a uncompressedSize, \a inheritVersionFrom, \a checkable, and \a expandedByDefault for the package. */ void LocalPackageHub::addPackage(const QString &name, const QString &version, const QString &title, const QString &description, const QStringList &dependencies, const QStringList &autoDependencies, bool forcedInstallation, bool virtualComp, quint64 uncompressedSize, const QString &inheritVersionFrom, bool checkable, bool expandedByDefault) { // TODO: This somewhat unexpected, remove? if (d->m_packageInfoMap.contains(name)) { // TODO: What about the other fields, update? d->m_packageInfoMap[name].version = version; d->m_packageInfoMap[name].lastUpdateDate = QDate::currentDate(); } else { LocalPackage info; info.name = name; info.version = version; info.inheritVersionFrom = inheritVersionFrom; info.installDate = QDate::currentDate(); info.title = title; info.description = description; info.dependencies = dependencies; info.autoDependencies = autoDependencies; info.forcedInstallation = forcedInstallation; info.virtualComp = virtualComp; info.uncompressedSize = uncompressedSize; info.checkable = checkable; info.expandedByDefault = expandedByDefault; d->m_packageInfoMap.insert(name, info); } d->modified = true; } /*! Removes the package specified by \a name. Returns \c false if the package is not found. */ bool LocalPackageHub::removePackage(const QString &name) { if (d->m_packageInfoMap.remove(name) <= 0) return false; d->modified = true; return true; } static void addTextChildHelper(QDomNode *node, const QString &tag, const QString &text, const QString &attributeName = QString(), const QString &attributeValue = QString()) { QDomElement domElement = node->ownerDocument().createElement(tag); QDomText domText = node->ownerDocument().createTextNode(text); domElement.appendChild(domText); if (!attributeName.isEmpty()) domElement.setAttribute(attributeName, attributeValue); node->appendChild(domElement); } /*! Writes the installation information file to disk. */ void LocalPackageHub::writeToDisk() { if (d->modified && (!d->m_packageInfoMap.isEmpty() || QFile::exists(d->fileName))) { QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("Packages")) ; doc.appendChild(root); addTextChildHelper(&root, QLatin1String("ApplicationName"), d->applicationName); addTextChildHelper(&root, QLatin1String("ApplicationVersion"), d->applicationVersion); Q_FOREACH (const LocalPackage &info, d->m_packageInfoMap) { QDomElement package = doc.createElement(QLatin1String("Package")); addTextChildHelper(&package, QLatin1String("Name"), info.name); addTextChildHelper(&package, QLatin1String("Title"), info.title); addTextChildHelper(&package, QLatin1String("Description"), info.description); if (info.inheritVersionFrom.isEmpty()) addTextChildHelper(&package, QLatin1String("Version"), info.version); else addTextChildHelper(&package, QLatin1String("Version"), info.version, QLatin1String("inheritVersionFrom"), info.inheritVersionFrom); addTextChildHelper(&package, QLatin1String("LastUpdateDate"), info.lastUpdateDate .toString(Qt::ISODate)); addTextChildHelper(&package, QLatin1String("InstallDate"), info.installDate .toString(Qt::ISODate)); addTextChildHelper(&package, QLatin1String("Size"), QString::number(info.uncompressedSize)); if (info.dependencies.count()) addTextChildHelper(&package, scDependencies, info.dependencies.join(QLatin1String(","))); if (info.autoDependencies.count()) addTextChildHelper(&package, scAutoDependOn, info.autoDependencies.join(QLatin1String(","))); if (info.forcedInstallation) addTextChildHelper(&package, QLatin1String("ForcedInstallation"), QLatin1String("true")); if (info.virtualComp) addTextChildHelper(&package, QLatin1String("Virtual"), QLatin1String("true")); if (info.checkable) addTextChildHelper(&package, QLatin1String("Checkable"), QLatin1String("true")); if (info.expandedByDefault) addTextChildHelper(&package, QLatin1String("ExpandedByDefault"), QLatin1String("true")); root.appendChild(package); } // Open Packages.xml QFile file(d->fileName); if (!file.open(QFile::WriteOnly)) return; file.write(doc.toByteArray(4)); file.close(); // Write permissions for installation information file QInstaller::setDefaultFilePermissions( &file, DefaultFilePermissions::NonExecutable); d->modified = false; } } void LocalPackageHub::PackagesInfoData::addPackageFrom(const QDomElement &packageE) { if (packageE.isNull()) return; QDomNodeList childNodes = packageE.childNodes(); if (childNodes.count() == 0) return; LocalPackage info; info.forcedInstallation = false; info.virtualComp = false; info.checkable = false; info.expandedByDefault = false; for (int i = 0; i < childNodes.count(); i++) { QDomNode childNode = childNodes.item(i); QDomElement childNodeE = childNode.toElement(); if (childNodeE.isNull()) continue; if (childNodeE.tagName() == QLatin1String("Name")) info.name = childNodeE.text(); else if (childNodeE.tagName() == QLatin1String("Title")) info.title = childNodeE.text(); else if (childNodeE.tagName() == QLatin1String("Description")) info.description = childNodeE.text(); else if (childNodeE.tagName() == QLatin1String("Version")) { info.version = childNodeE.text(); info.inheritVersionFrom = childNodeE.attribute(QLatin1String("inheritVersionFrom")); } else if (childNodeE.tagName() == QLatin1String("Virtual")) info.virtualComp = childNodeE.text().toLower() == QLatin1String("true") ? true : false; else if (childNodeE.tagName() == QLatin1String("Size")) info.uncompressedSize = childNodeE.text().toULongLong(); else if (childNodeE.tagName() == QLatin1String("Dependencies")) { info.dependencies = childNodeE.text().split(QInstaller::commaRegExp(), QString::SkipEmptyParts); } else if (childNodeE.tagName() == QLatin1String("AutoDependOn")) { info.autoDependencies = childNodeE.text().split(QInstaller::commaRegExp(), QString::SkipEmptyParts); } else if (childNodeE.tagName() == QLatin1String("ForcedInstallation")) info.forcedInstallation = childNodeE.text().toLower() == QLatin1String( "true" ) ? true : false; else if (childNodeE.tagName() == QLatin1String("LastUpdateDate")) info.lastUpdateDate = QDate::fromString(childNodeE.text(), Qt::ISODate); else if (childNodeE.tagName() == QLatin1String("InstallDate")) info.installDate = QDate::fromString(childNodeE.text(), Qt::ISODate); else if (childNodeE.tagName() == QLatin1String("Checkable")) info.checkable = childNodeE.text().toLower() == QLatin1String("true") ? true : false; else if (childNodeE.tagName() == QLatin1String("ExpandedByDefault")) info.expandedByDefault = childNodeE.text().toLower() == QLatin1String("true") ? true : false; } m_packageInfoMap.insert(info.name, info); } /*! Clears the installed package list. */ void LocalPackageHub::clearPackageInfos() { d->m_packageInfoMap.clear(); d->modified = true; } /*! \inmodule kdupdater \class KDUpdater::LocalPackage \brief The LocalPackage class describes a single installed package in the application. This class contains information about a single installed package in the application. The information contained in this class corresponds to the information described by the <Package> XML element in the installation information XML file. */ /*! \variable LocalPackage::name \brief The name of the package. */ /*! \variable LocalPackage::title */ /*! \variable LocalPackage::description */ /*! \variable LocalPackage::version */ /*! \variable LocalPackage::lastUpdateDate */ /*! \variable LocalPackage::installDate */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/localpackagehub.h�������������������������������������0100777�0000000�0000000�00000006750�13761647206�021565� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LOCALPACKAGEHUB_H #define LOCALPACKAGEHUB_H #include "updater.h" #include <QCoreApplication> #include <QDate> #include <QStringList> namespace KDUpdater { struct KDTOOLS_EXPORT LocalPackage { QString name; QString title; QString description; QString version; QString inheritVersionFrom; QStringList dependencies; QStringList autoDependencies; QDate lastUpdateDate; QDate installDate; bool forcedInstallation; bool virtualComp; quint64 uncompressedSize; bool checkable; bool expandedByDefault; }; class KDTOOLS_EXPORT LocalPackageHub { Q_DISABLE_COPY(LocalPackageHub) Q_DECLARE_TR_FUNCTIONS(LocalPackageHub) public: LocalPackageHub(); ~LocalPackageHub(); enum Error { NoError = 0, NotYetReadError, CouldNotReadPackageFileError, InvalidXmlError, InvalidContentError }; bool isValid() const; QStringList packageNames() const; Error error() const; QString errorString() const; QString fileName() const; void setFileName(const QString &fileName); QString applicationName() const; void setApplicationName(const QString &name); QString applicationVersion() const; void setApplicationVersion(const QString &version); void clearPackageInfos(); int packageInfoCount() const; QList<LocalPackage> packageInfos() const; LocalPackage packageInfo(const QString &pkgName) const; void addPackage(const QString &pkgName, const QString &version, // mandatory const QString &title, const QString &description, const QStringList &dependencies, const QStringList &autoDependencies, bool forcedInstallation, bool virtualComp, quint64 uncompressedSize, const QString &inheritVersionFrom, bool checkable, bool expandedByDefault); bool removePackage(const QString &pkgName); void refresh(); void writeToDisk(); private: struct PackagesInfoData; PackagesInfoData *d; }; } // KDUpdater #endif // LOCALPACKAGEHUB_H ������������������������qt-installer-framework-4.0.1/src/libs/kdtools/lockfile.cpp������������������������������������������0100777�0000000�0000000�00000003250�13761647206�020573� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lockfile.h" #include "lockfile_p.h" namespace KDUpdater { LockFile::LockFile(const QString &name) : d(new Private(name)) { } LockFile::~LockFile() { delete d; } bool LockFile::lock() { return d->lock(); } QString LockFile::errorString() const { return d->errorString; } bool LockFile::unlock() { return d->unlock(); } } // namespace KDUpdater ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/lockfile.h��������������������������������������������0100777�0000000�0000000�00000003260�13761647206�020241� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LOCKFILE_H #define LOCKFILE_H #include "kdtoolsglobal.h" namespace KDUpdater { class KDTOOLS_EXPORT LockFile { Q_DISABLE_COPY(LockFile) public: explicit LockFile(const QString &name); ~LockFile(); QString errorString() const; bool lock(); bool unlock(); private: class Private; Private *d; }; } // namespace KDUpdater #endif // LOCKFILE_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/lockfile_p.h������������������������������������������0100777�0000000�0000000�00000003507�13761647206�020564� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LOCKFILE_P_H #define LOCKFILE_P_H #include "lockfile.h" #include <QString> #ifdef Q_OS_WIN # include <qt_windows.h> #endif namespace KDUpdater { class LockFile::Private { public: explicit Private(const QString& name) : filename(name) , handle(0) , locked(false) {} bool lock(); bool unlock(); QString errorString; private: QString filename; #ifdef Q_OS_WIN HANDLE handle; #else int handle; #endif bool locked; }; } // namespace KDUpdater #endif // LOCKFILE_P_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/lockfile_unix.cpp�������������������������������������0100777�0000000�0000000�00000006361�13761647206�021644� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lockfile_p.h" #include <QCoreApplication> #include <QDir> #include <cerrno> #include <sys/file.h> #include <unistd.h> namespace KDUpdater { bool LockFile::Private::lock() { if (locked) return true; errorString.clear(); errno = 0; handle = open(filename.toLatin1().constData(), O_CREAT | O_RDWR | O_NONBLOCK, 0600); if (handle == -1) { errorString = QCoreApplication::translate("LockFile", "Cannot create lock file \"%1\": " "%2").arg(QDir::toNativeSeparators(filename), QString::fromLocal8Bit(strerror(errno))); return false; } const QString pid = QString::number(qApp->applicationPid()); const QByteArray data = pid.toLatin1(); errno = 0; qint64 written = 0; while (written < data.size()) { const qint64 n = write(handle, data.constData() + written, data.size() - written); if (n < 0) { errorString = QCoreApplication::translate("LockFile", "Cannot write PID to lock " "file \"%1\": %2").arg(QDir::toNativeSeparators(filename), QString::fromLocal8Bit(strerror(errno))); return false; } written += n; } errno = 0; locked = flock(handle, LOCK_NB | LOCK_EX) != -1; if (!locked) { errorString = QCoreApplication::translate("LockFile", "Cannot obtain the lock for " "file \"%1\": %2").arg(QDir::toNativeSeparators(filename), QString::fromLocal8Bit(strerror(errno))); } return locked; } bool LockFile::Private::unlock() { errorString.clear(); if (!locked) return true; errno = 0; locked = flock(handle, LOCK_UN | LOCK_NB) == -1; if (locked) { errorString = QCoreApplication::translate("LockFile", "Cannot release the lock for " "file \"%1\": %2").arg(QDir::toNativeSeparators(filename), QString::fromLocal8Bit(strerror(errno))); } else { unlink(filename.toLatin1()); } return !locked; } } // namespace KDUpdater �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/lockfile_win.cpp��������������������������������������0100777�0000000�0000000�00000006542�13761647206�021457� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lockfile.h" #include "lockfile_p.h" #include "utils.h" #include <QCoreApplication> #include <QDir> #include <QFileInfo> namespace KDUpdater { bool LockFile::Private::lock() { if (locked) return locked; errorString.clear(); handle = CreateFile(filename.toStdWString().data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, QFileInfo(filename).exists() ? OPEN_EXISTING : CREATE_NEW, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); if (handle == INVALID_HANDLE_VALUE) { errorString = QCoreApplication::translate("LockFile", "Cannot create lock file \"%1\": " "%2").arg(QDir::toNativeSeparators(filename), QInstaller::windowsErrorString(GetLastError())); return false; } DWORD bytesWritten; const QByteArray pid = QString::number(QCoreApplication::applicationPid()).toLatin1(); if (!WriteFile(handle, pid.data(), pid.size(), &bytesWritten, NULL)) { errorString = QCoreApplication::translate("LockFile", "Cannot write PID to lock file " "\"%1\": %2").arg(QDir::toNativeSeparators(filename), QInstaller::windowsErrorString(GetLastError())); return false; } FlushFileBuffers(handle); if (!::LockFile(handle, 0, 0, QFileInfo(filename).size(), 0)) { errorString = QCoreApplication::translate("LockFile", "Cannot obtain the lock for " "file \"%1\": %2").arg(QDir::toNativeSeparators(filename), QInstaller::windowsErrorString(GetLastError())); } else { locked = true; } return locked; } bool LockFile::Private::unlock() { errorString.clear(); if (!locked) return true; if (!UnlockFile(handle, 0, 0, QFileInfo(filename).size(), 0)) { errorString = QCoreApplication::translate("LockFile", "Cannot release the lock for " "file \"%1\": %2").arg(QDir::toNativeSeparators(filename), QInstaller::windowsErrorString(GetLastError())); } else { locked = false; CloseHandle(handle); } return !locked; } } // namespace KDUpdater ��������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/runoncechecker.cpp������������������������������������0100777�0000000�0000000�00000006121�13761647206�022001� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "runoncechecker.h" #include "lockfile.h" #include "sysinfo.h" #include "globals.h" #include <QCoreApplication> #include <QDebug> #include <QDir> #include <QFileInfo> #include <QList> #include <algorithm> using namespace KDUpdater; RunOnceChecker::RunOnceChecker(const QString &filename) : m_lockfile(filename) { } RunOnceChecker::~RunOnceChecker() { if (!m_lockfile.unlock()) qCWarning(QInstaller::lcInstallerInstallLog).noquote() << m_lockfile.errorString(); } class ProcessnameEquals { public: ProcessnameEquals(const QString &name) #ifdef Q_OS_WIN : m_name(name.toLower()) #else : m_name(name) #endif {} bool operator()(const ProcessInfo &info) { #ifdef Q_OS_WIN const QString infoName = info.name.toLower(); if (infoName == QDir::toNativeSeparators(m_name)) return true; #else const QString infoName = info.name; #endif if (infoName == m_name) return true; const QFileInfo fi(infoName); if (fi.fileName() == m_name || fi.baseName() == m_name) return true; return false; } private: QString m_name; }; bool RunOnceChecker::isRunning(RunOnceChecker::ConditionFlags flags) { if (flags.testFlag(ConditionFlag::ProcessList)) { const QList<ProcessInfo> allProcesses = runningProcesses(); const int count = std::count_if(allProcesses.constBegin(), allProcesses.constEnd(), ProcessnameEquals(QCoreApplication::applicationFilePath())); return (count > 1); } if (flags.testFlag(ConditionFlag::Lockfile)) { const bool locked = m_lockfile.lock(); if (!locked) qCWarning(QInstaller::lcInstallerInstallLog).noquote() << m_lockfile.errorString(); return !locked; } return false; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/runoncechecker.h��������������������������������������0100777�0000000�0000000�00000003514�13761647206�021451� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef RUNONCECHECKER_H #define RUNONCECHECKER_H #include "lockfile.h" #include <QString> class KDTOOLS_EXPORT RunOnceChecker { Q_DISABLE_COPY(RunOnceChecker) public: enum struct ConditionFlag { Lockfile = 0x01, ProcessList = 0x02 }; Q_DECLARE_FLAGS(ConditionFlags, ConditionFlag) explicit RunOnceChecker(const QString &filename = QString()); ~RunOnceChecker(); bool isRunning(RunOnceChecker::ConditionFlags flags); private: KDUpdater::LockFile m_lockfile; }; #endif // RUNONCECHECKER_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/selfrestarter.cpp�������������������������������������0100777�0000000�0000000�00000005577�13761647206�021706� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "selfrestarter.h" #include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QProcess> class SelfRestarter::Private { public: Private(int argc, char *argv[]) : restartOnQuit(false) { executable = QString::fromLocal8Bit(argv[0]); workingPath = QDir::currentPath(); for (int i = 1; i < argc; ++i) args << QString::fromLocal8Bit(argv[i]); } Private() { executable = qApp->applicationFilePath(); workingPath = QDir::currentPath(); args = qApp->arguments().mid(1); } ~Private() { if (restartOnQuit) QProcess::startDetached(executable, args, workingPath); } QString executable; QStringList args; bool restartOnQuit; QString workingPath; static SelfRestarter *instance; }; SelfRestarter *SelfRestarter::Private::instance = 0; SelfRestarter::SelfRestarter(int argc, char *argv[]) : d(new Private(argc, argv)) { Q_ASSERT_X(!Private::instance, Q_FUNC_INFO, "Cannot create more than one SelfRestarter instance"); Private::instance = this; } SelfRestarter::~SelfRestarter() { Q_ASSERT_X(Private::instance == this, Q_FUNC_INFO, "Cannot create more than one SelfRestarter instance"); delete d; Private::instance = 0; } void SelfRestarter::setRestartOnQuit(bool restart) { Q_ASSERT_X(Private::instance, Q_FUNC_INFO, "SelfRestarter instance must be created in main()"); if (Private::instance) Private::instance->d->restartOnQuit = restart; } bool SelfRestarter::restartOnQuit() { return Private::instance ? Private::instance->d->restartOnQuit : false; } ���������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/selfrestarter.h���������������������������������������0100777�0000000�0000000�00000003174�13761647206�021342� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SELFRESTARTER_H #define SELFRESTARTER_H #include "kdtoolsglobal.h" class KDTOOLS_EXPORT SelfRestarter { public: SelfRestarter(int argc, char *argv[]); ~SelfRestarter(); static bool restartOnQuit(); static void setRestartOnQuit(bool restart); private: Q_DISABLE_COPY(SelfRestarter) class Private; Private *d; }; #endif // SELFRESTARTER_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/sysinfo.cpp�������������������������������������������0100777�0000000�0000000�00000010611�13761647206�020474� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sysinfo.h" #include <QtCore/QDebug> #include <QtCore/QDir> using namespace KDUpdater; struct PathLongerThan { bool operator()(const VolumeInfo &lhs, const VolumeInfo &rhs) const { return lhs.mountPath().length() > rhs.mountPath().length(); } }; VolumeInfo::VolumeInfo() : m_size(0) , m_availableSize(0) { } VolumeInfo VolumeInfo::fromPath(const QString &path) { QDir targetPath(QDir::cleanPath(path)); QList<VolumeInfo> volumes = mountedVolumes(); // sort by length to get the longest mount point (not just "/") first std::sort(volumes.begin(), volumes.end(), PathLongerThan()); foreach (const VolumeInfo &volume, volumes) { const QDir volumePath(volume.mountPath()); if (targetPath == volumePath) return volume; #ifdef Q_OS_WIN if (QDir::toNativeSeparators(path).toLower().startsWith(volume.mountPath().toLower())) #else // we need to take some care here, as canonical path might return an empty string if the target // does not exist yet if (targetPath.exists()) { // the target exist, we can solve the path and if it fits return if (targetPath.canonicalPath().startsWith(volume.mountPath())) return volume; continue; } // the target directory does not exist yet, we need to cd up till we find the first existing dir QStringList parts = targetPath.absolutePath().split(QDir::separator(),QString::SkipEmptyParts); while (targetPath.absolutePath() != QDir::rootPath()) { if (targetPath.exists()) break; parts.pop_back(); if (parts.isEmpty()) targetPath = QDir(QDir::rootPath()); else targetPath = QDir(QLatin1Char('/') + parts.join(QDir::separator())); } if (targetPath.canonicalPath().startsWith(volume.mountPath())) #endif return volume; } return VolumeInfo(); } QString VolumeInfo::mountPath() const { return m_mountPath; } void VolumeInfo::setMountPath(const QString &path) { m_mountPath = path; } QString VolumeInfo::fileSystemType() const { return m_fileSystemType; } void VolumeInfo::setFileSystemType(const QString &type) { m_fileSystemType = type; } QString VolumeInfo::volumeDescriptor() const { return m_volumeDescriptor; } void VolumeInfo::setVolumeDescriptor(const QString &descriptor) { m_volumeDescriptor = descriptor; } quint64 VolumeInfo::size() const { return m_size; } void VolumeInfo::setSize(const quint64 &size) { m_size = size; } quint64 VolumeInfo::availableSize() const { return m_availableSize; } void VolumeInfo::setAvailableSize(const quint64 &available) { m_availableSize = available; } bool VolumeInfo::operator==(const VolumeInfo &other) const { return m_volumeDescriptor == other.m_volumeDescriptor; } QDebug operator<<(QDebug dbg, const VolumeInfo &volume) { return dbg << "KDUpdater::Volume(" << volume.mountPath() << ")"; } QDebug operator<<(QDebug dbg, ProcessInfo process) { return dbg << "KDUpdater::ProcessInfo(" << process.id << ", " << process.name << ")"; } �����������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/sysinfo.h���������������������������������������������0100777�0000000�0000000�00000005100�13761647206�020136� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSINFO_H #define SYSINFO_H #include "kdtoolsglobal.h" #include <QtCore/QString> namespace KDUpdater { class KDTOOLS_EXPORT VolumeInfo { public: VolumeInfo(); static VolumeInfo fromPath(const QString &path); QString mountPath() const; void setMountPath(const QString &path); QString fileSystemType() const; void setFileSystemType(const QString &type); QString volumeDescriptor() const; void setVolumeDescriptor(const QString &descriptor); quint64 size() const; void setSize(const quint64 &size); quint64 availableSize() const; void setAvailableSize(const quint64 &available); bool operator==(const VolumeInfo &other) const; private: QString m_mountPath; QString m_fileSystemType; QString m_volumeDescriptor; quint64 m_size; quint64 m_availableSize; }; struct ProcessInfo { quint32 id; QString name; }; quint64 installedMemory(); QList<VolumeInfo> mountedVolumes(); QList<ProcessInfo> runningProcesses(); bool killProcess(const ProcessInfo &process, int msecs = 30000); bool pathIsOnLocalDevice(const QString &path); } // namespace KDUpdater QT_BEGIN_NAMESPACE class QDebug; QT_END_NAMESPACE QDebug operator<<(QDebug dbg, KDUpdater::VolumeInfo volume); QDebug operator<<(QDebug dbg, KDUpdater::ProcessInfo process); #endif // SYSINFO_H ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/sysinfo_mac.cpp���������������������������������������0100777�0000000�0000000�00000011247�13761647206�021322� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sysinfo.h" #include <Carbon/Carbon.h> #include <sys/mount.h> #include <sys/sysctl.h> #include <sys/types.h> #include <QtCore/QList> namespace KDUpdater { quint64 installedMemory() { SInt32 mb = 0; Gestalt(gestaltPhysicalRAMSizeInMegabytes, &mb); return quint64(static_cast<quint64>(mb) * 1024LL * 1024LL); } QList<VolumeInfo> mountedVolumes() { QList<VolumeInfo> result; FSVolumeRefNum volume; FSVolumeInfo info; HFSUniStr255 volName; FSRef ref; int i = 0; while (FSGetVolumeInfo(kFSInvalidVolumeRefNum, ++i, &volume, kFSVolInfoFSInfo, &info, &volName, &ref) == 0) { UInt8 path[PATH_MAX + 1]; if (FSRefMakePath(&ref, path, PATH_MAX) == 0) { FSGetVolumeInfo(volume, 0, 0, kFSVolInfoSizes, &info, 0, 0); VolumeInfo v; v.setSize(quint64(info.totalBytes)); v.setAvailableSize(quint64(info.freeBytes)); v.setMountPath(QString::fromLocal8Bit(reinterpret_cast< char* >(path))); struct statfs data; if (statfs(qPrintable(v.mountPath() + QLatin1String("/.")), &data) == 0) { v.setFileSystemType(QLatin1String(data.f_fstypename)); v.setVolumeDescriptor(QLatin1String(data.f_mntfromname)); } result.append(v); } } return result; } QList<ProcessInfo> runningProcesses() { int mib[4] = { CTL_KERN, KERN_ARGMAX, 0, 0 }; int argMax = 0; size_t argMaxSize = sizeof(argMax); // fetch the maximum process arguments size sysctl(mib, 2, &argMax, &argMaxSize, NULL, 0); char *processArguments = (char*) malloc(argMax); mib[1] = KERN_PROC; mib[2] = KERN_PROC_ALL; size_t processTableSize = 0; // fetch the kernel process table size sysctl(mib, 4, NULL, &processTableSize, NULL, 0); struct kinfo_proc *processTable = (kinfo_proc*) malloc(processTableSize); // fetch the process table sysctl(mib, 4, processTable, &processTableSize, NULL, 0); QList<ProcessInfo> processes; for (size_t i = 0; i < (processTableSize / sizeof(struct kinfo_proc)); ++i) { struct kinfo_proc *process = processTable + i; ProcessInfo processInfo; processInfo.id = process->kp_proc.p_pid; mib[1] = KERN_PROCARGS2; mib[2] = process->kp_proc.p_pid; mib[3] = 0; size_t size = argMax; // fetch the process arguments if (sysctl(mib, 3, processArguments, &size, NULL, 0) != -1) { /* * |-----------------| <-- data returned by sysctl() * | argc | * |-----------------| * | executable path | * |-----------------| * | arguments | * ~~~~~~~~~~~~~~~~~~~ * |-----------------| */ processInfo.name = QString::fromLocal8Bit(processArguments + sizeof(int)); } else { // if we fail, use the name from the process table processInfo.name = QString::fromLocal8Bit(process->kp_proc.p_comm); } processes.append(processInfo); } free(processTable); free(processArguments); return processes; } bool pathIsOnLocalDevice(const QString &path) { Q_UNUSED(path); return true; } bool killProcess(const ProcessInfo &process, int msecs) { Q_UNUSED(process); Q_UNUSED(msecs); return true; } } // namespace KDUpdater ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/sysinfo_x11.cpp���������������������������������������0100777�0000000�0000000�00000011400�13761647206�021162� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sysinfo.h" #include <sys/utsname.h> #include <sys/statvfs.h> #ifdef Q_OS_FREEBSD #include <sys/types.h> #include <sys/sysctl.h> #endif #include <QtCore/QFile> #include <QtCore/QTextStream> #include <QtCore/QDir> #include <QtCore/QFileInfo> #include <QtCore/QRegExp> namespace KDUpdater { /*! Returns the amount of memory installed on a system. */ quint64 installedMemory() { #ifdef Q_OS_LINUX QFile f(QLatin1String("/proc/meminfo")); f.open(QIODevice::ReadOnly); QTextStream stream(&f); while (true) { const QString s = stream.readLine(); if( !s.startsWith(QLatin1String("MemTotal:" ))) continue; else if (s.isEmpty()) return quint64(); const QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts); return quint64(parts.at(1).toInt() * 1024LL); } #else quint64 physmem; size_t len = sizeof physmem; #ifdef Q_OS_FREEBSD static int mib[2] = { CTL_HW, HW_PHYSMEM }; #else static int mib[2] = { CTL_HW, HW_MEMSIZE }; #endif sysctl(mib, 2, &physmem, &len, 0, 0); return quint64(physmem); #endif return 0; } /*! Returns currently mounted volumes as list of the \c VolumeInfo objects. */ QList<VolumeInfo> mountedVolumes() { QList<VolumeInfo> result; QFile f(QLatin1String("/etc/mtab")); if (!f.open(QIODevice::ReadOnly)) { qCritical("%s: Cannot open %s: %s", Q_FUNC_INFO, qPrintable(f.fileName()), qPrintable(f.errorString())); return result; //better error-handling? } QTextStream stream(&f); while (true) { const QString s = stream.readLine(); if (s.isNull()) return result; if (!s.startsWith(QLatin1Char('/')) && !s.startsWith(QLatin1String("tmpfs ") + QDir::tempPath())) continue; const QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts); VolumeInfo v; v.setMountPath(parts.at(1)); v.setVolumeDescriptor(parts.at(0)); v.setFileSystemType(parts.value(2)); struct statvfs data; if (statvfs(qPrintable(v.mountPath() + QLatin1String("/.")), &data) == 0) { v.setSize(quint64(static_cast<quint64>(data.f_blocks) * data.f_bsize)); v.setAvailableSize(quint64(static_cast<quint64>(data.f_bavail) * data.f_bsize)); } result.append(v); } return result; } /*! Returns a list of currently running processes. */ QList<ProcessInfo> runningProcesses() { QList<ProcessInfo> processes; QDir procDir(QLatin1String("/proc")); const QFileInfoList procCont = procDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable); QRegExp validator(QLatin1String("[0-9]+")); Q_FOREACH (const QFileInfo &info, procCont) { if (validator.exactMatch(info.fileName())) { const QString linkPath = QDir(info.absoluteFilePath()).absoluteFilePath(QLatin1String("exe")); const QFileInfo linkInfo(linkPath); if (linkInfo.exists()) { ProcessInfo processInfo; processInfo.name = linkInfo.symLinkTarget(); processInfo.id = info.fileName().toInt(); processes.append(processInfo); } } } return processes; } /*! \internal */ bool pathIsOnLocalDevice(const QString &path) { Q_UNUSED(path); return true; } /*! \internal */ bool killProcess(const ProcessInfo &process, int msecs) { Q_UNUSED(process); Q_UNUSED(msecs); return true; } } // namespace KDUpdater ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/task.cpp����������������������������������������������0100777�0000000�0000000�00000024147�13761647206�017755� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "task.h" #include "globals.h" using namespace KDUpdater; /*! \inmodule kdupdater \class KDUpdater::Task \brief The Task class is the base class for all tasks in KDUpdater. This class is the base class for all task classes in KDUpdater. Task is an activity that occupies certain amount of execution time. It can be started, stopped (or canceled), paused and resumed. Tasks can report progress and error messages which an application can show in any sort of UI. The KDUpdater::Task class provides a common interface for dealing with all kinds of tasks in KDUpdater. User should be careful of these points: \list \li Task classes can be started only once. \li Instances of this class cannot be created. Only instances of the subclasses can. \endlist */ /*! \enum Task::Capability This enum value sets the capabilities of the task. \value NoCapability The task has no capabilities, so it cannot be paused or stopped. \value Pausable The task can be paused. \value Stoppable The task can be stopped. */ /*! \internal */ KDUpdater::Task::Task(const QString &name, int caps, QObject *parent) : QObject(parent) , m_caps(caps) , m_name(name) , m_errorCode(0) , m_started(false) , m_finished(false) , m_paused(false) , m_stopped(false) , m_progressPc(0) , m_autoDelete(true) { } /*! \internal */ Task::~Task() {} /*! Returns the name of the task. */ QString Task::name() const { return m_name; } /*! Returns the capabilities of the task. It is a combination of one or more Task::Capability flags. */ int Task::capabilities() const { return m_caps; } /*! Returns the last reported error code. */ int Task::error() const { return m_errorCode; } /*! Returns the last reported error message text. */ QString Task::errorString() const { return m_errorText; } /*! Returns whether the task has started and is running. */ bool Task::isRunning() const { return m_started; } /*! Returns whether the task has finished or not. \note Stopped (or canceled) tasks are not finished tasks. */ bool Task::isFinished() const { return m_finished; } /*! Returns whether the task is paused or not. */ bool Task::isPaused() const { return m_paused; } /*! Returns whether the task is stopped or not. \note Finished tasks are not stopped classes. */ bool Task::isStopped() const { return m_stopped; } /*! Returns the progress in percentage made by this task. */ int Task::progressPercent() const { return m_progressPc; } /*! Returns a string that describes the progress made by this task as a string. */ QString Task::progressText() const { return m_progressText; } /*! Starts the task. */ void Task::run() { if (m_started) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to start an already started task"; return; } if (m_stopped) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to start a finished or canceled task"; return; } m_stopped = false; m_finished = false; // for the sake of completeness m_started = true; emit started(); reportProgress(0, tr("%1 started").arg(m_name)); doRun(); } /*! Stops the task, provided the task has the Task::Stoppable capability. \note Once the task is stopped, it cannot be restarted. */ void Task::stop() { if (!(m_caps & Stoppable)) { const QString errorMsg = tr("%1 cannot be stopped").arg(m_name); reportError(ECannotStopTask, errorMsg); return; } if (!m_started) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to stop an unstarted task"; return; } if(m_finished || m_stopped) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to stop a finished or canceled task"; return; } m_stopped = doStop(); if (!m_stopped) { const QString errorMsg = tr("Cannot stop task %1").arg(m_name); reportError(ECannotStopTask, errorMsg); return; } m_started = false; // the task is not running m_finished = false; // the task is not finished, but was canceled half-way through emit stopped(); if (m_autoDelete) deleteLater(); } /*! Pauses the task, provided the task has the Task::Pausable capability. */ void Task::pause() { if (!(m_caps & Pausable)) { const QString errorMsg = tr("%1 cannot be paused").arg(m_name); reportError(ECannotPauseTask, errorMsg); return; } if (!m_started) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to pause an unstarted task"; return; } if (m_finished || m_stopped) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to pause a finished or canceled task"; return; } m_paused = doPause(); if (!m_paused) { const QString errorMsg = tr("Cannot pause task %1").arg(m_name); reportError(ECannotPauseTask, errorMsg); return; } // The task state has to be started, paused but not finished or stopped. // We need not set the flags below, but just in case. // Perhaps we should do Q_ASSERT() ??? m_started = true; m_finished = false; m_stopped = false; emit paused(); } /*! Resumes the task if it was paused. */ void Task::resume() { if (!m_paused) { qCDebug(QInstaller::lcInstallerInstallLog) << "Trying to resume an unpaused task"; return; } const bool val = doResume(); if (!val) { const QString errorMsg = tr("Cannot resume task %1").arg(m_name); reportError(ECannotResumeTask, errorMsg); return; } // The task state should be started, but not paused, finished or stopped. // We need not set the flags below, but just in case. // Perhaps we should do Q_ASSERT() ??? m_started = true; m_paused = false; m_finished = false; m_stopped = false; emit resumed(); } /*! \internal */ void Task::reportProgress(int percent, const QString &text) { if (m_progressPc == percent) return; m_progressPc = percent; m_progressText = text; emit progressValue(m_progressPc); emit progressText(m_progressText); } /*! \internal */ void Task::reportError(int errorCode, const QString &errorText) { m_errorCode = errorCode; m_errorText = errorText; emit error(m_errorCode, m_errorText); if (m_autoDelete) deleteLater(); } /*! \internal */ void Task::reportError(const QString &errorText) { reportError(EUnknown, errorText); } /*! \internal */ void Task::reportDone() { QString msg = tr("%1 done"); reportProgress(100, msg); // State should be finished, but not started, paused or stopped. m_finished = true; m_started = false; m_paused = false; m_stopped = false; m_errorCode = 0; m_errorText.clear(); emit finished(); if (m_autoDelete) deleteLater(); } /*! Returns \c true if the task will be automatically deleted. */ bool Task::autoDelete() const { return m_autoDelete; } /*! Automatically deletes the task if \a autoDelete is \c true. */ void Task::setAutoDelete(bool autoDelete) { m_autoDelete = autoDelete; } /*! \fn virtual void KDUpdater::Task::doRun() = 0; Returns \c 0 if the task is run. */ /*! \fn virtual bool KDUpdater::Task::doStop() = 0; Returns \c true if the task is stopped. */ /*! \fn virtual bool KDUpdater::Task::doPause() = 0; Returns \c true if the task is paused. */ /*! \fn virtual bool KDUpdater::Task::doResume() = 0; Returns \c true if the task is resumed. */ /*! \fn void KDUpdater::Task::error(int code, const QString &errorText) This signal is emitted to notify an error during the execution of this task. The \a code parameter indicates the error that was found during the execution of the task, while the \a errorText is the human-readable description of the last error that occurred. */ /*! \fn void KDUpdater::Task::progressValue(int percent) This signal is emitted to report progress made by the task. The \a percent parameter gives the progress made as a percentage. */ /*! \fn void KDUpdater::Task::progressText(const QString &progressText) This signal is emitted to report the progress made by the task. The \a progressText parameter represents the progress made in a human-readable form. */ /*! \fn void KDUpdater::Task::started() This signal is emitted when the task has started. */ /*! \fn void KDUpdater::Task::paused() This signal is emitted when the task has paused. */ /*! \fn void KDUpdater::Task::resumed() This signal is emitted when the task has resumed. */ /*! \fn void KDUpdater::Task::stopped() This signal is emitted when the task has stopped (or canceled). */ /*! \fn void KDUpdater::Task::finished() This signal is emitted when the task has finished. */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/task.h������������������������������������������������0100777�0000000�0000000�00000005720�13761647206�017416� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TASK_H #define TASK_H #include "updater.h" #include <QObject> namespace KDUpdater { class KDTOOLS_EXPORT Task : public QObject { Q_OBJECT public: enum Capability { NoCapability = 0, Pausable = 1, Stoppable = 2 }; virtual ~Task(); QString name() const; int capabilities() const; int error() const; QString errorString() const; bool isRunning() const; bool isFinished() const; bool isPaused() const; bool isStopped() const; int progressPercent() const; QString progressText() const; bool autoDelete() const; void setAutoDelete(bool autoDelete); public Q_SLOTS: void run(); void stop(); void pause(); void resume(); Q_SIGNALS: void error(int code, const QString &errorText); void progressValue(int percent); void progressText(const QString &progressText); void started(); void paused(); void resumed(); void stopped(); void finished(); protected: explicit Task(const QString &name, int caps = NoCapability, QObject *parent = 0); void reportProgress(int percent, const QString &progressText); void reportError(int errorCode, const QString &errorText); void reportError(const QString &errorText); void reportDone(); // Task interface virtual void doRun() = 0; virtual bool doStop() = 0; virtual bool doPause() = 0; virtual bool doResume() = 0; private: int m_caps; QString m_name; int m_errorCode; QString m_errorText; bool m_started; bool m_finished; bool m_paused; bool m_stopped; int m_progressPc; QString m_progressText; bool m_autoDelete; }; } // namespace KDUpdater #endif // TASK_H ������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/update.cpp��������������������������������������������0100777�0000000�0000000�00000004234�13761647206�020270� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "update.h" using namespace KDUpdater; /*! \inmodule kdupdater \class KDUpdater::Update \brief Represents a single update. The KDUpdater::Update class contains information about an update. It is created by KDUpdater::UpdateFinder corresponding to the update. The constructor of the KDUpdater::Update class is made protected, because it can be instantiated only by KDUpdater::UpdateFinder (which is a friend class). The destructor however is public. */ /*! \internal */ Update::Update(const QInstaller::PackageSource &packageSource, const UpdateInfo &updateInfo) : m_packageSource(packageSource) , m_updateInfo(updateInfo) { } /*! Returns the data specified by \a name, or an invalid \a defaultValue if the data does not exist. */ QVariant Update::data(const QString &name, const QVariant &defaultValue) const { return m_updateInfo.data.value(name, defaultValue); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/update.h����������������������������������������������0100777�0000000�0000000�00000003521�13761647206�017733� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATE_H #define UPDATE_H #include "packagesource.h" #include "updatesinfo_p.h" #include <QVariant> namespace KDUpdater { class Update { public: QVariant data(const QString &name, const QVariant &defaultValue = QVariant()) const; QInstaller::PackageSource packageSource() const {return m_packageSource; } private: friend class UpdateFinder; Update(const QInstaller::PackageSource &packageSource, const UpdateInfo &updateInfo); private: QInstaller::PackageSource m_packageSource; UpdateInfo m_updateInfo; }; } // namespace KDUpdater #endif // UPDATE_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updatefinder.cpp��������������������������������������0100777�0000000�0000000�00000051762�13761647206�021470� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "updatefinder.h" #include "update.h" #include "filedownloader.h" #include "filedownloaderfactory.h" #include "updatesinfo_p.h" #include "localpackagehub.h" #include "fileutils.h" #include "globals.h" #include <QCoreApplication> #include <QFileInfo> #include <QRegExp> using namespace KDUpdater; using namespace QInstaller; /*! \inmodule kdupdater \class KDUpdater::UpdateFinder \brief The UpdaterFinder class finds updates applicable for installed packages. The KDUpdater::UpdateFinder class helps in searching for updates and installing them on the application. The class basically processes the application's KDUpdater::PackagesInfo and the UpdateXMLs it aggregates from all the update sources and populates a list of KDUpdater::Update objects. */ // // Private // class UpdateFinder::Private { public: enum struct Resolution { AddPackage, KeepExisting, RemoveExisting }; Private(UpdateFinder *qq) : q(qq) , downloadCompleteCount(0) , m_downloadsToComplete(0) {} ~Private() { clear(); } struct Data { Data() : downloader(0) {} Data(const PackageSource &i, FileDownloader *d = 0) : info(i), downloader(d) {} PackageSource info; FileDownloader *downloader; }; UpdateFinder *q; QHash<QString, Update *> updates; // Temporary structure that notes down information about updates. bool cancel; int downloadCompleteCount; int m_downloadsToComplete; QHash<UpdatesInfo *, Data> m_updatesInfoList; void clear(); void computeUpdates(); void cancelComputeUpdates(); bool downloadUpdateXMLFiles(); bool computeApplicableUpdates(); QList<UpdateInfo> applicableUpdates(UpdatesInfo *updatesInfo); void createUpdateObjects(const PackageSource &source, const QList<UpdateInfo> &updateInfoList); Resolution checkPriorityAndVersion(const PackageSource &source, const QVariantHash &data) const; void slotDownloadDone(); QSet<PackageSource> packageSources; std::weak_ptr<LocalPackageHub> m_localPackageHub; }; static int computeProgressPercentage(int min, int max, int percent) { return min + qint64(max-min) * percent / 100; } static int computePercent(int done, int total) { return total ? done * Q_INT64_C(100) / total : 0 ; } /*! \internal Releases all internal resources consumed while downloading and computing updates. */ void UpdateFinder::Private::clear() { qDeleteAll(updates); updates.clear(); const QList<Data> values = m_updatesInfoList.values(); foreach (const Data &data, values) delete data.downloader; qDeleteAll(m_updatesInfoList.keys()); m_updatesInfoList.clear(); downloadCompleteCount = 0; m_downloadsToComplete = 0; } /*! \internal This method computes the updates that can be applied on the application by studying the application's KDUpdater::PackagesInfo object and the UpdateXML files from each of the update sources described in QInstaller::PackageSource. This function can take a long time to complete. The following signals are emitted during the execution of this function The function creates KDUpdater::Update objects on the stack. All KDUpdater::Update objects are made children of the application associated with this finder. The update sources are fetched from the QInstaller::PackageSource object associated with the application. Package information is extracted from the KDUpdater::PackagesInfo object associated with the application. \note Each time this function is called, all the previously computed updates are discarded and its resources are freed. */ void UpdateFinder::Private::computeUpdates() { // Computing updates is done in two stages // 1. Downloading Update XML files from all the update sources // 2. Matching updates with Package XML and figuring out available updates if (!q->isCompressedPackage()) clear(); cancel = false; // First do some quick sanity checks on the packages info std::shared_ptr<LocalPackageHub> packages = m_localPackageHub.lock(); if (!packages) { q->reportError(tr("Cannot access the package information of this application.")); return; } if (!packages->isValid()) { q->reportError(packages->errorString()); return; } // Now do some quick sanity checks on the package sources. if (packageSources.count() <= 0) { q->reportError(tr("No package sources set for this application.")); return; } // Now we can start... // Step 1: 0 - 49 percent if (!downloadUpdateXMLFiles() || cancel) { clear(); return; } // Step 2: 50 - 100 percent if (!computeApplicableUpdates() || cancel) { clear(); return; } // All done q->reportProgress(100, tr("%n update(s) found.", "", updates.count())); q->reportDone(); } /*! \internal Cancels the computation of updates. \sa computeUpdates() */ void UpdateFinder::Private::cancelComputeUpdates() { cancel = true; } /*! \internal This function downloads Updates.xml from all the update sources except local files. A single application can potentially have several update sources, hence we need to be asynchronous in downloading updates from different sources. The function basically does this for each update source: a) Create a KDUpdater::FileDownloader and KDUpdater::UpdatesInfo for each update b) Triggers the download of Updates.xml from each file downloader. c) The downloadCompleted(), downloadCanceled() and downloadAborted() signals are connected in each of the downloaders. Once all the downloads are complete and/or aborted, the next stage would be done. The function gets into an event loop until all the downloads are complete. */ bool UpdateFinder::Private::downloadUpdateXMLFiles() { // create UpdatesInfo for each update source foreach (const PackageSource &info, packageSources) { const QUrl url = QString::fromLatin1("%1/Updates.xml").arg(info.url.toString()); if (url.scheme() != QLatin1String("resource") && url.scheme() != QLatin1String("file")) { // create FileDownloader (except for local files and resources) FileDownloader *downloader = FileDownloaderFactory::instance().create(url.scheme(), q); if (!downloader) break; downloader->setUrl(url); downloader->setAutoRemoveDownloadedFile(true); connect(downloader, SIGNAL(downloadCanceled()), q, SLOT(slotDownloadDone())); connect(downloader, SIGNAL(downloadCompleted()), q, SLOT(slotDownloadDone())); connect(downloader, SIGNAL(downloadAborted(QString)), q, SLOT(slotDownloadDone())); m_updatesInfoList.insert(new UpdatesInfo, Data(info, downloader)); } else { UpdatesInfo *updatesInfo = new UpdatesInfo; updatesInfo->setFileName(QInstaller::pathFromUrl(url)); m_updatesInfoList.insert(updatesInfo, Data(info)); } } // Trigger download of Updates.xml file downloadCompleteCount = 0; m_downloadsToComplete = 0; foreach (const Data &data, m_updatesInfoList) { if (data.downloader) { m_downloadsToComplete++; data.downloader->download(); } } // Wait until all downloaders have completed their downloads. while (true) { QCoreApplication::processEvents(); if (cancel) return false; if (downloadCompleteCount == m_downloadsToComplete) break; q->reportProgress(computePercent(downloadCompleteCount, m_downloadsToComplete), tr("Downloading Updates.xml from update sources.")); } // Setup the update info objects with the files from download. foreach (UpdatesInfo *updatesInfo, m_updatesInfoList.keys()) { const Data data = m_updatesInfoList.value(updatesInfo); if (data.downloader) { if (!data.downloader->isDownloaded()) { q->reportError(tr("Cannot download package source %1 from \"%2\".").arg(data .downloader->url().fileName(), data.info.url.toString())); } else { updatesInfo->setFileName(data.downloader->downloadedFileName()); } } } // Remove all invalid update info objects. QMutableHashIterator<UpdatesInfo *, Data> it(m_updatesInfoList); while (it.hasNext()) { UpdatesInfo *info = it.next().key(); if (info->isValid()) continue; q->reportError(info->errorString()); delete info; it.remove(); } if (m_updatesInfoList.isEmpty()) return false; q->reportProgress(49, tr("Updates.xml file(s) downloaded from update sources.")); return true; } /*! \internal This function runs through all the KDUpdater::UpdatesInfo objects created during the downloadUpdateXMLFiles() method and compares it with the data contained in KDUpdater::PackagesInfo. Thereby figures out whether an update is applicable for this application or not. */ bool UpdateFinder::Private::computeApplicableUpdates() { int i = 0; foreach (UpdatesInfo *updatesInfo, m_updatesInfoList.keys()) { // Fetch updates applicable to this application. QList<UpdateInfo> updates = applicableUpdates(updatesInfo); if (!updates.count()) continue; if (cancel) return false; const PackageSource updateSource = m_updatesInfoList.value(updatesInfo).info; // Create Update objects for updates that have a valid // UpdateFile createUpdateObjects(updateSource, updates); if (cancel) return false; // Report progress q->reportProgress(computeProgressPercentage(51, 100, computePercent(i, m_updatesInfoList.count())), tr("Computing applicable updates.")); ++i; } q->reportProgress(99, tr("Application updates computed.")); return true; } QList<UpdateInfo> UpdateFinder::Private::applicableUpdates(UpdatesInfo *updatesInfo) { const QList<UpdateInfo> dummy; if (!updatesInfo || updatesInfo->updateInfoCount() == 0) return dummy; std::shared_ptr<LocalPackageHub> packages = m_localPackageHub.lock(); if (!packages) return dummy; // Check to see if the updates info contains updates for any application if (updatesInfo->applicationName() != QLatin1String("{AnyApplication}")) { // updatesInfo->applicationName() describes one application or a series of // application names separated by commas. QString appName = updatesInfo->applicationName(); appName = appName.replace(QLatin1String( ", " ), QLatin1String( "," )); appName = appName.replace(QLatin1String( " ," ), QLatin1String( "," )); // Catch hold of app names contained updatesInfo->applicationName() // If the application appName isn't one of the app names, then the updates are not applicable. const QStringList apps = appName.split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (apps.indexOf([&packages] { return packages->isValid() ? packages->applicationName() : QCoreApplication::applicationName(); } ()) < 0) { return dummy; } } return updatesInfo->updatesInfo(); } void UpdateFinder::Private::createUpdateObjects(const PackageSource &source, const QList<UpdateInfo> &updateInfoList) { foreach (const UpdateInfo &info, updateInfoList) { const Resolution value = checkPriorityAndVersion(source, info.data); if (value == Resolution::KeepExisting) continue; const QString name = info.data.value(QLatin1String("Name")).toString(); if (value == Resolution::RemoveExisting) delete updates.take(name); // Create and register the update if (!q->isCompressedPackage() || value == Resolution::AddPackage) updates.insert(name, new Update(source, info)); } } /* If a package of the same name exists, always use the one with the higher version. If the new package has the same version but a higher priority, use the new new package, otherwise keep the already existing package. */ UpdateFinder::Private::Resolution UpdateFinder::Private::checkPriorityAndVersion( const PackageSource &source, const QVariantHash &newPackage) const { const QString name = newPackage.value(QLatin1String("Name")).toString(); if (Update *existingPackage = updates.value(name)) { // Bingo, package was previously found elsewhere. const int match = compareVersion(newPackage.value(QLatin1String("Version")).toString(), existingPackage->data(QLatin1String("Version")).toString()); if (match > 0) { // new package has higher version, use qCDebug(QInstaller::lcDeveloperBuild).nospace() << "Remove Package 'Name: " << name << ", Version: "<< existingPackage->data(QLatin1String("Version")).toString() << ", Source: " << QFileInfo(existingPackage->packageSource().url.toLocalFile()).fileName() << "' found a package with higher version 'Name: " << name << ", Version: " << newPackage.value(QLatin1String("Version")).toString() << ", Source: " << QFileInfo(source.url.toLocalFile()).fileName() << "'"; return Resolution::RemoveExisting; } if ((match == 0) && (source.priority > existingPackage->packageSource().priority)) { // new package version equals but priority is higher, use qCDebug(QInstaller::lcDeveloperBuild).nospace() << "Remove Package 'Name: " << name << ", Priority: " << existingPackage->packageSource().priority << ", Source: " << QFileInfo(existingPackage->packageSource().url.toLocalFile()).fileName() << "' found a package with higher priority 'Name: " << name << ", Priority: " << source.priority << ", Source: " << QFileInfo(source.url.toLocalFile()).fileName() << "'"; return Resolution::RemoveExisting; } if (q->isCompressedPackage() && match == 0 && source.priority == existingPackage->packageSource().priority) { //Same package with the same priority and version already exists return Resolution::RemoveExisting; } return Resolution::KeepExisting; // otherwise keep existing } return Resolution::AddPackage; } // // UpdateFinder // /*! Constructs an update finder. */ UpdateFinder::UpdateFinder() : Task(QLatin1String("UpdateFinder"), Stoppable), m_compressedPackage(false), d(new Private(this)) { } /*! Destructor */ UpdateFinder::~UpdateFinder() { delete d; } /*! Returns a list of KDUpdater::Update objects. */ QList<Update *> UpdateFinder::updates() const { return d->updates.values(); } void UpdateFinder::setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub) { d->m_localPackageHub = std::move(hub); } /*! Sets the package \a sources information when searching for applicable packages. */ void UpdateFinder::setPackageSources(const QSet<PackageSource> &sources) { d->packageSources = sources; } /*! \internal Implemented from KDUpdater::Task::doRun(). */ void UpdateFinder::doRun() { d->computeUpdates(); } /*! \internal Implemented from KDUpdater::Task::doStop(). */ bool UpdateFinder::doStop() { d->cancelComputeUpdates(); // Wait until the cancel has actually happened, and then return. // Thinking of using QMutex for this. Frank/Till any suggestions? return true; } /*! \internal Implemented from KDUpdater::Task::doStop(). */ bool UpdateFinder::doPause() { // Not a pausable task return false; } /*! \internal Implemented from KDUpdater::Task::doStop(). */ bool UpdateFinder::doResume() { // Not a pausable task, hence it is not resumable as well return false; } /*! \internal */ void UpdateFinder::Private::slotDownloadDone() { ++downloadCompleteCount; int pc = computePercent(downloadCompleteCount, m_downloadsToComplete); pc = computeProgressPercentage(0, 45, pc); q->reportProgress( pc, tr("Downloading Updates.xml from update sources.") ); } /*! \inmodule kdupdater This function compares two version strings \a v1 and \a v2 and returns -1, 0 or +1 based on the following rule \list \li Returns 0 if v1 == v2 \li Returns -1 if v1 < v2 \li Returns +1 if v1 > v2 \endlist The function is very similar to \c strcmp(), except that it works on version strings. Example: \code KDUpdater::compareVersion("2.0", "2.1"); // Returns -1 KDUpdater::compareVersion("2.1", "2.0"); // Returns +1 KDUpdater::compareVersion("2.0", "2.0"); // Returns 0 KDUpdater::compareVersion("2.1", "2.1"); // Returns 0 KDUpdater::compareVersion("2.0", "2.x"); // Returns 0 KDUpdater::compareVersion("2.x", "2.0"); // Returns 0 KDUpdater::compareVersion("2.0.12.4", "2.1.10.4"); // Returns -1 KDUpdater::compareVersion("2.0.12.x", "2.0.x"); // Returns 0 KDUpdater::compareVersion("2.1.12.x", "2.0.x"); // Returns +1 KDUpdater::compareVersion("2.1.12.x", "2.x"); // Returns 0 KDUpdater::compareVersion("2.x", "2.1.12.x"); // Returns 0 \endcode */ int KDUpdater::compareVersion(const QString &v1, const QString &v2) { // For tests refer VersionCompareFnTest testcase. // Check for equality if (v1 == v2) return 0; // Split version components across ".", "-" or "_" QStringList v1_comps = v1.split(QRegExp(QLatin1String( "\\.|-|_"))); QStringList v2_comps = v2.split(QRegExp(QLatin1String( "\\.|-|_"))); // Check each component of the version int index = 0; while (true) { bool v1_ok = false; bool v2_ok = false; if (index == v1_comps.count() && index < v2_comps.count()) { v2_comps.at(index).toLongLong(&v2_ok); return v2_ok ? -1 : +1; } if (index < v1_comps.count() && index == v2_comps.count()) { v1_comps.at(index).toLongLong(&v1_ok); return v1_ok ? +1 : -1; } if (index >= v1_comps.count() || index >= v2_comps.count()) break; qlonglong v1_comp = v1_comps.at(index).toLongLong(&v1_ok); qlonglong v2_comp = v2_comps.at(index).toLongLong(&v2_ok); if (!v1_ok) { if (v1_comps.at(index) == QLatin1String("x")) return 0; } if (!v2_ok) { if (v2_comps.at(index) == QLatin1String("x")) return 0; } if (!v1_ok && !v2_ok) { // try remove equal start int i = 0; while (i < v1_comps.at(index).size() && i < v2_comps.at(index).size() && v1_comps.at(index).at(i) == v2_comps.at(index).at(i)) { ++i; } if (i > 0) { v1_comps[index] = v1_comps.at(index).mid(i); v2_comps[index] = v2_comps.at(index).mid(i); // compare again continue; } } if (!v1_ok || !v2_ok) { int res = v1_comps.at(index).compare(v2_comps.at(index)); if (res == 0) { // v1_comps.at(index) == v2_comps(index) ++index; continue; } return res > 0 ? +1 : -1; } if (v1_comp < v2_comp) return -1; if (v1_comp > v2_comp) return +1; // v1_comp == v2_comp ++index; } if (index < v2_comps.count()) return +1; if (index < v1_comps.count()) return -1; // Controversial return. I hope this never happens. return 0; } #include "moc_updatefinder.cpp" ��������������qt-installer-framework-4.0.1/src/libs/kdtools/updatefinder.h����������������������������������������0100777�0000000�0000000�00000004213�13761647206�021122� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATEFINDER_H #define UPDATEFINDER_H #include "task.h" #include "packagesource.h" #include <memory> namespace KDUpdater { class LocalPackageHub; class Update; class KDTOOLS_EXPORT UpdateFinder : public Task { Q_OBJECT class Private; public: UpdateFinder(); ~UpdateFinder(); QList<Update *> updates() const; void setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub); void setPackageSources(const QSet<QInstaller::PackageSource> &sources); void addCompressedPackage(bool add) { m_compressedPackage = add; } bool isCompressedPackage() { return m_compressedPackage; } private: void doRun(); bool doStop(); bool doPause(); bool doResume(); private: bool m_compressedPackage; Private *d; Q_PRIVATE_SLOT(d, void slotDownloadDone()) }; } // namespace KDUpdater #endif // UPDATEFINDER_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperation.cpp�����������������������������������0100777�0000000�0000000�00000041674�13761647206�022222� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "updateoperation.h" #include "constants.h" #include "fileutils.h" #include "packagemanagercore.h" #include "globals.h" #include <QDataStream> #include <QDebug> #include <QDir> #include <QFileInfo> #include <QTemporaryFile> using namespace KDUpdater; /*! \inmodule kdupdater \class KDUpdater::UpdateOperation \brief The UpdateOperation class is an abstract base class for update operations. The KDUpdater::UpdateOperation is an abstract class that specifies an interface for update operations. Concrete implementations of this class must perform a single update operation, such as copy, move, or delete. \note Two separate threads cannot be using a single instance of KDUpdater::UpdateOperation at the same time. */ /*! \enum UpdateOperation::Error This enum code specifies error codes related to operation arguments and operation runtime failures. \value NoError No error occurred. \value InvalidArguments Number of arguments does not match or an invalid argument was set. \value UserDefinedError An error occurred during operation run. Use UpdateOperation::errorString() to get the human-readable description of the error that occurred. */ /* \internal Returns a filename for a temporary file based on \a templateName. */ static QString backupFileName(const QString &templateName) { const QFileInfo templ(templateName); QTemporaryFile file( QDir::temp().absoluteFilePath(templ.fileName())); file.open(); const QString name = file.fileName(); file.close(); file.remove(); return name; } /*! \internal */ UpdateOperation::UpdateOperation(QInstaller::PackageManagerCore *core) : m_error(0) , m_core(core) { // Store the value for compatibility reasons. m_values[QLatin1String("installer")] = QVariant::fromValue(core); } /*! \internal */ UpdateOperation::~UpdateOperation() { if (auto *core = packageManager()) core->addFilesForDelayedDeletion(filesForDelayedDeletion()); } /*! Returns the update operation name. \sa setName() */ QString UpdateOperation::name() const { return m_name; } /*! Returns a command line string that describes the update operation. The returned string will be of the form: \c{<name> <arg1> <arg2> <arg3> ....} */ QString UpdateOperation::operationCommand() const { QString argsStr = m_arguments.join(QLatin1String( " " )); return QString::fromLatin1( "%1 %2" ).arg(m_name, argsStr); } /*! Returns \c true if a value called \a name exists, otherwise returns \c false. */ bool UpdateOperation::hasValue(const QString &name) const { return m_values.contains(name); } /*! Clears the value of \a name and removes it. */ void UpdateOperation::clearValue(const QString &name) { m_values.remove(name); } /*! Returns the value of \a name. If the value does not exist, returns an empty QVariant. */ QVariant UpdateOperation::value(const QString &name) const { return m_values.value(name); } /*! Sets the value of \a name to \a value. */ void UpdateOperation::setValue(const QString &name, const QVariant &value) { m_values[name] = value; } /*! Sets the name of the operation to \a name. Subclasses will have to provide a unique name to describe the operation. */ void UpdateOperation::setName(const QString &name) { m_name = name; } /*! Sets the arguments for the update operation to \a args. */ void UpdateOperation::setArguments(const QStringList &args) { m_arguments = args; } /*! Returns the arguments of the update operation. */ QStringList UpdateOperation::arguments() const { return m_arguments; } /*! Returns \c true if the argument count is within limits of \a minArgCount and \a maxArgCount. \a argDescription contains information about the expected form. */ bool UpdateOperation::checkArgumentCount(int minArgCount, int maxArgCount, const QString &argDescription) { const int argCount = arguments().count(); if (argCount < minArgCount || argCount > maxArgCount) { setError(InvalidArguments); QString countRange; if (minArgCount == maxArgCount) countRange = tr("exactly %1").arg(minArgCount); else if (maxArgCount == INT_MAX) countRange = tr("at least %1").arg(minArgCount); else if (minArgCount == 0) countRange = tr("not more than %1").arg(maxArgCount); else if (minArgCount == maxArgCount - 1) countRange = tr("%1 or %2").arg(minArgCount).arg(maxArgCount); else countRange = tr("%1 to %2").arg(minArgCount).arg(maxArgCount); if (argDescription.isEmpty()) setErrorString(tr("Invalid arguments in %1: %n arguments given, " "%2 arguments expected.", 0, argCount) .arg(name(), countRange)); else setErrorString(tr("Invalid arguments in %1: %n arguments given, " "%2 arguments expected in the form: %3.", 0, argCount) .arg(name(), countRange, argDescription)); return false; } return true; } /*! Returns \c true if the argument count is exactly \a argCount. */ bool UpdateOperation::checkArgumentCount(int argCount) { return checkArgumentCount(argCount, argCount); } struct StartsWith { StartsWith(const QString &searchTerm) : m_searchTerm(searchTerm) {} bool operator()(const QString &searchString) { return searchString.startsWith(m_searchTerm); } QString m_searchTerm; }; /*! Searches the arguments for the key specified by \a key. If it can find the key, it returns the value set for it. Otherwise, it returns \a defaultValue. Arguments are specified in the following form: \c{key=value}. */ QString UpdateOperation::argumentKeyValue(const QString &key, const QString &defaultValue) const { const QString keySeparater(key + QLatin1String("=")); const QStringList tArguments(arguments()); QStringList::const_iterator it = std::find_if(tArguments.begin(), tArguments.end(), StartsWith(keySeparater)); if (it == tArguments.end()) return defaultValue; const QString value = it->mid(keySeparater.size()); it = std::find_if(++it, tArguments.end(), StartsWith(keySeparater)); if (it != tArguments.end()) { qCWarning(QInstaller::lcInstallerInstallLog).nospace() << "There are multiple keys in the arguments calling " << name() << ". " << "Only the first found " << key << " is used: " << arguments().join(QLatin1String("; ")); } return value; } /*! Returns a human-readable description of the last error that occurred. */ QString UpdateOperation::errorString() const { return m_errorString; } /*! Returns the error that was found during the processing of the operation. If no error was found, returns NoError. Subclasses can set more detailed error codes (optional). \note To check if an operation was successful, use the return value of performOperation(), undoOperation(), or testOperation(). */ int UpdateOperation::error() const { return m_error; } /*! Sets the human-readable description of the last error that occurred to \a str. */ void UpdateOperation::setErrorString(const QString &str) { m_errorString = str; } /*! Sets the error condition to be \a error. The human-readable message is set to \a errorString. \sa UpdateOperation::error() \sa UpdateOperation::errorString() */ void UpdateOperation::setError(int error, const QString &errorString) { m_error = error; if (!errorString.isNull()) m_errorString = errorString; } /*! Clears the previously set arguments. */ void UpdateOperation::clear() { m_arguments.clear(); } /*! Returns the list of files that are scheduled for later deletion. */ QStringList UpdateOperation::filesForDelayedDeletion() const { return m_delayedDeletionFiles; } /*! Returns the package manager core this operation belongs to. */ QInstaller::PackageManagerCore *UpdateOperation::packageManager() const { return m_core; } /*! Registers a list of \a files to be deleted later once the application was restarted and the file or files are not used anymore. */ void UpdateOperation::registerForDelayedDeletion(const QStringList &files) { m_delayedDeletionFiles << files; } /*! Tries to delete \a file. If \a file cannot be deleted, it is registered for delayed deletion. If a backup copy of the file cannot be created, returns \c false and displays the error message specified by \a errorString. */ bool UpdateOperation::deleteFileNowOrLater(const QString &file, QString *errorString) { if (file.isEmpty() || QFile::remove(file)) return true; if (!QFile::exists(file)) return true; const QString backup = backupFileName(file); QFile f(file); if (!f.rename(backup)) { if (errorString) *errorString = tr("Renaming file \"%1\" to \"%2\" failed: %3").arg( QDir::toNativeSeparators(file), QDir::toNativeSeparators(backup), f.errorString()); return false; } registerForDelayedDeletion(QStringList(backup)); return true; } /*! \fn virtual void KDUpdater::UpdateOperation::backup() = 0; Subclasses must implement this function to back up any data before performing the action. */ /*! \fn virtual bool KDUpdater::UpdateOperation::performOperation() = 0; Subclasses must implement this function to perform the update operation. Returns \c true if the operation is successful. */ /*! \fn virtual bool KDUpdater::UpdateOperation::undoOperation() = 0; Subclasses must implement this function to perform the undo of the update operation. Returns \c true if the operation is successful. */ /*! \fn virtual bool KDUpdater::UpdateOperation::testOperation() = 0; Subclasses must implement this function to perform the test operation. Returns \c true if the operation is successful. */ /*! Saves operation arguments and values as an XML document and returns the document. You can override this method to store your own extra-data. Extra-data can be any data that you need to store to perform or undo the operation. The default implementation is taking care of arguments and values set via UpdateOperation::setValue(). */ QDomDocument UpdateOperation::toXml() const { QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("operation")); doc.appendChild(root); QDomElement args = doc.createElement(QLatin1String("arguments")); const QString target = m_core ? m_core->value(QInstaller::scTargetDir) : QString(); Q_FOREACH (const QString &s, arguments()) { QDomElement arg = doc.createElement(QLatin1String("argument")); arg.appendChild(doc.createTextNode(QInstaller::replacePath(s, target, QLatin1String(QInstaller::scRelocatable)))); args.appendChild(arg); } root.appendChild(args); if (m_values.isEmpty()) return doc; // append all values set with setValue QDomElement values = doc.createElement(QLatin1String("values")); for (QVariantMap::const_iterator it = m_values.constBegin(); it != m_values.constEnd(); ++it) { // the installer can't be put into XML, ignore if (it.key() == QLatin1String("installer")) continue; QDomElement value = doc.createElement(QLatin1String("value")); QVariant variant = it.value(); value.setAttribute(QLatin1String("name"), it.key()); value.setAttribute(QLatin1String("type"), QLatin1String(variant.typeName())); if (variant.type() != QVariant::List && variant.type() != QVariant::StringList && variant.canConvert(QVariant::String)) { // it can convert to string? great! value.appendChild(doc.createTextNode(QInstaller::replacePath(variant.toString(), target, QLatin1String(QInstaller::scRelocatable)))); } else { // no? then we have to go the hard way... if (variant.type() == QVariant::StringList) { QStringList list = variant.toStringList(); for (int i = 0; i < list.count(); ++i) { list[i] = QInstaller::replacePath(list.at(i), target, QLatin1String(QInstaller::scRelocatable)); } variant = QVariant::fromValue(list); } QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << variant; value.appendChild(doc.createTextNode(QLatin1String( data.toBase64().data()))); } values.appendChild(value); } root.appendChild(values); return doc; } /*! Restores operation arguments and values from the XML document \a doc. Returns \c true on success, otherwise \c false. \note: Clears all previously set values and arguments. */ bool UpdateOperation::fromXml(const QDomDocument &doc) { QString target = QCoreApplication::applicationDirPath(); // Does not change target on non macOS platforms. if (QInstaller::isInBundle(target, &target)) target = QDir::cleanPath(target + QLatin1String("/..")); QStringList args; const QDomElement root = doc.documentElement(); const QDomElement argsElem = root.firstChildElement(QLatin1String("arguments")); Q_ASSERT(! argsElem.isNull()); for (QDomNode n = argsElem.firstChild(); ! n.isNull(); n = n.nextSibling()) { const QDomElement e = n.toElement(); if (!e.isNull() && e.tagName() == QLatin1String("argument")) { args << QInstaller::replacePath(e.text(), QLatin1String(QInstaller::scRelocatable), target); } } setArguments(args); m_values.clear(); const QDomElement values = root.firstChildElement(QLatin1String("values")); for (QDomNode n = values.firstChild(); !n.isNull(); n = n.nextSibling()) { const QDomElement v = n.toElement(); if (v.isNull() || v.tagName() != QLatin1String("value")) continue; const QString name = v.attribute(QLatin1String("name")); const QString type = v.attribute(QLatin1String("type")); const QString value = v.text(); const QVariant::Type t = QVariant::nameToType(type.toLatin1().data()); QVariant var = qVariantFromValue(value); if (t == QVariant::List || t == QVariant::StringList || !var.convert(t)) { QDataStream stream(QByteArray::fromBase64( value.toLatin1())); stream >> var; if (t == QVariant::StringList) { QStringList list = var.toStringList(); for (int i = 0; i < list.count(); ++i) { list[i] = QInstaller::replacePath(list.at(i), QLatin1String(QInstaller::scRelocatable), target); } var = QVariant::fromValue(list); } } else if (t == QVariant::String) { const QString str = QInstaller::replacePath(value, QLatin1String(QInstaller::scRelocatable), target); var = QVariant::fromValue(str); } m_values[name] = var; } return true; } /*! \overload Restores operation arguments and values from the XML file at path \a xml. Returns \c true on success, otherwise \c false. */ bool UpdateOperation::fromXml(const QString &xml) { QDomDocument doc; QString errorMsg; int errorLine; int errorColumn; if (!doc.setContent( xml, &errorMsg, &errorLine, &errorColumn)) { qCWarning(QInstaller::lcInstallerInstallLog) << "Error parsing xml error=" << errorMsg << "line=" << errorLine << "column=" << errorColumn; return false; } return fromXml(doc); } ��������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperation.h�������������������������������������0100777�0000000�0000000�00000006635�13761647206�021665� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATEOPERATION_H #define UPDATEOPERATION_H #include "updater.h" #include <QCoreApplication> #include <QStringList> #include <QVariant> #include <QtXml/QDomDocument> namespace QInstaller { class PackageManagerCore; } namespace KDUpdater { class KDTOOLS_EXPORT UpdateOperation { Q_DECLARE_TR_FUNCTIONS(UpdateOperation) public: enum Error { NoError = 0, InvalidArguments = 1, UserDefinedError = 128 }; explicit UpdateOperation(QInstaller::PackageManagerCore *core); virtual ~UpdateOperation(); QString name() const; QString operationCommand() const; bool hasValue(const QString &name) const; void clearValue(const QString &name); QVariant value(const QString &name) const; void setValue(const QString &name, const QVariant &value); void setArguments(const QStringList &args); QStringList arguments() const; QString argumentKeyValue(const QString & key, const QString &defaultValue = QString()) const; void clear(); QString errorString() const; int error() const; QStringList filesForDelayedDeletion() const; QInstaller::PackageManagerCore *packageManager() const; virtual void backup() = 0; virtual bool performOperation() = 0; virtual bool undoOperation() = 0; virtual bool testOperation() = 0; virtual QDomDocument toXml() const; virtual bool fromXml(const QString &xml); virtual bool fromXml(const QDomDocument &doc); protected: void setName(const QString &name); void setErrorString(const QString &errorString); void setError(int error, const QString &errorString = QString()); void registerForDelayedDeletion(const QStringList &files); bool deleteFileNowOrLater(const QString &file, QString *errorString = 0); bool checkArgumentCount(int minArgCount, int maxArgCount, const QString &argDescription = QString()); bool checkArgumentCount(int argCount); private: QString m_name; QStringList m_arguments; QString m_errorString; int m_error; QVariantMap m_values; QStringList m_delayedDeletionFiles; QInstaller::PackageManagerCore *m_core; }; } // namespace KDUpdater #endif // UPDATEOPERATION_H ���������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperationfactory.cpp����������������������������0100777�0000000�0000000�00000006536�13761647206�023610� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "updateoperationfactory.h" #include "packagemanagercore.h" #include "updateoperations.h" using namespace KDUpdater; /*! \inmodule kdupdater \class KDUpdater::UpdateOperationFactory \brief The UpdateOperationFactory class is used to create update operations based on their name. This class acts as a factory for \c KDUpdater::UpdateOperation. You can register one or more update operations with this factory and query operations based on their name. This class follows the singleton design pattern. Only one instance of this class can be created and its reference can be fetched from the instance() method. The following operations are registered by default: \list \li Copy operation \li Move operation \li Delete operation \li Mkdir operation \li Rmdir operation \li AppendFile operation \li PrependFile operation \endlist */ /*! \obsolete \fn void KDUpdater::UpdateOperationFactory::registerUpdateOperation(const QString &name) Registers a new update operation with the factory based on \a name. When create() is called with that \a name, the update operation is constructed using its default constructor. Deprecated. Use registerProduct() instead. */ /*! Returns the UpdateOperationFactory instance. The instance is created if needed. */ UpdateOperationFactory &UpdateOperationFactory::instance() { static UpdateOperationFactory theFactory; return theFactory; } /*! Constructor */ UpdateOperationFactory::UpdateOperationFactory() { // Register the default update operation set registerUpdateOperation<CopyOperation>(QLatin1String("Copy")); registerUpdateOperation<MoveOperation>(QLatin1String("Move")); registerUpdateOperation<DeleteOperation>(QLatin1String("Delete")); registerUpdateOperation<MkdirOperation>(QLatin1String("Mkdir")); registerUpdateOperation<RmdirOperation>(QLatin1String("Rmdir")); registerUpdateOperation<AppendFileOperation>(QLatin1String("AppendFile")); registerUpdateOperation<PrependFileOperation>(QLatin1String("PrependFile")); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperationfactory.h������������������������������0100777�0000000�0000000�00000003747�13761647206�023256� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATEOPERATIONFACTORY_H #define UPDATEOPERATIONFACTORY_H #include "genericfactory.h" #include "updater.h" namespace QInstaller { class PackageManagerCore; } namespace KDUpdater { class UpdateOperation; class KDTOOLS_EXPORT UpdateOperationFactory : public GenericFactory<UpdateOperation, QString, QInstaller::PackageManagerCore*> { Q_DISABLE_COPY(UpdateOperationFactory) public: static UpdateOperationFactory &instance(); template <class T> void registerUpdateOperation(const QString &name) { registerProduct<T>(name); } private: UpdateOperationFactory(); }; } // namespace KDUpdater #endif // UPDATEOPERATIONFACTORY_H �������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperations.cpp����������������������������������0100777�0000000�0000000�00000065214�13761647206�022401� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "updateoperations.h" #include "errors.h" #include "fileutils.h" #include "constants.h" #include "packagemanagercore.h" #include <QDir> #include <QFile> #include <QTextStream> #include <QTemporaryFile> #include <QFileInfo> #include <cerrno> using namespace KDUpdater; static QString errnoToQString(int error) { #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW) char msg[128]; if (strerror_s(msg, sizeof msg, error) != 0) return QString::fromLocal8Bit(msg); return QString(); #else return QString::fromLocal8Bit(strerror(error)); #endif } static bool removeDirectory(const QString &path, QString *errorString, bool force, const QStringList &ignoreFiles = QStringList()) { Q_ASSERT(errorString); QDir dir = path; const QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden); foreach (const QFileInfo &entry, entries) { if (entry.isDir() && (!entry.isSymLink())) removeDirectory(entry.filePath(), errorString, force, ignoreFiles); else if (ignoreFiles.contains(entry.absoluteFilePath())) continue; else if (force && (!QFile(entry.filePath()).remove())) return false; } // even remove some hidden, OS-created files in there QInstaller::removeSystemGeneratedFiles(path); errno = 0; const bool success = dir.rmdir(path); if (!success && (dir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden).count() == ignoreFiles.count())){ return true; } if (errno) *errorString = errnoToQString(errno); return success; } /* * \internal * Returns a filename for a temporary file based on \a templateName */ static QString backupFileName(const QString &templateName) { QTemporaryFile file(templateName); file.open(); const QString name = file.fileName(); file.close(); file.remove(); return name; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::CopyOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::CopyOperation \internal */ CopyOperation::CopyOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Copy")); } CopyOperation::~CopyOperation() { deleteFileNowOrLater(value(QLatin1String("backupOfExistingDestination")).toString()); } QString CopyOperation::sourcePath() { return arguments().first(); } QString CopyOperation::destinationPath() { QString destination = arguments().last(); // if the target is a directory use the source filename to complete the destination path if (QFileInfo(destination).isDir()) destination = QDir(destination).filePath(QFileInfo(sourcePath()).fileName()); return destination; } void CopyOperation::backup() { QString destination = destinationPath(); if (!QFile::exists(destination)) { clearValue(QLatin1String("backupOfExistingDestination")); return; } setValue(QLatin1String("backupOfExistingDestination"), backupFileName(destination)); // race condition: The backup file could get created by another process right now. But this is the same // in QFile::copy... if (!QFile::rename(destination, value(QLatin1String("backupOfExistingDestination")).toString())) setError(UserDefinedError, tr("Cannot backup file \"%1\".").arg(QDir::toNativeSeparators(destination))); } bool CopyOperation::performOperation() { // We need two args to complete the copy operation. First arg provides the complete file name of source // Second arg provides the complete file name of dest if (!checkArgumentCount(2)) return false; QString source = sourcePath(); QString destination = destinationPath(); QFile sourceFile(source); if (!sourceFile.exists()) { setError(UserDefinedError); setErrorString(tr("Cannot copy a non-existent file: %1").arg(QDir::toNativeSeparators(source))); return false; } // If destination file exists, we cannot use QFile::copy() because it does not overwrite an existing // file. So we remove the destination file. QFile destinationFile(destination); if (destinationFile.exists()) { if (!destinationFile.remove()) { setError(UserDefinedError); setErrorString(tr("Cannot remove file \"%1\": %2").arg( QDir::toNativeSeparators(destination), destinationFile.errorString())); return false; } } const bool copied = sourceFile.copy(destination); if (!copied) { setError(UserDefinedError); setErrorString(tr("Cannot copy file \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(source), QDir::toNativeSeparators(destination), sourceFile.errorString())); } return copied; } bool CopyOperation::undoOperation() { QString source = sourcePath(); QString destination = destinationPath(); // if the target is a directory use the source filename to complete the destination path if (QFileInfo(destination).isDir()) destination = destination + QDir::separator() + QFileInfo(source).fileName(); QFile destFile(destination); // first remove the dest if (destFile.exists() && !destFile.remove()) { setError(UserDefinedError, tr("Cannot delete file \"%1\": %2").arg( QDir::toNativeSeparators(destination), destFile.errorString())); return false; } // no backup was done: // the copy destination file wasn't existing yet - that's no error if (!hasValue(QLatin1String("backupOfExistingDestination"))) return true; QFile backupFile(value(QLatin1String("backupOfExistingDestination")).toString()); // otherwise we have to copy the backup back: const bool success = backupFile.rename(destination); if (!success) setError(UserDefinedError, tr("Cannot restore backup file into \"%1\": %2").arg( QDir::toNativeSeparators(destination), backupFile.errorString())); return success; } /*! \reimp */ QDomDocument CopyOperation::toXml() const { // we don't want to save the backupOfExistingDestination if (!hasValue(QLatin1String("backupOfExistingDestination"))) return UpdateOperation::toXml(); CopyOperation *const me = const_cast<CopyOperation *>(this); const QVariant v = value(QLatin1String("backupOfExistingDestination")); me->clearValue(QLatin1String("backupOfExistingDestination")); const QDomDocument xml = UpdateOperation::toXml(); me->setValue(QLatin1String("backupOfExistingDestination"), v); return xml; } bool CopyOperation::testOperation() { // TODO return true; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::MoveOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::MoveOperation \internal */ MoveOperation::MoveOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Move")); } MoveOperation::~MoveOperation() { deleteFileNowOrLater(value(QLatin1String("backupOfExistingDestination")).toString()); } void MoveOperation::backup() { const QString dest = arguments().last(); if (!QFile::exists(dest)) { clearValue(QLatin1String("backupOfExistingDestination")); return; } setValue(QLatin1String("backupOfExistingDestination"), backupFileName(dest)); // race condition: The backup file could get created by another process right now. But this is the same // in QFile::copy... if (!QFile::rename(dest, value(QLatin1String("backupOfExistingDestination")).toString())) setError(UserDefinedError, tr("Cannot backup file \"%1\".").arg(QDir::toNativeSeparators(dest))); } bool MoveOperation::performOperation() { // We need two args to complete the copy operation. // First arg provides the complete file name of // source, second arg provides the complete file name of dest if (!checkArgumentCount(2)) return false; const QStringList args = arguments(); const QString dest = args.at(1); // If destination file exists, then we cannot use QFile::copy() because it does not overwrite an existing // file. So we remove the destination file. if (QFile::exists(dest)) { QFile file(dest); if (!file.remove(dest)) { setError(UserDefinedError); setErrorString(tr("Cannot remove file \"%1\": %2").arg( QDir::toNativeSeparators(dest), file.errorString())); return false; } } // Copy source to destination. QFile file(args.at(0)); if (!file.copy(dest)) { setError(UserDefinedError); setErrorString(tr("Cannot copy file \"%1\" to \"%2\": %3").arg(QDir::toNativeSeparators(file.fileName()), QDir::toNativeSeparators(dest), file.errorString())); return false; } return deleteFileNowOrLater(file.fileName()); } bool MoveOperation::undoOperation() { const QStringList args = arguments(); const QString dest = args.last(); // first: copy back the destination to source QFile destF(dest); if (!destF.copy(args.first())) { setError(UserDefinedError, tr("Cannot copy file \"%1\" to \"%2\": %3").arg( QDir::toNativeSeparators(dest), QDir::toNativeSeparators(args.first()), destF.errorString())); return false; } // second: delete the move destination if (!deleteFileNowOrLater(dest)) { setError(UserDefinedError, tr("Cannot remove file \"%1\".").arg(QDir::toNativeSeparators(dest))); return false; } // no backup was done: // the move destination file wasn't existing yet - that's no error if (!hasValue(QLatin1String("backupOfExistingDestination"))) return true; // otherwise we have to copy the backup back: QFile backupF(value(QLatin1String("backupOfExistingDestination")).toString()); const bool success = backupF.rename(dest); if (!success) setError(UserDefinedError, tr("Cannot restore backup file for \"%1\": %2").arg( QDir::toNativeSeparators(dest), backupF.errorString())); return success; } bool MoveOperation::testOperation() { // TODO return true; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::DeleteOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::DeleteOperation \internal */ DeleteOperation::DeleteOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Delete")); } DeleteOperation::~DeleteOperation() { deleteFileNowOrLater(value(QLatin1String("backupOfExistingFile")).toString()); } void DeleteOperation::backup() { const QString fileName = arguments().first(); setValue(QLatin1String("backupOfExistingFile"), backupFileName(fileName)); QFile file(fileName); if (!file.copy(value(QLatin1String("backupOfExistingFile")).toString())) setError(UserDefinedError, tr("Cannot create backup of file \"%1\": %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); } bool DeleteOperation::performOperation() { // Requires only one parameter. That is the name of the file to remove. if (!checkArgumentCount(1)) return false; return deleteFileNowOrLater(arguments().at(0)); } bool DeleteOperation::undoOperation() { if (!hasValue(QLatin1String("backupOfExistingFile"))) return true; const QString fileName = arguments().first(); QFile backupF(value(QLatin1String("backupOfExistingFile")).toString()); const bool success = backupF.copy(fileName) && deleteFileNowOrLater(backupF.fileName()); if (!success) setError(UserDefinedError, tr("Cannot restore backup file for \"%1\": %2").arg( QDir::toNativeSeparators(fileName), backupF.errorString())); return success; } bool DeleteOperation::testOperation() { // TODO return true; } /*! \reimp */ QDomDocument DeleteOperation::toXml() const { // we don't want to save the backupOfExistingFile if (!hasValue(QLatin1String("backupOfExistingFile"))) return UpdateOperation::toXml(); DeleteOperation *const me = const_cast<DeleteOperation *>(this); const QVariant v = value(QLatin1String("backupOfExistingFile")); me->clearValue(QLatin1String("backupOfExistingFile")); const QDomDocument xml = UpdateOperation::toXml(); me->setValue(QLatin1String("backupOfExistingFile"), v); return xml; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::MkdirOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::MkdirOperation \internal */ MkdirOperation::MkdirOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Mkdir")); } void MkdirOperation::backup() { QString path = arguments().first(); path.replace(QLatin1Char('\\'), QLatin1Char('/')); QDir createdDir = QDir::root(); // find out, which part of the path is the first one we actually need to create int end = 0; while (true) { QString p = path.section(QLatin1Char('/'), 0, ++end); createdDir = QDir(p); if (!createdDir.exists()) break; if (p == path) { // everything did already exist -> nothing to do for us (nothing to revert then, either) createdDir = QDir::root(); break; } } setValue(QLatin1String("createddir"), createdDir.absolutePath()); } bool MkdirOperation::performOperation() { // Requires only one parameter. That is the path which should be created if (!checkArgumentCount(1)) return false; const QString dirName = arguments().at(0); const bool created = QDir::root().mkpath(dirName); if (!created) { setError(UserDefinedError); setErrorString(tr("Cannot create directory \"%1\": %2").arg( QDir::toNativeSeparators(dirName), tr("Unknown error."))); } return created; } bool MkdirOperation::undoOperation() { Q_ASSERT(arguments().count() == 1); QString createdDirValue = value(QLatin1String("createddir")).toString(); if (packageManager()) { createdDirValue = QInstaller::replacePath(createdDirValue, QLatin1String(QInstaller::scRelocatable), packageManager()->value(QInstaller::scTargetDir)); } if (createdDirValue.isEmpty()) createdDirValue = arguments().first(); QDir createdDir = QDir(createdDirValue); const bool forceremoval = QVariant(value(QLatin1String("forceremoval"))).toBool(); // Since refactoring we know the mkdir operation which is creating the target path. If we do a full // uninstall prevent removing the full path including target, instead remove the target only. (QTIFW-46) QStringList excludeFiles; if (hasValue(QLatin1String("uninstall-only")) && value(QLatin1String("uninstall-only")).toBool()) { createdDir = QDir(arguments().first()); // Do not try to remove maintenancetool in Windows as it will fail as it is running. // In Windows we use deferred delete for maintenancetool. #ifdef Q_OS_WIN if (packageManager()) excludeFiles << packageManager()->maintenanceToolName(); #endif } if (createdDir == QDir::root()) return true; if (!createdDir.exists()) return true; QString errorString; const bool result = removeDirectory(createdDir.path(), &errorString, forceremoval, excludeFiles); if (!result) { if (errorString.isEmpty()) setError(UserDefinedError, tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(createdDir.path()), errorString)); else setError(UserDefinedError, tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(createdDir.path()), errnoToQString(errno))); } return result; } bool KDUpdater::MkdirOperation::testOperation() { // TODO return true; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::RmdirOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::RmdirOperation \internal */ RmdirOperation::RmdirOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("Rmdir")); setValue(QLatin1String("removed"), false); } void RmdirOperation::backup() { // nothing to backup - rollback will just create the directory } bool RmdirOperation::performOperation() { // Requires only one parameter. That is the name of the file to remove. if (!checkArgumentCount(1)) return false; const QString firstArg = arguments().at(0); QDir dir(firstArg); if (!dir.exists()) { setError(UserDefinedError); setErrorString(tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(firstArg), tr("The directory does not exist."))); return false; } errno = 0; const bool removed = dir.rmdir(firstArg); setValue(QLatin1String("removed"), removed); if (!removed) { setError(UserDefinedError); setErrorString(tr("Cannot remove directory \"%1\": %2").arg( QDir::toNativeSeparators(firstArg), errnoToQString(errno))); } return removed; } bool RmdirOperation::undoOperation() { if (!value(QLatin1String("removed")).toBool()) return true; errno = 0; const QFileInfo fi(arguments().first()); const bool success = fi.dir().mkdir(fi.fileName()); if( !success) setError(UserDefinedError, tr("Cannot recreate directory \"%1\": %2").arg( QDir::toNativeSeparators(fi.fileName()), errnoToQString(errno))); return success; } bool RmdirOperation::testOperation() { // TODO return true; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::AppendFileOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::AppendFileOperation \internal */ AppendFileOperation::AppendFileOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("AppendFile")); } void AppendFileOperation::backup() { const QString filename = arguments().first(); QFile file(filename); if (!file.exists()) return; // nothing to backup setValue(QLatin1String("backupOfFile"), backupFileName(filename)); if (!file.copy(value(QLatin1String("backupOfFile")).toString())) { setError(UserDefinedError, tr("Cannot backup file \"%1\": %2").arg( QDir::toNativeSeparators(filename), file.errorString())); clearValue(QLatin1String("backupOfFile")); } } bool AppendFileOperation::performOperation() { // This operation takes two arguments. First argument is the name of the file into which a text has to be // appended. Second argument is the text to append. if (!checkArgumentCount(2)) return false; const QStringList args = this->arguments(); const QString fName = args.at(0); QFile file(fName); if (!file.open(QFile::Append)) { // first we rename the file, then we copy it to the real target and open the copy - the renamed original is then marked for deletion bool error = false; const QString newName = backupFileName(fName); if (!QFile::rename(fName, newName)) error = true; if (!error && !QFile::copy(newName, fName)) { error = true; QFile::rename(newName, fName); } if (!error && !file.open(QFile::Append)) { error = true; deleteFileNowOrLater(newName); } if (error) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(file.fileName()), file.errorString())); return false; } deleteFileNowOrLater(newName); } QTextStream ts(&file); ts << args.at(1); file.close(); return true; } bool AppendFileOperation::undoOperation() { // backupOfFile being empty -> file didn't exist before -> no error const QString filename = arguments().first(); const QString backupOfFile = value(QLatin1String("backupOfFile")).toString(); if (!backupOfFile.isEmpty() && !QFile::exists(backupOfFile)) { setError(UserDefinedError, tr("Cannot find backup file for \"%1\".").arg( QDir::toNativeSeparators(filename))); return false; } const bool removed = deleteFileNowOrLater(filename); if (!removed) { setError(UserDefinedError, tr("Cannot restore backup file for \"%1\".").arg( QDir::toNativeSeparators(filename))); return false; } // got deleted? We might be done, if it didn't exist before if (backupOfFile.isEmpty()) return true; QFile backupFile(backupOfFile); const bool success = backupFile.rename(filename); if (!success) setError(UserDefinedError, tr("Cannot restore backup file for \"%1\": %2").arg( QDir::toNativeSeparators(filename), backupFile.errorString())); return success; } bool AppendFileOperation::testOperation() { // TODO return true; } //////////////////////////////////////////////////////////////////////////// // KDUpdater::PrependFileOperation //////////////////////////////////////////////////////////////////////////// /*! \inmodule KDUpdater \class KDUpdater::PrependFileOperation \internal */ PrependFileOperation::PrependFileOperation(QInstaller::PackageManagerCore *core) : UpdateOperation(core) { setName(QLatin1String("PrependFile")); } void PrependFileOperation::backup() { const QString filename = arguments().first(); QFile file(filename); if (!file.exists()) return; // nothing to backup setValue(QLatin1String("backupOfFile"), backupFileName(filename)); if (!file.copy(value(QLatin1String("backupOfFile")).toString())) { setError(UserDefinedError, tr("Cannot backup file \"%1\": %2").arg( QDir::toNativeSeparators(filename), file.errorString())); clearValue(QLatin1String("backupOfFile")); } } bool PrependFileOperation::performOperation() { // This operation takes two arguments. First argument is the name // of the file into which a text has to be appended. Second argument // is the text to append. if (!checkArgumentCount(2)) return false; const QStringList args = this->arguments(); const QString fName = args.at(0); // Load the file first. QFile file(fName); if (!file.open(QFile::ReadOnly)) { setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for reading: %2").arg( QDir::toNativeSeparators(file.fileName()), file.errorString())); return false; } // TODO: fix this, use a text stream QString fContents(QLatin1String(file.readAll())); file.close(); // Prepend text to the file text fContents = args.at(1) + fContents; // Now re-open the file in write only mode. if (!file.open(QFile::WriteOnly)) { // first we rename the file, then we copy it to the real target and open the copy - the renamed original is then marked for deletion const QString newName = backupFileName(fName); if (!QFile::rename(fName, newName) && QFile::copy(newName, fName) && file.open(QFile::WriteOnly)) { QFile::rename(newName, fName); setError(UserDefinedError); setErrorString(tr("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(file.fileName()), file.errorString())); return false; } deleteFileNowOrLater(newName); } QTextStream ts(&file); ts << fContents; file.close(); return true; } bool PrependFileOperation::undoOperation() { // bockupOfFile being empty -> file didn't exist before -> no error const QString filename = arguments().first(); const QString backupOfFile = value(QLatin1String("backupOfFile")).toString(); if (!backupOfFile.isEmpty() && !QFile::exists(backupOfFile)) { setError(UserDefinedError, tr("Cannot find backup file for \"%1\".").arg(QDir::toNativeSeparators(filename))); return false; } if (!deleteFileNowOrLater(filename)) { setError(UserDefinedError, tr("Cannot restore backup file for \"%1\".").arg(QDir::toNativeSeparators(filename))); return false; } // got deleted? We might be done, if it didn't exist before if (backupOfFile.isEmpty()) return true; QFile backupF(backupOfFile); const bool success = backupF.rename(filename); if (!success) setError(UserDefinedError, tr("Cannot restore backup file for \"%1\": %2").arg( QDir::toNativeSeparators(filename), backupF.errorString())); return success; } bool PrependFileOperation::testOperation() { // TODO return true; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updateoperations.h������������������������������������0100777�0000000�0000000�00000007275�13761647206�022051� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATEOPERATIONS_H #define UPDATEOPERATIONS_H #include "updateoperation.h" namespace KDUpdater { class KDTOOLS_EXPORT CopyOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::CopyOperation) public: explicit CopyOperation(QInstaller::PackageManagerCore *core = 0); ~CopyOperation(); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); QDomDocument toXml() const; private: QString sourcePath(); QString destinationPath(); }; class KDTOOLS_EXPORT MoveOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::MoveOperation) public: explicit MoveOperation(QInstaller::PackageManagerCore *core = 0); ~MoveOperation(); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; class KDTOOLS_EXPORT DeleteOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::DeleteOperation) public: explicit DeleteOperation(QInstaller::PackageManagerCore *core = 0); ~DeleteOperation(); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); QDomDocument toXml() const; }; class KDTOOLS_EXPORT MkdirOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::MkdirOperation) public: explicit MkdirOperation(QInstaller::PackageManagerCore *core = 0); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; class KDTOOLS_EXPORT RmdirOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::RmdirOperation) public: RmdirOperation(QInstaller::PackageManagerCore *core = 0); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; class KDTOOLS_EXPORT AppendFileOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::AppendFileOperation) public: explicit AppendFileOperation(QInstaller::PackageManagerCore *core = 0); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; class KDTOOLS_EXPORT PrependFileOperation : public UpdateOperation { Q_DECLARE_TR_FUNCTIONS(KDUpdater::PrependFileOperation) public: explicit PrependFileOperation(QInstaller::PackageManagerCore *core = 0); void backup(); bool performOperation(); bool undoOperation(); bool testOperation(); }; } // namespace KDUpdater #endif // UPDATEOPERATIONS_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updater.cpp�������������������������������������������0100777�0000000�0000000�00000002677�13761647206�020463� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "updater.h" /*! \enum KDUpdater::Error \value ENoError \value ECannotStartTask \value ECannotPauseTask \value ECannotResumeTask \value ECannotStopTask \value EUnknown */ �����������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updater.h���������������������������������������������0100777�0000000�0000000�00000003150�13761647206�020113� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATER_H #define UPDATER_H #include "kdtoolsglobal.h" namespace KDUpdater { enum Error { ENoError = 0, ECannotStartTask, ECannotPauseTask, ECannotResumeTask, ECannotStopTask, EUnknown }; KDTOOLS_EXPORT int compareVersion(const QString &v1, const QString &v2); } #endif // UPDATER_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updatesinfo.cpp���������������������������������������0100777�0000000�0000000�00000021115�13761647206�021324� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "updatesinfo_p.h" #include "utils.h" #include <QDomDocument> #include <QFile> #include <QLocale> #include <QPair> #include <QVector> #include <QUrl> using namespace KDUpdater; UpdatesInfoData::UpdatesInfoData() : error(UpdatesInfo::NotYetReadError) { } UpdatesInfoData::~UpdatesInfoData() { } void UpdatesInfoData::setInvalidContentError(const QString &detail) { error = UpdatesInfo::InvalidContentError; errorMessage = tr("Updates.xml contains invalid content: %1").arg(detail); } void UpdatesInfoData::parseFile(const QString &updateXmlFile) { QFile file(updateXmlFile); if (!file.open(QFile::ReadOnly)) { error = UpdatesInfo::CouldNotReadUpdateInfoFileError; errorMessage = tr("Cannot read \"%1\"").arg(updateXmlFile); return; } QDomDocument doc; QString parseErrorMessage; int parseErrorLine, parseErrorColumn; if (!doc.setContent(&file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn)) { error = UpdatesInfo::InvalidXmlError; errorMessage = tr("Parse error in %1 at %2, %3: %4").arg(updateXmlFile, QString::number(parseErrorLine), QString::number(parseErrorColumn), parseErrorMessage); return; } QDomElement rootE = doc.documentElement(); if (rootE.tagName() != QLatin1String("Updates")) { setInvalidContentError(tr("Root element %1 unexpected, should be \"Updates\".").arg(rootE.tagName())); return; } QDomNodeList childNodes = rootE.childNodes(); for(int i = 0; i < childNodes.count(); i++) { const QDomElement childE = childNodes.at(i).toElement(); if (childE.isNull()) continue; if (childE.tagName() == QLatin1String("ApplicationName")) applicationName = childE.text(); else if (childE.tagName() == QLatin1String("ApplicationVersion")) applicationVersion = childE.text(); else if (childE.tagName() == QLatin1String("PackageUpdate")) { if (!parsePackageUpdateElement(childE)) return; //error handled in subroutine } } if (applicationName.isEmpty()) { setInvalidContentError(tr("ApplicationName element is missing.")); return; } if (applicationVersion.isEmpty()) { setInvalidContentError(tr("ApplicationVersion element is missing.")); return; } errorMessage.clear(); error = UpdatesInfo::NoError; } bool UpdatesInfoData::parsePackageUpdateElement(const QDomElement &updateE) { if (updateE.isNull()) return false; UpdateInfo info; QMap<QString, QString> localizedDescriptions; for (int i = 0; i < updateE.childNodes().count(); i++) { QDomElement childE = updateE.childNodes().at(i).toElement(); if (childE.isNull()) continue; if (childE.tagName() == QLatin1String("ReleaseNotes")) { info.data[childE.tagName()] = QUrl(childE.text()); } else if (childE.tagName() == QLatin1String("Licenses")) { QHash<QString, QVariant> licenseHash; const QDomNodeList licenseNodes = childE.childNodes(); for (int i = 0; i < licenseNodes.count(); ++i) { const QDomNode licenseNode = licenseNodes.at(i); if (licenseNode.nodeName() == QLatin1String("License")) { QDomElement element = licenseNode.toElement(); licenseHash.insert(element.attributeNode(QLatin1String("name")).value(), element.attributeNode(QLatin1String("file")).value()); } } if (!licenseHash.isEmpty()) info.data.insert(QLatin1String("Licenses"), licenseHash); } else if (childE.tagName() == QLatin1String("Version")) { info.data.insert(QLatin1String("inheritVersionFrom"), childE.attribute(QLatin1String("inheritVersionFrom"))); info.data[childE.tagName()] = childE.text(); } else if (childE.tagName() == QLatin1String("DisplayName")) { processLocalizedTag(childE, info.data); } else if (childE.tagName() == QLatin1String("Description")) { if (!childE.hasAttribute(QLatin1String("xml:lang"))) info.data[QLatin1String("Description")] = childE.text(); QString languageAttribute = childE.attribute(QLatin1String("xml:lang"), QLatin1String("en")); localizedDescriptions.insert(languageAttribute.toLower(), childE.text()); } else if (childE.tagName() == QLatin1String("UpdateFile")) { info.data[QLatin1String("CompressedSize")] = childE.attribute(QLatin1String("CompressedSize")); info.data[QLatin1String("UncompressedSize")] = childE.attribute(QLatin1String("UncompressedSize")); } else { info.data[childE.tagName()] = childE.text(); } } QStringList candidates; foreach (const QString &lang, QLocale().uiLanguages()) candidates << QInstaller::localeCandidates(lang.toLower()); foreach (const QString &candidate, candidates) { if (localizedDescriptions.contains(candidate)) { info.data[QLatin1String("Description")] = localizedDescriptions.value(candidate); break; } } if (!info.data.contains(QLatin1String("Name"))) { setInvalidContentError(tr("PackageUpdate element without Name")); return false; } if (!info.data.contains(QLatin1String("Version"))) { setInvalidContentError(tr("PackageUpdate element without Version")); return false; } if (!info.data.contains(QLatin1String("ReleaseDate"))) { setInvalidContentError(tr("PackageUpdate element without ReleaseDate")); return false; } updateInfoList.append(info); return true; } void UpdatesInfoData::processLocalizedTag(const QDomElement &childE, QHash<QString, QVariant> &info) const { QString languageAttribute = childE.attribute(QLatin1String("xml:lang")).toLower(); if (!info.contains(childE.tagName()) && (languageAttribute.isEmpty())) info[childE.tagName()] = childE.text(); // overwrite default if we have a language specific description if (QLocale().name().startsWith(languageAttribute, Qt::CaseInsensitive)) info[childE.tagName()] = childE.text(); } // // UpdatesInfo // UpdatesInfo::UpdatesInfo() : d(new UpdatesInfoData) { } UpdatesInfo::~UpdatesInfo() { } bool UpdatesInfo::isValid() const { return d->error == NoError; } QString UpdatesInfo::errorString() const { return d->errorMessage; } void UpdatesInfo::setFileName(const QString &updateXmlFile) { if (d->updateXmlFile == updateXmlFile) return; d->applicationName.clear(); d->applicationVersion.clear(); d->updateInfoList.clear(); d->updateXmlFile = updateXmlFile; d->parseFile(d->updateXmlFile); } QString UpdatesInfo::fileName() const { return d->updateXmlFile; } QString UpdatesInfo::applicationName() const { return d->applicationName; } QString UpdatesInfo::applicationVersion() const { return d->applicationVersion; } int UpdatesInfo::updateInfoCount() const { return d->updateInfoList.count(); } UpdateInfo UpdatesInfo::updateInfo(int index) const { if (index < 0 || index >= d->updateInfoList.count()) return UpdateInfo(); return d->updateInfoList.at(index); } QList<UpdateInfo> UpdatesInfo::updatesInfo() const { return d->updateInfoList; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updatesinfodata_p.h�����������������������������������0100777�0000000�0000000�00000004127�13761647206�022146� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATESINFODATA_P_H #define UPDATESINFODATA_P_H #include <QCoreApplication> #include <QSharedData> QT_FORWARD_DECLARE_CLASS(QDomElement) namespace KDUpdater { struct UpdateInfo; struct UpdatesInfoData : public QSharedData { Q_DECLARE_TR_FUNCTIONS(KDUpdater::UpdatesInfoData) public: UpdatesInfoData(); ~UpdatesInfoData(); int error; QString errorMessage; QString updateXmlFile; QString applicationName; QString applicationVersion; QList<UpdateInfo> updateInfoList; void parseFile(const QString &updateXmlFile); bool parsePackageUpdateElement(const QDomElement &updateE); void setInvalidContentError(const QString &detail); private: void processLocalizedTag(const QDomElement &childE, QHash<QString, QVariant> &info) const; }; } // namespace KDUpdater #endif // UPDATESINFODATA_P_H �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/kdtools/updatesinfo_p.h���������������������������������������0100777�0000000�0000000�00000004563�13761647206�021320� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef UPDATESINFO_P_H #define UPDATESINFO_P_H #include "updater.h" #include "updatesinfodata_p.h" #include <QHash> #include <QSharedData> #include <QVariant> // They are not a part of the public API // Classes and structures in this header file are for internal use only but still exported for auto tests. namespace KDUpdater { struct KDTOOLS_EXPORT UpdateInfo { QHash<QString, QVariant> data; }; class KDTOOLS_EXPORT UpdatesInfo { public: enum Error { NoError = 0, NotYetReadError, CouldNotReadUpdateInfoFileError, InvalidXmlError, InvalidContentError }; UpdatesInfo(); ~UpdatesInfo(); bool isValid() const; Error error() const; QString errorString() const; QString fileName() const; void setFileName(const QString &updateXmlFile); QString applicationName() const; QString applicationVersion() const; int updateInfoCount() const; UpdateInfo updateInfo(int index) const; QList<UpdateInfo> updatesInfo() const; private: QSharedDataPointer<UpdatesInfoData> d; }; } // namespace KDUpdater #endif // UPDATESINFO_P_H ���������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/libs/libs.pro������������������������������������������������������0100777�0000000�0000000�00000000106�13761647206�016270� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = subdirs SUBDIRS += 7zip installer installer.depends = 7zip ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/���������������������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�014450� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/commandlineinterface.cpp���������������������������������������0100777�0000000�0000000�00000021344�13761647206�021327� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "commandlineinterface.h" #include <component.h> #include <init.h> #include <packagemanagercore.h> #include <globals.h> #include <productkeycheck.h> #include <errors.h> #include <QDir> #include <QDomDocument> #include <iostream> CommandLineInterface::CommandLineInterface(int &argc, char *argv[]) : SDKApp<QCoreApplication>(argc, argv) { QInstaller::init(); // register custom operations m_parser.parse(arguments()); } CommandLineInterface::~CommandLineInterface() { delete m_core; } bool CommandLineInterface::initialize() { QString errorMessage; if (!init(errorMessage)) { qCWarning(QInstaller::lcInstallerInstallLog) << errorMessage; return false; } if (m_core->settings().disableCommandLineInterface()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Command line interface support disabled from installer configuration by vendor!"; return false; } // Filter the arguments list by removing any key=value pair occurrences. m_positionalArguments = m_parser.positionalArguments(); foreach (const QString &argument, m_positionalArguments) { if (argument.contains(QLatin1Char('='))) m_positionalArguments.removeOne(argument); } if (m_positionalArguments.isEmpty()) { // Special case, normally positional arguments should contain // at least the command invoked. qCDebug(QInstaller::lcInstallerInstallLog) << "Command line interface initialized but no command argument found."; } else { // Sanity and order of arguments already checked in main(), we should be // quite safe to assume that command is the first positional argument. m_positionalArguments.removeFirst(); } return true; } int CommandLineInterface::checkUpdates() { if (!initialize()) return EXIT_FAILURE; if (m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot check updates with installer."; return EXIT_FAILURE; } m_core->setUpdater(); if (!m_core->fetchRemotePackagesTree()) { qCWarning(QInstaller::lcInstallerInstallLog) << m_core->error(); return EXIT_FAILURE; } const QList<QInstaller::Component *> components = m_core->components(QInstaller::PackageManagerCore::ComponentType::Root); if (components.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog) << "There are currently no updates available."; return EXIT_SUCCESS; } QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("updates")); doc.appendChild(root); foreach (QInstaller::Component *component, components) { QDomElement update = doc.createElement(QLatin1String("update")); update.setAttribute(QLatin1String("name"), component->value(QInstaller::scDisplayName)); update.setAttribute(QLatin1String("version"), component->value(QInstaller::scVersion)); update.setAttribute(QLatin1String("size"), component->value(QInstaller::scUncompressedSize)); update.setAttribute(QLatin1String("id"), component->value(QInstaller::scName)); root.appendChild(update); } std::cout << qPrintable(doc.toString(4)) << std::endl; return EXIT_SUCCESS; } int CommandLineInterface::listInstalledPackages() { if (!initialize()) return EXIT_FAILURE; if (m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot list installed packages with installer."; return EXIT_FAILURE; } m_core->setPackageManager(); m_core->listInstalledPackages(); return EXIT_SUCCESS; } int CommandLineInterface::searchAvailablePackages() { if (!initialize()) return EXIT_FAILURE; if (!m_core->isInstaller()) m_core->setPackageManager(); if (!checkLicense()) return EXIT_FAILURE; QString regexp; if (!m_positionalArguments.isEmpty()) regexp = m_positionalArguments.first(); m_core->listAvailablePackages(regexp); return EXIT_SUCCESS; } int CommandLineInterface::updatePackages() { if (!initialize()) return EXIT_FAILURE; if (m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot update packages with installer."; return EXIT_FAILURE; } if (!checkLicense()) return EXIT_FAILURE; try { return m_core->updateComponentsSilently(m_positionalArguments); } catch (const QInstaller::Error &err) { qCCritical(QInstaller::lcInstallerInstallLog) << err.message(); return EXIT_FAILURE; } } int CommandLineInterface::installPackages() { if (!initialize() || (m_core->isInstaller() && !setTargetDir()) || !checkLicense()) return EXIT_FAILURE; try { if (m_positionalArguments.isEmpty()) { if (!m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot perform default installation with maintenance tool."; return EXIT_FAILURE; } // No packages provided, install default components return m_core->installDefaultComponentsSilently(); } // Normal installation return m_core->installSelectedComponentsSilently(m_positionalArguments); } catch (const QInstaller::Error &err) { qCCritical(QInstaller::lcInstallerInstallLog) << err.message(); return EXIT_FAILURE; } } int CommandLineInterface::uninstallPackages() { if (!initialize()) return EXIT_FAILURE; if (m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot uninstall packages with installer."; return EXIT_FAILURE; } m_core->setPackageManager(); try { return m_core->uninstallComponentsSilently(m_positionalArguments); } catch (const QInstaller::Error &err) { qCCritical(QInstaller::lcInstallerInstallLog) << err.message(); return EXIT_FAILURE; } } int CommandLineInterface::removeInstallation() { if (!initialize()) return EXIT_FAILURE; if (m_core->isInstaller()) { qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot uninstall packages with installer."; return EXIT_FAILURE; } m_core->setUninstaller(); try { return m_core->removeInstallationSilently(); } catch (const QInstaller::Error &err) { qCCritical(QInstaller::lcInstallerInstallLog) << err.message(); return EXIT_FAILURE; } } bool CommandLineInterface::checkLicense() { const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(); if (!productKeyCheck->hasValidLicense()) { qCWarning(QInstaller::lcPackageLicenses) << "No valid license found."; return false; } return true; } bool CommandLineInterface::setTargetDir() { QString targetDir; if (m_parser.isSet(CommandLineOptions::scRootLong)) { targetDir = m_parser.value(CommandLineOptions::scRootLong); } else { targetDir = m_core->value(QLatin1String("TargetDir")); qCDebug(QInstaller::lcInstallerInstallLog) << "No target directory specified, using default value:" << targetDir; } if (m_core->checkTargetDir(targetDir)) { QString targetDirWarning = m_core->targetDirWarning(targetDir); if (!targetDirWarning.isEmpty()) { qCWarning(QInstaller::lcInstallerInstallLog) << m_core->targetDirWarning(targetDir); } else { m_core->setValue(QLatin1String("TargetDir"), targetDir); return true; } } return false; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/commandlineinterface.h�����������������������������������������0100777�0000000�0000000�00000003605�13761647206�020774� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef COMMANDLINEINTERFACE_H #define COMMANDLINEINTERFACE_H #include "sdkapp.h" class CommandLineInterface : public SDKApp<QCoreApplication> { Q_OBJECT Q_DISABLE_COPY(CommandLineInterface) public: CommandLineInterface(int &argc, char *argv[]); ~CommandLineInterface(); public: int checkUpdates(); int listInstalledPackages(); int searchAvailablePackages(); int updatePackages(); int installPackages(); int uninstallPackages(); int removeInstallation(); private: bool initialize(); bool checkLicense(); bool setTargetDir(); QStringList m_positionalArguments; }; #endif // COMMANDLINEINTERFACE_H ���������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbase.cpp����������������������������������������������0100777�0000000�0000000�00000016040�13761647206�020005� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "installerbase.h" #include "installerbasecommons.h" #include "tabcontroller.h" #include <init.h> #include <messageboxhandler.h> #include <packagemanagercore.h> #include <globals.h> #include <runoncechecker.h> #include <QDir> #include <QDirIterator> #include <QFontDatabase> #include <QTranslator> #ifdef ENABLE_SQUISH #include <qtbuiltinhook.h> #endif InstallerBase::InstallerBase(int &argc, char *argv[]) : SDKApp<QApplication>(argc, argv) { QInstaller::init(); // register custom operations } InstallerBase::~InstallerBase() { delete m_core; } int InstallerBase::run() { QString errorMessage; if (!init(errorMessage)) { QInstaller::MessageBoxHandler::information(nullptr, QLatin1String("UnableToStart"), tr("Unable to start installer"), errorMessage); return EXIT_FAILURE; } if (m_parser.isSet(CommandLineOptions::scShowVirtualComponentsLong)) { QFont f; f.setItalic(true); QInstaller::PackageManagerCore::setVirtualComponentsFont(f); } QString controlScript; if (m_parser.isSet(CommandLineOptions::scScriptLong)) { controlScript = m_parser.value(CommandLineOptions::scScriptLong); if (!QFileInfo(controlScript).exists()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Script file does not exist."; return false; } } else if (!m_core->settings().controlScript().isEmpty()) { controlScript = QLatin1String(":/metadata/installer-config/") + m_core->settings().controlScript(); } qCDebug(QInstaller::lcInstallerInstallLog) << "Language:" << QLocale().uiLanguages() .value(0, QLatin1String("No UI language set")).toUtf8().constData(); #ifndef IFW_DISABLE_TRANSLATIONS const QString directory = QLatin1String(":/translations"); // Check if there is a modified translation first to enable people // to easily provide corrected translations to Qt/IFW for their installers const QString newDirectory = QLatin1String(":/translations_new"); const QStringList translations = m_core->settings().translations(); if (translations.isEmpty()) { foreach (const QLocale locale, QLocale().uiLanguages()) { QScopedPointer<QTranslator> qtTranslator(new QTranslator(QCoreApplication::instance())); bool qtLoaded = qtTranslator->load(locale, QLatin1String("qt"), QLatin1String("_"), newDirectory); if (!qtLoaded) qtLoaded = qtTranslator->load(locale, QLatin1String("qt"), QLatin1String("_"), directory); if (qtLoaded || locale.language() == QLocale::English) { if (qtLoaded) QCoreApplication::instance()->installTranslator(qtTranslator.take()); QScopedPointer<QTranslator> ifwTranslator(new QTranslator(QCoreApplication::instance())); bool ifwLoaded = ifwTranslator->load(locale, QLatin1String("ifw"), QLatin1String("_"), newDirectory); if (!ifwLoaded) ifwLoaded = ifwTranslator->load(locale, QLatin1String("ifw"), QLatin1String("_"), directory); if (ifwLoaded) QCoreApplication::instance()->installTranslator(ifwTranslator.take()); // To stop loading other translations it's sufficient that // qt was loaded successfully or we hit English as system language break; } } } else { foreach (const QString &translation, translations) { QScopedPointer<QTranslator> translator(new QTranslator(QCoreApplication::instance())); if (translator->load(translation, QLatin1String(":/translations"))) QCoreApplication::instance()->installTranslator(translator.take()); } } #endif { QDirIterator fontIt(QStringLiteral(":/fonts")); while (fontIt.hasNext()) { const QString path = fontIt.next(); qCDebug(QInstaller::lcDeveloperBuild) << "Registering custom font" << path; if (QFontDatabase::addApplicationFont(path) == -1) qCWarning(QInstaller::lcDeveloperBuild) << "Failed to register font!"; } } //create the wizard GUI TabController controller(nullptr); controller.setManager(m_core); controller.setControlScript(controlScript); if (m_core->isInstaller()) controller.setGui(new InstallerGui(m_core)); else controller.setGui(new MaintenanceGui(m_core)); QInstaller::PackageManagerCore::Status status = QInstaller::PackageManagerCore::Status(controller.init()); if (status != QInstaller::PackageManagerCore::Success) return status; #ifdef ENABLE_SQUISH int squishPort = 11233; if (m_parser.isSet(CommandLineOptions::scSquishPortLong)) { squishPort = m_parser.value(CommandLineOptions::scSquishPortLong).toInt(); } if (squishPort != 0) { if (Squish::allowAttaching(squishPort)) qCDebug(QInstaller::lcDeveloperBuild) << "Attaching to squish port " << squishPort << " succeeded"; else qCDebug(QInstaller::lcDeveloperBuild) << "Attaching to squish failed."; } else { qCWarning(QInstaller::lcDeveloperBuild) << "Invalid squish port number: " << squishPort; } #endif const int result = QCoreApplication::instance()->exec(); if (result != 0) return result; if (m_core->finishedWithSuccess()) return QInstaller::PackageManagerCore::Success; status = m_core->status(); switch (status) { case QInstaller::PackageManagerCore::Success: return status; case QInstaller::PackageManagerCore::Canceled: return status; default: break; } return QInstaller::PackageManagerCore::Failure; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbase.h������������������������������������������������0100777�0000000�0000000�00000003315�13761647206�017453� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef INSTALLERBASE_H #define INSTALLERBASE_H #include "sdkapp.h" #include "commandlineparser.h" namespace QInstaller { class PackageManagerCore; } class InstallerBase : public SDKApp<QApplication> { Q_OBJECT Q_DISABLE_COPY(InstallerBase) public: InstallerBase(int &argc, char *argv[]); ~InstallerBase(); int run(); private: void dumpResourceTree() const; QStringList repositories(const QString &list) const; }; #endif // INSTALLERBASE_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbase.ico����������������������������������������������0100777�0000000�0000000�00000061176�13761647206�020007� 0����������������������������������������������������������������������������������������������������ustar�00���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �00���h��–��� ���č��þ�����(��æ ��00����Ļ�� �� ����Ļ��ķ������h��^"��00��� �Ļ%��Æ'�� ��� �Ļ��nM����� �h��^��(���0���`��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ���ww�����xx‡wwp�www�ˆĸø‡ww��xˆˆˆw�xˆĸĸĸĸ‡wwččøøøˆwˆˆĸĸĸĸøˆ‡~ŽŽĸøpˆˆĸĸĸĸˆˆxččččøĸĸĸ‡ˆˆĸwĸˆ‡xŪŽŽĸĸøpˆˆĸ""'xwŠĻčččøĸĸĸĸ‡ˆˆĸ""""zŠŠŽŽŽĸĸĸũˆˆĸ"""'zŠŠĻččøĸĸĸĸøpˆˆĸ"""'ŠŠŠŠŽŽĸĸĸĸĸpˆˆĸ**"'ˆŠŠŠĻĸĸĸĸĸĸĸ‡ˆˆĸĒĒ"gˆˆˆŠĸĸĸĸĸĸø‡ˆˆĸ**"xˆˆˆˆĸˆˆĸĸ‡ˆˆĸĒĒ"xøøøøp�ĸøøøũˆˆĸ**"xøøĸ‡ˆˆ~þĒĒĢxøøøĸøˆĸøøøũˆˆï*Šđxø‡ĸ‡ˆˆ~þŦ››xøøøĸĸp�xøččøũˆˆïđđđwĸĸĸøˆþŽŽ‡ˆˆ~þ›››wĸĸĸĸĸĸĸĻčččįˆˆïéđđ·ĸĸĸĸĸĸøŠŽŽŽ‡ˆˆ~þþþþwĸĸĸĸøøˆŠĻččpˆˆïïïïîxĸĸĸĸˆŠŠŽŽpˆˆ~îîîîîįĸĸĸøøøøˆŠĻįˆˆ~îîîîîįĸĸˆˆŠŠ‡ˆˆ~îîîîîîxĸĸøøøøˆŠŠpˆˆ~îînîîîįĸˆˆ§ˆˆ~ææææææîwøøøøøøˆpˆˆ~nnnnnnngxˆ€ˆˆvæ��æææææwwˆˆˆ�ˆˆ~gĸø���nnngwwpˆˆxĸĸĸĸø���æææpˆˆwĸĸĸĸĸĸĸĸø������ˆ‡‡wwwxĸĸĸĸĸĸĸĸø‡wwwwwwwwˆĸĸĸĸĸ€ũwwwwwwwwwxˆˆ‡xxĸũĸĸˆwwwwwwx‡wpĸũĸĸĸĸø‡wwwwĸĸ€ĸĸĸĸĸĸĸĸĸĸøĸĸĸ‡ĸøĸĸĸĸĸĸĸĸøĸĸĸũĸwĸĸĸĸĸĸĸĸĸøxĸĸĸøpwˆĸĸĸĸĸĸĸĸøxĸĸĸĸpwwwˆĸĸĸĸĸĸĸøwĸĸˆ‡wwwxĸĸĸøqxˆˆwqwwwwwwwĸĸĸĸĸ��þ�øĸ��ü�āĸ��ø��€�ĸ��ð������ā����?��ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā����?��ā������ā���ĸ��ā���ĸ��ā���ĸ��ā����ĸ��ā���ĸ��ā���ĸ��ā���ĸ��Ā���ĸ��Ā���ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ��0���ĸ��ĸ��ĸ��ĸþ�8?ĸ��ĸĸĸĸĸĸ��(��� ���@��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ��wwp����‡ø‡wp��xˆw�x‡ĸĸĸ‡wxˆøø‡ˆ‡ĸĸĸˆxŽĸpˆ‡ø'ˆˆxččøøĸũˆ‡ø""'ŠŽŽĸøpˆ‡ø""jŠĻččĸĸĸ€ˆ‡ø""xŠŠŽĸĸĸĸũˆ‡ø*"xˆŠĸˆĸĸøũˆ‡øĒĒxˆˆø�ĸˆˆ‡Ž*#xˆðˆøøøˆ‡čĒđxøøðˆþˆˆ‡č››ĸ�ččøˆ‡ŽđđxøøĸøúŽŽˆˆ‡î››xĸĸŠĻčįˆ‡îîé·øĸĸˆŠŽ€ˆ‡îîîîĸĸøøŠŠpˆ‡ææîîxĸĸˆŠĻˆ‡nnnnįĸøøˆ ˆ‡ā�æææw€ˆ‡ĸ��nnwwwˆ‡ĸĸĸĸ��ææįpˆwwwĸĸĸ����wũwwwwxĸˆˆũwwwwwxˆ‡pĸũĸĸˆ‡wx‡€ĸĸĸĸĸøxĸũwĸĸĸĸĸĸũĸĸũwĸĸĸĸĸĸĸũĸũwwwwĸĸĸũø‡wwwqwqøĸĸðĀĸā��?Ā��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��€��?€��?€��€��ĸ€��ĸ���������€��ĸĀaĸ(������ ��������������������������������������€���€€�€���€�€�€€��€€€�ĀĀĀ���ĸ��ĸ���ĸĸ�ĸ�������ĸĸ��ĸĸĸ���wpwpĸ‡ˆ‡"xïøpĒzŽĸpŠxĻ�ˆ€đxˆp›úþpŽxĸøĻčįĸø€ŽŽwwĸĸˆ€wwwwpxũˆˆˆðĸĸøwwwwwwᇇøĀxŠ€ĸĸ€�ũ€�‡ø€�xˆ€�ˆĸ€�ũ€‡ø€xˆ€�€ˆ€‡Ž�xˆ�ˆ�ø(���0���`�����������������������������zf‚�����ĸðĸ�ĸúĸ�ĸýĸ�ĸÞý�ĸËõ�Œ‡ˆ�ĸÅÎ�ĸžÅ�ĸĐģ�ýĖŌ�ĸģđ�ĸäæ�ĸģķ�˜op�ôšŧ�ĸ™™�ĸ››�ō““�ĸžž�ĸĄ �ų�Ė‚‚�ĸĪĪ�Ũ‹Š�ĸ§§�ųĨĨ�ĸŠŠ�晙�™ff�ĸ­­�ōĪĪ�•ee�ųŠŠ�‰^^�ĸ°°�Īqq�ĸģģ�yUU�ĸĩĩ�Žzz�Ÿqq�ĩ‚‚�ĸđđ�ōŊŊ�ĸšš�ŒŒ�Ķyy�üđđ�“mm�ĸūū�ĸĀĀ�ĸÅÅ�ĸĮĮ�ZFF�·�ĸËË�ĸĖĖ�ĸÐÐ�ōÅÅ�ĸŌŌ�ĘĶĶ�ū�Ŋ’’�I==�ĸÖÖ�xee�čÄÄ�ĸŲŲ�ĸÝÝ�Ō··�ĸââ�ndd�ĸéé�ŲÆÆ�úįį�ĸîî�ôãã�ÞÐÐ�æŲŲ�âÕÕ�ĸõõ�ĸųų�ĸüü�JII�įåå�VUU�üûû�ũöö�ŌŅŅ�Ÿlk�Ŧut�ԝ›�Į“’�ųÁĀ�ųÆÅ�ųËĘ�óÓŌ�Ģol�ĩ|�ŧ†ƒ�‰fd�­ƒ�ÚŠĻ�æ―ŧ�öÏÍ�îŨÖ�Ōŋū�į°Ž�Îē°�™kf�ĸĖĮ�îäã�Ęķģ�ôíė�ĸĖÂ�đŦĻ�ęÜŲ�ð―­�Ŧub�ĸĖŧ�ôÁŽ�ߎ”�Žy`�ĸĖģ�ĮÃÁ�æäã�ĩ~^�Ė’p�ĸš‘�ĸĖŽ�ÉŠ˜�åŋĶ�ģĨœ�đķī�íķ�ĸř�ėÄĶ�ØđĄ�ũ—�ĸĖĪ�Ėēœ�ĸə�…~x�ëāÖ�ĸʔ�ĸĖ™�ĸ͞�þÓ§�ĸÚĩ�æĖģ�ĸęÕ�ĸðá�îâÖ�ĸųó�öņė�ėčä�Ũ—S�ĸƇ�ĸāĀ�þäÉ�Š�ĸõę�Üx�ĸži�ĸūp�ō·n�æŽi�ĸĀu�ĸÂ{�ę·y�üˏ�áÁ›�ôâĖ�äÞŨ�éäÞ�üēM�þķY�ĸŧd�ûŅ™�įÐē�íÞĘ�ÕÉđ�ų•�ĸĒ�ûŠ4�ōŋu�ũÄx�ûČ|�öϖ�ë˛�ėÓŪ�õÛķ�ĸýú�ëđm�þøî�óíã�―žš�ÃŪ{�ŲØÕ�juH�ēV�ŋÝŪ�M€3�XēF�€Æt�&Œ�š�Ļ�°#�#·0�(Á<�5ÎQ�Hám�[ņ�§ßá�RÍÔ� Đ�IŪü�ŠąŨ�5•ų�Llš�ĸĸĸ�ųųų�ōōō�îîî�ëëë�ééé�æææ�äää�âââ�āāā�ÞÞÞ�ÜÜÜ�ÚÚÚ�ÖÖÖ�ĖĖĖ�ÆÆÆ�ÁÁÁ�ūūū�ŧŧŧ�đđđ�ĩĩĩ�ŊŊŊ�ĒĒĒ�”””�}}}�rrr�ggg�ddd�]]]�===�666�000�����ĸĸĸĸĸĸĸĸĸWúúĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúûWUüþüúúúĸĸĸĸĸĸĸĸĸĸĸĸøøúúúøøĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúũëZóúWUüýþWúúĸĸĸĸĸĸW7'''''7AþUĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúöíVÂÂÂÂČÆöũûWUýþüøĸC#[/>iiD>8!#7þWĸĸĸĸĸĸĸĸĸĸĸĸųôZZSSSSSSSS~ǐųWU'%]469=EFHJNl0#AþĸĸĸĸĸĸĸĸĸĸîZíí›››››››››˜““”Į!d"(.469=EFHJMTr7þĸĸĸĸĸĸĸĸĸõėņõï°ĢĢĢĢĢĢĢĢĢ”ˆ[$(.469=EFHJßßq*7þĸĸĸĸĸĸĸĸõóõîZ°ĢĢĢÍÎËœĢĄŒc$(.469=EFMßßßq*7üĸĸĸĸĸĸĸõííôņ°™™™ÐÐÐÐÓÍĘĮ\$(.469=ETßßßßP!AWĸĸĸĸĸĸõïöóZ‘™™™ŅŅŅŅŅÐÐÐ $(.469Fßßßßßßr#þĸĸĸĸĸĸõîZëČŊ˜˜˜ŌŌŌŌŅÐÐÉe&$(.46Jßßßßßßß07UĸĸĸĸĸõęęęëŊ˜˜˜ÓÓÓÓŅÐÐfm,& .5ßßßßßßßßK#þĸĸĸĸĸôéęęęŊ˜˜˜ÔÔÔÔŌÐÏ%53,&  ßßßßßßßß0AũĸĸĸĸôčéęęŊĄĄĄÕÕÕÕŌÐĖ/953,& ßßßßßßß>'UĸĸĸĸôįčéęŊĄĄĄÕÕÕÕÓÐÉ]:953,&3 ßXYYYYO#þĸĸĸĸôįįčéŊ   ÖÖÖÖÓÐÉi=:953,&H d*gKYsssssssþũĸĸĸôæįįčŊ   ÖÖÖÖÔÐÉi=;:953,MØ „*sœqqqqqqq)Aũĸĸĸôåæįį‘–––ŨŨŨŨÕÚ�m:::::::Rmؖ–ksvvvvvvvgAũĸĸĸôååæį‘–––ŨŨŨŨŲÝ�]:::::::M *ؖŠB$1_`ajbgAũĸĸĸôåååæ‘–––ŨŲÛÛÛÝÞ^::::::;MK[d[ 6$(.469+Aũĸĸĸóäåå呕••ÝÛÛÛÛÝÞ)::::EMTß</ R$(.46%Aĸĸĸĸóãäå呕••ÝÝÛÛÛÝÞ`=JSßßßß3$(.WĸĸĸĸóãķšĀ‘ÜÛÝÛÛÝÝ�Gßßßßßßßß $(]#ĸĸĸĸó•ļļš””””””·ðÜÞÞ0ßßßßßßßßßB &$e'ĸĸĸĸĸōžļļĩš“““““““““‰cKßßßßßßßR:953,&ĸĸĸĸĸōŧļĪĩš’’’’’’’’’’‚*Yßßßßßß =:953,&'ĸĸĸĸĸĸņŦĪĪĩšŸŸŸŸŸŸŸŸŸŸŸ‚\8ßßßßßTFB=:953,&[ĸĸĸĸĸĸņŦĪĪ—ŪŠŠŠŠŠŠŠŠŠŠŠŠˆc?ßßßßRHEB=:953,&\fĸĸĸĸĸĸĸņŦĪ­âŪĶĶĶĶĶĶĶĶĶĶĶĶĶĻo?ßßßM HEB=:953,&"\fĸĸĸĸĸĸĸĸðķ°îėŪģģģģģģģģģģģģģģĻxgsTMJ HEB=:953-\2ĸĸĸĸĸĸĸĸĸðZõôåŪēēļđđššąēēēēēēēē€nNMJ HEB=:`^[@ĸĸĸĸĸĸĸĸĸĸïëëîîŪąđīÅÁūžšđļđšššąąąž|8nDDbih/[gĸĸĸĸĸĸĸĸĸĸĸĸïėõôæŪš―YYááââããĀŋŧąšļđ𹹞€x!!ffĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸïęįāYĄģāāYYááââããäåæįčĩŋÃąšļđđđøüúúĸĸĸĸĸĸĸĸĸĸĸĸĸîXāāāķÄXāāYYááââããäåæįčééęëė·­ÃõúWUøĸĸĸĸĸĸĸĸĸĸĸîXXãė?[8?GOQYááââããäåæįčééęëėėėZZíôöĸĸĸĸĸĸĸĸĸĸĸĸîáęėė0c%%\\))8?GlQVãäåæįčééęëėėėZôôĸĸĸĸĸĸĸĸĸĸĸĸĸîęęęlc%%\\))dd++ee//>nléįčééęëėZõöĸĸĸĸĸĸĸĸĸĸĸĸĸņįįįሁed))dd++ee///^^^OäáYYáâöýĸĸĸĸĸĸĸĸĸĸĸĸĸĸōäää°ģĨП’“Œˆ{{]^///^^^^QáāßSMJJôýĸĸĸĸĸĸĸĸĸĸĸĸĸðæâââÁĨП’“””ƒƒƒ}zwmmhvLHFFHJMZûUĸĸĸĸĸĸĸĸĸĸĸĸņYYYYŽĐŸ’“””ƒƒƒ}}}yyyti=BF JMRSþĸĸĸĸĸĸĸĸĸĸĸĸðX› īП’“””ƒƒƒ}}}yyytt†DF JMRSßíUøĸĸĸĸĸĸĸĸĸĸððōēĨП’“””ƒƒƒ}}}yyyttpøu JMRTßßáøþĸĸĸĸĸĸĸĸĸĸððô§ĐŸ’“””ƒƒƒ}}}yyyttpDûîOMRTßßßßōûúĸĸĸĸĸĸĸĸĸĸĸððōôr††ŽŽ‹……ƒ}}}yyyttppGWĸôRTßßåZðōĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸððððððððð‡luunniiDuøĸĸðîîîîĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸððððððððððĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ��þ�øĸ��ü�āĸ��ø��€�ĸ��ð������ā����?��ā������ā������ā������ā������ā������ā������ā������ā������ā������ā�������ā�������ā�������ā�������ā�������ā������ā������ā������ā������ā������ā������ā������ā������ā������ā����?��ā������ā���ĸ��ā���ĸ��ā���ĸ��ā����ĸ��ā���ĸ��ā���ĸ��ā���ĸ��Ā���ĸ��Ā���ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ������ĸ��Ā��ĸ��þ��?ĸ��ĸĸ�?ĸĸ��(��� ���@�����������������������������vfˆ�����ĸøĸ�ĸüĸ�ą°ą�þæý�ĸôþ�ĸÍņ�}Ž�öĩÎ�ýÄŲ�ØÃË�õōó�óāä�ĸôö�ė§°�þÓŲ��ݔ˜�ĸËÎ�ĸáã�š Ą�ĸœ�Į|~�ü§Ļ�ĸŠŦ�Ɔ‡�ĸÂÃ�ԕ�ĸÔÕ�ĸ™™�ĸž�ĸžž�ĸĄĄ�ĸ§Ķ�·zz�坝�ĸą°�ĸēē�ýēē�ĸķĩ�°~~�Ĩww�rRR�ĸšđ��—nn�úļ·�ķ……�ĸū―�ĸÆÆ�ëķķ�ÖĻĻ�F77�É  �ĸĖĖ�ĸÐÐ�ûĖĖ�|hh�ĸŨŨ�ĸÛÛ�ĮŦŦ��ûÚÚ�QGG�Íĩĩ�4//�ĸčč�ÚĮĮ�ōßß�-**�ĸïï�ÛÏÏ�äÛÛ�čßß�ÓËË�wss�ĸųų�ðęę�ßŲŲ�ƒ€€�ÕŅŅ�jhh�ûøø�ŅÎÎ�CBB�ĸýý�ýüü�ÞÝÝ�ŌŅŅ�ʖ•�ĸÄÃ�ĸËĘ�öĘÉ�Ԋ†�óÄÂ�øÖÔ�ņÐÎ�ēvq�ĸÎÉ�Õš·�ą|u�Μ•�Ĝ–�ýËÂ�óÁ·�ûũö�ū‘…�øÅ·�ðÅš�Õ·Ŋ�ÛĻ—�ĸÍŧ�ëÂģ�ĸųũ�đ{�§‹�―…i�ĸÍī�õïė�ëåâ�Ӟ‚�áĀŪ�ðéå�æķ•�âØŅ�ĸÎŦ�ėčå�ƊZ�öØ�ĸÍĨ�ŌÅš�Ȁ=�ĸïā�ęãÝ�ĸ͚�ĸ͝�óɟ�ōĖĶ�‡s_�Ë·Ģ�ņāÏ�éßÕ�íėë�Ýq��þÂ�ā­x�ĸɎ�þĖ–�ÛĮē�zqg�ûęŨ�þžj�âĻb�ĸĀv�ĸÄ{�ĸÂ{�ĸŌž�ųÞ―�ĸæČ�ó‡��ĸąH�ýļZ�ĸšd�é°b�öʓ�ũÖŽ�üÝķ�þöė�þĐ*�ė/�þŪ>�îŦI�ôđc�ôŋq�îĮŽ�åŅģ�―ī§�ōūl�ōʍ�ÆÂŧ�Ųě�ÚÏš�ŨÓË�ĖËČ�{{U�ĸĸú�įįæ�ŲáŽ�ŅßŪ�ÉÞ°�Îâš�A|,�°ŲĨ�/š�€Įx�<Ž5�™�Ŋ�đ-�(ĮA�5ÕU�Jčs� …B�Yũ“�ĨĐĻ�ĒĖĖ�üĸĸ�ęëë�ÛÜÜ�FĘŅ�äįč�íïð�ęėí�áäæ�JŽų�ˆķÜ�1ō�ĮĘÍ�ŧ―ŋ�øúü�õũų�áãå�ÚÛÜ�ŲÚÛ�ŨØŲ�éíō�öųý�ßáä�ÔÖŲ�ŲÞæ�îóü�ÉĖŅ�DUĢ�üüþ�ŲŲÚ�ĸĸĸ�ééé�âââ�ÚÚÚ�ŲŲŲ�ÔÔÔ�ŌŌŌ�ÐÐÐ�ÎÎÎ�ËËË�ÁÁÁ�···��sss�ppp�\\\�MMM�999�&&&�����ĸĸĸĸĸPüû.ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸPLûUBFUûúĸĸĸĸĸR@55BýûĸĸĸĸĸĸĸĸĸĸR͏ XöøRüýFþü:+.46*+5þRĸĸĸĸĸĸĸøÛņššššrŒt–+#-28<CE=+FUĸĸĸĸĸĸÛöũxĻĻĻrV…s^(,7<Cėx.BUĸĸĸĸóũũö†ĻŋÄÃÁĩŊy!&,[7VėN.FúĸĸĸóÛö†ĻūÅÅÅÅÂe !&,[\CėėėI+þĸĸĸóöá뎅ūÆĮÆÅĀ$(" !"%,[Mėėėė5ųĸĸóõîߎ—―ĮČĮÅđ,%" ėėėėėN+ýĸĸóõîŅŽŸ―ČÉĮÅt,%" ėėWWWtF>ĸYôŧXŽŸ―ÉĘČÅg\(1eedSwwwj=B>ĸōóŧ䎞žĘĘÉË67\8Ξ) †††{A5>ĸōYíލ§žĖĖŌŲ777\;4ÍĶe/_]`n5>ĸņōÐӍĶķŌŨŨŲ\\\;C6b2"&,\45>ĸņåԆƒŲŲŨŲ�hVė  &ZUĸĸņ·Ē­ˆŠÛØØŨéAėėėėė !'*Lĸĸåĩ Ī”‡””‡‰$) ėėėėC2(%" !$+ĸĸĸáĩ ™“““““““^ėėėV<8\,%" #Pĸĸĸáĩ’šœœœœœ›‘uAėėr;8\,%^:ĸĸĸĸá•|ðžĢ˜Ģ˜˜˜˜˜˜u=ęrC;8721^.ĸĸĸĸĸáōÛč§ĄĐŦŦŦŦŦĄĒĒ€0 C<930>ĸĸĸĸĸĸðYÛÚĶŦ—wĶģŪ­ŦĐĐŠ„uk0.>ĸĸĸĸĸĸĸĸðáî㧟ÏÜÝįįâŧŽ}°ŊēŽŠŠ‹BýüĸĸĸĸĸĸĸðíėÐAADINÝ ÔÔÕÓÖäææáķīøøĸĸĸĸĸĸĸïXîå*.**)6AD}IIîXïáåāöĸĸĸĸĸĸĸĸõXÖķuee*))))006OÕÔíŧÍüĸĸĸĸĸĸĸĸĸÛÔâĨĢ‘”||offZZZJjGGþĸĸĸĸĸĸĸĸļÐãw›‘”ˆˆ‚~~vvvlia<<GNüûĸĸĸĸĸĸĸļw§“‘”ˆˆ‚‚~~vvphh?CGMėøþĸĸĸĸĸĸĸļąĒ‘”ˆˆ‚~~vvpphc_ûHVėėXųĸĸĸĸĸĸĸĸļYƒdnzzqqmhcdøõNíðõôKĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸKKKKQKTĸĸKKKKĸĸĸĸĸĸĸĸĸøĸĸðĀā��Ā��Ā��€��€��€��€��€���€���€���€���€���€��€��€��€��€��€��€��€��€��?€��?€��€��ĸ€��ĸ���������€��ĸĀaĸ(������ �����������������������������éčð�§ĄÃ�íéî�����ĸóĸ�ëäę�äÕß�|~�ōūÜ�ÆĨļ�üŧÐ�æĮŅ�ĸóũ�ŲĖÐ�ĸōö�ņāä�ýÁË�ĸËŌ�ĸąš�ĸ·―�˧Š�ĸĪ�ĸÉĖ�ĸÛÝ�ėÚÛ�ũĐŦ�ĸģī�―†‡�ĸÉĘ�ŞŸ�íËĖ�ĸÝÞ�ĸŸž�ĸ  �ĸĄ �üŸŸ�ĸĢĒ�ĸ­Ž�ē||�ĸģģ�üķķ�ĸū―�ŧ�‚cc�`II�ˆii�ĸÆÆ�·‘‘�}}�N>>�ĸÎÎ�ÍĨĨ�tt�ûËË�oZZ�|ee�=22�;11�ĸŲŲ�ĸęę�ÕÃÃ�ÔÃÃ�þėė�þîî�ĸðð�ÔÏÏ�ĸûû�îęę�ėéé�^]]�ĸþþ�úËĘ�ĀĶĨ�ģƒ€�ĸÏÍ�Į°Ŋ�ÉŊ­�ÛĖË�Ɔ�ėÄĀ�čâá�į°Ĩ�ËĶž�ĩ€t�843�ėäâ�ĸÔĮ�ĸõō�qfb�øõô�ė·Ģ�šĢš�ĸÐŧ�įūŽ�ãÐĮ�øôō�ĶĪĢ�ŨÕÔ�ō― �Ō·�ĸÎą�Č­�ØÄļ�âķ˜�øÄ�ĸÎĐ�íåß�îÁ�þĖĄ�ՙ]�öɛ�ĸŌĶ�õŌŊ�éåá�BA@�üķh�ýŋ�ûĮŽ�㷈�ČŠ‰�ü͓�ÝÂĢ�ũ°P�ōŦQ�ĸđ^�ĸÂv�Ō§m�ô˖�ĸĀh�üŋh�úÄx�āąp�áđ€�öÚģ�ĸĮq�û˂�ØŅÆ�óÜģ�įÔī�óáū�æâŲ�ņåÉ�ųóá�ðëÓ�ĸýō�œšc�Ÿt�âōÖ�)Š!�!­%�� �ą,�1ÃB�Sæk�]āĩ�lmm�§ĻĻ�6ĶĘ�a­õ�ęņø�žŋÂ�ÕÖŨ�:–û�âäé�ąąē�ĸĸĸ�ÆÆÆ�ūūū�����“““�ŽŽŽ�ŒŒŒ�„„„�}}}�vvv�sss�nnn�bbb�WWW�PPP�KKK�:::�444�///�...�---�ĸĸĸ�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ĻĻĻąģŊŊĻĻŊŪ°ŊĻĻĻĻĻŽ`ErT,-468đĻĻϜa“ŽkN.:><1ļĻĻĪA•”‘!%);Ĩ=9ŊĻĪP˜–’" ĨĨ7ķĻĪU‹™—e KY_H·ĻĪC‰š J[5G3ĩĻĪ…pžĒWB 'ŊĻ~{onyRĨ@$#+ĻĻwv}|€sc2(&ĻĻĻ ˆ†‡‚zmg]/0ĻĻĻĻĄj^�DqŒŠ„ƒXĻĻĻĻĻMfSI* ŸĢ›ĻĻĻĻMˆxthbZQO;?ēīĻĻĻMulid\VLFͧĻĻĻMMMMMMMMMMMMĻĻĻĻá‡õîĀ—―€Įŀ�,%€� €�ė€�ėė€�ýĸ€õ―€Įŀ,€��WW�F>(���0���`���� ����������������������������������������������������������K���p���m���X���?���+��������� ������������������������������������������� ������������������������ ����������������������������������������������������������������� ���&888’ZZZėHHHá666Ō·���œ���Ž���y���`���F���1���#���������������������������&���@���]���p���y���z���y���o���Y���?���&�������������������������������������������������������� ���3HHH·zzzĸŲŲŲĸÏÏÏĸģģģĸĸbbbûSSSî===Ú"""ŋ Ķ���”���€���g���Q���:���(���������(���S0 ™_@@ÍvNNä|SSë|RRė|RRėtMMįR66Ō(ļ���š������S���'��� �����������������������������������������LUUUŨ•••ĸÎÎÎĸæåäĸĸýúĸĸýúĸĸýúĸĸýúĸŲØÕĸ―žšĸ—–•ĸ{zzĸYYYóCCCß111ĖŊ���š���‹���t���gU99­Œ^^óœllĸŋ‹‹ĸÏĒĒĸæŧŧĸæŋŋĸæÃÃĸƧ§ĸķĸ–ffĸŠ\\ũF//Ņ���Ą���z���C�������������������������������������;;;UeeeįąąąĸŅŅŅĸÐÐÐĸįäâĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸĸúöĸėčäĸĮÃÁĸŠĸ…~xĸdddûOOOé?77Ô}SSęĶppĸؚšĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸččĸõååĸŲūūĸĶxxĸ‚WWó&Ā���’���T������������������������������SSS)}}}óĮĮĮĸÓÓÓĸËËËĸĘĘĘĸčäáĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸøņĸĸįÐĸĸĖ™ĸĸĖ™ĸĸΟĸÆ ƒĸ–ffĸžĸųŦŦĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸččĸĸîîĸĸûûĸĖģģĸ™ffĸF..Ó���˜���V��������������������������```HĄĄĄĸÖÖÖĸŧŧŧĸĸĀĀĀĸčäßĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸöėĸĸóįĸĸĖžĸĸʙĸĸʙĸė·ĸŸliĸŲ‰‰ĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸããĸĸééĸĸĸĸĸĸĸĸĸėââĸŸppĸF..Ó���—���S����������������������aaaHĢĢĢĸĩĩĩĸĄĄĄĸÆÆÆĸÓÓÓĸéãÝĸĸóčĸĸóčĸĸóčĸPĩIĸ€ÆtĸŋÝŪĸöņéĸĸóčĸĸãĘĸĸșĸĸșĸų–ĸĶrlĸĖ€€ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸÝÝĸĸîîĸĸĸĸĸĸĸĸĸĸĸĸĸėââĸŸppĸF..Ó���Ž���A��� ����������������bbbHĪĪĪĸÍÍÍĸĖĖĖĸ°°°ĸŧŧŧĸéâÛĸĸņãĸĸņãĸĸņãĸĸĸĸĸ4Ū1ĸ`ŊCĸēVĸŋŧsĸƐ|ĸģvvĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸŌŌĸĸØØĸĸûûĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸæŲŲĸ’aaû&Ā���y���'���������������cccHĨĨĨĸÂÂÂĸ™™™ĸĩĩĩĸŌŌŌĸęâÚĸĸïßĸĸïßĸĸïßĸĻĸĻĸĻĸĻĸ Ķĸ�™�ĸ�™�ĸ“ ĸ™ffĸōĪĪĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸĸÝÝĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖģģĸ‚WWó���Ą���S���������������dddHĶĶĶĸĮĮĮĸŌŌŌĸŲŲŲĸØØØĸæßØĸĸėÚĸĸėÚĸĸėÚĸ°#ĸ°#ĸ°#ĸ°#ĸŠĸ�™�ĸ�™�ĸ`y@ĸŋ……ĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸëëĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĶyyĸF//Ņ������(�����������eeeH§§§ĸÜÜÜĸÜÜÜĸÛÛÛĸŲŲŲĸâÝŨĸĸęÕĸĸęÕĸĸęÕĸ đ0ĸ đ0ĸ đ0ĸ đ0ĸĐĸ�™�ĸ�™�ĸi`ĸė­­ĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸģđĸĸšÄĸĸššĸĸÄÄĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŲÆÆĸŠ\\ũ������F��� ��������eeeHĐĐĐĸÞÞÞĸÜÜÜĸÜÜÜĸÛÛÛĸãÝŨĸĸčŅĸĸčŅĸĸčŅĸ(Á=ĸ(Á=ĸ(Á=ĸ(Á=ĸ­ĸ�™�ĸ&ŒĸĶssĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸ―ÉĸĸÓôĸĸĖĸĸĸÏĸĸĸÖûĸĸßîĸĸþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĶyyĸ2""Â���j�����������fffHŠŠŠĸāāāĸÞÞÞĸÜÜÜĸÜÜÜĸäÝŨĸĸåĖĸĸåĖĸĸåĖĸ1ĘIĸ1ĘIĸ1ĘIĸ1ĘIĸą%ĸ�™�ĸM€3ĸŋŒŒĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸĖÓĸĸåĸĸĸŲĸĸĸÄíĸĸÅęĸĸÖúĸĸãĸĸĸðĸĸĸþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÆĐĐĸkGGä���…���$��������gggHŦŦŦĸáááĸāāāĸÞÞÞĸÜÜÜĸåÞŨĸĸãĮĸĸãĮĸĸãĮĸ;ÔYĸ;ÔYĸ;ÔYĸ;ÔYĸ·-ĸ�™�ĸcvFĸĖ››ĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ――ĸĸōĸĸĸāųĸĸĐģĸߍĸԊŠĸōšžĸĸėĸĸĸîĸĸĸúĸĸĸĸĸĸþþþĸüúúĸúũũĸųõõĸųõõĸųõõĸáŅŅĸŠ\\ũ���”���.��������iiiH­­­ĸâââĸáááĸāāāĸÞÞÞĸåÞÖĸĸáÃĸĸáÃĸĸáÃĸDÝfĸDÝfĸDÝfĸDÝfĸ"ŧ3ĸ�™�ĸssMĸæđđĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸááĸĸōĸĸĸšÄĸŋzzĸŸvuĸŊ…}ĸ™ffĸŲÆÆĸĸņĸĸĸúĸĸųöõĸôîėĸôíëĸôíëĸôíëĸôíëĸôíëĸôíëĸ™ffĸ������?��������jjjHŪŪŪĸäääĸâââĸáááĸāāāĸæÞÖĸĸßūĸĸßūĸĸßūĸLåsĸLåsĸLåsĸLåsĸ&ŋ:ĸ�™�ĸssMĸæļļĸĸŌŌĸĸÐÐĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸėėĸĸōĸĸ雛ĸ˜opĸĐäåĸĸßūĸÉŠ˜ĸŸppĸũíðĸĸúĸĸöņïĸïåãĸïåãĸïåãĸïåãĸïåãĸïåãĸïåãĸĐ~}ĸ5$$ļ���E��������kkkHŊŊŊĸåååĸäääĸâââĸáááĸčßÖĸĸÜđĸĸÜđĸĸÜđĸWðƒĸWðƒĸWðƒĸWðƒĸ/ÅQĸ Đĸ|i†ĸæģģĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸōōĸĸōĸĸ掎ĸ–€ƒĸĶęîĸĸÜđĸĸÜđĸ™ffĸîŨÖĸĸúĸĸôíėĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸéÜØĸ­ƒƒĸ5$$ļ���E��������lllH°°°ĸæææĸåååĸäääĸâââĸéßÖĸĸÚĩĸĸÚĩĸĸÚĩĸ_øĸ_øĸ_øĸ[ęĒĸOÅÛĸ0ųĸvi†ĸԟŸĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸïïĸĸōĸĸųÏŌĸŸppĸ§ÎÐĸĸÚĩĸėÄĶĸ™ffĸĸģķĸĸúĸĸĸÕÕĸĸ°°ĸüđđĸųÁĀĸųÆÅĸųËĘĸöÏÍĸóÔŌĸŊ‚‚ĸ5$$ļ���E��������mmmHąąąĸįįįĸæææĸåååĸäääĸęāÖĸĸذĸĸذĸĸذĸ\čģĸUÕĖĸOūėĸMģĸĸMģĸĸ0ųĸ`mĶĸƓ“ĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸÏÏĸĸėėĸĸōĸĸĸðĸĸŲÆÆĸŸmkĸģƒyĸŸmkĸĖ€€ĸĸĘŌĸĸúĸĸĸĮĮĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĸËËĸ쁁ĸ6$$ķ���?��������mmmHēēēĸéééĸįįįĸæææĸåååĸëāÖĸĸÕŽĸĸÕŽĸĸÕŽĸ<Ēĸĸ@ĶĸĸEŦĸĸJ°ĸĸMģĸĸ2‘ųĸNnĩĸŽyyĸĸĖĖĸĸĖĖĸĸĖĖĸĸĖĖĸĸŲŲĸĸėėĸĸüüĸĸĸĸĸĸôĸĸĸåĸĸĸîĸĸōÅÅĸƋ‹ĸ◗ĸĸšÄĸĸîĸĸĸôųĸĸĪĪĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸĸĀĀĸĸĮĮĸĢrrĸ8&&Ū���.��������nnnHīīīĸęęęĸéééĸįįįĸæææĸëāÕĸĸÓ§ĸĸÓ§ĸĸÓ§ĸ9Ÿĸĸ<Ēĸĸ@ĶĸĸEŦĸĸJ°ĸĸ7—ųĸ0mŌĸ™ffĸųÆÆĸĸŌŌĸĸééĸĸųųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸýĸĸĸįĸĸĸŲĸĸĸÉõĸĸÆįĸĸÐïĸĸãĸĸĸîĸĸĸ―Āĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸĸššĸõššĸ™ffĸ������"��������oooHĩĩĩĸëëëĸíāÍĸų­:ĸėÓ­ĸėáÕĸĸŅĒĸĸŅĒĸĸŅĒĸŊÜĸ^Ļîĸ<Ēĸĸ@ĶĸĸEŦĸĸ<œųĸ#ißĸ{ayĸŌķķĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúĸĸĸßûĸĸĖĸĸĸÏĸĸĸŲĸĸĸÜõĸĸžÂĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸĸĩĩĸܟŸĸ…XXï���c�����������pppHķķķĸóÓĢĸĸ™�ĸũ‘�ĸëŅŪĸíáÕĸĸΞĸĸΞĸĸΞĸĸΞĸĸΞĸĸΞĸÏÄķĸđĀÂĸ’ģŅĸZ~ÎĸFVĶĸĶyyĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÕÕĸĸÆĖĸĸÃÏĸĸŋĮĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸĸŠŠĸĸ°°ĸŋƒƒĸhFFŌ���@��� ��������rrrHļļļĸũÄxĸũ‘�ĸíˆ�ĸéаĸîâÕĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸĖ™ĸĸřĸĸĶ™ĸĶnlĸŲÆÆĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸööĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĸĪĪĸųĨĨĸŸkkĸ4""���!�����������sssHđđđĸōŋxĸíˆ�ĸä�ĸčϰĸðâÕĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸʔĸĸŧ”ĸԌ†ĸŸppĸųõõĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸååĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸĸ™™ĸĸžžĸĖ……ĸ€UUå���C��� ������������tttHšššĸíŧxĸä�ĸÛu�ĸįÎēĸðâÓĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸĮ‰ĸĸļĸŽusĸ쌌ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸýýĸĸÞÞĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸĸĄĄĸĸ››ĸō““ĸŸjjĸ:&&€������������������uuuHŧŧŧĸëļyĸÛu�ĸŅk�ĸæĖģĸōâŅĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸųą‚ĸĢojĸŋŸŸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõõĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸĸ­­ĸĸ§§ĸųĸŽppĸqKKÂ���)�������������������vvvHžžžĸæģzĸÖ|ĸã―–ĸïïïĸóãÏĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸĸūpĸæ­mĸ™kfĸŋŸŸĸĸĸĸĸĸĸĸĸĸĸĸĸĸîîĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸĸđđĸĸģģĸųĐĐĸŽrrĸ„XXÝ���2��� ��������������������vvvHūūūĸîÛĮĸëåÞĸÅÅÅĸÕÕÕĸóâÍĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸĸŧeĸæŦdĸŽveĸރƒĸōėėĸĸüüĸĸïïĸĸééĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸĸËËĸĸÅÅĸĸūūĸōŊŊĸŽttĸ‰^^â,8��� �����������������������wwwHŋŋŋĸÓÓÓĸŸŸŸĸ°°°ĸįįįĸôâËĸĸ·ZĸĸĩTĸĸ ĸĸŸĸĸĢĸĸĐ.ĸĸŽ9ĸĸ°Dĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·Zĸĸ·ZĸõēZĸģaĸ™ffĸ˰°ĸōááĸĸïïĸĸééĸĸååĸĸááĸĸÛÛĸĸÖÖĸĸŌŌĸĸĖĖĸųÅÅĸĖ••ĸŸkkĸ~TTŪ����������������������������������xxxHĀĀĀĸÚÚÚĸŲŲŲĸĮĮĮĸÆÆÆĸõâÉĸĸģOĸĸĨ#ĸųŌ™ĸóíãĸõÛĩĸöϖĸöÃwĸúŪ;ĸýĢĸĸ ĸĸ ĸĸ§)ĸĸŠ2ĸĸ­<ĸĸģOĸĸģOĸĸģOĸߟSĸŽy`ĸ™ffĸđ‘‘ĸŌēēĸæČČĸæÄÄĸōŅŅĸæūūĸŲŽŽĸŋŽŽĸŸllĸ^^ÏnIIY��� �����������������������������������yyyHÁÁÁĸÕÕÕĸŸŸŸĸ°°°ĸäääĸöãČĸĸŽ8ĸûČ|ĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸîÔŪĸîΞĸōŋrĸö°Gĸų§*ĸĸœ ĸĸŸĸĸĨ$ĸĸĻ,ĸïĄ7ĸϏRĸķ}[ĸĐt_ĸ“ffĸ–ffĸŠccû~VVãpNN§N;;S������ ���������������������������������������{{{HÂÂÂĸÜÜÜĸáááĸøøøĸöööĸøãÆĸþ―^ĸúúúĸøøøĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸåŅĩĸčȘĸíšnĸņąRĸõĐ6ĸĸœĸĸŸĸĸĢĸĸĨ%ĸoooî���Ķ���€���c���O���1��� �����������������������������������|||HÄÄÄĸûûûĸúúúĸųųųĸøøøĸëÞËĸþøîĸüüüĸúúúĸøøøĸöööĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÛÎŧĸßşĸé·lĸŸŸŸû‚‚‚îWWWŲCCCČ666Ĩ���O��������������������������������������{{{IÅÅÅĸüüüĸûûûĸëëëĸÕÕÕĸķĸŸllĸļ’’ĸŋœœĸÐķķĸßÏÏĸãÖÖĸõõõĸóóóĸņņņĸïïïĸíííĸëëëĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÕÕÕĸÔÔÔĸŌŌŌĸÐÐÐĸÎÎÎĸ°°°ĸxxxĖ---2��������������������������������������wwwLÆÆÆĸðððĸÛÛÛĸÖÖÖĸÖÖÖĸĶyyĸĄnnĸĢppĸĨrrĸĻuuĸŠwwĸŽyyĸŪ{{ĸđŒŒĸœœĸŌđđĸÖĀĀĸāÓÓĸčååĸęęęĸčččĸæææĸäääĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸÕÕÕĸÔÔÔĸŌŌŌĸŊŊŊĸggg™���������������������������������������������ssscÄÄÄĸÜÜÜĸÜÜÜĸÜÜÜĸÍĀĀĸĄnnĸĢppĸĨrrĸĻuuĸŠwwĸŽyyĸŪ{{ĸ°}}ĸēĸĸ탃ĸļ……ĸš‡‡ĸž‰‰ĸŋŒŒĸËĨĨĸŅąąĸÕŧŧĸāÝÝĸâââĸāāāĸÞÞÞĸÝÝÝĸÛÛÛĸŲŲŲĸŨŨŨĸŅŅŅĸŸŸŸųOOOt�������������������������������������������������ˆˆˆēâââĸâââĸâââĸâââĸⷊĸŅ“dĸĖ“pĸ―ˆwĸīxĸŽyyĸŪ{{ĸ°}}ĸēĸĸ탃ĸļ……ĸš‡‡ĸž‰‰ĸŋŒŒĸÁŽŽĸАĸđ‘ĸĮ””ĸÛÎÎĸéééĸņņņĸöööĸũũũĸðððĸíííĸåããĸũŸ���9�����������������������������������������������III ···ĸéééĸéééĸéééĸęåßĸýđaĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸõ˜ĸėđ—ĸ㰕ĸÚ§“ĸԟ’ĸ˘ĸĀ‹ĸŋŒŒĸÁŽŽĸАĸđ‘ĸĮ””ĸɖ–ĸâÕÕĸņņņĸųųųĸĸĸĸĸĸøøĸĸððĸĸęęĸĸįįĸŽĻĻĸ­���[����������������������������������������������xxxuäääĸïïïĸïïïĸïïïĸõÚ·ĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸôÁŽĸð―­ĸæģĐĸäąĐĸÛĻĪĸíÝÜĸúįįĸĸããĸĸÜÜĸĸÝÝĸĸããĸĸččĸĸîîĸÖÏÏĸLLLÖ���‚���(������������������������������������������ ĻĻĻÚöööĸöööĸöööĸöööĸüˏĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸäūđĸĸÓÓĸĸŨŨĸĸÞÞĸĸääĸĸččĸĸïïĸĸõõĸĸųųĸ‹‹‹ũ���ž���H��� ������������������������������������bbb1ÕÕÕĸüüüĸüũōĸüáūĸýЙĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸŊĒ ĸäĮĮĸĸÞÞĸĸääĸĸččĸĸïïĸĸõõĸĸųųĸĸĸĸĸÉÉÉĸ000Ä���r��������������������������������������–ØØØĸ···ĸĸķWĸĸžiĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸsssãŠĄĄėĸääĸĸééĸĸððĸĸõõĸĸûûĸĸĸĸĸĸĸĸĸōōōĸqqqé���Ž���4�����������������������������������”””‚‚‚‚J’’’Æō·nĸĸĀuĸĸńĸĸ˕ĸĸĖ™ĸĸ˜ĸĸĖžĸĸĖĄĸĸĖĪĸĸ˧ĸĸĖĐĸĸĖŦĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸëÂŋĸUUUÆjjj‡ÞŅŅĸĸððĸĸööĸĸüüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ···ĸ%%%ƒ���2��� ����������������������������������������”””b†‘‘‘ķ’’’ÆŠŸ’ĮēĨ™ĸļϚĸĖēœĸĖēžĸØđĄĸåŋĨĸåŋĶĸĸĖŪĸĸĖąĸĸĖģĸĸĖķĸĸĖđĸĸĖŧĸĸĖūĸĸĖÁĸĸĖÄĸĸĖÆĸĸĖČĸŌĩīĸ###‹���$ĨĢĢáĸööĸĸüüĸĸĸĸĸĸĸĸĸåååĸŌŌŌĸŋŋŋĸ   Øxxxe������������������������������������������������������������������������“““B‰‰‰GŠŠŠX‡ŽŽŽ‰‘‘‘§›—–ÆīĢĮģĨĄņŋŽĶĸĖģ­ĸĖģŪĸæŋŧĸæŋžĸėÂÂĸīĢĢę���=���•••bŋūūĸĀĀĀņĐĐĐɊŠŠ„„„o€€€L��� ����������������������������������������������������������������������������������������������������������������������������”””BŠŠŠG‹‹‹X‘‘‘‡………\��� ���������������������������������������������������������������������������ü�āĸ��ð����ĸ��ā����?��Ā������Ā������Ā������Ā������Ā������Ā������Ā������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā�������Ā������Ā������Ā������Ā������Ā������Ā������Ā����?��Ā������Ā����?��Ā����?��Ā����?��Ā����ĸ��€���ĸ��€���ĸ��€���ĸ������ĸ������ĸ�������ĸ�������ĸ�������ĸ��Ā����ĸ��ð���ĸ��ĸþ�?ĸ��(��� ���@���� ����������������������������������������������N���s���n���X���D���1���"������������������ ������.���<���@���=���0������������������������������������������&;;;™vvví]]]ä555Ð―§���Œ���y���d���L���5���%���&���C{0 Ē/Ŋ.ąĨ���Œ���s���L���"��� �������������������������&LLLķĢĢĢĸíėëĸôôōĸÝÝÜĸÃÂĀĸ‘ũfffíCDDÝ**+ÆŽ—���„6##›wPPݟqqôĖ–ýŅĶĶþÆ  þ {{ũyRRė=((Ę������p���6������������������BBBoooÅūūūĸÔÔÔĸëčåĸĸĸųĸĸĸûĸĸĸûĸĸýøĸĸûöĸíčäĸË·Ģĸ§”ĸzpeóaJJčķ{{ýĸĸÆÆĸĸÏÏĸĸÚÚĸĸááĸĸééĸōßßĸČĐĐĸvPPëķ������<��� �����������ccc_ūūūĸÁÁÁĸ···ĸëįáĸĸøîĸþöėĸýöëĸĸųöĸĸüüĸĸðáĸĸПĸĸӜĸđ{ĸŅ„…ĸĸŦŦĸĸĩĩĸĸššĸĸÃÃĸĸĖĖĸĸÕÕĸĸÝÝĸĸįįĸĸĸĸĸëââĸ“mmöŧ���~���3�����������iiic···ĸķķķĸÁÂÂĸëäÝĸĸöîĸÎâšĸ<Ž5ĸ€Įxĸ°ŲĨĸŅΗĸïÆĸӞ‚ĸĮ|~ĸĸœĸĸĄĄĸĸŠŠĸĸēēĸĸššĸĸÄÄĸĸĖĖĸĸÔÔĸĸããĸĸþþĸĸĸĸĸņęęĸ‘iiõ ą���k����������jjjbŧŧŧĸąąąĸŋĀĀĸíäÛĸĸóčĸÆÞ°ĸ��ĸ� ĸĄĸœ ĸ/šĸ°zuĸü§ĻĸĸŸŸĸĸ™™ĸĸ  ĸĸŠŠĸĸģģĸĸšđĸĸÄÃĸĸËËĸĸęęĸĸĸĸĸĸĸĸĸĸĸĸĸ娨ĸoJJč���˜���F��� ����kkkbŋŋŋĸØØØĸŲŲÚĸéāØĸĸîßĸËÞ°ĸ °ĸī)ĸ­ĸ�œ�ĸA|,ĸ⚟ĸĸĩĩĸĸ§§ĸĸžžĸĸ™™ĸĸ  ĸĸ§Ĩĸĸą°ĸĸđđĸĸÅÃĸĸųųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸūŸŸþ3!!Ã���m�������kkkbĘĘĘĸáááĸÚÛÜĸčßÖĸĸęŨĸÎßŊĸ―1ĸ)Â=ĸī'ĸ�˜�ĸ{{Uĸĸ―Äĸĸđđĸĸ°°ĸĸ§§ĸĸĸĸ›šĸĸÁŅĸĸËôĸĸÎõĸĸÚęĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņęęĸnJJæ���‹���.����lllbËËËĸãããĸÛÜÜĸéßÕĸĸæÎĸŅßŪĸ'ĖGĸ7ÐRĸ ū4ĸ ĸ͈yĸĸËÎĸĸÃÃĸĸđđĸĸ°°ĸĸĶĨĸĸŅŲĸĸáûĸøąĖĸôļÏĸĸįĸĸĸõĸĸĸĸĸĸĸĸĸĸýüýĸýüüĸüûûĸІ†ú Ī���=����nnnbÍÍÍĸåååĸÞÞßĸęÞÓĸĸáÅĸÔāŪĸ6Ü^ĸFßhĸ(Č@ĸŠĸĜ–ĸĸÓÕĸĸËËĸĸÃÃĸĸķķĸĸū―ĸĸóýĸė§°ĸ°}wĸą~uĸÓķŧĸĸųĸĸûøøĸöðîĸõîíĸõîėĸûũõĸÉŽŦĸ#°���I����ooobÏÏÏĸįįįĸßāâĸëÞŌĸĸÝžĸŨā­ĸEęuĸTî}ĸ2ÓOĸ …Bĸ˜ŸĸĸÓÔĸĸÍÍĸĸËËĸĸÃÃĸĸŅÐĸĸôüĸƆ‡ĸĒĖĖĸũāūĸ­‚|ĸũîōĸũóōĸęâßĸëâßĸëâßĸðéåĸÏĩīĸB++Â���M����qqqbŅŅŅĸéééĸâãäĸíÞÐĸĸŲīĸÛâŦĸTûŒĸ^ō™ĸLŅÁĸ<ØĸŧŒ•ĸĸÍĖĸĸĖĖĸĸĖĖĸĸÉÉĸĸŨÖĸĸũĸĸÖŦ­ĸ ŽŦĸóÓ°ĸēzsĸüÔŲĸýâãĸúļ·ĸöÄÃĸöĘÉĸøÖÔĸÔ°ŊĸA++Ā���I����rrrbŌŌŌĸęëëĸãæčĸïßÏĸĸŨŠĸÖÔ·ĸ@ÂāĸJģûĸLģĸĸ6†éĸ}ŽĸĸËČĸĸĘĘĸĸËËĸĸÖÖĸĸęéĸĸõĸĸûėûĸËĄžĸēvqĸݔ˜ĸĸðũĸĸÅÆĸĸĶĨĸĸēēĸĸššĸĸĘĘĸÚĶĶĸD--―���=����tttbÔÖØĸíïņĸįãÚĸïÞÍĸĸÔ ĸŌÆžĸ'˜ĸĸ3Ģĸĸ@Ūĸĸ)ŒųĸvfˆĸüÉÃĸĸããĸĸõõĸĸýýĸĸĸĸĸĸüĸĸĸįĸĸĸŅúĸúÂáĸĸãýĸĸÞįĸĸžĸĸŸŸĸĸŠŠĸĸēēĸĸĀĀĸɓ“ĸ)Ÿ���-����uvwbŨÓËĸúŧ[ĸōļeĸïßŅĸĸϜĸōĖĶĸ°ŧÅĸ”ķÔĸ{ķãĸQšëĸDUĢĸÎĩĩĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸóũĸĸËčĸĸĖëĸĸÉØĸĸŠŦĸĸœœĸĸ™™ĸĸ  ĸĸŠŠĸýēēĸĶssũu�������wz€bÞĞĸûŒ�ĸé°bĸņáŅĸĸ˖ĸĸ͙ĸĸϔĸĸϔĸĸ˚ĸóɟĸāĄšĸ瀂ĸũôôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸčæĸĸĮÅĸĸÂÁĸĸ·ĩĸĸ°°ĸĸĻĻĸĸžžĸĸ™™ĸĸĒĒĸĸsLLŨA��� ����y}bÛÁĸë�ĸâĻbĸóáÏĸĸĮŠĸĸɏĸĸɏĸĸɏĸĸɎĸĸʎĸĸɐĸŌ|ĸū ĪĸĸĸĸĸĸĸĸĸĸĸĸĸĸþþĸĸÜÜĸĸÏÏĸĸËĘĸĸÃÃĸĸššĸĸąąĸĸ§§ĸĸžžĸĸœœĸđxxý<((€����������{‚bØ―›ĸÝq�ĸā­xĸõáÉĸĸĀvĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÂ{ĸĸÄ{ĸĸÁĸžlĸÉīļĸĸĸĸĸĸĸĸĸĸũũĸĸßßĸĸŨŨĸĸÐÐĸĸËËĸĸÃÃĸĸđđĸĸąąĸĸŽŽĸԆ†ĸmIIŧ���(�����������|bÛĮēĸ⚏ĸŲŲŲĸõÝūĸĸšdĸĸžhĸĸŧgĸĸžhĸĸžjĸĸ―lĸĸ―lĸĸūkĸųšiĸļ‚dĸÅŦ­ĸüüþĸĸũũĸĸččĸĸááĸĸØØĸĸÐÐĸĸĖĖĸĸÆÆĸĸ――ĸŌĸ€WWÍ *��������������€€€bŌŌŌĸšŋÃĸÉĖŅĸũÛļĸĸ°FĸþŠ/ĸýŊ@ĸþŊ@ĸþ­;ĸĸ­=ĸĸŪ?ĸĸēJĸĸķSĸþļ[ĸƊZĸ牅ĸØÃËĸóāäĸþæįĸĸããĸĸÚÚĸûĖĖĸëķķĸ큁øzRRĒ������������������bŅŅŅĸŧŧŧĸĮĘÍĸũŨ­ĸþ­9ĸöęÖĸóņïĸōãÎĸōÖŠĸōʍĸôŋqĸöđ`ĸúŪAĸþĻ,ĸĸĻ"ĸí1ĸȀ=ĸŋ‰jĸū‘…ĸķĸ牉ý–llėmLLļO44`��������������������������‚‚‚bŨŨŨĸâââĸöøûĸýá·ĸĸėÅĸüĸĸĸøúüĸôũûĸïôûĸėōüĸéíóĸččįĸæáŲĸãÛÎĸåŅģĸíĮŽĸōūlĸîŦIĸëž1ĸė+ĸˆr\ōž���‘���d���,�����������������������bčččĸĸĸĸĸęëëĸĘ·ēĸÍīĩĸÚĮĮĸįÜÜĸïęęĸõũũĸōóóĸïņņĸėîîĸęėíĸåįčĸáäæĸÞáåĸÛßåĸŨÝæĸÖØÚĸÜÏŧĸĮÃŧþ°īĩø‘““éQRR‹�������������������������{{{fÝÝÝĸáááĸÔÖØĸĄv{ĸ›dgĸĪqqĸŦyyĸ°ĸĸÅĒĒĸŅĩĩĸŲĮĮĸāÔÔĸâÛÛĸâÝÝĸáááĸÞÝÝĸÚÚÚĸŨØŲĸÔÖÚĸŲÚÛĸÂÂÂĸnnnĪ...'�������������������������‡‡‡™ßÞÞĸāãæĸÝËžĸ†iĸķrĸ­zvĸŦxxĸ­z{ĸ°|}ĸą}~ĸģ~ĸ큂ĸŧ„…ĸӔĸƟŸĸßŲŲĸęėėĸíïïĸéęęĸįææĸŦŦŦø111­���8���������������������������(((đđđëîïïĸéėðĸöʓĸĸđbĸýÁĸûȕĸöØĸėđ˜ĸ㰗ĸÛĻ—ĸҟ”ĸΛ•ĸĖ™•ĸ˗•ĸʗ–ĸčßßĸúööĸĸööĸĸîîĸĸîîĸĩŽŽúĨ���U���������������������������dęëėýõųþĸõïčĸýÃ{ĸĸÃ~ĸĸĖ—ĸĸ˜ĸĸ͟ĸĸÎĪĸĸÏĐĸĸÏ­ĸĸŅąĸĸÏĩĸýĘķĸøÅ·ĸóÁ·ĸņÐÎĸĸÛÛĸĸÜÜĸĸääĸĸððĸïččĸKLLÓ���|���&�����������������������ģģī·óïëĸþÞķĸþˍĸĸÃ~ĸĸ˗ĸĸ˜ĸĸ˟ĸĸĖĪĸĸ˧ĸĸĖŦĸĸĖŊĸĸĖģĸĸĖ·ĸĸÍžĸĸÍÁĸûĘÁĸīĒĄüûÚÚĸĸččĸĸïïĸĸųųĸĸĸĸĸ———í‘���;��� ��������������������žŸĄ‹ŦŸ‘Öþ·^ĸþÂ~ĸþ˖ĸþ˜ĸĸ˟ĸĸÎĪĸĸÎĻĸĸÎŽĸĸΰĸĸÎīĸĸÎļĸĸÍžĸĸÍĀĸĸÍÅĸðÄĀþ\]]ÂÎÂÂëĸõõĸĸýýĸĸĸĸĸĸĸĸĸÝÝÝĸFFFŽ���/��� ������������������������=’‘x–“ŽŸ’ŠļĨ“žŋЖÉÂŦ›Ó˰žáÛļĨëā―ŠøęÁąĸëÂīĸðÅšĸúĘÂĸĸÎÉĸÚđļýO•””›ïëëĸéééĸÓÔÔéžžžÕ­­­ŧwwwX��� ������������������������������������������������€ƒ† ‡‰‹ƒˆŠ%‡‡ˆ9Ą”DĶ™•XŪžšeŸ˜˜…Ļ›››š““���sss§§§ZDooo'MMM ����������������������������������ā��€��€��€��€��€���€���€���€���€���€���€���€���€���€���€���€���€���€��€��€��€��€��€��������?���?���������€��ð��(������ ���� ����������������������������������?���m���{���p���_���O���H���W���j���m���^���;������GGGZ‰‰‰ÜЧ§ï|~åYXXŨ543Å$ķ\>?ȌhhޓssämTTŲ*ŧ���Œ���O���XXXĄĒĒņŨÕÔĸĸýōĸâōÖĸųóáĸîÁĸƆ~þũĐŦĸĸÆÆĸĸŲŲĸþėėĸÖÃÃýB--Ð������=ccc#ŊŊ°ųÔÏÏĸðëÓĸ!­%ĸ)Š!ĸœšcĸĸĪĸĸ  ĸĸ­Žĸĸū―ĸĸęęĸĸĸĸĸÕÃÃý&ŧ���heee"―――öčâáĸņåÉĸ1ÃBĸ� ĸŸtĸĸ·―ĸĸĄ ĸĸąšĸüŧÐĸĸóũĸĸĸĸĸĸĸĸĸz``ã���‡hhh"ÂÂÃöėäâĸóáūĸSækĸą,ĸČ­ĸĸÉĖĸĸÉĘĸæĮŅĸĮ°ŊĸņāäĸøõôĸøôōĸĀĶĪû���Žlkk"ÅČËöîęęĸóÜģĸ]āĩĸ6ĶĘĸÆĨļĸĸÏÍĸĸÝÞĸäÕßĸšĢšĸíËĖĸûËËĸúËĘĸÎĨĨü���ƒmno"ËÅšööÚģĸõŌŊĸa­õĸ:–ûĸ§ĄÃĸĸõōĸĸûûĸĸóĸĸōūÜĸýÁËĸĸŸžĸĸģģĸˆˆũ���_qv}"ÏĢföōŦQĸĸŌĶĸöɛĸÝÂĢĸËĶžĸíéîĸĸĸĸĸĸððĸĸËŌĸĸģīĸĸĢĒĸüŸŸĸ{RRŋ���.uy}"ŧ„ö㷈ĸĸÂvĸĸđ^ĸĸĀhĸüķhĸŌ·ĸëäęĸĸōöĸĸÛÝĸĸÎÎĸüķķĸŪppâ0 D��� www#đžūöØŅÆĸĸĮqĸû˂ĸúÄxĸüŋhĸũ°Pĸՙ]ĸâķ˜ĸįūŽĸš’’ō‡^^É5""G��� ���lll$ŌŌÓũíåßĸãÐĮĸéčðĸėééĸéåáĸæâŲĸįÔīĸáđ€ĸāąpĸqd`Ý"w����������ooo5ØÛÞúØÄļĸĩ€tĸģƒ€ĸŧĸŞŸĸ˧ŠĸŲĖÐĸęņøĸâäéĸlmmŲl����������ĄĄĒvôōîĸü͓ĸýŋĸøÄĸō― ĸė·Ģĸį°ĨĸėÄĀĸĸęęĸþîîĸSRRŋ���g����������ĻĶ̐óȒøûĮŽþþĖĄĸĸÎĐĸĸÎąĸĸÐŧĸĸÔĮĸÉ­ŠęėÚÛþĸþþĸĀĀĀáC����������ˆˆ‡ —’‹2ŦG§šY –jĩĄ™yÂĐĒūϧۈƒƒcŸŸŸhģģģv˜˜˜TEEE�����������������kb��Ęĸ��áĸ��Üĸ��Öĸ��Ũĸ��Ŋĸ��1ĸ��=ĸ��'ĸ��ĸ�Uĸ�Äĸ�đĸ�°ĸ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbase.manifest�����������������������������������������0100777�0000000�0000000�00000002137�13761647206�021033� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <!-- Make sure Vista UAC does not believe installerbase is an installer --> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!--The ID below indicates app support for Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!--The ID below indicates app support for Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!--The ID below indicates app support for Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!--The ID below indicates app support for Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> </application> </compatibility> </assembly> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbase.rc�����������������������������������������������0100777�0000000�0000000�00000001106�13761647206�017624� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> /* Version info for Windows binary */ VS_VERSION_INFO VERSIONINFO FILEVERSION IFW_VERSION_WIN32 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "FileVersion", IFW_VERSION_STR_WIN32 END END END /* End of version info */ IDI_ICON1 ICON DISCARDABLE "installerbase.ico" #define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "installerbase.manifest" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbasecommons.cpp���������������������������������������0100777�0000000�0000000�00000012211�13761647206�021375� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "installerbasecommons.h" #include <packagemanagercore.h> #include <scriptengine.h> #include <packagemanagerpagefactory.h> #include <productkeycheck.h> #include <settings.h> using namespace QInstaller; // -- InstallerGui InstallerGui::InstallerGui(PackageManagerCore *core) : PackageManagerGui(core, nullptr) { ProductKeyCheck *checker = ProductKeyCheck::instance(); foreach (const int id, checker->registeredPages()) { PackageManagerPage *page = PackageManagerPageFactory::instance().create(id, core); Q_ASSERT_X(page, Q_FUNC_INFO, qPrintable(QString::fromLatin1("Page with %1 couldn't be " "constructed.").arg(id))); setPage(id, page); } setPage(PackageManagerCore::Introduction, new IntroductionPage(core)); setPage(PackageManagerCore::TargetDirectory, new TargetDirectoryPage(core)); setPage(PackageManagerCore::ComponentSelection, new ComponentSelectionPage(core)); setPage(PackageManagerCore::LicenseCheck, new LicenseAgreementPage(core)); #ifdef Q_OS_WIN setPage(PackageManagerCore::StartMenuSelection, new StartMenuDirectoryPage(core)); #endif setPage(PackageManagerCore::ReadyForInstallation, new ReadyForInstallationPage(core)); setPage(PackageManagerCore::PerformInstallation, new PerformInstallationPage(core)); setPage(PackageManagerCore::InstallationFinished, new FinishedPage(core)); foreach (const int id, pageIds()) { QWizardPage *wizardPage = page(id); packageManagerCore()->controlScriptEngine()->addToGlobalObject(wizardPage); packageManagerCore()->componentScriptEngine()->addToGlobalObject(wizardPage); } } // -- MaintenanceGui MaintenanceGui::MaintenanceGui(PackageManagerCore *core) : PackageManagerGui(core, nullptr) { ProductKeyCheck *checker = ProductKeyCheck::instance(); foreach (const int id, checker->registeredPages()) { PackageManagerPage *page = PackageManagerPageFactory::instance().create(id, core); Q_ASSERT_X(page, Q_FUNC_INFO, qPrintable(QString::fromLatin1("Page with %1 couldn't be " "constructed.").arg(id))); setPage(id, page); } connect(core, &PackageManagerCore::installerBinaryMarkerChanged, this, &MaintenanceGui::updateRestartPage); if (!core->isOfflineOnly() || validRepositoriesAvailable()) { setPage(PackageManagerCore::Introduction, new IntroductionPage(core)); setPage(PackageManagerCore::ComponentSelection, new ComponentSelectionPage(core)); setPage(PackageManagerCore::LicenseCheck, new LicenseAgreementPage(core)); } else { core->setUninstaller(); core->setCompleteUninstallation(true); } setPage(PackageManagerCore::ReadyForInstallation, new ReadyForInstallationPage(core)); setPage(PackageManagerCore::PerformInstallation, new PerformInstallationPage(core)); setPage(PackageManagerCore::InstallationFinished, new FinishedPage(core)); RestartPage *p = new RestartPage(core); connect(p, &RestartPage::restart, this, &PackageManagerGui::gotRestarted); setPage(PackageManagerCore::InstallationFinished + 1, p); if (core->isUninstaller()) wizardPageVisibilityChangeRequested(false, PackageManagerCore::InstallationFinished + 1); foreach (const int id, pageIds()) { QWizardPage *wizardPage = page(id); packageManagerCore()->controlScriptEngine()->addToGlobalObject(wizardPage); packageManagerCore()->componentScriptEngine()->addToGlobalObject(wizardPage); } } void MaintenanceGui::updateRestartPage() { wizardPageVisibilityChangeRequested((packageManagerCore()->isUninstaller() ? false : true), PackageManagerCore::InstallationFinished + 1); } bool MaintenanceGui::validRepositoriesAvailable() const { foreach (const Repository &repo, packageManagerCore()->settings().repositories()) { if (repo.isEnabled() && repo.isValid()) { return true; } } return false; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/installerbasecommons.h�����������������������������������������0100777�0000000�0000000�00000003543�13761647206�021052� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef INSTALLERBASECOMMONS_H #define INSTALLERBASECOMMONS_H #include <packagemanagergui.h> // -- InstallerGui class InstallerGui : public QInstaller::PackageManagerGui { Q_OBJECT public: explicit InstallerGui(QInstaller::PackageManagerCore *core); ~InstallerGui() {} }; // -- MaintenanceGui class MaintenanceGui : public QInstaller::PackageManagerGui { Q_OBJECT public: explicit MaintenanceGui(QInstaller::PackageManagerCore *core); ~MaintenanceGui() {} private Q_SLOTS: void updateRestartPage(); private: bool validRepositoriesAvailable() const; }; #endif // INSTALLERBASECOMMONS_H �������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/main.cpp�������������������������������������������������������0100777�0000000�0000000�00000031267�13761647206�016111� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "constants.h" #include "commandlineparser.h" #include "installerbase.h" #include "sdkapp.h" #include "commandlineinterface.h" #include <errors.h> #include <selfrestarter.h> #include <remoteserver.h> #include <utils.h> #include <QCommandLineParser> #include <QDateTime> #include <QNetworkProxyFactory> #include <iostream> #if defined(Q_OS_MACOS) or defined(Q_OS_UNIX) # include <unistd.h> # include <sys/types.h> #endif #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) #define VERSION "IFW Version: " QUOTE(IFW_VERSION_STR) ", built with Qt " QT_VERSION_STR "." #define BUILDDATE "Build date: " __DATE__ #define SHA "Installer Framework SHA1: " QUOTE(_GIT_SHA1_) static const char PLACEHOLDER[32] = "MY_InstallerCreateDateTime_MY"; int main(int argc, char *argv[]) { if (!qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR") && !qEnvironmentVariableIsSet("QT_SCALE_FACTOR") && !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); #endif // increase maximum numbers of file descriptors #if defined(Q_OS_MACOS) QCoreApplication::setSetuidAllowed(true); struct rlimit rl; getrlimit(RLIMIT_NOFILE, &rl); rl.rlim_cur = qMin((rlim_t) OPEN_MAX, rl.rlim_max); setrlimit(RLIMIT_NOFILE, &rl); #endif qsrand(QDateTime::currentDateTime().toTime_t()); // We need to start either a command line application or a GUI application. Since we // fail doing so at least on Linux while parsing the argument using a core application // object and later starting the GUI application, we now parse the arguments first. CommandLineParser parser; parser.parse(QInstaller::parseCommandLineArgs(argc, argv)); bool sanityCheck = true; QString sanityMessage; QStringList mutually; mutually = QInstaller::checkMutualOptions(parser, QStringList() << CommandLineOptions::scStartUpdaterLong << CommandLineOptions::scStartPackageManagerLong << CommandLineOptions::scStartUninstallerLong << CommandLineOptions::scDeprecatedUpdater); if (mutually.isEmpty()) { mutually = QInstaller::checkMutualOptions(parser, QStringList() << CommandLineOptions::scSystemProxyLong << CommandLineOptions::scNoProxyLong); } if (mutually.isEmpty()) { mutually = QInstaller::checkMutualOptions(parser, QStringList() << CommandLineOptions::scAcceptMessageQueryLong << CommandLineOptions::scRejectMessageQueryLong << CommandLineOptions::scMessageDefaultAnswerLong); } if (mutually.isEmpty()) { mutually = QInstaller::checkMutualOptions(parser, QStringList() << CommandLineOptions::scStartServerLong << CommandLineOptions::scStartClientLong); } if (!mutually.isEmpty()) { sanityMessage = QString::fromLatin1("The following options are mutually exclusive: %1.") .arg(mutually.join(QLatin1String(", "))); sanityCheck = false; } const QSet<QString> commands = parser.positionalArguments().toSet() .intersect(CommandLineOptions::scCommandLineInterfaceOptions.toSet()); // Check sanity of the given argument sequence. if (commands.size() > 1) { sanityMessage = QString::fromLatin1("%1 commands provided, only one can be used at a time.") .arg(commands.size()); sanityCheck = false; } else if (!commands.isEmpty() && parser.positionalArguments().indexOf(commands.values().first()) != 0) { sanityMessage = QString::fromLatin1("Found command but it is not given as the first positional " "argument. \"%1\" given.").arg(parser.positionalArguments().first()); sanityCheck = false; } const bool help = parser.isSet(CommandLineOptions::scHelpLong); if (help || parser.isSet(CommandLineOptions::scVersionLong) || !sanityCheck) { QCoreApplication app(argc, argv); if (parser.isSet(CommandLineOptions::scVersionLong)) { std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl; const QDateTime dateTime = QDateTime::fromString(QLatin1String(PLACEHOLDER), QLatin1String("yyyy-MM-dd - HH:mm:ss")); if (dateTime.isValid()) std::cout << "Installer creation time: " << PLACEHOLDER << std::endl; return EXIT_SUCCESS; } std::cout << qPrintable(parser.helpText()) << std::endl; if (!sanityCheck) { std::cerr << qPrintable(sanityMessage) << std::endl; } return help ? EXIT_SUCCESS : EXIT_FAILURE; } if (parser.isSet(CommandLineOptions::scStartServerLong)) { const QStringList arguments = parser.value(CommandLineOptions::scStartServerLong) .split(QLatin1Char(','), QString::SkipEmptyParts); QString socketName, key; const QString mode = arguments.value(0); bool argumentsValid = (mode.compare(QLatin1String(QInstaller::Protocol::ModeDebug), Qt::CaseInsensitive) == 0); if (argumentsValid) { socketName = arguments.value(1, QLatin1String(QInstaller::Protocol::DefaultSocket)); key = arguments.value(2, QLatin1String(QInstaller::Protocol::DefaultAuthorizationKey)); } else { socketName = arguments.value(1); key = arguments.value(2); } const bool production = (mode.compare(QLatin1String(QInstaller::Protocol::ModeProduction), Qt::CaseInsensitive) == 0); if (production) { argumentsValid = (!key.isEmpty()) && (!socketName.isEmpty()); #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) /* In production mode detach child so that sudo waiting on us will terminate. */ pid_t child = fork(); if (child <= -1) { std::cerr << "Fatal cannot fork and detach server." << std::endl; return EXIT_FAILURE; } if (child != 0) { return EXIT_SUCCESS; } ::setsid(); #endif } SDKApp<QCoreApplication> app(argc, argv); if (!argumentsValid) { std::cout << qPrintable(parser.helpText()) << std::endl; QString startServerStr = CommandLineOptions::scStartServerLong; std::cerr << "Wrong argument(s) for option --" << startServerStr.toStdString() << std::endl; return EXIT_FAILURE; } #if defined(Q_OS_MACOS) // make sure effective == real user id. uid_t realUserId = getuid(); uid_t effectiveUserId = geteuid(); if (realUserId != effectiveUserId) setreuid(effectiveUserId, -1); #endif QInstaller::RemoteServer *server = new QInstaller::RemoteServer; QObject::connect(server, &QInstaller::RemoteServer::destroyed, &app, &decltype(app)::quit); server->init(socketName, key, (production ? QInstaller::Protocol::Mode::Production : QInstaller::Protocol::Mode::Debug)); server->start(); return app.exec(); } try { QStringList optionNames = parser.optionNames(); //Verbose level can be increased by setting the verbose multiple times foreach (QString value, optionNames) { if (value == CommandLineOptions::scVerboseShort || value == CommandLineOptions::scVerboseLong) { QInstaller::setVerbose(true); } } foreach (const QString &option, CommandLineOptions::scCommandLineInterfaceOptions) { bool setVerbose = parser.positionalArguments().contains(option); if (setVerbose) { QInstaller::setVerbose(setVerbose); break; } } const QStringList unknownOptionNames = parser.unknownOptionNames(); if (!unknownOptionNames.isEmpty()) { const QString options = unknownOptionNames.join(QLatin1String(", ")); std::cerr << "Unknown option: " << qPrintable(options) << std::endl; } if (parser.isSet(CommandLineOptions::scSystemProxyLong)) { // Make sure we honor the system's proxy settings QNetworkProxyFactory::setUseSystemConfiguration(true); } if (parser.isSet(CommandLineOptions::scNoProxyLong)) QNetworkProxyFactory::setUseSystemConfiguration(false); const SelfRestarter restarter(argc, argv); if (parser.positionalArguments().contains(CommandLineOptions::scCheckUpdatesShort) || parser.positionalArguments().contains(CommandLineOptions::scCheckUpdatesLong) || parser.isSet(CommandLineOptions::scDeprecatedCheckUpdates)) { // Also check for deprecated --checkupdates option, which is superseded by check-updates // command in IFW 4.x.x. Should not be used for normal interactive usage. return CommandLineInterface(argc, argv).checkUpdates(); } else if (parser.positionalArguments().contains(CommandLineOptions::scListShort) || parser.positionalArguments().contains(CommandLineOptions::scListLong)) { return CommandLineInterface(argc, argv).listInstalledPackages(); } else if (parser.positionalArguments().contains(CommandLineOptions::scSearchShort) || parser.positionalArguments().contains(CommandLineOptions::scSearchLong)) { return CommandLineInterface(argc, argv).searchAvailablePackages(); } else if (parser.positionalArguments().contains(CommandLineOptions::scUpdateShort) || parser.positionalArguments().contains(CommandLineOptions::scUpdateLong)) { return CommandLineInterface(argc, argv).updatePackages(); } else if (parser.positionalArguments().contains(CommandLineOptions::scInstallShort) || parser.positionalArguments().contains(CommandLineOptions::scInstallLong)) { return CommandLineInterface(argc, argv).installPackages(); } else if (parser.positionalArguments().contains(CommandLineOptions::scRemoveShort) || parser.positionalArguments().contains(CommandLineOptions::scRemoveLong)){ return CommandLineInterface(argc, argv).uninstallPackages(); } else if (parser.positionalArguments().contains(CommandLineOptions::scPurgeShort) || parser.positionalArguments().contains(CommandLineOptions::scPurgeLong)){ return CommandLineInterface(argc, argv).removeInstallation(); } if (QInstaller::isVerbose()) { std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl; } else { #ifdef Q_OS_WIN // Check if installer is started from console. If so, restart the installer so it // won't reserve the console handles. DWORD procIDs[2]; DWORD maxCount = 2; DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount); FreeConsole(); // Closes console in GUI version if (result > 1) { restarter.setRestartOnQuit(true); return EXIT_FAILURE; } #endif } return InstallerBase(argc, argv).run(); } catch (const QInstaller::Error &e) { std::cerr << qPrintable(e.message()) << std::endl; } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } catch (...) { std::cerr << "Unknown exception caught." << std::endl; } return EXIT_FAILURE; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/sdk.pro��������������������������������������������������������0100777�0000000�0000000�00000007436�13761647206�015765� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = app INCLUDEPATH += . .. TARGET = installerbase include(../../installerfw.pri) !isEmpty(SQUISH_PATH) { DEFINES += ENABLE_SQUISH include($$SQUISH_PATH/qtbuiltinhook.pri) } QT += network qml xml widgets # add the minimal plugin in static build to be able to start the installer headless with: # installer-binary --platform minimal # using QT += qpa_minimal_plugin would result in a minimal only compiled version !win32:CONFIG(static, static|shared) { QTPLUGIN += qminimal } CONFIG(static, static|shared) { # prevent qmake from automatically linking in imageformats, bearer, qmltooling plugins QTPLUGIN.imageformats = - QTPLUGIN.bearer = - QTPLUGIN.qmltooling = - } DESTDIR = $$IFW_APP_PATH exists($$LRELEASE) { IB_TRANSLATIONS = $$files($$PWD/translations/*_??.ts) IB_TRANSLATIONS -= $$PWD/translations/ifw_en.ts empty_ts = "<TS></TS>" write_file($$OUT_PWD/translations/ifw_en.ts, empty_ts)|error("Aborting.") IB_TRANSLATIONS += $$OUT_PWD/translations/ifw_en.ts QMAKE_DISTCLEAN += translations/ifw_en.ts qrc_cont = \ "<RCC>" \ " <qresource prefix=\"/\">" for (file, IB_TRANSLATIONS) { lang = $$replace(file, .*_([^/]*)\\.ts, \\1) qlang = $${lang} qfile = $$[QT_INSTALL_TRANSLATIONS]/qtbase_$${lang}.qm !exists($$qfile) { qfile = $$[QT_INSTALL_TRANSLATIONS]/qt_$${qlang}.qm !exists($$qfile) { # get 'pt' from 'pt_BR', for example, to find 'qt_pt.qm' file qlang ~= s/_.*// qfile = $$[QT_INSTALL_TRANSLATIONS]/qtbase_$${lang}.qm !exists($$qfile) { qfile = $$[QT_INSTALL_TRANSLATIONS]/qt_$${qlang}.qm !exists($$qfile) { warning("No Qt translation for '$$lang'; skipping.") next() } } } } qrc_cont += \ " <file>translations/ifw_$${lang}.qm</file>" \ " <file alias=\"translations/qt_$${qlang}.qm\">$$qfile</file>" ACTIVE_IB_TRANSLATIONS += $$file RESOURCE_DEPS += $$qfile translations/ifw_$${lang}.qm } qrc_cont += \ " </qresource>" \ "</RCC>" RESOURCE = $$OUT_PWD/installerbase.qrc write_file($$RESOURCE, qrc_cont)|error("Aborting.") QMAKE_DISTCLEAN += $$RESOURCE !isEmpty(ACTIVE_IB_TRANSLATIONS) { updateqm.input = ACTIVE_IB_TRANSLATIONS updateqm.output = translations/${QMAKE_FILE_BASE}.qm updateqm.commands = $$LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} updateqm.name = LRELEASE ${QMAKE_FILE_IN} updateqm.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += updateqm exists($$RCC) { runrcc.input = RESOURCE runrcc.output = qrc_${QMAKE_FILE_BASE}.cpp runrcc.commands = $$RCC -name ${QMAKE_FILE_BASE} ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} runrcc.name = RCC ${QMAKE_FILE_IN} runrcc.CONFIG += no_link explicit_dependencies runrcc.depends = $$RESOURCE_DEPS runrcc.variable_out = SOURCES QMAKE_EXTRA_COMPILERS += runrcc } } } FORMS += settingsdialog.ui HEADERS += \ tabcontroller.h \ installerbasecommons.h \ settingsdialog.h \ sdkapp.h \ commandlineinterface.h \ installerbase.h SOURCES = \ main.cpp \ installerbase.cpp \ tabcontroller.cpp \ installerbasecommons.cpp \ settingsdialog.cpp \ commandlineinterface.cpp win32 { # Use our own manifest file CONFIG -= embed_manifest_exe RC_FILE = installerbase.rc } macx:include(../../no_app_bundle.pri) target.path = $$[QT_INSTALL_BINS] INSTALLS += target ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/sdkapp.h�������������������������������������������������������0100777�0000000�0000000�00000053762�13761647206�016120� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SDKAPP_H #define SDKAPP_H #include "commandlineparser.h" #include <binarycontent.h> #include <binaryformat.h> #include <fileio.h> #include <fileutils.h> #include <constants.h> #include <packagemanagercore.h> #include <settings.h> #include <productkeycheck.h> #include <binaryformatenginehandler.h> #include <filedownloaderfactory.h> #include <packagemanagerproxyfactory.h> #include <utils.h> #include <runoncechecker.h> #include <globals.h> #include <errors.h> #include <QApplication> #include <QDir> #include <QDirIterator> #include <QFileInfo> #include <QResource> #include <QLoggingCategory> #include <QUuid> #include <QMessageBox> #include <QMetaEnum> #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) template<class T> class SDKApp : public T { public: SDKApp(int& argc, char** argv) : T(argc, argv), m_runCheck(QDir::tempPath() + QLatin1Char('/') + qApp->applicationName() + QLatin1String("1234865.lock")) { m_parser.parse(QCoreApplication::arguments()); } virtual ~SDKApp() { foreach (const QByteArray &ba, m_resourceMappings) QResource::unregisterResource((const uchar*) ba.data(), QLatin1String(":/metadata")); } bool notify(QObject *receiver, QEvent *event) { try { return T::notify(receiver, event); } catch (std::exception &e) { qFatal("Exception thrown: %s", e.what()); } catch (...) { qFatal("Unknown exception caught."); } return false; } bool init(QString &errorMessage) { QString appname = qApp->applicationName(); if (m_runCheck.isRunning(RunOnceChecker::ConditionFlag::Lockfile)) { // It is possible to install an application and thus the maintenance tool into a // directory that requires elevated permission to create a lock file. Since this // cannot be done without requesting credentials from the user, we silently ignore // the fact that we could not create the lock file and check the running processes. if (m_runCheck.isRunning(RunOnceChecker::ConditionFlag::ProcessList)) { errorMessage = QObject::tr("Another %1 instance is already running. Wait " "until it finishes, close it, or restart your system.").arg(qAppName()); return false; } } QFile binary(binaryFile()); #ifdef Q_OS_WIN // On some admin user installations it is possible that the installer.dat // file is left without reading permissions for non-administrator users, // we should check this and prompt the user to run the executable as admin if needed. if (!binary.open(QIODevice::ReadOnly)) { QFileInfo binaryInfo(binary.fileName()); errorMessage = QObject::tr("Please make sure that the current user has reading access " "to file \"%1\" or try running %2 as an administrator.").arg(binaryInfo.fileName(), qAppName()); return false; } binary.close(); #endif QString fileName = datFile(binaryFile()); quint64 cookie = QInstaller::BinaryContent::MagicCookieDat; if (fileName.isEmpty()) { fileName = binaryFile(); cookie = QInstaller::BinaryContent::MagicCookie; } binary.setFileName(fileName); QInstaller::openForRead(&binary); qint64 magicMarker; QInstaller::ResourceCollectionManager manager; QList<QInstaller::OperationBlob> oldOperations; QInstaller::BinaryContent::readBinaryContent(&binary, &oldOperations, &manager, &magicMarker, cookie); // Usually resources simply get mapped into memory and therefore the file does not need to be // kept open during application runtime. Though in case of offline installers we need to access // the appended binary content (packages etc.), so we close only in maintenance mode. if (magicMarker != QInstaller::BinaryContent::MagicInstallerMarker) binary.close(); bool isCommandLineInterface = false; foreach (const QString &option, CommandLineOptions::scCommandLineInterfaceOptions) { if (m_parser.positionalArguments().contains(option)) { isCommandLineInterface = true; break; } } if (m_parser.isSet(CommandLineOptions::scDeprecatedCheckUpdates)) isCommandLineInterface = true; QString loggingRules; if (m_parser.isSet(CommandLineOptions::scLoggingRulesLong)) { loggingRules = QLatin1String("ifw.* = false\n"); loggingRules += m_parser.value(CommandLineOptions::scLoggingRulesLong) .split(QLatin1Char(','), QString::SkipEmptyParts) .join(QLatin1Char('\n')); // take rules from command line } else if (isCommandLineInterface) { loggingRules = QLatin1String("ifw.* = false\n" "ifw.installer.* = true\n" "ifw.server = true\n" "ifw.progress.indicator = true\n" "ifw.package.name = true\n" "ifw.package.version = true\n" "ifw.package.displayname = true\n"); } else { // enable all except detailed package information and developer specific logging loggingRules = QLatin1String("ifw.* = true\n" "ifw.developer.build = false\n" "ifw.package.* = false\n" "ifw.package.name = true\n" "ifw.package.version = true\n" "ifw.package.displayname = true\n"); } if (QInstaller::verboseLevel() > 1) { loggingRules += QLatin1String("\nifw.developer.build = true\n" "ifw.package.* = true\n"); } QLoggingCategory::setFilterRules(loggingRules); qCDebug(QInstaller::lcInstallerInstallLog).noquote() << "Arguments:" << QCoreApplication::arguments().join(QLatin1String(", ")); dumpResourceTree(); SDKApp::registerMetaResources(manager.collectionByName("QResources")); QInstaller::BinaryFormatEngineHandler::instance()->registerResources(manager.collections()); const QHash<QString, QString> userArgs = userArguments(); if (m_parser.isSet(CommandLineOptions::scStartClientLong)) { const QStringList arguments = m_parser.value(CommandLineOptions::scStartClientLong) .split(QLatin1Char(','), QString::SkipEmptyParts); m_core = new QInstaller::PackageManagerCore( magicMarker, oldOperations, arguments.value(0, QLatin1String(QInstaller::Protocol::DefaultSocket)), arguments.value(1, QLatin1String(QInstaller::Protocol::DefaultAuthorizationKey)), QInstaller::Protocol::Mode::Debug, userArgs, isCommandLineInterface); } else { m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations, QUuid::createUuid().toString(), QUuid::createUuid().toString(), QInstaller::Protocol::Mode::Production, userArgs, isCommandLineInterface); } // Set this for convenience usage with the installer JS object m_core->setValue(QLatin1String("FrameworkVersion"), QLatin1String(QUOTE(IFW_VERSION_STR))); // From Qt5.8 onwards system proxy is used by default. If Qt is built with // QT_USE_SYSTEM_PROXIES false then system proxies are not used by default. if (m_parser.isSet(CommandLineOptions::scNoProxyLong)) { m_core->settings().setProxyType(QInstaller::Settings::NoProxy); KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); } else if (QNetworkProxyFactory::usesSystemConfiguration()) { m_core->settings().setProxyType(QInstaller::Settings::SystemProxy); KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); } if (m_parser.isSet(CommandLineOptions::scShowVirtualComponentsLong)) QInstaller::PackageManagerCore::setVirtualComponentsVisible(true); // IFW 3.x.x style --updater option support provided for backward compatibility if (m_parser.isSet(CommandLineOptions::scStartUpdaterLong) || m_parser.isSet(CommandLineOptions::scDeprecatedUpdater)) { if (m_core->isInstaller()) { errorMessage = QObject::tr("Cannot start installer binary as updater."); return false; } m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUpdaterMarker); } if (m_parser.isSet(CommandLineOptions::scStartPackageManagerLong)) { if (m_core->isInstaller()) { errorMessage = QObject::tr("Cannot start installer binary as package manager."); return false; } m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicPackageManagerMarker); } if (m_parser.isSet(CommandLineOptions::scStartUninstallerLong)) { if (m_core->isInstaller()) { errorMessage = QObject::tr("Cannot start installer binary as uninstaller."); return false; } m_core->setUserSetBinaryMarker(QInstaller::BinaryContent::MagicUninstallerMarker); } if (m_parser.isSet(CommandLineOptions::scAddRepositoryLong)) { const QStringList repoList = repositories(m_parser.value(CommandLineOptions::scAddRepositoryLong)); if (repoList.isEmpty()) { errorMessage = QObject::tr("Empty repository list for option 'addRepository'."); return false; } m_core->addUserRepositories(repoList); } if (m_parser.isSet(CommandLineOptions::scAddTmpRepositoryLong)) { const QStringList repoList = repositories(m_parser.value(CommandLineOptions::scAddTmpRepositoryLong)); if (repoList.isEmpty()) { errorMessage = QObject::tr("Empty repository list for option 'addTempRepository'."); return false; } m_core->setTemporaryRepositories(repoList, false); } if (m_parser.isSet(CommandLineOptions::scSetTmpRepositoryLong)) { const QStringList repoList = repositories(m_parser.value(CommandLineOptions::scSetTmpRepositoryLong)); if (repoList.isEmpty()) { errorMessage = QObject::tr("Empty repository list for option 'setTempRepository'."); return false; } m_core->setTemporaryRepositories(repoList, true); } if (m_parser.isSet(CommandLineOptions::scInstallCompressedRepositoryLong)) { const QStringList repoList = repositories(m_parser.value(CommandLineOptions::scInstallCompressedRepositoryLong)); if (repoList.isEmpty()) { errorMessage = QObject::tr("Empty repository list for option 'installCompressedRepository'."); return false; } foreach (QString repository, repoList) { if (!QFileInfo::exists(repository)) { errorMessage = QObject::tr("The file %1 does not exist.").arg(repository); return false; } } m_core->setTemporaryRepositories(repoList, false, true); } // Disable checking for free space on target if (m_parser.isSet(CommandLineOptions::scNoSizeCheckingLong)) m_core->setCheckAvailableSpace(false); QInstaller::PackageManagerCore::setNoForceInstallation(m_parser .isSet(CommandLineOptions::scNoForceInstallationLong)); QInstaller::PackageManagerCore::setNoDefaultInstallation(m_parser .isSet(CommandLineOptions::scNoDefaultInstallationLong)); QInstaller::PackageManagerCore::setCreateLocalRepositoryFromBinary(m_parser .isSet(CommandLineOptions::scCreateLocalRepositoryLong) || m_core->settings().createLocalRepository()); if (m_parser.isSet(CommandLineOptions::scAcceptLicensesLong)) m_core->setAutoAcceptLicenses(); if (m_parser.isSet(CommandLineOptions::scConfirmCommandLong)) m_core->setAutoConfirmCommand(); // Ignore message acceptance options when running the installer with GUI if (m_core->isCommandLineInstance()) { if (m_parser.isSet(CommandLineOptions::scAcceptMessageQueryLong)) m_core->autoAcceptMessageBoxes(); if (m_parser.isSet(CommandLineOptions::scRejectMessageQueryLong)) m_core->autoRejectMessageBoxes(); if (m_parser.isSet(CommandLineOptions::scMessageDefaultAnswerLong)) m_core->acceptMessageBoxDefaultButton(); if (m_parser.isSet(CommandLineOptions::scMessageAutomaticAnswerLong)) { const QString positionalArguments = m_parser.value(CommandLineOptions::scMessageAutomaticAnswerLong); const QStringList items = positionalArguments.split(QLatin1Char(','), QString::SkipEmptyParts); if (items.count() > 0) { errorMessage = setMessageBoxAutomaticAnswers(items); if (!errorMessage.isEmpty()) return false; } else { errorMessage = QObject::tr("Arguments missing for option %1") .arg(CommandLineOptions::scMessageAutomaticAnswerLong); return false; } } if (m_parser.isSet(CommandLineOptions::scFileDialogAutomaticAnswer)) { const QString positionalArguments = m_parser.value(CommandLineOptions::scFileDialogAutomaticAnswer); const QStringList items = positionalArguments.split(QLatin1Char(','), QString::SkipEmptyParts); foreach (const QString &item, items) { if (item.contains(QLatin1Char('='))) { const QString name = item.section(QLatin1Char('='), 0, 0); QString value = item.section(QLatin1Char('='), 1, 1); m_core->setFileDialogAutomaticAnswer(name, value); } } } } try { ProductKeyCheck::instance()->init(m_core); } catch (const QInstaller::Error &e) { errorMessage = e.message(); return false; } ProductKeyCheck::instance()->addPackagesFromXml(QLatin1String(":/metadata/Updates.xml")); return true; } /*! Returns the installer binary or installer.dat. In case of an installer this will be the installer binary itself, which contains the binary layout and the binary content. In case of an maintenance tool, it will return a .dat file that has just a binary layout as the binary layout cannot be appended to the actual maintenance tool binary itself because of signing. On macOS: This function will return always the .dat file .dat file is located inside the resource folder in the application bundle in macOS. */ QString binaryFile() const { QString binaryFile = QCoreApplication::applicationFilePath(); // The installer binary on macOS and Windows does not contain the binary // content, it's put into the resources folder as separate file. // Adjust the actual binary path. No error checking here since we // will fail later while reading the binary content. QDir resourcePath(QFileInfo(binaryFile).dir()); #ifdef Q_OS_MACOS resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); #endif QString datFilePath = resourcePath.filePath(QLatin1String("installer.dat")); if (QFileInfo::exists(datFilePath)) return datFilePath; return binaryFile; } /*! Returns the corresponding .dat file for a given installer / maintenance tool binary or an empty string if it fails to find one. */ QString datFile(const QString &binaryFile) const { QFile file(binaryFile); QInstaller::openForRead(&file); const quint64 cookiePos = QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie); if (!file.seek(cookiePos - sizeof(qint64))) // seek to read the marker return QString(); // ignore error, we will fail later const qint64 magicMarker = QInstaller::retrieveInt64(&file); if (magicMarker == QInstaller::BinaryContent::MagicUninstallerMarker) { QFileInfo fi(binaryFile); QString bundlePath; if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath)) fi.setFile(bundlePath); #ifdef Q_OS_MACOS return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat")); #else return fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat")); #endif } return QString(); } void registerMetaResources(const QInstaller::ResourceCollection &collection) { foreach (const QSharedPointer<QInstaller::Resource> &resource, collection.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) continue; if (!resource->seek(0)) continue; const QByteArray ba = resource->readAll(); if (ba.isEmpty()) continue; if (QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) m_resourceMappings.append(ba); if (!isOpen) // If we reach that point, either the resource was opened already... resource->close(); // or we did open it and have to close it again. } } QStringList repositories(const QString &list) const { const QStringList items = list.split(QLatin1Char(','), QString::SkipEmptyParts); foreach (const QString &item, items) qCDebug(QInstaller::lcInstallerInstallLog) << "Adding custom repository:" << item; return items; } QHash<QString, QString> userArguments() { QHash<QString, QString> params; const QStringList positionalArguments = m_parser.positionalArguments(); foreach (const QString &argument, positionalArguments) { if (argument.contains(QLatin1Char('='))) { const QString name = argument.section(QLatin1Char('='), 0, 0); const QString value = argument.section(QLatin1Char('='), 1, 1); params.insert(name, value); } } return params; } QString setMessageBoxAutomaticAnswers(const QStringList &items) { foreach (const QString &item, items) { if (item.contains(QLatin1Char('='))) { const QMetaObject metaObject = QMessageBox::staticMetaObject; int enumIndex = metaObject.indexOfEnumerator("StandardButton"); if (enumIndex != -1) { QMetaEnum en = metaObject.enumerator(enumIndex); const QString name = item.section(QLatin1Char('='), 0, 0); QString value = item.section(QLatin1Char('='), 1, 1); value.prepend(QLatin1String("QMessageBox::")); bool ok = false; int buttonValue = en.keyToValue(value.toLocal8Bit().data(), &ok); if (ok) m_core->setMessageBoxAutomaticAnswer(name, buttonValue); else return QObject::tr("Invalid button value %1 ").arg(value); } } else { return QObject::tr("Incorrect arguments for %1") .arg(CommandLineOptions::scMessageAutomaticAnswerLong); } } return QString(); } void dumpResourceTree() const { qCDebug(QInstaller::lcDeveloperBuild) << "Resource tree:"; QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden, QDirIterator::Subdirectories); while (it.hasNext()) { if (it.next().startsWith(QLatin1String(":/qt-project.org"))) continue; qCDebug(QInstaller::lcDeveloperBuild) << " " << it.filePath().toUtf8().constData(); } } private: QList<QByteArray> m_resourceMappings; public: QInstaller::PackageManagerCore *m_core; CommandLineParser m_parser; RunOnceChecker m_runCheck; }; #endif // SDKAPP_H ��������������qt-installer-framework-4.0.1/src/sdk/settingsdialog.cpp���������������������������������������������0100777�0000000�0000000�00000041257�13761647206�020205� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "settingsdialog.h" #include "ui_settingsdialog.h" #include <packagemanagercore.h> #include <productkeycheck.h> #include <testrepository.h> #include <QtCore/QFile> #include <QItemSelectionModel> #include <QMessageBox> #include <QTreeWidget> #include <QtXml/QDomDocument> using namespace QInstaller; // -- PasswordDelegate void PasswordDelegate::showPasswords(bool show) { m_showPasswords = show; } void PasswordDelegate::disableEditing(bool disable) { m_disabledEditor = disable; } QString PasswordDelegate::displayText(const QVariant &value, const QLocale &locale) const { const QString tmp = QStyledItemDelegate::displayText(value, locale); if (m_showPasswords) return tmp; return QString(tmp.length(), QChar(0x25CF)); } QWidget *PasswordDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { if (m_disabledEditor) return nullptr; QLineEdit *lineEdit = new QLineEdit(parent); lineEdit->setEchoMode(m_showPasswords ? QLineEdit::Normal : QLineEdit::Password); return lineEdit; } // -- RepositoryItem RepositoryItem::RepositoryItem(const QString &label) : QTreeWidgetItem(QTreeWidgetItem::UserType) { setText(0, label); m_repo = QInstaller::Repository(QUrl(), true); } RepositoryItem::RepositoryItem(const Repository &repo) : QTreeWidgetItem(QTreeWidgetItem::UserType) , m_repo(repo) { if (!repo.isDefault()) setFlags(flags() | Qt::ItemIsEditable); } QVariant RepositoryItem::data(int column, int role) const { const QVariant &data = QTreeWidgetItem::data(column, role); switch (role) { case Qt::UserRole: { if (column == 0) return m_repo.isDefault(); } break; case Qt::CheckStateRole: { if (column == 1) return (m_repo.isEnabled() ? Qt::Checked : Qt::Unchecked); } break; case Qt::EditRole: case Qt::DisplayRole:{ switch (column) { case 0: return data.toString().isEmpty() ? QLatin1String(" ") : data; case 2: return m_repo.username(); case 3: return m_repo.password(); case 4: return m_repo.displayname(); default: break; }; } break; case Qt::ToolTipRole: switch (column) { case 1: return SettingsDialog::tr("Check this to use repository during fetch."); case 2: return SettingsDialog::tr("Add the username to authenticate on the server."); case 3: return SettingsDialog::tr("Add the password to authenticate on the server."); case 4: return SettingsDialog::tr("The servers URL that contains a valid repository."); default: return QVariant(); } break; break; }; return data; } void RepositoryItem::setData(int column, int role, const QVariant &value) { switch (role) { case Qt::EditRole: { switch (column) { case 2: m_repo.setUsername(value.toString()); break; case 3: m_repo.setPassword(value.toString()); break; case 4: m_repo.setUrl(QUrl::fromUserInput(value.toString())); break; default: break; }; } break; case Qt::CheckStateRole: { if (column == 1) m_repo.setEnabled(Qt::CheckState(value.toInt()) == Qt::Checked); } break; default: break; } QTreeWidgetItem::setData(column, role, value); } QSet<Repository> RepositoryItem::repositories() const { QSet<Repository> set; for (int i = 0; i < childCount(); ++i) { if (QTreeWidgetItem *item = child(i)) { if (item->type() == QTreeWidgetItem::UserType) { if (RepositoryItem *repoItem = static_cast<RepositoryItem*> (item)) set.insert(repoItem->repository()); } } } return set; } // -- SettingsDialog SettingsDialog::SettingsDialog(PackageManagerCore *core, QWidget *parent) : QDialog(parent) , m_ui(new Ui::SettingsDialog) , m_core(core) , m_showPasswords(false) { m_ui->setupUi(this); setupRepositoriesTreeWidget(); const Settings &settings = m_core->settings(); switch (settings.proxyType()) { case Settings::NoProxy: m_ui->m_noProxySettings->setChecked(true); break; case Settings::SystemProxy: m_ui->m_systemProxySettings->setChecked(true); break; case Settings::UserDefinedProxy: m_ui->m_manualProxySettings->setChecked(true); break; default: m_ui->m_noProxySettings->setChecked(true); Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown proxy type given!"); } const QNetworkProxy &ftpProxy = settings.ftpProxy(); m_ui->m_ftpProxy->setText(ftpProxy.hostName()); m_ui->m_ftpProxyPort->setValue(ftpProxy.port()); const QNetworkProxy &httpProxy = settings.httpProxy(); m_ui->m_httpProxy->setText(httpProxy.hostName()); m_ui->m_httpProxyPort->setValue(httpProxy.port()); connect(m_ui->m_addRepository, &QAbstractButton::clicked, this, &SettingsDialog::addRepository); connect(m_ui->m_showPasswords, &QAbstractButton::clicked, this, &SettingsDialog::updatePasswords); connect(m_ui->m_removeRepository, &QAbstractButton::clicked, this, &SettingsDialog::removeRepository); connect(m_ui->m_useTmpRepositories, &QAbstractButton::clicked, this, &SettingsDialog::useTmpRepositoriesOnly); connect(m_ui->m_repositoriesView, &QTreeWidget::currentItemChanged, this, &SettingsDialog::currentRepositoryChanged); connect(m_ui->m_testRepository, &QAbstractButton::clicked, this, &SettingsDialog::testRepository); connect(m_ui->m_selectAll, &QAbstractButton::clicked, this, &SettingsDialog::selectAll); connect(m_ui->m_deselectAll, &QAbstractButton::clicked, this, &SettingsDialog::deselectAll); useTmpRepositoriesOnly(settings.hasReplacementRepos()); m_ui->m_useTmpRepositories->setChecked(settings.hasReplacementRepos()); m_ui->m_useTmpRepositories->setEnabled(settings.hasReplacementRepos()); m_ui->m_repositoriesView->setCurrentItem(m_rootItems.at(settings.hasReplacementRepos())); if (!settings.repositorySettingsPageVisible()) { // workaround a inconvenience that the page won't hide inside a QTabWidget m_ui->m_repositories->setParent(this); m_ui->m_repositories->setVisible(settings.repositorySettingsPageVisible()); } } void SettingsDialog::accept() { bool settingsChanged = false; Settings newSettings; const Settings &settings = m_core->settings(); // set possible updated default repositories newSettings.setDefaultRepositories((dynamic_cast<RepositoryItem*> (m_rootItems.at(0)))->repositories()); settingsChanged |= (settings.defaultRepositories() != newSettings.defaultRepositories()); // set possible new temporary repositories newSettings.setTemporaryRepositories((dynamic_cast<RepositoryItem*> (m_rootItems.at(1)))->repositories(), m_ui->m_useTmpRepositories->isChecked()); settingsChanged |= (settings.temporaryRepositories() != newSettings.temporaryRepositories()); settingsChanged |= (settings.hasReplacementRepos() != newSettings.hasReplacementRepos()); // set possible new user repositories newSettings.setUserRepositories((dynamic_cast<RepositoryItem*> (m_rootItems.at(2)))->repositories()); settingsChanged |= (settings.userRepositories() != newSettings.userRepositories()); // update proxy type newSettings.setProxyType(Settings::NoProxy); if (m_ui->m_systemProxySettings->isChecked()) newSettings.setProxyType(Settings::SystemProxy); else if (m_ui->m_manualProxySettings->isChecked()) newSettings.setProxyType(Settings::UserDefinedProxy); settingsChanged |= settings.proxyType() != newSettings.proxyType(); if (newSettings.proxyType() == Settings::UserDefinedProxy) { // update ftp proxy settings newSettings.setFtpProxy(QNetworkProxy(QNetworkProxy::HttpProxy, m_ui->m_ftpProxy->text(), m_ui->m_ftpProxyPort->value())); settingsChanged |= (settings.ftpProxy() != newSettings.ftpProxy()); // update http proxy settings newSettings.setHttpProxy(QNetworkProxy(QNetworkProxy::HttpProxy, m_ui->m_httpProxy->text(), m_ui->m_httpProxyPort->value())); settingsChanged |= (settings.httpProxy() != newSettings.httpProxy()); } if (settingsChanged) emit networkSettingsChanged(newSettings); QDialog::accept(); } // -- private slots void SettingsDialog::addRepository() { int index = 0; QTreeWidgetItem *parent = m_ui->m_repositoriesView->currentItem(); if (parent && !m_rootItems.contains(parent)) { parent = parent->parent(); index = parent->indexOfChild(m_ui->m_repositoriesView->currentItem()); } if (parent) { Repository repository; repository.setEnabled(true); RepositoryItem *item = new RepositoryItem(repository); parent->insertChild(index, item); m_ui->m_repositoriesView->editItem(item, 4); m_ui->m_repositoriesView->scrollToItem(item); m_ui->m_repositoriesView->setCurrentItem(item); if (parent == m_rootItems.value(1)) m_ui->m_useTmpRepositories->setEnabled(parent->childCount() > 0); } } void SettingsDialog::testRepository() { RepositoryItem *current = dynamic_cast<RepositoryItem*> (m_ui->m_repositoriesView->currentItem()); if (current && !m_rootItems.contains(current)) { m_ui->tabWidget->setEnabled(false); m_ui->buttonBox->setEnabled(false); TestRepository testJob(m_core); testJob.setRepository(current->repository()); testJob.start(); testJob.waitForFinished(); current->setRepository(testJob.repository()); QMessageBox msgBox(this); msgBox.setIcon(QMessageBox::Question); msgBox.setWindowModality(Qt::WindowModal); msgBox.setDetailedText(testJob.errorString()); const bool isError = (testJob.error() > Job::NoError); const bool isEnabled = current->data(1, Qt::CheckStateRole).toBool(); msgBox.setText(isError ? tr("An error occurred while testing this repository.") : tr("The repository was tested successfully.")); const bool showQuestion = (isError == isEnabled); msgBox.setStandardButtons(showQuestion ? QMessageBox::Yes | QMessageBox::No : QMessageBox::Close); msgBox.setDefaultButton(showQuestion ? QMessageBox::Yes : QMessageBox::Close); if (showQuestion) { msgBox.setInformativeText(isEnabled ? tr("Do you want to disable the repository?") : tr("Do you want to enable the repository?") ); } if (msgBox.exec() == QMessageBox::Yes) current->setData(1, Qt::CheckStateRole, (!isEnabled) ? Qt::Checked : Qt::Unchecked); m_ui->tabWidget->setEnabled(true); m_ui->buttonBox->setEnabled(true); } } void SettingsDialog::updatePasswords() { m_showPasswords = !m_showPasswords; m_delegate->showPasswords(m_showPasswords); m_ui->m_showPasswords->setText(m_showPasswords ? tr("Hide Passwords") : tr("Show Passwords")); // force an tree view update so the delegate has to repaint m_ui->m_repositoriesView->viewport()->update(); } void SettingsDialog::removeRepository() { QTreeWidgetItem *item = m_ui->m_repositoriesView->currentItem(); if (item && !m_rootItems.contains(item)) { QTreeWidgetItem *parent = item->parent(); if (parent) { delete parent->takeChild(parent->indexOfChild(item)); if (parent == m_rootItems.value(1) && parent->childCount() <= 0) { useTmpRepositoriesOnly(false); m_ui->m_useTmpRepositories->setChecked(false); m_ui->m_useTmpRepositories->setEnabled(false); } } } } void SettingsDialog::useTmpRepositoriesOnly(bool use) { m_rootItems.at(0)->setDisabled(use); m_rootItems.at(2)->setDisabled(use); } void SettingsDialog::currentRepositoryChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { Q_UNUSED(previous) if (current) { const int index = m_rootItems.at(0)->indexOfChild(current); m_ui->m_testRepository->setEnabled(!m_rootItems.contains(current)); m_ui->m_removeRepository->setEnabled(!current->data(0, Qt::UserRole).toBool()); m_ui->m_addRepository->setEnabled((current != m_rootItems.at(0)) & (index == -1)); } } void SettingsDialog::checkSubTree(QTreeWidgetItem *item, Qt::CheckState state) { if (item->flags() & Qt::ItemIsUserCheckable) item->setData(1, Qt::CheckStateRole, state); for (int i = 0; i < item->childCount(); i++) checkSubTree(item->child(i), state); } void SettingsDialog::selectAll() { for (int i = 0; i < m_ui->m_repositoriesView->topLevelItemCount(); i++) checkSubTree(m_ui->m_repositoriesView->topLevelItem(i), Qt::Checked); } void SettingsDialog::deselectAll() { for (int i = 0; i < m_ui->m_repositoriesView->topLevelItemCount(); i++) checkSubTree(m_ui->m_repositoriesView->topLevelItem(i), Qt::Unchecked); } // -- private void SettingsDialog::setupRepositoriesTreeWidget() { QTreeWidget *treeWidget = m_ui->m_repositoriesView; treeWidget->header()->setVisible(true); treeWidget->setHeaderLabels(QStringList() << QString() << tr("Use") << tr("Username") << tr("Password") << tr("Repository")); m_rootItems.append(new RepositoryItem(tr("Default repositories"))); m_rootItems.append(new RepositoryItem(tr("Temporary repositories"))); m_rootItems.append(new RepositoryItem(tr("User defined repositories"))); treeWidget->addTopLevelItems(m_rootItems); const Settings &settings = m_core->settings(); insertRepositories(settings.userRepositories(), m_rootItems.at(2)); insertRepositories(settings.defaultRepositories(), m_rootItems.at(0)); insertRepositories(settings.temporaryRepositories(), m_rootItems.at(1)); treeWidget->expandAll(); for (int i = 0; i < treeWidget->model()->columnCount(); ++i) treeWidget->resizeColumnToContents(i); treeWidget->header()->setSectionResizeMode(0, QHeaderView::Fixed); treeWidget->header()->setSectionResizeMode(1, QHeaderView::Fixed); treeWidget->header()->setMinimumSectionSize(treeWidget->columnWidth(1)); treeWidget->setItemDelegateForColumn(0, new PasswordDelegate(treeWidget)); treeWidget->setItemDelegateForColumn(1, new PasswordDelegate(treeWidget)); treeWidget->setItemDelegateForColumn(3, m_delegate = new PasswordDelegate(treeWidget)); m_delegate->showPasswords(false); m_delegate->disableEditing(false); } void SettingsDialog::insertRepositories(const QSet<Repository> repos, QTreeWidgetItem *rootItem) { rootItem->setFirstColumnSpanned(true); foreach (const Repository &repo, repos) { RepositoryItem *item = new RepositoryItem(repo); rootItem->addChild(item); item->setHidden(!ProductKeyCheck::instance()->isValidRepository(repo)); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/settingsdialog.h�����������������������������������������������0100777�0000000�0000000�00000007327�13761647206�017652� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H #include <repository.h> #include <settings.h> #include <QDialog> #include <QStyledItemDelegate> #include <QTreeWidgetItem> QT_BEGIN_NAMESPACE class QAuthenticator; class QLocale; class QVariant; namespace Ui { class SettingsDialog; } QT_END_NAMESPACE namespace QInstaller { class PackageManagerCore; } // -- PasswordDelegate class PasswordDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit PasswordDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) , m_showPasswords(true) , m_disabledEditor(true) {} void showPasswords(bool show); void disableEditing(bool disable); protected: QString displayText(const QVariant &value, const QLocale &locale) const; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const; private: bool m_showPasswords; bool m_disabledEditor; }; // -- RepositoryItem class RepositoryItem : public QTreeWidgetItem { public: explicit RepositoryItem(const QString &label); explicit RepositoryItem(const QInstaller::Repository &repo); QVariant data(int column, int role) const; void setData(int column, int role, const QVariant &value); QSet<QInstaller::Repository> repositories() const; QInstaller::Repository repository() const { return m_repo; } void setRepository(const QInstaller::Repository &repo) { m_repo = repo; } private: QInstaller::Repository m_repo; }; // -- SettingsDialog class SettingsDialog : public QDialog { Q_OBJECT public: explicit SettingsDialog(QInstaller::PackageManagerCore *core, QWidget *parent = 0); public slots: void accept(); signals: void networkSettingsChanged(const QInstaller::Settings &settings); private slots: void addRepository(); void testRepository(); void updatePasswords(); void removeRepository(); void useTmpRepositoriesOnly(bool use); void currentRepositoryChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void selectAll(); void deselectAll(); private: void setupRepositoriesTreeWidget(); void insertRepositories(const QSet<QInstaller::Repository> repos, QTreeWidgetItem *rootItem); void checkSubTree(QTreeWidgetItem *item, Qt::CheckState state); private: Ui::SettingsDialog *m_ui; PasswordDelegate *m_delegate; QInstaller::PackageManagerCore *m_core; bool m_showPasswords; QList<QTreeWidgetItem*> m_rootItems; }; #endif // SETTINGSDIALOG_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/settingsdialog.ui����������������������������������������������0100777�0000000�0000000�00000031600�13761647206�020027� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>SettingsDialog</class> <widget class="QDialog" name="SettingsDialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>543</width> <height>443</height> </rect> </property> <property name="windowTitle"> <string>Settings</string> </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> <number>0</number> </property> <widget class="QWidget" name="m_network"> <attribute name="title"> <string>Network</string> </attribute> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QRadioButton" name="m_noProxySettings"> <property name="text"> <string>No proxy</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item> <widget class="QRadioButton" name="m_systemProxySettings"> <property name="enabled"> <bool>true</bool> </property> <property name="text"> <string>System proxy settings</string> </property> <property name="checked"> <bool>false</bool> </property> </widget> </item> <item> <widget class="QRadioButton" name="m_manualProxySettings"> <property name="text"> <string>Manual proxy configuration</string> </property> </widget> </item> <item> <widget class="QWidget" name="m_rootWidget" native="true"> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <widget class="QLabel" name="m_httpProxyLabel"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>HTTP proxy:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLineEdit" name="m_httpProxy"> <property name="enabled"> <bool>false</bool> </property> </widget> </item> <item row="0" column="2"> <widget class="QLabel" name="m_httpProxyPortLabel"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>Port:</string> </property> </widget> </item> <item row="0" column="3"> <widget class="QSpinBox" name="m_httpProxyPort"> <property name="enabled"> <bool>false</bool> </property> <property name="maximum"> <number>65535</number> </property> </widget> </item> <item row="1" column="0"> <widget class="QWidget" name="m_httpAuthWidget" native="true"> <property name="enabled"> <bool>false</bool> </property> <layout class="QGridLayout" name="gridLayout_2"> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> </layout> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="m_ftpProxyLabel"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>FTP proxy:</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QLineEdit" name="m_ftpProxy"> <property name="enabled"> <bool>false</bool> </property> </widget> </item> <item row="2" column="2"> <widget class="QLabel" name="m_ftpProxyPortLabel"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>Port:</string> </property> </widget> </item> <item row="2" column="3"> <widget class="QSpinBox" name="m_ftpProxyPort"> <property name="enabled"> <bool>false</bool> </property> <property name="maximum"> <number>65535</number> </property> </widget> </item> <item row="3" column="0"> <widget class="QWidget" name="m_ftpAuthWidget" native="true"> <property name="enabled"> <bool>false</bool> </property> <layout class="QGridLayout" name="gridLayout"> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> </layout> </widget> </item> <item row="3" column="2"> <spacer name="verticalSpacer_2"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>0</height> </size> </property> </spacer> </item> </layout> </widget> </item> </layout> </widget> <widget class="QWidget" name="m_repositories"> <attribute name="title"> <string>Repositories</string> </attribute> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="m_httpAuthLabel"> <property name="text"> <string>Add Username and Password for authentication if needed.</string> </property> </widget> </item> <item> <widget class="QTreeWidget" name="m_repositoriesView"> <column> <property name="text"> <string notr="true">1</string> </property> </column> </widget> </item> <item> <widget class="QCheckBox" name="m_useTmpRepositories"> <property name="text"> <string>Use temporary repositories only</string> </property> </widget> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QPushButton" name="m_addRepository"> <property name="text"> <string>Add</string> </property> </widget> </item> <item> <widget class="QPushButton" name="m_removeRepository"> <property name="text"> <string>Remove</string> </property> </widget> </item> <item> <widget class="QPushButton" name="m_testRepository"> <property name="text"> <string>Test</string> </property> </widget> </item> <item> <widget class="QPushButton" name="m_selectAll"> <property name="text"> <string>Select All</string> </property> </widget> </item> <item> <widget class="QPushButton" name="m_deselectAll"> <property name="text"> <string>Deselect All</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="m_showPasswords"> <property name="text"> <string>Show Passwords</string> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> </layout> </widget> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>accepted()</signal> <receiver>SettingsDialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>269</x> <y>422</y> </hint> <hint type="destinationlabel"> <x>157</x> <y>274</y> </hint> </hints> </connection> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>SettingsDialog</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>337</x> <y>422</y> </hint> <hint type="destinationlabel"> <x>286</x> <y>274</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_httpProxyLabel</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>104</x> <y>74</y> </hint> <hint type="destinationlabel"> <x>121</x> <y>97</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_httpProxy</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>232</x> <y>77</y> </hint> <hint type="destinationlabel"> <x>232</x> <y>97</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_httpProxyPort</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>392</x> <y>74</y> </hint> <hint type="destinationlabel"> <x>392</x> <y>96</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_httpProxyPortLabel</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>349</x> <y>78</y> </hint> <hint type="destinationlabel"> <x>347</x> <y>96</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_ftpProxyPortLabel</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>336</x> <y>77</y> </hint> <hint type="destinationlabel"> <x>336</x> <y>241</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_ftpProxyLabel</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>61</x> <y>76</y> </hint> <hint type="destinationlabel"> <x>109</x> <y>243</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_ftpProxy</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>204</x> <y>78</y> </hint> <hint type="destinationlabel"> <x>203</x> <y>248</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_ftpProxyPort</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>406</x> <y>78</y> </hint> <hint type="destinationlabel"> <x>380</x> <y>252</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_httpAuthWidget</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>54</x> <y>79</y> </hint> <hint type="destinationlabel"> <x>53</x> <y>179</y> </hint> </hints> </connection> <connection> <sender>m_manualProxySettings</sender> <signal>toggled(bool)</signal> <receiver>m_ftpAuthWidget</receiver> <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>73</x> <y>76</y> </hint> <hint type="destinationlabel"> <x>56</x> <y>298</y> </hint> </hints> </connection> </connections> </ui> ��������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/tabcontroller.cpp����������������������������������������������0100777�0000000�0000000�00000014526�13761647206�020036� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "tabcontroller.h" #include "installerbasecommons.h" #include "settingsdialog.h" #include "globals.h" #include <packagemanagercore.h> #include <productkeycheck.h> #include <QtCore/QTimer> using namespace QInstaller; // -- TabController::Private class TabController::Private { public: Private(); ~Private(); bool m_init; QString m_controlScript; QHash<QString, QString> m_params; Settings m_settings; bool m_networkSettingsChanged; QInstaller::PackageManagerGui *m_gui; QInstaller::PackageManagerCore *m_core; }; TabController::Private::Private() : m_init(false) , m_networkSettingsChanged(false) , m_gui(nullptr) , m_core(nullptr) { } TabController::Private::~Private() { delete m_gui; } // -- TabController TabController::TabController(QObject *parent) : QObject(parent) , d(new Private) { } TabController::~TabController() { d->m_core->writeMaintenanceTool(); delete d; } void TabController::setGui(QInstaller::PackageManagerGui *gui) { d->m_gui = gui; connect(d->m_gui, &PackageManagerGui::gotRestarted, this, &TabController::restartWizard); } void TabController::setControlScript(const QString &script) { d->m_controlScript = script; } void TabController::setManager(QInstaller::PackageManagerCore *core) { d->m_core = core; } // -- public slots int TabController::init() { if (!d->m_init) { d->m_init = true; // this should called as early as possible, to handle error message boxes for example if (!d->m_controlScript.isEmpty()) { d->m_gui->loadControlScript(d->m_controlScript); qCDebug(QInstaller::lcInstallerInstallLog) << "Using control script:" << d->m_controlScript; } connect(d->m_gui, &QWizard::currentIdChanged, this, &TabController::onCurrentIdChanged); connect(d->m_gui, &PackageManagerGui::settingsButtonClicked, this, &TabController::onSettingsButtonClicked); } IntroductionPage *page = qobject_cast<IntroductionPage*> (d->m_gui->page(PackageManagerCore::Introduction)); if (page) { page->setMessage(QString()); page->setErrorMessage(QString()); page->onCoreNetworkSettingsChanged(); } d->m_gui->restart(); d->m_gui->setVisible(!d->m_gui->isSilent()); onCurrentIdChanged(d->m_gui->currentId()); return PackageManagerCore::Success; } // -- private slots void TabController::restartWizard() { d->m_core->reset(); if (d->m_networkSettingsChanged) { d->m_networkSettingsChanged = false; d->m_core->settings().setFtpProxy(d->m_settings.ftpProxy()); d->m_core->settings().setHttpProxy(d->m_settings.httpProxy()); d->m_core->settings().setProxyType(d->m_settings.proxyType()); d->m_core->settings().setUserRepositories(d->m_settings.userRepositories()); d->m_core->settings().setDefaultRepositories(d->m_settings.defaultRepositories()); d->m_core->settings().setTemporaryRepositories(d->m_settings.temporaryRepositories(), d->m_settings.hasReplacementRepos()); d->m_core->networkSettingsChanged(); } // Make sure we are writing the .dat file with the list of uninstall operations already now. // Otherwise we will write at the end of the next updater run, with a potentially // empty component list (if no updates are found). d->m_core->writeMaintenanceTool(); // restart and switch back to intro page QTimer::singleShot(0, this, &TabController::init); } void TabController::onSettingsButtonClicked() { SettingsDialog dialog(d->m_core); // set custom stylesheet const QString styleSheetFile = d->m_core->settings().styleSheet(); if (!styleSheetFile.isEmpty()) { QFile sheet(styleSheetFile); if (sheet.exists()) { if (sheet.open(QIODevice::ReadOnly)) { dialog.setStyleSheet(QString::fromLatin1(sheet.readAll())); } else { qCWarning(QInstaller::lcDeveloperBuild) << "The specified style sheet file " "can not be opened."; } } else { qCWarning(QInstaller::lcDeveloperBuild) << "A style sheet file is specified, " "but it does not exist."; } } connect(&dialog, &SettingsDialog::networkSettingsChanged, this, &TabController::onNetworkSettingsChanged); dialog.exec(); if (d->m_networkSettingsChanged) { d->m_core->setCanceled(); IntroductionPage *page = qobject_cast<IntroductionPage*> (d->m_gui->page(PackageManagerCore::Introduction)); if (page) { page->setMessage(QString()); page->setErrorMessage(QString()); } restartWizard(); } } void TabController::onCurrentIdChanged(int newId) { if (d->m_gui) { if (PackageManagerPage *page = qobject_cast<PackageManagerPage *>(d->m_gui->page(newId))) d->m_gui->showSettingsButton(page->settingsButtonRequested()); } } void TabController::onNetworkSettingsChanged(const QInstaller::Settings &settings) { d->m_settings = settings; d->m_networkSettingsChanged = true; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/tabcontroller.h������������������������������������������������0100777�0000000�0000000�00000004125�13761647206�017475� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef TABCONTROLLER_H #define TABCONTROLLER_H #include <QtCore/QHash> #include <QtCore/QObject> namespace QInstaller { class PackageManagerGui; class PackageManagerCore; class Settings; } class IntroductionPageImpl; class TabController : public QObject { Q_OBJECT Q_DISABLE_COPY(TabController) public: explicit TabController(QObject *parent = 0); ~TabController(); void setGui(QInstaller::PackageManagerGui *gui); void setManager(QInstaller::PackageManagerCore *core); void setControlScript(const QString &script); public Q_SLOTS: int init(); private Q_SLOTS: void restartWizard(); void onSettingsButtonClicked(); void onCurrentIdChanged(int newId); void onNetworkSettingsChanged(const QInstaller::Settings &settings); private: class Private; Private *const d; }; #endif // TABCONTROLLER_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/��������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�017171� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_ca.ts�����������������������������������������0100777�0000000�0000000�00000315767�13761647206�021014� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="ca"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>El servidor intermediari requereix autenticaciÃģ.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>No s'ha pogut cercar a %1 per a llegir les dades de les operacions.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>No s'ha pogut cercar a %1 per a llegir el bloc de la col·lecciÃģ de recursos.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>No s'ha pogut obrir el recurs de metadades %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>No s'ha pogut cercar a %1 per a llegir el recompte de les metadades incrustades.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>No s'ha pogut cercar a %1 per a llegir el segment de la col·lecciÃģ de recursos.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Discrepància inesperada en els recursos de metadades. S'han llegit %1, s'esperaven: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Es requereix autenticaciÃģ HTTP</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Cal proporcionar un nom d'usuari i una contrasenya per accedir a aquest lloc.</translation> </message> <message> <source>Username:</source> <translation>Nom d'usuari:</translation> </message> <message> <source>Password:</source> <translation>Contrasenya:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>El camí ÂŦ%1Âŧ existeix, perÃē no ÃĐs un directori.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>No s'ha pogut recuperar el camí de l'element d'arxiu %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>No s'ha pogut eliminar l'enllaç simbÃēlic existent %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>No s'ha pogut crear l'enllaç simbÃēlic a ÂŦ%1Âŧ. Ja n'hi ha un altre.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>No s'ha pogut llegir la destinaciÃģ de l'enllaç simbÃēlic des del fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>No s'ha pogut crear l'enllaç simbÃēlic a %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>S'està esperant a %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Ja s'està executant una altra instància de %1. Espereu a que finalitzi, tanqueu-la o reinicieu el sistema.</translation> </message> <message> <source>Cannot open file "%1" for reading</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura</translation> </message> <message> <source>Please make sure that the current user has reading access to file "%1" or try running %2 as an administrator.</source> <translation>Assegureu-vos que l'usuari actual tÃĐ accÃĐs de lectura al fitxer ÂŦ%1Âŧ o intenteu executar %2 com a administrador.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Components afegits com a dependÃĻncies automàtiques:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Components afegits com a dependÃĻncia per a ÂŦ%1Âŧ:</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Components que tenen dependÃĻncies resoltes:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Components seleccionats sense dependÃĻncies:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>S'ha detectat una recurrÃĻncia, el component ÂŦ%1Âŧ ja s'ha afegit amb la raÃģ: ÂŦ%2Âŧ</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>No s'ha pogut trobar la dependÃĻncia ÂŦ%1Âŧ que falta per a ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>S'ha cancel·lat</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>No s'ha pogut trobar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>No s'ha pogut copiar un fitxer que no existeix: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No s'ha pogut copiar el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>No s'ha pogut suprimir el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat dins de ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>S'ha completat la descàrrega.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Els resums criptogràfics no coincideixen.</translation> </message> <message> <source>Download canceled.</source> <translation>S'ha cancel·lat de descàrrega.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>S'ha descarregat %1.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/seg)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dia, </numerusform> <numerusform>%n dies, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora, </numerusform> <numerusform>%n hores, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minut</numerusform> <numerusform>%n minuts</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segon</numerusform> <numerusform>%n segons</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - resta %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - temps restant desconegut.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>No s'ha pogut descarregar %1. Error en escriure al fitxer ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>No s'ha pogut descarregar %1. No s'ha pogut crear el fitxer ÂŦ%2Âŧ: %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>La sol·licitud d'autenticaciÃģ s'ha cancel·lat.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Error en la connexiÃģ segura</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>S'ha produÃŊt un error durant la connexiÃģ amb: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Podria tractar-se d'un problema amb la configuraciÃģ del servidor o algÚ que està intentant suplantar al servidor.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Si en el passat ja s'ha connectat correctament amb aquest servidor o bÃĐ confieu en ell, podeu intentar-ho de nou perquÃĻ ÃĐs possible que es tracti d'un error temporal.</translation> </message> <message> <source>Try again</source> <translation>Torna a intentar-ho</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Ha fallat en escriure al fitxer ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconegut.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No s'ha pogut eliminar el directori ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No s'ha pogut copiar el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>No s'ha pogut trobar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No s'ha pogut restaurar el fitxer de cÃēpia de seguretat per a ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>No s'ha pogut llegir el fitxer de recursos ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>No s'ha pogut eliminar el directori ÂŦ%1Âŧ: %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>El directori no existeix.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>No s'ha pogut tornar a crear el directori ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>S'ha iniciat %1</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>No s'ha pogut aturar %1</translation> </message> <message> <source>Cannot stop task %1</source> <translation>No s'ha pogut aturar la tasca %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>No s'ha pogut fer pausa de %1</translation> </message> <message> <source>Cannot pause task %1</source> <translation>No s'ha pogut fer pausa de la tasca %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>No s'ha pogut reprendre la tasca %1</translation> </message> <message> <source>%1 done</source> <translation>%1 s'ha fet</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>No s'ha pogut accedir a la informaciÃģ del paquet d'aquesta aplicaciÃģ.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>No hi ha establerta cap font de paquet per a aquesta aplicaciÃģ.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>S'ha trobat %n actualitzaciÃģ.</numerusform> <numerusform>S'han trobat %n actualitzacions.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>S'està descarregant Updates.xml des de les fuents d'actualitzaciÃģ.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>No s'ha pogut descarregar la font del paquet %1 des de ÂŦ%2Âŧ.</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>El/s fitxer/s Updates.xml descarregat/s des de les fonts d'actualitzaciÃģ.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>S'estan calculant les actualitzacions vàlides.</translation> </message> <message> <source>Application updates computed.</source> <translation>Actualitzacions d'aplicaciÃģ calculades.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml tÃĐ un contingut no vàlid: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>No s'ha pogut llegir ÂŦ%1Âŧ</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Error d'anàlisi en %1 a %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Element arrel %1 inesperat, hauria de ser ÂŦUpdatesÂŧ.</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Manca l'element ÂŦApplicationNameÂŧ.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Manca l'element ÂŦApplicationVersionÂŧ.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Element ÂŦPackageUpdateÂŧ sense nom</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Element ÂŦPackageUpdateÂŧ sense versiÃģ</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Element ÂŦPackageUpdateÂŧ sense data de publicaciÃģ</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>codi intern: %1</translation> </message> <message> <source>not enough memory</source> <translation>no hi ha prou memÃēria</translation> </message> <message> <source>Error: %1</source> <translation>Error: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>No s'ha pogut recuperar la propietat %1 de l'element %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>La propietat %1 de l'element %2 no ÃĐs del tipus VT_FILETIME sinÃģ %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>No s'ha pogut convertir l'hora UTC del fitxer a l'hora del sistema.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>No s'han pogut carregar els cÃēdecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>No s'ha pogut obrir l'arxiu ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>No s'ha pogut recuperar el nombre d'elements a l'arxiu.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>No s'ha pogut recuperar el camí de l'element d'arxiu ÂŦ%1Âŧ.</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>No s'ha pogut crear el fitxer temporal: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Tipus d'arxiu no admÃĻs.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>No s'ha pogut crear l'arxiu ÂŦ%1Âŧ</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>No s'ha pogut crear l'arxiu ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>No s'ha pogut eliminar l'arxiu antic ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>No s'ha pogut canviar el nom de l'arxiu temporal ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 tÃĐ un contingut no vàlid: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>El fitxer %1 no existeix.</translation> </message> <message> <source>Cannot open %1.</source> <translation>No s'ha pogut obrir %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Error en analitzar en %1 a %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>No s'esperava l'element arrel %1, hauria de ser ÂŦPackagesÂŧ.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>No s'ha pogut crear el fitxer de bloqueig ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>No s'ha pogut escriure el PID en el fitxer de bloqueig ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>No s'ha pogut obtenir el bloqueig per al fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>No s'ha pogut alliberar el bloqueig per al fitxer ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>No s'ha trobat cap marcador, s'ha aturat desprÃĐs de %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Error de lectura desprÃĐs de %1 bytes: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Ha fallat en copiar: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Ha fallat en escriure desprÃĐs de %1 bytes: %2</translation> </message> <message> <source>bytes</source> <translation>bytes</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No s'ha pogut eliminar el directori ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>No s'ha pogut copiar el fitxer des de ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>No s'ha pogut moure el fitxer des de ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>No s'ha pogut obrir el fitxer temporal: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>No s'ha pogut obrir el fitxer temporal per a la plantilla %1: %2</translation> </message> <message> <source>The specified module could not be found.</source> <translation>No s'ha trobat el mÃēdul especificat.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Els components no poden tenir elements secundaris en el mode actualitzador.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>No s'ha pogut obrir el fitxer UI ÂŦ%1Âŧ sol·licitat: %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>No s'ha pogut carregar el fitxer UI ÂŦ%1Âŧ sol·licitat: %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>No s'ha pogut obrir el fitxer de llicÃĻncia ÂŦ%1Âŧ sol·licitat: %2</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Error: l'operaciÃģ %1 no existeix.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>No s'ha pogut resoldre ÂŦisDefaultÂŧ en %1</translation> </message> <message> <source>There was an error loading the selected component. This component can not be installed.</source> <translation>S'ha produÃŊt un error en carregar el component seleccionat. Aquest component no es pot instal·lar.</translation> </message> <message> <source>Update Info: </source> <translation>InformaciÃģ de l'actualitzaciÃģ: </translation> </message> <message> <source>There was an error loading the selected component. This component can not be updated.</source> <translation>S'ha produÃŊt un error en carregar el component seleccionat. Aquest component no es pot actualitzar.</translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>El component està marcat per a la instal·laciÃģ.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>El component està marcat per a la desinstal·laciÃģ.</translation> </message> <message> <source>Component is installed.</source> <translation>El component està instal·lat.</translation> </message> <message> <source>Component is not installed.</source> <translation>El component no està instal·lat.</translation> </message> <message> <source>Component Name</source> <translation>Nom del component</translation> </message> <message> <source>Action</source> <translation>AcciÃģ</translation> </message> <message> <source>Installed Version</source> <translation>VersiÃģ instal·lada</translation> </message> <message> <source>New Version</source> <translation>VersiÃģ nova</translation> </message> <message> <source>Release Date</source> <translation>Data de la versiÃģ</translation> </message> <message> <source>Size</source> <translation>Mida</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>Predetermin&at</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&Restableix</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&Selecciona-ho tot</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>&Desselecciona-ho tot</translation> </message> <message> <source>&Browse QBSP files</source> <translation>Explora els fitxers Q&BSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Aquest component ocuparà aproximadament %1 en el disc dur.</translation> </message> <message> <source>Open File</source> <translation>Obre un fitxer</translation> </message> <message> <source>Select Components</source> <translation>Selecciona els components</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Seleccioneu els components que voleu actualitzar.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Seleccioneu els components que voleu instal·lar.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Seleccioneu els components que voleu desinstal·lar.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Seleccioneu els components que voleu instal·lar. Desseleccioneu els components instal·lats per a desinstal·lar-los. No s'actualitzaran els components ja instal·lats.</translation> </message> <message> <source>Mandatory components need to be updated first before you can select other components to update.</source> <translation>Cal que actualitzeu els components obligatoris abans de poder seleccionar altres components per actualitzar-los.</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPagePrivate</name> <message> <source>Filter</source> <translation>Filtre</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><per a desar el nom de la clau de l’instal·lador> <executable> [argument_1] [argument_2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L'objecte de l'instal·lador necessari en l'operaciÃģ %1 està buit.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>No s'ha pogut desar la sortida de ÂŦ%1Âŧ a un valor de clau buit de l'instal·lador.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>El fitxer ÂŦ%1Âŧ no existeix o no ÃĐs un binari executable.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>L'execuciÃģ de ÂŦ%1Âŧ ha resultat en una fallada.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><origen> <destinaciÃģ> [ÂŦforceOverwriteÂŧ]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Argument no vàlid a %1: el tercer argument hauria de ser ÂŦforceOverwriteÂŧ, si s'ha especificat.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Argument no vàlid a %1: el directori ÂŦ%2Âŧ no ÃĐs vàlid.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ.</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Ha fallat en sobreescriure ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No s'ha pogut copiar el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Recompte no vàlid dels elements a la tasca.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Ha fallat en escriure al fitxer ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Ha fallat en sobreescriure el fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>No s'ha pogut escriure l'entrada d'escriptori a ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>No s'ha pogut crear l'enllaç entre ÂŦ%1Âŧ i ÂŦ%2Âŧ.</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>No s'ha pogut eliminar l'enllaç entre ÂŦ%1Âŧ i ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>No s'han pogut establir els permisos per al fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>No s'ha pogut moure el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>L'instal·lador de ÂŦ%1Âŧ necessita estar sense connexiÃģ.</translation> </message> <message> <source>Creating local repository into elevated permissions directory: %1 is not supported.</source> <translation>CreaciÃģ d'un repositori local en un directori de permisos elevats: no s'admet %1.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>No s'ha pogut llegir el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>No s'ha pogut crear el directori de destinaciÃģ: ÂŦ%1Âŧ.</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>S'està eliminant el fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No s'ha pogut eliminar el fitxer ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No s'ha pogut eliminar el directori ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><destinaciÃģ> <ubicaciÃģ de l'enllaç> [arguments de la destinaciÃģ] [ÂŦworkingDirectory=...Âŧ] [ÂŦiconPath=...Âŧ] [ÂŦiconId=...Âŧ] [ÂŦdescription=...Âŧ]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Ha fallat en sobreescriure ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>No s'ha pogut crear l'enllaç ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>S'ha cancel·lat</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Ha fallat en descarregar la signatura de la suma.</translation> </message> <message> <source>Download Error</source> <translation>Error en descarregar</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Ha fallat en la verificaciÃģ de la suma durant la descàrrega. És un error temporal, torneu a intentar-ho.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>No s'ha pogut verificar la suma</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>No s'ha pogut descarregar l'arxiu %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>No s'han pogut obtenir els arxius: %1 Error en descarregar %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>S'està descarregant l'arxiu ÂŦ%1Âŧ per al component %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Esquema %1 no admÃĻs (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>No s'ha pogut trobar el component per a %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>El fitxer de destinaciÃģ ÂŦ%1Âŧ ja existeix, perÃē no ÃĐs un fitxer.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error </extracomment> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error. </extracomment> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error. </extracomment> <translation>Ha fallat en escriure al fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>S'ha detectat un bucle de redirecciÃģ per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Error de xarxa durant la descàrrega de ÂŦ%1Âŧ: %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error </extracomment> <translation>Error de xarxa desconegut durant la descàrrega de ÂŦ%1Âŧ.</translation> </message> <message> <source>Network transfers canceled.</source> <translation>S'han cancel·lat les transferÃĻncies de xarxa.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>La pausa i la represa no estan admeses per les transferÃĻncies de xarxa.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error </extracomment> <translation>URL d'origen ÂŦ%1Âŧ no vàlid: %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>No s'ha pogut iniciar separat: ÂŦ%1Âŧ</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>No s'ha pogut iniciar: ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>El programa ha fallat: ÂŦ%1Âŧ</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Ha fallat durant l'execuciÃģ (codi d'error no esperat: %1): ÂŦ%2Âŧ</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation</name> <message> <source>Extracting "%1"</source> <translation>S'està extraient ÂŦ%1Âŧ</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Error en extreure l'arxiu ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda en extreure ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>No s'ha pogut obtenir el nucli del gestor de paquets.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Aquest procÃĐs s'ha d'aturar abans de continuar: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Aquests processos s'han d'aturar abans de continuar: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 rebut/s.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/seg)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dia, </numerusform> <numerusform>%n dies, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora, </numerusform> <numerusform>%n hores, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minut</numerusform> <numerusform>%n minuts</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segon</numerusform> <numerusform>%n segons</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - resta %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - temps restant desconegut.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>S'ha completat l'Assistent de %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Feu clic a %1 per a sortir de l'Assistent de %2.</translation> </message> <message> <source>Restart</source> <translation>Reinicia</translation> </message> <message> <source>Run %1 now.</source> <translation>Executa %1 ara.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>Ha fallat l'Assistent de %1.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>No s'han pogut escriure els ajustaments.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Ha fallat en escriure els ajustaments.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><camí d'origen> [prefix del proveÃŊdor]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Argument no vàlid: el directori d'origen no pot estar buit.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>No s'ha pogut crear una cÃēpia de seguretat del fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Ha fallat en sobreescriure ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Ha fallat en copiar el fitxer ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No s'ha pogut crear el directori ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Programa d'instal·laciÃģ: %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Us donem la benvinguda a l'Assistent de configuraciÃģ de %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>&Afegeix o elimina els components</translation> </message> <message> <source>&Update components</source> <translation>Act&ualitza els components</translation> </message> <message> <source>&Remove all components</source> <translation>E&limina tots els components</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>S'està recuperant la informaciÃģ des de les fonts d'instal·laciÃģ remotes...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Es requereix almenys un repositori vàlid i habilitat per a que aquesta acciÃģ es realitzi correctament.</translation> </message> <message> <source>No updates available.</source> <translation>No hi ha disponible cap actualitzaciÃģ.</translation> </message> <message> <source> Only local package management available.</source> <translation> NomÃĐs està disponible la gestiÃģ dels paquets locals.</translation> </message> <message> <source>&Quit</source> <translation>Su&rt</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Acord de llicÃĻncia</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Llegiu aquest acord de llicÃĻncia. Caldrà acceptar els termes continguts en aquest acord abans de continuar amb la instal·laciÃģ.</translation> </message> <message> <source>I accept the license.</source> <translation>Accepto la llicÃĻncia.</translation> </message> <message> <source>I do not accept the license.</source> <translation>No accepto la llicÃĻncia.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Llegiu els segÞents acords de llicÃĻncia. Cal acceptar els termes continguts en aquests acords abans de continuar amb la instal·laciÃģ.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Accepto les llicÃĻncies.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>No accepto les llicÃĻncies.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>No s'han trobat fitxers de llicÃĻncia per a copiar.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L'objecte de l'instal·lador necessari a l'operaciÃģ %1 està buit.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>No s'ha pogut escriure en el fitxer de llicÃĻncia ÂŦ%1Âŧ.</translation> </message> <message> <source>No license files found to delete.</source> <translation>No s'han trobat fitxers de llicÃĻncia per a suprimir.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Manca el motor del nucli del gestor de paquets.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>S'està preparant la descàrrega de la informaciÃģ de les metadades...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>S'estan desempaquetant els repositoris comprimits. Aquesta operaciÃģ pot trigar una estona...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>S'ha cancel·lat la descàrrega de les metadades.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda durant l'extracciÃģ.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Manquen les credencials del servidor intermediari.</translation> </message> <message> <source>Authentication failed.</source> <translation>Ha fallat l'autenticaciÃģ.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda durant la descàrrega.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Ha fallat en recuperar els repositoris.</translation> </message> <message> <source>Extracting meta information...</source> <translation>S'està extraient la informaciÃģ de les metadades...</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>S'ha detectat una discrepància en la suma de verificaciÃģ per a ÂŦ%1Âŧ.</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>S'està recuperant la informaciÃģ de les metadades des del repositori remot... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>S'està recuperant la informaciÃģ de les metadades des del repositori remot... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Error en extreure l'arxiu ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>S'ha produÃŊt una excepciÃģ desconeguda en extreure l'arxiu ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Error en escriure a l'Eina de manteniment</translation> </message> <message> <source> Downloading packages...</source> <translation> S'estan descarregant els paquets...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Instal·laciÃģ cancel·lada per l'usuari.</translation> </message> <message> <source>All downloads finished.</source> <translation>S'han finalitzat totes les descàrregues.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>S'ha cancel·lant l'Instal·lador</translation> </message> <message> <source>Authentication Error</source> <translation>Error en l'autenticaciÃģ</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Alguns components no s'han pogut eliminar per complet perquÃĻ no s'han pogut adquirir els drets administratius: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconegut.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Alguns components no s'han pogut eliminar per complet perquÃĻ ha succeÃŊt un error desconegut.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>L'aplicaciÃģ no s'està executant en el mode Gestor de paquets.</translation> </message> <message> <source>No installed packages found.</source> <translation>No s'ha trobat cap paquet instal·lat.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>L'aplicaciÃģ s'està executant en el mode Desinstal·lador.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Hi ha disponible una actualitzaciÃģ important, executeu primer l'actualitzador.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>No s'han pogut resoldre totes les dependÃĻncies.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Components que estan a punt d'eliminar-se.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Error en elevar els drets d'accÃĐs.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>No hi ha prou espai en el disc per a emmagatzemar els fitxers temporals i la instal·laciÃģ. Es disposa d'un espai de %1 i almenys es requereixin %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>No hi ha prou espai en el disc per a emmagatzemar tots els components seleccionats. Es disposa d'un espai de %1 i almenys es requereixin %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>No hi ha prou espai en el disc per a emmagatzemar els fitxers temporals. Es disposa d'un espai de %1 i almenys es requereixin %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards.</source> <translation>El volum seleccionat per a la instal·laciÃģ sembla que tÃĐ espai suficient per a la instal·laciÃģ, perÃē desprÃĐs quedarà menys de l'1% de l'espai disponible del volum.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards.</source> <translation>El volum seleccionat per a la instal·laciÃģ sembla que tÃĐ espai suficient per a la instal·laciÃģ, perÃē desprÃĐs quedarà menys de 100 MB d'espai disponible.</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>La instal·laciÃģ usarà %1 d'espai en el disc.</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>invalid</source> <translation>no vàlid</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>DependÃĻncies sense resoldre</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>Access error</source> <translation>Error d'accÃĐs</translation> </message> <message> <source>Format error</source> <translation>Error de format</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>No s'ha pogut escriure la configuraciÃģ de l'instal·lador a %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Atura els processos</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Cal aturar aquests processos abans de continuar: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Instal·laciÃģ cancel·lada per l'usuari</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>S'està escrivint a l'eina de manteniment.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Ha fallat en cercar al fitxer %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>L'eina de manteniment no ÃĐs un paquet</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer de dades ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>No s'han pogut escriure les dades de l'eina de manteniment a %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>No s'ha pogut escriure a l'eina de manteniment a ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot remove temporary data file "%1": %2</source> <translation>No s'ha pogut eliminar el fitxer temporal de dades ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>No s'han pogut escriure les dades binàries de l'eina de manteniment a %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>No s'ha establert la variable ÂŦTargetDirÂŧ.</translation> </message> <message> <source>Preparing the installation...</source> <translation>S'està preparant la instal·laciÃģ...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>No ÃĐs possible instal·lar des d'una ubicaciÃģ a la xarxa</translation> </message> <message> <source>Creating local repository</source> <translation>S'està creant el repositori local</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>S'està creant l'Eina de manteniment</translation> </message> <message> <source> Installation finished!</source> <translation> S'ha finalitzat la instal·laciÃģ!</translation> </message> <message> <source> Installation aborted!</source> <translation> S'ha interromput la instal·laciÃģ!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>No ÃĐs possible executar aquesta operaciÃģ des d'una ubicaciÃģ a la xarxa</translation> </message> <message> <source>Removing deselected components...</source> <translation>S'estan eliminant els components desseleccionats...</translation> </message> <message> <source> Update finished!</source> <translation> Ha finalitzat l'actualitzaciÃģ!</translation> </message> <message> <source> Update aborted!</source> <translation> S'ha interromput l'actualitzaciÃģ!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>La desinstal·laciÃģ s'ha completat correctament.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>S'ha interromput la desinstal·laciÃģ.</translation> </message> <message> <source> Installing component %1</source> <translation> S'instal·la el component %1</translation> </message> <message> <source>Installer Error</source> <translation>Error de l'instal·lador</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Error durant el procÃĐs d'instal·laciÃģ (%1): %2</translation> </message> <message> <source>Done</source> <translation>Fet</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>No s'ha pogut preparar la desinstal·laciÃģ</translation> </message> <message> <source>Cannot start uninstall</source> <translation>No s'ha pogut iniciar la desinstal·laciÃģ</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Error durant el procÃĐs de desinstal·laciÃģ: %1</translation> </message> <message> <source>Unknown error</source> <translation>Error desconegut</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>No s'ha pogut recuperar l'arbre remot %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Ha fallat en llegir els paquets des de %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>No s'ha pogut recuperar la informaciÃģ de les metadades: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>No s'ha pogut afegir la informaciÃģ temporal de la font d'actualitzaciÃģ.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>No s'ha pogut trobar cap informaciÃģ de la font d'actualitzaciÃģ.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>S'ha detectat un cicle de dependÃĻncia entre components ÂŦ%1Âŧ i ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>Arranjament de %1</translation> </message> <message> <source>Maintain %1</source> <translation>Mantenir %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Voleu cancel·lar el procÃĐs d'instal·laciÃģ?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Voleu cancel·lar el procÃĐs de desinstal·laciÃģ?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Voleu sortir de l'aplicaciÃģ de l'instal·lador?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Voleu sortir de l'aplicaciÃģ del desinstal·lador?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Voleu sortir de l'aplicaciÃģ de manteniment?</translation> </message> <message> <source>%1 Question</source> <translation>Pregunta %1</translation> </message> <message> <source>Settings</source> <translation>Ajustaments</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>No ÃĐs possible instal·lar des d'una ubicaciÃģ a la xarxa. Copieu l'instal·lador en una unitat local</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>Mo&stra els detalls</translation> </message> <message> <source>&Hide Details</source> <translation>O&culta els detalls</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstal·la</translation> </message> <message> <source>Uninstalling %1</source> <translation>S'està desinstal·lant %1</translation> </message> <message> <source>&Update</source> <translation>Act&ualitza</translation> </message> <message> <source>Updating components of %1</source> <translation>S'estan actualitzant els components de %1</translation> </message> <message> <source>&Install</source> <translation>&Instal·la</translation> </message> <message> <source>Installing %1</source> <translation>S'està instal·lant %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Diàleg</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>El servidor intermediari %1 requereix un nom d'usuari i una contrasenya.</translation> </message> <message> <source>Username:</source> <translation>Nom d'usuari:</translation> </message> <message> <source>Username</source> <translation>Nom d'usuari</translation> </message> <message> <source>Password:</source> <translation>Contrasenya:</translation> </message> <message> <source>Password</source> <translation>Contrasenya</translation> </message> <message> <source>Proxy Credentials</source> <translation>Credencials del servidor intermediari</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstal·la</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Llest per a desinstal·lar</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>El programa d'instal·laciÃģ està preparat per a començar a eliminar %1 de l'ordinador.<br><font color="red">El directori del programa %2 se suprimirà completament</font>, incloent tot el contingut d'aquest directori.</translation> </message> <message> <source>U&pdate</source> <translation>A&ctualitza</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Llest per a actualitzar els paquets</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>El programa d'instal·laciÃģ està preparat per a començar a actualitzar la vostra instal·laciÃģ.</translation> </message> <message> <source>&Install</source> <translation>&Instal·la</translation> </message> <message> <source>Ready to Install</source> <translation>Llest per a instal·lar</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>El programa d'instal·laciÃģ està preparat per a començar a instal·lar %1 en el vostre ordinador.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source>Registering file types is only supported on Windows.</source> <translation>El registre dels tipus de fitxer nomÃĐs s'admet sobre Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Registre del tipus de fitxer: arguments no vàlids</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>No s'han pogut llegir totes les dades desprÃĐs d'enviar l'ordre: %1. Bytes esperats: %2. Bytes rebuts: %3. Error: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No s'ha pogut obrir el fitxer ÂŦ%1Âŧ per a escriptura: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>No s'ha pogut obrir el recurs %1 per a lectura.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Ha fallat en llegir desprÃĐs de %1 bytes: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Ha fallat en escriure desprÃĐs de %1 bytes: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>S'està completant l'Assistent d'instal·laciÃģ de %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>No s'ha pogut obrir el fitxer de script a %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>ExcepciÃģ en carregar l'script del component ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconegut.</translation> </message> <message> <source>on line number: </source> <translation>a la línia nÚmero: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>L'objecte de l'instal·lador necessari en l'operaciÃģ %1 està buit.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Reinici automàtic: nomÃĐs ÃĐs vàlid en els modes Actualitzador o Gestor de paquets.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Reinici automàtic: arguments no vàlids</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>El servidor requereix autenticaciÃģ</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Cal proporcionar un nom d'usuari i una contrasenya per accedir a aquest lloc.</translation> </message> <message> <source>Username:</source> <translation>Nom d'usuari:</translation> </message> <message> <source>Password:</source> <translation>Contrasenya:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Manquen arguments ÂŦ%1Âŧ que cridin a %2 amb els arguments ÂŦ%3Âŧ.</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>L'argument del mÃĻtode actual que crida a ÂŦ%1Âŧ amb els arguments ÂŦ%2Âŧ no està admÃĻs. Useu ÂŦsetÂŧ, ÂŦremoveÂŧ, ÂŦadd_array_valueÂŧ o ÂŦremove_array_valueÂŧ.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>No pot haver-hi cap argument buit: origen ÂŦ%1Âŧ, destinaciÃģ ÂŦ%2Âŧ.</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>No s'ha pogut moure el fitxer des de ÂŦ%1Âŧ a ÂŦ%2Âŧ, perquÃĻ el camí de destinaciÃģ ja existeix i no es pot eliminar.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>No s'ha pogut moure el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>S'està movent el fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Dreceres del menÚ d'Inici</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Seleccioneu al menÚ d'Inici a on voleu crear les dreceres del programa. TambÃĐ podeu introduir un nom per a crear un directori nou.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Carpeta d'instal·laciÃģ</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Especifiqueu el directori en el que s'instal·larà %1.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+X</translation> </message> <message> <source>B&rowse...</source> <translation>E&xplora...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>El directori que heu seleccionat ja existeix i contÃĐ una instal·laciÃģ. Trieu una altra destinaciÃģ per a la instal·laciÃģ.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Heu seleccionat un directori existent i no buit per a la instal·laciÃģ. Tingueu en compte que s'esborrarà del tot en desinstal·lar aquesta aplicaciÃģ. No ÃĐs recomanable instal·lar en aquest directori, ja que la instal·laciÃģ podria generar un error. Voleu continuar?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Heu seleccionat un fitxer o un enllaç simbÃēlic existent. Trieu una destinaciÃģ diferent per a la instal·laciÃģ.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Selecciona la carpeta d'instal·laciÃģ</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>El camí d'instal·laciÃģ no pot estar buit, especifiqueu un directori vàlid.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>El camí d'instal·laciÃģ no pot ser relatiu, especifiqueu un camí absolut.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>El camí o el directori d'instal·laciÃģ contÃĐ caràcters que no sÃģn ASCII. AixÃē no està admÃĻs actualment! Trieu un camí o un directori d'instal·laciÃģ diferent.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Ja que el directori d'instal·laciÃģ s'ha suprimit per complet, està prohibit instal·lar a %1.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>El camí que heu introduÃŊt ÃĐs massa llarg. Haureu d'especificar un camí vàlid.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>El camí que heu introduÃŊt no ÃĐs vàlid. Haureu d'especificar una destinaciÃģ vàlida.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>El camí que heu introduÃŊt no ÃĐs vàlid. Haureu d'especificar una unitat vàlida.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>El camí d'instal·laciÃģ no haurà de finalitzar amb ÂŦ.Âŧ. Especifiqueu un directori vàlid.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>El camí d'instal·laciÃģ no haurà de contenir ÂŦ%1Âŧ. Especifiqueu un directori vàlid.</translation> </message> <message> <source>Warning</source> <translation>Avís</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Manca el nucli del gestor de paquets.</translation> </message> <message> <source>Empty repository URL.</source> <translation>L'URL del repositori està buit.</translation> </message> <message> <source>Download canceled.</source> <translation>S'ha cancel·lat la descàrrega.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Temps d'espera durant les proves del repositori ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>No s'ha pogut analitzar Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>No s'ha pogut obrir Updates.xml per a lectura: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Ha fallat durant l'autenticaciÃģ.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Error desconegut durant les proves del repositori ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Es requereix autoritzaciÃģ</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>IntroduÃŊu la contrasenya per autoritzar el ÂŦsudoÂŧ:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Error en adquirir els drets d'administrador</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>No s'ha pogut obtenir l'autoritzaciÃģ.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>No s'ha pogut obtenir l'autoritzaciÃģ necessària per continuar la instal·laciÃģ. Inicieu el programa de configuraciÃģ amb un usuari amb els permisos apropiats. O accepteu l'elevaciÃģ dels drets d'accÃĐs si es demana.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>No s'ha pogut obtenir l'autoritzaciÃģ necessària per continuar la instal·laciÃģ. Interrompeu la instal·laciÃģ o useu la soluciÃģ alternativa de reserva executant %1 amb un usuari amb els permisos apropiats i desprÃĐs feu clic a D'acord. </translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>No s'ha pogut obrir el recurs %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>No s'ha pogut obrir el fitxer d'ajustaments %1 per a lectura: %2</translation> </message> <message> <source>Select Categories</source> <translation>Selecciona les categories dels paquets</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Ajustament</translation> </message> <message> <source>Network</source> <translation>Xarxa</translation> </message> <message> <source>No proxy</source> <translation>Sense servidor intermediari</translation> </message> <message> <source>System proxy settings</source> <translation>Ajustaments del servidor intermediari del sistema</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Ajustaments manuals per al servidor intermediari</translation> </message> <message> <source>HTTP proxy:</source> <translation>Servidor intermediari HTTP:</translation> </message> <message> <source>Port:</source> <translation>Port:</translation> </message> <message> <source>FTP proxy:</source> <translation>Servidor intermediari FTP:</translation> </message> <message> <source>Repositories</source> <translation>Repositoris</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Afegiu el nom d'usuari i la contrasenya per a l'autenticaciÃģ si ÃĐs necessari.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Usa nomÃĐs repositoris temporals</translation> </message> <message> <source>Add</source> <translation>Afegeix</translation> </message> <message> <source>Remove</source> <translation>Elimina</translation> </message> <message> <source>Test</source> <translation>Prova</translation> </message> <message> <source>Select All</source> <translation>Selecciona-ho tot</translation> </message> <message> <source>Deselect All</source> <translation>Desselecciona-ho tot</translation> </message> <message> <source>Show Passwords</source> <translation>Mostra les contrasenyes</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Marqueu aquesta opciÃģ per a usar el repositori durant l'obtenciÃģ.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Afegiu el nom d'usuari per a autenticar en el servidor.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Afegiu la contrasenya per a autenticar en el servidor.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>Els URL dels servidors que contenen un repositori vàlid.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>S'ha produÃŊt un error en provar aquest repositori.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Repositori provat amb ÃĻxit.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Voleu inhabilitar el repositori?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Voleu habilitar el repositori?</translation> </message> <message> <source>Hide Passwords</source> <translation>Oculta les contrasenyes</translation> </message> <message> <source>Use</source> <translation>Empra</translation> </message> <message> <source>Username</source> <translation>Nom d'usuari</translation> </message> <message> <source>Password</source> <translation>Contrasenya</translation> </message> <message> <source>Repository</source> <translation>Repositori</translation> </message> <message> <source>Default repositories</source> <translation>Repositoris predeterminats</translation> </message> <message> <source>Temporary repositories</source> <translation>Repositoris temporals</translation> </message> <message> <source>User defined repositories</source> <translation>Repositoris definits per l'usuari</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>No s'ha pogut escriure en el camí del registre %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>El camí del registre %1 no ÃĐs d'escriptura.</translation> </message> <message> <source>exactly %1</source> <translation>exactament %1</translation> </message> <message> <source>at least %1</source> <translation>almenys %1</translation> </message> <message> <source>not more than %1</source> <translation>no mÃĐs de %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 o %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 a %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Arguments no vàlids a %1: s'ha proporcionat %n argument, s'esperaven %2.</numerusform> <numerusform>Arguments no vàlids a %1: s'han proporcionat %n arguments, s'esperaven %2.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Arguments no vàlids a %1: s'ha proporcionat %n argument, s'esperaven %2 en la forma: %3.</numerusform> <numerusform>Arguments no vàlids a %1: s'han proporcionat %n arguments, s'esperaven %2 en la forma: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Ha fallat en canviar el nom del fitxer ÂŦ%1Âŧ a ÂŦ%2Âŧ: %3</translation> </message> </context> </TS> ���������qt-installer-framework-4.0.1/src/sdk/translations/ifw_da.ts�����������������������������������������0100777�0000000�0000000�00000301432�13761647206�020775� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="da"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 hos %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>Proxyen krÃĶver autentifikation.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Kan ikke sÃļge til %1 for at lÃĶse handlingsdataene.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Kan ikke sÃļge til %1 for at lÃĶse ressourcesamlingsblokken.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Kan ikke ÃĨbne metaressourcen %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Kan ikke sÃļge til %1 for at lÃĶse antallet af indlejret metadata.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Kan ikke sÃļge til %1 for at lÃĶse ressourcesamlingssegmentet.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Uventet uoverensstemmelse af metaressourcer. LÃĶste %1, ventede: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Http-autentifikation krÃĶvet</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Du skal angive brugernavn og adgangskode for at tilgÃĨ stedet.</translation> </message> <message> <source>Username:</source> <translation>Brugernavn:</translation> </message> <message> <source>Password:</source> <translation>Adgangskode:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 hos %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>Stien "%1" findes men er ikke en mappe.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Kan ikke oprette mappen "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Kan ikke hente stien af arkivposten %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Kan ikke fjerne allerede eksisterende symlink %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Kan ikke oprette symlink ved "%1". Et andet findes allerede.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Kan ikke lÃĶse symlink-mÃĨl fra filen "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Kan ikke oprette symlink ved %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Venter pÃĨ %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>En anden %1-instans kÃļrer allerede. Vent til den er fÃĶrdig, luk den eller genstart dit system.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Komponenter tilfÃļjet som automatiske afhÃĶngigheder:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Komponenter tilfÃļjet som afhÃĶngighed til "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Komponenter som har lÃļste afhÃĶngigheder:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Valgte komponenter uden afhÃĶngigheder:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Rekursion registreret, komponenten "%1" allerede tilfÃļjet med begrundelsen: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>Kan ikke finde manglende afhÃĶngighed "%1" til "%2".</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Annulleret</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Kan ikke sikkerhedskopiere filen "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Kan ikke finde sikkerhedskopieret fil for "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1": %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Kan ikke sikkerhedskopiere filen "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Kan ikke kopiere en ikke-eksisterende fil: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Kan ikke fjerne filen "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Kan ikke kopiere filen "%1" til "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Kan ikke slette filen "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Kan ikke genskabe sikkerhedskopieret fil ind i "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Kan ikke oprette sikkerhedskopi af filen "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1": %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Download fÃĶrdig.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Kryptografiske hashes matcher ikke.</translation> </message> <message> <source>Download canceled.</source> <translation>Download annulleret.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 af %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 downloadet.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sek.)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dag, </numerusform> <numerusform>%n dage, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n time, </numerusform> <numerusform>%n timer, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minut</numerusform> <numerusform>%n minutter</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n sekund</numerusform> <numerusform>%n sekunder</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 tilbage.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - ukendt tid tilbage.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Kan ikke downloade %1. Skrivning til filen "%2" mislykkedes: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Kan ikke downloade %1. Kan ikke oprette filen "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 hos %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Autentifikationsanmodning annulleret.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Sikker forbindelse mislykkedes</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Der opstod en fejl under forbindelse til: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Der kan vÃĶre et problem med serverens konfiguration eller det kan vÃĶre nogen som prÃļve at udgive sig for at vÃĶre serveren.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Hvis du fÃļrhen har oprettet forbindelse til serveren eller har tillid til serveren, kan fejlen vÃĶre midlertidig og du kan prÃļve igen.</translation> </message> <message> <source>Try again</source> <translation>PrÃļv igen</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Skrivning til filen "%1" mislykkedes: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Kan ikke oprette mappen "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Ukendt fejl.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Kan ikke fjerne mappen "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Kan ikke sikkerhedskopiere filen "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Kan ikke fjerne filen "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Kan ikke kopiere filen "%1" til "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Kan ikke fjerne filen "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Kan ikke sikkerhedskopiere filen "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Kan ikke finde sikkerhedskopieret fil for "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Kan ikke genskabe sikkerhedskopieret fil for "%1": %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Kan ikke lÃĶse ressourcefilen "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Kan ikke fjerne mappen "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>Mappen findes ikke.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Kan ikke genoprette mappen "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 startet</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 kan ikke stoppes</translation> </message> <message> <source>Cannot stop task %1</source> <translation>Kan ikke stoppe opgaven %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 kan ikke sÃĶttes pÃĨ pause</translation> </message> <message> <source>Cannot pause task %1</source> <translation>Kan ikke sÃĶtte opgaven %1 pÃĨ pause</translation> </message> <message> <source>Cannot resume task %1</source> <translation>Kan ikke genoptage opgaven %1</translation> </message> <message> <source>%1 done</source> <translation>%1 fÃĶrdig</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Kan ikke tilgÃĨ pakkeinformationen til programmet.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Ingen pakkekilder sat til programmet.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n opdatering fundet.</numerusform> <numerusform>%n opdateringer fundet.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Downloader Updates.xml fra opdateringskilder.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Kan ikke downloade pakkekilden %1 fra "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Updates.xml fil(er) downloadet fra opdateringskilder.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Udregner anvendelige opdateringer.</translation> </message> <message> <source>Application updates computed.</source> <translation>Programopdateringer udregnet.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml indeholder ugyldigt indhold: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Kan ikke lÃĶse "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Parse-fejl i %1 ved %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Rod-elementet %1 uventet, skulle vÃĶre "Updates".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>ApplicationName-element mangler.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>ApplicationVersion-element mangler.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>PackageUpdate-element uden Name</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>PackageUpdate-element uden Version</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>PackageUpdate-element uden ReleaseDate</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>intern kode: %1</translation> </message> <message> <source>not enough memory</source> <translation>ikke nok hukommelse</translation> </message> <message> <source>Error: %1</source> <translation>Fejl: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Kan ikke hente egenskaben %1 for posten %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>Egenskaben %1 for posten %2 ikke af typen VT_FILETIME men %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Kan ikke konvertere UTC-filtid til systemets tid.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Kan ikke indlÃĶse codecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Kan ikke ÃĨbne arkivet "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Kan ikke hente antal poster i arkiv.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Kan ikke hente stien af arkivposten "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Ukendt undtagelse fanget (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Kan ikke oprette midlertidig fil: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Ikke-understÃļttet arkivtype.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Kan ikke oprette arkivet "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Kan ikke oprette arkivet "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>Kan ikke fjerne gamle arkiv "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>Kan ikke omdÃļbe midlertidigt arkiv "%1" til "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Ukendt undtagelse fanget (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 indeholder ugyldigt indhold: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Filen %1 findes ikke.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Kan ikke ÃĨbne %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Parse-fejl i %1 ved %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Rod-elementet %1 uventet, skulle vÃĶre 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Kan ikke oprette lÃĨsfilen "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Kan ikke skrive PID til lÃĨsfilen "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Kan ikke fÃĨ lÃĨsfilen for filen "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Kan ikke frigive lÃĨsfilen for filen "%1": %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Ingen markÃļr fundet, stoppet efter %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>LÃĶsning mislykkedes efter %1 byte: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Kopiering mislykkedes: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Skrivning mislykkedes efter %1 byte: %2</translation> </message> <message> <source>bytes</source> <translation>byte</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Kan ikke fjerne filen "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Kan ikke fjerne mappen "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Kan ikke oprette mappen "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Kan ikke kopiere filen fra "%1" til "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Kan ikke flytte filen fra "%1" til "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Kan ikke oprette mappen "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Kan ikke ÃĨbne midlertidig fil: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Kan ikke ÃĨbne midlertidig fil til skabelonen %1: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>Ødelagt installation</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>Din installation ser ud til at vÃĶre Ãļdelagt. Overvej venligst at geninstallere from bunden.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Det angivne modul blev ikke fundet.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Komponenter mÃĨ ikke have bÃļrn i opdateringstilstand.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Kan ikke ÃĨbne den anmodede UI-fil "%1": %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Kan ikke indlÃĶse den anmodede UI-fil "%1": %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Kan ikke ÃĨbne den anmodede licensfil "%1": %2</translation> </message> <message> <source>Error</source> <translation>Fejl</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Fejl: handlingen %1 findes ikke.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Kan ikke lÃļse isDefault i %1</translation> </message> <message> <source>Update Info: </source> <translation>Opdateringsinfo: </translation> </message> <message> <source>There was an error loading the selected component. This component can not be installed.</source> <translation>Der opstod en fejl under indlÃĶsning af den valgte komponent. Komponentet kan ikke installeres.</translation> </message> <message> <source>There was an error loading the selected component. This component can not be updated.</source> <translation>Der opstod en fejl under indlÃĶsning af den valgte komponent. Komponentet kan ikke opdateres.</translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Komponenten er mÃĶrket til installation.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Komponenten er mÃĶrket til afinstallation.</translation> </message> <message> <source>Component is installed.</source> <translation>Komponenten er installeret.</translation> </message> <message> <source>Component is not installed.</source> <translation>Komponenten er ikke installeret.</translation> </message> <message> <source>Component Name</source> <translation>Komponentnavn</translation> </message> <message> <source>Action</source> <translation>Handling</translation> </message> <message> <source>Installed Version</source> <translation>Installeret version</translation> </message> <message> <source>New Version</source> <translation>Ny version</translation> </message> <message> <source>Release Date</source> <translation>Udgivelsesdato</translation> </message> <message> <source>Size</source> <translation>StÃļrrelse</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+S</translation> </message> <message> <source>Def&ault</source> <translation>&Standard</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+N</translation> </message> <message> <source>&Reset</source> <translation>&Nulstil</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+V</translation> </message> <message> <source>&Select All</source> <translation>&VÃĶlg alle</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+F</translation> </message> <message> <source>&Deselect All</source> <translation>&FravÃĶlg alle</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Gennemse repositorierne fra din computer, for at installere nyt komprimeret repository</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&Gennemse QBSP-filer</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>VÃĶlg de komponenter du vil installere. FravÃĶlg installeret komponenter for at afinstallere dem. Komponenter som allerede er installeret vil ikke blive opdateret.</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Komponenten vil optage cirka %1 pÃĨ dit harddisk-drev.</translation> </message> <message> <source>Open File</source> <translation>Åbn fil</translation> </message> <message> <source>Select Components</source> <translation>VÃĶlg komponenter</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>VÃĶlg venligst de komponenter du vil opdatere.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>VÃĶlg venligst de komponenter du vil installere.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>VÃĶlg venligst de komponenter du vil afinstallere.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><installer-nÃļglenavn som skal gammes> <eksekverbar> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>NÃļdvendigt installer-objekt i %1-handling er tomt.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Kan ikke gemme outputtet fra "%1" til en tom installer-nÃļglevÃĶrdi.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Filen "%1" findes ikke eller er ikke en eksekverbar binÃĶr.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>KÃļrsel af "%1" resulterede i at det holdt op med at virke.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><kilde> <mÃĨl> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Ugyldigt argument i %1: tredje argument skal vÃĶre forceOverwrite, hvis angivet.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Ugyldigt argument i %1: mappen "%2" er ugyldig.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Kan ikke oprette mappen "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Kunne ikke overskrive "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Kan ikke kopiere filen "%1" til "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Kan ikke fjerne filen "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Ugyldigt antal poster i opgave.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Skrivning til filen "%1" mislykkedes: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Kan ikke sikkerhedskopiere filen "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Kunne ikke overskrive filen "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Kan ikke skrive skrivebordspost til "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Kan ikke oprette link fra "%1" til "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Kan ikke fjerne link fra "%1" til "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Kan ikke sÃĶtte tilladelser for filen "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Kan ikke fjerne filen "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Kan ikke flytte filen "%1" til "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Installeren ved "%1" skal vÃĶre af typen offline.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Kan ikke lÃĶse filen "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Kan ikke oprette mÃĨl-mappen: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Ukendt undtagelse fanget: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Fjerner filen "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Kan ikke fjerne filen "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Kan ikke fjerne mappen "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><mÃĨl> <linkplacering> [mÃĨl-argumenter] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Kan ikke oprette mappen "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Kunne ikke overskrive "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Kan ikke oprette linket "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Annulleret</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Download af hash-signatur mislykkedes.</translation> </message> <message> <source>Download Error</source> <translation>Download-fejl</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Hash-verifikation under download mislykkedes. Det er en midlertidig fejl, prÃļv venligst igen.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>Kan ikke verificere hash</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Kan ikke downloade arkivet %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Kan ikke hente arkiver: %1 Fejl under indlÃĶsning af %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Downloader arkivet "%1" til komponenten %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Skemaet %1 understÃļttes ikke (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Kan ikke finde komponent til %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>MÃĨl-filen "%1" findes allerede men er ikke en fil.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Filen "%1" er ikke ÃĨben til skrivning: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Skrivning til filen "%1" mislykkedes: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>OmdirigeringslÃļkke registreret for "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>NetvÃĶrksfejl under download af '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Ukendt netvÃĶrksfejl under download af "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>NetvÃĶrksoverfÃļrsler annulleret.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>Pause og genoptag understÃļttes ikke af netvÃĶrksoverfÃļrsler.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Ugyldig kilde-URL "%1": %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Kan ikke starte afkoblet: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Kan ikke starte: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Programmet holdt op med at virke: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Eksekvering mislykkedes (uventet afslutningskode: %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne arkivet "%1" til lÃĶsning: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Fejl under udpakning af arkivet "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Ukendt undtagelse fanget under udpakning af "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Kan ikke fÃĨ pakkehÃĨndterings-kerne.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Processen bÃļr stoppes inden der fortsÃĶttes: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Disse processer bÃļr stoppes inden der fortsÃĶttes: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 af %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 modtaget.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sek.)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dag, </numerusform> <numerusform>%n dage, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n time, </numerusform> <numerusform>%n timer, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minut</numerusform> <numerusform>%n minutter</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n sekund</numerusform> <numerusform>%n sekunder</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 tilbage.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - ukendt tid tilbage.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>FuldfÃļrer %1-assistenten</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Klik pÃĨ %1 for at afslutte %2-assistenten.</translation> </message> <message> <source>Restart</source> <translation>Genstart</translation> </message> <message> <source>Run %1 now.</source> <translation>KÃļr %1 nu.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>%1-assistenten mislykkedes.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Indstillinger er ikke skrivbare.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Kunne ikke skrive indstillinger.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><kildesti> [producent prÃĶfiks]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Ugyldigt argument: kildemappen mÃĨ ikke vÃĶre tom.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Kan ikke sikkerhedskopiere filen "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Kunne ikke overskrive "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Kunne ikke kopiere filen "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Kan ikke oprette mappen "%1": %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>OpsÃĶtning - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Velkommen til opsÃĶtningsassistenten for %1.</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Henter information fra fjern-installationskilder...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Mindst ÃĐt gyldigt og aktiveret repository krÃĶvet for at handlingen skal lykkedes.</translation> </message> <message> <source>No updates available.</source> <translation>Ingen tilgÃĶngelige opdateringer.</translation> </message> <message> <source> Only local package management available.</source> <translation> Kun lokal pakkehÃĨndtering tilgÃĶngeligt.</translation> </message> <message> <source>&Add or remove components</source> <translation>&TilfÃļj eller fjern komponenter</translation> </message> <message> <source>&Update components</source> <translation>&Opdater komponenter</translation> </message> <message> <source>&Remove all components</source> <translation>&Fjern alle komponenter</translation> </message> <message> <source>&Quit</source> <translation>&Afslut</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Licensaftale</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+I</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>LÃĶs venligst fÃļlgende licensaftale. Du skal acceptere vilkÃĨrene i aftalen for at fortsÃĶtte installationen.</translation> </message> <message> <source>I accept the license.</source> <translation>Jeg accepterer licensen.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Jeg accepterer ikke licensen.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>LÃĶs venligst fÃļlgende licensaftaler. Du skal acceptere vilkÃĨrene i disse aftaler for at fortsÃĶtte installationen.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Jeg accepterer licenserne.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Jeg accepterer ikke licenserne.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Ingen licensfil fundet til kopiering.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>NÃļdvendigt installer-objekt i %1-handling er tomt.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Kan ikke skrive licensfilen "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Ingen licensfil fundet til sletning.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Manglende pakkehÃĨndterings-kernemotor.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Forbedreder download af metainformation...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Download af metadata annulleret.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Ukendt undtagelse under udpakning.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Manglende proxy-loginoplysninger.</translation> </message> <message> <source>Authentication failed.</source> <translation>Autentifikation mislykkedes.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Ukendt undtagelse under download.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Kunne ikke hente repositories.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Udpakker metainformation...</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Fejl under udpakning af arkivet "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Ukendt undtagelse fanget under udpakning af arkivet "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Udpakker komprimerede repositories. Det kan tage noget tid...</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Tjeksum uoverensstemmelse registreret for "%1".</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Henter metainformation fra fjern-repository... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Henter metainformation fra fjern-repository... </translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Fejl ved skrivning af vedligeholdelsesvÃĶrktÃļj</translation> </message> <message> <source> Downloading packages...</source> <translation> Downloader pakker...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Installation annulleret af bruger.</translation> </message> <message> <source>All downloads finished.</source> <translation>Alle downloads fÃĶrdige.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Annullerer installeren</translation> </message> <message> <source>Authentication Error</source> <translation>Autentifikationsfejl</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Nogle komponenter kunne ikke fjernes fuldstÃĶndigt da administrative rettigheder ikke kunne anskaffes: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Ukendt fejl.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Nogle komponenter kunne ikke fjernes fuldstÃĶndigt da der opstod en ukendt fejl.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>Program kÃļrer ikke i pakkehÃĨndteringstilstand.</translation> </message> <message> <source>No installed packages found.</source> <translation>Ingen installeret pakker fundet.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>Program kÃļrer i afinstallationstilstand.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Der er en vigtig opdatering tilgÃĶngelig, kÃļr venligst opdateringen fÃļrst.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Kan ikke lÃļse alle afhÃĶngigheder.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Komponenter som er ved at blive fjernet.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Fejl under ophÃļjelse af adgangsrettigheder.</translation> </message> <message> <source>Error</source> <translation>Fejl</translation> </message> <message> <source>invalid</source> <translation>ugyldig</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>UlÃļste afhÃĶngigheder</translation> </message> <message> <source>Error</source> <translation>Fejl</translation> </message> <message> <source>Access error</source> <translation>Adgangsfejl</translation> </message> <message> <source>Format error</source> <translation>Format-fejl</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Kan ikke skrive installerens konfiguration til %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Stop processer</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Disse processer bÃļr stoppes inden der fortsÃĶttes: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Installation annulleret af bruger</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Skriver vedligeholdelsesvÃĶrktÃļj.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Kunne ikke sÃļge i filen %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>VedligeholdelsesvÃĶrktÃļjet er ikke et bundt</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Kan ikke fjerne data-filen "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Kan ikke skrive vedligeholdelsesvÃĶrktÃļjets data til %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Kan ikke skrive vedligeholdelsesvÃĶrktÃļjet til "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Kan ikke skrive vedligeholdelsesvÃĶrktÃļjets binÃĶre data til %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>Variablen 'TargetDir' ikke sat.</translation> </message> <message> <source>Preparing the installation...</source> <translation>KlargÃļr installationen...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Det er ikke muligt at installere fra netvÃĶrksplacering</translation> </message> <message> <source>Creating local repository</source> <translation>Opretter lokal repository</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Opretter vedligeholdelsesvÃĶrktÃļj</translation> </message> <message> <source> Installation finished!</source> <translation> Installation fÃĶrdig!</translation> </message> <message> <source> Installation aborted!</source> <translation> Installation afbrudt!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Det er ikke muligt at kÃļre handlingen fra en netvÃĶrksplacering</translation> </message> <message> <source>Removing deselected components...</source> <translation>Fjerner fravalgte komponenter...</translation> </message> <message> <source> Update finished!</source> <translation> Opdatering fÃĶrdig!</translation> </message> <message> <source> Update aborted!</source> <translation> Opdatering afbrudt!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>Afinstallation fuldfÃļrt med succes.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>Afinstallation afbrudt.</translation> </message> <message> <source> Installing component %1</source> <translation> Installerer komponenten %1</translation> </message> <message> <source>Installer Error</source> <translation>Installer-fejl</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Fejl under installationsprocessen (%1): %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Kan ikke klargÃļre afinstallation</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Kan ikke starte afinstallation</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Fejl under afinstallationsprocessen: %1</translation> </message> <message> <source>Unknown error</source> <translation>Ukendt fejl</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Kan ikke hente fjern-trÃĶet %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Kunne ikke lÃĶse pakker fra %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Kan ikke hente metainformation: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Kan ikke tilfÃļje kildeinformation for midlertidig opdatering.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Kan ikke finde nogen kildeinformation for opdatering.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>AfhÃĶngighedscyklus registreret mellem komponenterne "%1" og "%2".</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>%1 opsÃĶtning</translation> </message> <message> <source>Maintain %1</source> <translation>Vedligehold %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Vil du annullere installationsprocessen?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Vil du annullere afinstallationsprocessen?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Vil du afslutte installationsprogrammet?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Vil du afslutte afinstallationsprogrammet?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Vil du afslutte vedligeholdelsesprogrammet?</translation> </message> <message> <source>%1 Question</source> <translation>%1 spÃļrgsmÃĨl</translation> </message> <message> <source>Settings</source> <translation>Indstillinger</translation> </message> <message> <source>Error</source> <translation>Fejl</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Det er ikke muligt at installere fra netvÃĶrksplacering. KopiÃĐr venligst installeren til et lokalt drev</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&Vis detaljer</translation> </message> <message> <source>&Hide Details</source> <translation>&Skjul detaljer</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Afinstaller</translation> </message> <message> <source>Uninstalling %1</source> <translation>Afinstallerer %1</translation> </message> <message> <source>&Update</source> <translation>&Opdater</translation> </message> <message> <source>Updating components of %1</source> <translation>Opdaterer komponenter af %1</translation> </message> <message> <source>&Install</source> <translation>&Installer</translation> </message> <message> <source>Installing %1</source> <translation>Installerer %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Dialog</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>Proxyen %1 krÃĶver brugernavn og adgangskode.</translation> </message> <message> <source>Username:</source> <translation>Brugernavn:</translation> </message> <message> <source>Username</source> <translation>Brugernavn</translation> </message> <message> <source>Password:</source> <translation>Adgangskode:</translation> </message> <message> <source>Password</source> <translation>Adgangskode</translation> </message> <message> <source>Proxy Credentials</source> <translation>Proxy-loginoplysninger</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Afinstaller</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Klar til afinstallation</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>OpsÃĶtningen er nu klar til at begynde fjernelsen af %1 fra din computer.<br><font color="red">Programmappen %2 slettes fuldstÃĶndigt</font>, inklusiv alt indhold i mappen!</translation> </message> <message> <source>U&pdate</source> <translation>&Opdater</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Klar til opdateringspakker</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>OpsÃĶtningen er nu klar til at begynde opdateringen af din installation.</translation> </message> <message> <source>&Install</source> <translation>&Installer</translation> </message> <message> <source>Ready to Install</source> <translation>Klar til installation</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>OpsÃĶtningen er nu klar til at begynde installationen af %1 pÃĨ din computer.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>Ikke nok displads til at lagre midlertidige filer og installationen. %1 er tilgÃĶngelige, mens mindst %2 krÃĶves.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>Ikke nok displads til at lagre alle valgte komponenter! %1 er tilgÃĶngelige, mens mindst %2 krÃĶves.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>Ikke nok displads til at lagre midlertidige filer! %1 er tilgÃĶngelige, mens mindst %2 krÃĶves.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Det bind du har valg til installation ser ud til at have tilstrÃĶkkelig plads til installationen, men der vil efterfÃļlgende vÃĶre mindre end 1% af bindets plads tilgÃĶngeligt. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Det bind du har valg til installation ser ud til at have tilstrÃĶkkelig plads til installationen, men der vil efterfÃļlgende vÃĶre mindre end 100 MB tilgÃĶngeligt. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>Installationen vil bruge %1 diskplads.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><udvidelse> <kommando> [beskrivelse [indholdsType [ikon]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>Tilknytning af filtyper understÃļttes kun i Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Tilknytning af filtype: ugyldige argumenter</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Kan ikke lÃĶse alle data efter afsendelse af kommando: %1. Byte ventet: %2, byte modtaget: %3. Fejl: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til lÃĶsning: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Kan ikke ÃĨbne filen "%1" til skrivning: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Kan ikke ÃĨbne ressourcen %1 til lÃĶsning.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>LÃĶsning mislykkedes efter %1 byte: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Skrivning mislykkedes efter %1 byte: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>FuldfÃļrer opsÃĶtningsassistenten for %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Kan ikke ÃĨbne script-filen ved %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Undtagelse under indlÃĶsning af komponent-scriptet "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Ukendt fejl.</translation> </message> <message> <source>on line number: </source> <translation>pÃĨ linje nummer: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>NÃļdvendigt installer-objekt i %1-handling er tomt.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Selv-genstart: kun gyldigt i opdaterings- eller pakkehÃĨndteringstilstand.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Selv-genstart: ugyldige argumenter</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Serveren krÃĶver autentifikation</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Du skal angive brugernavn og adgangskode for at tilgÃĨ stedet.</translation> </message> <message> <source>Username:</source> <translation>Brugernavn:</translation> </message> <message> <source>Password:</source> <translation>Adgangskode:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 hos %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Manglende argument(er) "%1" kalder %2 med argumenterne "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>NuvÃĶrende metode-argument som kalder "%1" med argumenterne "%2" understÃļttes ikke. Brug venligst set, remove, add_array_value eller remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Ingen af argumenterne mÃĨ vÃĶre tomme: kilde "%1", mÃĨl "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Kan ikke flytte filen fra "%1" to "%2", da mÃĨl-stien findes og ikke er flytbar.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Kan ikke flytte filen "%1" til "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>Flytter filen "%1" til "%2".</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Genveje i menuen Start</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>VÃĶlg hvor i menuen Start du Ãļnsker programmernes genveje oprettet. Du kan ogsÃĨ indtaste et navn for at oprette en ny mappe.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Installationsmappe</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Angiv venligst mappen hvor %1 skal installeres.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+G</translation> </message> <message> <source>B&rowse...</source> <translation>&Gennemse...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Mappen du har valgt findes allerede og indeholder en installation. VÃĶlg et andet mÃĨl til installationen.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Du har valgt en eksisterende mappe til installation som ikke er tom. BemÃĶrk at den vil blive fuldstÃĶndigt ryddet ved afinstallation af programmet. Det anbefales ikke at installere i mappen eftersom installationen kan mislykkes. Vil du fortsÃĶtte?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Du har valgt en eksisterende fil eller symlink, vÃĶlg venligst et andet mÃĨl for installationen.</translation> </message> <message> <source>Select Installation Folder</source> <translation>VÃĶlg installationsmappe</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>Installationsstien mÃĨ ikke vÃĶre tom, angiv venligst en gyldig mappe.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>Installationsstien mÃĨ ikke vÃĶre relativ, angiv venligst en absolut sti.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>Stien eller installationsmappen indeholder ikke-ASCII-tegn. Det understÃļttes ikke i Ãļjeblikket! VÃĶlg venligst en anden sti eller installationsmappe.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Da installationsmappen er fuldstÃĶndigt slettet, er installation i %1 forbudt.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>Stien du har indtastet er for lang, sÃļrg venligst for at angive en gyldig sti.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>Stien du har indtastet er ikke gyldig, sÃļrg venligst for at angive et gyldigt mÃĨl.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>Stien du har indtastet er ikke gyldig, sÃļrg venligst for at angive et gyldigt drev.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>Installationsstien mÃĨ ikke slutte med '.', angiv venligst en gyldig mappe.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>Installationsstien mÃĨ ikke indholde "%1", angiv venligst en gyldig mappe.</translation> </message> <message> <source>Warning</source> <translation>Advarsel</translation> </message> <message> <source>Error</source> <translation>Fejl</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Manglende pakkehÃĨndterings-kernemotor.</translation> </message> <message> <source>Empty repository URL.</source> <translation>Tom repository-URL.</translation> </message> <message> <source>Download canceled.</source> <translation>Download annulleret.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Timeout ved test af repository'et "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Kan ikke parse Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Kan ikke ÃĨbne Updates.xml til lÃĶsning: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Autentifikation mislykkedes.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Ukendt fejl ved test af repository'et "%1".</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Godkendelse krÃĶves</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Indtast din adgangskode til godkendelse for sudo:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Fejl ved anskaffelse af administrator rettigheder</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Kan ikke fÃĨ godkendelse.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Kan ikke fÃĨ godkendelse som er nÃļdvendigt for at fortsÃĶtte installationen. Start venligst opsÃĶtningsprogrammet som en bruger med de fornÃļdne rettigheder. Eller acceptÃĐr ophÃļjelsen af adgangsrettigheder hvis du bliver spurgt.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Kan ikke fÃĨ godkendelse som er nÃļdvendigt for at fortsÃĶtte installationen. Abryd enten installationen eller brug tilbagefaldslÃļsningen ved at kÃļre %1 som en bruger med de fornÃļdne rettigheder og klik sÃĨ pÃĨ OK.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Kan ikke ÃĨbne ressourcen %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Kan ikke ÃĨbne indstillingsfilen %1 til lÃĶsning: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Indstillinger</translation> </message> <message> <source>Network</source> <translation>NetvÃĶrk</translation> </message> <message> <source>No proxy</source> <translation>Ingen proxy</translation> </message> <message> <source>System proxy settings</source> <translation>Systemets proxy-indstillinger</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Manuel proxy-konfiguration</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP-proxy:</translation> </message> <message> <source>Port:</source> <translation>Port:</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP-proxy:</translation> </message> <message> <source>Repositories</source> <translation>Repositories</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>TilfÃļj brugernavn og adgangskode til autentifikation hvis det er nÃļdvendigt.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Brug kun midlertidige repositories</translation> </message> <message> <source>Add</source> <translation>TilfÃļj</translation> </message> <message> <source>Remove</source> <translation>Fjern</translation> </message> <message> <source>Test</source> <translation>Test</translation> </message> <message> <source>Show Passwords</source> <translation>Vis adgangskoder</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>TilvÃĶlg denne for at bruge repository under hentning.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>TilfÃļj brugernavnet til at autentificere pÃĨ serveren.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>TilfÃļj adgangskoden til at autentificere pÃĨ serveren.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>Serverens URL som indeholder et gyldigt repository.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Der opstod en fejl under test af repository'et.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Repository'et blev testet med succes.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Vil du deaktivere repository'et?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Vil du aktivere repository'et?</translation> </message> <message> <source>Hide Passwords</source> <translation>Skjul adgangskoder</translation> </message> <message> <source>Use</source> <translation>Brug</translation> </message> <message> <source>Username</source> <translation>Brugernavn</translation> </message> <message> <source>Password</source> <translation>Adgangskode</translation> </message> <message> <source>Repository</source> <translation>Repository</translation> </message> <message> <source>Default repositories</source> <translation>Standard repositories</translation> </message> <message> <source>Temporary repositories</source> <translation>Midlertidige repositories</translation> </message> <message> <source>User defined repositories</source> <translation>Brugerdefinerede repositories</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Registry path %1 is not writable.</source> <translation>Registreringsdatabasestien %1 er ikke skrivbar.</translation> </message> <message> <source>Cannot write to registry path %1.</source> <translation>Kan ikke skrive til registreringsdatabasestien %1.</translation> </message> <message> <source>exactly %1</source> <translation>prÃĶcist %1</translation> </message> <message> <source>at least %1</source> <translation>mindst %1</translation> </message> <message> <source>not more than %1</source> <translation>ikke flere end %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 eller %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 til %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Ugyldigt argument i %1: %n argument givet, %2 argument ventet.</numerusform> <numerusform>Ugyldige argumenter i %1: %n argumenter givet, %2 argumenter ventet.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Ugyldigt argument i %1: %n argument givet, %2 argument ventet i udformningen: %3.</numerusform> <numerusform>Ugyldige argumenter i %1: %n argumenter givet, %2 argumenter ventet i udformningen: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>OmdÃļbning af filen "%1" til "%2" mislykkedes: %3</translation> </message> </context> </TS> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_de.ts�����������������������������������������0100777�0000000�0000000�00000307363�13761647206�021012� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="de_DE"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 auf %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>Proxy verlangt Autentifizierung.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Konnte nicht bis zur Anweisungsliste an Position %1 springen.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Konnte nicht bis zur Resourcensammlung an Position %1 suchen.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Konnte Metainformationen nicht Ãķffnen: %1</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Konnte nicht bis %1 suchen, um die eingebettete Metadatenanzahl zu lesen.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Konnte nicht bis %1 suchen, um die Resourcensammlung zu lesen.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Unerwarteter Unterschied zwischen Metadaten. %1 gelesen, %2 erwartet.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>HTTP-Authentifizierung erforderlich</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Benutzername und Passwort fÞr die Authentifizierung benÃķtigt.</translation> </message> <message> <source>Username:</source> <translation>Nutzername:</translation> </message> <message> <source>Password:</source> <translation>Passwort:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 auf %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>Pfad "%1" existiert, aber ist kein Verzeichnis.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Konnte Verzeichnis "%1" nicht anlegen.</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Konnte Pfad des Archivs %1 nicht feststellen.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Konnte existierende VerknÞpfung (Symlink) %1 nicht entfernen.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei "%1" nicht Ãķffnen: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Konnte VerknÞpfung (Symlink) '%1' nicht erstellen. Es existiert bereits eine an dieser Stelle.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Konnte Ziel der VerknÞpfung (Symlink) '%1' nicht lesen.</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Konnte VerknÞpfung (Symlink) %1 nicht anlegen: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation type="unfinished"></translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation type="unfinished"></translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Komponenten, die als automatische AbhÃĪngigkeiten hinzugefÞgt wurden:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Komponenten, die als AbhÃĪngigkeiten fÞr '%1' hinzugefÞgt wurden:</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Komponenten, die aufgelÃķste AbhÃĪngigkeiten besitzen:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>AusgewÃĪhlte Komponenten ohne AbhÃĪngigkeiten:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Rekursion entdeckt, Komponente '%1' wurde bereits aufgrund von '%2' hinzugefÞgt</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>Konnte fehlende AbhÃĪngigkeit '%1' fÞr '%2' nicht finden.</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Abgebrochen</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Konnte Datei "%1" nicht sichern: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei "%1" nicht zum Schreiben Ãķffnen: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Konnte Sicherungsdatei fÞr "%1" nicht finden.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Konnte Datei "%1" nicht wiederherstellen.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Konnte Datei "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Konnte Datei "%1" nicht sichern.</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Konnte nicht existierende Datei nicht kopieren: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Konnte Zieldatei "%1" nicht entfernen: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Konnte Datei "%1" nicht nach "%2" kopieren: %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Konnte Datei "%1" nicht lÃķschen: %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Konnte Datei "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Konnte Datei "%1" nicht sichern: %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Konnte Datei "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download canceled.</source> <translation>Herunterladen abgebrochen.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>PrÞfsummen stimmen nicht Þberein.</translation> </message> <message> <source>Download finished.</source> <translation>Heruntergeladen abgeschlossen.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 von %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 heruntergeladen.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n Tag, </numerusform> <numerusform>%n Tage, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n Stunde, </numerusform> <numerusform>%n Stunden, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n Minute</numerusform> <numerusform>%n Minuten</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n Sekunde</numerusform> <numerusform>%n Sekunden</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 verbleibend.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - verbleibende Zeit unbekannt.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Konnte %1 nicht herunterladen. Schreiben in Datei '%2' fehlgeschlagen: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Konnte %1 nicht herunterladen. Erstellen der Datei "%2" fehlgeschlagen: %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 auf %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Authentifizierung abgebrochen.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Sichere Verbindung fehlgeschlagen</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Beim Aufbau der Verbindung zu '%1' ist ein Fehler aufgetreten.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Dies kann ein Fehler in der Konfiguration sein oder es versucht jemand, diesen Server vorzutÃĪuschen.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Wenn frÞhere Verbindungen zu diesem Server erfolgreich waren, kann dieser Fehler temporÃĪr sein und bei einem erneuten Versuch verschwinden.</translation> </message> <message> <source>Try again</source> <translation>Erneut versuchen</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei '%1' nicht zum Lesen Ãķffnen.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Zieldatei '%1' nicht zum Schreiben Ãķffnen.</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Konnte Datei "%1" nicht zum Schreiben Ãķffnen: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht anlegen: %2</translation> </message> <message> <source>Unknown error.</source> <translation>Unbekannter Fehler.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht lÃķschen: %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Konnte Datei "%1" nicht sichern.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Konnte Datei "%1" nicht entfernen: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Konnte Datei "%1" nicht nach "%1" kopieren: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Konnte Datei "%1" nicht lÃķschen.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Konnte Datei "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Konnte Datei "%1" nicht sichern: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei "%1" nicht zum Lesen Ãķffnen: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei "%1" nicht zum Schreiben Ãķffnen: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Konnte Sicherungsdatei fÞr "%1" nicht finden.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Konnte Datei "%1" nicht wiederherstellen.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Konnte Datei "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Konnte Ressourcendatei "%1" nicht zum Lesen Ãķffnen: %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht lÃķschen: %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>Der Verzeichnis existiert nicht.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht wiederherstellen: %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 gestartet</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 kann nicht angehalten werden</translation> </message> <message> <source>Cannot stop task %1</source> <translation>%1 kann nicht angehalten werden</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 kann nicht pausiert werden</translation> </message> <message> <source>Cannot pause task %1</source> <translation>%1 kann nicht pausiert werden</translation> </message> <message> <source>Cannot resume task %1</source> <translation>%1 kann nicht wiederaufgenommen werden</translation> </message> <message> <source>%1 done</source> <translation>%1 abgeschlossen</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Konnte nicht auf die Paketinformationen dieser Anwendung zugreifen.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Keine Paketquellen fÞr diese Anwendung festgelegt.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n Aktualisierung gefunden.</numerusform> <numerusform>%n Aktualisierungen gefunden.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Datei Updates.xml wird von der Aktualisierungsquelle heruntergeladen.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Konnte Aktualisierungen nicht von %1 ('%2') herunterladen.</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Datei Updates.xml von der Aktualisierungsquelle heruntergeladen.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Anwendbare Aktualisierungen werden ermittelt.</translation> </message> <message> <source>Application updates computed.</source> <translation>Anwendbare Aktualisierungen ermittelt.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml enthÃĪlt ungÞltige Inhalte: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Konnte Datei "%1" nicht lesen.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>UngÞltiges XML in Datei %1, Zeile %2, Spalte %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Unerwartetes Wurzelelement %1, erwartet wird "UpdateSources".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Element ApplicationName fehlt.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Element ApplicationVersion fehlt.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Element PackageUpdate braucht ein Feld Name.</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Element PackageUpdate braucht ein Feld Version.</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Element PackageUpdate braucht ein Feld ReleaseDate.</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>Interner Fehlercode: %1</translation> </message> <message> <source>not enough memory</source> <translation>nicht genug Speicher</translation> </message> <message> <source>Error: %1</source> <translation>Fehler: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Konnte Eigenschaft %1 von %2 nicht erhalten.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>Eigenschaft %1 von %2 ist nicht vom Typ VT_FILETIME, sondern vom Typ %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Kann nicht UTC Datei Zeit zur Systemzeit konvertieren.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Konnte Codecs nicht laden.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Konnte Archiv nicht Ãķffnen.</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Konnte Anzahl Dateien im Archiv nicht feststellen.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Konnte Pfad des Archivs "%1" nicht feststellen.</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Unbekannte Ausnahmebedingung (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Konnte temporÃĪre Datei nicht anlegen: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation type="unfinished"></translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Konnte kein Archiv "%1" anlegen.</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Konnte kein Archiv "%1" anlegen: %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation type="unfinished"></translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation type="unfinished"></translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Unbekannte Ausnahmebedingung (%1).</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>Inhalt von Datei %1 ungÞltig: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Datei %1 existiert nicht.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Konnte Datei %1 nicht Ãķffnen.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>UngÞltiges XML in Datei %1, Zeile %2, Spalte %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Unerwartetes Wurzelelement %1, erwartet wird 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Konnte keine Sperrdatei "%1" anlegen: %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Konnte PID nicht in die Sperrdatei "%1" schreiben: %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Konnte Sperre fÞr Datei '%1' nicht anlegen: '%2'</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Konnte Sperre fÞr Datei '%1' nicht aufheben: '%2'</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Keine Markierung gefunden, abgebrochen nach %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei "%1" nicht zum Lesen Ãķffnen: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei "%1" nicht zum Schreiben Ãķffnen: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Das Lesen ist nach %1 Bytes fehlgeschlagen: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Kopieren ist fehlgeschlagen: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Das Schreiben ist nach %1 Bytes fehlgeschlagen: %2</translation> </message> <message> <source>bytes</source> <translation>Bytes</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Konnte Datei "%1" nicht lÃķschen: %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht lÃķschen: %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Konnte Verzeichnis "%1" nicht anlegen.</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Konnte Datei "%1" nicht nach "%1" kopieren: %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Konnte Datei "%1" nicht nach "%1" verschieben: %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht anlegen: %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Konnte temporÃĪre Datei nicht Ãķffnen: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Konnte keine temporÃĪre Datei fÞr die Vorlage %1 Ãķffnen: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>Installation beschÃĪdigt</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>Ihre Installation scheint beschÃĪdigt zu sein. Komplette Neuinstallation empfohlen.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Das angegebene Modul konnte nicht gefunden werden.</translation> </message> <message> <source>Error: --include and --exclude are mutually exclusive. Use either one or the other.</source> <translation>Fehler: --include und --exclude schließen sich gegenseitig aus. Benutze entweder das eine oder das andere.</translation> </message> <message> <source>Error: Package to exclude missing</source> <translation type="unfinished"></translation> </message> <message> <source>Error: Package to include missing</source> <translation type="unfinished"></translation> </message> <message> <source>Error: Packages parameter missing argument</source> <translation type="unfinished"></translation> </message> <message> <source>Error: Package directory not found at the specified location</source> <translation type="unfinished"></translation> </message> <message> <source>Argument -r|--remove and --update|--update-new-components are mutually exclusive!</source> <translation type="unfinished"></translation> </message> <message> <source>Repository target directory "%1" already exists.</source> <translation type="unfinished"></translation> </message> <message> <source>Invalid content in "%1".</source> <translation type="unfinished"></translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Komponenten kÃķnnen im Updater-Modus keine Kinder haben.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Konnte angeforderte UI-Datei '%1' nicht Ãķffnen: %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Konnte angeforderte UI-Datei '%1' nicht laden: %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Konnte angeforderte Lizenzdatei '%1' nicht Ãķffnen: %2</translation> </message> <message> <source>Error</source> <translation>Fehler</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Fehler: Anweisung %1 existiert nicht.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Kann isDefault in %1 nicht auflÃķsen.</translation> </message> <message> <source>Update Info: </source> <translation>Aktualisierungsinformation: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Komponente wird installiert.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Komponente wird deinstalliert.</translation> </message> <message> <source>Component is installed.</source> <translation>Komponente ist installiert.</translation> </message> <message> <source>Component is not installed.</source> <translation>Komponente ist nicht installiert.</translation> </message> <message> <source>Component Name</source> <translation>Komponentenname</translation> </message> <message> <source>Action</source> <translation>Aktion</translation> </message> <message> <source>Installed Version</source> <translation>Installierte Version</translation> </message> <message> <source>New Version</source> <translation>Neue Version</translation> </message> <message> <source>Release Date</source> <translation>VerÃķffentlichungsdatum</translation> </message> <message> <source>Size</source> <translation>GrÃķße</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>St&andard</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+Z</translation> </message> <message> <source>&Reset</source> <translation>&ZurÞcksetzen</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>Alle au&swÃĪhlen</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+B</translation> </message> <message> <source>&Deselect All</source> <translation>Alle a&bwÃĪhlen</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Um das neu komprimierte Repository zu installieren, suche ein Repository von deinem Computer aus.</translation> </message> <message> <source>&Browse QBSP files</source> <translation>Durchsuche QBSP Dateien</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Diese Komponente wird ungefÃĪhr %1 auf Ihrer Festplatte belegen.</translation> </message> <message> <source>Select Components</source> <translation>Komponenten auswÃĪhlen</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Bitte wÃĪhlen Sie die Komponenten aus, die Sie aktualisieren mÃķchten.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Bitte wÃĪhlen Sie die Komponenten aus, die Sie installieren mÃķchten.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Bitte wÃĪhlen Sie die Komponenten aus, die Sie entfernen mÃķchten.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Bitte wÃĪhlen Sie die Komponenten aus, die Sie installieren mÃķchten. WÃĪhlen Sie die Komponenten ab, die Sie entfernen mÃķchten.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation type="unfinished"></translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Das fÞr die Anweisung %1 benÃķtigte Installerobjekt ist leer.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Konnte die Ausgabe von "%1" nicht in einen leeren SchlÞsselwert des Installers speichern.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Datei '%1' existiert nicht oder ist keine ausfÞhrbare BinÃĪrdatei.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>AusfÞhren von '%1' fÞhrte zu einem Absturz.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation> (<Quelle> <Ziel> [forceOverwrite])</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>UngÞltiges Argument in %1: Drittes Argument muss forceOverwrite sein, wenn es angegeben wird</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation type="unfinished"></translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Konnte Verzeichnis "%1" nicht anlegen.</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Konnte Datei "%1" nicht Þberschreiben</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Konnte "%1" nicht nach "%1" kopieren: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Konnte Datei "%1" nicht lÃķschen.</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>UngÞltige Anzahl task items.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Quelle '%1' nicht zum Lesen Ãķffnen: %2.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Ziel '%1' nicht zum Schreiben Ãķffnen: %2.</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Konnte Datei '%1' nicht zum Schreiben Ãķffnen: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Konnte Datei "%1" nicht sichern: %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Konnte Datei "%1" nicht Þberschreiben.</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Konnte keinen Eintrag "%1" auf dem Arbeitsplatz anlegen.</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Konnte keinen Link von "%1" nach "%1" erstellen.</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Konnte Link von "%1" nach "%1" nicht entfernen.</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Konnte Dateiberechtigungen auf Datei "%1" nicht setzen.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Konnte Datei "%1" nicht lÃķschen: %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Konnte Datei "%1" nicht nach "%1" verschieben: %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Installer muss eine Offline-Version sein: %1.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Konnte Datei "%1" nicht Ãķffnen.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Konnte Datei "%1" nicht lesen: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei "%1" nicht Ãķffnen: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Konnte Zielordner %1. nicht anlegen.</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Unbekannte Ausnahmebedingung: %1</translation> </message> <message> <source>Removing file "%1".</source> <translation>Datei %0 wird entfernt</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Konnte Datei %0 nicht lÃķschen.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht lÃķschen: %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source> (optional: 'workingDirectory=...', 'iconPath=...', 'iconId=...')</source> <translation> (optional: 'workingDirectory=...', 'iconPath=...', 'iconId=...')</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht anlegen: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Konnte Datei "%1" nicht Þberschreiben: %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Konnte Verweis "%1" nicht anlegen: %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Abgebrochen</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Herunterladen der PrÞfsumme fehlgeschlagen.</translation> </message> <message> <source>Download Error</source> <translation>Fehler beim Herunterladen</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>PrÞfsumme ungÞltig beim Herunterladen. Dies ist ein kurzzeitiger Fehler, bitte erneut versuchen.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>PrÞfsumme konnte nicht geprÞft werden.</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Konnte Archiv %1 nicht herunterladen: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Konnte Archiv nicht laden. Fehler: %1 Fehler beim Laden von %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Archiv '%1' fÞr Komponente %2 wird heruntergeladen.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Schema "%1" nicht unterstÞtzt in "%2".</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Konnte keine Komponente fÞr Datei %1 finden.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>Zieldatei '%1' existiert bereits aber ist keine Datei.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Konnte Datei %1 nicht zum Schreiben Ãķffnen: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Datei konnte nicht zum Schreiben geÃķffnet werden.</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Schreiben in Datei '%1' fehlgeschlagen: %2.</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Schleife in Umleitung erkannt '%1'.</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Checksummen stimmen nicht Þberein '%1'.</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Netzwerkfehler beim Herunterladen von '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Unbekannter Netzwerkfehler beim Herunterladen: '%1'.</translation> </message> <message> <source>Network transfers canceled.</source> <translation>NetwerkÞbertragung abgebrochen.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>Pausieren und Fortsetzen werden bei NetzwerkÞbertragungen nicht unterstÞtzt.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>UngÞltige Quelle '%1'. Fehler: %2.</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Konnte "%1" nicht losgelÃķst starten.</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Konnte '%1' nicht starten: %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>AusfÞhrung fehlgeschlagen (Absturz): "%1"</translation> </message> <message> <source>Execution failed(Unexpected exit code: %1): "%2"</source> <translation>AusfÞhrung fehlgeschlagen (Unerwarteter Fehlercode %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Konnte Datei "%1" nicht zum Lesen Ãķffnen: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Fehler beim Auspacken von '%1': %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Beim Auspacken von "%1" ist eine unbekannte Ausnahmebedingung aufgetreten.</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Konnte PackageManagerCore nicht erhalten.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Dieser Prozess sollte beendet werden, um fortsetzen zu kÃķnnen: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Diese Prozesse sollten beendet werden, um fortsetzen zu kÃķnnen: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 von %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 empfangen.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n Tag, </numerusform> <numerusform>%n Tage, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n Stunde, </numerusform> <numerusform>%n Stunden, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n Minute</numerusform> <numerusform>%n Minuten</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n Sekunde</numerusform> <numerusform>%n Sekunden</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 verbleibend.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - verbleibende Zeit unbekannt.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>Den %1-Assistent abschließen.</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Klicken Sie %1, um den %2 Assistenten zu beenden.</translation> </message> <message> <source>Restart</source> <translation>Neu starten</translation> </message> <message> <source>Run %1 now.</source> <translation>Starte jetzt %1.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>Der %1-Assistent ist fehlgeschlagen.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Einstellungen konnten nicht geschrieben werden.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Einstellungen konnten nicht geschrieben werden.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation> (Quellpfad, [Vendorprefix])</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>UngÞltiges Argument: Quellordner darf nicht leer sein.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Konnte Datei "%1" nicht sichern: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Konnte Datei "%1" nicht Þberschreiben: %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Konnte Datei nicht nach "%1" kopieren: %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Konnte Verzeichnis "%1" nicht anlegen: %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Einrichten - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Willkommen zum %1-Einrichtungsassistenten.</translation> </message> <message> <source>&Add or remove components</source> <translation>Komponenten hinzufÞgen oder entfernen</translation> </message> <message> <source>&Update components</source> <translation>Komponenten aktualisieren</translation> </message> <message> <source>&Remove all components</source> <translation>Alle Komponenten entfernen</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Daten werden vom Installationsserver empfangen ...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Mindestens ein gÞltiges und aktiviertes Repository wird benÃķtigt, um diese Aktion erfolgreich abzuschließen.</translation> </message> <message> <source>No updates available.</source> <translation>Keine Aktualisierungen verfÞgbar.</translation> </message> <message> <source> Only local package management available.</source> <translation> Nur lokale Paketverwaltung verfÞgbar.</translation> </message> <message> <source>&Quit</source> <translation>Beenden</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Lizenzabkommen</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translatorcomment>Lizenz akzeptieren</translatorcomment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translatorcomment>Der Lizenz nicht zustimmen</translatorcomment> <translation>Alt+N</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Bitte lesen Sie das folgende Lizenzabkommen. Sie mÞssen die Bedingungen in diesem Abkommen akzeptieren, um die Installation fortsetzen zu kÃķnnen.</translation> </message> <message> <source>I accept the license.</source> <translation>Ich akzeptiere die Lizenzvereinbarung.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Ich akzeptiere die Lizenzvereinbarung nicht.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Bitte lesen Sie die folgenden Lizenzabkommen. Sie mÞssen die Bedingungen in diesen Abkommen akzeptieren, um die Installation fortsetzen zu kÃķnnen.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Ich akzeptiere die Lizenzvereinbarungen.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Ich akzeptiere die Lizenzvereinbarungen nicht.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Keine Lizenzdateien zum Kopieren gefunden.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Das fÞr die Anweisung %1 benÃķtigte Installer-Objekt ist leer.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Konnte Lizenzdatei "%1" nicht schreiben.</translation> </message> <message> <source>No license files found to delete.</source> <translation>Keine Lizenzdateien zum LÃķschen gefunden.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei '%1' nicht zum Lesen Ãķffnen.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei '%1' nicht zum Schreiben Ãķffnen.</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Fehlende Paketmanager-Kernkomponente.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Herunterladen der Metainformationen wird vorbereitet ...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Entpacken des komprimierten Repository, Das kÃķnnte eine Weile dauern...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Herunterladen der Metainformationen abgebrochen.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Beim Auspacken ist eine unbekannte Ausnahmebedingung aufgetreten.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Fehlende Proxy-Zugangsdaten.</translation> </message> <message> <source>Authentication failed.</source> <translation>Authentifizierung fehlgeschlagen.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Beim Herunterladen ist eine unbekannte Ausnahmebedingung aufgetreten.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Herunterladen von Paketquellen fehlgeschlagen.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Metainformationen werden ausgepackt ...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Metainformationen werden vom Installationsserver empfangen ... %1/%2</translation> </message> <message> <source>Retrieving meta information from remote repository...</source> <translation>Metainformationen werden vom Installationsserver empfangen ...</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Fehler beim auspacken des Archives "%1":</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Beim Auspacken von "%1" ist eine unbekannte Ausnahmebedingung aufgetreten.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Kann die Datei "%1" nicht zum Lesen Ãķffnen: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Fehler beim Schreiben des Verwaltungswerkzeugs</translation> </message> <message> <source> Downloading packages...</source> <translation> Pakete werden heruntergeladen ...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Installation durch den Benutzer abgebrochen</translation> </message> <message> <source>All downloads finished.</source> <translation>Alle Herunterladeprozesse abgeschlossen.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Der Installationsvorgang wird abgebrochen</translation> </message> <message> <source>Authentication Error</source> <translation>Autentifizierungsfehler</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Einige Komponenten konnten nicht vollstÃĪndig entfernt werden, weil die nÃķtigen Administratorrechte nicht erlangt werden konnten: %1</translation> </message> <message> <source>Unknown error.</source> <translation>Unbekannter Fehler.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Einige Komponenten konnten nicht vollstÃĪndig entfernt werden, weil ein unbekannter Fehler aufgetreten ist.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>Die Anwendung lÃĪuft nicht im Paketverwaltungsmodus.</translation> </message> <message> <source>No installed packages found.</source> <translation>Keine installierten Pakete gefunden.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>Die Anwendung lÃĪuft im Deinstallationsmodus.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Es gibt eine wichtige Aktualisierung, bitte zuerst den Updater starten.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Konnte nicht alle AbhÃĪngigkeiten auflÃķsen.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Komponenten, die entfernt werden.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Fehler beim Erlangen von Administratorrechten.</translation> </message> <message> <source>Error</source> <translation>Fehler</translation> </message> <message> <source>invalid</source> <translation>ungÞltig</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>UngelÃķste AbhÃĪngigkeiten</translation> </message> <message> <source>Error</source> <translation>Fehler</translation> </message> <message> <source>Access error</source> <translation>Zugriffsfehler</translation> </message> <message> <source>Format error</source> <translation>Formatfehler</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Konnte Einstellungen des Installers nicht nach %1 schreiben: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Prozesse anhalten</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Diese Prozesse sollten beendet werden, um fortsetzen zu kÃķnnen: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Installation durch den Benutzer abgebrochen</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Schreiben des Verwaltungswerkzeugs.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Suchen in Datei %1 fehlgeschlagen: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Verwaltungswerkzeug ist kein Bundle</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Konnte Datei "%1" nicht lÃķschen: %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Konnte Daten des Verwaltungswerkzeugs nicht nach %1 schreiben: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Konnte Verwaltungswerkzeug nicht nach "%1" schreiben: %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Konnte BinÃĪrdaten des Verwaltungswerkzeugs nicht nach %1 schreiben: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>TargetDir muss gesetzt sein.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Installation wird vorbereitet ...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Es ist nicht mÃķglich, von einem Netzwerk-Speicherort aus zu installieren</translation> </message> <message> <source>Creating local repository</source> <translation>Lokale Quelle wird erstellt</translation> </message> <message> <source>Creating Maintenance Tool</source> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation></translation> </message> <message> <source> Installation finished!</source> <translation> Installation abgeschlossen!</translation> </message> <message> <source> Installation aborted!</source> <translation> Installation abgebrochen!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Es ist nicht mÃķglich, diese Oparation von einem Netzwerk-Speicherort aus zu starten</translation> </message> <message> <source>Removing deselected components...</source> <translation>AbgewÃĪhlte Komponenten werden entfernt ...</translation> </message> <message> <source> Update finished!</source> <translation> Aktualisierung beendet!</translation> </message> <message> <source> Update aborted!</source> <translation> Aktualisierung abgebrochen!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>Deinstallation erfolgreich abgeschlossen.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>Deinstallation abgebrochen.</translation> </message> <message> <source> Installing component %1</source> <translation> Komponente %1 wird installiert</translation> </message> <message> <source>Installer Error</source> <translation>Installationsfehler</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Fehler beim Installieren von Komponente %1: %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Kann Deinstallation nicht vorbereiten</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Kann Deinstallation nicht starten</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Fehler bei der Deinstallation: %1</translation> </message> <message> <source>Unknown error</source> <translation>Unbekannter Fehler</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Kann entfernten Baum nicht empfangen %1</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Fehler beim Lesen der Pakete von %1</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Konnte die Metainformationen nicht empfangen: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Konnte Informationen nicht zu temporÃĪren Aktualisierungsquellen hinzufÞgen.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Konnte keine Informationen zu Aktualisierungsquellen finden.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Zyklische AbhÃĪngigkeit zwischen Komponenten entdeckt: '%1' und '%2'.</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>%1 Einrichtung</translation> </message> <message> <source>Maintain %1</source> <translation>%1 verwalten</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>MÃķchten Sie den Installationsprozess abbrechen?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>MÃķchten Sie den Deinstallationsprozess abbrechen?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>MÃķchten Sie die Installationsanwendung beenden?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>MÃķchten Sie die Deinstallationsanwendung beenden?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>MÃķchten Sie das Verwaltungswerkzeug beenden?</translation> </message> <message> <source>%1 Question</source> <translation>%1 Frage</translation> </message> <message> <source>Settings</source> <translation>Einstellungen</translation> </message> <message> <source>Error</source> <translation>Fehler</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Es ist nicht mÃķglich, von einem Netzwerk-Speicherort aus zu installieren. Bitte kopieren Sie den Installer auf ein lokales Laufwerk</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>Details &anzeigen</translation> </message> <message> <source>&Hide Details</source> <translation>Details aus&blenden</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Deinstallieren</translation> </message> <message> <source>Uninstalling %1</source> <translation>%1 wird deinstalliert</translation> </message> <message> <source>&Update</source> <translation>&Aktualisieren</translation> </message> <message> <source>Updating components of %1</source> <translation>Komponenten von %1 werden aktualisiert</translation> </message> <message> <source>&Install</source> <translation>&Installieren</translation> </message> <message> <source>Installing %1</source> <translation>%1 wird installiert</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Dialog</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>Der Proxy %1 verlangt einen Benutzernamen und Passwort.</translation> </message> <message> <source>Username:</source> <translation>Benutzername:</translation> </message> <message> <source>Username</source> <translation>Benutzername</translation> </message> <message> <source>Password:</source> <translation>Passwort:</translation> </message> <message> <source>Password</source> <translation>Passwort</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Deinstallieren</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Bereit zum Deinstallieren</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>Das Einrichtungsprogramm ist jetzt bereit, %1 von Ihrem Computer zu entfernen. <br><font color="red">Das Programmverzeichnis %2 wird vollstÃĪndig gelÃķscht</font>, inklusive allen Inhalten in diesem Verzeichnis!</translation> </message> <message> <source>U&pdate</source> <translation>&Aktualisieren</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Bereit zum Aktualisieren der Pakete</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>Das Einrichtungsprogramm ist jetzt bereit, Ihre Installation zu aktualisieren.</translation> </message> <message> <source>&Install</source> <translation>&Installieren</translation> </message> <message> <source>Ready to Install</source> <translation>Bereit zum Installieren</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>Das Einrichtungsprogramm ist jetzt bereit, %1 auf Ihrem Computer zu installieren.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>Nicht genÞgend Festplattenplatz fÞr temporÃĪre Dateien und die Installation! VerfÞgbarer Platz: %1, mindestens benÃķtigt: %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>Nicht genÞgend Festplattenplatz fÞr alle ausgewÃĪhlten Komponenten! VerfÞgbarer Platz: %1, mindestens benÃķtigt: %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>Nicht genÞgend Festplattenplatz fÞr temporÃĪre Dateien! VerfÞgbarer Platz: %1, mindestens benÃķtigt: %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Die fÞr die Installation ausgewÃĪhlte Partition scheint genÞgend Platz zu bieten, aber es werden anschließend weniger als 1% der PartitionsgrÃķße verfÞgbar sein. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Die fÞr die Installation ausgewÃĪhlte Partition scheint genÞgend Platz zu bieten, aber es werden anschließend weniger als 100 MB verfÞgbar sein. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>Die Installation wird %1 Festplattenplatz verwenden.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source>Registering file types is only supported on Windows.</source> <translation>Dateitypenregistrierung wird nur unter Windows unterstÞtzt.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Dateitypenregistrierung: UngÞltige Argumente</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Konnte nicht alle Daten nach dem Senden des Befehls '%1' lesen. Bytes erwartet: %2, Bytes erhalten: %3. Fehler: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Konnte Datei "%1" nicht zum Lesen Ãķffnen</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Konnte Datei "%1" nicht zum Schreiben Ãķffnen</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Konnte Ressourcendatei '%1' nicht schreibgeschÞtzt Ãķffnen.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Das Lesen ist nach %1 Bytes fehlgeschlagen: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Das Schreiben ist nach %1 Bytes fehlgeschlagen: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>Der %1-Assistent wird abgeschlossen</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Konnte angeforderte Skriptdatei '%1' nicht Ãķffnen: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Ausnahme beim Laden des Komponentenskripts '%1'. (%2)</translation> </message> <message> <source>Unknown error.</source> <translation>Unbekannter Fehler.</translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>Das fÞr die Anweisung '%1' benÃķtigte Installer-Objekt ist leer.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Automatischer Neustart: Nur im Aktualisierungs- und Pakatverwaltungs-Modus erlaubt.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Automatischer Neustart: UngÞltige Argumente</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Server verlangt Authentifizierung</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Benutzername und Passwort fÞr den Zugriff benÃķtigt.</translation> </message> <message> <source>Username:</source> <translation>Benutzername:</translation> </message> <message> <source>Password:</source> <translation>Passwort:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 auf %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Fehlende Argumente '%1' beim Aufruf von '%2' mit den Argumenten '%3'.</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>Aufruf von '%1' mit den Argumenten '%2' nicht unterstÞtzt. Bitte 'set', 'remove', 'add_array_value' oder 'remove_array_value' verwenden.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Keines der Argumente darf leer sein: Quelle '%1', Ziel '%2'.</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Konnte Quelle '%1' nicht nach Ziel '%2' verschieben, weil das Ziel bereits existiert und nicht entfernt werden kann.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Konnte Datei '%1' nicht nach '%2' verschieben: %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>'%1' nach '%2' verschieben.</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>VerknÞpfungen im StartmenÞ</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>WÃĪhlen Sie den Verzeichnis im StartmenÞ, in dem die VerknÞpfungen zur Anwendung erstellt werden sollen. Sie kÃķnnen einen Namen angeben, um einen neuen Verzeichnis anzulegen.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Installationsordner</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Bitte geben Sie den Verzeichnis an, in dem %1 installiert werden soll.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translatorcomment>Dateisystem durchsuchen, um eine Datei auszuwÃĪhlen</translatorcomment> <translation>Alt+D</translation> </message> <message> <source>B&rowse...</source> <translation>&Durchsuchen ...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Der ausgewÃĪhlte Verzeichnis existiert bereits und enthÃĪlt eine Installation. Bitte wÃĪhlen Sie einen anderen Zielordner aus.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Sie haben einen existierenden, nicht leeren Verzeichnis fÞr die Installation ausgewÃĪhlt. Dieser wird bei der Deinstallation dieser Anwendung komplett gelÃķscht werden. Es wird nicht empfohlen, in diesen Verzeichnis zu installieren. MÃķchten Sie trotzdem fortsetzen?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Existierende Datei oder Symlink ausgewÃĪhlt, bitte ein anderes Installationsziel auswÃĪhlen.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Installationsordner auswÃĪhlen.</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>Der Installationspfad darf nicht leer sein. Bitte einen gÞltigen Verzeichnis angeben.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>Der Installationspfad darf nicht relativ sein. Bitte einen absoluten Pfad angeben.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>Der Pfad zum Installationsverzeichnis enthÃĪlt Zeichen ausserhalb des ASCII-Zeichensatzes. Dies ist zur Zeit nicht unterstÞtzt. Bitte wÃĪhlen Sie einen anderen Pfad oder Installationsordner.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Da das Installations-Verzeichnis komplett gelÃķscht wird, ist das Installieren in %1 verboten.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>Der von Ihnen eingegebene Pfad ist zu lang, bitte geben Sie einen gÞltigen Pfad ein.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>Der von Ihnen eingegebene Pfad ist ungÞltig, bitte geben Sie ein gÞltiges Ziel ein.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>Der von Ihnen eingegebene Pfad ist ungÞltig, bitte geben Sie ein gÞltiges Laufwerk an.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>Der Installationspfad darf nicht auf '.' enden, bitte geben Sie einen gÞltigen Verzeichnis ein.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>Der Installationspfad darf nicht "%1" enthalten, bitte geben Sie einen gÞltigen Verzeichnis ein.</translation> </message> <message> <source>Warning</source> <translation>Achtung</translation> </message> <message> <source>Error</source> <translation>Fehler</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Fehlende Paketmanager-Kernkomponente.</translation> </message> <message> <source>Empty repository URL.</source> <translation>Leere Quelladresse.</translation> </message> <message> <source>Download canceled.</source> <translation>Heruntergeladen abgeschlossen.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation type="unfinished"></translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>UngÞltiges Format der Updates.xml: %1.</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Konnte Updates.xml nicht zum Lesen Ãķffnen.</translation> </message> <message> <source>Authentication failed.</source> <translation>Authentifizierung fehlgeschlagen.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Unbekannte Fehler beim Testen des Repository "%1"</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Autorisierung benÃķtigt.</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Geben Sie Ihr Passwort ein, um sich fÞr sudo zu authentifizieren:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Fehler beim Erlangen von Administratorrechten.</translation> </message> </context> <context> <name>Receiver</name> <message> <source>remaining.</source> <translation>verbleibend.</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Konnte Autorisierung nicht erhalten.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Konnte die Autorisierung, die zum Fortsetzen der Installation nÃķtig ist, nicht erhalten. Bitte starten Sie das Programm mit den nÃķtigen Rechten erneut.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Konnte die Autorisierung, die zum Fortsetzen der Installation nÃķtig ist, nicht erhalten. Brechen Sie entweder die Installation ab, oder verwenden Sie die Fallback-LÃķsung, indem Sie %1 als root aufrufen und dann "Ok" auswÃĪhlen. </translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Konnte Ressource %1 nicht Ãķffnen: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Konnte Einstellungsdatei %1 nicht zum Lesen Ãķffnen: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Einstellungen</translation> </message> <message> <source>Network</source> <translation>Netzwerk</translation> </message> <message> <source>No proxy</source> <translation>Kein Proxy</translation> </message> <message> <source>System proxy settings</source> <translation>Systemeinstellungen fÞr Proxy</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Manuelle Konfiguration des Proxy</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP-Proxy:</translation> </message> <message> <source>Port:</source> <translation>Port:</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP-Proxy:</translation> </message> <message> <source>Repositories</source> <translation>Quellen</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Benutzername und Passwort fÞr die Autentifizierung hinzufÞgen, falls benÃķtigt.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Ausschließlich temporÃĪre Quellen verwenden</translation> </message> <message> <source>Add</source> <translation>HinzufÞgen</translation> </message> <message> <source>Remove</source> <translation>Entfernen</translation> </message> <message> <source>Test</source> <translation>Testen</translation> </message> <message> <source>Show Passwords</source> <translation>PasswÃķrter anzeigen</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>AuswÃĪhlen, um die Quelle zu verwenden.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Benutzernamen eintragen, um sich gegenÞber der Quelle zu authentifizieren.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Passwort eintragen, um sich gegenÞber der Quelle zu authentifizieren.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>Adresse angeben, die auf eine gÞltige Quelle zeigt.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Beim Testen der Quelle ist ein Fehler aufgetreten.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Das Repository wurde erfolgreich getestet.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Soll die getestete Quelle deaktiviert werden?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Wollen Sie das Repository anschalten?</translation> </message> <message> <source>Hide Passwords</source> <translation>PasswÃķrter ausblenden</translation> </message> <message> <source>Use</source> <translation>Verwende</translation> </message> <message> <source>Username</source> <translation>Benutzername</translation> </message> <message> <source>Password</source> <translation>Passwort</translation> </message> <message> <source>Repository</source> <translation>Quelle</translation> </message> <message> <source>Default repositories</source> <translation>Standardquellen</translation> </message> <message> <source>Temporary repositories</source> <translation>TemporÃĪre Quellen</translation> </message> <message> <source>User defined repositories</source> <translation>Benutzerdefinierte Quellen</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>Registrierungspfad %1 ist nicht beschreibbar</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>Konnte nicht in Registrierungspfad %1 schreiben</translation> </message> <message> <source>exactly %1</source> <translation>genau %1</translation> </message> <message> <source>at least %1</source> <translation>mindestens %1</translation> </message> <message> <source>not more than %1</source> <translation>nicht mehr als %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 oder %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 zu %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation type="unfinished"> <numerusform>UngÞltige Argumente in %0: %1 Argumente erhalten, %2 erwartet.</numerusform> <numerusform>UngÞltige Argumente in %0: %1 Argumente erhalten, %2 erwartet.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>UngÞltige Argumente in %0: %1 Argumente erhalten, %2 erwartet.</numerusform> <numerusform>UngÞltige Argumente in %0: %1 Argumente erhalten, %2 erwartet.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Verbleibende Datei "%1" wegen "%2": %3</translation> </message> </context> </TS> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_es.ts�����������������������������������������0100777�0000000�0000000�00000306046�13761647206�021026� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 en %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>El proxy requiere autenticaciÃģn.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>No se puede buscar %1 para leer los datos de operaciones.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>No se puede buscar %1 para leer el bloque de captura de recursos.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>No se puede abrir el recurso de metadatos %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>No se puede buscar %1 para leer el recuento de metadatos integrados.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>No se puede buscar %1 para leer el segmento de captura de recursos.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Discrepancia inesperada de recursos de metadatos. Leídos %1, esperados: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Se requiere autenticaciÃģn http</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Debe proporcionar un nombre de usuario y una contraseÃąa para acceder a este sitio.</translation> </message> <message> <source>Username:</source> <translation>Nombre de usuario:</translation> </message> <message> <source>Password:</source> <translation>ContraseÃąa:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 en %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>La ruta "%1" existe, pero no es un directorio.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No se puede crear el directorio "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>No se puede recuperar la ruta del elemento del archivo %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>No se puede quitar el symlink existente %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>No se puede crear el symlink en "%1". Ya existe otro.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>No se puede leer el destino del symlink en el archivo "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>No se puede crear el symlink en %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Esperando a %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Ya se estÃĄ ejecutando otra instancia de %1. Espere a que finalice, ciÃĐrrela o reinicie el sistema.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Componentes agregados como dependencias automÃĄticas:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Componentes agregados como dependencia para "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Componentes que tienen dependencias resueltas:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Componentes seleccionados sin dependencias:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Recurrencia detectada, el componente "%1" ya se ha agregado con la razÃģn: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>No se puede encontrar la dependencia "%1" que falta para "%2".</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Cancelado</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No se puede crear una copia de seguridad del archivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>No se puede encontrar el archivo de copia de seguridad para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>No se puede crear una copia de seguridad del archivo "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>No se puede copiar un archivo que no existe: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No se puede eliminar el archivo "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No se puede copiar el archivo "%1" a "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>No se puede eliminar el archivo "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>No se puede restaurar el archivo de copia de seguridad en "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>No se puede crear una copia de seguridad del archivo "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Descarga completada.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Los hashes criptogrÃĄficos no coinciden.</translation> </message> <message> <source>Download canceled.</source> <translation>Descarga cancelada.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 descargado.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/seg)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n día(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto(s)</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segundo(s)</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restante.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tiempo restante desconocido.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>No se puede descargar %1. Error al escribir en el archivo "%2": %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>No se puede descargar %1. No se puede crear el archivo "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 en %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>La solicitud de autenticaciÃģn se ha cancelado.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Error de la conexiÃģn segura</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Se ha producido un error durante la conexiÃģn a: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Podría tratarse de un problema con la configuraciÃģn del servidor o alguien que estÃĄ intentando suplantar al servidor.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Si en el pasado ya se ha conectado correctamente a este servidor o bien confía en el servidor, puede intentarlo de nuevo porque es posible que se trate de un error temporal.</translation> </message> <message> <source>Try again</source> <translation>Volver a intentar</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Error al escribir en el archivo "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>No se puede crear el directorio "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconocido.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No se puede eliminar el directorio "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>No se puede crear una copia de seguridad del archivo "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No se puede eliminar el archivo "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No se puede copiar el archivo "%1" a "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No se puede eliminar el archivo "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No se puede crear una copia de seguridad del archivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>No se puede encontrar el archivo de copia de seguridad para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>No se puede restaurar el archivo de copia de seguridad para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>No se puede leer el archivo de recursos "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>No se puede eliminar el directorio "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>El directorio no existe.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>No se puede volver a crear el directorio "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 se ha iniciado</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 no se puede detener</translation> </message> <message> <source>Cannot stop task %1</source> <translation>No se puede detener la tarea %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 no se puede pausar</translation> </message> <message> <source>Cannot pause task %1</source> <translation>No se puede pausar la tarea %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>No se puede reanudar la tarea %1</translation> </message> <message> <source>%1 done</source> <translation>%1 se ha completado</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>No se puede acceder a la informaciÃģn de paquete de esta aplicaciÃģn.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>No hay definida ninguna fuente de paquete para esta aplicaciÃģn.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n actualizaciones encontradas.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Descargando Updates.xml de las fuentes de actualizaciÃģn.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>No se puede descargar la fuente del paquete %1 desde "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Archivo(s) Updates.xml descargado(s) desde las fuentes de actualizaciÃģn.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Calculando actualizaciones vÃĄlidas.</translation> </message> <message> <source>Application updates computed.</source> <translation>Actualizaciones de aplicaciÃģn calculadas.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml tiene contenido no vÃĄlido: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>No se puede leer "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Error de anÃĄlisis en %1 en %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Elemento raíz %1 inesperado, debería ser "Updates".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Falta el elemento ApplicationName.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Falta el elemento ApplicationVersion.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Elemento PackageUpdate sin nombre</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Elemento PackageUpdate sin versiÃģn</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Elemento PackageUpdate sin fecha de publicaciÃģn</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>cÃģdigo interno: %1</translation> </message> <message> <source>not enough memory</source> <translation>no hay suficiente memoria</translation> </message> <message> <source>Error: %1</source> <translation>Error: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>No se puede recuperar la propiedad %1 del elemento %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>La propiedad %1 del elemento %2 no es del tipo VT_FILETIME sino %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>No se puede convertir la hora UTC del archivo a la hora del sistema.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>No se pueden cargar los cÃģdecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>No se puede abrir el archivo "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>No se puede recuperar el nÚmero de elementos del archivo.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>No se puede recuperar la ruta del elemento del archivo "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Se ha producido una excepciÃģn desconocida (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>No se puede crear el archivo temporal: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Tipo de archivo no admitido.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>No se puede crear el archivo "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>No se puede crear el archivo "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>No se puede quitar el archivo antiguo "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>No se puede cambiar el nombre del archivo temporal de "%1" a "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Se ha producido una excepciÃģn desconocida (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 tiene contenido no vÃĄlido: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>El archivo %1 no existe.</translation> </message> <message> <source>Cannot open %1.</source> <translation>No se puede abrir %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Error de anÃĄlisis en %1 en %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>No se esperaba el elemento raíz %1, debería ser 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>No se puede crear el archivo de bloqueo "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>No se puede escribir el PID en el archivo de bloqueo "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>No se puede obtener el bloqueo para el archivo "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>No se puede liberar el bloqueo para el archivo "%1": %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>No se ha encontrado ningÚn marcador, se ha detenido despuÃĐs de %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Error de lectura despuÃĐs de %1 bytes: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Error al copiar: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Error de escritura despuÃĐs de %1 bytes: %2</translation> </message> <message> <source>bytes</source> <translation>bytes</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No se puede eliminar el archivo "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No se puede eliminar el directorio "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No se puede crear el directorio "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>No se puede copiar el archivo de "%1" a "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>No se puede mover el archivo de "%1" a "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No se puede crear el directorio "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>No se puede abrir el archivo temporal: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>No se puede abrir el archivo temporal para la plantilla %1: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>InstalaciÃģn daÃąada</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>Parece que su instalaciÃģn estÃĄ daÃąada. Vuelva a realizar la instalaciÃģn desde el principio.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>No se encontrÃģ el mÃģdulo especificado.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Los componentes no pueden tener elementos secundarios en el modo actualizador.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>No se puede abrir el archivo de UI "%1" solicitado: %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>No se puede cargar el archivo de UI "%1" solicitado: %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>No se puede abrir el archivo de licencia "%1" solicitado: %2</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Error: la operaciÃģn %1 no existe.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>No se puede resolver isDefault en %1</translation> </message> <message> <source>Update Info: </source> <translation>InformaciÃģn de actualizaciÃģn: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>El componente estÃĄ marcado para la instalaciÃģn.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>El componente estÃĄ marcado para la desinstalaciÃģn.</translation> </message> <message> <source>Component is installed.</source> <translation>El componente estÃĄ instalado.</translation> </message> <message> <source>Component is not installed.</source> <translation>El componente no estÃĄ instalado.</translation> </message> <message> <source>Component Name</source> <translation>Nombre del componente</translation> </message> <message> <source>Action</source> <translation>AcciÃģn</translation> </message> <message> <source>Installed Version</source> <translation>VersiÃģn instalada</translation> </message> <message> <source>New Version</source> <translation>Nueva versiÃģn</translation> </message> <message> <source>Release Date</source> <translation>Fecha de versiÃģn</translation> </message> <message> <source>Size</source> <translation>TamaÃąo</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>Predetermin&ado</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&Restablecer</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&Seleccionar todo</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>Anular selecciÃģn de to&do</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Para instalar el nuevo repositorio comprimido, examine los repositorios de su equipo</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&Examinar archivos QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Este componente ocuparÃĄ aproximadamente %1 en el disco duro.</translation> </message> <message> <source>Open File</source> <translation>Abrir archivo</translation> </message> <message> <source>Select Components</source> <translation>Seleccionar componentes</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Seleccione los componentes que desea actualizar.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Seleccione los componentes que desea instalar.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Seleccione los componentes que desea desinstalar.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Seleccione los componentes que desea instalar. Anule la selecciÃģn de los componentes instalados para desinstalarlos. No se actualizarÃĄn los componentes ya instalados.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><to be saved installer key name> <executable> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>El objeto de instalador necesario en la operaciÃģn %1 estÃĄ vacío.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>No se puede guardar la salida de "%1" en un valor de clave de instalador vacío.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>El archivo "%1" no existe o no es un binario ejecutable.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>Se ha producido un error al ejecutar "%1".</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><source> <target> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Argumento no vÃĄlido en %1: el tercer argumento debe ser forceOverwrite, si se ha especificado.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Argumento no vÃĄlido en %1: el directorio "%2" no es vÃĄlido.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>No se puede crear el directorio "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Error al sobrescribir "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>No se puede copiar el archivo "%1" a "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No se puede eliminar el archivo "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Recuento de elementos de tarea no vÃĄlido.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Error al escribir en el archivo "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>No se puede crear una copia de seguridad del archivo "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Error al sobrescribir el archivo "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>No se puede escribir la entrada de escritorio en %1.</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>No se puede crear el vínculo entre "%1" y "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>No se puede quitar el vínculo entre "%1" y "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>No se pueden establecer permisos para el archivo "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>No se puede eliminar el archivo "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>No se puede mover el archivo "%1" a "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>El instalador de "%1" debe ser sin conexiÃģn.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>No se puede abrir el archivo "%1" para la lectura.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>No se puede leer el archivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>No se puede crear el directorio de destino: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Se ha producido una excepciÃģn desconocida: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Eliminando el archivo "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>No se puede eliminar el archivo "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>No se puede eliminar el directorio "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No se puede crear el directorio "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Error al sobrescribir "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>No se puede crear el vínculo "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Cancelado</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Error al descargar la firma del hash.</translation> </message> <message> <source>Download Error</source> <translation>Error de descarga</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Error de verificaciÃģn del hash durante la descarga. Es un error temporal, vuelva a intentarlo.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>No se puede verificar el hash</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>No se puede descargar el archivo %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>No se pueden obtener los archivos: %1 Error al descargar %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Descargando el archivo "%1" para el componente %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Esquema %1 no admitido (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>No se puede encontrar el componente para %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>El archivo de destino "%1" ya existe, pero no es un archivo.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>No se pudo abrir el archivo "%1" para la escritura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Error al escribir en el archivo "%1": %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Se ha detectado un bucle de redirecciÃģn para "%1".</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Discrepancia de suma de comprobaciÃģn detectada para "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Error de red durante la descarga de '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Error de red desconocido durante la descarga de "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>Transferencias de red canceladas.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>La pausa y la reanudaciÃģn no son compatibles con las transferencias de red.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>URL de origen "%1" no vÃĄlida: %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>No se puede iniciar aislado: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>No se puede iniciar: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>El programa ha dejado de funcionar: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Error de ejecuciÃģn (cÃģdigo de error no esperado: %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Error al extraer el archivo "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Se ha producido una excepciÃģn desconocida al extraer "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>No se puede obtener el componente bÃĄsico del administrador de paquetes.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Este proceso se debe detener antes de continuar: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Estos procesos se deben detener antes de continuar: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 recibido.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/seg)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n día(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto(s)</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segundo(s)</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restante.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tiempo restante desconocido.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>Completando el Asistente de %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Haga clic en %1 para salir del asistente de %2.</translation> </message> <message> <source>Restart</source> <translation>Reiniciar</translation> </message> <message> <source>Run %1 now.</source> <translation>Ejecute %1 ahora.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>Error del Asistente de %1.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>No se puede escribir en la configuraciÃģn.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Error al escribir en la configuraciÃģn.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><source path> [vendor prefix]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Argumento no vÃĄlido: el directorio de origen no debe estar vacío.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>No se puede crear una copia de seguridad del archivo "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Error al sobrescribir "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Error al copiar el archivo "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>No se puede crear el directorio "%1": %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Programa de instalaciÃģn - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Bienvenido al Asistente de instalaciÃģn de %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>Agregar o quitar componentes</translation> </message> <message> <source>&Update components</source> <translation>Actualizar componentes</translation> </message> <message> <source>&Remove all components</source> <translation>Quitar todos los componentes</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Recuperando informaciÃģn de fuentes de instalaciÃģn remotas...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Se requiere al menos un repositorio vÃĄlido y habilitado para que esta acciÃģn se realice correctamente.</translation> </message> <message> <source>No updates available.</source> <translation>No hay actualizaciones disponibles.</translation> </message> <message> <source> Only local package management available.</source> <translation> Solo estÃĄ disponible la administraciÃģn de paquetes locales.</translation> </message> <message> <source>&Quit</source> <translation>Salir</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Contrato de licencia</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Lea el siguiente contrato de licencia. Debe aceptar los tÃĐrminos contenidos en este contrato antes de continuar con la instalaciÃģn.</translation> </message> <message> <source>I accept the license.</source> <translation>Acepto la licencia.</translation> </message> <message> <source>I do not accept the license.</source> <translation>No acepto la licencia.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Lea los siguientes contratos de licencia. Debe aceptar los tÃĐrminos contenidos en estos contratos antes de continuar con la instalaciÃģn.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Acepto las licencias.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>No acepto las licencias.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>No se han encontrado archivos de licencia para copiar.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>El objeto de instalador necesario en la operaciÃģn %1 estÃĄ vacío.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>No se puede escribir en el archivo de licencia "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>No se han encontrado archivos de licencia para eliminar.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Falta el motor de componente bÃĄsico del administrador de paquetes.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Preparando la descarga de la informaciÃģn de metadatos...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Desempaquetando los repositorios comprimidos. Esta operaciÃģn puede tardar...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Descarga de metadatos cancelada.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Se ha producido una excepciÃģn durante la extracciÃģn.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Faltan las credenciales del proxy.</translation> </message> <message> <source>Authentication failed.</source> <translation>Error de autenticaciÃģn.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Se ha producido una excepciÃģn desconocida durante la descarga.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Error al recuperar los repositorios.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Extrayendo la informaciÃģn de metadatos...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Recuperando informaciÃģn de metadatos del repositorio remoto... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Recuperando informaciÃģn de metadatos del repositorio remoto... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Error al extraer el archivo "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Se ha producido una excepciÃģn desconocida al extraer el archivo "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Error al escribir la herramienta de mantenimiento</translation> </message> <message> <source> Downloading packages...</source> <translation> Descargando paquetes...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>InstalaciÃģn cancelada por el usuario.</translation> </message> <message> <source>All downloads finished.</source> <translation>Se han completado todas las descargas.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Cancelando el instalador</translation> </message> <message> <source>Authentication Error</source> <translation>Error de autenticaciÃģn</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Algunos componentes no se pueden eliminar por completo porque no se pueden adquirir derechos administrativos: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconocido.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Algunos componentes no se han podido eliminar por completo porque se ha producido un error desconocido.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>La aplicaciÃģn no se estÃĄ ejecutando en el modo de administrador de paquetes.</translation> </message> <message> <source>No installed packages found.</source> <translation>No se han encontrado paquetes instalados.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>La aplicaciÃģn se estÃĄ ejecutando en el modo de desinstalador.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Hay disponible una actualizaciÃģn importante; ejecute primero el actualizador.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>No se pueden resolver todas las dependencias.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Componentes que estÃĄn a punto de eliminarse.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Error al aumentar los derechos de acceso.</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>invalid</source> <translation>no vÃĄlido</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>Dependencias sin resolver</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>Access error</source> <translation>Error de acceso</translation> </message> <message> <source>Format error</source> <translation>Error de formato</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>No se puede escribir la configuraciÃģn del instalador en %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Detener procesos</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Estos procesos se deben detener para continuar: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>InstalaciÃģn cancelada por el usuario</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Escribiendo la herramienta de mantenimiento.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>No se puede buscar en el archivo %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>La herramienta de mantenimiento no es un paquete</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>No se puede quitar el archivo de datos "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>No se pueden escribir los datos de la herramienta de mantenimiento en %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>No se puede escribir la herramienta de mantenimiento en "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>No se pueden escribir los datos binarios de la herramienta de mantenimiento en %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>'TargetDir' no se ha definido.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Preparando la instalaciÃģn...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>No es posible instalar desde una ubicaciÃģn de red</translation> </message> <message> <source>Creating local repository</source> <translation>Creando repositorio local</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Creando herramienta de mantenimiento</translation> </message> <message> <source> Installation finished!</source> <translation> InstalaciÃģn completada.</translation> </message> <message> <source> Installation aborted!</source> <translation> InstalaciÃģn cancelada.</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>No es posible ejecutar esa operaciÃģn desde una ubicaciÃģn de red</translation> </message> <message> <source>Removing deselected components...</source> <translation>Eliminando componentes anulados de la selecciÃģn...</translation> </message> <message> <source> Update finished!</source> <translation> ActualizaciÃģn completada.</translation> </message> <message> <source> Update aborted!</source> <translation> ActualizaciÃģn cancelada.</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>La desinstalaciÃģn se ha completado correctamente.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>DesinstalaciÃģn cancelada.</translation> </message> <message> <source> Installing component %1</source> <translation> Instalando componente %1</translation> </message> <message> <source>Installer Error</source> <translation>Error del instalador</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Error durante el proceso de instalaciÃģn (%1): %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>No se puede preparar la desinstalaciÃģn</translation> </message> <message> <source>Cannot start uninstall</source> <translation>No se puede iniciar la desinstalaciÃģn</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Error durante el proceso de desinstalaciÃģn: %1</translation> </message> <message> <source>Unknown error</source> <translation>Error desconocido</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>No se puede recuperar el ÃĄrbol remoto %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Error al leer los paquetes en %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>No se puede recuperar la informaciÃģn de los metadatos: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>No se puede agregar la informaciÃģn de la fuente de actualizaciÃģn temporal.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>No se puede encontrar ninguna informaciÃģn de fuente de actualizaciÃģn.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Se ha detectado un ciclo de dependencia entre componentes los "%1" y "%2".</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>Programa de instalaciÃģn de %1</translation> </message> <message> <source>Maintain %1</source> <translation>Mantener %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>ÂŋDesea cancelar el proceso de instalaciÃģn?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>ÂŋDesea cancelar el proceso de desinstalaciÃģn?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>ÂŋDesea salir de la aplicaciÃģn del instalador?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>ÂŋDesea salir de la aplicaciÃģn del desinstalador?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>ÂŋDesea salir de la aplicaciÃģn de mantenimiento?</translation> </message> <message> <source>%1 Question</source> <translation>%1 pregunta</translation> </message> <message> <source>Settings</source> <translation>ConfiguraciÃģn</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>No es posible instalar desde una ubicaciÃģn de red. Copie el instalador en una unidad local.</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>Mo&strar detalles</translation> </message> <message> <source>&Hide Details</source> <translation>O&cultar detalles</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstalar</translation> </message> <message> <source>Uninstalling %1</source> <translation>Desinstalando %1</translation> </message> <message> <source>&Update</source> <translation>Act&ualizar</translation> </message> <message> <source>Updating components of %1</source> <translation>Actualizando componentes de %1</translation> </message> <message> <source>&Install</source> <translation>&Instalar</translation> </message> <message> <source>Installing %1</source> <translation>Instalando %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Cuadro de diÃĄlogo</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>El proxy %1 requiere un nombre de usuario y una contraseÃąa.</translation> </message> <message> <source>Username:</source> <translation>Nombre de usuario:</translation> </message> <message> <source>Username</source> <translation>Nombre de usuario</translation> </message> <message> <source>Password:</source> <translation>ContraseÃąa:</translation> </message> <message> <source>Password</source> <translation>ContraseÃąa</translation> </message> <message> <source>Proxy Credentials</source> <translation>Credenciales del Proxy</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstalar</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Preparado para desinstalar</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>El programa de instalaciÃģn estÃĄ preparado para empezar a eliminar %1 del equipo.<br><font color="red">El directorio del programa %2 se eliminarÃĄ completamente</font>, incluido todo el contenido del directorio.</translation> </message> <message> <source>U&pdate</source> <translation>Actu&alizar</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Preparado para actualizar paquetes</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>El programa de instalaciÃģn estÃĄ preparado para empezar a actualizar la instalaciÃģn.</translation> </message> <message> <source>&Install</source> <translation>&Instalar</translation> </message> <message> <source>Ready to Install</source> <translation>Preparado para instalar</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>El programa de instalaciÃģn estÃĄ preparado para empezar a instalar %1 en su equipo.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>No hay suficiente espacio en disco para almacenar los archivos temporales y la instalaciÃģn. Se dispone de %1 y se requiere al menos un espacio de %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>No hay suficiente espacio en disco para almacenar todos los componentes seleccionados. Se dispone de %1 y se requiere al menos un espacio de %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>No hay suficiente espacio en disco para almacenar los archivos temporales. Se dispone de %1 y se requiere al menos un espacio de %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>El volumen que ha seleccionado para la instalaciÃģn parece tener suficiente espacio para la instalaciÃģn, pero despuÃĐs quedarÃĄ menos del 1% del espacio disponible. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>El volumen que ha seleccionado para la instalaciÃģn parece tener suficiente espacio para la instalaciÃģn, pero despuÃĐs quedarÃĄn menos de 100 MB disponibles. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>La instalaciÃģn usarÃĄ %1 de espacio de disco.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><extension> <command> [description [contentType [icon]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>El registro de tipos de archivos solo se admite en Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Tipo de archivo de registro: argumentos no vÃĄlidos</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>No se pueden leer todos los datos despuÃĐs de enviar el comando: %1. Bytes esperados: %2. Bytes recibidos: %3. Error: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>No se puede abrir el archivo "%1" para la lectura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>No se puede abrir el archivo '%1' para la escritura: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>No se puede abrir el recurso "%1" para la lectura.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Error de lectura despuÃĐs de %1 bytes: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Error de escritura despuÃĐs de %1 bytes: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>Completando el Asistente de instalaciÃģn de %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>No se puede abrir el archivo de script en %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>ExcepciÃģn al cargar el script del componente "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Error desconocido.</translation> </message> <message> <source>on line number: </source> <translation>en la línea nÚmero: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>El objeto de instalador necesario en la operaciÃģn %1 estÃĄ vacío.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Auto-reinicio: solo es vÃĄlido en el modo de actualizaciÃģn o de administrador de paquetes.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Auto-reinicio: argumentos no vÃĄlidos</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>El servidor requiere autenticaciÃģn</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Debe proporcionar un nombre de usuario y una contraseÃąa para acceder a este sitio.</translation> </message> <message> <source>Username:</source> <translation>Nombre de usuario:</translation> </message> <message> <source>Password:</source> <translation>ContraseÃąa:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 en %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Faltan argumentos "%1" que llamen a %2 con los argumentos "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>El argumento de mÃĐtodo actual que llama a "%1" con los argumentos "%2" no estÃĄ admitido. Utilice set, remove, add_array_value o remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>No puede haber ningÚn argumento vacío: origen "%1", destino "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>No se puede mover el archivo de "%1" a "%2", porque la ruta de destino ya existe y no se puede eliminar.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>No se puede mover el archivo "%1" a "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>Moviendo el archivo "%1" a "%2".</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Accesos directos del menÚ de Inicio</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Seleccione en menÚ de inicio donde desee crear los accesos directos del programa. TambiÃĐn puede introducir un nombre para crear un directorio nuevo.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Carpeta de instalaciÃģn</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Especifique el directorio en el que se instalarÃĄ %1.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>Examina&r...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>El directorio que ha seleccionado ya existe y contiene una instalaciÃģn. Elija otro destino para la instalaciÃģn.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Ha seleccionado un directorio existente y no vacío para la instalaciÃģn. Tenga en cuenta que se eliminarÃĄ por completo al desinstalar esta aplicaciÃģn. No es recomendable instalar en este directorio, ya que la instalaciÃģn podría generar un error. ÂŋDesea continuar?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Ha seleccionado un archivo o un symlink existente. Elija un destino diferente para la instalaciÃģn.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Seleccionar carpeta de instalaciÃģn</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>La ruta de instalaciÃģn no puede estar vacía. Especifique un directorio vÃĄlido.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>La ruta de instalaciÃģn no puede ser relativa. Especifique una ruta absoluta.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>La ruta o el directorio de instalaciÃģn contiene caracteres que no son ASCII. Esto no es compatible actualmente. Elija una ruta o un directorio de instalaciÃģn diferente.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Puesto que el directorio de instalaciÃģn se ha eliminado por completo, estÃĄ prohibido instalar en %1.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>La ruta que ha introducido es demasiado larga. Debe especificar una ruta vÃĄlida.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>La ruta que ha introducido no es vÃĄlida. Debe especificar un destino vÃĄlido.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>La ruta que ha introducido no es vÃĄlida. Debe especificar una unidad vÃĄlida.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>La ruta de instalaciÃģn no debe terminar con '.'. Especifique un directorio vÃĄlido.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>La ruta de instalaciÃģn no debe contener "%1". Especifique un directorio vÃĄlido.</translation> </message> <message> <source>Warning</source> <translation>Advertencia</translation> </message> <message> <source>Error</source> <translation>Error</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Falta el motor de componente bÃĄsico del administrador de paquetes.</translation> </message> <message> <source>Empty repository URL.</source> <translation>La direcciÃģn URL del repositorio estÃĄ vacía.</translation> </message> <message> <source>Download canceled.</source> <translation>Descarga cancelada.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Se ha obtenido un tiempo de espera durante la prueba del repositorio "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>No se puede analizar Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>No se puede abrir Updates.xml para la lectura: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Error de autenticaciÃģn.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Se ha obtenido un error desconocido durante la prueba del repositorio "%1".</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Se necesita autorizaciÃģn</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Introduzca su contraseÃąa para autorizar para sudo:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Error al adquirir derechos de administrador</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>No se puede obtener la autorizaciÃģn.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>No se puede obtener una autorizaciÃģn que se necesita para continuar con la instalaciÃģn. Inicie el programa de instalaciÃģn como usuario con los derechos necesarios. O bien acepte la elevaciÃģn de los derechos de acceso si se le pide.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>No se puede obtener una autorizaciÃģn que se necesita para continuar con la instalaciÃģn. Cancele la instalaciÃģn o use la soluciÃģn alternativa ejecutando %1 como usuario con los derechos adecuados y, luego, haga clic en Aceptar.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>No se puede abrir el recurso %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>No se puede abrir el archivo de configuraciÃģn %1 para la lectura: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>ConfiguraciÃģn</translation> </message> <message> <source>Network</source> <translation>Red</translation> </message> <message> <source>No proxy</source> <translation>No hay proxy</translation> </message> <message> <source>System proxy settings</source> <translation>ConfiguraciÃģn de proxy del sistema</translation> </message> <message> <source>Manual proxy configuration</source> <translation>ConfiguraciÃģn de proxy manual</translation> </message> <message> <source>HTTP proxy:</source> <translation>Proxy HTTP:</translation> </message> <message> <source>Port:</source> <translation>Puerto:</translation> </message> <message> <source>FTP proxy:</source> <translation>Proxy FTP:</translation> </message> <message> <source>Repositories</source> <translation>Repositorios</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Agregue el nombre de usuario y la contraseÃąa para la autenticaciÃģn si es necesario.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Usar solo repositorios temporales</translation> </message> <message> <source>Add</source> <translation>AÃąadir</translation> </message> <message> <source>Remove</source> <translation>Quitar</translation> </message> <message> <source>Test</source> <translation>Prueba</translation> </message> <message> <source>Show Passwords</source> <translation>Mostrar contraseÃąas</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Active esta opciÃģn para usar el repositorio durante la obtenciÃģn.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Agregue el nombre de usuario para autenticar en el servidor.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Agregue la contraseÃąa para autenticar en el servidor.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>DirecciÃģn URL de los servidores que contiene un repositorio vÃĄlido.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Se produjo un error al probar este repositorio.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Repositorio probado correctamente.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>ÂŋDesea deshabilitar el repositorio?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>ÂŋDesea habilitar el repositorio?</translation> </message> <message> <source>Hide Passwords</source> <translation>Ocultar contraseÃąas</translation> </message> <message> <source>Use</source> <translation>Utilizar</translation> </message> <message> <source>Username</source> <translation>Nombre de usuario</translation> </message> <message> <source>Password</source> <translation>ContraseÃąa</translation> </message> <message> <source>Repository</source> <translation>Repositorio</translation> </message> <message> <source>Default repositories</source> <translation>Repositorios predeterminados</translation> </message> <message> <source>Temporary repositories</source> <translation>Repositorios temporales</translation> </message> <message> <source>User defined repositories</source> <translation>Repositorios definidos por el usuario</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>No se puede escribir en la ruta de registro %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>No se puede escribir en la ruta de registro %1.</translation> </message> <message> <source>exactly %1</source> <translation>exactamente %1</translation> </message> <message> <source>at least %1</source> <translation>al menos %1</translation> </message> <message> <source>not more than %1</source> <translation>no mÃĄs de %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 o %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 a %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Argumentos no vÃĄlidos en %1: se han proporcionado %n argumentos, se esperaban %2.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Argumentos no vÃĄlidos en %1: se han proporcionado %n argumentos, se esperaban %2 con la forma: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Error al cambiar el nombre de archivo de "%1" a "%2": %3</translation> </message> </context> </TS> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_fr.ts�����������������������������������������0100777�0000000�0000000�00000311071�13761647206�021020� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 sur %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>Le proxy requiert une authentification.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Impossible de rechercher %1 pour lire les donnÃĐes de l’opÃĐration.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Impossible de rechercher %1 pour lire le bloc de collection des ressources.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Impossible d’ouvrir les mÃĐta-ressources %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Impossible de rechercher %1 pour lire le total des mÃĐtadonnÃĐes incorporÃĐes.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Impossible de rechercher %1 pour lire le segment de collection des ressources.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Non-concordance inattendue des mÃĐta-ressources. %1 lu, attendu : %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Authentification HTTP requise</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Vous devez fournir un nom d’utilisateur et un mot de passe pour accÃĐder au site.</translation> </message> <message> <source>Username:</source> <translation>Nom d'utilisateur :</translation> </message> <message> <source>Password:</source> <translation>Mot de passe :</translation> </message> <message> <source>%1 at %2</source> <translation>%1 sur %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>Le chemin "%1" existe, mais il ne s’agit pas d’un rÃĐpertoire.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Impossible d’extraire le chemin d’accÃĻs de l’ÃĐlÃĐment d’archive %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Impossible de supprimer le lien symbolique %1 existant.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Impossible de crÃĐer un lien symbolique dans "%1". Un autre existe dÃĐjà.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Impossible de lire la cible du lien symbolique à partir du fichier "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Impossible de crÃĐer un lien symbolique dans %1 : %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Attente de %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Une autre instance de %1 est dÃĐjà en cours d’exÃĐcution. Attendez qu’elle soit terminÃĐe, fermez-la ou redÃĐmarrez votre systÃĻme.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Composants ajoutÃĐs en tant que dÃĐpendances automatiques :</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Composants ajoutÃĐs en tant que dÃĐpendances pour "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Composants qui ont rÃĐsolu les dÃĐpendances :</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Composants sÃĐlectionnÃĐs sans dÃĐpendances :</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>RÃĐcursion dÃĐtectÃĐe, composant "%1" dÃĐjà ajoutÃĐ avec raison : "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>La dÃĐpendance manquante "%1" est introuvable pour "%2".</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>AbandonnÃĐ</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossible de sauvegarder le fichier "%1" : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Le fichier de sauvegarde pour "%1" est introuvable.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Impossible de sauvegarder le fichier "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Impossible de copier un fichier qui n’existe pas : %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossible de supprimer le fichier "%1" : %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossible de copier le fichier "%1" vers "%2" : %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Impossible de supprimer le fichier "%1" : %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Impossible de restaurer le fichier de sauvegarde dans "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Impossible de crÃĐer une sauvegarde du fichier "%1" : %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>TÃĐlÃĐchargement terminÃĐ.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Les hachages de chiffrement ne correspondent pas.</translation> </message> <message> <source>Download canceled.</source> <translation>TÃĐlÃĐchargement annulÃĐ.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 sur %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 tÃĐlÃĐchargÃĐ.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sec)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n jour(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n heure(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minute(s)</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n seconde(s)</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restants.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - temps restant inconnu.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Impossible de tÃĐlÃĐcharger %1. L’ÃĐcriture dans le fichier "%2" a ÃĐchouÃĐ : %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Impossible de tÃĐlÃĐcharger %1. Impossible de crÃĐer le fichier "%2" : %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 sur %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Demande d’authentification annulÃĐe.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Échec de la connexion sÃĐcurisÃĐe</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Une erreur s’est produite lors de la connexion à : %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Il peut s’agir d’un problÃĻme avec la configuration du serveur ou quelqu’un peut tenter d’usurper l’identitÃĐ du serveur.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Si vous vous Êtes dÃĐjà connectÃĐ au serveur dans le passÃĐ ou si vous lui faites confiance, l’erreur peut Être temporaire et vous pouvez rÃĐessayer.</translation> </message> <message> <source>Try again</source> <translation>RÃĐessayez</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>L’ÃĐcriture dans le fichier "%1" a ÃĐchouÃĐ : %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1" : %2</translation> </message> <message> <source>Unknown error.</source> <translation>Erreur inconnue.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossible de supprimer le rÃĐpertoire "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Impossible de sauvegarder le fichier "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossible de supprimer le fichier "%1" : %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossible de copier le fichier "%1" vers "%2" : %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossible de supprimer le fichier "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossible de sauvegarder le fichier "%1" : %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Le fichier de sauvegarde pour "%1" est introuvable.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossible de restaurer le fichier de sauvegarde pour "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Impossible de lire le fichier de ressources "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossible de supprimer le rÃĐpertoire "%1" : %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>Le rÃĐpertoire n’existe pas.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Impossible de recrÃĐer le rÃĐpertoire "%1" : %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 dÃĐmarrÃĐe</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 ne peut pas Être arrÊtÃĐe</translation> </message> <message> <source>Cannot stop task %1</source> <translation>Impossible d’arrÊter la tÃĒche %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 ne peut pas Être interrompue</translation> </message> <message> <source>Cannot pause task %1</source> <translation>Impossible d’interrompre la tÃĒche %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>Impossible de reprendre la tÃĒche %1</translation> </message> <message> <source>%1 done</source> <translation>%1 terminÃĐe</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Impossible d’accÃĐder aux informations de paquetage de cette application.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Aucune source de paquetage dÃĐfinie pour cette application.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n mise(s) à jour trouvÃĐe(s).</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>TÃĐlÃĐchargement de Updates.xml à partir des sources de mise à jour.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Impossible de tÃĐlÃĐcharger la source de paquetage %1 depuis "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Fichier(s) Updates.xml tÃĐlÃĐchargÃĐ(s) à partir des sources de mise à jour.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Calcul des mises à jour applicables.</translation> </message> <message> <source>Application updates computed.</source> <translation>Mises à jour de l’application calculÃĐes.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml renferme un contenu non valide : %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Impossible de lire "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Erreur d’analyse dans %1 sur %2, %3 : %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>ÉlÃĐment racine %1 inattendu, il doit s’agir de "Updates".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>L’ÃĐlÃĐment ApplicationName est manquant.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>L’ÃĐlÃĐment ApplicationVersion est manquant.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>ÉlÃĐment PackageUpdate sans nom</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>ÉlÃĐment PackageUpdate sans version</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>ÉlÃĐment PackageUpdate sans date de publication</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>code interne : %1</translation> </message> <message> <source>not enough memory</source> <translation>mÃĐmoire insuffisante</translation> </message> <message> <source>Error: %1</source> <translation>Erreur : %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Impossible d’extraire la propriÃĐtÃĐ %1 pour l’ÃĐlÃĐment %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>La propriÃĐtÃĐ %1 pour l’ÃĐlÃĐment %2 n’est pas de type VT_FILETIME mais %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Impossible de convertir l’heure du fichier UTC en heure systÃĻme.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Impossible de charger les codecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Impossible d’ouvrir l’archive "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Impossible d’extraire le nombre d’ÃĐlÃĐments dans l’archive.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Impossible d’extraire le chemin d’accÃĻs de l’ÃĐlÃĐment d’archive "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Exception inconnue dÃĐtectÃĐe (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Impossible de crÃĐer le fichier temporaire : %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Type d’archive non pris en charge.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Impossible de crÃĐer l’archive "%1".</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Impossible de crÃĐer l’archive "%1" : %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>Impossible de supprimer l’ancienne archive "%1" : %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>Impossible de renommer l’archive temporaire "%1" en "%2" : %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Exception inconnue dÃĐtectÃĐe (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 renferme un contenu non valide : %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Le fichier %1 n’existe pas.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Impossible d’ouvrir %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Erreur d’analyse dans %1 sur %2, %3 : %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>ÉlÃĐment racine %1 inattendu, il doit s’agir de 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Impossible de crÃĐer le fichier de verrouillage "%1" : %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Impossible d’ÃĐcrire l’identifiant du processus dans le fichier de verrouillage "%1" : %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Impossible d’obtenir le verrou du fichier "%1" : %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Impossible de dÃĐsactiver le verrou du fichier "%1" : %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Aucun symbole ponctuel trouvÃĐ. ArrÊt aprÃĻs %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Échec de la lecture aprÃĻs %1 octets : %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Échec de la copie : %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Échec de l’ÃĐcriture aprÃĻs %1 octets : %2</translation> </message> <message> <source>bytes</source> <translation>octets</translation> </message> <message> <source>KB</source> <translation>Ko</translation> </message> <message> <source>MB</source> <translation>Mo</translation> </message> <message> <source>GB</source> <translation>Go</translation> </message> <message> <source>TB</source> <translation>To</translation> </message> <message> <source>PB</source> <translation>Po</translation> </message> <message> <source>EB</source> <translation>Eo</translation> </message> <message> <source>ZB</source> <translation>Zo</translation> </message> <message> <source>YB</source> <translation>Yo</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossible de supprimer le fichier "%1" : %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossible de supprimer le rÃĐpertoire "%1" : %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Impossible de copier le fichier depuis "%1" vers "%2" : %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Impossible de dÃĐplacer le fichier depuis "%1" vers "%2" : %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1" : %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Ouvrir d’ouvrir le fichier temporaire : %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Ouvrir d’ouvrir le fichier temporaire pour le modÃĻle %1 : %2</translation> </message> <message> <source>Corrupt installation</source> <translation>Installation endommagÃĐe</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>Votre installation semble endommagÃĐe. Vous pouvez rÃĐinstaller entiÃĻrement le produit.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Le module spÃĐcifiÃĐ est introuvable.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Les composants ne peuvent pas comporter d’enfants en mode de mise à jour.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Impossible d’ouvrir le fichier d’interface utilisateur demandÃĐ "%1" : %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Impossible de charger le fichier d’interface utilisateur demandÃĐ "%1" : %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Impossible d’ouvrir le fichier de licence demandÃĐ "%1" : %2</translation> </message> <message> <source>Error</source> <translation>Erreur</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Erreur : l’opÃĐration %1 n’existe pas.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Impossible de rÃĐsoudre isDefault dans %1</translation> </message> <message> <source>Update Info: </source> <translation>Informations de mise à jour : </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Le composant est destinÃĐ Ã  Être installÃĐ.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Le composant est destinÃĐ Ã  Être dÃĐsinstallÃĐ.</translation> </message> <message> <source>Component is installed.</source> <translation>Le composant est installÃĐ.</translation> </message> <message> <source>Component is not installed.</source> <translation>Le composant n’est pas installÃĐ.</translation> </message> <message> <source>Component Name</source> <translation>Nom du composant</translation> </message> <message> <source>Action</source> <translation>OpÃĐration</translation> </message> <message> <source>Installed Version</source> <translation>Version installÃĐe</translation> </message> <message> <source>New Version</source> <translation>Nouvelle version</translation> </message> <message> <source>Release Date</source> <translation>Date de publication</translation> </message> <message> <source>Size</source> <translation>Taille</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>Par dÃĐf&aut</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&RÃĐinitialiser</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&SÃĐlectionner tout</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>&Tout dÃĐsÃĐlectionner</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Pour installer un nouveau rÃĐfÃĐrentiel compressÃĐ, parcourez les rÃĐfÃĐrentiels sur votre ordinateur</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&Parcourir les fichiers QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Ce composant occupera environ %1 sur votre disque dur.</translation> </message> <message> <source>Open File</source> <translation>Ouvrir un fichier</translation> </message> <message> <source>Select Components</source> <translation>SÃĐlectionner des composants</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>SÃĐlectionnez les composants que vous souhaitez mettre à jour.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>SÃĐlectionnez les composants que vous souhaitez installer.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>SÃĐlectionnez les composants que vous souhaitez dÃĐsinstaller.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>SÃĐlectionnez les composants à installer. DÃĐsÃĐlectionnez les composants installÃĐs pour les dÃĐsinstaller. Les composants dÃĐjà installÃĐs ne seront pas mis à jour.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><Nom de clÃĐ du programme d’installation à enregistrer> <exÃĐcutable> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L’objet du programme d’installation requis dans l’opÃĐration %1 est vide.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Impossible d’enregistrer la sortie de "%1" dans une valeur clÃĐ du programme d’installation vide.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Le fichier "%1" n’existe pas ou n’est pas un objet binaire exÃĐcutable.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>L’exÃĐcution de "%1" a entraÃŪnÃĐ un blocage.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><source> <cible> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Argument non valide dans %1 : le troisiÃĻme argument doit Être forceOverwrite, s’il est spÃĐcifiÃĐ.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Argument non valide dans %1 : le rÃĐpertoire "%2" n’est pas valide.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Échec du remplacement de "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossible de copier le fichier "%1" vers "%2" : %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossible de supprimer le fichier "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Total des ÃĐlÃĐments de la tÃĒche non valide.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>L’ÃĐcriture dans le fichier "%1" a ÃĐchouÃĐ : %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossible de sauvegarder le fichier "%1" : %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Échec du remplacement du fichier "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Impossible d’ÃĐcrire l’entrÃĐe bureautique dans "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Impossible de crÃĐer le lien depuis "%1" vers "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Impossible de supprimer le lien depuis "%1" vers "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Impossible de dÃĐfinir les autorisations du fichier "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossible de supprimer le fichier "%1" : %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Impossible de dÃĐplacer le fichier "%1" vers "%2" : %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Le programme d’installation de "%1" doit Être hors connexion.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Impossible de lire le fichier "%1" : %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Impossible de crÃĐer le rÃĐpertoire cible : "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Exception inconnue dÃĐtectÃĐe : %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Suppression du fichier "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossible de supprimer le fichier "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossible de supprimer le rÃĐpertoire "%1" : %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><cible> <emplacement du lien> [arguments cibles] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1" : %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Échec du remplacement de "%1" : %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Impossible de crÃĐer le lien "%1" : %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>AbandonnÃĐ</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Le tÃĐlÃĐchargement de la signature de hachage a ÃĐchouÃĐ.</translation> </message> <message> <source>Download Error</source> <translation>Erreur de tÃĐlÃĐchargement</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>La vÃĐrification du hachage lors du tÃĐlÃĐchargement a ÃĐchouÃĐ. Cette erreur est temporaire, rÃĐessayez.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>Impossible de vÃĐrifier le hachage</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Impossible de tÃĐlÃĐcharger l’archive %1 : %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Impossible de rÃĐcupÃĐrer les archives : %1 Erreur lors du chargement de %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>TÃĐlÃĐchargement de l’archive "%1" pour le composant %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Structure %1 non prise en charge (URL : %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Composant introuvable pour %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>Le fichier cible "%1" existe dÃĐjà, mais il ne s’agit pas d’un fichier.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Fichier "%1" non ouvert en ÃĐcriture : %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>L’ÃĐcriture dans le fichier "%1" a ÃĐchouÃĐ : %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Boucle de redirection dÃĐtectÃĐe pour "%1".</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Non-concordance des sommes de contrÃīle dÃĐtectÃĐe pour "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Erreur rÃĐseau lors du tÃĐlÃĐchargement de '%1' : %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Erreur rÃĐseau inconnue lors du tÃĐlÃĐchargement de '%1'.</translation> </message> <message> <source>Network transfers canceled.</source> <translation>Transferts rÃĐseau annulÃĐs.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>Les fonctions d’interruption et de reprise ne sont pas prises en charge par les transferts rÃĐseau.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>URL source non valide "%1" : %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Impossible de dÃĐmarrer le mode dÃĐtachÃĐ : "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Impossible de dÃĐmarrer : "%1" : %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Blocage du programme : "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>L’exÃĐcution a ÃĐchouÃĐ (code de sortie inattendu : %1) : "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Impossible d’ouvrir l’archive "%1" en lecture : %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Erreur lors de l’extraction de l’archive "%1" : %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Exception inconnue dÃĐtectÃĐe lors de l’extraction de "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Impossible d’obtenir le moteur principal du gestionnaire de paquetages.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Ce processus doit Être arrÊtÃĐ avant de poursuivre : %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Ces processus doivent Être arrÊtÃĐs avant de poursuivre : %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 sur %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 reçu.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sec)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n jour(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n heure(s), </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minute(s)</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n seconde(s)</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restants.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - temps restant inconnu.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>ExÃĐcution de l’assistant de %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Cliquez sur %1 pour quitter l’assistant de %2.</translation> </message> <message> <source>Restart</source> <translation>RedÃĐmarrer</translation> </message> <message> <source>Run %1 now.</source> <translation>ExÃĐcutez %1 maintenant.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>L’assistant de %1 a ÃĐchouÃĐ.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Les paramÃĻtres ne sont pas accessibles en ÃĐcriture.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Échec de l’ÃĐcriture des paramÃĻtres.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><chemin de la source> [prÃĐfixe fournisseur]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Argument non valide : le rÃĐpertoire source doit Être renseignÃĐ.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossible de sauvegarder le fichier "%1" : %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Échec du remplacement de "%1" : %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Échec de la copie du fichier "%1" : %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossible de crÃĐer le rÃĐpertoire "%1" : %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Installation - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Bienvenue dans l’assistant d’installation de %1</translation> </message> <message> <source>&Add or remove components</source> <translation>Ajouter ou supprimer des composants</translation> </message> <message> <source>&Update components</source> <translation>Mettre à jour des composants</translation> </message> <message> <source>&Remove all components</source> <translation>Supprimer tous les composants</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Extraction d’informations à partir des sources d’installation distantes...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Au moins un rÃĐfÃĐrentiel valide et activÃĐ est requis pour que cette action rÃĐussisse.</translation> </message> <message> <source>No updates available.</source> <translation>Aucune mise à jour disponible.</translation> </message> <message> <source> Only local package management available.</source> <translation> Seule la gestion des paquetages locaux est disponible.</translation> </message> <message> <source>&Quit</source> <translation>Quitter</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Contrat de licence</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Lisez le contrat de licence suivant. Vous devez accepter les termes contenus dans ce contrat avant de poursuivre l’installation.</translation> </message> <message> <source>I accept the license.</source> <translation>J’accepte la licence.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Je n’accepte pas la licence.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Lisez les contrats de licence suivants. Vous devez accepter les termes contenus dans ces contrats avant de poursuivre l’installation.</translation> </message> <message> <source>I accept the licenses.</source> <translation>J’accepte les licences.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Je n’accepte pas les licences.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Aucun fichier de licence à copier.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L’objet du programme d’installation requis dans l’opÃĐration %1 est vide.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Impossible d’ÃĐcrire le fichier de licence "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Aucun fichier de licence à supprimer.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Moteur principal du gestionnaire de paquetages manquant.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>PrÃĐparation du tÃĐlÃĐchargement des mÃĐtadonnÃĐes...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>DÃĐcompression des rÃĐfÃĐrentiels compressÃĐs. Cette opÃĐration peut prendre du temps...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Le tÃĐlÃĐchargement des mÃĐtadonnÃĐes a ÃĐtÃĐ annulÃĐ.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Exception inconnue au cours de l’extraction.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Identifiants de connexion proxy manquants.</translation> </message> <message> <source>Authentication failed.</source> <translation>L’authentification a ÃĐchouÃĐ.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Exception inconnue au cours du tÃĐlÃĐchargement.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Échec de la rÃĐcupÃĐration des rÃĐfÃĐrentiels.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Extraction des mÃĐtadonnÃĐes...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Extraction des mÃĐtadonnÃĐes depuis le rÃĐfÃĐrentiel distant... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Extraction des mÃĐtadonnÃĐes depuis le rÃĐfÃĐrentiel distant... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Erreur lors de l’extraction de l’archive "%1" : %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Exception inconnue dÃĐtectÃĐe lors de l’extraction de l’archive "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Erreur d’ÃĐcriture de l’outil de maintenance</translation> </message> <message> <source> Downloading packages...</source> <translation> TÃĐlÃĐchargement des paquetages...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Installation annulÃĐe par l’utilisateur.</translation> </message> <message> <source>All downloads finished.</source> <translation>Tous les tÃĐlÃĐchargements sont terminÃĐs.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Annulation du programme d’installation</translation> </message> <message> <source>Authentication Error</source> <translation>Erreur d’authentification</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Certains composants n’ont pas pu Être supprimÃĐs entiÃĻrement car les droits d’administrateur n’ont pas pu Être acquis : %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Erreur inconnue.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Certains composants n’ont pas pu Être supprimÃĐs entiÃĻrement en raison d’une erreur inconnue.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>L’application ne s’exÃĐcute pas en mode de gestionnaire de paquetages.</translation> </message> <message> <source>No installed packages found.</source> <translation>Aucun paquetage installÃĐ n’a ÃĐtÃĐ trouvÃĐ.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>L’application s’exÃĐcute en mode de dÃĐsinstallation.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Une mise à jour importante est disponible. ExÃĐcutez d’abord le programme de mise à jour.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Impossible de rÃĐsoudre toutes les dÃĐpendances.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Les composants vont Être supprimÃĐs.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Erreur lors de l’ÃĐlÃĐvation des droits d’accÃĻs.</translation> </message> <message> <source>Error</source> <translation>Erreur</translation> </message> <message> <source>invalid</source> <translation>non valide</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>DÃĐpendances non rÃĐsolues</translation> </message> <message> <source>Error</source> <translation>Erreur</translation> </message> <message> <source>Access error</source> <translation>Erreur d'accÃĻs</translation> </message> <message> <source>Format error</source> <translation>Erreur de format</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Impossible d’ÃĐcrire la configuration du programme d’installation dans %1 : %2</translation> </message> <message> <source>Stop Processes</source> <translation>ArrÊter les processus</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Ces processus doivent Être arrÊtÃĐs pour poursuivre : %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Installation annulÃĐe par l’utilisateur</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Écriture de l’outil de maintenance.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Échec de la recherche dans le fichier %1 : %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>L’outil de maintenance n’est pas un groupe</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Impossible de supprimer le fichier de donnÃĐes "%1" : %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Impossible d’ÃĐcrire les donnÃĐes de l’outil de maintenance dans %1 : %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Impossible d’ÃĐcrire l’outil de maintenance dans %1 : %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Impossible d’ÃĐcrire les donnÃĐes binaires de l’outil de maintenance dans %1 : %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>Variable 'TargetDir' non dÃĐfinie.</translation> </message> <message> <source>Preparing the installation...</source> <translation>PrÃĐparation de l’installation...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Installation impossible à partir d’une localisation de rÃĐseau</translation> </message> <message> <source>Creating local repository</source> <translation>CrÃĐation d’un rÃĐfÃĐrentiel local</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>CrÃĐation d’un outil de maintenance</translation> </message> <message> <source> Installation finished!</source> <translation> Installation terminÃĐe !</translation> </message> <message> <source> Installation aborted!</source> <translation> Installation annulÃĐe !</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Impossible d’exÃĐcuter cette opÃĐration à partir d’une localisation de rÃĐseau</translation> </message> <message> <source>Removing deselected components...</source> <translation>Suppression des composants dÃĐsÃĐlectionnÃĐs...</translation> </message> <message> <source> Update finished!</source> <translation> Mise à jour terminÃĐe !</translation> </message> <message> <source> Update aborted!</source> <translation> Mise à jour annulÃĐe !</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>La dÃĐsinstallation a rÃĐussi.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>DÃĐsinstallation abandonnÃĐe.</translation> </message> <message> <source> Installing component %1</source> <translation> Installation du composant %1</translation> </message> <message> <source>Installer Error</source> <translation>Erreur du programme d’installation</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Une erreur s’est produite au cours de l’installation (%1) : %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Impossible de prÃĐparer la dÃĐsinstallation</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Impossible de dÃĐmarrer la dÃĐsinstallation</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Une erreur s’est produite au cours de la dÃĐsinstallation : %1</translation> </message> <message> <source>Unknown error</source> <translation>Erreur inconnue</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Impossible d’extraire l’arborescence distante %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Échec de la lecture des paquetages depuis %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Impossible d’extraire les mÃĐtadonnÃĐes : %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Impossible d’ajouter des informations sur la source de mise à jour temporaire.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Informations introuvables sur la source de mise à jour.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Cycle de dÃĐpendance entre les composants "%1" et "%2" dÃĐtectÃĐ.</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>Installation de %1</translation> </message> <message> <source>Maintain %1</source> <translation>GÃĐrer %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Voulez-vous annuler l’installation ?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Voulez-vous annuler la dÃĐsinstallation ?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Voulez-vous quitter le programme d’installation ?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Voulez-vous quitter le programme de dÃĐsinstallation ?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Voulez-vous quitter l’application de maintenance ?</translation> </message> <message> <source>%1 Question</source> <translation>Question %1</translation> </message> <message> <source>Settings</source> <translation>RÃĐglages</translation> </message> <message> <source>Error</source> <translation>Erreur</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Installation impossible à partir d’une localisation de rÃĐseau. Copiez le programme d’installation sur un disque local</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&Afficher les dÃĐtails</translation> </message> <message> <source>&Hide Details</source> <translation>&Masquer les dÃĐtails</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>DÃĐs&installer</translation> </message> <message> <source>Uninstalling %1</source> <translation>DÃĐsinstallation de %1</translation> </message> <message> <source>&Update</source> <translation>&Mettre à jour</translation> </message> <message> <source>Updating components of %1</source> <translation>Mise à jour des composants de %1</translation> </message> <message> <source>&Install</source> <translation>&Installer</translation> </message> <message> <source>Installing %1</source> <translation>Installation de %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>BoÃŪte de dialogue</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>Le proxy %1 requiert un nom d’utilisateur et un mot de passe.</translation> </message> <message> <source>Username:</source> <translation>Nom d'utilisateur :</translation> </message> <message> <source>Username</source> <translation>Nom d'utilisateur</translation> </message> <message> <source>Password:</source> <translation>Mot de passe :</translation> </message> <message> <source>Password</source> <translation>Mot de passe</translation> </message> <message> <source>Proxy Credentials</source> <translation>Informations d'authentification proxy</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>DÃĐs&installer</translation> </message> <message> <source>Ready to Uninstall</source> <translation>PrÊt pour la dÃĐsinstallation</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>Le programme d’installation est maintenant prÊt à supprimer %1 de votre ordinateur.<br><font color="red">Le rÃĐpertoire du programme %2 va Être entiÃĻrement supprimÃĐ</font>, y compris tout son contenu !</translation> </message> <message> <source>U&pdate</source> <translation>M&ettre à jour</translation> </message> <message> <source>Ready to Update Packages</source> <translation>PrÊt à mettre à jour les paquetages</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>Le programme d’installation est maintenant prÊt à mettre à jour votre installation.</translation> </message> <message> <source>&Install</source> <translation>&Installer</translation> </message> <message> <source>Ready to Install</source> <translation>PrÊt pour l’installation</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>Le programme d’installation est maintenant prÊt à installer %1 sur votre ordinateur.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>L’espace disque est insuffisant pour stocker les fichiers temporaires et l’installation. %1 sont disponibles, alors qu’au moins %2 sont nÃĐcessaires.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>L’espace disque est insuffisant pour stocker tous les composants sÃĐlectionnÃĐs ! %1 sont disponibles, alors qu’au moins %2 sont nÃĐcessaires.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>L’espace disque est insuffisant pour stocker les fichiers temporaires ! %1 sont disponibles, alors qu’au moins %2 sont nÃĐcessaires.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Le volume sÃĐlectionnÃĐ pour l’installation semble avoir un espace suffisant, mais il restera ensuite moins de 1% de l’espace du volume. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Le volume sÃĐlectionnÃĐ pour l’installation semble avoir un espace suffisant, mais il restera ensuite moins de 100 Mo. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>L’installation va utiliser %1 de l’espace disque.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><extension> <commande> [description [contentType [icon]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>L’inscription des types de fichiers est uniquement prise en charge sur Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Inscrire le type de fichier : arguments non valides</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Impossible de lire toutes les donnÃĐes aprÃĻs l’envoi de la commande : %1. Octets attendus : %2, octets reçus : %3. Erreur : %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en lecture : %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossible d’ouvrir le fichier "%1" en ÃĐcriture : %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Impossible d’ouvrir la ressource %1 en lecture.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Échec de la lecture aprÃĻs %1 octets : %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Échec de l’ÃĐcriture aprÃĻs %1 octets : %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>ExÃĐcution de l’assistant d’installation de %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Ouvrir d’ouvrir le fichier de script dans %1 : %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Exception lors du chargement du script du composant "%1" : %2</translation> </message> <message> <source>Unknown error.</source> <translation>Erreur inconnue.</translation> </message> <message> <source>on line number: </source> <translation>sur le numÃĐro de ligne : </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>L’objet du programme d’installation requis dans l’opÃĐration %1 est vide.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>RedÃĐmarrage automatique : valide uniquement en mode de mise à jour ou de gestionnaire de paquetages.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>RedÃĐmarrage automatique : arguments non valides</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Le serveur doit Être authentifiÃĐ</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Vous devez fournir un nom d’utilisateur et un mot de passe pour accÃĐder au site.</translation> </message> <message> <source>Username:</source> <translation>Nom d'utilisateur :</translation> </message> <message> <source>Password:</source> <translation>Mot de passe :</translation> </message> <message> <source>%1 at %2</source> <translation>%1 sur %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Argument(s) manquant(s) "%1", appel de %2 avec les arguments "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>L’argument de la mÃĐthode actuelle qui appelle "%1" avec les arguments "%2" n’est pas pris en charge. Utilisez la propriÃĐtÃĐ set, remove, add_array_value ou remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Aucun des arguments ne peut Être vide : source "%1", cible "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Impossible de dÃĐplacer le fichier de "%1" vers "%2" car le chemin cible existe et ne peut pas Être supprimÃĐ.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Impossible de dÃĐplacer le fichier "%1" vers "%2" : %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>DÃĐplacement du fichier "%1" vers "%2"</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Raccourcis du menu DÃĐmarrer</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>SÃĐlectionnez le menu DÃĐmarrer dans lequel crÃĐer les raccourcis du programme. Vous pouvez ÃĐgalement saisir un nom pour crÃĐer un nouveau rÃĐpertoire.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Dossier d’installation</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>SpÃĐcifiez le rÃĐpertoire dans lequel %1 va Être installÃĐ.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>P&arcourir...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Le rÃĐpertoire sÃĐlectionnÃĐ existe dÃĐjà et contient une installation. Choisissez une autre cible pour l’installation.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Vous avez sÃĐlectionnÃĐ un rÃĐpertoire existant et non vide pour l’installation. Notez qu’il va Être entiÃĻrement effacÃĐ lors de la dÃĐsinstallation de l’application. Il n’est pas conseillÃĐ d’effectuer l’installation dans ce rÃĐpertoire car elle risque d’ÃĐchouer. Souhaitez-vous continuer ?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Vous avez sÃĐlectionnÃĐ un fichier ou lien symbolique existant. Choisissez une autre cible pour l’installation.</translation> </message> <message> <source>Select Installation Folder</source> <translation>SÃĐlectionner le dossier d’installation</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>Le chemin d’installation ne peut pas Être vide. SpÃĐcifiez un rÃĐpertoire valide.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>Le chemin d’installation ne peut pas Être relatif. SpÃĐcifiez un chemin absolu.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>Le chemin d’accÃĻs ou le rÃĐpertoire d’installation contient des caractÃĻres autres qu’ASCII. Cette opÃĐration n’est actuellement pas prise en charge ! Choisissez un autre chemin d’accÃĻs ou rÃĐpertoire d’installation.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Comme le rÃĐpertoire d’installation est entiÃĻrement supprimÃĐ, l’installation de %1 est interdite.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>Le chemin d’accÃĻs que vous avez saisi est trop long. SpÃĐcifiez un chemin valide.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>Le chemin d’accÃĻs que vous avez saisi n’est pas valide. SpÃĐcifiez une cible valide.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>Le chemin d’accÃĻs que vous avez saisi n’est pas valide. SpÃĐcifiez un disque valide.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>Le chemin d’installation ne doit pas se terminer par '.'. SpÃĐcifiez un rÃĐpertoire valide.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>Le chemin d’installation ne doit pas contenir "%1". SpÃĐcifiez un rÃĐpertoire valide.</translation> </message> <message> <source>Warning</source> <translation>Avertissement</translation> </message> <message> <source>Error</source> <translation>Erreur</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Moteur principal du gestionnaire de paquetages manquant.</translation> </message> <message> <source>Empty repository URL.</source> <translation>URL du rÃĐfÃĐrentiel vide.</translation> </message> <message> <source>Download canceled.</source> <translation>TÃĐlÃĐchargement annulÃĐ.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Expiration lors du test du rÃĐfÃĐrentiel "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Impossible d’analyser Updates.xml : %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Impossible d’ouvrir Updates.xml en lecture : %1</translation> </message> <message> <source>Authentication failed.</source> <translation>L’authentification a ÃĐchouÃĐ.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Erreur inconnue lors du test du rÃĐfÃĐrentiel "%1".</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Autorisation requise</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Saisissez votre mot de passe pour autoriser sudo :</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Erreur d’acquisition des droits d’administrateur</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Impossible d’obtenir l’autorisation.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Impossible d’obtenir l’autorisation requise pour poursuivre l’installation. DÃĐmarrez le programme d’installation en tant qu’utilisateur dotÃĐ des droits appropriÃĐs. Ou acceptez l’ÃĐlÃĐvation des droits d’accÃĻs si un message vous y invite.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Impossible d’obtenir l’autorisation requise pour poursuivre l’installation. Annulez l’installation ou utilisez la solution de secours en exÃĐcutant %1 en tant qu’utilisateur dotÃĐ des droits appropriÃĐs, puis cliquez sur OK.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Impossible d’ouvrir la ressource %1 : %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Impossible d’ouvrir le fichier de paramÃĻtres %1 en lecture : %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>RÃĐglages</translation> </message> <message> <source>Network</source> <translation>RÃĐseau</translation> </message> <message> <source>No proxy</source> <translation>Aucun proxy</translation> </message> <message> <source>System proxy settings</source> <translation>ParamÃĻtres proxy du systÃĻme</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Configuration manuelle du proxy</translation> </message> <message> <source>HTTP proxy:</source> <translation>Proxy HTTP :</translation> </message> <message> <source>Port:</source> <translation>Port :</translation> </message> <message> <source>FTP proxy:</source> <translation>Proxy FTP :</translation> </message> <message> <source>Repositories</source> <translation>RÃĐfÃĐrentiels</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Ajoutez un nom d’utilisateur et un mot de passe pour l’authentification si cela est nÃĐcessaire.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Utiliser des rÃĐfÃĐrentiels temporaires uniquement</translation> </message> <message> <source>Add</source> <translation>Ajouter</translation> </message> <message> <source>Remove</source> <translation>Retirer</translation> </message> <message> <source>Test</source> <translation>Tester</translation> </message> <message> <source>Show Passwords</source> <translation>Afficher les mots de passe</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Cochez cette case pour utiliser le rÃĐfÃĐrentiel au cours de l’extraction.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Ajoutez le nom d’utilisateur à authentifier sur le serveur.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Ajoutez le mot de passe à authentifier sur le serveur.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>L’URL des serveurs qui contient un rÃĐfÃĐrentiel valide.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Une erreur s’est produite pendant le test du rÃĐfÃĐrentiel.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Le test du rÃĐfÃĐrentiel a rÃĐussi.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Voulez-vous dÃĐsactiver le rÃĐfÃĐrentiel ?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Voulez-vous activer le rÃĐfÃĐrentiel ?</translation> </message> <message> <source>Hide Passwords</source> <translation>Masquer les mots de passe</translation> </message> <message> <source>Use</source> <translation>Utilisation</translation> </message> <message> <source>Username</source> <translation>Nom d'utilisateur</translation> </message> <message> <source>Password</source> <translation>Mot de passe</translation> </message> <message> <source>Repository</source> <translation>RÃĐfÃĐrentiel</translation> </message> <message> <source>Default repositories</source> <translation>RÃĐfÃĐrentiels par dÃĐfaut</translation> </message> <message> <source>Temporary repositories</source> <translation>RÃĐfÃĐrentiels temporaires</translation> </message> <message> <source>User defined repositories</source> <translation>RÃĐfÃĐrentiels dÃĐfinis par l’utilisateur</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>Impossible d’ÃĐcrire dans le chemin de registre %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>Le chemin de registre %1 n’est pas accessible en ÃĐcriture.</translation> </message> <message> <source>exactly %1</source> <translation>exactement %1</translation> </message> <message> <source>at least %1</source> <translation>au moins %1</translation> </message> <message> <source>not more than %1</source> <translation>pas plus de %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 ou %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 vers %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Arguments non valides dans %1 : %n arguments fournis, %2 arguments attendus.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Arguments non valides dans %1 : %n arguments fournis, %2 arguments attendus dans le formulaire : %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Le changement de nom du fichier "%1" en "%2" a ÃĐchouÃĐ : %3</translation> </message> </context> </TS> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_hr.ts�����������������������������������������0100777�0000000�0000000�00000303676�13761647206�021036� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="hr"> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation type="unfinished">Dijalog</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>PosluÅūitelj %1 zahtijeva korisničko ime i lozinku.</translation> </message> <message> <source>Username:</source> <translation>Korisničko ime:</translation> </message> <message> <source>Username</source> <translation>Korisničko ime</translation> </message> <message> <source>Password:</source> <translation>Lozinka:</translation> </message> <message> <source>Password</source> <translation>Lozinka</translation> </message> <message> <source>Proxy Credentials</source> <translation>Podaci za prijavu na posluÅūitelj</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>PosluÅūitelj zahtijeva autentifikaciju</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Za pristupanje ovoj stranici, potrebno je unijeti korisničko ime i lozinku.</translation> </message> <message> <source>Username:</source> <translation>Korisničko ime:</translation> </message> <message> <source>Password:</source> <translation>Lozinka:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 na %2</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Potrebna je http autentifikacija</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Za pristupanje ovoj stranici, potrebno je unijeti korisničko ime i lozinku.</translation> </message> <message> <source>Username:</source> <translation>Korisničko ime:</translation> </message> <message> <source>Password:</source> <translation>Lozinka:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 na %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Postavke</translation> </message> <message> <source>Network</source> <translation>MreÅūa</translation> </message> <message> <source>No proxy</source> <translation>Bez posluÅūitelja</translation> </message> <message> <source>System proxy settings</source> <translation>Sustavske postavke posluÅūitelja</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Ručna konfiguracija posluÅūitelja</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP posluÅūitelj:</translation> </message> <message> <source>Port:</source> <translation>Priključak:</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP posluÅūitelj:</translation> </message> <message> <source>Repositories</source> <translation>SpremiÅĄta</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Ako je potrebna autentifikacija, unesi korisničko ime i lozinku.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Koristi samo privremena spremiÅĄta</translation> </message> <message> <source>Add</source> <translation>Dodaj</translation> </message> <message> <source>Remove</source> <translation>Ukloni</translation> </message> <message> <source>Test</source> <translation>Testiraj</translation> </message> <message> <source>Show Passwords</source> <translation>PrikaÅūi lozinke</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Aktiviraj ovo, za koriÅĄtenje spremiÅĄta za vrijeme dohvaćanja.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Dodaj korisničko ime za autentifikaciju na posluÅūitelju.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Dodaj lozinku za autentifikaciju na posluÅūitelju.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>URL posluÅūitelja koji sadrÅūi valjano spremiÅĄte.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>DoÅĄlo je do greÅĄke prilikom testiranja ovog spremiÅĄta.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>SpremiÅĄte je uspjeÅĄno testirano.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Å―eliÅĄ li aktivirati ovo spremiÅĄte?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Å―eliÅĄ li deaktivirati ovo spremiÅĄte?</translation> </message> <message> <source>Hide Passwords</source> <translation>Sakrij lozinke</translation> </message> <message> <source>Use</source> <translation>Koristi</translation> </message> <message> <source>Username</source> <translation>Korisničko ime</translation> </message> <message> <source>Password</source> <translation>Lozinka</translation> </message> <message> <source>Repository</source> <translation>SpremiÅĄte</translation> </message> <message> <source>Default repositories</source> <translation>Standardna spremiÅĄta</translation> </message> <message> <source>Temporary repositories</source> <translation>Privremena spremiÅĄta</translation> </message> <message> <source>User defined repositories</source> <translation>Korisnička spremiÅĄta</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Potrebna je autorizacija</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Dodaj tvoju lozinku za autorizaciju koriÅĄtenja sudo naredba:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>GreÅĄka prilikom preuzimanja administratorskih prava</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Marker nije nađen, prekid nakon %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Učitavanje je prekinuto nakon %1 bajta: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Kopija nije uspjela: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Zapisivanje je prekinuto nakon %1 bajta: %2</translation> </message> <message> <source>bytes</source> <translation>bajta</translation> </message> <message> <source>KiB</source> <translation>KiB</translation> </message> <message> <source>MiB</source> <translation>MiB</translation> </message> <message> <source>GiB</source> <translation>GiB</translation> </message> <message> <source>TiB</source> <translation>TiB</translation> </message> <message> <source>PiB</source> <translation>PiB</translation> </message> <message> <source>EiB</source> <translation>EiB</translation> </message> <message> <source>ZiB</source> <translation>ZiB</translation> </message> <message> <source>YiB</source> <translation>YiB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nije moguće ukloniti datoteku "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nije moguće ukloniti mapu "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nije moguće stvoriti mapu "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Nije moguće kopirati datoteku iz "%1" u "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Nije moguće premjestiti datoteku iz "%1" u "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nije moguće stvoriti mapu "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Nije moguće otvoriti privremenu datoteku: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Nije moguće otvoriti privremenu datoteku za predloÅūak %1: %2</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Određeni modul nije nađen.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Nije moguće traÅūiti do %1 za učitavanje ugrađenog broja meta podataka.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Nije moguće traÅūiti do %1 za učitavanje segmenta zbirke resursa.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Neočekivana nesuglasnost meta resursa. Pročitano %1, očekivano: %2.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Nije moguće traÅūiti do %1 za učitavanje podataka operacije.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Nije moguće traÅūiti do %1 za učitavanje bloka zbiraka resursa.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Nije moguće otvoriti meta resurs %1.</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Nije moguće otvoriti resurs %1 za učitavanje.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Učitavanje je prekinuto nakon %1 bajta: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Zapisivanje je prekinuto nakon %1 bajta: %2</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Nije moguće otvoriti resurs %1: %2</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Komponente nemaju podređenih u modusu aktualiziranja.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Nije moguće otvoriti traÅūenu UI datoteku "%1": %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Nije moguće učitati traÅūenu UI datoteku "%1": %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Nije moguće otvoriti traÅūenu licencnu datoteku "%1": %2</translation> </message> <message> <source>Error</source> <translation>GreÅĄka</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>GreÅĄka: Operacija %1 ne postoji.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Nije moguće razrijeÅĄiti isDefault u %1</translation> </message> <message> <source>Update Info: </source> <translation>Podaci nadogradnje: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Komponenta je označena za instaliranje.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Komponenta je označena za deinstaliranje.</translation> </message> <message> <source>Component is installed.</source> <translation>Komponenta je instalirana.</translation> </message> <message> <source>Component is not installed.</source> <translation>Komponenta je deinstalirana.</translation> </message> <message> <source>Component Name</source> <translation>Ime komponente</translation> </message> <message> <source>Action</source> <translation>Akcija</translation> </message> <message> <source>Installed Version</source> <translation>Instalirana verzija</translation> </message> <message> <source>New Version</source> <translation>Nova verzija</translation> </message> <message> <source>Release Date</source> <translation>Datum objave</translation> </message> <message> <source>Size</source> <translation>Veličina</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><ime ključa programa za instaliranje koje se sprema> <izvrÅĄne stavke> [argument1] [argument2] [â€Ķ]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Potreban instalacijski objekt u operaciji %1 je prazan.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Izlaz "%1" nije moguće spremiti u praznu vrijednost ključa programa za instaliranje.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Datoteka "%1" ne postoji ili nije izvrÅĄna binarna datoteka.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>Pokretanje "%1" je prouzročilo uruÅĄavanje.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><izvor> <odrediÅĄte> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Nevaljani argument u %1. Treći argument mora biti forceOverwrtie, ako je određeno.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Nevaljani argument u %1. Mapa "%2" nije valjana.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nije moguće stvoriti mapu "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>NeuspjeÅĄno prepisivanje "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nije moguće kopirati datoteku "%1" u "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nije moguće ukloniti datoteku "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Nevaljani broj zadataka.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Zapisivanje u datoteku "%1" nije uspjelo: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>NeuspjeÅĄno prepisivanje datoteke "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Nije moguće zapisati unos s radne povrÅĄine u "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Nije moguće stvoriti vezu između "%1" i "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Nije moguće ukloniti vezu između "%1" i "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Nije moguće postaviti korisnička prava za datoteku "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nije moguće ukloniti datoteku "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Nije moguće premjestiti datoteku iz "%1" u "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Instalacijski program na "%1" mora biti bezmreÅūni.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Nije moguće čitati datoteku "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Nije moguće stvoriti odrediÅĄnu mapu: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Nepoznata iznimka: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Uklanjanje datoteke "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nije moguće ukloniti datoteku "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nije moguće ukloniti mapu "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><odrediÅĄte> <mjesto poveznice> [odrediÅĄni argumenti] ["radnaMapa=..."] ["StazaIkone=..."] ["IdIkone=..."] ["opis=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nije moguće stvoriti mapu "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>NeuspjeÅĄno prepisivanje datoteke "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Nije moguće stvoriti poveznicu "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Prekinuto</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>NeuspjeÅĄno preuzimanje hash signature.</translation> </message> <message> <source>Download Error</source> <translation>GreÅĄka u preuzimanju</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Hash provjera prilikom preuzimanja nije uspjela. Ovo je privremena greÅĄka, pokuÅĄaj ponovo.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>Nije moguće provjeriti Hash</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Nije moguće preuzeti arhivu %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Nije moguće dohvatiti arhivu: %1 GreÅĄka prilikom učitavanja %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Preuzimanje arhive "%1" za komponentu %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>NepodrÅūana shema %1 (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Nije moguće naći komponentu za %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>OdrediÅĄna datoteka "%1" već postoji, međutim nije datoteka.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Zapisivanje u datoteku "%1" nije uspjelo: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Ustanovljena je petlja preusmjeravanja za "%1".</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Ustanovljena je neusklađenost kontrolnog zbroja za "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>MreÅūna greÅĄka prilikom preuzimanja '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Nepoznata mreÅūna greÅĄka prilikom preuzimanja "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>MreÅūni prijenosi su prekinuti.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>MreÅūni prijenosi ne podrÅūavaju zaustavljanje i ponovo pokretanje.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Nevaljani izvorni URL "%1": %2</translation> </message> </context> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 na %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>PosluÅūitelj zahtijeva autentifikaciju.</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Nije moguće započeti odvojeno: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Nije moguće započeti: "%1"; %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Program se uruÅĄio: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Neuspjelo izvrÅĄavanje (neočekivan kȏd: %1): "%2"</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>Nije moguće pisati u registarsku stazu %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>Nije moguće pisati u registarsku stazu %1.</translation> </message> <message> <source>exactly %1</source> <translation>točno %1</translation> </message> <message> <source>at least %1</source> <translation>barem %1</translation> </message> <message> <source>not more than %1</source> <translation>ne viÅĄe od %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 ili %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 do %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2.</numerusform> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2.</numerusform> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2 u obliku: %3.</numerusform> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2 u obliku: %3.</numerusform> <numerusform>Nevaljani argumenti u %1: zadanih argumenata: %n, očekivanih argumenata: %2 u obliku: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Neuspjelo preimenovanje datoteke "%1" u "%2": %3</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation</name> <message> <source>Extracting "%1"</source> <translation>Raspakiravanje "%1"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Nije moguće otvoriti arhivu "%1" za učitavanje: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>GreÅĄka prilikom raspakiravanja arhive "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Nepoznata iznimka prilikom raspakiravanja "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Nije moguće dobiti osnovni upravljač paketa.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Ovaj proces treba zaustaviti prije nastavljanja: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Ove procese treba zaustaviti prije nastavljanja: %1</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Nije moguće pisati postavke.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Neuspjelo zapisivanje u postavke.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Komponente su dodane kao automatske ovisnosti:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Komponente su dodane kao ovisnosti za "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Komponente koje imaju razrjeÅĄene ovisnosti:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Odabrane komponente bez ovisnosti:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Otkrivena je rekurzija, komponenta "%1" je već dodana s razlogom: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>Nije moguće naći nedostajuću ovisnost "%1" za "%2".</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><izvorna staza> [vendor prefix]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Nevaljani argument: izvorna mapa ne smije biti prazna.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>NeuspjeÅĄno prepisivanje datoteke "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>NeuspjeÅĄno kopiranje datoteke "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nije moguće stvoriti mapu "%1": %2</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>interni kȏd: %1</translation> </message> <message> <source>not enough memory</source> <translation>nedovoljno memorije</translation> </message> <message> <source>Error: %1</source> <translation>GreÅĄka: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Nije moguće pronaći osobinu %1 za element %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>Osobina %1 za element %2 nije vrste VT_FILETIME, već %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Nije moguće pretvoriti UTC vrijeme datoteke u vrijeme sustava.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Nije moguće učitati codecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Nije moguće otvoriti arhiv "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Nije moguće pronaći broj elemenata u arhivu.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Nije moguće pronaći stazu elementa "%1" u arhivu.</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Nepoznata iznimka (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Nije moguće stvoriti privremenu datoteku: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>NepodrÅūana vrsta arhiva.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Nije moguće stvoriti arhiv "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Nije moguće stvoriti arhiv "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>Nije moguće ukloniti stari arhiv "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>Nije moguće preimenovati privremenu datoteku "%1" u "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Nepoznata iznimka (%1)</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>Staza "%1" postoji, međutim nije mapa.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nije moguće stvoriti mapu "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Nije moguće pronaći stazu elementa "%1" u arhivu.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Nije moguće ukloniti postojeći symlink %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Nije moguće stvoriti symlink na "%1". Jedan drugi već postoji.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Nije moguće čitati symlink odrediÅĄte iz datoteke "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Nije moguće stvoriti symlink na %1: %2</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Nema licencnih datoteka za kopiranje.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Potreban instalacijski objekt u operaciji %1 je prazan.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Nije moguće zapisati licencnu datoteku "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Nema licencnih datoteka za brisanje.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Nedostaje osnovni uređaj upravljača paketa.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Pripremanje preuzimanja meta informacija â€Ķ</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Raspakiravanje komprimiranih spremiÅĄta. MoÅūe poneÅĄto potrajati â€Ķ</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Prekinuto je preuzimanje meta podataka.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Nepoznata iznimka prilikom raspakiravanja.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Nedostaju podaci za prijavu na posluÅūitelj.</translation> </message> <message> <source>Authentication failed.</source> <translation>Neuspjela autentifikacija.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Nepoznata iznimka prilikom preuzimanja.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>GreÅĄka u dohvaćanju spremiÅĄta.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Raspakiravanje meta informacija â€Ķ</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Dohvaćanje meta informacija s udaljenih spremiÅĄta â€Ķ %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Dohvaćanje meta informacija s udaljenih spremiÅĄta â€Ķ </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>GreÅĄka prilikom raspakiravanja arhive "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Nepoznata iznimka prilikom raspakiravanja "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 od %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 – primljeno.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dan, </numerusform> <numerusform>%n dana, </numerusform> <numerusform>%n dana, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n sat, </numerusform> <numerusform>%n sata, </numerusform> <numerusform>%n sati, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuta</numerusform> <numerusform>%n minute</numerusform> <numerusform>%n minuta</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n sekunda</numerusform> <numerusform>%n sekunde</numerusform> <numerusform>%n sekundi</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> – preostaje %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> – nepoznato preostalo vrijeme.</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>GreÅĄka prilikom pisanja u alat za odrÅūavanje</translation> </message> <message> <source> Downloading packages...</source> <translation> Preuzimanje paketa â€Ķ</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Korisnik je zaustavio instaliranje.</translation> </message> <message> <source>All downloads finished.</source> <translation>Sva preuzimanja su dovrÅĄena.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Program za instaliranje se prekida</translation> </message> <message> <source>Authentication Error</source> <translation>GreÅĄka u autentifikaciji</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Neke komponente nije moguće u potpunosti ukloniti, jer administrativna prava nisu dostupna: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Nepoznata greÅĄka.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Neke komponente nije moguće u potpunosti ukloniti, jer se dogodila nepoznata greÅĄka.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>Aplikacija nije pokrenuta u modusu za upravljanjem paketima.</translation> </message> <message> <source>No installed packages found.</source> <translation>Nema instaliranih paketa.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>Aplikacija je pokrenuta u modusu za deinstaliranje.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Dostupna je vaÅūna nadogradnja. Najprije pokreni aktualiziranje nadogradnja.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Nije moguće razrijeÅĄiti sve ovisnosti.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Komponente se uklanjaju.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>GreÅĄka prilikom podizanja pristupnih prava.</translation> </message> <message> <source>Error</source> <translation>GreÅĄka</translation> </message> <message> <source>invalid</source> <translation>nevaljano</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>NerazrijeÅĄene ovisnosti</translation> </message> <message> <source>Error</source> <translation>GreÅĄka</translation> </message> <message> <source>Access error</source> <translation>GreÅĄka u pristupanju</translation> </message> <message> <source>Format error</source> <translation>GreÅĄka u formatu</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Nije moguće zapisati konfiguraciju programa za instaliranje u %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Zaustavi procese</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Ove procese treba zaustaviti prije nastavljanja: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Korisnik je zaustavio instaliranje</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Pisanje u alat za odrÅūavanje.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Neuspjelo traÅūenje u datoteci %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Alat za odrÅūavanje nije paket</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Nije moguće ukloniti datoteku podataka "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Nije moguće zapisati podatke alata za odrÅūavanje u %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Nije moguće zapisati alat za odrÅūavanje u "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Nije moguće zapisati binarne podatke alata za odrÅūavanje u %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>Varijabilna odrediÅĄna mapa (TargetDir) nije postavljena.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Pripremanje instalacije â€Ķ</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Nije moguće instalirati s mreÅūnog mjesta</translation> </message> <message> <source>Creating local repository</source> <translation>Stvaranje lokalnog spremiÅĄta</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Stvaranje alata za odrÅūavanje</translation> </message> <message> <source> Installation finished!</source> <translation> Instaliranje je dovrÅĄeno!</translation> </message> <message> <source> Installation aborted!</source> <translation> Instaliranje je prekinuto!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Nije moguće pokrenuti operaciju s mreÅūnog mjesta</translation> </message> <message> <source>Removing deselected components...</source> <translation>Uklanjanje neodabranih komponenata â€Ķ</translation> </message> <message> <source> Update finished!</source> <translation> Aktualiziranje je dovrÅĄeno!</translation> </message> <message> <source> Update aborted!</source> <translation> Aktualiziranje je prekinuto!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>Deinstaliranje je uspjeÅĄno dovrÅĄeno.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>Deinstaliranje je prekinuto.</translation> </message> <message> <source> Installing component %1</source> <translation> Instaliranje komponente %1</translation> </message> <message> <source>Installer Error</source> <translation>GreÅĄka u programu za instaliranje</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>GreÅĄka prilikom instalacijskog procesa (%1): %2</translation> </message> <message> <source>Done</source> <translation>Gotovo</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Nije moguće pripremiti deinstaliranje</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Nije moguće pokrenuti deinstaliranje</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>GreÅĄka prilikom deinstalacijskog procesa: %1</translation> </message> <message> <source>Unknown error</source> <translation>Nepoznata greÅĄka</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Nije moguće pronaći udaljeno stablo %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>GreÅĄka u čitanju paketa iz %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Nije moguće pronaći meta podatke: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Nije moguće dodati privremene podatke izvora nadogradnje.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Nije moguće naći bilo koje podatke izvora nadogradnje.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Ustanovljena je ovisnost između komponenata "%1" i "%2".</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>%1 Postavljanje</translation> </message> <message> <source>Maintain %1</source> <translation>ZadrÅūi %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Å―eliÅĄ li prekinuti proces instaliranja?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Å―eliÅĄ li prekinuti proces deinstaliranja?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Å―eliÅĄ li zatvoriti program za instaliranje?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Å―eliÅĄ li zatvoriti program za deinstaliranje?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Å―eliÅĄ li zatvoriti program za odrÅūavanje?</translation> </message> <message> <source>%1 Question</source> <translation>%1 Pitanje</translation> </message> <message> <source>Settings</source> <translation>Postavke</translation> </message> <message> <source>Error</source> <translation>GreÅĄka</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Nije moguće instalirati s mreÅūnog mjesta. Kopiraj program za instaliranje na računalo</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Postavljanje – %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>DobrodoÅĄli u čarobnjak postavaka za %1.</translation> </message> <message> <source>Add or remove components</source> <translation>Dodaj ili ukloni komponente</translation> </message> <message> <source>Update components</source> <translation>Aktualiziraj komponente</translation> </message> <message> <source>Remove all components</source> <translation>Ukloni sve komponente</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Dohvaćanje podataka s udaljenih izvornih instalacija â€Ķ</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Za uspjeh ove radnje, potrebno je barem jedno valjano i aktivirano spremiÅĄte.</translation> </message> <message> <source>No updates available.</source> <translation>Nema dostupnih nadogradnja.</translation> </message> <message> <source> Only local package management available.</source> <translation> Dostupno je samo lokalno upravljanje paketima.</translation> </message> <message> <source>Quit</source> <translation>Zatvori</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Licencni ugovor</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Pročitaj ugovor o licenci. Za nastavljanje s instaliranjem, moraÅĄ prihvatiti uvjete sadrÅūane u ovom ugovoru.</translation> </message> <message> <source>I accept the license.</source> <translation>Prihvaćam licencu.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Ne prihvaćam licencu.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Pročitaj ugovor o licenci. Za nastavljanje s instaliranjem, moraÅĄ prihvatiti uvjete sadrÅūane u ovom ugovoru.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Prihvaćam licencu.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Ne prihvaćam licencu.</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>St&andardne</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&Resetiraj</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>Odaberi &sve</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>O&dznači sav odabir</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Za instaliranje novog komprimiranog spremiÅĄta, pretraÅūi spremiÅĄta s tvog računala</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&PretraÅūi QBSP datoteke</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Ova će komponenta zauzeti otprilike %1 na tvom tvrdom disku.</translation> </message> <message> <source>Open File</source> <translation>Otvori datoteku</translation> </message> <message> <source>Select Components</source> <translation>Odaberi komponente</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Odaberi komponente koje ÅūeliÅĄ aktualizirati.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Odaberi komponente koje ÅūeliÅĄ instalirati.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Odaberi komponente koje ÅūeliÅĄ deinstalirati.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Odaberi komponente koje ÅūeliÅĄ instalirati. Odznači instalirane komponente, kako bi se deinstalirale. Već instalirane komponente neće biti aktualizirane.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Mapa za instaliranje</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Odredi mapu, gdje će se %1 instalirati.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>P&retraÅūi â€Ķ</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Odabrana mapa već postoji i sadrÅūi instalaciju. Odaberi drugo odrediÅĄte za instalaciju.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Odabran je postojeća, neprazna mapa za instalaciju. Imaj na umu da će biti potpuno izbrisana prilikom deinstaliranja ove aplikacije. Ne preporučujemo instalirati u ovu mapu, jer instaliranje moÅūda neće uspjeti. Å―eliÅĄ li nastaviti?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Odabrana je postojeća datoteka ili symlink, za instaliranje odaberi neko drugo odrediÅĄte.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Odaberi mapu za instaliranje</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>Staza instalacije ne smije biti prazna. Odredi valjanu mapu.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>Staza instalacije ne smije biti relativna. Odredi apsolutnu stazu.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>Staza ili mapa instalacije sadrÅūi ASCII znakove. Ovo trenutno nije podrÅūano! Odaberi neku drugu stazu ili mapu.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Budući da je mapa instalacije potpuno izbrisana, instaliranje u %1 je zabranjeno.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>UneÅĄena staza je predugačka. Unesi valjanu stazu.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>UneÅĄena staza nije valjana. Unesi valjanu stazu.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>UneÅĄena staza nije valjana. Unesi valjani disk.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>Staza instalacije ne smije zavrÅĄiti s točkom. Odredi valjanu mapu.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>Staza instalacije ne smije sadrÅūavati "%1". Odredi valjanu mapu.</translation> </message> <message> <source>Warning</source> <translation>Upozorenje</translation> </message> <message> <source>Error</source> <translation>GreÅĄka</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Prečaci za početni izbornik</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Odaberi početni izbornik u kojem ÅūeliÅĄ stvoriti prečace programa. Također moÅūeÅĄ unijeti ime, i izraditi novu mapu.</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>Dei&nstaliraj</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Spremno za deinstaliranje</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>Postavljanje je sad spremno za uklanjanje %1 s računala.<br><font color="red">Mapa programa %2 će se potpuno izbrisati</font>, uključujući sav sadrÅūaj mape!</translation> </message> <message> <source>U&pdate</source> <translation>&Aktualiziraj</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Spremno za aktualiziranje paketa</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>Postavljanje je sad spremno za aktualiziranje tvoje instalacije.</translation> </message> <message> <source>&Install</source> <translation>&Instaliraj</translation> </message> <message> <source>Ready to Install</source> <translation>Spremno za instaliranje</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>Postavljanje je sad spremno za instaliranje %1 na tvoje računalo.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>Nedovoljno mjesta na disku za spremanje privremenih datoteka i instalacije. Dostupno %1, barem potrebno %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>Nedovoljno mjesta na disku za spremanje odabranih komponenata. Dostupno %1, barem potrebno %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>Nedovoljno mjesta na disku za spremanje privremenih datoteka! Dostupno %1, barem potrebno %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Instalacija je moguća na odabranom mjestu, ali preostat će ti manje od 1 % memorije na disku. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Instalacija je moguća na odabranom mjestu, ali preostat će ti manje od 100 MB memorije na disku. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>Instalacija će zauzeti otprilike %1 na tvom tvrdom disku.</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>Dei&nstaliraj</translation> </message> <message> <source>Uninstalling %1</source> <translation>Deinstalira se %1</translation> </message> <message> <source>&Update</source> <translation>&Aktualiziraj</translation> </message> <message> <source>Updating components of %1</source> <translation>Aktualiziranje komponenata za %1</translation> </message> <message> <source>&Install</source> <translation>&Instaliraj</translation> </message> <message> <source>Installing %1</source> <translation>Instalira se %1</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>DovrÅĄavanje čarobnjaka %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Klikni %1 za izlaÅūenje iz čarobnjaka %2.</translation> </message> <message> <source>Restart</source> <translation>Pokreni ponovo</translation> </message> <message> <source>Run %1 now.</source> <translation>Sad pokreni %1.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>NeuspjeÅĄno pokretanje čarobnjaka %1.</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>DovrÅĄavanje čarobnjaka postavaka %1</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&PrikaÅūi detalje</translation> </message> <message> <source>&Hide Details</source> <translation>&Sakrij detalje</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source>Registering file types is only supported on Windows.</source> <translation>Registriranje vrsta datoteka je moguće samo na Windows sustavu.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Registriranje vrsta datoteka: Nevaljani argumenti</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Nije moguće dobiti autorizaciju.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Nije moguće dobiti autorizaciju, koja je potrebna za nastavljanje s instaliranjem. Pokreni program za posatvljanje, u modusu korisnika s odgovarajućim pravima. Ili dozvoli podizanje korisničkih prava.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Nije moguće dobiti autorizaciju, koja je potrebna za nastavljanje s instaliranjem. Prekini s instaliranjem ili koristi rezervno rjeÅĄenje, pokretanjem %1 u modusu korisnika s odgovarajućim pravima. Zatim klikni "U redu".</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Nakon slanja naredbi, nije moguće iÅĄÄitati sve podatke: %1. Očekivanih bajta: %2, primljenih bajta: %3. GreÅĄka: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Nije moguće otvoriti datoteku skripta u %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Iznimka prilikom učitavanja skripta komponente "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Nepoznata greÅĄka.</translation> </message> <message> <source>on line number: </source> <translation>u retku broj: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>Instalacijski objekt, koji je potreban u operaciji "%1" je prazan.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Samopokretanje: Valjano je samo u modusima za aktualiziranje ili za upravljanje paketima.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Samopokretanje: Nevaljani argumenti</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Nije moguće otvoriti datoteke postavaka %1 za učitavanje: %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Nedostajući argumenti "%1" poziva %2 s argumentima "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>Trenutačna metoda, pozivanje "%1" s argumentima "%2", nije podrÅūana. Umjesto toga koristi set, remove, add_array_value ili remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Nijedan argument ne smije biti prazan: izvor "%1", odrediÅĄte "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Nije moguće premjestiti datoteku "%1" u "%2", jer odrediÅĄna staza već postoji i ne moÅūe se premjestiti.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Nije moguće premjestiti datoteku "%1" u "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>PremjeÅĄtanje datoteke "%1" u "%2".</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Nedostaje osnovni uređaj upravljača paketa.</translation> </message> <message> <source>Empty repository URL.</source> <translation>Prazan URL spremiÅĄta.</translation> </message> <message> <source>Download canceled.</source> <translation>Preuzimanje je prekinuto.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Istek vremena prilikom testiranja spremiÅĄta "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Nije moguće obraditi Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Nije moguće otvoriti Updates.xml za učitavanje: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Neuspjela autentifikacija.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Nepoznata greÅĄka prilikom testiranja spremiÅĄta "%1".</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Preuzimanje je dovrÅĄeno.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Kriptografski hashevi se ne podudaraju.</translation> </message> <message> <source>Download canceled.</source> <translation>Preuzimanje je prekinuto.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 od %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>Preuzeto: %1.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dan, </numerusform> <numerusform>%n dana, </numerusform> <numerusform>%n dana, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n sat, </numerusform> <numerusform>%n sata, </numerusform> <numerusform>%n sati, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuta</numerusform> <numerusform>%n minute</numerusform> <numerusform>%n minuta</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n sekunda</numerusform> <numerusform>%n sekunde</numerusform> <numerusform>%n sekunda</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> – preostaje %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> – nepoznato preostalo vrijeme.</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Zapisivanje u datoteku "%1" nije uspjelo: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Nije moguće čitati datoteku resursa "%1": %2</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Nije moguće preuzeti %1. NeuspjeÅĄno zapisivanje u datoteku "%2": %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Nije moguće preuzeti %1. Nije moguće stvoriti datoteku "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 na %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Zahtjev za autentifikacijom je prikinut.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Neuspjelo sigurno povezivanje</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>DoÅĄlo je do greÅĄke prilikom povezivanja na: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Problem moÅūda leÅūi u konfiguraciji posluÅūitelja ili netko pokuÅĄava manipulirati posluÅūiteljem.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Ako je u proÅĄlosti bilo moguće povezivanje s ovim posluÅūiteljem ili ako se radi o povjerljivom posluÅūitelju, moÅūda se radi o privremenoj greÅĄci. PokuÅĄaj ponovo.</translation> </message> <message> <source>Try again</source> <translation>PokuÅĄaj ponovo</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Prekinuto</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 sadrÅūava nevaljan sadrÅūaj: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Datoteka %1 ne postoji.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Nije moguće otvoriti %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>GreÅĄka u obradi u %1 na %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Neočekivani Root element %1, mora biti "Packages".</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Nije moguće stvoriti datoteku za zaključavanje "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Nije moguće upisati PID u datoteku za zaključavanje "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Nije moguće dobiti ključ za datoteku "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Nije moguće otključati datoteku "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 – pokrenuto</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 se ne moÅūe prekinuti</translation> </message> <message> <source>Cannot stop task %1</source> <translation>Nije moguće prekinuti zadatak %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 se ne moÅūe zaustaviti</translation> </message> <message> <source>Cannot pause task %1</source> <translation>Nije moguće zaustaviti zadatak %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>Nije moguće nastaviti zadatak %1</translation> </message> <message> <source>%1 done</source> <translation>%1 – zavrÅĄeno</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Nije moguće dobiti informacije o paketu za ovu aplikaciju.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Za ovu aplikaciju nisu postavljeni izvori paketa.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>Nađena je %n nadogradnja.</numerusform> <numerusform>Nađene su %n nadogradnje.</numerusform> <numerusform>Nađeno je %n nadogradnji.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Preuzimanje Updates.xml iz izvora nadogradnja.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Nije moguće preuzeti paket %1 iz "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Updates.xml datoteke su preuzete iz izvora nadogradnja.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Određivanje mogućih nadogradnji.</translation> </message> <message> <source>Application updates computed.</source> <translation>Nadogradnje za aplikaciju su određene.</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Nije moguće kopirati nepostojeću datoteku: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nije moguće ukloniti datoteku "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nije moguće kopirati datoteku "%1" u "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Nije moguće izbrisati datoteku "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Nije moguće učitati sigurnosnu kopiju u "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nije moguće ukloniti datoteku "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nije moguće kopirati datoteku "%1" u "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nije moguće ukloniti datoteku "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Nije moguće stvoriti mapu "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Nepoznata greÅĄka.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nije moguće ukloniti mapu "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nije moguće ukloniti mapu "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>Mapa ne postoji.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Nije moguće vratiti mapu "%1": %2</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Nije moguće naći sigurnosnu kopiju za "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nije moguće stvoriti sigurnosnu kopiju datoteke "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za učitavanje: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nije moguće otvoriti datoteku "%1" za zapisivanje: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Nije moguće naći sigurnosnu kopiju za "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nije moguće učitati sigurnosnu kopiju za "%1": %2</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml sadrÅūava nevaljan sadrÅūaj: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Nije moguće čitati "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>GreÅĄka u obradi u %1 na %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Neočekivani Root element %1, mora biti "Updates".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Nedostaje element ApplicationName (ime aplikacije).</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Nedostaje element ApplicationVersion (vezija aplikacije).</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Element PackageUpdate bez Name (imena)</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Element PackageUpdate bez Version (verzije)</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Element PackageUpdate bez ReleaseDate (datuma objave)</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Čekanje na %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Već je pokrenuta jedna instanca za %1. Pričekaj da zavrÅĄi, zatvori je ili ponovo pokreni sustav.</translation> </message> </context> </TS> ������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_it.ts�����������������������������������������0100777�0000000�0000000�00000305364�13761647206�021035� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>Il proxy richiede l'autenticazione.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Impossibile cercare in %1 per leggere i dati dell'operazione.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Impossibile cercare in %1 per leggere il blocco raccolta risorse.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Impossibile aprire risorsa metadati %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Impossibile cercare in %1 per leggere il conteggio metadati incorporato.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Impossibile cercare in %1 per leggere il segmento raccolta risorse.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Imprevista incongruenza delle risorse metadati. Letto %1, previsto: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Richiesta autenticazione http</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>È necessario fornire un nome utente e una password per accedere a questo sito.</translation> </message> <message> <source>Username:</source> <translation>Nome Utente:</translation> </message> <message> <source>Password:</source> <translation>Password:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>Il percorso "%1" esiste ma non ÃĻ una directory.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossibile creare la directory "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Impossibile recuperare il percorso dell'elemento dell’archivio %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Impossibile rimuovere collegamento simbolico già esistente %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Impossibile creare collegamento simbolico in "%1". Un altro ÃĻ già presente.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Impossibile leggere la destinazione del collegamento simbolico dal file "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Impossibile creare collegamento simbolico in %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>In attesa di %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Un'altra istanza di %1 ÃĻ già in esecuzione. Attendere fino al termine, chiuderla o riavviare il sistema.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Componenti aggiunti come dipendenze automatiche:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Componenti aggiunti come dipendenza per "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Componenti che hanno dipendenza risolte:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Componenti selezionati senza dipendenze:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Rilevata ricorsione, componente "%1" già aggiunto con motivo: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>Impossibile trovare la dipendenza mancante "%1" per "%2".</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Annullato</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossibile eseguire il backup del file "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Impossibile trovare il file di backup per "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Impossibile ripristinare il file di backup per "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossibile ripristinare il file di backup per "%1": %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Impossibile eseguire il backup del file "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Impossibile copiare un file non esistente: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossibile rimuovere il file "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossibile copiare il file da "%1" a "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Impossibile eliminare il file "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Impossibile ripristinare il file di backup in "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Impossibile creare il backup del file "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossibile ripristinare il file di backup per "%1": %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Download completato.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Gli hash di crittografia non corrispondono.</translation> </message> <message> <source>Download canceled.</source> <translation>Download annullato.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 di %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 scaricato.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sec)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n giorno/i, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n ora/e, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto/i</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n secondo/i</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 rimanente.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tempo rimanente sconosciuto.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Impossibile scaricare %1. Scrittura nel file "%2" non riuscita: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Impossibile scaricare %1. Impossibile creare il file "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Richiesta di autenticazione annullata.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Connessione protetta non riuscita</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Errore durante la connessione a: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Il problema verificatosi potrebbe essere relativo alla configurazione del server o a qualcuno che sta tentando di impersonare il server.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Se la connessione al server ÃĻ stata già stabilita in passato o se si considera il server attendibile, l'errore puÃē essere temporaneo ed ÃĻ possibile riprovare.</translation> </message> <message> <source>Try again</source> <translation>Riprova</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Scrittura nel file "%1" non riuscita: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossibile creare la directory "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Errore sconosciuto.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossibile rimuovere la directory "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Impossibile eseguire il backup del file "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossibile rimuovere il file "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossibile copiare il file da "%1" a "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossibile rimuovere il file "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossibile ripristinare il file di backup per "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossibile eseguire il backup del file "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Impossibile trovare il file di backup per "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Impossibile ripristinare il file di backup per "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Impossibile ripristinare il file di backup per "%1": %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Impossibile leggere il file di risorse "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossibile rimuovere la directory "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>La directory non esiste.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Impossibile ricreare la directory "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 avviato</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 non puÃē essere arrestato</translation> </message> <message> <source>Cannot stop task %1</source> <translation>Impossibile arrestare l'attività %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 non puÃē essere sospeso</translation> </message> <message> <source>Cannot pause task %1</source> <translation>Impossibile sospendere l'attività %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>Impossibile riprendere l'attività %1</translation> </message> <message> <source>%1 done</source> <translation>%1 completato</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Impossibile accedere alle informazioni sul pacchetto di questa applicazione.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Nessuna origine pacchetto impostata per questa applicazione.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n aggiornamento/i trovato/i.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Download di Updates.xml dalle origini di aggiornamento.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Impossibile scaricare origine pacchetto %1 da "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>File Updates.xml scaricati dalle origini di aggiornamento.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Calcolo degli aggiornamenti applicabili.</translation> </message> <message> <source>Application updates computed.</source> <translation>Aggiornamenti applicazione calcolati.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml contiene contenuto non valido: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Impossibile leggere "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Errore di analisi in %1 a %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Elemento radice %1 imprevisto, dovrebbe essere "Updates".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Elemento ApplicationName mancante.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Elemento ApplicationVersion mancante.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Elemento PackageUpdate senza Name</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Elemento PackageUpdate senza Version</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Elemento PackageUpdate senza ReleaseDate</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>codice interno: %1</translation> </message> <message> <source>not enough memory</source> <translation>memoria insufficiente</translation> </message> <message> <source>Error: %1</source> <translation>Errore: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Impossibile recuperare la proprietà %1 per l'elemento %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>La proprietà %1 per l'elemento %2 non ÃĻ di tipo VT_FILETIME ma %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Impossibile convertire l'ora del file UTC nell'ora di sistema.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Impossibile caricare i codec.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Impossibile aprire l'archivio "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Impossibile recuperare il numero di elementi nell'archivio.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Impossibile recuperare il percorso dell'elemento dell’archivio "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Rilevata eccezione sconosciuta (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Impossibile creare file temporaneo: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Tipo di archivio non supportato.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Impossibile creare l'archivio "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Impossibile creare l'archivio "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>Impossibile rimuovere il vecchio archivio "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>Impossibile rinominare l'archivio temporaneo "%1" "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Rilevata eccezione sconosciuta (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 contiene contenuto non valido: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Il file %1 non esiste.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Impossibile aprire %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Errore di analisi in %1 a %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Elemento radice %1 imprevisto, dovrebbe essere 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Impossibile creare il file di blocco "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Impossibile scrivere PID nel file di blocco "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Impossibile ottenere il blocco per il file "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Impossibile rilasciare il blocco per il file "%1": %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Nessun marcatore trovato, operazione interrotta dopo %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Lettura non riuscita dopo %1 byte: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Copia non riuscita: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Scrittura non riuscita dopo %1 byte: %2</translation> </message> <message> <source>bytes</source> <translation>byte</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossibile rimuovere il file "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossibile rimuovere la directory "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossibile creare la directory "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Impossibile copiare il file da "%1" a "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Impossibile spostare il file da "%1" a "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossibile creare la directory "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Impossibile aprire il file temporaneo: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Impossibile aprire il file temporaneo per il modello %1: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>Installazione danneggiata</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>L'installazione sembra danneggiata. Provare a reinstallare da zero.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Impossibile trovare il modulo specificato.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>I componenti non possono avere figli in modalità updater.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Impossibile aprire il file di interfaccia utente richiesto "%1": %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Impossibile caricare il file di interfaccia utente richiesto "%1": %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Impossibile aprire il file di licenza richiesto "%1": %2</translation> </message> <message> <source>Error</source> <translation>Errore</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Errore: l'operazione %1 non esiste.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Impossibile risolvere isDefault in %1</translation> </message> <message> <source>Update Info: </source> <translation>Informazioni aggiornamento: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Il componente ÃĻ contrassegnato per l'installazione.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Il componente ÃĻ contrassegnato per la disinstallazione.</translation> </message> <message> <source>Component is installed.</source> <translation>Il componente ÃĻ installato.</translation> </message> <message> <source>Component is not installed.</source> <translation>Il componente non ÃĻ installato.</translation> </message> <message> <source>Component Name</source> <translation>Nome componente</translation> </message> <message> <source>Action</source> <translation>Azione</translation> </message> <message> <source>Installed Version</source> <translation>Versione installata</translation> </message> <message> <source>New Version</source> <translation>Nuova versione</translation> </message> <message> <source>Release Date</source> <translation>Data di pubblicazione</translation> </message> <message> <source>Size</source> <translation>Dimensioni</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>&Predefinito</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+F</translation> </message> <message> <source>&Reset</source> <translation>&Reimposta</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&Seleziona tutto</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>&Deseleziona tutto</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Per installare un nuovo repository compresso, sfogliare i repository nel computer</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&Sfoglia file QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Questo componente occuperà circa %1 sul disco rigido.</translation> </message> <message> <source>Open File</source> <translation>Apri file</translation> </message> <message> <source>Select Components</source> <translation>Seleziona componenti</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Selezionare i componenti che si desidera aggiornare.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Selezionare i componenti che si desidera installare.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Selezionare i componenti che si desidera disinstallare.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Selezionare i componenti da installare. Deselezionare i componenti installati per disinstallarli. I componenti già installati non verranno aggiornati.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><to be saved installer key name> <executable> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L'oggetto programma di installazione necessario nell'operazione %1 ÃĻ vuoto.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Impossibile salvare l'output di "%1” in un valore chiave del programma di installazione vuoto.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Il file "%1" non esiste o non ÃĻ un file binario eseguibile.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>L'esecuzione di "%1" ha causato un arresto anomalo.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><source> <target> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Argomento non valido in %1: il terzo argomento deve essere forceOverwrite, se specificato.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Argomento non valido in %1: la directory "%2" non ÃĻ valida.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Impossibile creare la directory "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Impossibile sovrascrivere "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Impossibile copiare il file da "%1" a "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossibile rimuovere il file "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Conteggio elementi attività non valido.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Scrittura nel file "%1" non riuscita: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossibile eseguire il backup del file "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Impossibile sovrascrivere il file "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Impossibile scrivere la voce desktop su "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Impossibile creare collegamento da "%1" a "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Impossibile rimuovere collegamento da "%1" a "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Impossibile impostare le autorizzazioni file "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Impossibile rimuovere il file "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Impossibile spostare il file da "%1" a "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Il programma di installazione su "%1” deve essere in versione offline.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Impossibile aprire il file "%1" per la lettura.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Impossibile leggere il file "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Impossibile creare la directory di destinazione: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Rilevata eccezione sconosciuta: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Rimozione file "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Impossibile rimuovere il file "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Impossibile rimuovere la directory "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossibile creare la directory "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Impossibile sovrascrivere "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Impossibile creare il collegamento "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Annullato</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Download firma hash non riuscito.</translation> </message> <message> <source>Download Error</source> <translation>Errore download</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Verifica hash durante il download non riuscita. Errore temporaneo, riprovare.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>Impossibile verificare hash</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Impossibile scaricare l'archivio %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Impossibile recuperare gli archivi: %1 Errore durante il caricamento di %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Download archivio "%1" per il componente %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Schema %1 non supportato (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Impossibile trovare il componente per %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>Il file di destinazione "%1" esiste già ma non ÃĻ un file.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>File "%1" non aperto per la scrittura: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Scrittura nel file "%1" non riuscita: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Rilevato ciclo di reindirizzamento per "%1".</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Rilevata mancata corrispondenza checksum per "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Errore di rete durante il download di '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Errore di rete sconosciuto durante il download di "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>Trasferimenti rete annullati.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>I trasferimenti rete non supportano le operazioni di pausa e ripresa.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>URL di origine non valido "%1": %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Impossibile avvio scollegato: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Impossibile avviare: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Arresto del programma: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Esecuzione non riuscita (codice di uscita imprevisto: %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Impossibile aprire l’archivio "%1" per la lettura: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Errore durante l'estrazione dell'archivio "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Rilevata eccezione sconosciuta durante l'estrazione di "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Impossibile ottenere core di gestione pacchetti.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Questo processo deve essere arrestato prima di continuare: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Questi processi devono essere arrestati prima di continuare: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 di %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 ricevuto.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/sec)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n giorno/i, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n ora/e, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto/i</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n secondo/i</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 rimanente.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tempo rimanente sconosciuto.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>Completamento della procedura guidata %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Fare clic su %1 per uscire dalla procedura guidata %2.</translation> </message> <message> <source>Restart</source> <translation>Riavvia</translation> </message> <message> <source>Run %1 now.</source> <translation>Eseguire %1 ora.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>Procedura guidata %1 non riuscita.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Le impostazioni non sono scrivibili.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Impossibile scrivere le impostazioni.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><source path> [vendor prefix]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Argomento non valido: la directory di origine non deve essere vuota.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Impossibile eseguire il backup del file "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Impossibile sovrascrivere "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Impossibile copiare il file "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Impossibile creare la directory "%1": %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Installazione - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Installazione guidata di %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>Aggiungi o rimuovi componenti</translation> </message> <message> <source>&Update components</source> <translation>Aggiorna componenti</translation> </message> <message> <source>&Remove all components</source> <translation>Rimuovi tutti i componenti</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Recupero informazioni dalle origini di installazione remote in corso...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Richiesto almeno un repository valido e abilitato per il completamento di questa azione.</translation> </message> <message> <source>No updates available.</source> <translation>Nessun aggiornamento disponibile.</translation> </message> <message> <source> Only local package management available.</source> <translation> Disponibile solo gestione pacchetto locale.</translation> </message> <message> <source>&Quit</source> <translation>Esci</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Contratto di licenza</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Leggere il seguente contratto di licenza. È necessario accettare i termini contenuti in questo contratto prima di continuare l'installazione.</translation> </message> <message> <source>I accept the license.</source> <translation>Accetto la licenza.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Non accetto la licenza.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Leggere i seguenti contratti di licenza. È necessario accettare i termini contenuti in questi contratti prima di continuare l'installazione.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Accetto le licenze.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Non accetto le licenze.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Nessun file di licenza da copiare trovato.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>L'oggetto programma di installazione necessario nell'operazione %1 ÃĻ vuoto.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Impossibile scrivere il file di licenza "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Nessun file di licenza da eliminare trovato.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Motore core di gestione pacchetti mancante.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Preparazione del download delle informazioni sui metadati...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Decompressione repository compressi. Potrebbe volerci qualche momento...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Download dei metadati annullato.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Eccezione sconosciuta durante l'estrazione.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Credenziali proxy mancanti.</translation> </message> <message> <source>Authentication failed.</source> <translation>Autenticazione non riuscita.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Eccezione sconosciuta durante il download.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Impossibile recuperare repository.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Estrazione informazioni sui metadati in corso...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Recupero delle informazioni sui metadati dal repository remoto in corso... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Recupero delle informazioni sui metadati dal repository remoto in corso... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Errore durante l'estrazione dell'archivio "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Rilevata eccezione sconosciuta durante l'estrazione dell'archivio "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Errore durante la scrittura dello strumento di manutenzione</translation> </message> <message> <source> Downloading packages...</source> <translation> Download pacchetti in corso...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Installazione annullata dall'utente.</translation> </message> <message> <source>All downloads finished.</source> <translation>Completati tutti i download.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Annullamento del programma di installazione</translation> </message> <message> <source>Authentication Error</source> <translation>Errore di autenticazione</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Alcuni componenti non possono essere rimossi completamente poichÃĐ non ÃĻ possibile acquisire diritti di amministrazione: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Errore sconosciuto.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Alcuni componenti non possono essere rimossi completamente a causa di un errore sconosciuto.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>L'applicazione non ÃĻ in esecuzione in modalità Gestione pacchetti.</translation> </message> <message> <source>No installed packages found.</source> <translation>Nessun pacchetto installato trovato.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>L'applicazione ÃĻ in esecuzione in modalità Programma di disinstallazione.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>È disponibile un aggiornamento importante, eseguire innanzitutto l'updater.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Impossibile risolvere tutte le dipendenze.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Componenti che si sta per rimuovere.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Errore durante l'elevazione dei diritti di accesso.</translation> </message> <message> <source>Error</source> <translation>Errore</translation> </message> <message> <source>invalid</source> <translation>non valido</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>Dipendenze non risolte</translation> </message> <message> <source>Error</source> <translation>Errore</translation> </message> <message> <source>Access error</source> <translation>Errore di accesso</translation> </message> <message> <source>Format error</source> <translation>Errore di formato</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Impossibile scrivere la configurazione del programma di installazione in %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Arresta processi</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Questi processi devono essere arrestati per continuare: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Installazione annullata dall'utente</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Scrittura dello strumento di manutenzione.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Impossibile cercare nel file %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Lo strumento di manutenzione non ÃĻ un bundle</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Impossibile rimuovere il file di dati "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Impossibile scrivere i dati dello strumento di manutenzione in %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Impossibile scrivere lo strumento di manutenzione in "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Impossibile scrivere i dati binari dello strumento di manutenzione in %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>Variabile 'TargetDir' non impostata.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Preparazione dell'installazione in corso...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Impossibile installare dalla posizione di rete</translation> </message> <message> <source>Creating local repository</source> <translation>Creazione repository locale</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Creazione strumento di manutenzione</translation> </message> <message> <source> Installation finished!</source> <translation> Installazione completata.</translation> </message> <message> <source> Installation aborted!</source> <translation> Installazione annullata.</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Impossibile eseguire l'operazione da una posizione di rete</translation> </message> <message> <source>Removing deselected components...</source> <translation>Rimozione dei componenti deselezionati in corso...</translation> </message> <message> <source> Update finished!</source> <translation> Aggiornamento completato.</translation> </message> <message> <source> Update aborted!</source> <translation> Aggiornamento annullato.</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>Disinstallazione completata.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>Disinstallazione interrotta.</translation> </message> <message> <source> Installing component %1</source> <translation> Installazione componente %1</translation> </message> <message> <source>Installer Error</source> <translation>Errore del programma di installazione</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Errore durante il processo di installazione (%1): %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Impossibile preparare la disinstallazione</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Impossibile avviare la disinstallazione</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Errore durante il processo di disinstallazione: %1</translation> </message> <message> <source>Unknown error</source> <translation>Errore sconosciuto</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Impossibile recuperare l'albero remoto %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Impossibile leggere pacchetti da %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Impossibile recuperare le meta informazioni: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Impossibile aggiungere informazioni sull'origine di aggiornamento temporanea.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Impossibile trovare informazioni sull'origine di aggiornamento.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Rilevato ciclo di dipendenza tra i componenti "%1" e "%2"</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>Installazione di %1</translation> </message> <message> <source>Maintain %1</source> <translation>Manutenzione %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Annullare il processo di installazione?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Annullare il processo di disinstallazione?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Uscire dal programma di installazione?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Uscire dal programma di disinstallazione?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Uscire dall'applicazione di manutenzione?</translation> </message> <message> <source>%1 Question</source> <translation>%1 Domanda</translation> </message> <message> <source>Settings</source> <translation>Impostazioni</translation> </message> <message> <source>Error</source> <translation>Errore</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Impossibile effettuare la disinstallazione da una posizione di rete. Copiare il programma di installazione in un'unità locale</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&Mostra dettagli</translation> </message> <message> <source>&Hide Details</source> <translation>&Nascondi dettagli</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>Disi&nstalla</translation> </message> <message> <source>Uninstalling %1</source> <translation>Disinstallazione di %1</translation> </message> <message> <source>&Update</source> <translation>&Aggiorna</translation> </message> <message> <source>Updating components of %1</source> <translation>Aggiornamento componenti di %1</translation> </message> <message> <source>&Install</source> <translation>&Installa</translation> </message> <message> <source>Installing %1</source> <translation>Installazione %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Finestra di dialogo</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>Il proxy %1 richiede un nome utente e una password.</translation> </message> <message> <source>Username:</source> <translation>Nome Utente:</translation> </message> <message> <source>Username</source> <translation>Nome utente</translation> </message> <message> <source>Password:</source> <translation>Password:</translation> </message> <message> <source>Password</source> <translation>Password</translation> </message> <message> <source>Proxy Credentials</source> <translation>Credenziali proxy</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>Disi&nstalla</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Pronto alla disinstallazione</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>Si ÃĻ ora pronti per iniziare la rimozione di %1 dal computer.<br><font color="red">La directory del programma %2 verrà eliminata completamente</font>, incluso tutto il contenuto di tale directory!</translation> </message> <message> <source>U&pdate</source> <translation>A&ggiorna</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Pronto all'aggiornamento dei pacchetti</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>Si ÃĻ ora pronti per iniziare l'installazione.</translation> </message> <message> <source>&Install</source> <translation>&Installa</translation> </message> <message> <source>Ready to Install</source> <translation>Pronto all'installazione</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>Si ÃĻ ora pronti per iniziare l'installazione di %1 nel computer.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>Spazio su disco insufficiente per memorizzare i file temporanei e l'installazione. Spazio disponibile %1, spazio minimo richiesto %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>Spazio su disco insufficiente per memorizzare tutti i componenti selezionati! Spazio disponibile %1, spazio minimo richiesto %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>Spazio su disco insufficiente per memorizzare i file temporanei! Spazio disponibile %1, spazio minimo richiesto %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Lo spazio per l'installazione del volume selezionato per l'installazione pare sufficiente, tuttavia successivamente resterà meno dell'1% del volume di spazio disponibile. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Lo spazio per l'installazione del volume selezionato per l'installazione pare sufficiente, tuttavia successivamente resteranno meno di 100 MB disponibili. %1. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>L'installazione utilizzerà %1 di spazio su disco.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><extension> <command> [description [contentType [icon]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>La registrazione dei tipi di file ÃĻ supportata solo in Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Tipo di file di registro: argomenti non validi</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Impossibile leggere tutti i dati dopo l'invio del comando: %1. Byte previsti: %2; Byte ricevuti: %3. Errore: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Impossibile aprire il file "%1" per la lettura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Impossibile aprire il file "%1" per la scrittura: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Impossibile aprire la risorsa %1 per la lettura.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Lettura non riuscita dopo %1 byte: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Scrittura non riuscita dopo %1 byte: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>Completamento dell'installazione guidata di %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Impossibile aprire il file di script in %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Eccezione durante il caricamento dello script del componente "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Errore sconosciuto.</translation> </message> <message> <source>on line number: </source> <translation>Numero online: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>L'oggetto programma di installazione necessario nell'operazione %1 ÃĻ vuoto.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Riavvio automatico: valido solo in modalità aggiornamento o gestione pacchetti.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Riavvio automatico: argomenti non validi</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Il server richiede l'autenticazione</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>È necessario fornire un nome utente e una password per accedere a questo sito.</translation> </message> <message> <source>Username:</source> <translation>Nome Utente:</translation> </message> <message> <source>Password:</source> <translation>Password:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 a %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Argomento(i) mancante(i) "%1" richiamando %2 con argomenti "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>La chiamata all’argomento metodo corrente "%1" con argomenti "%2" non ÃĻ supportata. Utilizzare set, remove, add_array_value o remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Nessuno degli argomenti puÃē essere vuoto: origine "%1", destinazione "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Impossibile spostare il file da "%1" a "%2", poichÃĐ la destinazione esiste e non ÃĻ rimovibile.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Impossibile spostare il file da "%1" a "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>Spostamento del file "%1" su "%2".</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Collegamenti del menu Start</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Selezionare il menu Start in cui si desidera creare i collegamenti del programma. È anche possibile immettere un nome per creare una nuova directory.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Cartella di installazione</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Specificare la directory in cui %1 verrà installato.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+F</translation> </message> <message> <source>B&rowse...</source> <translation>S&foglia...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>La directory selezionata esiste già e contiene un'installazione. Scegliere una destinazione diversa per l'installazione.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Si ÃĻ selezionata una directory esistente non vuota per l'installazione. Notare che verrà eliminata completamente in caso di disinstallazione di questa applicazione. Non ÃĻ consigliabile eseguire l'installazione in questa directory poichÃĐ l'installazione potrebbe avere esito negativo. Continuare?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Si ÃĻ selezionato un file o un collegamento simbolico esistente, scegliere una destinazione diversa per l'installazione.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Seleziona cartella di installazione</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>Il percorso di installazione non puÃē essere vuoto, specificare una directory valida.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>Il percorso di installazione non puÃē essere relativo, specificare un percorso assoluto.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>Il percorso o la directory di installazione contengono caratteri non ASCII. Questo non ÃĻ al momento supportato. Scegliere un percorso diverso o una directory di installazione diversa.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Dal momento che la directory di installazione viene eliminata completamente, l'installazione in %1 non ÃĻ consentita.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>Il percorso immesso ÃĻ troppo lungo, assicurarsi di specificare un percorso valido.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>Il percorso immesso non ÃĻ valido, assicurarsi di specificare una destinazione valida.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>Il percorso immesso non ÃĻ valido, assicurarsi di specificare un'unità valida.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>Il percorso di installazione non deve terminare con '.', specificare una directory valida.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>Il percorso di installazione non deve contenere "%1", specificare una directory valida.</translation> </message> <message> <source>Warning</source> <translation>Avviso</translation> </message> <message> <source>Error</source> <translation>Errore</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Motore core di gestione pacchetti mancante.</translation> </message> <message> <source>Empty repository URL.</source> <translation>URL repository vuoto.</translation> </message> <message> <source>Download canceled.</source> <translation>Download annullato.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Timeout durante il test del repository "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Impossibile analizzare Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Impossibile aprire Updates.xml per la lettura: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Autenticazione non riuscita.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Errore sconosciuto durante il test del repository "%1".</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Necessaria autorizzazione</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Immettere la password per autorizzare sudo:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Errore durante l'acquisizione di diritti di amministrazione</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Impossibile ottenere l’autorizzazione.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Impossibile ottenere l'autorizzazione necessaria per continuare l'installazione. Avviare il programma di installazione come utente con i diritti appropriati. O accettare l'elevazione dei diritti di accesso, ove richiesto.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Impossibile ottenere l'autorizzazione necessaria per continuare l'installazione. Annullare l'installazione o utilizzare la soluzione di fallback eseguendo %1 come utente con i diritti appropriati, quindi fare clic su OK.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Impossibile aprire la risorsa %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Impossibile aprire il file di impostazioni %1 per la lettura: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Impostazioni</translation> </message> <message> <source>Network</source> <translation>Rete</translation> </message> <message> <source>No proxy</source> <translation>Nessun proxy</translation> </message> <message> <source>System proxy settings</source> <translation>Impostazioni proxy di sistema</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Configurazione manuale proxy</translation> </message> <message> <source>HTTP proxy:</source> <translation>Proxy HTTP:</translation> </message> <message> <source>Port:</source> <translation>Porta:</translation> </message> <message> <source>FTP proxy:</source> <translation>Proxy FTP:</translation> </message> <message> <source>Repositories</source> <translation>Repository</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Aggiungere nome utente e password per l'autenticazione, se necessario.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Utilizza solo repository temporanei</translation> </message> <message> <source>Add</source> <translation>Aggiungi</translation> </message> <message> <source>Remove</source> <translation>Rimuovi</translation> </message> <message> <source>Test</source> <translation>Test</translation> </message> <message> <source>Show Passwords</source> <translation>Mostra password</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Selezionare questa opzione per utilizzare il repository durante il recupero.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Aggiungere il nome per eseguire l'autenticazione sul server.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Aggiungere la password per eseguire l'autenticazione sul server.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>URL di server che contiene un repository valido.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Si ÃĻ verificato un errore durante il test del repository.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Repository testato correttamente.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Disabilitare il repository?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Abilitare il repository?</translation> </message> <message> <source>Hide Passwords</source> <translation>Nascondi password</translation> </message> <message> <source>Use</source> <translation>Usare</translation> </message> <message> <source>Username</source> <translation>Nome utente</translation> </message> <message> <source>Password</source> <translation>Password</translation> </message> <message> <source>Repository</source> <translation>Repository</translation> </message> <message> <source>Default repositories</source> <translation>Repository predefiniti</translation> </message> <message> <source>Temporary repositories</source> <translation>Repository temporanei</translation> </message> <message> <source>User defined repositories</source> <translation>Repository definiti dall'utente</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>Impossibile scrivere nel percorso del registro di sistema %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>Il percorso del registro di sistema %1 non ÃĻ scrivibile.</translation> </message> <message> <source>exactly %1</source> <translation>esattamente %1</translation> </message> <message> <source>at least %1</source> <translation>almeno %1</translation> </message> <message> <source>not more than %1</source> <translation>Non piÃđ di %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 o %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 a %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Argomenti non validi in %1: %n argomenti forniti, %2 argomenti previsti.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Argomenti non validi in %1: %n argomenti forniti, %2 argomenti previsti nel modulo: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Impossibile rinominare il file "%1" "%2": %3</translation> </message> </context> </TS> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_ja.ts�����������������������������������������0100777�0000000�0000000�00000323564�13761647206�021015� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%2 ãŪ %1</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>プロキシãŦãŊ詍čĻžãŒåŋ…čĶã§ã™ã€‚</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>æ“ä―œãƒ‡ãƒžã‚ŋã‚’čŠ­ãŋ取るためãŪ %1 ãŪシマã‚Ŋができãūせん。</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>ãƒŠã‚―ãƒžã‚đ ã‚ģノã‚Ŋショãƒģ ブロッã‚Ŋã‚’čŠ­ãŋ取るためãŪ %1 ãŪシマã‚Ŋができãūせん。</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>ãƒĄã‚ŋ ãƒŠã‚―ãƒžã‚đ %1 を開けãūせん。</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>埋めčūžãŋãƒĄã‚ŋ デマã‚ŋæ•°ã‚’čŠ­ãŋ取るためãŪ %1 ãŪシマã‚Ŋができãūせん。</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>ãƒŠã‚―ãƒžã‚đ ã‚ģノã‚Ŋショãƒģ ã‚ŧã‚°ãƒĄãƒģãƒˆã‚’čŠ­ãŋ取るためãŪ %1 ãŪシマã‚Ŋができãūせん。</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>äšˆæœŸã—ãŠã„ãƒĄã‚ŋ ãƒŠã‚―ãƒžã‚đãŪäļäļ€č‡īです。 %1 ã‚’čŠ­ãŋ取りãūす。䚈æƒģされるįĩæžœ: %2</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>HTTP 詍čĻžãŒåŋ…čĶã§ã™</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>こãŪã‚ĩã‚ĪトãŦã‚Ēã‚Ŋã‚ŧã‚đするãŦãŊ、ãƒĶマã‚ķマ名ãĻパã‚đãƒŊマドを指åŪšã™ã‚‹åŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>Username:</source> <translation>ãƒĶマã‚ķマ名:</translation> </message> <message> <source>Password:</source> <translation>パã‚đãƒŊマド:</translation> </message> <message> <source>%1 at %2</source> <translation>%2 ãŪ %1</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>パã‚đ "%1" ãŊ存åœĻしãūすが、デã‚Ģノã‚ŊトナでãŊありãūせん。</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん。</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>ã‚Ēマã‚Ŧã‚Īブ ã‚Ēã‚Īテム %1 ãŪパã‚đを取åū—できãūせん。</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>æ—Ē存ãŪシãƒģボナッã‚Ŋ ナãƒģã‚Ŋ %1 を削é™Īできãūせん。</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>"%1" でシãƒģボナッã‚Ŋ ナãƒģã‚Ŋã‚’ä―œæˆã§ããūせん。 すでãŦåˆĨãŪもãŪが存åœĻしãĶいãūす。</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" からシãƒģボナッã‚Ŋ ナãƒģã‚Ŋ ã‚ŋマã‚ēãƒƒãƒˆã‚’čŠ­ãŋ取れãūせん。</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>%1 でシãƒģボナッã‚Ŋ ナãƒģã‚Ŋã‚’ä―œæˆã§ããūせん: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>%1 をåū…æĐŸã—ãĶいãūす</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>åˆĨãŪ %1 ã‚Īãƒģã‚đã‚ŋãƒģã‚đがすでãŦåŪŸčĄŒã•ã‚ŒãĶいãūす。 そãŪã‚Īãƒģã‚đã‚ŋãƒģã‚đがįĩ‚䚆するãūでåū…æĐŸã™ã‚‹ã‹ã€ããŪã‚Īãƒģã‚đã‚ŋãƒģã‚đを閉じるか、シã‚đテムを再čĩ·å‹•しãĶください。</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>č‡Šå‹•įš„ãŠäūå­˜é–Ēäŋ‚ãĻしãĶčŋ―加されたã‚ģãƒģポマネãƒģト:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>"%1" ãŪäūå­˜é–Ēäŋ‚ãĻしãĶčŋ―加されたã‚ģãƒģポマネãƒģト:</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>äūå­˜é–Ēäŋ‚がč§Ģæąšã•ã‚ŒãŸã‚ģãƒģポマネãƒģト:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>äūå­˜é–Ēäŋ‚がおいéļ択æļˆãŋãŪã‚ģãƒģポマネãƒģト:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>再åļ°ãŒæĪœå‡šã•れãūした。ã‚ģãƒģポマネãƒģト "%1" ãŊã€į†į”ą: "%2" ですでãŦčŋ―加されãĶいãūす。</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>"%2" ãŪæŽ č―ã—ãŸäūå­˜é–Ēäŋ‚ "%1" がčĶ‹ãĪかりãūせん。</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>キãƒĢãƒģã‚ŧãƒŦ</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん。</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>存åœĻã—ãŠã„ãƒ•ã‚Ąã‚ĪãƒŦãŊã‚ģピマできãūせん: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦã‚ģピマできãūせん: %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>バッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦを "%1" ãŦåūĐ元できãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>ダã‚Ķãƒģロマドがįĩ‚䚆しãūした。</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>暗号ハッシãƒĨがäļ€č‡īしãĶいãūせん。</translation> </message> <message> <source>Download canceled.</source> <translation>ダã‚ĶãƒģロマドがキãƒĢãƒģã‚ŧãƒŦされãūした。</translation> </message> <message> <source>%1 of %2</source> <translation>%1/%2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 がダã‚Ķãƒģロマドされãūした。</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/į§’)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n æ—Ĩ、 </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n 時間、 </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n 分</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n į§’</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - æŪ‹ã‚Š %1%2%3%4</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - æŪ‹ã‚Šæ™‚é–“äļæ˜Ž</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>%1 をダã‚Ķãƒģロマドできãūせん。 ãƒ•ã‚Ąã‚ĪãƒŦ "%2" ãļãŪæ›ļきčūžãŋができãūせんでした: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>%1 をダã‚Ķãƒģロマドできãūせん。 ãƒ•ã‚Ąã‚ĪãƒŦ "%2" ã‚’ä―œæˆã§ããūせん: %3</translation> </message> <message> <source>%1 at %2</source> <translation>%2 ãŪ %1</translation> </message> <message> <source>Authentication request canceled.</source> <translation>詍čĻžãƒŠã‚Ŋã‚Ļã‚đトがキãƒĢãƒģã‚ŧãƒŦされãūした。</translation> </message> <message> <source>Secure Connection Failed</source> <translation>ã‚ŧキãƒĨナテã‚Ģでäŋč­·ã•れたæŽĨįķšãŦåĪąæ•—ã—ãūした</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>%1 ãļãŪæŽĨįķšäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>ã‚ĩマバマãŪ構成ãŦå•éĄŒãŒã‚ã‚‹ã‹ã€čŠ°ã‹ãŒã‚ĩãƒžãƒãƒžã‚’å―čĢ…ã—ã‚ˆã†ãĻしたåŊčƒ―æ€§ãŒã‚ã‚Šãūす。</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>これãūでãŦこãŪã‚ĩマバマãļãŪæŽĨįķšãŦ成功したこãĻがあるå ī合やこãŪã‚ĩマバマがäŋĄé žã§ãã‚‹å ī合ãŊ、ä™‚įš„ãŠã‚ĻãƒĐマãĻ思われるため、再čĐĶčĄŒã—ãĶもかãūいãūせん。</translation> </message> <message> <source>Try again</source> <translation>再čĐĶ行</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãļãŪæ›ļきčūžãŋができãūせんでした: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Unknown error.</source> <translation>äļæ˜ŽãŠã‚ĻãƒĐマです。</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" を削é™Īできãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん。</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦã‚ģピマできãūせん: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>"%1" ãŪバッã‚Ŋã‚Ēップ ãƒ•ã‚Ąã‚ĪãƒŦをåūĐ元できãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>ãƒŠã‚―ãƒžã‚đ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ã‚’čŠ­ãŋ取れãūせん: %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>こãŪデã‚Ģノã‚ŊトナãŊ存åœĻしãūせん。</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’å†ä―œæˆã§ããūせん: %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 を開始しãūした</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 を停æ­Ēできãūせん</translation> </message> <message> <source>Cannot stop task %1</source> <translation>ã‚ŋã‚đã‚Ŋ %1 を停æ­Ēできãūせん</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 をč§Ģ析できãūせん</translation> </message> <message> <source>Cannot pause task %1</source> <translation>ã‚ŋã‚đã‚Ŋ %1 をč§Ģ析できãūせん</translation> </message> <message> <source>Cannot resume task %1</source> <translation>ã‚ŋã‚đã‚Ŋ %1 を再開できãūせん</translation> </message> <message> <source>%1 done</source> <translation>%1 がįĩ‚䚆しãūした</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>こãŪã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģãŪãƒ‘ãƒƒã‚ąãƒžã‚ļæƒ…å ąãŦã‚Ēã‚Ŋã‚ŧã‚đできãūせん。</translation> </message> <message> <source>No package sources set for this application.</source> <translation>こãŪã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģį”ĻãŦčĻ­åŪšã•ã‚ŒãŸãƒ‘ãƒƒã‚ąãƒžã‚ļ ã‚―ãƒžã‚đがありãūせん。</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n äŧķãŪæ›ī新がčĶ‹ãĪかりãūした。</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>æ›īæ–°ã‚―ãƒžã‚đから Updates.xml をダã‚ĶãƒģロマドしãĶいãūす。</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>"%2" ã‹ã‚‰ãƒ‘ãƒƒã‚ąãƒžã‚ļ ã‚―ãƒžã‚đ %1 をダã‚Ķãƒģロマドできãūせん。</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>æ›īæ–°ã‚―ãƒžã‚đから Updates.xml ãƒ•ã‚Ąã‚ĪãƒŦがダã‚Ķãƒģロマドされãūした。</translation> </message> <message> <source>Computing applicable updates.</source> <translation>čĐēå―“ã™ã‚‹æ›ī新をčψįŪ—ã—ãĶいãūす。</translation> </message> <message> <source>Application updates computed.</source> <translation>ã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģãŪæ›ī新がčψįŪ—ã•ã‚Œãūした。</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml ãŦį„ĄåŠđおã‚ģãƒģテãƒģツがåŦãūれãĶいãūす: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>"%1" ã‚’čŠ­ãŋ取れãūせん</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>%2、%3 で %1 ãŪã‚ĻãƒĐマをč§Ģ析しãūす: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>ãƒŦマト ã‚ĻãƒŽãƒĄãƒģト %1 ãŊ䚈期しおいもãŪです。"Updates" でおければおりãūせん。</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>ApplicationName ã‚ĻãƒŽãƒĄãƒģトがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>ApplicationVersion ã‚ĻãƒŽãƒĄãƒģトがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>PackageUpdate ã‚ĻãƒŽãƒĄãƒģトãŦ名前がありãūせん</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>PackageUpdate ã‚ĻãƒŽãƒĄãƒģトãŦバマã‚ļョãƒģがありãūせん</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>PackageUpdate ã‚ĻãƒŽãƒĄãƒģトãŦナナマã‚đæ—Ĩがありãūせん</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>内éƒĻã‚ģマド: %1</translation> </message> <message> <source>not enough memory</source> <translation>ãƒĄãƒĒナがčķģりãūせん</translation> </message> <message> <source>Error: %1</source> <translation>ã‚ĻãƒĐマ: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>ã‚Ēã‚Īテム %2 ãŪプロパテã‚Ģ %1 を取åū—できãūせん。</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>ã‚Ēã‚Īテム %2 ãŪプロパテã‚Ģ %1 ãŪã‚ŋã‚ĪプãŊ VT_FILETIME でãŊおく %3 です。</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>UTC ãƒ•ã‚Ąã‚ĪãƒŦ時間をシã‚đテム時間ãŦåĪ‰æ›ã§ããūせん。</translation> </message> <message> <source>Cannot load codecs.</source> <translation>ã‚ģマデッã‚Ŋã‚’čŠ­ãŋčūžã‚ãūせん。</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" を開けãūせん。</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>ã‚Ēマã‚Ŧã‚Īブ内ãŪã‚Ēã‚ĪテムãŪ数を取åū—できãūせん。</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>ã‚Ēマã‚Ŧã‚Īブ ã‚Ēã‚Īテム "%1" ãŪパã‚đを取åū—できãūせん。</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>äļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした (%1)。</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>ä™‚ãƒ•ã‚Ąã‚ĪãƒŦã‚’ä―œæˆã§ããūせん: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>ã‚ĩポマトされãĶいおいã‚Ēマã‚Ŧã‚Īブ ã‚ŋã‚Īプです。</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" ã‚’ä―œæˆã§ããūせん</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>åĪいã‚Ēマã‚Ŧã‚Īブ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>ä™‚ã‚Ēマã‚Ŧã‚ĪブãŪ名前を "%1" から "%2" ãŦåΉæ›īできãūせん: %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>äļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 ãŦį„ĄåŠđおã‚ģãƒģテãƒģツがåŦãūれãĶいãūす: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ %1 ãŊ存åœĻしãūせん。</translation> </message> <message> <source>Cannot open %1.</source> <translation>%1 を開けãūせん。</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>%2、%3 で %1 ãŪã‚ĻãƒĐマをč§Ģ析しãūす: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>ãƒŦマト ã‚ĻãƒŽãƒĄãƒģト %1 ãŊ䚈期しおいもãŪです。'Packages' でおければおりãūせん。</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>ロッã‚Ŋ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>PID をロッã‚Ŋ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŦæ›ļきčūžã‚ãūせん: %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪロッã‚Ŋを取åū—できãūせん: %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪロッã‚Ŋをč§Ģé™Īできãūせん: %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>ママã‚ŦマがčĶ‹ãĪかりãūせん。%1 ãŪåūŒã§åœæ­Ēしãūした。</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>%1 バã‚ĪトäŧĨ降ãŪ芭ãŋ取りができãūせんでした: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>ã‚ģピマできãūせんでした: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>%1 バã‚ĪトäŧĨ降ãŪæ›ļきčūžãŋができãūせんでした: %2</translation> </message> <message> <source>bytes</source> <translation>バã‚Īト</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん。</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>"%1" から "%2" ãŦãƒ•ã‚Ąã‚ĪãƒŦをã‚ģピマできãūせん: %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>"%1" から "%2" ãŦãƒ•ã‚Ąã‚ĪãƒŦをį§ŧ動できãūせん: %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>ä™‚ãƒ•ã‚Ąã‚ĪãƒŦを開けãūせん: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>テãƒģプノマト %1 ãŪä™‚ãƒ•ã‚Ąã‚ĪãƒŦを開けãūせん: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>ã‚Īãƒģã‚đトマãƒŦがį ī損しãĶいãūす</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>ã‚Īãƒģã‚đトマãƒŦがį ī損しãĶいるåŊčƒ―æ€§ãŒã‚ã‚Šãūす。 再ã‚Īãƒģã‚đトマãƒŦをæĪœčĻŽã—ãĶください。</translation> </message> <message> <source>The specified module could not be found.</source> <translation>指åŪšã—ãŸãƒĒã‚ļãƒĨマãƒŦがčĶ‹ãĪかりãūせんでした。</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>ã‚ģãƒģポマネãƒģトãŊ、ã‚Ēップデマã‚ŋマ ãƒĒマドで子を持ãĪこãĻができãūせん。</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>čĶæą‚ã•ã‚ŒãŸ UI ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>čĶæą‚ã•ã‚ŒãŸ UI ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ã‚’čŠ­ãŋčūžã‚ãūせん: %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>čĶæą‚ã•ã‚ŒãŸãƒĐã‚Īã‚ŧãƒģã‚đ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Error</source> <translation>ã‚ĻãƒĐマ</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>ã‚ĻãƒĐマ: æ“ä―œ %1 ãŊ存åœĻしãūせん。</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>%1 で isDefault をč§Ģæąšã§ããūせん</translation> </message> <message> <source>Update Info: </source> <translation>æ›īæ–°æƒ…å ą: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>ã‚ģãƒģポマネãƒģトがã‚Īãƒģã‚đトマãƒŦåŊū蹥ãĻしãĶママã‚ŊされãĶいãūす。</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>ã‚ģãƒģポマネãƒģトがã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦåŊū蹥ãĻしãĶママã‚ŊされãĶいãūす。</translation> </message> <message> <source>Component is installed.</source> <translation>ã‚ģãƒģポマネãƒģトがã‚Īãƒģã‚đトマãƒŦされãĶいãūす。</translation> </message> <message> <source>Component is not installed.</source> <translation>ã‚ģãƒģポマネãƒģトがã‚Īãƒģã‚đトマãƒŦされãĶいãūせん。</translation> </message> <message> <source>Component Name</source> <translation>ã‚ģãƒģポマネãƒģト名</translation> </message> <message> <source>Action</source> <translation>ã‚Ēã‚Ŋショãƒģ</translation> </message> <message> <source>Installed Version</source> <translation>ã‚Īãƒģã‚đトマãƒŦæļˆãŋバマã‚ļョãƒģ</translation> </message> <message> <source>New Version</source> <translation>新čĶãƒãƒžã‚ļョãƒģ</translation> </message> <message> <source>Release Date</source> <translation>ナナマã‚đæ—Ĩ</translation> </message> <message> <source>Size</source> <translation>ã‚ĩã‚Ī゚</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt + A</translation> </message> <message> <source>Def&ault</source> <translation>デフã‚ĐãƒŦト (&A)</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt + R</translation> </message> <message> <source>&Reset</source> <translation>ナã‚ŧット(&R)</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt + S</translation> </message> <message> <source>&Select All</source> <translation>すãđãĶéļ択(&S)</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt + D</translation> </message> <message> <source>&Deselect All</source> <translation>すãđãĶéļ択č§Ģé™Ī (&D)</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>圧įļŪされたナポã‚ļトナを新čĶãŦã‚Īãƒģã‚đトマãƒŦするãŦãŊ、おä―ŋいãŪã‚ģãƒģピãƒĨマã‚ŋãƒžã‚’å‚į…§ã—ãĶčĐēå―“ã™ã‚‹ãƒŠãƒã‚ļトナをéļ択しãūす。</translation> </message> <message> <source>&Browse QBSP files</source> <translation>QBSP ãƒ•ã‚Ąã‚ĪãƒŦãŪå‚į…§ (&B)</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>こãŪã‚ģãƒģポマネãƒģトãŊハマド デã‚Ģã‚đã‚Ŋ ドãƒĐã‚ĪブãŪįī„ %1 を占有しãūす。</translation> </message> <message> <source>Open File</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦを開く</translation> </message> <message> <source>Select Components</source> <translation>ã‚ģãƒģポマネãƒģトãŪéļ択</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>æ›ī新するã‚ģãƒģポマネãƒģトをéļ択しãĶください。</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>ã‚Īãƒģã‚đトマãƒŦするã‚ģãƒģポマネãƒģトをéļ択しãĶください。</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦするã‚ģãƒģポマネãƒģトをéļ択しãĶください。</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>ã‚Īãƒģã‚đトマãƒŦするã‚ģãƒģポマネãƒģトをéļ択しãūす。 ã‚ģãƒģポマネãƒģトをã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦするãŦãŊ、ã‚Īãƒģã‚đトマãƒŦæļˆãŋãŪã‚ģãƒģポマネãƒģトをéļ択č§Ģé™Īしãūす。 すでãŦã‚Īãƒģã‚đトマãƒŦされãĶいるã‚ģãƒģポマネãƒģトãŊæ›ī新されãūせん。</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><äŋå­˜åŊū蹥ãŪã‚Īãƒģã‚đトマãƒĐマãŪキマ名> <åŪŸčĄŒåŊčƒ―ãƒ•ã‚Ąã‚ĪãƒŦ> [垕数 1] [垕数 2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>%1 æ“ä―œãŦåŋ…čĶãŠã‚Īãƒģã‚đトマãƒĐマ りブã‚ļェã‚ŊトがįĐšã§ã™ã€‚</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>"%1" ãŪ凚力をįĐšãŪã‚Īãƒģã‚đトマãƒĐマ キマå€ĪãŦäŋå­˜ã§ããūせん。</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŊ存åœĻしおいか、åŪŸčĄŒåŊčƒ―ãŠãƒã‚Īナナ ãƒ•ã‚Ąã‚ĪãƒŦでãŊありãūせん。</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>"%1" をåŪŸčĄŒã—ãŸįĩæžœã€ã‚ŊãƒĐッシãƒĨãŒį™šį”Ÿã—ãūした。</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><ã‚―ãƒžã‚đ> <ã‚ŋマã‚ēット> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>%1 ãŪåž•æ•°ãŒį„ĄåŠđです: 3 į•Šį›ŪãŪ垕数を指åŪšã™ã‚‹å ī合ãŊ、forceOverwrite ãŦするåŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>%1 ãŪåž•æ•°ãŒį„ĄåŠđです: デã‚Ģノã‚Ŋトナ "%2" ãŊ有åŠđでありãūせん。</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん。</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>"%1" をä›ļきできãūせんでした。</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦã‚ģピマできãūせん: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん。</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>ã‚ŋã‚đã‚Ŋ ã‚Ēã‚Īãƒ†ãƒ æ•°ãŒį„ĄåŠđです。</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãļãŪæ›ļきčūžãŋができãūせんでした: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" をä›ļきできãūせんでした。</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>デã‚đã‚Ŋトップ ã‚Ļãƒģトナマを "%1" ãŦæ›ļきčūžã‚ãūせん。</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>"%1" から "%2" ãļãŪナãƒģã‚Ŋã‚’ä―œæˆã§ããūせん。</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>"%1" から "%2" ãļãŪナãƒģã‚Ŋを削é™Īできãūせん。</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪæĻĐ限をčĻ­åŪšã§ããūせん。</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦį§ŧ動できãūせん: %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>"%1" ãŪã‚Īãƒģã‚đトマãƒĐマをりフãƒĐã‚ĪãƒģãŦするåŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん。</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ã‚’čŠ­ãŋ取れãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>ã‚ŋマã‚ēット デã‚Ģノã‚ŊãƒˆãƒŠã‚’ä―œæˆã§ããūせん: "%1"</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>äļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした: %1</translation> </message> <message> <source>Removing file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™ĪしãĶいãūす。</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん。</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" を削é™Īできãūせん: %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><ã‚ŋマã‚ēット> <ナãƒģã‚Ŋä―į―Ū> [ã‚ŋマã‚ēット垕数] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>"%1" をä›ļきできãūせんでした: %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>ナãƒģã‚Ŋ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>キãƒĢãƒģã‚ŧãƒŦ</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>ハッシãƒĨ シグネチãƒĢをダã‚Ķãƒģロマドできãūせんでした。</translation> </message> <message> <source>Download Error</source> <translation>ダã‚Ķãƒģロマド ã‚ĻãƒĐマ</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>ダã‚Ķãƒģロマドäļ­ãŦハッシãƒĨをæĪœčĻžã§ããūせんでした。 これãŊä™‚įš„ãŠã‚ĻãƒĐマです。再čĐĶčĄŒã—ãĶください。</translation> </message> <message> <source>Cannot verify Hash</source> <translation>ハッシãƒĨをæĪœčĻžã§ããūせん</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>ã‚Ēマã‚Ŧã‚Īブ %1 をダã‚Ķãƒģロマドできãūせん: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>ã‚Ēマã‚Ŧã‚Īブを取åū—できãūせん: %1 %2 ãŪ芭ãŋčūžãŋäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>ã‚ģãƒģポマネãƒģト %2 ãŪã‚Ēマã‚Ŧã‚Īブ "%1" をダã‚ĶãƒģロマドしãĶいãūす。</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>ã‚đキママ %1 ãŊã‚ĩポマトされãĶいãūせん (URL: %2)。</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>%1 į”ĻãŪã‚ģãƒģポマネãƒģトがčĶ‹ãĪかりãūせん。</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>ã‚ŋマã‚ēット ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŊすでãŦ存åœĻしãūã™ãŒã€ãƒ•ã‚Ąã‚ĪãƒŦでãŊありãūせん。</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" が開けãūせん: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãļãŪæ›ļきčūžãŋができãūせんでした: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>"%1" でナダã‚Īノã‚Ŋト ãƒŦマプがæĪœå‡šã•れãūした。</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>"%1" でチェッã‚Ŋã‚ĩムãŪäļäļ€č‡īがæĪœå‡šã•れãūした。</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>'%1' ãŪダã‚Ķãƒģロマドäļ­ãŦネットãƒŊマã‚Ŋ ã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした: %2</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>"%1" ãŪダã‚Ķãƒģロマドäļ­ãŦäļæ˜ŽãŠãƒãƒƒãƒˆãƒŊマã‚Ŋ ã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Network transfers canceled.</source> <translation>ネットãƒŊマã‚ŊčŧĒ送がキãƒĢãƒģã‚ŧãƒŦされãūした。</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>ネットãƒŊマã‚ŊčŧĒ送でãŊä™‚停æ­ĒãĻ再開ができãūせん。</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>ã‚―ãƒžã‚đ URL "%1" ãŊį„ĄåŠđです: %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>デã‚ŋッチを開始できãūせん: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>開始できãūせん: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>プログãƒĐムがã‚ŊãƒĐッシãƒĨしãūした: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>åŪŸčĄŒã§ããūせんでした (䚈期しおいįĩ‚䚆ã‚ģマド: %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪã‚Ēマã‚Ŧã‚Īブ "%1" を開けãūせん: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" ãŪæŠ―å‡šäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした: %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>"%1" ãŪæŠ―å‡šäļ­ãŦäļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした。</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>ãƒ‘ãƒƒã‚ąãƒžã‚ļ マネマã‚ļãƒĢマ ã‚ģã‚Ēを取åū—できãūせん。</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>こãŪå‡Ķį†ã‚’įĩ‚䚆しãĶã‹ã‚‰æŽĄãŦé€ēんでください: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>これらãŪå‡Ķį†ã‚’įĩ‚䚆しãĶã‹ã‚‰æŽĄãŦé€ēんでください: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1/%2</translation> </message> <message> <source>%1 received.</source> <translation>%1 を受äŋĄã—ãūした。</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/į§’)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n æ—Ĩ、 </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n 時間、 </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n 分</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n į§’</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - æŪ‹ã‚Š %1%2%3%4</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - æŪ‹ã‚Šæ™‚é–“äļæ˜Ž</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>%1 ã‚Ķã‚Ģã‚ķマドをåŪŒäš†ã—ãĶいãūす</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>%2 ã‚Ķã‚Ģã‚ķマドをįĩ‚䚆するãŦãŊ、%1 をã‚Ŋナッã‚Ŋしãūす。</translation> </message> <message> <source>Restart</source> <translation>再čĩ·å‹•</translation> </message> <message> <source>Run %1 now.</source> <translation>äŧŠã™ã %1 をåŪŸčĄŒã—ãūす。</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>%1 ã‚Ķã‚Ģã‚ķマドがæ­ĢåļļãŦåŪŸčĄŒã•ã‚Œãūせんでした。</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>čĻ­åۚãŊæ›ļきčūžãŋäļåŊです。</translation> </message> <message> <source>Failed to write settings.</source> <translation>čĻ­åۚãŦæ›ļきčūžã‚ãūせんでした。</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><ã‚―ãƒžã‚đ パã‚đ> [ベãƒģダマãŪæŽĨé ­čūž]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>åž•æ•°ãŒį„ĄåŠđです: ã‚―ãƒžã‚đ デã‚Ģノã‚ŊトナをįĐšãŦするこãĻãŊできãūせん。</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŪバッã‚Ŋã‚Ēãƒƒãƒ—ã‚’ä―œæˆã§ããūせん: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>"%1" をä›ļきできãūせんでした: %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" をã‚ģピマできãūせんでした: %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>デã‚Ģノã‚Ŋトナ "%1" ã‚’ä―œæˆã§ããūせん: %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>čĻ­åۚ - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>%1 čĻ­åۚã‚Ķã‚Ģã‚ķマドãļようこそ。</translation> </message> <message> <source>&Add or remove components</source> <translation>ã‚ģãƒģポマネãƒģトãŪčŋ―加ãūたãŊ削é™Ī</translation> </message> <message> <source>&Update components</source> <translation>ã‚ģãƒģポマネãƒģトãŪæ›ī新</translation> </message> <message> <source>&Remove all components</source> <translation>すãđãĶãŪã‚ģãƒģポマネãƒģトを削é™Ī</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>ナãƒĒマト ã‚Īãƒģã‚đトマãƒŦ ã‚―ãƒžã‚đã‹ã‚‰æƒ…å ąã‚’å–åū—しãĶいãūす...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>こãŪæ“ä―œã‚’æ­ĢåļļãŦåŪŸčĄŒã™ã‚‹ãŦãŊ、有åŠđおナポã‚ļトナが 1 ãĪäŧĨäļŠåŋ…čĶã§ã™ã€‚</translation> </message> <message> <source>No updates available.</source> <translation>åˆĐį”Ļできるæ›ī新ãŊありãūせん。</translation> </message> <message> <source> Only local package management available.</source> <translation> ロマã‚ŦãƒŦ ãƒ‘ãƒƒã‚ąãƒžã‚ļįŪĄį†ãŪãŋåˆĐį”ĻåŊčƒ―ã§ã™ã€‚</translation> </message> <message> <source>&Quit</source> <translation>äļ­æ­Ē</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>ä―ŋį”ĻčĻąčŦūåĨ‘įī„</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt + A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt + D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>æŽĄãŪä―ŋį”ĻčĻąčŦūåĨ‘įī„ã‚’ãŠčŠ­ãŋください。 ã‚Īãƒģã‚đトマãƒŦå‡ĶᐆãŦé€ēむ前ãŦ、こãŪåĨ‘įī„ãŦčĻ˜čž‰ã•ã‚ŒãŸåˆĐį”ĻæĄäŧķãŦ同意するåŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>I accept the license.</source> <translation>ä―ŋį”ĻčĻąčŦūãŦ同意しãūす。</translation> </message> <message> <source>I do not accept the license.</source> <translation>ä―ŋį”ĻčĻąčŦūãŦ同意しãūせん。</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>æŽĄãŪä―ŋį”ĻčĻąčŦūåĨ‘įī„ã‚’ãŠčŠ­ãŋください。 ã‚Īãƒģã‚đトマãƒŦå‡ĶᐆãŦé€ēむ前ãŦ、これらãŪåĨ‘įī„ãŦčĻ˜čž‰ã•ã‚ŒãŸåˆĐį”ĻæĄäŧķãŦ同意するåŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>I accept the licenses.</source> <translation>ä―ŋį”ĻčĻąčŦūãŦ同意しãūす。</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>ä―ŋį”ĻčĻąčŦūãŦ同意しãūせん。</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>ã‚ģピマåŊū蹥ãŪãƒĐã‚Īã‚ŧãƒģã‚đ ãƒ•ã‚Ąã‚ĪãƒŦがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>%1 æ“ä―œãŦåŋ…čĶãŠã‚Īãƒģã‚đトマãƒĐマ りブã‚ļェã‚ŊトがįĐšã§ã™ã€‚</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>ãƒĐã‚Īã‚ŧãƒģã‚đ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" ãŦæ›ļきčūžã‚ãūせん</translation> </message> <message> <source>No license files found to delete.</source> <translation>削é™ĪåŊū蹥ãŪãƒĐã‚Īã‚ŧãƒģã‚đ ãƒ•ã‚Ąã‚ĪãƒŦがčĶ‹ãĪかりãūせん。</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>ãƒ‘ãƒƒã‚ąãƒžã‚ļ マネマã‚ļãƒĢマ ã‚ģã‚Ē ã‚Ļãƒģã‚ļãƒģがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Preparing meta information download...</source> <translation>ãƒĄã‚ŋæƒ…å ąãŪダã‚Ķãƒģロマドを暖備しãĶいãūす...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>圧įļŪされたナポã‚ļトナをč§Ģ凍しãĶいãūす。 しばらくおåū…ãĄãã ã•ã„...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>ãƒĄã‚ŋ デマã‚ŋãŪダã‚ĶãƒģロマドがキãƒĢãƒģã‚ŧãƒŦされãūした。</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>æŠ―å‡šäļ­ãŦäļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>ãƒ—ãƒ­ã‚­ã‚·čŠčĻžæƒ…å ąãŒčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Authentication failed.</source> <translation>詍čĻžãŦåĪąæ•—ã—ãūした。</translation> </message> <message> <source>Unknown exception during download.</source> <translation>ダã‚Ķãƒģロマドäļ­ãŦäļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>ナポã‚ļトナを取åū—できãūせん。</translation> </message> <message> <source>Extracting meta information...</source> <translation>ãƒĄã‚ŋæƒ…å ąã‚’å–åū—しãĶいãūす...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>ナãƒĒマト ナポã‚ļãƒˆãƒŠã‹ã‚‰ãƒĄã‚ŋæƒ…å ąã‚’å–åū—しãĶいãūす... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>ナãƒĒマト ナポã‚ļãƒˆãƒŠã‹ã‚‰ãƒĄã‚ŋæƒ…å ąã‚’å–åū—しãĶいãūす... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" ãŪæŠ―å‡šäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした: %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>ã‚Ēマã‚Ŧã‚Īブ "%1" ãŪæŠ―å‡šäļ­ãŦäļæ˜ŽãŠäū‹åĪ–ãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦãļãŪæ›ļきčūžãŋäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした</translation> </message> <message> <source> Downloading packages...</source> <translation> ãƒ‘ãƒƒã‚ąãƒžã‚ļをダã‚ĶãƒģロマドしãĶいãūす...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>ãƒĶマã‚ķマがã‚Īãƒģã‚đトマãƒŦをキãƒĢãƒģã‚ŧãƒŦしãūした。</translation> </message> <message> <source>All downloads finished.</source> <translation>ダã‚ĶãƒģロマドがすãđãĶįĩ‚䚆しãūした。</translation> </message> <message> <source>Cancelling the Installer</source> <translation>ã‚Īãƒģã‚đトマãƒĐマをキãƒĢãƒģã‚ŧãƒŦしãĶいãūす</translation> </message> <message> <source>Authentication Error</source> <translation>詍čĻžã‚ĻãƒĐマ</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>įŪĄį†č€…æĻĐ限を取åū—できおかãĢたため、äļ€éƒĻãŪã‚ģãƒģポマネãƒģトを削é™Īできãūせんでした: %1</translation> </message> <message> <source>Unknown error.</source> <translation>äļæ˜ŽãŠã‚ĻãƒĐマです。</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>äļæ˜ŽãŠã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãŸãŸã‚ã€äļ€éƒĻãŪã‚ģãƒģポマネãƒģトを削é™Īできãūせんでした。</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>ã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģãŒãƒ‘ãƒƒã‚ąãƒžã‚ļ マネマã‚ļãƒĢマ ãƒĒマドでåŪŸčĄŒã•ã‚ŒãĶいãūせん。</translation> </message> <message> <source>No installed packages found.</source> <translation>ã‚Īãƒģã‚đトマãƒŦã•ã‚ŒãŸãƒ‘ãƒƒã‚ąãƒžã‚ļがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>ã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģがã‚Ēãƒģã‚Īãƒģã‚đトマãƒĐマ ãƒĒマドでåŪŸčĄŒã•ã‚ŒãĶいãūす。</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>重čĶãŠæ›ī新がありãūす。最初ãŦã‚Ēップデマã‚ŋマをåŪŸčĄŒã—ãĶください。</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>äļ€éƒĻãŪäūå­˜é–Ēäŋ‚ã‚’č§Ģæąšã§ããūせん。</translation> </message> <message> <source>Components about to be removed.</source> <translation>ã‚ģãƒģポマネãƒģトを削é™ĪしようãĻしãĶいãūす。</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>ã‚Ēã‚Ŋã‚ŧã‚đæĻĐ限ãŪ昇栞äļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Error</source> <translation>ã‚ĻãƒĐマ</translation> </message> <message> <source>invalid</source> <translation>į„ĄåŠđ</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>äūå­˜é–Ēäŋ‚が朊č§Ģæąšã§ã™</translation> </message> <message> <source>Error</source> <translation>ã‚ĻãƒĐマ</translation> </message> <message> <source>Access error</source> <translation>ã‚Ēã‚Ŋã‚ŧã‚đ ã‚ĻãƒĐマ</translation> </message> <message> <source>Format error</source> <translation>フã‚Đママット ã‚ĻãƒĐマ</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>ã‚Īãƒģã‚đトマãƒĐマãŪ構成を %1 ãŦæ›ļきčūžã‚ãūせん: %2</translation> </message> <message> <source>Stop Processes</source> <translation>å‡ĶᐆãŪįĩ‚䚆</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>æŽĄãŦé€ēむãŦãŊ、これらãŪå‡Ķį†ã‚’įĩ‚䚆するåŋ…čĶãŒã‚ã‚Šãūす: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>ãƒĶマã‚ķマがã‚Īãƒģã‚đトマãƒŦをキãƒĢãƒģã‚ŧãƒŦしãūした</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦãŪデマã‚ŋをæ›ļきčūžã‚“でいãūす。</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ %1 ãŪシマã‚Ŋができãūせんでした: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦがバãƒģドãƒŦでãŊありãūせん</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>デマã‚ŋ ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を削é™Īできãūせん: %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦãŪデマã‚ŋを %1 ãŦæ›ļきčūžã‚ãūせん: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦãŪデマã‚ŋを "%1" ãŦæ›ļきčūžã‚ãūせん: %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦãŪバã‚Īナナ デマã‚ŋを %1 ãŦæ›ļきčūžã‚ãūせん: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>åĪ‰æ•° 'TargetDir' がčĻ­åŪšã•ã‚ŒãĶいãūせん。</translation> </message> <message> <source>Preparing the installation...</source> <translation>ã‚Īãƒģã‚đトマãƒŦを暖備しãĶいãūす...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>ネットãƒŊマã‚Ŋ ãƒ­ã‚ąãƒžã‚·ãƒ§ãƒģからã‚Īãƒģã‚đトマãƒŦできãūせん。</translation> </message> <message> <source>Creating local repository</source> <translation>ロマã‚ŦãƒŦ ナポã‚ļãƒˆãƒŠã‚’ä―œæˆã—ãĶいãūす</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>äŋåŪˆãƒ„ãƒžãƒŦã‚’ä―œæˆã—ãĶいãūす</translation> </message> <message> <source> Installation finished!</source> <translation> ã‚Īãƒģã‚đトマãƒŦがįĩ‚䚆しãūした。</translation> </message> <message> <source> Installation aborted!</source> <translation> ã‚Īãƒģã‚đトマãƒŦがäļ­æ­Ēされãūした。</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>こãŪæ“ä―œã‚’ãƒãƒƒãƒˆãƒŊマã‚Ŋ ãƒ­ã‚ąãƒžã‚·ãƒ§ãƒģからåŪŸčĄŒã§ããūせん。</translation> </message> <message> <source>Removing deselected components...</source> <translation>éļ択č§Ģé™Īしたã‚ģãƒģポマネãƒģトを削é™ĪしãĶいãūす...</translation> </message> <message> <source> Update finished!</source> <translation> æ›ī新がįĩ‚䚆しãūした。</translation> </message> <message> <source> Update aborted!</source> <translation> æ›ī新がäļ­æ­Ēされãūした。</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦがæ­ĢåļļãŦåŪŒäš†ã—ãūした。</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦがäļ­æ­Ēされãūした。</translation> </message> <message> <source> Installing component %1</source> <translation> ã‚ģãƒģポマネãƒģト %1 をã‚Īãƒģã‚đトマãƒŦしãĶいãūす</translation> </message> <message> <source>Installer Error</source> <translation>ã‚Īãƒģã‚đトマãƒĐマãŪã‚ĻãƒĐマ</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>ã‚Īãƒģã‚đトマãƒŦå‡Ķᐆäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした (%1): %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦを暖備できãūせん</translation> </message> <message> <source>Cannot start uninstall</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦを開始できãūせん</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦå‡Ķᐆäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした: %1</translation> </message> <message> <source>Unknown error</source> <translation>原因äļæ˜ŽãŪã‚ĻãƒĐマ</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>ナãƒĒマト ツナマ %1 を取åū—できãūせん。</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>%1 ã‹ã‚‰ãƒ‘ãƒƒã‚ąãƒžã‚ļã‚’čŠ­ãŋ取れãūせん。</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>ãƒĄã‚ŋæƒ…å ąã‚’å–åū—できãūせん: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>ä™‚įš„ãŠæ›īæ–°ã‚―ãƒžã‚đæƒ…å ąã‚’čŋ―加できãūせん。</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>æ›īæ–°ã‚―ãƒžã‚đæƒ…å ąãŒčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>ã‚ģãƒģポマネãƒģト "%1" ãĻ "%2" ãĻãŪäūå­˜ã‚ĩã‚Īã‚ŊãƒŦがæĪœå‡šã•れãūした。</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>%1 čĻ­åۚ</translation> </message> <message> <source>Maintain %1</source> <translation>%1 ãŪäŋåۈ</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>ã‚Īãƒģã‚đトマãƒŦå‡Ķį†ã‚’ã‚­ãƒĢãƒģã‚ŧãƒŦしãūすか</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦå‡Ķį†ã‚’ã‚­ãƒĢãƒģã‚ŧãƒŦしãūすか</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>ã‚Īãƒģã‚đトマãƒĐマ ã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģをįĩ‚䚆しãūすか</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒĐマ ã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģをįĩ‚䚆しãūすか</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>äŋåۈã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģをįĩ‚䚆しãūすか</translation> </message> <message> <source>%1 Question</source> <translation>%1 čģŠå•</translation> </message> <message> <source>Settings</source> <translation>čĻ­åۚ</translation> </message> <message> <source>Error</source> <translation>ã‚ĻãƒĐマ</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>ネットãƒŊマã‚Ŋ ãƒ­ã‚ąãƒžã‚·ãƒ§ãƒģからã‚Īãƒģã‚đトマãƒŦできãūせん。 ã‚Īãƒģã‚đトマãƒĐマをロマã‚ŦãƒŦ ドãƒĐã‚ĪブãŦã‚ģピマしãĶください。</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>čĐģįī°ãŪčĄĻįĪš (&S)</translation> </message> <message> <source>&Hide Details</source> <translation>čĐģįī°ãŪ非čĄĻįĪš (&H)</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦ (&N)</translation> </message> <message> <source>Uninstalling %1</source> <translation>%1 をã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦしãĶいãūす</translation> </message> <message> <source>&Update</source> <translation>æ›ī新 (&U)</translation> </message> <message> <source>Updating components of %1</source> <translation>%1 ãŪã‚ģãƒģポマネãƒģトをæ›ī新しãĶいãūす</translation> </message> <message> <source>&Install</source> <translation>ã‚Īãƒģã‚đトマãƒŦ(&I)</translation> </message> <message> <source>Installing %1</source> <translation>%1 をã‚Īãƒģã‚đトマãƒŦしãĶいãūす</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>ダã‚Īã‚Ēログ</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>プロキシ %1 ãŦãŊ、ãƒĶマã‚ķマ名ãĻパã‚đãƒŊマドがåŋ…čĶã§ã™ã€‚</translation> </message> <message> <source>Username:</source> <translation>ãƒĶマã‚ķマ名:</translation> </message> <message> <source>Username</source> <translation>ãƒĶマã‚ķマ名</translation> </message> <message> <source>Password:</source> <translation>パã‚đãƒŊマド:</translation> </message> <message> <source>Password</source> <translation>パã‚đãƒŊマド</translation> </message> <message> <source>Proxy Credentials</source> <translation>ãƒ—ãƒ­ã‚­ã‚·čŠčĻžæƒ…å ą</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦ (&N)</translation> </message> <message> <source>Ready to Uninstall</source> <translation>ã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦãŪ暖備ができãūした</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>ã‚ģãƒģピãƒĨマã‚ŋマから %1 を削é™Īする暖備がæ•īãĢãĶいãūす。<br><font color="red">プログãƒĐム デã‚Ģノã‚Ŋトナ %2 がåیå…ĻãŦ削é™Īされãūす</font>。こãŪデã‚Ģノã‚Ŋトナ内ãŪã‚ģãƒģテãƒģツもすãđãĶ削é™Īされãūす。</translation> </message> <message> <source>U&pdate</source> <translation>æ›ī新 (&P)</translation> </message> <message> <source>Ready to Update Packages</source> <translation>ãƒ‘ãƒƒã‚ąãƒžã‚ļをæ›ī新する暖備ができãūした</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>ã‚Īãƒģã‚đトマãƒŦをæ›ī新する暖備がæ•īãĢãĶいãūす。</translation> </message> <message> <source>&Install</source> <translation>ã‚Īãƒģã‚đトマãƒŦ(&I)</translation> </message> <message> <source>Ready to Install</source> <translation>ã‚Īãƒģã‚đトマãƒŦãŪ暖備ができãūした</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>ã‚ģãƒģピãƒĨマã‚ŋマãŦ %1 をã‚Īãƒģã‚đトマãƒŦする暖備がæ•īãĢãĶいãūす。</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>十分おデã‚Ģã‚đã‚ŊįĐšãåŪđ量がおいため、ä™‚ãƒ•ã‚Ąã‚ĪãƒŦãĻã‚Īãƒģã‚đトマãƒŦ内åŪđã‚’æ žįīã§ããūせん。%2 ãŒæœ€ä―Žé™åŋ…čĶãŠå ī合ãŊ、%1 をåˆĐį”Ļできãūす。</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>十分おデã‚Ģã‚đã‚ŊįĐšãåŪđ量がおいため、éļ択されたäļ€éƒĻãŪã‚ģãƒģポマネãƒģトを栞įīã§ããūせん。 %2 ãŒæœ€ä―Žé™åŋ…čĶãŠå ī合ãŊ、%1 をåˆĐį”Ļできãūす。</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>十分おデã‚Ģã‚đã‚ŊįĐšãåŪđ量がおいため、ä™‚ãƒ•ã‚Ąã‚ĪãƒŦã‚’æ žįīã§ããūせん。 %2 ãŒæœ€ä―Žé™åŋ…čĶãŠå ī合ãŊ、%1 をåˆĐį”Ļできãūす。</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>ã‚Īãƒģã‚đトマãƒŦį”ĻãŦéļ択したボナãƒĨマムãŦãŊ、ã‚Īãƒģã‚đトマãƒŦできるだけãŪåŪđ量ãŊありãūすが、ã‚Īãƒģã‚đトマãƒŦåūŒãŦそãŪボナãƒĨマムãŪįĐšãåŪđ量ãŊ 1 % 朊暀ãŦおりãūす。%1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>ã‚Īãƒģã‚đトマãƒŦį”ĻãŦéļ択したボナãƒĨマムãŦãŊ、ã‚Īãƒģã‚đトマãƒŦできるだけãŪåŪđ量ãŊありãūすが、ã‚Īãƒģã‚đトマãƒŦåūŒãŪįĐšãåŪđ量ãŊ 100 MB 朊暀ãŦおりãūす。%1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>デã‚Ģã‚đã‚ŊįĐšãåŪđ量ãŪ %1 がã‚Īãƒģã‚đトマãƒŦãŦä―ŋį”Ļされãūす。</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><ã‚Ļã‚Ŋã‚đテãƒģショãƒģ> <ã‚ģマãƒģド> [čŠŽæ˜Ž [contentType [ã‚Ēã‚Īã‚ģãƒģ]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ ã‚ŋã‚ĪプãŪį™ŧéŒēãŊ Windows でãŪãŋåŪŸčĄŒã§ããūす。</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ ã‚ŋã‚ĪプãŪį™ŧéŒē: åž•æ•°ãŒį„ĄåŠđです</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>ã‚ģマãƒģドを送äŋĄã—たåūŒã§äļ€éƒĻãŪデマã‚ŋã‚’čŠ­ãŋ取れãūせん: %1。 䚈æƒģされるバã‚Īト: %2、受äŋĄã•れたバã‚Īト: %3。 ã‚ĻãƒĐマ: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>æ›ļきčūžãŋį”ĻãŪãƒ•ã‚Ąã‚ĪãƒŦ "%1" を開けãūせん: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>芭ãŋ取りį”ĻãŪãƒŠã‚―ãƒžã‚đ "%1" を開けãūせん。</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>%1 バã‚ĪトäŧĨ降ãŪ芭ãŋ取りができãūせんでした: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>%1 バã‚ĪトäŧĨ降ãŪæ›ļきčūžãŋができãūせんでした: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>%1 čĻ­åۚã‚Ķã‚Ģã‚ķマドをåŪŒäš†ã—ãĶいãūす</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>%1 でã‚đã‚Ŋナプト ãƒ•ã‚Ąã‚ĪãƒŦを開けãūせん: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>ã‚ģãƒģポマネãƒģト ã‚đã‚Ŋナプト "%1" ãŪ芭ãŋčūžãŋäļ­ãŦäū‹åĪ–ãŒį™šį”Ÿã—ãūした: %2</translation> </message> <message> <source>Unknown error.</source> <translation>äļæ˜ŽãŠã‚ĻãƒĐマです。</translation> </message> <message> <source>on line number: </source> <translation>ã‚ĻãƒĐマがæĪœå‡šã•ã‚ŒãŸčĄŒį•Šå·: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>æ“ä―œ %1 ãŦåŋ…čĶãŠã‚Īãƒģã‚đトマãƒĐマ りブã‚ļェã‚ŊトがįĐšã§ã™ã€‚</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>č‡Šå‹•å†čĩ·å‹•: ã‚Ēップデマã‚ŋマãūたãŊãƒ‘ãƒƒã‚ąãƒžã‚ļ マネマã‚ļãƒĢマ ãƒĒマド内でãŪãŋ有åŠđです。</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>č‡Šå‹•å†čĩ·å‹•: åž•æ•°ãŒį„ĄåŠđです</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>ã‚ĩマバマãŦãŊ詍čĻžãŒåŋ…čĶã§ã™</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>こãŪã‚ĩã‚ĪトãŦã‚Ēã‚Ŋã‚ŧã‚đするãŦãŊ、ãƒĶマã‚ķマ名ãĻパã‚đãƒŊマドを指åŪšã™ã‚‹åŋ…čĶãŒã‚ã‚Šãūす。</translation> </message> <message> <source>Username:</source> <translation>ãƒĶマã‚ķマ名:</translation> </message> <message> <source>Password:</source> <translation>パã‚đãƒŊマド:</translation> </message> <message> <source>%1 at %2</source> <translation>%2 ãŪ %1</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>垕数 "%3" で %2 を呞ãģ凚す垕数 "%1" がčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>垕数 "%2" で "%1" を呞ãģå‡šã™ãƒĄã‚―ãƒƒãƒ‰ãŪ垕数ãŊįūåœĻã‚ĩポマトされãĶいãūせん。 set、remove、add_array_value、ãūたãŊ remove_array_value をä―ŋį”ĻしãĶください。</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>ãĐãŪ垕数もįĐšãŦするこãĻができãūせん: ã‚―ãƒžã‚đ "%1"、ã‚ŋマã‚ēット "%2"</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>削é™Īできおいã‚ŋマã‚ēット パã‚đが存åœĻã™ã‚‹ãŸã‚ã€ãƒ•ã‚Ąã‚ĪãƒŦを "%1" から "%2" ãŦį§ŧ動できãūせん。</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦį§ŧ動できãūせん: %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ "%1" を "%2" ãŦį§ŧ動しãĶいãūす。</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>ã‚đã‚ŋマト ãƒĄãƒ‹ãƒĨマãŪショマトã‚Ŧット</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>プログãƒĐムãŪショマトã‚Ŧãƒƒãƒˆã‚’ä―œæˆã™ã‚‹ã‚đã‚ŋマト ãƒĄãƒ‹ãƒĨマをéļ択しãūす。 名前をå…Ĩ力しãĶ、新しいデã‚Ģノã‚ŊãƒˆãƒŠã‚’ä―œæˆã™ã‚‹ã“ãĻもできãūす。</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>ã‚Īãƒģã‚đトマãƒŦ フã‚ĐãƒŦダマ</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>%1 をã‚Īãƒģã‚đトマãƒŦするデã‚Ģノã‚Ŋトナを指åŪšã—ãĶください。</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt + R</translation> </message> <message> <source>B&rowse...</source> <translation>å‚į…§(&R)...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>éļ択したデã‚Ģノã‚ŊトナãŊすでãŦ存åœĻし、ã‚Īãƒģã‚đトマãƒŦ内åŪđがåŦãūれãĶいãūす。 åˆĨãŪã‚ŋマã‚ēットをã‚Īãƒģã‚đトマãƒŦį”ĻãŦéļ択しãĶください。</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>įĐšã§ãŠã„æ—Ē存ãŪデã‚Ģノã‚Ŋトナをã‚Īãƒģã‚đトマãƒŦį”ĻãŦéļ択しãūした。 éļ択したデã‚Ģノã‚ŊトナãŊ、こãŪã‚Ēãƒ—ãƒŠã‚ąãƒžã‚·ãƒ§ãƒģãŪã‚Ēãƒģã‚Īãƒģã‚đトマãƒŦ時ãŦåیå…ĻãŦæķˆåŽŧされるãŪでæģĻæ„ã—ãĶください。 ã‚Īãƒģã‚đトマãƒŦãŦåĪąæ•—ã™ã‚‹ã“ãĻもあるため、こãŪデã‚Ģノã‚ŊトナãļãŪã‚Īãƒģã‚đトマãƒŦãŊお勧めしãūせん。 įķščĄŒã—ãūすか</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>æ—Ē存ãŪãƒ•ã‚Ąã‚ĪãƒŦãūたãŊシãƒģボナッã‚Ŋ ナãƒģã‚Ŋをéļ択しãūした。åˆĨãŪã‚ŋマã‚ēットをã‚Īãƒģã‚đトマãƒŦį”ĻãŦéļ択しãĶください。</translation> </message> <message> <source>Select Installation Folder</source> <translation>ã‚Īãƒģã‚đトマãƒŦ フã‚ĐãƒŦダマãŪéļ択</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>ã‚Īãƒģã‚đトマãƒŦ パã‚đをįĐšãŦするこãĻãŊできãūせん。有åŠđおデã‚Ģノã‚Ŋトナを指åŪšã—ãĶください。</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>ã‚Īãƒģã‚đトマãƒŦ パã‚đをį›ļåŊūパã‚đãŦするこãĻãŊできãūせん。įĩķåŊūパã‚đを指åŪšã—ãĶください。</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>パã‚đãūたãŊã‚Īãƒģã‚đトマãƒŦ デã‚Ģノã‚ŊトナãŦ ASCII äŧĨåĪ–ãŪ文字がåŦãūれãĶいãūす。 こãŪ文字ãŊįūåœĻã‚ĩポマトされãĶいãūせん。 åˆĨãŪパã‚đãūたãŊã‚Īãƒģã‚đトマãƒŦ デã‚Ģノã‚Ŋトナをéļ択しãĶください。</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>ã‚Īãƒģã‚đトマãƒŦ デã‚Ģノã‚Ŋトナå…Ļä―“ãŒå‰Šé™ĪされるãŪで、%1 ãļãŪã‚Īãƒģã‚đトマãƒŦãŊできãūせん。</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>å…Ĩ力したパã‚đãŊ長すぎãūす。有åŠđおパã‚đを指åŪšã—ãĶください。</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>å…Ĩ力したパã‚đãŊį„ĄåŠđです。有åŠđおã‚ŋマã‚ēットを指åŪšã—ãĶください。</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>å…Ĩ力したパã‚đãŊį„ĄåŠđです。有åŠđおドãƒĐã‚Īブを指åŪšã—ãĶください。</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>ã‚Īãƒģã‚đトマãƒŦ パã‚đを '.' でįĩ‚䚆するこãĻãŊできãūせん。有åŠđおデã‚Ģノã‚Ŋトナを指åŪšã—ãĶください。</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>ã‚Īãƒģã‚đトマãƒŦ パã‚đãŦ "%1" をåŦめるこãĻãŊできãūせん。有åŠđおデã‚Ģノã‚Ŋトナを指åŪšã—ãĶください。</translation> </message> <message> <source>Warning</source> <translation>č­Ķ告</translation> </message> <message> <source>Error</source> <translation>ã‚ĻãƒĐマ</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>ãƒ‘ãƒƒã‚ąãƒžã‚ļ マネマã‚ļãƒĢマ ã‚ģã‚Ē ã‚Ļãƒģã‚ļãƒģがčĶ‹ãĪかりãūせん。</translation> </message> <message> <source>Empty repository URL.</source> <translation>ナポã‚ļトナãŪ URL がįĐšã§ã™ã€‚</translation> </message> <message> <source>Download canceled.</source> <translation>ダã‚ĶãƒģロマドがキãƒĢãƒģã‚ŧãƒŦされãūした。</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>ナポã‚ļトナ "%1" ãŪテã‚đトäļ­ãŦã‚ŋã‚Īムã‚Ēã‚ĶãƒˆãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Updates.xml をč§Ģ析できãūせん: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>芭ãŋ取りį”ĻãŪ Updates.xml を開けãūせん: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>詍čĻžãŦåĪąæ•—ã—ãūした。</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>ナポã‚ļトナ "%1" ãŪテã‚đトäļ­ãŦäļæ˜ŽãŠã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした。</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>詍čĻžãŒåŋ…čĶã§ã™</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>sudo ãŪ詍čĻžã‚’čĄŒã†ãƒ‘ã‚đãƒŊマドをå…Ĩ力しãūす:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>įŪĄį†č€…æĻĐ限ãŪ取åū—äļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>詍čĻžã‚’å–åū—できãūせん。</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>ã‚Īãƒģã‚đトマãƒŦãŪįķščĄŒãŦåŋ…čĶãŠčŠčĻžã‚’å–åū—できãūせん。 éĐ切おæĻĐ限を持ãĪãƒĶマã‚ķマãĻしãĶčĻ­åŪšãƒ—ãƒ­ã‚°ãƒĐムを開始しãĶください。 ãūた、čĶæą‚ã•ã‚ŒãŸå ī合ãŊ、ã‚Ēã‚Ŋã‚ŧã‚đæĻĐ限ãŪ昇栞をæ‰ŋčŠã—ãūす。</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>ã‚Īãƒģã‚đトマãƒŦãŪįķščĄŒãŦåŋ…čĶãŠčŠčĻžã‚’å–åū—できãūせん。 ã‚Īãƒģã‚đトマãƒŦをäļ­æ­Ēするか、フã‚ĐマãƒŦバッã‚Ŋ ã‚―ãƒŠãƒĨマショãƒģをä―ŋį”ĻするãŦãŊ、éĐ切おæĻĐ限を持ãĪãƒĶマã‚ķマãĻしãĶ %1 をåŪŸčĄŒã—ãĶ [OK] をã‚Ŋナッã‚Ŋしãūす。</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>ãƒŠã‚―ãƒžã‚đ %1 を開けãūせん: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>芭ãŋ取りį”ĻãŪčĻ­åŪšãƒ•ã‚Ąã‚ĪãƒŦ %1 を開けãūせん: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>čĻ­åۚ</translation> </message> <message> <source>Network</source> <translation>ネットãƒŊマã‚Ŋ</translation> </message> <message> <source>No proxy</source> <translation>プロキシおし</translation> </message> <message> <source>System proxy settings</source> <translation>シã‚đテムãŪプロキシčĻ­åۚ</translation> </message> <message> <source>Manual proxy configuration</source> <translation>手動ãŦよるプロキシ構成</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP プロキシ:</translation> </message> <message> <source>Port:</source> <translation>ポマト:</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP プロキシ:</translation> </message> <message> <source>Repositories</source> <translation>ナポã‚ļトナ</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>åŋ…č́ãŦåŋœã˜ãĶã€čŠčĻžį”ĻãŪãƒĶマã‚ķマ名ãĻパã‚đãƒŊマドをčŋ―加しãūす。</translation> </message> <message> <source>Use temporary repositories only</source> <translation>ä™‚įš„ãŠãƒŠãƒã‚ļトナãŪãŋä―ŋį”Ļ</translation> </message> <message> <source>Add</source> <translation>čŋ―加</translation> </message> <message> <source>Remove</source> <translation>削é™Ī</translation> </message> <message> <source>Test</source> <translation>テã‚đト</translation> </message> <message> <source>Show Passwords</source> <translation>パã‚đãƒŊマドãŪčĄĻįĪš</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>取åū—時ãŦナポã‚ļトナをä―ŋį”Ļするå ī合ãŊ、こãŪチェッã‚Ŋボッã‚Ŋã‚đをりãƒģãŦしãūす。</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>ã‚ĩマバマäļŠã§čŠčĻžã‚’čĄŒã†ãƒĶマã‚ķマ名をčŋ―加しãūす。</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>ã‚ĩマバマäļŠã§čŠčĻžã‚’čĄŒã†ãƒ‘ã‚đãƒŊマドをčŋ―加しãūす。</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>有åŠđおナポã‚ļトナをåŦむã‚ĩマバマãŪ URL。</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>こãŪナポã‚ļトナãŪテã‚đトäļ­ãŦã‚ĻãƒĐãƒžãŒį™šį”Ÿã—ãūした。</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>こãŪナポã‚ļトナãŊテã‚đトãŦ合栞しãūした。</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>こãŪナポã‚ļãƒˆãƒŠã‚’į„ĄåŠđãŦしãūすか?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>こãŪナポã‚ļトナを有åŠđãŦしãūすか?</translation> </message> <message> <source>Hide Passwords</source> <translation>パã‚đãƒŊマドãŪ非čĄĻįĪš</translation> </message> <message> <source>Use</source> <translation>ä―ŋį”Ļ</translation> </message> <message> <source>Username</source> <translation>ãƒĶマã‚ķマ名</translation> </message> <message> <source>Password</source> <translation>パã‚đãƒŊマド</translation> </message> <message> <source>Repository</source> <translation>ナポã‚ļトナ</translation> </message> <message> <source>Default repositories</source> <translation>デフã‚ĐãƒŦトãŪナポã‚ļトナ</translation> </message> <message> <source>Temporary repositories</source> <translation>ä™‚įš„ãŠãƒŠãƒã‚ļトナ</translation> </message> <message> <source>User defined repositories</source> <translation>ãƒĶマã‚ķマåۚįūĐãŪナポã‚ļトナ</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>ノã‚ļã‚đトナ パã‚đ %1 ãŦæ›ļきčūžã‚ãūせん。</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>ノã‚ļã‚đトナ パã‚đ %1 ãŊæ›ļきčūžãŋäļåŊです。</translation> </message> <message> <source>exactly %1</source> <translation>%1 ãĻåیå…ĻãŦäļ€č‡ī</translation> </message> <message> <source>at least %1</source> <translation>%1 äŧĨäļŠ</translation> </message> <message> <source>not more than %1</source> <translation>%1 äŧĨäļ‹</translation> </message> <message> <source>%1 or %2</source> <translation>%1 ãūたãŊ %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 ï―ž %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>%1 ãŪåž•æ•°ãŒį„ĄåŠđです: %n 個ãŪ垕数が指åŪšã•ã‚ŒãĶいãūすが、%2 個ãŪ垕数がåŋ…čĶã§ã™ã€‚</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>%1 ãŪåž•æ•°ãŒį„ĄåŠđです: %n 個ãŪ垕数が指åŪšã•ã‚ŒãĶいãūすが、å―Ē垏: %3 で %2 個ãŪ垕数がåŋ…čĶã§ã™ã€‚</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>ãƒ•ã‚Ąã‚ĪãƒŦ名を "%1" から "%2" ãŦåΉæ›īできãūせんでした: %3</translation> </message> </context> </TS> ��������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_pl.ts�����������������������������������������0100777�0000000�0000000�00000303325�13761647206�021027� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 przy %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>Serwer proxy wymaga uwierzytelnienia.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>Nie moÅžna przejść do %1 w celu odczytania danych operacji.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>Nie moÅžna przejść do %1 w celu odczytu bloku zbioru zasobÃģw.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>Nie moÅžna otworzyć metazasobu %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>Nie moÅžna przejść do %1 w celu odczytania liczby osadzonych metadanych.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>Nie moÅžna przejść do %1 w celu odczytu segmentu zbioru zasobÃģw.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Nieoczekiwana niezgodność metazasobÃģw. Odczytano %1, oczekiwano: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>Wymagane uwierzytelnianie HTTP</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>Aby uzyskać dostęp do tej witryny, musisz podać Nazwę uÅžytkownika i Hasło.</translation> </message> <message> <source>Username:</source> <translation>Nazwa uÅžytkownika:</translation> </message> <message> <source>Password:</source> <translation>Hasło:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 przy %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>ŚcieÅžka "%1" istnieje, ale nie jest katalogiem.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nie moÅžna utworzyć katalogu "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>Nie moÅžna pobrać ścieÅžki elementu archiwum %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>Nie moÅžna usunąć istniejącego łącza symbolicznego %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>Nie moÅžna utworzyć łącza symbolicznego w "%1". JuÅž istnieje inne takie łącze.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>Nie moÅžna odczytać wartości docelowej łącza symbolicznego z pliku "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>Nie moÅžna utworzyć łącza symbolicznego w %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Oczekiwanie na %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Inna instancja %1 juÅž działa. Poczekaj, aÅž zakończy działanie, i zamknij ją lub uruchom ponownie system.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Elementy dodano jako zaleÅžności automatyczne:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Elementy dodano jako zaleÅžność dla "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Elementy, ktÃģre rozwiązały zaleÅžności:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Wybrane elementy bez zaleÅžności:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>Wykryto rekurencję, element "%1" został juÅž dodany z przyczyną: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>Nie moÅžna znaleŚć brakującej zaleÅžności "%1" dla "%2".</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Anulowano</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Nie moÅžna znaleŚć kopii zapasowej "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1": %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>Nie moÅžna skopiować nieistniejącego pliku: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nie moÅžna usunąć pliku "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nie moÅžna skopiować pliku "%1" do "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>Nie moÅžna usunąć pliku "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej do "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>Nie moÅžna utworzyć kopii zapasowej pliku "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1": %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Pobieranie zakończone.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>SkrÃģty kryptograficzne nie pasują.</translation> </message> <message> <source>Download canceled.</source> <translation>Pobieranie anulowane.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 z %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>Liczba pobranych: %1.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n d, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n godz., </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n min</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n s</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> — %1%2%3%4 pozostało.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> — nie moÅžna określić pozostałego czasu.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>Nie moÅžna pobrać %1. Zapisywanie do pliku "%2" nie powiodło się: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>Nie moÅžna pobrać %1. Nie moÅžna utworzyć pliku "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 przy %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Åŧądanie uwierzytelnienia anulowano.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Nawiązanie bezpiecznego połączenia nie powiodło się</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Wystąpił błąd podczas nawiązywania połączenia z: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>MoÅže to być problem dotyczący konfiguracji serwera albo ktoś prÃģbuje podszyć się pod serwer.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Jeśli w przeszłości łączono się juÅž z tym serwerem pomyślnie lub jeśli ten serwer jest zaufany, błąd moÅže być tymczasowy i moÅžna sprÃģbować ponownie.</translation> </message> <message> <source>Try again</source> <translation>SprÃģbuj ponownie</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Zapisywanie do pliku "%1" nie powiodło się: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>Nie moÅžna utworzyć katalogu "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Nieznany błąd.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nie moÅžna usunąć katalogu "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nie moÅžna usunąć pliku "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nie moÅžna skopiować pliku "%1" do "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nie moÅžna usunąć pliku "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>Nie moÅžna znaleŚć kopii zapasowej "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>Nie moÅžna przywrÃģcić kopii zapasowej "%1": %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>Nie moÅžna odczytać pliku zasobÃģw "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nie moÅžna usunąć katalogu "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>Katalog nie istnieje.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>Nie moÅžna utworzyć ponownie katalogu "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 rozpoczęto</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>Nie moÅžna zatrzymać %1</translation> </message> <message> <source>Cannot stop task %1</source> <translation>Nie moÅžna zatrzymać zadania %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>Nie moÅžna wstrzymać %1</translation> </message> <message> <source>Cannot pause task %1</source> <translation>Nie moÅžna wstrzymać zadania %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>Nie moÅžna wznowić zadania %1</translation> </message> <message> <source>%1 done</source> <translation>%1 ukończono</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>Nie moÅžna uzyskać dostępu do informacji o pakietach tej aplikacji.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Dla tej aplikacji nie ustawiono Åžadnych ÅšrÃģdeł pakietÃģw.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>Liczba znalezionych aktualizacji: %n.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Trwa pobieranie Updates.xml ze ÅšrÃģdeł aktualizacji.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>Nie moÅžna pobrać ÅšrÃģdła pakietu %1 z "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Pobrano plik(i) Updates.xml file(s) ze ÅšrÃģdeł aktualizacji.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Obliczanie odpowiednich aktualizacji.</translation> </message> <message> <source>Application updates computed.</source> <translation>Aktualizacje aplikacji obliczone.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml zawiera nieprawidłową treść: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>Nie moÅžna odczytać "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Błąd analizy w %1 przy %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Nieoczekiwany element głÃģwny %1, powinno być "Aktualizacje".</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>Brak elementu ApplicationName.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>Brak elementu ApplicationVersion.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Element PackageUpdate bez nazwy</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Element PackageUpdate bez wersji</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Element PackageUpdate bez ReleaseDate</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>kod wewnętrzny: %1</translation> </message> <message> <source>not enough memory</source> <translation>za mało pamięci</translation> </message> <message> <source>Error: %1</source> <translation>Błąd: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>Nie moÅžna pobrać właściwości %1 dla elementu %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>Właściwość %1 dla pozycji %2 nie jest typu VT_FILETIME, ale %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>Nie moÅžna przekonwertować czasu UTC pliku na czas systemowy.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>Nie moÅžna wczytać kodekÃģw.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>Nie moÅžna otworzyć archiwum "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>Nie moÅžna pobrać liczby elementÃģw w archiwum.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>Nie moÅžna pobrać ścieÅžki elementu archiwum "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>Przechwycono nieznany wyjątek (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>Nie moÅžna utworzyć pliku tymczasowego: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Nieobsługiwany typ archiwum.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>Nie moÅžna utworzyć archiwum "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>Nie moÅžna utworzyć archiwum "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>Nie moÅžna usunąć starego archiwum "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>Nie moÅžna zmienić nazwy archiwum tymczasowego "%1" na "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>Przechwycono nieznany wyjątek (%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 zawiera nieprawidłową treść: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>Plik %1 nie istnieje.</translation> </message> <message> <source>Cannot open %1.</source> <translation>Nie moÅžna otworzyć %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Błąd analizy w %1 przy %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Nieoczekiwany element głÃģwny %1, powinno być 'Pakiety'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>Nie moÅžna utworzyć pliku blokady "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>Nie moÅžna zapisać identyfikatora PID do pliku blokady "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>Nie moÅžna uzyskać blokady dla pliku "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>Nie moÅžna usunąć blokady dla pliku "%1": %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Nie znaleziono znaku, zatrzymano po %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Niepowodzenie odczytu po %1 bajtach: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>Kopiowanie nie powiodło się: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Niepowodzenie zapisu po %1 bajtach: %2</translation> </message> <message> <source>bytes</source> <translation>bajtÃģw</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nie moÅžna usunąć pliku "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nie moÅžna usunąć katalogu "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nie moÅžna utworzyć katalogu "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>Nie moÅžna skopiować pliku z "%1" do "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>Nie moÅžna przenieść pliku z "%1" do "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nie moÅžna utworzyć katalogu "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>Nie moÅžna otworzyć pliku tymczasowego: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>Nie moÅžna otworzyć pliku tymczasowego dla szablonu %1: %2</translation> </message> <message> <source>Corrupt installation</source> <translation>Uszkodzona instalacja</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>Instalacja wygląda na uszkodzoną. WeÅš pod uwagę zainstalowanie od zera.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>Nie udało się znaleŚć określonego modułu.</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Elementy nie mogą mieć elementÃģw podrzędnych w trybie programu aktualizującego.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>Nie moÅžna otworzyć Şądanego pliku interfejsu uÅžytkownika "%1": %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>Nie moÅžna wczytać Şądanego pliku interfejsu uÅžytkownika "%1": %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>Nie moÅžna otworzyć Şądanego pliku licencji "%1": %2</translation> </message> <message> <source>Error</source> <translation>Błąd</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Błąd: Operacja %1 nie istnieje.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>Nie moÅžna rozwiązać isDefault w %1</translation> </message> <message> <source>Update Info: </source> <translation>Informacje o aktualizacji: </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Element jest oznaczony do zainstalowania.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Element jest oznaczony do odinstalowania.</translation> </message> <message> <source>Component is installed.</source> <translation>Element jest zainstalowany.</translation> </message> <message> <source>Component is not installed.</source> <translation>Element nie jest zainstalowany.</translation> </message> <message> <source>Component Name</source> <translation>Nazwa elementu</translation> </message> <message> <source>Action</source> <translation>Operacja</translation> </message> <message> <source>Installed Version</source> <translation>Zainstalowana wersja</translation> </message> <message> <source>New Version</source> <translation>Nowa wersja</translation> </message> <message> <source>Release Date</source> <translation>Data wydania</translation> </message> <message> <source>Size</source> <translation>Rozmiar</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>&Domyślne</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&Resetuj</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&Zaznacz wszystkie</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>&Usuń zaznaczenie wszystkich</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>Aby zainstalować nowe skompresowane repozytorium, przejrzyj repozytoria na swoim komputerze</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&ZnajdÅš pliki QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Element ten zajmie około %1 miejsca na dysku twardym.</translation> </message> <message> <source>Open File</source> <translation>OtwÃģrz plik</translation> </message> <message> <source>Select Components</source> <translation>Wybierz elementy</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Wybierz elementy, ktÃģre chcesz zaktualizować.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Wybierz elementy, ktÃģre chcesz zainstalować.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Wybierz elementy, ktÃģre chcesz odinstalować.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Wybierz elementy do zainstalowania. Anuluj zaznaczenie zainstalowanych elementÃģw, aby je dezinstalować. Elementy, ktÃģre są juÅž zainstalowane, nie zostaną zaktualizowane.</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><nazwa klucza instalacyjnego do zapisania> <plik wykonywalny> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Wymagany obiekt instalatora w operacji %1 jest pusty.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>Nie moÅžna zapisać danych wynikowych "%1" do pustej wartości klucza instalacyjnego.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>Plik "%1" nie istnieje lub nie jest wykonywalnym plikiem binarnym.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>Uruchamianie "%1" spowodowało awarię.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><ÅšrÃģdło> <cel> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Nieprawidłowy argument w %1: Trzecim argumentem musi być forceOverwrite, jeśli określono.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Nieprawidłowy argument w %1: Katalog "%2" jest nieprawidłowy.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>Nie moÅžna utworzyć katalogu "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Nie powiodło się zastąpienie "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>Nie moÅžna skopiować pliku "%1" do "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nie moÅžna usunąć pliku "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Nieprawidłowa liczba pozycji zadań.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>Zapisywanie do pliku "%1" nie powiodło się: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Nie powiodło się zastąpienie pliku "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>Nie moÅžna zapisać wpisu pulpitu w "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>Nie moÅžna utworzyć łącza z "%1" do "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>Nie moÅžna usunąć łącza z "%1" do "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>Nie moÅžna ustawić uprawnień dla pliku "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>Nie moÅžna usunąć pliku "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Nie moÅžna przenieść pliku "%1" do "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>Instalator w "%1" musi być instalatorem offline.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>Nie moÅžna odczytać pliku "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>Nie moÅžna utworzyć katalogu docelowego: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>Przechwycono nieznany wyjątek: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Usuwanie pliku "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>Nie moÅžna usunąć pliku "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>Nie moÅžna usunąć katalogu "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><cel> <lokalizacja łącza> [argumenty docelowe] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nie moÅžna utworzyć katalogu "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Nie powiodło się zastąpienie "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>Nie moÅžna utworzyć łącza "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Anulowano</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Pobieranie podpisu skrÃģtu nie powiodło się.</translation> </message> <message> <source>Download Error</source> <translation>Błąd pobierania</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>Weryfikacja skrÃģtu podczas pobierania nie powiodła się. Jest to tymczasowy błąd, sprÃģbuj ponownie.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>Nie moÅžna zweryfikować skrÃģtu</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>Nie moÅžna pobrać archiwum %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>Nie moÅžna pobrać archiwÃģw: %1 Błąd podczas wczytywania %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Pobieranie archiwum "%1" dla elementu %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Schemat %1 nie jest obsługiwany (adres URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>Nie moÅžna znaleŚć elementu dla %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>Plik docelowy "%1" juÅž istnieje, ale nie jest plikiem.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Plik "%1" nie jest otwarty do zapisu: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Zapisywanie do pliku "%1" nie powiodło się: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Wykryto pętlę przekierowania dla "%1".</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Wykryto niezgodność sumy kontrolnej dla "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Błąd sieci podczas pobierania '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Nieznany błąd sieci podczas pobierania "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>Anulowano transfery sieciowe.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>Transfery sieciowe nie obsługują wstrzymywania i wznawiania.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>Nieprawidłowy adres URL ÅšrÃģdła "%1": %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>Nie moÅžna uruchomić odłączonego: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>Nie moÅžna uruchomić: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Program uległ awarii: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Wykonanie nie powiodło się (nieoczekiwany kod wyjścia: %1): "%2"</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć archiwum "%1" do odczytu: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Błąd podczas wyodrębniania archiwum "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>Zarejestrowano nieznany wyjątek podczas wyodrębniania "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>Nie moÅžna uzyskać rdzenia menedÅžera pakietÃģw.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Przed przejściem dalej naleÅžy zatrzymać ten proces: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Przed przejściem dalej naleÅžy zatrzymać te procesy: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 z %2</translation> </message> <message> <source>%1 received.</source> <translation>Liczba odebranych: %1.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/s)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n d, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n godz., </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n min</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n s</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> — %1%2%3%4 pozostało.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> — nieznany czas pozostały.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>Wykonywanie Kreatora %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Kliknij pozycję %1, aby zamknąć Kreator %2.</translation> </message> <message> <source>Restart</source> <translation>Uruchom ponownie</translation> </message> <message> <source>Run %1 now.</source> <translation>Uruchom %1 teraz.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>Działanie Kreatora %1 nie powiodło się.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>Ustawienia nie są zapisywalne.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Zapisywanie ustawień nie powiodło się.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><ścieÅžka ÅšrÃģdła> [prefiks dostawcy]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Nieprawidłowy argument: katalog ÅšrÃģdłowy nie moÅže być pusty.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>Nie moÅžna wykonać kopii zapasowej pliku "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Nie powiodło się zastąpienie "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Nie powiodło się kopiowanie pliku "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>Nie moÅžna utworzyć katalogu "%1": %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>Konfiguracja - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Witamy w Kreatorze konfiguracji %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>Dodaj lub usuń elementy</translation> </message> <message> <source>&Update components</source> <translation>Zaktualizuj elementy</translation> </message> <message> <source>&Remove all components</source> <translation>Usuń wszystkie elementy</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Trwa pobieranie informacji ze zdalnych ÅšrÃģdeł instalacji...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>Do wykonania tego działania wymagane jest co najmniej jedno waÅžne i aktywne repozytorium.</translation> </message> <message> <source>No updates available.</source> <translation>Brak dostępnych aktualizacji.</translation> </message> <message> <source> Only local package management available.</source> <translation> Dostępne jedynie lokalne zarządzanie pakietami.</translation> </message> <message> <source>&Quit</source> <translation>Zakończ</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Umowa licencyjna</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Prosimy o przeczytanie poniÅžszych umÃģw licencyjnych. UÅžytkownik musi zaakceptować warunki zawarte w tej umowie przed kontynuowaniem instalacji.</translation> </message> <message> <source>I accept the license.</source> <translation>Akceptuję warunki licencji.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Nie akceptuję warunkÃģw licencji.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Prosimy o przeczytanie poniÅžszych umÃģw licencyjnych. UÅžytkownik musi zaakceptować warunki zawarte w tych umowach przed kontynuowaniem instalacji.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Akceptuję warunki licencji.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Nie akceptuję warunkÃģw licencji.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Nie znaleziono plikÃģw licencji do skopiowania.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>Wymagany obiekt instalatora w operacji %1 jest pusty.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>Nie moÅžna zapisać pliku licencji: "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Nie znaleziono plikÃģw licencji do usunięcia.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Brak podstawowego mechanizmu menedÅžera pakietÃģw.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Przygotowanie metainformacji do pobrania...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Rozpakowywanie skompresowanych repozytoriÃģw. MoÅže to chwilę potrwać...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Pobieranie metadanych zostało anulowane.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>Nieznany wyjątek podczas wyodrębniania.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Brak poświadczeń serwera proxy.</translation> </message> <message> <source>Authentication failed.</source> <translation>Uwierzytelnianie nie powiodło się.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>Nieznany wyjątek podczas pobierania.</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Pobranie repozytoriÃģw nie powiodło się.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Wyodrębnianie metainformacji...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Pobieranie metainformacji z repozytorium zdalnego... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Pobieranie metainformacji z repozytorium zdalnego... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Błąd podczas wyodrębniania archiwum "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>Zarejestrowano nieznany wyjątek podczas wyodrębniania archiwum "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Błąd zapisu w narzędziu konserwacji</translation> </message> <message> <source> Downloading packages...</source> <translation> Pobieranie pakietÃģw...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>Instalacja anulowana przez uÅžytkownika.</translation> </message> <message> <source>All downloads finished.</source> <translation>Ukończono wszystkie pobierania.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Anulowanie Instalatora</translation> </message> <message> <source>Authentication Error</source> <translation>Błąd uwierzytelniania</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>NiektÃģre elementy nie mogły zostać całkowicie usunięte, poniewaÅž nie uzyskano uprawnień administratora: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Nieznany błąd.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>NiektÃģre elementy nie mogły zostać całkowicie usunięte, poniewaÅž wystąpił nieznany błąd.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>Aplikacja nie działa w trybie MenedÅžer pakietÃģw.</translation> </message> <message> <source>No installed packages found.</source> <translation>Nie znaleziono zainstalowanych pakietÃģw.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>Aplikacja działa w trybie Dezinstalatora.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Jest dostępna waÅžna aktualizacja, najpierw uruchom program aktualizujący.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>Nie moÅžna rozwiązać wszystkich zaleÅžności.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Elementy mają zostać usunięte.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Błąd podczas podnoszenia prawa dostępu.</translation> </message> <message> <source>Error</source> <translation>Błąd</translation> </message> <message> <source>invalid</source> <translation>nieprawidłowe</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>Nierozwiązane zaleÅžności</translation> </message> <message> <source>Error</source> <translation>Błąd</translation> </message> <message> <source>Access error</source> <translation>Błąd dostępu</translation> </message> <message> <source>Format error</source> <translation>Błąd formatu</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>Nie moÅžna zapisać konfiguracji instalatora w %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Zatrzymaj procesy</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>PoniÅžsze procesy powinny być zatrzymane, aby kontynuować: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>Instalacja anulowana przez uÅžytkownika</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Zapisywanie w narzędziu do konserwacji</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Nie powiodło się wyszukiwanie w pliku %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Narzędzie konserwacji nie jest pakietem</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>Nie moÅžna usunąć pliku danych "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>Nie moÅžna zapisać danych narzędzia konserwacji w %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>Nie moÅžna zapisać narzędzia konserwacji w "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>Nie moÅžna zapisać danych binarnych narzędzia konserwacji w %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>Nie skonfigurowano zmiennej 'TargetDir'.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Trwa przygotowanie instalacji...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>Nie jest moÅžliwa instalacja z lokalizacji sieciowej</translation> </message> <message> <source>Creating local repository</source> <translation>Tworzenie lokalnego repozytorium</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Tworzenie narzędzia konserwacji</translation> </message> <message> <source> Installation finished!</source> <translation> Ukończono instalację!</translation> </message> <message> <source> Installation aborted!</source> <translation> Przerwano instalację!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>Nie jest moÅžliwe uruchomienie tego działania z lokalizacji sieciowej</translation> </message> <message> <source>Removing deselected components...</source> <translation>Trwa usuwanie elementÃģw, ktÃģrych zaznaczenie wyłączono...</translation> </message> <message> <source> Update finished!</source> <translation> Aktualizacja zakończona!</translation> </message> <message> <source> Update aborted!</source> <translation> Aktualizację przerwano!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>Dezinstalacja zakończona powodzeniem.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>Dezinstalacja przerwana.</translation> </message> <message> <source> Installing component %1</source> <translation> Trwa instalowanie elementu %1</translation> </message> <message> <source>Installer Error</source> <translation>Błąd instalatora</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Błąd podczas procesu instalacji (%1): %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>Nie moÅžna przygotować dezinstalacji</translation> </message> <message> <source>Cannot start uninstall</source> <translation>Nie moÅžna uruchomić dezinstalacji</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Błąd podczas procesu dezinstalacji: %1</translation> </message> <message> <source>Unknown error</source> <translation>Nieznany błąd</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>Nie moÅžna pobrać drzewa zdalnego %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Nie powiÃģdł się odczyt pakietÃģw z %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>Nie moÅžna pobrać metainformacji: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>Nie moÅžna dodać informacji o tymczasowym ÅšrÃģdle aktualizacji.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>Nie moÅžna znaleŚć Åžadnych informacji o ÅšrÃģdle aktualizacji.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Wykryto cykl zaleÅžności między elementami "%1" i "%2".</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>Konfiguracja %1</translation> </message> <message> <source>Maintain %1</source> <translation>Zachowaj %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Czy chcesz anulować proces instalacji?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Czy chcesz anulować proces dezinstalacji?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Czy chcesz zakończyć aplikację instalatora?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Czy chcesz zakończyć aplikację dezinstalatora?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Czy chcesz zakończyć aplikację do konserwacji?</translation> </message> <message> <source>%1 Question</source> <translation>Pytanie: %1</translation> </message> <message> <source>Settings</source> <translation>Parametry</translation> </message> <message> <source>Error</source> <translation>Błąd</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Nie jest moÅžliwa instalacja z lokalizacji sieciowej. Skopiuj instalator na dysk lokalny</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&PokaÅž szczegÃģły</translation> </message> <message> <source>&Hide Details</source> <translation>&Ukryj szczegÃģły</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Odinstaluj</translation> </message> <message> <source>Uninstalling %1</source> <translation>Odinstalowanie %1</translation> </message> <message> <source>&Update</source> <translation>&Aktualizuj</translation> </message> <message> <source>Updating components of %1</source> <translation>Aktualizacja elementÃģw %1</translation> </message> <message> <source>&Install</source> <translation>&Zainstaluj</translation> </message> <message> <source>Installing %1</source> <translation>Instalacja %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>Okno</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>Serwer proxy %1 wymaga nazwy uÅžytkownika i hasła.</translation> </message> <message> <source>Username:</source> <translation>Nazwa uÅžytkownika:</translation> </message> <message> <source>Username</source> <translation>Nazwa uÅžytkownika</translation> </message> <message> <source>Password:</source> <translation>Hasło:</translation> </message> <message> <source>Password</source> <translation>Hasło</translation> </message> <message> <source>Proxy Credentials</source> <translation>Poświadczenia serwera proxy</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>&Odinstaluj</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Gotowy do dezinstalacji</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>Instalator jest juÅž gotowy, aby rozpocząć usuwanie %1 z komputera.<br><font color="red">Katalog programu %2 zostanie w całości usunięty</font>, włącznie z całą zawartością!</translation> </message> <message> <source>U&pdate</source> <translation>&Aktualizuj</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Gotowy do aktualizacji pakietÃģw</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>Instalator jest juÅž gotowy do rozpoczęcia aktualizowania instalacji.</translation> </message> <message> <source>&Install</source> <translation>&Zainstaluj</translation> </message> <message> <source>Ready to Install</source> <translation>Gotowy do instalacji</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>Instalator jest gotowy do rozpoczęcia instalacji %1 na komputerze.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>Za mało miejsca na dysku do przechowywania plikÃģw tymczasowych i instalacyjnych. Dostępne miejsce: %1, wymagane miejsce: co najmniej %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>Za mało miejsca na dysku do przechowywania wszystkich wybranych elementÃģw! Dostępne miejsce: %1, wymagane miejsce: co najmniej %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>Za mało miejsca na dysku do przechowywania plikÃģw tymczasowych! Dostępne miejsce: %1, wymagane miejsce: co najmniej %2.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>Wolumin wybrany do instalacji wydaje się mieć wystarczająco miejsca na instalację, jednak po tej operacji pozostanie mniej niÅž 1% wolnego miejsca. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>Wolumin wybrany do instalacji wydaje się mieć wystarczająco miejsca na instalację, jednak po tej operacji pozostanie mniej niÅž 100 MB wolnego miejsca. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>Instalacja zajmie %1 miejsca na dysku.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><rozszerzenie> <polecenie> [opis [typZasobu [ikona]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>Rejestrowanie typÃģw plikÃģw jest obsługiwane tylko w systemie Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Typ pliku rejestru: Nieprawidłowe argumenty</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>Nie moÅžna odczytać wszystkich danych po wysłaniu polecenia: %1. Oczekiwano: %2 B, odebrano: %3 B. Błąd: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do odczytu: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>Nie moÅžna otworzyć pliku "%1" do zapisu: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>Nie moÅžna otworzyć zasobu %1 do odczytu.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Niepowodzenie odczytu po %1 bajtach: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Niepowodzenie zapisu po %1 bajtach: %2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>Wykonywanie Kreatora instalacji %1</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>Nie moÅžna otworzyć pliku skryptu w %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>Wyjątek podczas wczytywania skryptu elementu "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Nieznany błąd.</translation> </message> <message> <source>on line number: </source> <translation>w wierszu numer: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>Wymagany obiekt instalatora w operacji %1 jest pusty.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Ponowne uruchomienie automatyczne: Wyłącznie w trybie aktualizatora lub menedÅžera pakietÃģw.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Ponowne uruchomienie automatyczne: Nieprawidłowe argumenty</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Serwer wymaga uwierzytelnienia</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>Aby uzyskać dostęp do tej witryny, musisz podać nazwę uÅžytkownika i hasło.</translation> </message> <message> <source>Username:</source> <translation>Nazwa uÅžytkownika:</translation> </message> <message> <source>Password:</source> <translation>Hasło:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 przy %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Brakujące argumenty. "%1" wywołuje %2 z argumentami "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>Wywoływanie argumentu bieŞącej metody "%1" z argumentami "%2" nie jest obsługiwane. UÅžyj metod set, remove, add_array_value lub remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Åŧaden z argumentÃģw nie moÅže być pusty: wartość ÅšrÃģdłowa "%1", wartość docelowa "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>Nie moÅžna przenieść pliku z "%1" do "%2", poniewaÅž ścieÅžka docelowa istnieje i nie jest usuwalna.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>Nie moÅžna przenieść pliku "%1" do "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>Przenoszenie pliku "%1" do "%2".</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>SkrÃģty Menu Start</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Wybierz menu Start, w ktÃģrym mają zostać utworzone skrÃģty programu. MoÅžna takÅže wprowadzić nazwę, aby utworzyć nowy katalog.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Folder instalacji</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Podaj katalog, w ktÃģrym ma zostać zainstalowany element %1.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>P&rzeglądaj...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Wybrany katalog juÅž istnieje i zawiera instalację. Wybierz inny katalog docelowy na potrzeby instalacji.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>Wybrano istniejący, niepusty katalog na potrzeby instalacji. NaleÅžy pamiętać, Åže zostanie on całkowicie wyczyszczony podczas dezinstalowania aplikacji. Instalowanie w tym folderze nie jest zalecane, gdyÅž instalacja moÅže się nie powieść. Czy chcesz kontynuować?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Wybrano istniejący plik lub łącze symboliczne. Wybierz inne miejsce docelowe instalacji.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Wybierz folder instalacji</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>ŚcieÅžka instalacji nie moÅže być pusta, podaj prawidłowy katalog.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>ŚcieÅžka instalacji nie moÅže być względna, podaj ścieÅžkę bezwzględną.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>ŚcieÅžka lub katalog instalacji zawiera znaki spoza ASCII. Nie są one obecnie obsługiwane! Wybierz inną ścieÅžkę lub katalog instalacji.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Katalog instalacji został całkowicie usunięty, instalacja w %1 jest zabroniona.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>Wpisana ścieÅžka jest zbyt długa, podaj prawidłową ścieÅžkę.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>Wpisana ścieÅžka jest nieprawidłowa, podaj prawidłowe miejsce docelowe.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>Wpisana ścieÅžka jest zbyt długa, podaj prawidłowy dysk.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>ŚcieÅžka instalacji nie moÅže kończyć się znakiem '.', podaj prawidłowy katalog.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>ŚcieÅžka instalacji nie moÅže zawierać "%1", podaj prawidłowy katalog.</translation> </message> <message> <source>Warning</source> <translation>OstrzeÅženie</translation> </message> <message> <source>Error</source> <translation>Błąd</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Brak podstawowego mechanizmu menedÅžera pakietÃģw.</translation> </message> <message> <source>Empty repository URL.</source> <translation>Adres URL pustego repozytorium.</translation> </message> <message> <source>Download canceled.</source> <translation>Pobieranie anulowane.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Upłynął limit czasu podczas testowania repozytorium "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>Nie moÅžna przeanalizować pliku Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>Nie moÅžna otworzyć pliku Updates.xml do odczytu: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Uwierzytelnianie nie powiodło się.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Nieznany błąd podczas testowania repozytorium "%1".</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>Wymagana autoryzacja</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>WprowadÅš swoje hasło, aby zezwolić na sudo:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Błąd w trakcie nabywania praw administratora</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>Nie moÅžna uzyskać autoryzacji.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>Nie moÅžna uzyskać autoryzacji wymaganej do kontynuowania instalacji. Uruchom program instalacyjny jako uÅžytkownik z odpowiednimi prawami. Alternatywnie zaakceptuj podniesienie praw dostępu, jeśli zostanie wyświetlone odpowiednie pytanie.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>Nie moÅžna uzyskać autoryzacji wymaganej do kontynuowania instalacji. Przerwij instalację lub skorzystaj z rozwiązania awaryjnego, uruchamiając %1 jako uÅžytkownik z odpowiednimi prawami, a następnie kliknij przycisk OK.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>Nie moÅžna otworzyć zasobu %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>Nie moÅžna otworzyć pliku ustawień %1 do odczytu: %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>Parametry</translation> </message> <message> <source>Network</source> <translation>Network</translation> </message> <message> <source>No proxy</source> <translation>Brak proxy</translation> </message> <message> <source>System proxy settings</source> <translation>Ustawienia serwera proxy systemu</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Ręczna konfiguracja serwerÃģw proxy</translation> </message> <message> <source>HTTP proxy:</source> <translation>Serwer proxy HTTP:</translation> </message> <message> <source>Port:</source> <translation>Port:</translation> </message> <message> <source>FTP proxy:</source> <translation>Serwer proxy FTP:</translation> </message> <message> <source>Repositories</source> <translation>Repozytoria</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>W razie potrzeby dodaj nazwę uÅžytkownika hasło do uwierzytelniania.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Korzystaj jedynie z repozytoriÃģw tymczasowych</translation> </message> <message> <source>Add</source> <translation>Dodaj</translation> </message> <message> <source>Remove</source> <translation>Usuń</translation> </message> <message> <source>Test</source> <translation>Test</translation> </message> <message> <source>Show Passwords</source> <translation>Wyświetl hasła</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Zaznacz tę pozycję, aby korzystać z repozytorium w trakcie pobierania.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Dodaj nazwę uÅžytkownika do uwierzytelniania na serwerze.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Dodaj hasło do uwierzytelniania na serwerze.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>Adres URL serwerÃģw zawierających prawidłowe repozytorium.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Wystąpił błąd podczas testowania tego repozytorium.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>Repozytorium zostało pomyślnie przetestowane.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>Czy chcesz wyłączyć repozytorium?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>Czy chcesz włączyć repozytorium?</translation> </message> <message> <source>Hide Passwords</source> <translation>Ukryj hasła</translation> </message> <message> <source>Use</source> <translation>Korzystanie z</translation> </message> <message> <source>Username</source> <translation>Nazwa uÅžytkownika</translation> </message> <message> <source>Password</source> <translation>Hasło</translation> </message> <message> <source>Repository</source> <translation>Repozytorium</translation> </message> <message> <source>Default repositories</source> <translation>Repozytoria domyślne</translation> </message> <message> <source>Temporary repositories</source> <translation>Repozytoria tymczasowe</translation> </message> <message> <source>User defined repositories</source> <translation>Repozytoria zdefiniowane przez uÅžytkownika</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>Nie moÅžna zapisać do ścieÅžki rejestru %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>ŚcieÅžka rejestru %1 nie jest zapisywalna.</translation> </message> <message> <source>exactly %1</source> <translation>dokładnie %1</translation> </message> <message> <source>at least %1</source> <translation>co najmniej %1</translation> </message> <message> <source>not more than %1</source> <translation>nie więcej niÅž %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 lub %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 do %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Nieprawidłowe argumenty w %1: podane argumenty: %n, oczekiwane argumenty: %2.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Nieprawidłowe argumenty w %1: podane argumenty: %n, oczekiwane argumenty (%2) w postaci: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>Zmiana nazwy pliku "%1" na "%2" nie powiodła się: %3</translation> </message> </context> </TS> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_pt_BR.ts��������������������������������������0100777�0000000�0000000�00000310754�13761647206�021426� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="pt"> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>DiÃĄlogo</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>O proxy %1 requer um nome de usuÃĄrio e senha.</translation> </message> <message> <source>Username:</source> <translation>Nome de usuÃĄrio:</translation> </message> <message> <source>Username</source> <translation>Nome de usuÃĄrio</translation> </message> <message> <source>Password:</source> <translation>Senha:</translation> </message> <message> <source>Password</source> <translation>Senha</translation> </message> <message> <source>Proxy Credentials</source> <translation>Credenciais do proxy</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>Servidor Requer AutenticaçÃĢo</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>VocÊ precisa fornecer um nome de usuÃĄrio e senha para acessar este site.</translation> </message> <message> <source>Username:</source> <translation>Nome de usuÃĄrio:</translation> </message> <message> <source>Password:</source> <translation>Senha:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 em %2</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>AutenticaçÃĢo HTTP necessÃĄria</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>VocÊ precisa fornecer um nome de usuÃĄrio e senha para acessar este site.</translation> </message> <message> <source>Username:</source> <translation>Nome de usuÃĄrio:</translation> </message> <message> <source>Password:</source> <translation>Senha:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 em %2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>ConfiguraçÃĩes</translation> </message> <message> <source>Network</source> <translation>Rede</translation> </message> <message> <source>No proxy</source> <translation>Sem proxy</translation> </message> <message> <source>System proxy settings</source> <translation>ConfiguraçÃĩes de proxy do sistema</translation> </message> <message> <source>Manual proxy configuration</source> <translation>ConfiguraçÃĢo manual de proxy</translation> </message> <message> <source>HTTP proxy:</source> <translation>Proxy HTTP:</translation> </message> <message> <source>Port:</source> <translation>Porta:</translation> </message> <message> <source>FTP proxy:</source> <translation>Proxy FTP:</translation> </message> <message> <source>Repositories</source> <translation>RepositÃģrios</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>Adicione nome de usuÃĄrio e senha para autenticaçÃĢo, se necessÃĄrio.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>Usar apenas repositÃģrios temporÃĄrios</translation> </message> <message> <source>Add</source> <translation>Adicionar</translation> </message> <message> <source>Remove</source> <translation>Remover</translation> </message> <message> <source>Test</source> <translation>Testar</translation> </message> <message> <source>Show Passwords</source> <translation>Mostrar Senhas</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>Marque isso para usar o repositÃģrio durante a busca.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>Adicione o nome de usuÃĄrio para autenticar no servidor.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>Adicione a senha para autenticar no servidor.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>URL dos servidores que contÃĐm um repositÃģrio vÃĄlido.</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>Ocorreu um erro durante o teste deste repositÃģrio.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>O repositÃģrio foi testado com sucesso.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>VocÊ deseja desabilitar o repositÃģrio?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>VocÊ deseja habilitar o repositÃģrio?</translation> </message> <message> <source>Hide Passwords</source> <translation>Ocultar Senhas</translation> </message> <message> <source>Use</source> <translation>Usar</translation> </message> <message> <source>Username</source> <translation>Nome de usuÃĄrio</translation> </message> <message> <source>Password</source> <translation>Senha</translation> </message> <message> <source>Repository</source> <translation>RepositÃģrio</translation> </message> <message> <source>Default repositories</source> <translation>RepositÃģrios padrÃĢo</translation> </message> <message> <source>Temporary repositories</source> <translation>RepositÃģrios temporÃĄrios</translation> </message> <message> <source>User defined repositories</source> <translation>RepositÃģrios definidos pelo usuÃĄrio</translation> </message> <message> <source>Select All</source> <translation>Selecionar Todos</translation> </message> <message> <source>Deselect All</source> <translation>Desmarcar Todos</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>AutorizaçÃĢo necessÃĄria</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>Digite sua senha para autorizar para o sudo:</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>Erro ao adquirir privilÃĐgios de administrador</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>Nenhum marcador encontrado, interrompido apÃģs %1.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Falha na leitura apÃģs %1 bytes: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>CÃģpia falhou: %1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Falha na gravaçÃĢo apÃģs %1 bytes: %2</translation> </message> <message> <source>bytes</source> <translation></translation> </message> <message> <source>KiB</source> <translation></translation> </message> <message> <source>MiB</source> <translation></translation> </message> <message> <source>GiB</source> <translation></translation> </message> <message> <source>TiB</source> <translation></translation> </message> <message> <source>PiB</source> <translation></translation> </message> <message> <source>EiB</source> <translation></translation> </message> <message> <source>ZiB</source> <translation></translation> </message> <message> <source>YiB</source> <translation></translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1": %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o diretÃģrio "%1": %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1".</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível copiar o arquivo de "%1" para "%2": %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível mover o arquivo de "%1" para "%2": %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1": %2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>NÃĢo ÃĐ possível abrir o arquivo temporÃĄrio: %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo temporÃĄrio para o modelo %1: %2</translation> </message> <message> <source>Corrupt installation</source> <translation type="vanished">InstalaçÃĢo corrompida</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation type="vanished">Sua instalaçÃĢo parece estar corrompida. Por favor, considere reinstalar a partir do zero.</translation> </message> <message> <source>The specified module could not be found.</source> <translation>O mÃģdulo especificado nÃĢo pÃīde ser encontrado.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>NÃĢo ÃĐ possível avançar atÃĐ %1 para ler o contador de metadados.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>NÃĢo ÃĐ possível avançar atÃĐ %1 para ler o segmento da coletÃĒnea de recursos.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>Incompatibilidade inesperada de meta recursos. Lidos %1, esperava: %2.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>NÃĢo ÃĐ possível avançar atÃĐ %1 para ler os dados da operaçÃĢo.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>NÃĢo ÃĐ possível avançar atÃĐ %1 para ler o bloco do conjunto de recursos.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>NÃĢo ÃĐ possível abrir o meta recurso %1.</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>NÃĢo ÃĐ possível abrir o recurso %1 para leitura.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>Falha na leitura apÃģs %1 bytes: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>Falha na gravaçÃĢo apÃģs %1 bytes: %2</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>NÃĢo ÃĐ possível abrir o recurso %1: %2</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>Componentes nÃĢo podem ter filhos no modo de atualizaçÃĢo.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo da interface do usuÃĄrio solicitado "%1": %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>NÃĢo ÃĐ possível carregar o arquivo da interface do usuÃĄrio solicitado "%1":%2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo de licença solicitado "%1": %2</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>Erro: A operaçÃĢo %1 nÃĢo existe.</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>NÃĢo ÃĐ possível resolver o isDefault em %1</translation> </message> <message> <source>There was an error loading the selected component. This component can not be installed.</source> <translation>Houve um erro ao carregar o componente selecionado. Este componente nÃĢo pode ser instalado.</translation> </message> <message> <source>Update Info: </source> <translation>InformaçÃĢo de AtualizaçÃĢo: </translation> </message> <message> <source>There was an error loading the selected component. This component can not be updated.</source> <translation>Houve um erro ao carregar o componente selecionado. Este componente nÃĢo pode ser atualizado.</translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>Componente estÃĄ marcado para instalaçÃĢo.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>Componente estÃĄ marcado para desinstalaçÃĢo.</translation> </message> <message> <source>Component is installed.</source> <translation>Componente estÃĄ instalado.</translation> </message> <message> <source>Component is not installed.</source> <translation>Componente nÃĢo estÃĄ instalado.</translation> </message> <message> <source>Component Name</source> <translation>Nome do Componente</translation> </message> <message> <source>Action</source> <translation>AçÃĢo</translation> </message> <message> <source>Installed Version</source> <translation>VersÃĢo Instalada</translation> </message> <message> <source>New Version</source> <translation>Nova VersÃĢo</translation> </message> <message> <source>Release Date</source> <translation>Data de Lançamento</translation> </message> <message> <source>Size</source> <translation>Tamanho</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><a ser salvo nome da chave do instalador> <executÃĄvel> [argumento1] [argumento2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>O objeto de instalaçÃĢo necessÃĄrio na operaçÃĢo %1 estÃĄ vazio.</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>NÃĢo ÃĐ possível salvar a saída de "%1" em uma chave de instalaçÃĢo vazia.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>O arquivo "%1" nÃĢo existe ou nÃĢo ÃĐ um binÃĄrio executÃĄvel.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>A execuçÃĢo de "%1" resultou em uma falha.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation></translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>Argumento invÃĄlido em %1: O terceiro argumento precisa ser forceOverwrite, se especificado.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>Argumento invÃĄlido em %1: O diretÃģrio "%2" ÃĐ invÃĄlido.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1".</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>Falha ao sobrescrever "%1".</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível copiar o arquivo de "%1" para "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1".</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>Contagem de item de tarefa invÃĄlida.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>A gravaçÃĢo no arquivo "%1" falhou: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1": %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>Falha ao sobrescrever o arquivo "%1".</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>NÃĢo ÃĐ possível gravar a entrada da ÃĄrea de trabalho em "%1".</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>NÃĢo ÃĐ possível criar link de "%1" para "%2".</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>NÃĢo ÃĐ possível remover o link de "%1" para "%2".</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>NÃĢo ÃĐ possível definir permissÃĩes para o arquivo "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1": %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível mover o arquivo "%1" para "%2": %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>O instalador em "%1" precisa ser off-line.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>NÃĢo ÃĐ possível ler o arquivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio: "%1".</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>ExceçÃĢo desconhecida detectada: %1.</translation> </message> <message> <source>Removing file "%1".</source> <translation>Removendo o arquivo "%1".</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1".</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o diretÃģrio "%1": %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation></translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Falha ao sobrescrever "%1": %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o link "%1": %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>Cancelado</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>Falha ao baixar assinatura de hash.</translation> </message> <message> <source>Download Error</source> <translation>Erro de Download</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>A verificaçÃĢo de hash durante o download falhou. Este ÃĐ um erro temporÃĄrio. Por favor, tente novamente.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>NÃĢo ÃĐ possível verificar o Hash</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>NÃĢo ÃĐ possível baixar o arquivo %1: %2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>NÃĢo ÃĐ possível buscar arquivos: %1 Erro ao carregar %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>Baixando arquivo "%1" para o componente %2.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>Esquema %1 nÃĢo suportado (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>NÃĢo ÃĐ possível encontrar o componente para %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>O arquivo de destino "%1" jÃĄ existe, mas nÃĢo ÃĐ um arquivo.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>Arquivo "%1" nÃĢo aberto para gravaçÃĢo: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>A gravaçÃĢo no arquivo "%1" falhou: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>Loop de redirecionamento detectado para "%1".</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>Erro de rede durante o download de '%1': %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>Erro de rede desconhecido durante o download de "%1".</translation> </message> <message> <source>Network transfers canceled.</source> <translation>TransferÊncias de rede canceladas.</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>Pausa e retomada nÃĢo suportada por transferÊncias de rede.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>URL invÃĄlida "%1": %2</translation> </message> </context> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 em %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>O proxy requer autenticaçÃĢo.</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>NÃĢo ÃĐ possível iniciar desanexado: "%1"</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>NÃĢo ÃĐ possível iniciar: "%1": %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>Programa falhou: "%1"</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>Falha na execuçÃĢo (cÃģdigo de saída inesperado:%1): "%2"</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>NÃĢo ÃĐ possível gravar no caminho do registro %1.</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>O caminho do registro %1 nÃĢo ÃĐ gravÃĄvel.</translation> </message> <message> <source>exactly %1</source> <translation>exatamente %1</translation> </message> <message> <source>at least %1</source> <translation>pelo menos %1</translation> </message> <message> <source>not more than %1</source> <translation>nÃĢo mais que %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 ou %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 a %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>Argumento invÃĄlido em %1: %n argumento fornecido,%2 argumentos esperados.</numerusform> <numerusform>Argumentos invÃĄlidos em %1: %n argumentos fornecidos,%2 argumentos esperados.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>Argumento invÃĄlido em %1: %n argumento fornecido,%2 argumentos esperados no formulÃĄrio %3.</numerusform> <numerusform>Argumentos invÃĄlidos em %1: %n argumentos fornecidos,%2 argumentos esperados no formulÃĄrio %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>A renomeaçÃĢo do arquivo "%1" para "%2" falhou: %3</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Erro ao extrair o arquivo "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>ExceçÃĢo desconhecida detectada ao extrair "%1".</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>NÃĢo ÃĐ possível obter o nÚcleo do gerenciador de pacotes.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>Este processo deve ser interrompido antes de continuar: %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>Esses processos devem ser interrompidos antes de continuar: %1</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>ConfiguraçÃĩes nÃĢo sÃĢo gravÃĄveis.</translation> </message> <message> <source>Failed to write settings.</source> <translation>Falha ao gravar configuraçÃĩes.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>Componentes adicionados como dependÊncias automÃĄticas:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>Componentes adicionados como dependÊncia para "%1":</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>Componentes que resolveram dependÊncias:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Componentes selecionados sem dependÊncias:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>RecursÃĢo detectada, componente "%1" jÃĄ adicionado com o motivo: "%2"</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>NÃĢo foi possível encontrar a dependÊncia ausente "%1" para "%2".</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><caminho de origem> [prefixo do fornecedor]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>Argumento InvÃĄlido: o diretÃģrio de origem nÃĢo deve estar vazio.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1": %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>Falha ao sobrescrever "%1": %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>Falha ao copiar o arquivo "%1": %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1": %2</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>cÃģdigo interno: %1</translation> </message> <message> <source>not enough memory</source> <translation>memÃģria insuficiente</translation> </message> <message> <source>Error: %1</source> <translation>Erro: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>NÃĢo ÃĐ possível obter a propriedade %1 do item %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>Propriedade %1 do item %2 nÃĢo ÃĐ do tipo VT_FILETIME, mas %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>NÃĢo ÃĐ possível converter a hora do arquivo UTC em hora do sistema.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>NÃĢo ÃĐ possível carregar codecs.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1".</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>NÃĢo ÃĐ possível recuperar o nÚmero de itens no arquivo.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>NÃĢo ÃĐ possível recuperar o caminho do item de arquivo "%1".</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>ExceçÃĢo desconhecida detectada (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>NÃĢo ÃĐ possível criar arquivo temporÃĄrio: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>Tipo de arquivo nÃĢo suportado.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>NÃĢo ÃĐ possível criar o arquivo "%1"</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o arquivo "%1": %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo antigo "%1": %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível renomear o arquivo temporÃĄrio "%1" para "%2": %3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>ExceçÃĢo desconhecida detectada (%1)</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>O caminho "%1" existe, mas nÃĢo ÃĐ um diretÃģrio.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1".</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>NÃĢo ÃĐ possível recuperar o caminho do item de arquivo "%1".</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>NÃĢo ÃĐ possível remover o link simbÃģlico jÃĄ existente %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>NÃĢo ÃĐ possível criar o link simbÃģlico em "%1". Outro jÃĄ existe.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>NÃĢo ÃĐ possível ler o destino do link simbÃģlico do arquivo "%1".</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>NÃĢo ÃĐ possível criar o link simbÃģlico em %1:%2</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>Nenhum arquivo de licença encontrado para copiar.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>O objeto de instalaçÃĢo necessÃĄrio na operaçÃĢo %1 estÃĄ vazio.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>NÃĢo ÃĐ possível gravar o arquivo de licença "%1".</translation> </message> <message> <source>No license files found to delete.</source> <translation>Nenhum arquivo de licença foi encontrado para ser excluído.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>Faltando o mecanismo principal do gerenciador de pacotes.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>Preparando o download de metadados...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Descompactando repositÃģrios compactados. Isso pode demorar um pouco...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>Download de metadados cancelado.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>ExceçÃĢo desconhecida durante a extraçÃĢo.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>Faltando credenciais de proxy.</translation> </message> <message> <source>Authentication failed.</source> <translation>Falha de autenticaçÃĢo.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>ExceçÃĢo desconhecida durante o download.</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>Incompatibilidade detectada na soma de verificaçÃĢo para "%1".</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>Recuperando metadados do repositÃģrio remoto...%1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>Recuperando metadados do repositÃģrio remoto... </translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>Falha ao buscar repositÃģrios.</translation> </message> <message> <source>Extracting meta information...</source> <translation>Extraindo metadados...</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>Erro ao extrair o arquivo "%1": %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>ExceçÃĢo desconhecida detectada ao extrair o arquivo "%1".</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 recebido.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/segundo)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dia, </numerusform> <numerusform>%n dias, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora, </numerusform> <numerusform>%n horas, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto</numerusform> <numerusform>%n minutos</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segundo</numerusform> <numerusform>%n segundos</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restantes.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tempo restante desconhecido.</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>Erro ao gravar a Ferramenta de ManutençÃĢo</translation> </message> <message> <source> Downloading packages...</source> <translation> Baixando pacotes...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>InstalaçÃĢo cancelada pelo usuÃĄrio.</translation> </message> <message> <source>All downloads finished.</source> <translation>Todos os downloads terminados.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>Cancelando o Instalador</translation> </message> <message> <source>Authentication Error</source> <translation>Erro de AutenticaçÃĢo</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>Alguns componentes nÃĢo puderam ser removidos completamente porque nÃĢo foi possível adquirir privilÃĐgios de administrador: %1.</translation> </message> <message> <source>Unknown error.</source> <translation>Erro desconhecido.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>Alguns componentes nÃĢo puderam ser removidos completamente porque ocorreu um erro desconhecido.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>AplicaçÃĢo nÃĢo executada no modo Gerenciador de Pacotes.</translation> </message> <message> <source>No installed packages found.</source> <translation>Nenhum pacote instalado foi encontrado.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>AplicaçÃĢo em execuçÃĢo no modo Desinstalador.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>Existe uma atualizaçÃĢo importante disponível, execute o atualizador primeiro.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>NÃĢo ÃĐ possível resolver todas as dependÊncias.</translation> </message> <message> <source>Components about to be removed.</source> <translation>Componentes prestes a serem removidos.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>Erro ao elevar os privilÃĐgios de acesso.</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> <message> <source>invalid</source> <translation>invÃĄlido</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>DependÊncias nÃĢo resolvidas</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> <message> <source>Access error</source> <translation>Erro de acesso</translation> </message> <message> <source>Format error</source> <translation>Erro de formato</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>NÃĢo ÃĐ possível gravar a configuraçÃĢo do instalador em %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>Parar Processos</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>Esses processos devem ser interrompidos para continuar: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>InstalaçÃĢo cancelada pelo usuÃĄrio</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>Escrevendo ferramenta de manutençÃĢo.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>Falha ao procurar no arquivo %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Ferramenta de manutençÃĢo nÃĢo ÃĐ um pacote</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo de dados "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>NÃĢo ÃĐ possível gravar dados da ferramenta de manutençÃĢo em %1: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>NÃĢo ÃĐ possível gravar a ferramenta de manutençÃĢo em "%1": %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>NÃĢo ÃĐ possível gravar dados binÃĄrios da ferramenta de manutençÃĢo em %1: %2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>VariÃĄvel 'TargetDir' nÃĢo definida.</translation> </message> <message> <source>Preparing the installation...</source> <translation>Preparando a instalaçÃĢo...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>NÃĢo ÃĐ possível instalar a partir do local da rede</translation> </message> <message> <source>Creating local repository</source> <translation>Criando repositÃģrio local</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>Criando Ferramenta de ManutençÃĢo</translation> </message> <message> <source> Installation finished!</source> <translation> InstalaçÃĢo finalizada!</translation> </message> <message> <source> Installation aborted!</source> <translation> InstalaçÃĢo cancelada!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>NÃĢo ÃĐ possível executar essa operaçÃĢo a partir de um local de rede</translation> </message> <message> <source>Removing deselected components...</source> <translation>Removendo componentes nÃĢo selecionados...</translation> </message> <message> <source> Update finished!</source> <translation> AtualizaçÃĢo finalizada!</translation> </message> <message> <source> Update aborted!</source> <translation> AtualizaçÃĢo cancelada!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>DesinstalaçÃĢo concluída com sucesso.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>DesinstalaçÃĢo cancelada.</translation> </message> <message> <source> Installing component %1...</source> <translation> Instalando o componente %1...</translation> </message> <message> <source> Installing component %1</source> <translation type="vanished"> Instalando o componente %1</translation> </message> <message> <source>Installer Error</source> <translation>Erro de InstalaçÃĢo</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>Erro durante o processo de instalaçÃĢo (%1): %2</translation> </message> <message> <source>Done</source> <translation>Feito</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>NÃĢo ÃĐ possível preparar a desinstalaçÃĢo</translation> </message> <message> <source>Cannot start uninstall</source> <translation>NÃĢo ÃĐ possível iniciar a desinstalaçÃĢo</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>Erro durante o processo de desinstalaçÃĢo: %1</translation> </message> <message> <source>Unknown error</source> <translation>Erro desconhecido</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>NÃĢo ÃĐ possível recuperar a ÃĄrvore remota %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>Falha ao ler pacotes de %1.</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>NÃĢo ÃĐ possível recuperar metadados: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>NÃĢo ÃĐ possível adicionar informaçÃĩes de fontes de atualizaçÃĢo temporÃĄria.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>NÃĢo ÃĐ possível encontrar informaçÃĩes de fonte de atualizaçÃĢo.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>Ciclo de dependÊncia entre os componentes "%1" e "%2" detectados.</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>InstalaçÃĢo %1</translation> </message> <message> <source>Maintain %1</source> <translation>ManutençÃĢo %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>Deseja cancelar o processo de instalaçÃĢo?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>Deseja cancelar o processo de desinstalaçÃĢo?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Deseja sair do instalador?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Deseja sair do desinstalador?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Deseja sair do aplicativo de manutençÃĢo?</translation> </message> <message> <source>%1 Question</source> <translation>%1</translation> </message> <message> <source>Settings</source> <translation>ConfiguraçÃĩes</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>NÃĢo ÃĐ possível instalar a partir da rede. Por favor, copie o instalador para uma unidade local</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>%1 - ConfiguraçÃĢo</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>Bem-vindo ao Assistente de ConfiguraçÃĢo %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>&Adicionar ou remover componentes</translation> </message> <message> <source>&Update components</source> <translation>At&ualizar componentes</translation> </message> <message> <source>&Remove all components</source> <translation>&Remover todos os componentes</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>Recuperando informaçÃĩes das fontes de instalaçÃĩes remotas...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>É necessÃĄrio pelo menos um repositÃģrio vÃĄlido e ativado para que esta açÃĢo seja bem-sucedida.</translation> </message> <message> <source>No updates available.</source> <translation>Nenhuma atualizaçÃĢo disponível.</translation> </message> <message> <source> Only local package management available.</source> <translation> Apenas gerenciamento de pacotes locais disponível.</translation> </message> <message> <source>&Quit</source> <translation>Sair</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>Contrato de Licença</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation></translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation></translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>Por favor, leia o seguinte contrato de licença. VocÊ deve aceitar os termos contidos neste contrato antes de continuar com a instalaçÃĢo.</translation> </message> <message> <source>I accept the license.</source> <translation>Eu aceito a licença.</translation> </message> <message> <source>I do not accept the license.</source> <translation>Eu nÃĢo aceito a licença.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>Por favor, leia os seguintes contratos de licença. VocÊ deve aceitar os termos contidos nesses contratos antes de continuar com a instalaçÃĢo.</translation> </message> <message> <source>I accept the licenses.</source> <translation>Eu aceito as licenças.</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>Eu nÃĢo aceito as licenças.</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation></translation> </message> <message> <source>Def&ault</source> <translation>Def&ault</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation></translation> </message> <message> <source>&Reset</source> <translation>&Resetar</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation></translation> </message> <message> <source>&Select All</source> <translation>&Selecionar Todos</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation></translation> </message> <message> <source>&Deselect All</source> <translation>&Desmarcar Todos</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&Procurar arquivos QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Este componente ocuparÃĄ aproximadamente %1 na sua unidade de disco rígido.</translation> </message> <message> <source>Open File</source> <translation>Abrir Arquivo</translation> </message> <message> <source>Select Components</source> <translation>Selecionar Componentes</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>Por favor, selecione os componentes que vocÊ deseja atualizar.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>Por favor, selecione os componentes que vocÊ deseja instalar.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>Por favor, selecione os componentes que vocÊ deseja desinstalar.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Selecione os componentes para instalar. Desmarque os componentes instalados para desinstalÃĄ-los. Quaisquer componentes jÃĄ instalados nÃĢo serÃĢo atualizados.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>Pasta de InstalaçÃĢo</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>Por favor especifique o diretÃģrio onde %1 serÃĄ instalado.</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation></translation> </message> <message> <source>B&rowse...</source> <translation>P&rocurar...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>O diretÃģrio selecionado jÃĄ existe e contÃĐm uma instalaçÃĢo. Escolha um destino diferente para instalaçÃĢo.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>VocÊ selecionou um diretÃģrio nÃĢo vazio existente para instalaçÃĢo. Ele serÃĄ completamente apagado na desinstalaçÃĢo deste aplicativo. NÃĢo ÃĐ aconselhÃĄvel instalar neste diretÃģrio, pois a instalaçÃĢo pode falhar. VocÊ quer continuar?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>VocÊ selecionou um arquivo ou link simbÃģlico existente, escolha um destino diferente para a instalaçÃĢo.</translation> </message> <message> <source>Select Installation Folder</source> <translation>Selecione a Pasta de InstalaçÃĢo</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>O caminho da instalaçÃĢo nÃĢo pode estar vazio, especifique um diretÃģrio vÃĄlido.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>O caminho da instalaçÃĢo nÃĢo pode ser relativo, especifique um caminho absoluto.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>O caminho ou diretÃģrio de instalaçÃĢo contÃĐm caracteres nÃĢo ASCII. Atualmente, isso nÃĢo ÃĐ suportado! Por favor, escolha um caminho ou diretÃģrio de instalaçÃĢo diferente.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>Como o diretÃģrio de instalaçÃĢo estÃĄ completamente deletado, a instalaçÃĢo em %1 ÃĐ proibida.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>O caminho que vocÊ digitou ÃĐ muito longo, por favor, certifique-se de especificar um caminho vÃĄlido.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>O caminho que vocÊ digitou nÃĢo ÃĐ vÃĄlido, por favor, certifique-se de especificar um caminho vÃĄlido.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>O caminho que vocÊ digitou nÃĢo ÃĐ vÃĄlido, por favor, certifique-se de especificar uma unidade vÃĄlida.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>O caminho da instalaçÃĢo nÃĢo deve terminar com '.', por favor, especifique um diretÃģrio vÃĄlido.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>O caminho da instalaçÃĢo nÃĢo deve conter "%1", por favor, especifique um diretÃģrio vÃĄlido.</translation> </message> <message> <source>Warning</source> <translation>Aviso</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>Atalhos do Menu Iniciar</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Selecione o local no Menu Iniciar onde vocÊ gostaria de criar os atalhos do programa. VocÊ tambÃĐm pode digitar um nome para criar um novo diretÃģrio.</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstalar</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Pronto para Desinstalar</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>O assistente de configuraçÃĢo estÃĄ pronto para remover %1 do seu computador.<br><font color="red">O diretÃģrio do programa %2 serÃĄ excluído completamente</font>, incluindo todo o conteÚdo nesse diretÃģrio!</translation> </message> <message> <source>U&pdate</source> <translation>A&tualizar</translation> </message> <message> <source>Ready to Update Packages</source> <translation>Pronto para Atualizar Pacotes</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>O assistente de configuraçÃĢo estÃĄ pronto para começar a atualizar sua instalaçÃĢo.</translation> </message> <message> <source>&Install</source> <translation>&Instalar</translation> </message> <message> <source>Ready to Install</source> <translation>Pronto para Instalar</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>O assistente de configuraçÃĢo estÃĄ pronto para começar a instalar o %1 no seu computador.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>NÃĢo hÃĄ espaço em disco suficiente para armazenar arquivos temporÃĄrios e a instalaçÃĢo. %1 estÃĢo disponíveis, enquanto pelo menos %2 sÃĢo necessÃĄrios.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>NÃĢo hÃĄ espaço em disco suficiente para armazenar todos os componentes selecionados! %1 estÃĢo disponíveis, enquanto pelo menos %2 sÃĢo necessÃĄrios.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>NÃĢo hÃĄ espaço em disco suficiente para armazenar arquivos temporÃĄrios! %1 estÃĢo disponíveis, enquanto pelo menos %2 sÃĢo necessÃĄrios.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>O volume que vocÊ selecionou para instalaçÃĢo parece ter espaço suficiente para instalaçÃĢo, mas haverÃĄ menos de 100 MB disponíveis posteriormente. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>O volume que vocÊ selecionou para instalaçÃĢo parece ter espaço suficiente para instalaçÃĢo, mas haverÃĄ menos de 100 MB do espaço do volume disponível posteriormente. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>A instalaçÃĢo usarÃĄ %1 de espaço em disco.</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>Desi&nstalar</translation> </message> <message> <source>Uninstalling %1</source> <translation>Desinstalando %1</translation> </message> <message> <source>&Update</source> <translation>At&ualizar</translation> </message> <message> <source>Updating components of %1</source> <translation>Atualizando componentes de %1</translation> </message> <message> <source>&Install</source> <translation>&Instalar</translation> </message> <message> <source>Installing %1</source> <translation>Instalando %1</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>Concluindo o Assistente %1</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>Clique em %1 para sair do Assistente %2.</translation> </message> <message> <source>Restart</source> <translation>Reiniciar</translation> </message> <message> <source>Run %1 now.</source> <translation>Executar %1 agora.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>O Assistente %1 falhou.</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>Concluindo o Assistente de ConfiguraçÃĢo %1</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>Mostrar &Detalhes</translation> </message> <message> <source>&Hide Details</source> <translation>&Esconder Detalhes</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source>Registering file types is only supported on Windows.</source> <translation>O registro de tipos de arquivos ÃĐ suportado apenas no Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>Registro de Tipo de Arquivo: argumentos invÃĄlidos</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>NÃĢo ÃĐ possível obter autorizaçÃĢo.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>NÃĢo ÃĐ possível obter a autorizaçÃĢo necessÃĄria para continuar a instalaçÃĢo. Por favor, inicie o programa de instalaçÃĢo como um usuÃĄrio com os privilÃĐgios apropriados. Ou aceite a elevaçÃĢo de direitos de acesso se for solicitado.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>NÃĢo ÃĐ possível obter a autorizaçÃĢo necessÃĄria para continuar a instalaçÃĢo. Anule a instalaçÃĢo ou use a soluçÃĢo de fallback executando %1 como um usuÃĄrio com os privilÃĐgios apropriados e, em seguida, clicando em OK.</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>NÃĢo ÃĐ possível ler todos os dados apÃģs o envio do comando: %1. Bytes esperados: %2, Bytes recebidos: %3. Erro: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo de script em %1: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>ExceçÃĢo ao carregar o script do componente "%1" %2</translation> </message> <message> <source>Unknown error.</source> <translation>Erro desconhecido.</translation> </message> <message> <source>on line number: </source> <translation>na linha nÚmero: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>O objeto de instalaçÃĢo necessÃĄrio na operaçÃĢo %1 estÃĄ vazio.</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>Reinício AutomÃĄtico: VÃĄlido somente no modo updater ou packagemanager.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>Reinício AutomÃĄtico: Argumentos invÃĄlidos</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo de configuraçÃĩes %1 para leitura: %2</translation> </message> <message> <source>Package categories</source> <translation>Categorias de pacote</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>Argumento(s) ausente(s) "%1" chamando %2 com argumentos "%3".</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>O argumento do mÃĐtodo atual chamando "%1" com argumentos "%2" nÃĢo ÃĐ suportado. Por favor, use set, remove, add_array_value ou remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Nenhum dos argumentos pode estar vazio: origem "%1", destino "%2".</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>NÃĢo ÃĐ possível mover o arquivo de "%1" para "%2" porque o caminho de destino existe e nÃĢo ÃĐ removível.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível mover o arquivo "%1" para "%2": %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>Movendo arquivo "%1" para "%2".</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>Faltando o mecanismo principal do gerenciador de pacotes.</translation> </message> <message> <source>Empty repository URL.</source> <translation>URL do repositÃģrio vazia.</translation> </message> <message> <source>Download canceled.</source> <translation>Download cancelado.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Tempo esgotado durante o teste do repositÃģrio "%1".</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>NÃĢo ÃĐ possível analisar o arquivo Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>NÃĢo ÃĐ possível abrir o arquivo Updates.xml para leitura: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>Falha de autenticaçÃĢo.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>Erro desconhecido ao testar o repositÃģrio "%1".</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>Download concluído.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>Os hashes criptogrÃĄficos nÃĢo coincidem.</translation> </message> <message> <source>Download canceled.</source> <translation>Download cancelado.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 de %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 baixado.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/segundo)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n dia, </numerusform> <numerusform>%n dias, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n hora, </numerusform> <numerusform>%n horas, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n minuto</numerusform> <numerusform>%n minutos</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n segundo</numerusform> <numerusform>%n segundos</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - %1%2%3%4 restantes.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - tempo restante desconhecido.</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>A gravaçÃĢo no arquivo "%1" falhou: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>NÃĢo ÃĐ possível ler o arquivo de recursos "%1": %2</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>NÃĢo ÃĐ possível fazer o download de %1. A gravaçÃĢo no arquivo "%2" falhou: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>NÃĢo ÃĐ possível fazer o download de %1. NÃĢo ÃĐ possível criar o arquivo "%2": %3</translation> </message> <message> <source>%1 at %2</source> <translation>%1 em %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>Pedido de autenticaçÃĢo cancelado.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>Falha na ConexÃĢo Segura</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>Houve um erro durante a conexÃĢo com: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Isso pode ser um problema na configuraçÃĢo do servidor ou alguÃĐm tentando se passar pelo servidor.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Se vocÊ se conectou a este servidor com sucesso no passado ou confia nele, o erro pode ser temporÃĄrio e vocÊ pode tentar novamente.</translation> </message> <message> <source>Try again</source> <translation>Tente novamente</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>Cancelado</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 contÃĐm conteÚdo invÃĄlido: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>O arquivo %1 nÃĢo existe.</translation> </message> <message> <source>Cannot open %1.</source> <translation>NÃĢo ÃĐ possível abrir %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Erro de anÃĄlise em %1 em %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>Elemento raiz %1 inesperado. Deveria ser 'Packages'.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o arquivo de bloqueio "%1": %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>NÃĢo ÃĐ possível gravar o PID no arquivo de bloqueio "%1": %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>NÃĢo ÃĐ possível obter o bloqueio para o arquivo "%1": %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>NÃĢo ÃĐ possível liberar o bloqueio para o arquivo "%1": %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 inicializado</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 nÃĢo pode ser parado</translation> </message> <message> <source>Cannot stop task %1</source> <translation>NÃĢo ÃĐ possível parar a tarefa %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 nÃĢo pode ser pausado</translation> </message> <message> <source>Cannot pause task %1</source> <translation>NÃĢo ÃĐ possível pausar a tarefa %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>NÃĢo ÃĐ possível retomar a tarefa %1</translation> </message> <message> <source>%1 done</source> <translation>%1 concluído</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>NÃĢo ÃĐ possível acessar as informaçÃĩes do pacote desta aplicaçÃĢo.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Nenhuma fonte de pacote definida para esta aplicaçÃĢo.</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>%n atualizaçÃĢo encontrada.</numerusform> <numerusform>%n atualizaçÃĩes encontradas.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>Baixando o arquivo Updates.xml dos repositÃģrios de atualizaçÃĢo.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>NÃĢo ÃĐ possível baixar a fonte de pacote %1 de "%2".</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>Arquivos Updates.xml baixados das fontes de atualizaçÃĢo.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>Calculando atualizaçÃĩes aplicÃĄveis.</translation> </message> <message> <source>Application updates computed.</source> <translation>AtualizaçÃĩes aplicÃĄveis calculadas.</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1".</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>NÃĢo ÃĐ possível copiar um arquivo inexistente: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível copiar o arquivo de "%1" para "%2": %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>NÃĢo ÃĐ possível deletar o arquivo "%1": %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup em "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1".</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1": %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>NÃĢo ÃĐ possível copiar o arquivo de "%1" para "%2": %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>NÃĢo ÃĐ possível remover o arquivo "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>NÃĢo ÃĐ possível criar backup do arquivo "%1": %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>NÃĢo ÃĐ possível criar o diretÃģrio "%1": %2</translation> </message> <message> <source>Unknown error.</source> <translation>Erro desconhecido.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o diretÃģrio "%1": %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>NÃĢo ÃĐ possível remover o diretÃģrio "%1": %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>O diretÃģrio nÃĢo existe.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>NÃĢo ÃĐ possível recriar o diretÃģrio "%1": %2</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>NÃĢo ÃĐ possível encontrar o arquivo de backup para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>NÃĢo ÃĐ possível fazer o backup do arquivo "%1": %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para leitura: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>NÃĢo ÃĐ possível abrir o arquivo "%1" para gravaçÃĢo: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>NÃĢo ÃĐ possível encontrar o arquivo de backup para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1".</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>NÃĢo ÃĐ possível restaurar o arquivo de backup para "%1": %2</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>O arquivo Updates.xml contÃĐm conteÚdo invÃĄlido: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>NÃĢo ÃĐ possível ler "%1"</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>Erro de anÃĄlise em %1 em %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>Elemento raiz %1 inesperado. Deveria ser 'Updates'.</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>O elemento "ApplicationName" estÃĄ faltando.</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>O elemento "ApplicationVersion" estÃĄ faltando.</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>Elemento "PackageUpdate" sem "Name"</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>Elemento "PackageUpdate" sem "Version"</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>Elemento "PackageUpdate" sem "ReleaseDate"</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>Aguardando por %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Outra instÃĒncia %1 jÃĄ estÃĄ em execuçÃĢo. Espere atÃĐ que termine, feche ou reinicie o sistema.</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPagePrivate</name> <message> <source>Fetch</source> <translation>Buscar</translation> </message> <message> <source>Error</source> <translation>Erro</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation</name> <message> <source>Extracting "%1"</source> <translation>Extraindo "%1"</translation> </message> </context> </TS> ��������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_ru.ts�����������������������������������������0100777�0000000�0000000�00000341131�13761647206�021037� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="ru_RU"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1 Ðē %2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>ÐŸŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€ ҂ҀÐĩÐąŅƒÐĩŅ‚ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅŽ.</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐđŅ‚Ðļ Ðē ÐŋÐūзÐļ҆ÐļŅŽ %1 ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ ÐīÐ°Ð―Ð―Ņ‹Ņ… ÐūÐŋÐĩŅ€Ð°Ņ†ÐļÐđ.</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐđŅ‚Ðļ Ðē ÐŋÐūзÐļ҆ÐļŅŽ %1 ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ ÐąÐŧÐūКа Ð―Ð°ÐąÐūŅ€Ð° Ņ€ÐĩŅŅƒŅ€ŅÐūÐē.</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ ОÐĩŅ‚Ð°Ņ€ÐĩŅŅƒŅ€ŅŅ‹ %1.</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐđŅ‚Ðļ Ðē ÐŋÐūзÐļ҆ÐļŅŽ %1 ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ ҁ҇ґ҂҇ÐļКа Ðēҁ҂ҀÐūÐĩÐ―Ð―Ņ‹Ņ… ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ….</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐđŅ‚Ðļ Ðē ÐŋÐūзÐļ҆ÐļŅŽ %1 ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ ҁÐĩÐģОÐĩÐ―Ņ‚Ð° Ð―Ð°ÐąÐūŅ€Ð° Ņ€ÐĩŅŅƒŅ€ŅÐūÐē.</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>НÐĩÐūÐķÐļÐīÐ°Ð―Ð―ÐūÐĩ Ð―ÐĩҁÐūÐēÐŋаÐīÐĩÐ―ÐļÐĩ ОÐĩŅ‚Ð°Ņ€ÐĩŅŅƒŅ€ŅÐūÐē. ÐŸŅ€Ðū҇ÐļŅ‚Ð°Ð―Ðū %1, ÐūÐķÐļÐīаÐŧÐūҁҌ: %2.</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>ÐĒŅ€ÐĩÐąŅƒÐĩŅ‚ŅŅ http-Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅ</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>ДÐŧŅ ÐīÐūŅŅ‚ŅƒÐŋа К ŅŅ‚ÐūÐžŅƒ ŅÐ°ÐđŅ‚Ņƒ Ð’Ņ‹ ÐīÐūÐŧÐķÐ―Ņ‹ ÐēÐēÐĩҁ҂Ðļ ÐŧÐūÐģÐļÐ― Ðļ ÐŋÐ°Ņ€ÐūÐŧҌ.</translation> </message> <message> <source>Username:</source> <translation>ЛÐūÐģÐļÐ―:</translation> </message> <message> <source>Password:</source> <translation>ÐŸÐ°Ņ€ÐūÐŧҌ:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 Ðē %2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>ÐŸŅƒŅ‚ŅŒ ÂŦ%1Âŧ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚, Ð―Ðū Ð―Ðĩ ŅÐēÐŧŅÐĩŅ‚ŅŅ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģÐūО.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūÐŋŅ€ÐĩÐīÐĩÐŧÐļŅ‚ŅŒ ÐŋŅƒŅ‚ŅŒ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° Ð°Ņ€Ņ…ÐļÐēа %1.</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ŅŅƒŅ‰Ðĩҁ҂ÐēŅƒŅŽŅ‰ŅƒŅŽ ҁÐļОÐēÐūÐŧŅŒÐ―ŅƒŅŽ ҁҁҋÐŧÐšŅƒ %1.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ҁÐļОÐēÐūÐŧŅŒÐ―ŅƒŅŽ ҁҁҋÐŧÐšŅƒ ÂŦ%1Âŧ, ÐŋÐūŅ‚ÐūÐžŅƒ ҇҂Ðū ҁҁҋÐŧКа ҃ÐķÐĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚.</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ ҆ÐĩÐŧҌ ҁÐļОÐēÐūÐŧŅŒÐ―ÐūÐđ ҁҁҋÐŧКÐļ Ðļз Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ҁÐļОÐēÐūÐŧŅŒÐ―ŅƒŅŽ ҁҁҋÐŧÐšŅƒ %1: %2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>ОÐķÐļÐīÐ°Ð―ÐļÐĩ %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>Ð”Ņ€ŅƒÐģÐūÐđ ŅÐšÐ·ÐĩОÐŋÐŧŅŅ€ %1 ҃ÐķÐĩ Ņ€Ð°ÐąÐūŅ‚Ð°ÐĩŅ‚. ДÐūÐķÐīÐļŅ‚ÐĩҁҌ ÐĩÐģÐū заÐēÐĩŅ€ŅˆÐĩÐ―ÐļŅ, Ð·Ð°ÐšŅ€ÐūÐđŅ‚Ðĩ ÐĩÐģÐū ÐļÐŧÐļ ÐŋÐĩŅ€ÐĩзаÐģŅ€ŅƒÐ·ÐļŅ‚Ðĩ ҁÐļҁ҂ÐĩÐžŅƒ.</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹, ÐīÐūÐąÐ°ÐēÐŧÐĩÐ―Ð―Ņ‹Ðĩ КаК аÐēŅ‚ÐūÐžÐ°Ņ‚Ðļ҇ÐĩŅÐšÐļÐĩ заÐēÐļҁÐļОÐūҁ҂Ðļ:</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ ҁ Ņ€Ð°Ð·Ņ€ÐĩŅˆŅ‘Ð―Ð―Ņ‹ÐžÐļ заÐēÐļҁÐļОÐūŅŅ‚ŅÐžÐļ:</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>Ð’Ņ‹ÐąŅ€Ð°Ð―Ð―Ņ‹Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ ÐąÐĩз заÐēÐļҁÐļОÐūҁ҂ÐĩÐđ:</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹, ÐīÐūÐąÐ°ÐēÐŧÐĩÐ―Ð―Ņ‹Ðĩ КаК заÐēÐļҁÐļОÐūҁ҂Ðļ ÐīÐŧŅ ÂŦ%1Âŧ:</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ð° Ņ€ÐĩÐšŅƒŅ€ŅÐļŅ: КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ÂŦ%1Âŧ ҃ÐķÐĩ ÐīÐūÐąÐ°ÐēÐŧÐĩÐ― ÐŋÐū ÐŋŅ€Ðļ҇ÐļÐ―Ðĩ: ÂŦ%2Âŧ</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð―Ð°ÐđŅ‚Ðļ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ÂŦ%1Âŧ, Ð―ÐĩÐūÐąŅ…ÐūÐīÐļÐžŅ‹Ðđ ÐīÐŧŅ ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>ÐžŅ‚ÐžÐĩÐ―ÐĩÐ―Ðū</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð―Ð°ÐđŅ‚Ðļ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot copy a non-existent file: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ ÐūŅ‚ŅŅƒŅ‚ŅŅ‚ÐēŅƒŅŽŅ‰ÐļÐđ Ņ„Ð°ÐđÐŧ: %1</translation> </message> <message> <source>Cannot backup file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ Ðļз ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ðē ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° заÐēÐĩŅ€ŅˆÐĩÐ―Ð°.</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>ÐĨÐĩ҈-ŅŅƒÐžÐžŅ‹ Ð―Ðĩ ҁÐūÐēÐŋаÐīÐ°ŅŽŅ‚.</translation> </message> <message> <source>Download canceled.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ð°.</translation> </message> <message> <source>%1 of %2</source> <translation>%1 Ðļз %2</translation> </message> <message> <source>%1 downloaded.</source> <translation>заÐģŅ€ŅƒÐķÐĩÐ―Ðū %1.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/ҁ)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n ÐīÐĩÐ―ŅŒ, </numerusform> <numerusform>%n ÐīÐ―Ņ, </numerusform> <numerusform>%n ÐīÐ―ÐĩÐđ, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n Ņ‡Ð°Ņ, </numerusform> <numerusform>%n Ņ‡Ð°ŅÐ°, </numerusform> <numerusform>%n Ņ‡Ð°ŅÐūÐē, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n ОÐļÐ―ŅƒŅ‚Ð°</numerusform> <numerusform>%n ОÐļÐ―ŅƒŅ‚Ņ‹</numerusform> <numerusform>%n ОÐļÐ―ŅƒŅ‚</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n ҁÐĩÐšŅƒÐ―Ðīа</numerusform> <numerusform>%n ҁÐĩÐšŅƒÐ―ÐīŅ‹</numerusform> <numerusform>%n ҁÐĩÐšŅƒÐ―Ðī</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - ÐūŅŅ‚Ð°ÐŧÐūҁҌ %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - ÐēŅ€ÐĩÐžŅ ÐūКÐūÐ―Ņ‡Ð°Ð―ÐļŅ заÐģŅ€ŅƒÐ·ÐšÐļ Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―Ðū.</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>%1 at %2</source> <translation>%1 Ðē %2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>ЗаÐŋŅ€Ðūҁ Ð―Ð° Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅŽ ÐūŅ‚ÐžÐĩÐ―Ņ‘Ð―.</translation> </message> <message> <source>Secure Connection Failed</source> <translation>ÐĄÐąÐūÐđ ÐąÐĩзÐūÐŋÐ°ŅÐ―ÐūÐģÐū ҁÐūÐĩÐīÐļÐ―ÐĩÐ―ÐļŅ</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ðū҈ÐļÐąÐšÐ° ÐŋÐūÐīКÐŧŅŽŅ‡ÐĩÐ―ÐļŅ К: %1.</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>Ð­Ņ‚Ðū ÐēÐūзОÐūÐķÐ―Ðū ÐļÐŧÐļ Ðļз-за ÐŋŅ€ÐūÐąÐŧÐĩО ҁ Ð―Ð°ŅŅ‚Ņ€ÐūÐđКÐūÐđ ҁÐĩŅ€ÐēÐĩŅ€Ð°, ÐļÐŧÐļ Ðļз-за ÐŋÐūÐŋŅ‹Ņ‚ÐšÐļ зÐŧÐūŅƒÐžŅ‹ŅˆÐŧÐĩÐ―Ð―ÐļКа ÐŋÐūÐīОÐĩÐ―ÐļŅ‚ŅŒ ҁÐĩŅ€ÐēÐĩŅ€.</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>Ð•ŅÐŧÐļ ÐēŅ‹ Ņ€Ð°Ð―ŅŒŅˆÐĩ ҃ҁÐŋÐĩŅˆÐ―Ðū ÐŋÐūÐīКÐŧŅŽŅ‡Ð°ÐŧÐļҁҌ К ŅŅ‚ÐūÐžŅƒ ҁÐĩŅ€ÐēÐĩŅ€Ņƒ ÐļÐŧÐļ ÐīÐūÐēÐĩŅ€ŅÐĩŅ‚Ðĩ ÐĩÐžŅƒ, Ņ‚Ðū Ðū҈ÐļÐąÐšÐ° ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐēŅ€ÐĩОÐĩÐ―Ð―ÐūÐđ, Ðļ ÐēŅ‹ ОÐūÐķÐĩŅ‚Ðĩ ÐŋÐūÐēŅ‚ÐūŅ€ÐļŅ‚ŅŒ Ðĩ҉ґ Ņ€Ð°Ð·.</translation> </message> <message> <source>Try again</source> <translation>ПÐūÐēŅ‚ÐūŅ€ÐļŅ‚ŅŒ</translation> </message> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ ÂŦ%1Âŧ: НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ðē Ņ„Ð°ÐđÐŧ ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ ÂŦ%1Âŧ. НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÂŦ%2Âŧ: %3</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ðē ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown error.</source> <translation>НÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ°.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð―Ð°ÐđŅ‚Ðļ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐēÐūŅŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ Ņ€ÐĩŅŅƒŅ€ŅÐūÐē ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>The directory does not exist.</source> <translation>ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ Ð―Ðĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚.</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 заÐŋŅƒŅ‰ÐĩÐ―Ð°</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐūŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð°</translation> </message> <message> <source>Cannot stop task %1</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐūŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ заÐīÐ°Ņ‡Ņƒ %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐŋŅ€ÐļÐūŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð°</translation> </message> <message> <source>Cannot pause task %1</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€ÐļÐūŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ ÐēŅ‹ÐŋÐūÐŧÐ―ÐĩÐ―ÐļÐĩ заÐīÐ°Ņ‡Ðļ %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€ÐūÐīÐūÐŧÐķÐļŅ‚ŅŒ ÐēŅ‹ÐŋÐūÐŧÐ―ÐĩÐ―ÐļÐĩ заÐīÐ°Ņ‡Ðļ %1</translation> </message> <message> <source>%1 done</source> <translation>%1 ÐēŅ‹ÐŋÐūÐŧÐ―ÐĩÐ―Ð°</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>ÐŸŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļÐĩ Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŒ ÐīÐūŅŅ‚ŅƒÐŋ К ÐļÐ―Ņ„ÐūŅ€ÐžÐ°Ņ†ÐļÐļ Ðū ÐŋаКÐĩŅ‚Ð°Ņ….</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ðū %n ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐĩ.</numerusform> <numerusform>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ðū %n ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ.</numerusform> <numerusform>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ðū %n ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐđ.</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>ЗаÐģŅ€ŅƒÐķаÐĩŅ‚ŅŅ Ņ„Ð°ÐđÐŧ Updates.xml ҁ ҁÐĩŅ€ÐēÐĩŅ€Ð° ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐđ.</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° Ņ„Ð°ÐđÐŧа Updates.xml заÐēÐĩŅ€ŅˆÐĩÐ―Ð°.</translation> </message> <message> <source>Computing applicable updates.</source> <translation>ПÐūÐīÐģÐūŅ‚ÐūÐēКа ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐđ ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Application updates computed.</source> <translation>ÐžÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ ÐŋÐūÐīÐģÐūŅ‚ÐūÐēÐŧÐĩÐ―Ņ‹.</translation> </message> <message> <source>No package sources set for this application.</source> <translation>Ð˜ŅŅ…ÐūÐīÐ―ÐļКÐļ ÐŋаКÐĩŅ‚Ð° Ð―Ðĩ заÐīÐ°Ð―Ņ‹ ÐīÐŧŅ ŅŅ‚ÐūÐģÐū ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ Ðļҁ҅ÐūÐīÐ―ÐļК ÐŋаКÐĩŅ‚Ð° ÂŦ%1Âŧ Ðļз ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>ÐĪаÐđÐŧ Updates.xml ҁÐūÐīÐĩŅ€ÐķÐļŅ‚ Ð―ÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðĩ ÐīÐ°Ð―Ð―Ņ‹Ðĩ: %1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ ÂŦ%1Âŧ</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ņ€Ð°Ð·ÐąÐūŅ€Ð° XML Ðē %1 Ðē %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>НÐĩÐŋŅ€ÐĩÐīÐēÐļÐīÐĩÐ―Ð―Ņ‹Ðđ КÐūŅ€Ð―ÐĩÐēÐūÐđ ŅÐŧÐĩОÐĩÐ―Ņ‚ %1, ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ ÂŦUpdatesÂŧ.</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>ÐžŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ŅÐŧÐĩОÐĩÐ―Ņ‚ "ApplicationName".</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>ÐžŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ŅÐŧÐĩОÐĩÐ―Ņ‚ "ApplicationVersion".</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>ÐĢ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° PackageUpdate ÐūŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ÐŋÐūÐŧÐĩ "Name"</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>ÐĢ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° PackageUpdate ÐūŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ÐŋÐūÐŧÐĩ "Version"</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>ÐĢ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° PackageUpdate ÐūŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ÐŋÐūÐŧÐĩ "ReleaseDate"</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>Unknown exception caught (%1)</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ (%1)</translation> </message> <message> <source>internal code: %1</source> <translation>ÐēÐ―ŅƒŅ‚Ņ€ÐĩÐ―Ð―ÐļÐđ КÐūÐī Ðū҈ÐļÐąÐšÐļ: %1</translation> </message> <message> <source>not enough memory</source> <translation>Ð―ÐĩÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ÐŋÐ°ÐžŅŅ‚Ðļ</translation> </message> <message> <source>Error: %1</source> <translation>ÐžŅˆÐļÐąÐšÐ°: %1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŒ ҁÐēÐūÐđҁ҂ÐēÐū %1 ÐīÐŧŅ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° %2.</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>ÐĄÐēÐūÐđҁ҂ÐēÐū %1 ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° %2 ÐūŅ‚Ð―ÐūҁÐļŅ‚ŅŅ Ð―Ðĩ К Ņ‚ÐļÐŋ҃ VT_FILETIME, а К %3.</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€ÐĩÐūÐąŅ€Ð°Ð·ÐūÐēÐ°Ņ‚ŅŒ UTC ÐēŅ€ÐĩÐžŅ Ņ„Ð°ÐđÐŧа Ðē ҁÐļҁ҂ÐĩÐžÐ―ÐūÐĩ ÐēŅ€ÐĩÐžŅ.</translation> </message> <message> <source>Cannot load codecs.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ КÐūÐīÐĩКÐļ.</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūÐŋŅ€ÐĩÐīÐĩÐŧÐļŅ‚ŅŒ КÐūÐŧÐļ҇Ðĩҁ҂ÐēÐū ŅÐŧÐĩОÐĩÐ―Ņ‚ÐūÐē Ð°Ņ€Ņ…ÐļÐēа.</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūÐŋŅ€ÐĩÐīÐĩÐŧÐļŅ‚ŅŒ ÐŋŅƒŅ‚ŅŒ ŅÐŧÐĩОÐĩÐ―Ņ‚Ð° Ð°Ņ€Ņ…ÐļÐēа ÂŦ%1Âŧ.</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ (%1).</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ðđ Ņ„Ð°ÐđÐŧ: %1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>НÐĩÐŋÐūÐīÐīÐĩŅ€ÐķÐļÐēаÐĩÐžŅ‹Ðđ Ņ‚ÐļÐŋ Ð°Ņ€Ņ…ÐļÐēа.</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ŅŅ‚Ð°Ņ€Ņ‹Ðđ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐļОÐĩÐ―ÐūÐēÐ°Ņ‚ŅŒ ŅŅ‚Ð°Ņ€Ņ‹Ðđ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 ҁÐūÐīÐĩŅ€ÐķÐļŅ‚ Ð―ÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðĩ ÐīÐ°Ð―Ð―Ņ‹Ðĩ: %2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>ÐĪаÐđÐŧ %1 Ð―Ðĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚.</translation> </message> <message> <source>Cannot open %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ %1.</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ņ€Ð°Ð·ÐąÐūŅ€Ð° Ðē %1 Ðē %2, %3: %4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>НÐĩÐŋŅ€ÐĩÐīÐēÐļÐīÐĩÐ―Ð―Ņ‹Ðđ КÐūŅ€Ð―ÐĩÐēÐūÐđ ŅÐŧÐĩОÐĩÐ―Ņ‚ %1, ÐīÐūÐŧÐķÐĩÐ― ÐąŅ‹Ņ‚ŅŒ ÂŦPackagesÂŧ.</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÐąÐŧÐūКÐļŅ€ÐūÐēКÐļ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ PID Ðē Ņ„Ð°ÐđÐŧ ÐąÐŧÐūКÐļŅ€ÐūÐēКÐļ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð·Ð°ÐąÐŧÐūКÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ņ€Ð°Ð·ÐąÐŧÐūКÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>bytes</source> <translation>ÐąÐ°ÐđŅ‚(ÐūÐē)</translation> </message> <message> <source>KB</source> <translation>КБ</translation> </message> <message> <source>MB</source> <translation>МБ</translation> </message> <message> <source>GB</source> <translation>ГБ</translation> </message> <message> <source>TB</source> <translation>ÐĒБ</translation> </message> <message> <source>PB</source> <translation>ПБ</translation> </message> <message> <source>EB</source> <translation>ЭБ</translation> </message> <message> <source>ZB</source> <translation>ЗБ</translation> </message> <message> <source>YB</source> <translation>ИБ</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ðđ Ņ„Ð°ÐđÐŧ %1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ðđ Ņ„Ð°ÐđÐŧ ÐīÐŧŅ ŅˆÐ°ÐąÐŧÐūÐ―Ð° %1: %2</translation> </message> <message> <source>No marker found, stopped after %1.</source> <translation>ÐœÐ°Ņ€ÐšÐĩŅ€ Ð―Ðĩ Ð―Ð°ÐđÐīÐĩÐ―, ÐūŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ðū ÐŋÐūҁÐŧÐĩ %1.</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ ÐŋÐūҁÐŧÐĩ %1 ÐąÐ°ÐđŅ‚: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>ÐĄÐąÐūÐđ заÐŋÐļҁÐļ ҁ %1 ÐąÐ°ÐđŅ‚Ð°: %2</translation> </message> <message> <source>The specified module could not be found.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð―Ð°ÐđŅ‚Ðļ ŅƒÐšÐ°Ð·Ð°Ð―Ð―Ņ‹Ðđ ОÐūÐī҃ÐŧҌ.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Copy failed: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ: %1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩОÐĩҁ҂ÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>ÐĢ ÐšÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐŋÐūŅ‚ÐūОКÐūÐē Ðē Ņ€ÐĩÐķÐļОÐĩ ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐēŅ‹ÐŋÐūÐŧÐ―ÐļŅ‚ŅŒ ОÐĩŅ‚ÐūÐī isDefault Ðē ҁ҆ÐĩÐ―Ð°Ņ€ÐļÐļ %1</translation> </message> <message> <source>There was an error loading the selected component. This component can not be installed.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ðū҈ÐļÐąÐšÐ° ÐŋŅ€Ðļ заÐģŅ€ŅƒÐ·ÐšÐĩ ÐēŅ‹ÐąŅ€Ð°Ð―Ð―ÐūÐģÐū КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð°. ÐĢŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ ÐĩÐģÐū Ð―Ðĩ ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŅ.</translation> </message> <message> <source>Update Info: </source> <translation>Ð˜Ð―Ņ„ÐūŅ€ÐžÐ°Ņ†ÐļŅ ÐūÐą ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐļ: </translation> </message> <message> <source>There was an error loading the selected component. This component can not be updated.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ðū҈ÐļÐąÐšÐ° ÐŋŅ€Ðļ заÐģŅ€ŅƒÐ·ÐšÐĩ ÐēŅ‹ÐąŅ€Ð°Ð―Ð―ÐūÐģÐū КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð°. ÐžÐąÐ―ÐūÐēÐļŅ‚ŅŒ ÐĩÐģÐū Ð―Ðĩ ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŅ.</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ заÐŋŅ€Ðū҈ÐĩÐ―Ð―Ņ‹Ðđ UI Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ заÐŋŅ€Ðū҈ÐĩÐ―Ð―Ņ‹Ðđ UI Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ заÐŋŅ€Ðū҈ÐĩÐ―Ð―Ņ‹Ðđ Ņ„Ð°ÐđÐŧ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐļ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>ÐžŅˆÐļÐąÐšÐ°: ÐūÐŋÐĩŅ€Ð°Ņ†ÐļŅ %1 Ð―Ðĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚.</translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component Name</source> <translation>Ð˜ÐžŅ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð°</translation> </message> <message> <source>Action</source> <translation>ДÐĩÐđҁ҂ÐēÐļÐĩ</translation> </message> <message> <source>Installed Version</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð―Ð°Ņ ÐēÐĩҀҁÐļŅ</translation> </message> <message> <source>New Version</source> <translation>НÐūÐēÐ°Ņ ÐēÐĩҀҁÐļŅ</translation> </message> <message> <source>Release Date</source> <translation>Ð”Ð°Ņ‚Ð° ÐēŅ‹ÐŋŅƒŅÐšÐ°</translation> </message> <message> <source>Size</source> <translation>РазОÐĩŅ€</translation> </message> <message> <source>Component is marked for installation.</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ÐēŅ‹ÐąŅ€Ð°Ð― ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ.</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ÐēŅ‹ÐąŅ€Ð°Ð― ÐīÐŧŅ ҃ÐīаÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Component is installed.</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―.</translation> </message> <message> <source>Component is not installed.</source> <translation>КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ Ð―Ðĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―.</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translatorcomment>Ð―Ð°ÐąÐūŅ€ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē ÐŋÐū ŅƒÐžÐūÐŧŅ‡Ð°Ð―ÐļŅŽ</translatorcomment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>&ПÐū ŅƒÐžÐūÐŧŅ‡Ð°Ð―ÐļŅŽ</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translatorcomment>ÐūŅ‚ÐžÐĩÐ―ÐļŅ‚ŅŒ ÐēŅ‹ÐąÐūŅ€ Ð―ÐūÐēҋ҅ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translatorcomment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>&ÐžŅ‚ÐžÐĩÐ―ÐļŅ‚ŅŒ</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translatorcomment>ÐēŅ‹ÐąŅ€Ð°Ņ‚ŅŒ ÐēҁÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹</translatorcomment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>&Ð’Ņ‹ÐąŅ€Ð°Ņ‚ŅŒ Ðēҁґ</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translatorcomment>ŅÐ―ŅŅ‚ŅŒ ÐūŅ‚ÐžÐĩŅ‚ÐšÐļ ÐēŅ‹ÐąÐūŅ€Ð° ҁÐū ÐēҁÐĩŅ… КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translatorcomment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>&ÐĄÐ―ŅŅ‚ŅŒ ÐūŅ‚ÐžÐĩŅ‚ÐšÐļ ÐēŅ‹ÐąÐūŅ€Ð° ҁÐū ÐēҁÐĩŅ… КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translation> </message> <message> <source>&Browse QBSP files</source> <translation>&ÐžÐąÐ·ÐūŅ€ Ņ„Ð°ÐđÐŧÐūÐē QBSP</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>Ð­Ņ‚ÐūŅ‚ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ заÐđÐžŅ‘Ņ‚ ÐŋŅ€ÐļÐąÐŧÐļзÐļŅ‚ÐĩÐŧŅŒÐ―Ðū %1 Ð―Ð° ÐķÐĩŅŅ‚ÐšÐūО ÐīÐļŅÐšÐĩ.</translation> </message> <message> <source>Select Components</source> <translation>Ð’Ņ‹ÐąÐūŅ€ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐēŅ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹, КÐūŅ‚ÐūҀҋÐĩ ÐēŅ‹ Ņ…ÐūŅ‚ÐļŅ‚Ðĩ ÐūÐąÐ―ÐūÐēÐļŅ‚ŅŒ.</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐēŅ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹, КÐūŅ‚ÐūҀҋÐĩ ÐēŅ‹ Ņ…ÐūŅ‚ÐļŅ‚Ðĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ.</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐēŅ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹, КÐūŅ‚ÐūҀҋÐĩ ÐēŅ‹ Ņ…ÐūŅ‚ÐļŅ‚Ðĩ ҃ÐīаÐŧÐļŅ‚ŅŒ.</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. ДÐŧŅ ҃ÐīаÐŧÐĩÐ―ÐļŅ ҃ÐķÐĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð―Ņ‹Ņ… КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē ŅÐ―ÐļОÐļŅ‚Ðĩ ÐūŅ‚ÐžÐĩŅ‚ÐšÐļ ÐēŅ‹ÐąÐūŅ€Ð°. ÐĢÐķÐĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð―Ņ‹Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ Ð―Ðĩ ÐąŅƒÐīŅƒŅ‚ ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―Ņ‹.</translation> </message> <message> <source>Open File</source> <translation>ÐžŅ‚ÐšŅ€Ņ‹Ņ‚ÐļÐĩ Ņ„Ð°ÐđÐŧа</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPagePrivate</name> <message> <source>Filter</source> <translation>ÐžŅ‚Ņ„ÐļÐŧŅŒŅ‚Ņ€ÐūÐēÐ°Ņ‚ŅŒ</translation> </message> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>В ÐūÐŋÐĩŅ€Ð°Ņ†ÐļÐļ ÂŦ%1Âŧ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļÐžŅ‹Ðđ ÐūÐąŅŠÐĩÐšŅ‚ ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа ÐŋŅƒŅŅ‚.</translation> </message> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><ҁÐūŅ…Ņ€Ð°Ð―ŅÐĩОÐūÐĩ ÐļÐžŅ КÐŧŅŽŅ‡Ð° ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа> <ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžÐ°> [ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ1] [ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ2] [...]</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ҁÐūŅ…Ņ€Ð°Ð―ÐļŅ‚ŅŒ ÐēŅ‹ÐēÐūÐī ÂŦ%1Âŧ Ðē ÐŋŅƒŅŅ‚ÐūÐĩ Ð·Ð―Ð°Ņ‡ÐĩÐ―ÐļÐĩ КÐŧŅŽŅ‡Ð° ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа.</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>ÐĪаÐđÐŧ ÂŦ%1Âŧ Ð―Ðĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚ ÐļÐŧÐļ Ð―Ðĩ ŅÐēÐŧŅÐĩŅ‚ŅŅ ÐļҁÐŋÐūÐŧÐ―ŅÐĩÐžŅ‹Ðž.</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>ЗаÐŋŅƒŅÐš ÂŦ%1Âŧ заÐēÐĩŅ€ŅˆÐļÐŧŅŅ ÐšŅ€Ð°Ņ…ÐūО.</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><Ðļҁ҂ÐūŅ‡Ð―ÐļК> <Ð―Ð°Ð·Ð―Ð°Ņ‡ÐĩÐ―ÐļÐĩ> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>НÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðđ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ Ðē %1: ҂ҀÐĩŅ‚ŅŒÐļО ÐŋÐ°Ņ€Ð°ÐžÐĩ҂ҀÐūО ÐīÐūÐŧÐķÐĩÐ― ÐąŅ‹Ņ‚ŅŒ "forceOverwrite", ÐĩҁÐŧÐļ ÐūÐ― заÐīÐ°Ð―.</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>НÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%2Âŧ Ð―ÐĩÐēÐĩŅ€ÐĩÐ―.</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ.</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩзаÐŋÐļŅÐ°Ņ‚ŅŒ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>НÐĩÐēÐĩŅ€Ð―ÐūÐĩ ҇ÐļҁÐŧÐū ŅÐŧÐĩОÐĩÐ―Ņ‚ÐūÐē task.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ðē ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩзаÐŋÐļŅÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū заÐŋÐļŅÐ°Ņ‚ŅŒ Desktop Entry Ðē ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ҁҁҋÐŧÐšŅƒ ҁ ÂŦ%1Âŧ Ð―Ð° ÂŦ%2Âŧ.</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ҁҁҋÐŧÐšŅƒ ҁ ÂŦ%1Âŧ Ð―Ð° ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Unknown exception caught: %1.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ: %1.</translation> </message> <message> <source>Cannot set permissions for file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ ÐŋŅ€Ð°Ðēа ÐīÐūŅŅ‚ŅƒÐŋа К Ņ„Ð°ÐđÐŧ҃ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩОÐĩҁ҂ÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐē҉ÐļК Ðē ÂŦ%1Âŧ ÐīÐūÐŧÐķÐĩÐ― ÐąŅ‹Ņ‚ŅŒ Ðū҄҄ÐŧаÐđÐ―ÐūÐēŅ‹Ðž.</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ.</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ҆ÐĩÐŧÐĩÐēÐūÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ.</translation> </message> <message> <source>Removing file "%1".</source> <translation>ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><҆ÐĩÐŧҌ> <Ņ€Ð°Ð·ÐžÐĩ҉ÐĩÐ―ÐļÐĩ ҁҁҋÐŧКÐļ> [ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ ҆ÐĩÐŧÐļ] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩзаÐŋÐļŅÐ°Ņ‚ŅŒ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ҁҁҋÐŧÐšŅƒ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>ÐžŅ‚ÐžÐĩÐ―ÐĩÐ―Ðū</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ Ņ…Ðĩ҈-ҁÐļÐģÐ―Ð°Ņ‚ŅƒŅ€Ņƒ.</translation> </message> <message> <source>Download Error</source> <translation>ÐžŅˆÐļÐąÐšÐ° заÐģŅ€ŅƒÐ·ÐšÐļ</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€ÐūÐēÐĩŅ€ÐļŅ‚ŅŒ ҆ÐĩÐŧÐūŅŅ‚Ð―ÐūŅŅ‚ŅŒ Ņ…ÐĩŅˆÐ° Ðē ÐŋŅ€Ðū҆ÐĩҁҁÐĩ заÐģŅ€ŅƒÐ·ÐšÐļ. ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐŋÐūÐēŅ‚ÐūŅ€ÐļŅ‚Ðĩ ÐūÐŋÐĩŅ€Ð°Ņ†ÐļŅŽ.</translation> </message> <message> <source>Cannot verify Hash</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€ÐūÐēÐĩŅ€ÐļŅ‚ŅŒ Ņ…Ðĩ҈</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŒ Ð°Ņ€Ņ…ÐļÐēŅ‹ :%1 ÐžŅˆÐļÐąÐšÐ° Ðē ÐŋŅ€Ðū҆ÐĩҁҁÐĩ заÐģŅ€ŅƒÐ·ÐšÐļ %2</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° Ð°Ņ€Ņ…ÐļÐēа ÂŦ%1Âŧ ÐīÐŧŅ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð° ÂŦ%2Âŧ.</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>ÐĄŅ…ÐĩОа %1 Ð―Ðĩ ÐŋÐūÐīÐīÐĩŅ€ÐķÐļÐēаÐĩŅ‚ŅŅ (URL: %2).</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ð―Ð°ÐđŅ‚Ðļ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ ÐīÐŧŅ %1.</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Pause and resume not supported by network transfers.</source> <translation>ÐŸŅ€ÐļÐūŅŅ‚Ð°Ð―ÐūÐēКа Ðļ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļÐĩ Ð―Ðĩ ÐŋÐūÐīÐīÐĩŅ€ÐķÐļÐēÐ°ŅŽŅ‚ŅŅ ҁÐĩŅ‚ÐĩÐēŅ‹ÐžÐļ ÐŋŅ€ÐūŅ‚ÐūКÐūÐŧаОÐļ.</translation> </message> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>ÂŦ%1Âŧ ҃ÐķÐĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚, Ð―Ðū Ð―Ðĩ ŅÐēÐŧŅÐĩŅ‚ŅŅ Ņ„Ð°ÐđÐŧÐūО.</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ðē ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ðū КÐūÐŧŅŒŅ†Ðū ÐŋÐĩŅ€ÐĩÐ―Ð°ÐŋŅ€Ð°ÐēÐŧÐĩÐ―ÐļÐđ ÂŦ%1Âŧ.</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ðū҈ÐļÐąÐšÐ° ҁÐĩŅ‚Ðļ ÐŋŅ€Ðļ заÐģŅ€ŅƒÐ·ÐšÐĩ ÂŦ%1Âŧ: %2.</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ° ҁÐĩŅ‚Ðļ ÐēÐū ÐēŅ€ÐĩÐžŅ заÐģŅ€ŅƒÐ·ÐšÐļ ÂŦ%1Âŧ.</translation> </message> <message> <source>Network transfers canceled.</source> <translation>ÐĄÐĩŅ‚ÐĩÐēŅ‹Ðĩ ÐŋÐĩŅ€ÐĩÐīÐ°Ņ‡Ðļ ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ņ‹.</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðđ URL Ðļҁ҂ÐūŅ‡Ð―ÐļКа ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋŅƒŅŅ‚ÐļŅ‚ŅŒ Ðū҂҆ÐĩÐŋÐŧŅ‘Ð―Ð―Ņ‹Ðž: ÂŦ%1Âŧ</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋŅƒŅŅ‚ÐļŅ‚ŅŒ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>ÐŸŅ€ÐūÐģŅ€Ð°ÐžÐžÐ° заÐēÐĩŅ€ŅˆÐļÐŧÐ°ŅŅŒ ÐšŅ€Ð°Ņ…ÐūО: ÂŦ%1Âŧ</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐļҁÐŋÐūÐŧÐ―ÐļŅ‚ŅŒ (Ð―ÐĩÐūÐķÐļÐīÐ°Ð―Ð―Ņ‹Ðđ КÐūÐī заÐēÐĩŅ€ŅˆÐĩÐ―ÐļŅ: %1): ÂŦ%2Âŧ</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation</name> <message> <source>Extracting "%1"</source> <translation>ИзÐēÐŧÐĩ҇ÐĩÐ―ÐļÐĩ ÂŦ%1Âŧ</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ð°Ņ€Ņ…ÐļÐē ÂŦ%1Âŧ ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ: %2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐļзÐēÐŧÐĩ҇ÐĩÐ―ÐļŅ Ðļз Ð°Ņ€Ņ…ÐļÐēа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>В ÐŋŅ€Ðū҆ÐĩҁҁÐĩ ÐļзÐēÐŧÐĩ҇ÐĩÐ―ÐļŅ ÂŦ%1Âŧ ÐēÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ.</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋÐūÐŧŅƒŅ‡ÐļŅ‚ŅŒ ŅÐīŅ€Ðū ОÐĩÐ―ÐĩÐīÐķÐĩŅ€Ð° ÐŋаКÐĩŅ‚ÐūÐē.</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>ДÐŧŅ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļŅ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОÐū заÐēÐĩŅ€ŅˆÐļŅ‚ŅŒ ÐŋŅ€Ðū҆Ðĩҁҁ %1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>ДÐŧŅ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļŅ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОÐū заÐēÐĩŅ€ŅˆÐļŅ‚ŅŒ ŅŅ‚Ðļ ÐŋŅ€Ðū҆Ðĩҁҁҋ: %1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1 Ðļз %2</translation> </message> <message> <source>%1 received.</source> <translation>%1 ÐŋÐūÐŧŅƒŅ‡ÐĩÐ―Ðū.</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/ҁ)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n ÐīÐĩÐ―ŅŒ, </numerusform> <numerusform>%n ÐīÐ―Ņ, </numerusform> <numerusform>%n ÐīÐ―ÐĩÐđ, </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n Ņ‡Ð°Ņ, </numerusform> <numerusform>%n Ņ‡Ð°ŅÐ°, </numerusform> <numerusform>%n Ņ‡Ð°ŅÐūÐē, </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n ОÐļÐ―ŅƒŅ‚Ð°</numerusform> <numerusform>%n ОÐļÐ―ŅƒŅ‚Ņ‹</numerusform> <numerusform>%n ОÐļÐ―ŅƒŅ‚</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n ҁÐĩÐšŅƒÐ―Ðīа</numerusform> <numerusform>%n ҁÐĩÐšŅƒÐ―ÐīŅ‹</numerusform> <numerusform>%n ҁÐĩÐšŅƒÐ―Ðī</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - ÐūŅŅ‚Ð°ÐŧÐūҁҌ %1%2%3%4.</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - ÐēŅ€ÐĩÐžŅ ÐūКÐūÐ―Ņ‡Ð°Ð―ÐļŅ заÐģŅ€ŅƒÐ·ÐšÐļ Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―Ðū.</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>ЗаÐēÐĩŅ€ŅˆÐĩÐ―ÐļÐĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ %1</translation> </message> <message> <source>Restart</source> <translation>ПÐĩŅ€ÐĩзаÐŋŅƒŅŅ‚ÐļŅ‚ŅŒ</translation> </message> <message> <source>Run %1 now.</source> <translation>ЗаÐŋŅƒŅŅ‚ÐļŅ‚ŅŒ %1 ҁÐĩÐđŅ‡Ð°Ņ.</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа %1 Ð―Ðĩ ҃ÐīаÐŧÐ°ŅŅŒ.</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>НаÐķОÐļŅ‚Ðĩ ÂŦ%1Âŧ ÐīÐŧŅ Ðēҋ҅ÐūÐīа Ðļз ÐžÐ°ŅŅ‚ÐĩŅ€Ð° %2.</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>ÐÐ°ŅŅ‚Ņ€ÐūÐđКÐļ Ņ‚ÐūÐŧŅŒÐšÐū ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Failed to write settings.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ð―Ð°ŅŅ‚Ņ€ÐūÐđКÐļ.</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><ÐŋŅƒŅ‚ŅŒ К Ðļҁ҅ÐūÐīÐ―ÐļКаО> [ÐŋŅ€ÐĩŅ„ÐļÐšŅ ÐēÐĩÐ―ÐīÐūŅ€Ð°]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðđ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ: Ðļҁ҅ÐūÐīÐ―Ņ‹Ðđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐŋŅƒŅŅ‚Ņ‹Ðž.</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ Ņ€ÐĩзÐĩŅ€ÐēÐ―ŅƒŅŽ КÐūÐŋÐļŅŽ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩзаÐŋÐļŅÐ°Ņ‚ŅŒ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ŅÐšÐūÐŋÐļŅ€ÐūÐēÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҁÐūзÐīÐ°Ņ‚ŅŒ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÂŦ%1Âŧ: %2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>ДÐūÐąŅ€Ðū ÐŋÐūÐķаÐŧÐūÐēÐ°Ņ‚ŅŒ Ðē ÐžÐ°ŅŅ‚ÐĩŅ€ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ %1.</translation> </message> <message> <source>&Add or remove components</source> <translation>&ДÐūÐąÐ°ÐēÐŧÐĩÐ―ÐļÐĩ ÐļÐŧÐļ ҃ÐīаÐŧÐĩÐ―ÐļÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translation> </message> <message> <source>&Update components</source> <translation>&ÐžÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translation> </message> <message> <source>&Remove all components</source> <translation>&ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ ÐēҁÐĩŅ… КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>ПÐūÐŧŅƒŅ‡ÐĩÐ―ÐļÐĩ ÐļÐ―Ņ„ÐūŅ€ÐžÐ°Ņ†ÐļÐļ Ðļз ҃ÐīаÐŧŅ‘Ð―Ð―Ņ‹Ņ… Ðļҁ҂ÐūŅ‡Ð―ÐļКÐūÐē...</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>ДÐŧŅ ÐēŅ‹ÐŋÐūÐŧÐ―ÐĩÐ―ÐļŅ ŅŅ‚ÐūÐģÐū ÐīÐĩÐđҁ҂ÐēÐļŅ Ð―ŅƒÐķÐ―Ðū Ņ…ÐūŅ‚Ņ ÐąŅ‹ ÐūÐīÐ―Ðū ÐēКÐŧŅŽŅ‡Ņ‘Ð―Ð―ÐūÐĩ Ðļ ÐīÐĩÐđҁ҂ÐēŅƒŅŽŅ‰ÐĩÐĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ.</translation> </message> <message> <source>No updates available.</source> <translation>НÐĩŅ‚ ÐīÐūŅŅ‚ŅƒÐŋÐ―Ņ‹Ņ… ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐđ.</translation> </message> <message> <source> Only local package management available.</source> <translation> ДÐūŅŅ‚ŅƒÐŋÐ―Ðū Ņ‚ÐūÐŧŅŒÐšÐū ÐŧÐūКаÐŧŅŒÐ―ÐūÐĩ ҃ÐŋŅ€Ð°ÐēÐŧÐĩÐ―ÐļÐĩ ÐŋаКÐĩŅ‚Ð°ÐžÐļ.</translation> </message> <message> <source>&Quit</source> <translation>&Ð’Ņ‹ÐđŅ‚Ðļ</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>ЛÐļ҆ÐĩÐ―Ð·ÐļÐūÐ―Ð―ÐūÐĩ ҁÐūÐģÐŧÐ°ŅˆÐĩÐ―ÐļÐĩ</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐŋŅ€Ðū҇ÐļŅ‚Ð°ÐđŅ‚Ðĩ ҁÐŧÐĩÐīŅƒŅŽŅ‰ÐĩÐĩ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐūÐ―Ð―ÐūÐĩ ҁÐūÐģÐŧÐ°ŅˆÐĩÐ―ÐļÐĩ. Ð’Ņ‹ ÐīÐūÐŧÐķÐ―Ņ‹ ҁÐūÐģÐŧÐ°ŅÐļŅ‚ŅŒŅŅ ҁÐū ÐēҁÐĩОÐļ ҃ҁÐŧÐūÐēÐļŅÐžÐļ ŅŅ‚ÐūÐģÐū ҁÐūÐģÐŧÐ°ŅˆÐĩÐ―ÐļŅ ÐŋÐĩŅ€ÐĩÐī ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļÐĩО ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ.</translation> </message> <message> <source>I accept the license.</source> <translation>ÐŊ ҁÐūÐģÐŧÐ°ŅÐĩÐ―(а) ҁ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐĩÐđ.</translation> </message> <message> <source>I do not accept the license.</source> <translation>ÐŊ Ð―Ðĩ ҁÐūÐģÐŧÐ°ŅÐĩÐ―(а) ҁ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐĩÐđ.</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ÐŋŅ€Ðū҇ÐļŅ‚Ð°ÐđŅ‚Ðĩ ҁÐŧÐĩÐīŅƒŅŽŅ‰ÐļÐĩ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐūÐ―Ð―Ņ‹Ðĩ ҁÐūÐģÐŧÐ°ŅˆÐĩÐ―ÐļŅ. Ð’Ņ‹ ÐīÐūÐŧÐķÐ―Ņ‹ ҁÐūÐģÐŧÐ°ŅÐļŅ‚ŅŒŅŅ ҁÐū ÐēҁÐĩОÐļ ҃ҁÐŧÐūÐēÐļŅÐžÐļ ŅŅ‚ÐļŅ… ҁÐūÐģÐŧÐ°ŅˆÐĩÐ―ÐļÐđ ÐŋÐĩŅ€ÐĩÐī ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļÐĩО ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ.</translation> </message> <message> <source>I accept the licenses.</source> <translation>ÐŊ ҁÐūÐģÐŧÐ°ŅÐĩÐ―(а) ҁ ÐŧÐļ҆ÐĩÐ―ÐļÐĩÐđ.</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>ÐŊ Ð―Ðĩ ҁÐūÐģÐŧÐ°ŅÐĩÐ―(а) ҁ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐĩÐđ.</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>НÐĩ Ð―Ð°ÐđÐīÐĩÐ―Ņ‹ Ņ„Ð°ÐđÐŧŅ‹ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐļ ÐīÐŧŅ КÐūÐŋÐļŅ€ÐūÐēÐ°Ð―ÐļŅ.</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>В ÐūÐŋÐĩŅ€Ð°Ņ†ÐļÐļ ÂŦ%1Âŧ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļÐžŅ‹Ðđ ÐūÐąŅŠÐĩÐšŅ‚ ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа ÐŋŅƒŅŅ‚.</translation> </message> <message> <source>No license files found to delete.</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐļ: Ņ„Ð°ÐđÐŧ Ð―Ðĩ Ð―Ð°ÐđÐīÐĩÐ―.</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÐŧÐļ҆ÐĩÐ―Ð·ÐļÐļ ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>ÐžŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ОÐĩÐ―ÐĩÐīÐķÐĩŅ€ ÐŋаКÐĩŅ‚ÐūÐē.</translation> </message> <message> <source>Preparing meta information download...</source> <translation>ПÐūÐīÐģÐūŅ‚ÐūÐēКа К заÐģŅ€ŅƒÐ·ÐšÐĩ ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ…...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>Ð Ð°ŅÐŋаКÐūÐēКа ҁÐķÐ°Ņ‚Ņ‹Ņ… Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉. Ð­Ņ‚Ðū ОÐūÐķÐĩŅ‚ Ð·Ð°Ð―ŅŅ‚ŅŒ Ð―ÐĩКÐūŅ‚ÐūŅ€ÐūÐĩ ÐēŅ€ÐĩÐžŅ...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ… ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ð°.</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>ÐŸŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€Ņƒ ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅ.</translation> </message> <message> <source>Authentication failed.</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ.</translation> </message> <message> <source>Unknown exception during download.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ ÐēÐū ÐēŅ€ÐĩÐžŅ заÐģŅ€ŅƒÐ·ÐšÐļ.</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ðū Ð―ÐĩҁÐūÐēÐŋаÐīÐĩÐ―ÐļÐĩ КÐūÐ―Ņ‚Ņ€ÐūÐŧŅŒÐ―ÐūÐđ ŅŅƒÐžÐžŅ‹ ҃ ÂŦ%1Âŧ.</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>ПÐūÐŧŅƒŅ‡ÐĩÐ―ÐļÐĩ ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ… Ðļз ÐēÐ―ÐĩŅˆÐ―ÐĩÐģÐū Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>ПÐūÐŧŅƒŅ‡ÐĩÐ―ÐļÐĩ ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ… Ðļз ÐēÐ―ÐĩŅˆÐ―ÐĩÐģÐū Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°... </translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°.</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ ÐēÐū ÐēŅ€ÐĩÐžŅ ÐļзÐēÐŧÐĩ҇ÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Extracting meta information...</source> <translation>ИзÐēÐŧÐĩ҇ÐĩÐ―ÐļÐĩ ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ņ…...</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐļзÐēÐŧÐĩ҇ÐĩÐ―ÐļŅ Ðļз Ð°Ņ€Ņ…ÐļÐēа ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>В ÐŋŅ€Ðū҆ÐĩҁҁÐĩ ÐļзÐēÐŧÐĩ҇ÐĩÐ―ÐļŅ Ðļз Ð°Ņ€Ņ…ÐļÐēа ÂŦ%1Âŧ ÐēÐūÐ·Ð―ÐļКÐŧÐū Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―ÐūÐĩ ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ.</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>ÐžŅˆÐļÐąÐšÐ° заÐŋÐļҁÐļ Maintenance Tool</translation> </message> <message> <source> Downloading packages...</source> <translation> ЗаÐģŅ€ŅƒÐ·ÐšÐ° ÐŋаКÐĩŅ‚ÐūÐē...</translation> </message> <message> <source>All downloads finished.</source> <translation>Ð’ŅÐĩ заÐģŅ€ŅƒÐ·ÐšÐļ заÐēÐĩŅ€ŅˆÐĩÐ―Ņ‹.</translation> </message> <message> <source>Cancelling the Installer</source> <translation>ÐžŅ‚ÐžÐĩÐ―Ð° ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅ‹ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ</translation> </message> <message> <source>Authentication Error</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ</translation> </message> <message> <source>Unknown error.</source> <translation>НÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ°.</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>НÐĩКÐūŅ‚ÐūҀҋÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ Ð―Ðĩ ÐąŅ‹ÐŧÐļ ҃ÐīаÐŧÐĩÐ―Ņ‹ ÐŋÐūÐŧÐ―ÐūŅŅ‚ŅŒŅŽ: ÐēÐūÐ·Ð―ÐļКÐŧа Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ°.</translation> </message> <message> <source>No installed packages found.</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð―Ņ‹Ðĩ ÐŋаКÐĩ҂ҋ Ð―Ðĩ Ð―Ð°ÐđÐīÐĩÐ―Ņ‹.</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>ДÐūŅŅ‚ŅƒÐŋÐ―Ðū ÐēаÐķÐ―ÐūÐĩ ÐļҁÐŋŅ€Ð°ÐēÐŧÐĩÐ―ÐļÐĩ, ŅÐ―Ð°Ņ‡Ð°Ðŧа заÐŋŅƒŅŅ‚ÐļŅ‚Ðĩ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅƒ ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐŋŅ€Ðļ ÐŋÐūÐŋŅ‹Ņ‚ÐšÐĩ ÐŋÐūÐēҋҁÐļŅ‚ŅŒ ŅƒŅ€ÐūÐēÐĩÐ―ŅŒ ÐīÐūŅŅ‚ŅƒÐŋа.</translation> </message> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> <message> <source>invalid</source> <translation>Ð―ÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžÐ°Ņ ÐēÐĩҀҁÐļŅ</translation> </message> <message> <source>Installation canceled by user.</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ð° ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧÐĩО.</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>НÐĩКÐūŅ‚ÐūҀҋÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹ Ð―Ðĩ ÐąŅ‹ÐŧÐļ ҃ÐīаÐŧÐĩÐ―Ņ‹ ÐŋÐūÐŧÐ―ÐūŅŅ‚ŅŒŅŽ. ДÐŧŅ ÐļŅ… ÐŋÐūÐŧÐ―ÐūÐģÐū ҃ÐīаÐŧÐĩÐ―ÐļŅ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļÐžŅ‹ ÐŋŅ€Ð°Ðēа АÐīОÐļÐ―ÐļŅŅ‚Ņ€Ð°Ņ‚ÐūŅ€Ð°: %1.</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>ÐŸŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļÐĩ Ð―Ðĩ заÐŋŅƒŅ‰ÐĩÐ―Ðū Ðē Ņ€ÐĩÐķÐļОÐĩ ОÐĩÐ―ÐĩÐīÐķÐĩŅ€Ð° ÐŋаКÐĩŅ‚ÐūÐē.</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>ÐŸŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļÐĩ заÐŋŅƒŅ‰ÐĩÐ―Ðū Ðē Ņ€ÐĩÐķÐļОÐĩ ҃ÐīаÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ņ€Ð°Ð·Ņ€Ðĩ҈ÐļŅ‚ŅŒ ÐēҁÐĩ заÐēÐļҁÐļОÐūҁ҂Ðļ.</translation> </message> <message> <source>Components about to be removed.</source> <translation>ÐĢÐīаÐŧŅÐĩÐžŅ‹Ðĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ņ‹.</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> <message> <source>Access error</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐīÐūŅŅ‚ŅƒÐŋа</translation> </message> <message> <source>Format error</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ņ„ÐūŅ€ÐžÐ°Ņ‚ÐļŅ€ÐūÐēÐ°Ð―ÐļŅ</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū заÐŋÐļŅÐ°Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ КÐūÐ―Ņ„ÐļÐģŅƒŅ€Ð°Ņ†ÐļÐļ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅ‹ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ðē %1: %2</translation> </message> <message> <source>Stop Processes</source> <translation>ÐžŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ ÐŋŅ€Ðū҆Ðĩҁҁҋ</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>ДÐŧŅ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļŅ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОÐū ÐūŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ ҁÐŧÐĩÐīŅƒŅŽŅ‰ÐļÐĩ ÐŋŅ€Ðū҆Ðĩҁҁҋ: %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ð° ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧÐĩО</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>ПÐĩŅ€ÐĩОÐĩÐ―Ð―Ð°Ņ 'TargetDir' Ð―Ðĩ ÐūÐŋŅ€ÐĩÐīÐĩÐŧÐĩÐ―Ð°.</translation> </message> <message> <source>Preparing the installation...</source> <translation>ПÐūÐīÐģÐūŅ‚ÐūÐēКа К ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐĩ...</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€ÐūÐļзÐēÐĩҁ҂Ðļ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ Ðļз ҁÐĩŅ‚ÐĩÐēÐūÐģÐū Ðļҁ҂ÐūŅ‡Ð―ÐļКа</translation> </message> <message> <source>Creating local repository</source> <translation>ÐĄÐūзÐīÐ°Ņ‘Ņ‚ŅŅ ÐŧÐūКаÐŧŅŒÐ―ÐūÐĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ</translation> </message> <message> <source> Installation finished!</source> <translation> ÐĢŅŅ‚Ð°Ð―ÐūÐēКа заÐēÐĩŅ€ŅˆÐĩÐ―Ð°!</translation> </message> <message> <source> Installation aborted!</source> <translation> ÐĢŅŅ‚Ð°Ð―ÐūÐēКа ÐŋŅ€ÐĩŅ€ÐēÐ°Ð―Ð°!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐēŅ‹ÐŋÐūÐŧÐ―ÐļŅ‚ŅŒ ŅŅ‚Ņƒ ÐūÐŋÐĩŅ€Ð°Ņ†ÐļŅŽ ÐŋÐū ҁÐĩŅ‚Ðļ</translation> </message> <message> <source>Removing deselected components...</source> <translation>ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē...</translation> </message> <message> <source> Update finished!</source> <translation> ÐžÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐĩ заÐēÐĩŅ€ŅˆÐĩÐ―Ðū!</translation> </message> <message> <source> Update aborted!</source> <translation> ÐžÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐĩ ÐŋŅ€ÐĩŅ€ÐēÐ°Ð―Ðū!</translation> </message> <message> <source>Unresolved dependencies</source> <translation>НÐĩŅ€Ð°Ð·Ņ€ÐĩŅˆŅ‘Ð―Ð―Ņ‹Ðĩ заÐēÐļҁÐļОÐūҁ҂Ðļ</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>ЗаÐŋÐļҁҌ Maintenance Tool.</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>ÐĄÐąÐūÐđ ÐŋÐūÐļŅÐšÐ° Ðē Ņ„Ð°ÐđÐŧÐĩ %1: %2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>Maintenance Tool Ð―Ðĩ ŅÐēÐŧŅÐĩŅ‚ŅŅ ÐŋаКÐĩŅ‚ÐūО</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ ÐīÐ°Ð―Ð―Ņ‹Ðĩ Maintenance Tool Ðē %1: %2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ ÐīÐēÐūÐļŅ‡Ð―Ņ‹Ðĩ ÐīÐ°Ð―Ð―Ņ‹Ðĩ Maintenance Tool Ðē %1: %2</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>ÐĄÐūзÐīÐ°Ð―ÐļÐĩ Maintenance Tool</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ ҃ҁÐŋÐĩŅˆÐ―Ðū заÐēÐĩŅ€ŅˆÐĩÐ―Ðū.</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ ÐŋŅ€ÐĩŅ€ÐēÐ°Ð―Ðū.</translation> </message> <message> <source> Installing component %1</source> <translation> ÐĢŅŅ‚Ð°Ð―ÐūÐēКа КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð° %1</translation> </message> <message> <source>Installer Error</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅ‹ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐēÐū ÐēŅ€ÐĩÐžŅ ÐŋŅ€Ðū҆ÐĩŅŅÐ° ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ (%1): %2</translation> </message> <message> <source>Done</source> <translation>ГÐūŅ‚ÐūÐēÐū</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋÐūÐīÐģÐūŅ‚ÐūÐēÐļŅ‚ŅŒŅŅ К ҃ÐīаÐŧÐĩÐ―ÐļŅŽ</translation> </message> <message> <source>Cannot start uninstall</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū Ð―Ð°Ņ‡Ð°Ņ‚ŅŒ ҃ÐīаÐŧÐĩÐ―ÐļÐĩ</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ðē ÐŋŅ€Ðū҆ÐĩҁҁÐĩ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ: %1</translation> </message> <message> <source>Unknown error</source> <translation>НÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ°</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ ОÐĩŅ‚Ð°ÐīÐ°Ð―Ð―Ņ‹Ðĩ: %1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐīÐūÐąÐ°ÐēÐļŅ‚ŅŒ ÐļÐ―Ņ„ÐūŅ€ÐžÐ°Ņ†ÐļŅŽ Ðū ÐēŅ€ÐĩОÐĩÐ―Ð―ÐūО ҁÐĩŅ€ÐēÐĩŅ€Ðĩ ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū Ð―Ð°ÐđŅ‚Ðļ ÐļÐ―Ņ„ÐūŅ€ÐžÐ°Ņ†ÐļŅŽ ÐūÐą Ðļҁ҂ÐūŅ‡Ð―ÐļÐšÐ°Ņ… ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ҃ÐīаÐŧÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÐīÐ°Ð―Ð―Ņ‹Ņ… ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅƒ ÐūÐąŅÐŧ҃ÐķÐļÐēÐ°Ð―ÐļŅ Ðē ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐģŅ€ŅƒÐ·ÐļŅ‚ŅŒ ҃ÐīаÐŧŅ‘Ð―Ð―ÐūÐĩ ÐīÐĩŅ€ÐĩÐēÐū: %1.</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ ÐŋаКÐĩ҂ҋ Ðļз %1.</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>ÐžÐąÐ―Ð°Ņ€ŅƒÐķÐĩÐ―Ð° ҆ÐļКÐŧÐļ҇ÐĩŅÐšÐ°Ņ заÐēÐļҁÐļОÐūŅŅ‚ŅŒ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē ÂŦ%1Âŧ Ðļ ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа %1</translation> </message> <message> <source>Maintain %1</source> <translation>ÐĄÐĩŅ€ÐēÐļŅÐ―Ņ‹Ðđ Ņ€ÐĩÐķÐļО %1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>ÐžŅ‚ÐžÐĩÐ―ÐļŅ‚ŅŒ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>ÐžŅ‚ÐžÐĩÐ―ÐļŅ‚ŅŒ ҃ÐīаÐŧÐĩÐ―ÐļÐĩ?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>Ð’Ņ‹ÐđŅ‚Ðļ Ðļз ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>Ð’Ņ‹ÐđŅ‚Ðļ Ðļз ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ ҃ÐīаÐŧÐĩÐ―ÐļŅ?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>Ð’Ņ‹ÐđŅ‚Ðļ Ðļз ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ ÐūÐąŅÐŧ҃ÐķÐļÐēÐ°Ð―ÐļŅ?</translation> </message> <message> <source>Settings</source> <translation>ÐÐ°ŅŅ‚Ņ€ÐūÐđКÐļ</translation> </message> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>Ð―ÐĩÐēÐūзОÐūÐķÐ―Ðū ÐŋŅ€ÐūÐļзÐēÐĩҁ҂Ðļ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ Ðļз ҁÐĩŅ‚ÐĩÐēÐūÐģÐū Ðļҁ҂ÐūŅ‡Ð―ÐļКа. ПÐūÐķаÐŧ҃ÐđŅŅ‚Ð°, ҁÐūŅ…Ņ€Ð°Ð―ÐļŅ‚Ðĩ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅƒ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ð° ÐķŅ‘ŅÐšŅ‚Ðđ ÐīÐļŅÐš Ð’Ð°ŅˆÐĩÐģÐū КÐūОÐŋŅŒŅŽŅ‚ÐĩŅ€Ð°</translation> </message> <message> <source>%1 Question</source> <translatorcomment>ВÐūŅ‚ ŅŅ‚Ðū Ð―ÐĩÐŋÐūÐ―ŅŅ‚Ð―Ð°Ņ Ņ…Ņ€ÐĩÐ―ŅŒ.</translatorcomment> <translation>ВÐūÐŋŅ€Ðūҁ ÐŋÐū %1</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>&ПÐūÐšÐ°Ð·Ð°Ņ‚ŅŒ ÐīÐĩŅ‚Ð°ÐŧÐļ</translation> </message> <message> <source>&Hide Details</source> <translation>&ÐĄÐšŅ€Ņ‹Ņ‚ŅŒ ÐīÐĩŅ‚Ð°ÐŧÐļ</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>&ÐĢÐīаÐŧÐļŅ‚ŅŒ</translation> </message> <message> <source>Uninstalling %1</source> <translation>ÐĢÐīаÐŧÐĩÐ―ÐļÐĩ %1</translation> </message> <message> <source>&Update</source> <translation>&ÐžÐąÐ―ÐūÐēÐļŅ‚ŅŒ</translation> </message> <message> <source>Updating components of %1</source> <translation>ÐžÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļÐĩ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē %1</translation> </message> <message> <source>&Install</source> <translation>&ÐĢŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ</translation> </message> <message> <source>Installing %1</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation></translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>ÐŸŅ€ÐūÐšŅÐļ %1 ҂ҀÐĩÐąŅƒÐĩŅ‚ ÐļÐžŅ ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧŅ Ðļ ÐŋÐ°Ņ€ÐūÐŧҌ.</translation> </message> <message> <source>Username:</source> <translation>Ð˜ÐžŅ:</translation> </message> <message> <source>Username</source> <translation>Ð˜ÐžŅ ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧŅ</translation> </message> <message> <source>Password:</source> <translation>ÐŸÐ°Ņ€ÐūÐŧҌ:</translation> </message> <message> <source>Password</source> <translation>ÐŸÐ°Ņ€ÐūÐŧҌ</translation> </message> <message> <source>Proxy Credentials</source> <translation>ÐŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅ Ð―Ð° ÐŋŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€Ðĩ</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>ÐĢ&ÐīаÐŧÐļŅ‚ŅŒ</translation> </message> <message> <source>Ready to Uninstall</source> <translation>Ð’ŅŅ‘ ÐģÐūŅ‚ÐūÐēÐū К ҃ÐīаÐŧÐĩÐ―ÐļŅŽ</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>ÐŸŅ€ÐūÐģŅ€Ð°ÐžÐžÐ° ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐģÐūŅ‚ÐūÐēа Ð―Ð°Ņ‡Ð°Ņ‚ŅŒ ҃ÐīаÐŧÐĩÐ―ÐļÐĩ %1 ҁ ÐēÐ°ŅˆÐĩÐģÐū КÐūОÐŋŅŒŅŽŅ‚ÐĩŅ€Ð°. <br><font color="red">ДÐļŅ€ÐĩÐšŅ‚ÐūŅ€ÐļŅ ҁ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžÐūÐđ %2 ÐąŅƒÐīÐĩŅ‚ ÐŋÐūÐŧÐ―ÐūŅŅ‚ŅŒŅŽ ҃ÐīаÐŧÐĩÐ―Ð°</font>, ÐēКÐŧŅŽŅ‡Ð°Ņ ҁÐūÐīÐĩŅ€ÐķÐļОÐūÐĩ ŅŅ‚ÐūÐđ ÐīÐļŅ€ÐĩÐšŅ‚ÐūŅ€ÐļÐļ!</translation> </message> <message> <source>U&pdate</source> <translation>О&ÐąÐ―ÐūÐēÐļŅ‚ŅŒ</translation> </message> <message> <source>Ready to Update Packages</source> <translation>ГÐūŅ‚ÐūÐē К ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅŽ ÐŋаКÐĩŅ‚ÐūÐē</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>ÐŸŅ€ÐūÐģŅ€Ð°ÐžÐžÐ° ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐģÐūŅ‚ÐūÐēа К ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅŽ Ņ„Ð°ÐđÐŧÐūÐē.</translation> </message> <message> <source>&Install</source> <translation>&ÐĢŅŅ‚Ð°Ð―ÐūÐēÐļŅ‚ŅŒ</translation> </message> <message> <source>Ready to Install</source> <translation>Ð’ŅŅ‘ ÐģÐūŅ‚ÐūÐēÐū К ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐĩ</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>ÐŸŅ€ÐūÐģŅ€Ð°ÐžÐžÐ° ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐģÐūŅ‚ÐūÐēа Ð―Ð°Ņ‡Ð°Ņ‚ŅŒ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ %1 Ð―Ð° ÐēÐ°Ņˆ КÐūОÐŋŅŒŅŽŅ‚ÐĩŅ€.</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>На ÐēŅ‹ÐąŅ€Ð°Ð―Ð―ÐūО ВаОÐļ ÐīÐļŅÐšÐĩ ÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ОÐĩŅŅ‚Ð° ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. ÐĒÐĩО Ð―Ðĩ ОÐĩÐ―ÐĩÐĩ, ÐŋÐūҁÐŧÐĩ заÐēÐĩŅ€ŅˆÐĩÐ―ÐļŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ð° ÐīÐļŅÐšÐĩ ÐūŅŅ‚Ð°Ð―ÐĩŅ‚ŅŅ ОÐĩÐ―ŅŒŅˆÐĩ 1% ҁÐēÐūÐąÐūÐīÐ―ÐūÐģÐū ОÐĩŅŅ‚Ð°. %1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>На ÐēŅ‹ÐąŅ€Ð°Ð―Ð―ÐūО ВаОÐļ ÐīÐļŅÐšÐĩ ÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ОÐĩŅŅ‚Ð° ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. ÐĒÐĩО Ð―Ðĩ ОÐĩÐ―ÐĩÐĩ, ÐŋÐūҁÐŧÐĩ заÐēÐĩŅ€ŅˆÐĩÐ―ÐļŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ð° ÐīÐļŅÐšÐĩ ÐūŅŅ‚Ð°Ð―ÐĩŅ‚ŅŅ ОÐĩÐ―ŅŒŅˆÐĩ 100 МБ ҁÐēÐūÐąÐūÐīÐ―ÐūÐģÐū ОÐĩŅŅ‚Ð°. %1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>ДÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐŋÐū҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ %1 ÐīÐļŅÐšÐūÐēÐūÐģÐū ÐŋŅ€ÐūŅŅ‚Ņ€Ð°Ð―ŅŅ‚Ðēа.</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>НÐĩÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ОÐĩŅŅ‚Ð° Ð―Ð° ÐīÐļŅÐšÐĩ ÐīÐŧŅ ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ņ… Ņ„Ð°ÐđÐŧÐūÐē Ðļ Ņ„Ð°ÐđÐŧÐūÐē ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. ДÐūŅŅ‚ŅƒÐŋÐ―Ðū %1, а ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ ОÐļÐ―ÐļÐžŅƒÐž %2.</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>НÐĩÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ОÐĩŅŅ‚Ð° Ð―Ð° ÐīÐļŅÐšÐĩ ÐīÐŧŅ ҁÐūŅ…Ņ€Ð°Ð―ÐĩÐ―ÐļŅ ÐēҁÐĩŅ… ÐēŅ‹ÐąŅ€Ð°Ð―Ð―Ņ‹Ņ… КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚ÐūÐē. ДÐūŅŅ‚ŅƒÐŋÐ―Ðū %1, а ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ ОÐļÐ―ÐļÐžŅƒÐž: %2.</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>НÐĩÐīÐūŅŅ‚Ð°Ņ‚ÐūŅ‡Ð―Ðū ОÐĩŅŅ‚Ð° Ð―Ð° ÐīÐļŅÐšÐĩ ÐīÐŧŅ ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ņ… Ņ„Ð°ÐđÐŧÐūÐē. ДÐūŅŅ‚ŅƒÐŋÐ―Ðū %1, а ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ ОÐļÐ―ÐļÐžŅƒÐž %2.</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source>Registering file types is only supported on Windows.</source> <translation>РÐĩÐģÐļŅŅ‚Ņ€Ð°Ņ†ÐļŅ Ņ‚ÐļÐŋÐūÐē Ņ„Ð°ÐđÐŧÐūÐē ÐēÐūзОÐūÐķÐ―Ð° Ņ‚ÐūÐŧŅŒÐšÐū Ðē Windows.</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>РÐĩÐģÐļŅŅ‚Ņ€Ð°Ņ†ÐļŅ Ņ‚ÐļÐŋÐūÐē Ņ„Ð°ÐđÐŧÐūÐē: Ð―ÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€Ðū҇ÐļŅ‚Ð°Ņ‚ŅŒ ÐēҁÐĩ ÐīÐ°Ð―Ð―Ņ‹Ðĩ ÐŋÐūҁÐŧÐĩ ÐūŅ‚ÐŋŅ€Ð°ÐēКÐļ КÐūÐžÐ°Ð―ÐīŅ‹: %1. ОÐķÐļÐīаÐŧÐūҁҌ ÐąÐ°ÐđŅ‚: %2; ÐŋÐūÐŧŅƒŅ‡ÐĩÐ―Ðū ÐąÐ°ÐđŅ‚: %3. ÐžŅˆÐļÐąÐšÐ°: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ð―Ð° заÐŋÐļҁҌ: %2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Read failed after %1 bytes: %2</source> <translation>ÐĄÐąÐūÐđ ҇҂ÐĩÐ―ÐļŅ ҁ %1 ÐąÐ°ÐđŅ‚Ð°: %2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>ÐĄÐąÐūÐđ заÐŋÐļҁÐļ ҁ %1 ÐąÐ°ÐđŅ‚Ð°: %2</translation> </message> <message> <source>Cannot open resource %1 for reading.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ€ÐĩŅŅƒŅ€Ņ %1 ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ.</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>ЗаÐēÐĩŅ€ŅˆÐĩÐ―ÐļÐĩ %1 ÐžÐ°ŅŅ‚ÐĩŅ€Ð° ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ ҁ҆ÐĩÐ―Ð°Ņ€ÐļŅ ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>ВÐūÐ·Ð―ÐļКÐŧÐū ÐļŅÐšÐŧŅŽŅ‡ÐĩÐ―ÐļÐĩ ÐŋŅ€Ðļ заÐģŅ€ŅƒÐ·ÐšÐĩ ҁ҆ÐĩÐ―Ð°Ņ€ÐļŅ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð° ÂŦ%1Âŧ: %2</translation> </message> <message> <source>Unknown error.</source> <translation>НÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ°.</translation> </message> <message> <source>on line number: </source> <translation>Ðē ҁ҂ҀÐūКÐĩ: </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>АÐēŅ‚ÐūÐžÐ°Ņ‚Ðļ҇ÐĩŅÐšÐ°Ņ ÐŋÐĩŅ€ÐĩзаÐģŅ€ŅƒÐ·ÐšÐ°: ÐŋÐūÐīŅ…ÐūÐīÐļŅ‚ Ņ‚ÐūÐŧŅŒÐšÐū ÐīÐŧŅ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅ‹ ÐūÐąÐ―ÐūÐēÐŧÐĩÐ―ÐļŅ ÐļÐŧÐļ ÐīÐŧŅ Ņ€ÐĩÐķÐļОа ОÐĩÐ―ÐĩÐīÐķÐĩŅ€Ð° ÐŋаКÐĩŅ‚ÐūÐē.</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>АÐēŅ‚ÐūÐžÐ°Ņ‚Ðļ҇ÐĩŅÐšÐ°Ņ ÐŋÐĩŅ€ÐĩзаÐģŅ€ŅƒÐ·ÐšÐ°: Ð―ÐĩÐīÐūÐŋŅƒŅŅ‚ÐļÐžŅ‹Ðđ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ</translation> </message> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>ÐžÐąŅŠÐĩÐšŅ‚ ŅƒŅŅ‚Ð°Ð―ÐūÐē҉ÐļКа, Ð―ÐĩÐūÐąŅ…ÐūÐīÐļÐžŅ‹Ðđ Ðē ÐūÐŋÐĩŅ€Ð°Ņ†ÐļÐļ ÂŦ%1Âŧ, ÐŋŅƒŅŅ‚.</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>ÐĄÐĩŅ€ÐēÐĩŅ€ ҂ҀÐĩÐąŅƒÐĩŅ‚ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>ÐĄÐ°ÐđŅ‚ ҂ҀÐĩÐąŅƒÐĩŅ‚ ÐēÐēÐĩҁ҂Ðļ ÐļÐžŅ ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧŅ Ðļ ÐŋÐ°Ņ€ÐūÐŧҌ.</translation> </message> <message> <source>Username:</source> <translation>Ð˜ÐžŅ:</translation> </message> <message> <source>Password:</source> <translation>ÐŸÐ°Ņ€ÐūÐŧҌ:</translation> </message> <message> <source>%1 at %2</source> <translation>%1 Ðē %2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>ÐžŅ‚ŅŅƒŅ‚ŅŅ‚ÐēŅƒŅŽŅ‚ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ(Ņ‹) ÂŦ%1Âŧ ÐŋŅ€Ðļ ÐēŅ‹Ð·ÐūÐēÐĩ ÂŦ%2Âŧ ҁ ÐŋÐ°Ņ€Ð°ÐžÐĩŅ‚Ņ€Ð°ÐžÐļ ÂŦ%3Âŧ.</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>ÐĒÐĩÐšŅƒŅ‰ÐļÐđ ҁÐŋÐūҁÐūÐą ÐēŅ‹Ð·ÐūÐēа ÂŦ%1Âŧ ҁ Ð°Ņ€ÐģŅƒÐžÐĩÐ―Ņ‚Ð°ÐžÐļ ÂŦ%2Âŧ Ð―Ðĩ ÐŋÐūÐīÐīÐĩŅ€ÐķÐļÐēаÐĩŅ‚ŅŅ. Ð˜ŅÐŋÐūÐŧŅŒÐ·ŅƒÐđŅ‚Ðĩ set, remove, add_array_value ÐļÐŧÐļ remove_array_value.</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>Ð’ŅÐĩ Ð°Ņ€ÐģŅƒÐžÐĩÐ―Ņ‚Ņ‹ ÐīÐūÐŧÐķÐ―Ņ‹ ÐąŅ‹Ņ‚ŅŒ Ð―ÐĩÐŋŅƒŅŅ‚Ņ‹ÐžÐļ: Ðļҁ҂ÐūŅ‡Ð―ÐļК ÂŦ%1Âŧ, Ð―Ð°Ð·Ð―Ð°Ņ‡ÐĩÐ―ÐļÐĩ ÂŦ%2Âŧ.</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩОÐĩҁ҂ÐļŅ‚ŅŒ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ, Ņ‚Ð°Ðš КаК Ņ„Ð°ÐđÐŧ Ð―Ð°Ð·Ð―Ð°Ņ‡ÐĩÐ―ÐļŅ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚ Ðļ Ð―Ðĩ ҃ÐīаÐŧŅÐĩО.</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩОÐĩҁ҂ÐļŅ‚ŅŒ Ņ„Ð°ÐđÐŧ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>ПÐĩŅ€ÐĩОÐĩ҉ÐĩÐ―ÐļÐĩ Ņ„Ð°ÐđÐŧа ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ.</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>ÐŊŅ€ÐŧŅ‹ÐšÐļ ОÐĩÐ―ŅŽ "ÐŸŅƒŅÐš"</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐŋаÐŋÐšŅƒ Ðē ОÐĩÐ―ŅŽ ÂŦÐŸŅƒŅÐšÂŧ ÐīÐŧŅ Ņ€Ð°Ð·ÐžÐĩ҉ÐĩÐ―ÐļŅ ŅŅ€ÐŧŅ‹ÐšÐūÐē ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅ‹. Ð§Ņ‚ÐūÐąŅ‹ ҁÐūзÐīÐ°Ņ‚ŅŒ Ð―ÐūÐēŅƒŅŽ ÐŋаÐŋÐšŅƒ, ÐēÐēÐĩÐīÐļŅ‚Ðĩ ÐĩŅ‘ ÐļÐžŅ.</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translatorcomment>ÐūŅ‚ÐšŅ€Ņ‹ÐēаÐĩŅ‚ ÐūÐšÐ―Ðū ÐēŅ‹ÐąÐūŅ€Ð° Ņ„Ð°ÐđÐŧа</translatorcomment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>О&ÐąÐ·ÐūŅ€...</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>Ð’Ņ‹ÐąŅ€Ð°Ð―Ð―Ņ‹Ðđ Ņ„Ð°ÐđÐŧ ÐļÐŧÐļ ҁÐļОÐēÐūÐŧŅŒÐ―Ð°Ņ ҁҁҋÐŧКа ҃ÐķÐĩ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐīŅ€ŅƒÐģÐūÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ.</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>ÐŸŅƒŅ‚ŅŒ К ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ҃ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐąŅ‹Ņ‚ŅŒ ÐūŅ‚Ð―ÐūҁÐļŅ‚ÐĩÐŧŅŒÐ―Ņ‹Ðž. ЗаÐīаÐđŅ‚Ðĩ Ð°ÐąŅÐūÐŧŅŽŅ‚Ð―Ņ‹Ðđ ÐŋŅƒŅ‚ŅŒ.</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>В ҁ҂ҀÐūКÐĩ ÐŋŅƒŅ‚Ðļ ÐļÐŧÐļ Ðē ÐļОÐĩÐ―Ðļ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģа ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ҁÐūÐīÐĩŅ€ÐķÐļŅ‚ŅŅ ҁÐļОÐēÐūÐŧ, Ð―Ðĩ ÐūŅ‚Ð―ÐūŅŅŅ‰ÐļÐđŅŅ К ASCII. В Ð―Ð°ŅŅ‚ÐūŅŅ‰ÐĩÐĩ ÐēŅ€ÐĩÐžŅ Ņ‚Ð°ÐšÐļÐĩ ҁÐļОÐēÐūÐŧŅ‹ Ð―Ðĩ ÐŋÐūÐīÐīÐĩŅ€ÐķÐļÐēÐ°ŅŽŅ‚ŅŅ. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐīŅ€ŅƒÐģÐūÐđ ÐŋŅƒŅ‚ŅŒ ÐļÐŧÐļ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ.</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>ÐĢŅŅ‚Ð°Ð―ÐūÐēКа Ðē %1 заÐŋŅ€Ðĩ҉ÐĩÐ―Ð°, Ņ‚Ð°Ðš КаК ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐŋÐūÐŧÐ―ÐūŅŅ‚ŅŒŅŽ ҃ÐīаÐŧŅ‘Ð―.</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>ВÐēÐĩÐīŅ‘Ð―Ð―Ņ‹Ðđ ÐŋŅƒŅ‚ŅŒ ҁÐŧÐļŅˆÐšÐūО ÐīÐŧÐļÐ―Ð―Ņ‹Ðđ, ÐēÐēÐĩÐīÐļŅ‚Ðĩ КÐūҀҀÐĩÐšŅ‚Ð―Ņ‹Ðđ ÐŋŅƒŅ‚ŅŒ.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>ВÐēÐĩÐīŅ‘Ð― Ð―ÐĩÐēÐĩŅ€Ð―Ņ‹Ðđ ÐŋŅƒŅ‚ŅŒ, ÐŋŅ€ÐūÐēÐĩŅ€ŅŒŅ‚Ðĩ ÐŋŅ€Ð°ÐēÐļÐŧŅŒÐ―ÐūŅŅ‚ŅŒ ŅƒÐšÐ°Ð·Ð°Ð―ÐļŅ ÐŋŅƒŅ‚Ðļ К ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ҃.</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>ÐĢÐšÐ°Ð·Ð°Ð― Ð―ÐĩÐēÐĩŅ€Ð―Ņ‹Ðđ ÐŋŅƒŅ‚ŅŒ, ÐŋŅ€ÐūÐēÐĩŅ€ŅŒŅ‚Ðĩ ÐļÐžŅ ÐīÐļŅÐšÐ°.</translation> </message> <message> <source>Error</source> <translation>ÐžŅˆÐļÐąÐšÐ°</translation> </message> <message> <source>Warning</source> <translation>ÐŸŅ€ÐĩÐī҃ÐŋŅ€ÐĩÐķÐīÐĩÐ―ÐļÐĩ</translation> </message> <message> <source>Select Installation Folder</source> <translation>Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>ÐĢКаÐķÐļŅ‚Ðĩ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ %1.</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>Ð’Ņ‹ÐąŅ€Ð°Ð―Ð―Ņ‹Ðđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ ŅŅƒŅ‰Ðĩҁ҂Ðē҃ÐĩŅ‚ Ðļ ҁÐūÐīÐĩŅ€ÐķÐļŅ‚ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐŧÐĩÐ―Ð―ÐūÐĩ ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļÐĩ. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐīŅ€ŅƒÐģÐūÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ.</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ, ÐēŅ‹ÐąŅ€Ð°Ð―Ð―Ņ‹Ðđ ÐīÐŧŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ, ҃ÐķÐĩ ҁÐūÐīÐĩŅ€ÐķÐļŅ‚ Ņ„Ð°ÐđÐŧŅ‹. ÐžÐ― ÐąŅƒÐīÐĩŅ‚ ҁ҂ґҀ҂ ÐēОÐĩҁ҂Ðĩ ҁÐū ÐēҁÐĩО ҁÐūÐīÐĩŅ€ÐķÐļÐžŅ‹Ðž ÐŋŅ€Ðļ ҃ÐīаÐŧÐĩÐ―ÐļÐļ ÐŋŅ€ÐļÐŧÐūÐķÐĩÐ―ÐļŅ. ÐŸŅ€ÐūÐļзÐēÐūÐīÐļŅ‚ŅŒ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ Ðē ŅŅ‚ÐūŅ‚ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ Ð―Ðĩ Ņ€ÐĩКÐūОÐĩÐ―Ðī҃ÐĩŅ‚ŅŅ, Ņ‚Ð°Ðš КаК Ð―Ðĩ ÐļŅÐšÐŧŅŽŅ‡Ņ‘Ð― ŅÐąÐūÐđ. ÐŸŅ€ÐūÐīÐūÐŧÐķÐļŅ‚ŅŒ?</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>НÐĩÐūÐąŅ…ÐūÐīÐļОÐū заÐīÐ°Ņ‚ŅŒ ÐŋŅƒŅ‚ŅŒ К ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ҃ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐŋÐūÐīŅ…ÐūÐīŅŅ‰ÐļÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ.</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>ÐŸŅƒŅ‚ŅŒ К ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ҃ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ðĩ ОÐūÐķÐĩŅ‚ ÐūÐšÐ°Ð―Ņ‡ÐļÐēÐ°Ņ‚ŅŒŅŅ Ņ‚ÐūŅ‡ÐšÐūÐđ. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐīŅ€ŅƒÐģÐūÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ.</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>ÐŸŅƒŅ‚ŅŒ К ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ҃ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ Ð―Ðĩ ОÐūÐķÐĩŅ‚ ҁÐūÐīÐĩŅ€ÐķÐ°Ņ‚ŅŒ ÂŦ%1Âŧ. Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐīŅ€ŅƒÐģÐūÐđ ÐšÐ°Ņ‚Ð°ÐŧÐūÐģ.</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Empty repository URL.</source> <translation>ÐŸŅƒŅŅ‚ÐūÐđ URL Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°.</translation> </message> <message> <source>Missing package manager core engine.</source> <translation>ÐžŅ‚ŅŅƒŅ‚ŅŅ‚Ðē҃ÐĩŅ‚ ОÐĩÐ―ÐĩÐīÐķÐĩŅ€ ÐŋаКÐĩŅ‚ÐūÐē.</translation> </message> <message> <source>Download canceled.</source> <translation>ЗаÐģŅ€ŅƒÐ·ÐšÐ° ÐūŅ‚ÐžÐĩÐ―ÐĩÐ―Ð°.</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>Ð˜ŅŅ‚ÐĩКÐŧÐū ÐēŅ€ÐĩÐžŅ ÐēŅ€ÐĩÐžŅ Ņ‚Ðĩҁ҂ÐļŅ€ÐūÐēÐ°Ð―ÐļÐļ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð° ÂŦ%1Âŧ.</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ Ņ€Ð°Ð·ÐūÐąŅ€Ð°Ņ‚ŅŒ Updates.xml: %1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ Updates.xml ÐīÐŧŅ ҇҂ÐĩÐ―ÐļŅ: %1</translation> </message> <message> <source>Authentication failed.</source> <translation>ÐžŅˆÐļÐąÐšÐ° Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ.</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ð―ÐĩÐļзÐēÐĩŅŅ‚Ð―Ð°Ņ Ðū҈ÐļÐąÐšÐ° ÐŋŅ€Ðļ Ņ‚Ðĩҁ҂ÐļŅ€ÐūÐēÐ°Ð―ÐļÐļ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð° ÂŦ%1Âŧ.</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>ÐĒŅ€ÐĩÐąŅƒÐĩŅ‚ŅŅ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļŅ</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>ВÐēÐĩÐīÐļŅ‚Ðĩ ÐŋÐ°Ņ€ÐūÐŧҌ ÐīÐŧŅ ÐīÐūŅŅ‚ŅƒÐŋа К "sudo":</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>ÐžŅˆÐļÐąÐšÐ° ÐŋŅ€Ðļ ÐŋÐūÐŋŅ‹Ņ‚ÐšÐĩ ÐŋÐūÐŧŅƒŅ‡ÐĩÐ―ÐļŅ ÐŋŅ€Ð°Ðē аÐīОÐļÐ―ÐļŅŅ‚Ņ€Ð°Ņ‚ÐūŅ€Ð°</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ аÐēŅ‚ÐūŅ€ÐļзÐūÐēÐ°Ņ‚ŅŒŅŅ.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€ÐūÐđŅ‚Ðļ аÐēŅ‚ÐūŅ€ÐļÐ·Ð°Ņ†ÐļŅŽ, КÐūŅ‚ÐūŅ€Ð°Ņ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОа ÐīÐŧŅ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. ЗаÐŋŅƒŅŅ‚ÐļŅ‚Ðĩ ÐŋŅ€ÐūÐģŅ€Ð°ÐžÐžŅƒ ÐūŅ‚ ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧŅ ҁ ÐŋÐūÐīŅ…ÐūÐīŅŅ‰ÐļОÐļ ÐŋŅ€Ð°ÐēаОÐļ. ИÐŧÐļ Ņ€Ð°Ð·Ņ€Ðĩ҈ÐļŅ‚Ðĩ ÐŋÐūÐēŅ‹ŅˆÐĩÐ―ÐļÐĩ ÐŋŅ€Ð°Ðē, КÐūÐģÐīа ÐūÐą ŅŅ‚ÐūО ÐąŅƒÐīÐĩŅ‚ ÐŋÐūÐŋŅ€Ðū҈ÐĩÐ―Ðū.</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋŅ€ÐūÐđŅ‚Ðļ аÐēŅ‚ÐūŅ€ÐļÐ·Ð°Ņ†ÐļŅŽ, КÐūŅ‚ÐūŅ€Ð°Ņ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОа ÐīÐŧŅ ÐŋŅ€ÐūÐīÐūÐŧÐķÐĩÐ―ÐļŅ ŅƒŅŅ‚Ð°Ð―ÐūÐēКÐļ. МÐūÐķÐ―Ðū ÐŋŅ€ÐĩŅ€ÐēÐ°Ņ‚ŅŒ ŅƒŅŅ‚Ð°Ð―ÐūÐēÐšŅƒ ÐļÐŧÐļ ÐŋÐūÐŋŅ‹Ņ‚Ð°Ņ‚ŅŒŅŅ ŅƒŅŅ‚Ņ€Ð°Ð―ÐļŅ‚ŅŒ ÐŋŅ€ÐūÐąÐŧÐĩÐžŅƒ заÐŋŅƒŅŅ‚ÐļÐē %1 ÐūŅ‚ ÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ÐĩÐŧŅ ҁ ÐŋÐūÐīŅ…ÐūÐīŅŅ‰ÐļОÐļ ÐŋŅ€Ð°ÐēаОÐļ Ðļ Ð―Ð°ÐķаÐē ОК.</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ€ÐĩŅŅƒŅ€Ņ %1: %2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>НÐĩÐēÐūзОÐūÐķÐ―Ðū ÐūŅ‚ÐšŅ€Ņ‹Ņ‚ŅŒ Ņ„Ð°ÐđÐŧ Ð―Ð°ŅŅ‚Ņ€ÐūÐĩК %1 Ð―Ð° ҇҂ÐĩÐ―ÐļÐĩ: %2</translation> </message> <message> <source>Select Categories</source> <translation>Ð’Ņ‹ÐąÐĩŅ€ÐļŅ‚Ðĩ ÐšÐ°Ņ‚ÐĩÐģÐūŅ€ÐļÐļ ÐŋаКÐĩŅ‚ÐūÐē</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>ÐÐ°ŅŅ‚Ņ€ÐūÐđКÐļ</translation> </message> <message> <source>Network</source> <translation>ÐĄÐĩŅ‚ŅŒ</translation> </message> <message> <source>No proxy</source> <translation>БÐĩз ÐŋŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€Ð°</translation> </message> <message> <source>System proxy settings</source> <translation>ÐÐ°ŅŅ‚Ņ€ÐūÐđКÐļ ҁÐļҁ҂ÐĩÐžÐ―ÐūÐģÐū ÐŋŅ€ÐūÐšŅÐļ</translation> </message> <message> <source>Manual proxy configuration</source> <translation>Ð ŅƒŅ‡Ð―Ð°Ņ Ð―Ð°ŅŅ‚Ņ€ÐūÐđКа ÐŋŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€Ð°</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP ÐŋŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€:</translation> </message> <message> <source>Port:</source> <translation>ПÐūҀ҂:</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP ÐŋŅ€ÐūÐšŅÐļ-ҁÐĩŅ€ÐēÐĩŅ€:</translation> </message> <message> <source>Repositories</source> <translation>ÐĨŅ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>ДÐūÐąÐ°ÐēÐļŅ‚ŅŒ ÐŧÐūÐģÐļÐ― Ðļ ÐŋÐ°Ņ€ÐūÐŧҌ ÐīÐŧŅ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ ÐŋŅ€Ðļ Ð―ÐĩÐūÐąŅ…ÐūÐīÐļОÐūҁ҂Ðļ.</translation> </message> <message> <source>Use temporary repositories only</source> <translation>ÐļҁÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ŅŒ Ņ‚ÐūÐŧŅŒÐšÐū ÐēŅ€ÐĩОÐĩÐ―Ð―Ņ‹Ðĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°</translation> </message> <message> <source>Add</source> <translation>ДÐūÐąÐ°ÐēÐļŅ‚ŅŒ</translation> </message> <message> <source>Remove</source> <translation>ÐĢÐīаÐŧÐļŅ‚ŅŒ</translation> </message> <message> <source>Test</source> <translation>ÐŸŅ€ÐūÐēÐĩŅ€ÐļŅ‚ŅŒ</translation> </message> <message> <source>Show Passwords</source> <translation>ПÐūÐšÐ°Ð·Ð°Ņ‚ŅŒ ÐŋÐ°Ņ€ÐūÐŧÐļ</translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>ПÐūŅŅ‚Ð°ÐēŅŒŅ‚Ðĩ Ņ„ÐŧаÐķÐūК, ҇҂ÐūÐąŅ‹ ÐļҁÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ŅŒ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ Ðē ÐŋŅ€Ðū҆ÐĩҁҁÐĩ ÐŋÐūÐŧŅƒŅ‡ÐĩÐ―ÐļŅ.</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>ДÐūÐąÐ°ÐēÐļŅ‚ŅŒ ÐŧÐūÐģÐļÐ― ÐīÐŧŅ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ Ð―Ð° ҁÐĩŅ€ÐēÐĩŅ€Ðĩ.</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>ДÐūÐąÐ°ÐēÐļŅ‚ŅŒ ÐŋÐ°Ņ€ÐūÐŧҌ ÐīÐŧŅ Ð°ŅƒŅ‚ÐĩÐ―Ņ‚ÐļŅ„ÐļÐšÐ°Ņ†ÐļÐļ Ð―Ð° ҁÐĩŅ€ÐēÐĩŅ€Ðĩ.</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>АÐīŅ€ÐĩŅÐ° ҁÐĩŅ€ÐēÐĩŅ€ÐūÐē, КÐūŅ‚ÐūҀҋÐĩ ҁÐūÐīÐĩŅ€ÐķÐ°Ņ‚ Ņ€Ð°ÐąÐū҇ÐļÐĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°.</translation> </message> <message> <source>Hide Passwords</source> <translation>ÐĄÐšŅ€Ņ‹Ņ‚ŅŒ ÐŋÐ°Ņ€ÐūÐŧÐļ</translation> </message> <message> <source>Use</source> <translation>Ð˜ŅÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ŅŒ</translation> </message> <message> <source>Username</source> <translation>ЛÐūÐģÐļÐ―</translation> </message> <message> <source>Password</source> <translation>ÐŸÐ°Ņ€ÐūÐŧҌ</translation> </message> <message> <source>Repository</source> <translation>ÐĨŅ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ</translation> </message> <message> <source>Default repositories</source> <translation>ÐĨŅ€Ð°Ð―ÐļÐŧÐļŅ‰Ð° ÐŋÐū ŅƒÐžÐūÐŧŅ‡Ð°Ð―ÐļŅŽ</translation> </message> <message> <source>Temporary repositories</source> <translation>Ð’Ņ€ÐĩОÐĩÐ―Ð―Ņ‹Ðĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°</translation> </message> <message> <source>User defined repositories</source> <translation>Ð˜ŅÐŋÐūÐŧŅŒÐ·ÐūÐēÐ°Ņ‚ŅŒ Ð―Ð°Ð·Ð―Ð°Ņ‡ÐĩÐ―Ð―Ņ‹Ðĩ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>ВÐūÐ·Ð―ÐļКÐŧа Ðū҈ÐļÐąÐšÐ° ÐŋŅ€Ðļ Ņ‚Ðĩҁ҂ÐļŅ€ÐūÐēÐ°Ð―ÐļÐļ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļŅ‰Ð°.</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>ÐĨŅ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ ÐŋŅ€ÐūŅ‚Ðĩҁ҂ÐļŅ€ÐūÐēÐ°Ð―Ðū ҃ҁÐŋÐĩŅˆÐ―Ðū.</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>ЖÐĩÐŧаÐĩŅ‚Ðĩ ÐūŅ‚ÐšÐŧŅŽŅ‡ÐļŅ‚ŅŒ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>ЖÐĩÐŧаÐĩŅ‚Ðĩ ÐēКÐŧŅŽŅ‡ÐļŅ‚ŅŒ Ņ…Ņ€Ð°Ð―ÐļÐŧÐļ҉Ðĩ?</translation> </message> <message> <source>Select All</source> <translation>Ð’Ņ‹ÐąŅ€Ð°Ņ‚ŅŒ Ðēҁґ</translation> </message> <message> <source>Deselect All</source> <translation>ÐĄÐ―ŅŅ‚ŅŒ ÐēŅ‹ÐąÐūŅ€</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Registry path %1 is not writable.</source> <translation>ÐŸŅƒŅ‚ŅŒ Ņ€ÐĩÐĩŅŅ‚Ņ€Ð° %1 Ð―ÐĩÐīÐūŅŅ‚ŅƒÐŋÐĩÐ― ÐīÐŧŅ заÐŋÐļҁÐļ.</translation> </message> <message> <source>Cannot write to registry path %1.</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ заÐŋÐļŅÐ°Ņ‚ŅŒ КÐŧŅŽŅ‡ %1 Ðē Ņ€ÐĩÐĩҁ҂Ҁ.</translation> </message> <message> <source>exactly %1</source> <translation>Ņ‚ÐūŅ‡Ð―Ðū %1</translation> </message> <message> <source>at least %1</source> <translation>ОÐļÐ―ÐļÐžŅƒÐž %1</translation> </message> <message> <source>not more than %1</source> <translation>Ð―Ðĩ ÐąÐūÐŧÐĩÐĩ %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 ÐļÐŧÐļ %2</translation> </message> <message> <source>%1 to %2</source> <translation>ÐūŅ‚ %1 ÐīÐū %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ ÐŋÐĩŅ€ÐĩÐīÐ°Ð―, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ.</numerusform> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩŅ‚Ņ€Ð° ÐŋÐĩŅ€ÐĩÐīÐ°Ð―Ðū, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ.</numerusform> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩ҂ҀÐūÐē ÐŋÐĩŅ€ÐĩÐīÐ°Ð―Ðū, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ.</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁ ÐŋÐĩŅ€ÐĩÐīÐ°Ð―, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ Ðē Ņ„ÐūŅ€ÐžÐĩ: %3.</numerusform> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩŅ‚Ņ€Ð° ÐŋÐĩŅ€ÐĩÐīÐ°Ð―Ðū, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ Ðē Ņ„ÐūŅ€ÐžÐĩ: %3.</numerusform> <numerusform>НÐĩÐēÐĩŅ€Ð―Ņ‹Ðĩ ÐŋÐ°Ņ€Ð°ÐžÐĩ҂Ҁҋ Ðē %1: %n ÐŋÐ°Ņ€Ð°ÐžÐĩ҂ҀÐūÐē ÐŋÐĩŅ€ÐĩÐīÐ°Ð―Ðū, Ð―Ðū %2 ҂ҀÐĩÐąŅƒÐĩŅ‚ŅŅ Ðē Ņ„ÐūŅ€ÐžÐĩ: %3.</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>НÐĩ ҃ÐīаÐŧÐūҁҌ ÐŋÐĩŅ€ÐĩÐļОÐĩÐ―ÐūÐēÐ°Ņ‚ŅŒ ÂŦ%1Âŧ Ðē ÂŦ%2Âŧ: %3</translation> </message> </context> </TS> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/ifw_zh_CN.ts��������������������������������������0100777�0000000�0000000�00000266534�13761647206�021427� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> <context> <name>AuthenticationRequiredException</name> <message> <source>%1 at %2</source> <translation>%1%2</translation> </message> <message> <source>Proxy requires authentication.</source> <translation>äŧĢį†éœ€č́čŋ›čĄŒčšŦäŧ―驌čŊã€‚</translation> </message> </context> <context> <name>BinaryContent</name> <message> <source>Cannot seek to %1 to read the operation data.</source> <translation>无æģ•åŊŧæą‚ %1 čŊŧå–æ“ä―œæ•°æŪ。</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection block.</source> <translation>无æģ•åŊŧæą‚ %1 čŊŧ取čĩ„暐æ”ķ集块。</translation> </message> <message> <source>Cannot open meta resource %1.</source> <translation>无æģ•打垀元čĩ„暐%1。</translation> </message> </context> <context> <name>BinaryLayout</name> <message> <source>Cannot seek to %1 to read the embedded meta data count.</source> <translation>无æģ•åŊŧæą‚ %1 čŊŧ取åĩŒå…Ĩ垏元数æŪčŪĄæ•°ã€‚</translation> </message> <message> <source>Cannot seek to %1 to read the resource collection segment.</source> <translation>无æģ•åŊŧæą‚ %1 čŊŧ取čĩ„暐æ”ķ集æŪĩ。</translation> </message> <message> <source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source> <translation>元čĩ„暐意åĪ–äļåŒđ配。 čŊŧ取 %1éĒ„æœŸïžš%2。</translation> </message> </context> <context> <name>Dialog</name> <message> <source>Http authentication required</source> <translation>需č́čŋ›čĄŒ Http čšŦäŧ―驌čŊ</translation> </message> <message> <source>You need to supply a Username and Password to access this site.</source> <translation>æ‚Ļ需čĶæäū›į”Ļ户名和åŊ†į æĨčŪŋé—Ūæ­ĪįŦ™į‚đ。</translation> </message> <message> <source>Username:</source> <translation>į”Ļ户名</translation> </message> <message> <source>Password:</source> <translation>åŊ†į ïžš</translation> </message> <message> <source>%1 at %2</source> <translation>%1%2</translation> </message> </context> <context> <name>DirectoryGuard</name> <message> <source>Path "%1" exists but is not a directory.</source> <translation>č·Ŋåū„“%1”存åœĻïžŒä―†äļæ˜Ŋį›Ūå―•ã€‚</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”。</translation> </message> </context> <context> <name>ExtractCallbackImpl</name> <message> <source>Cannot retrieve path of archive item %1.</source> <translation>无æģ•æĢ€įīĒ存æĄĢéĄđ %1 įš„č·Ŋåū„。</translation> </message> <message> <source>Cannot remove already existing symlink %1.</source> <translation>无æģ•į§ŧé™Īå·ē存åœĻįš„įŽĶ号é“ūæŽĨ %1。</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Cannot create symlink at "%1". Another one is already existing.</source> <translation>无æģ•åœĻ“%1”åĪ„åˆ›åŧšįŽĶ号é“ūæŽĨ。 å·ē存åœĻåĶäļ€äļŠįŽĶ号é“ūæŽĨ。</translation> </message> <message> <source>Cannot read symlink target from file "%1".</source> <translation>无æģ•äŧŽæ–‡äŧķ“%1”äļ­čŊŧ取įŽĶ号é“ūæŽĨį›Ū标。</translation> </message> <message> <source>Cannot create symlink at %1: %2</source> <translation>无æģ•åœĻ %1 创åŧšįŽĶ号é“ūæŽĨïžš%2</translation> </message> </context> <context> <name>InstallerBase</name> <message> <source>Waiting for %1</source> <translation>æ­ĢåœĻį­‰åū… %1</translation> </message> <message> <source>Another %1 instance is already running. Wait until it finishes, close it, or restart your system.</source> <translation>åĶäļ€äļŠ %1 åŪžäū‹å·ēčŋčĄŒã€‚ čŊ·į­‰åū…č‡ģåŪŒæˆã€å…ģ闭或重新åŊåŠĻįģŧįŧŸã€‚</translation> </message> </context> <context> <name>InstallerCalculator</name> <message> <source>Components added as automatic dependencies:</source> <translation>įŧ„äŧķä―œäļšč‡ŠåŠĻäūčĩ–éĄđæ·ŧ加</translation> </message> <message> <source>Components added as dependency for "%1":</source> <translation>æ·ŧ加äļšâ€œ%1”äūčĩ–éĄđįš„įŧ„äŧķïžš</translation> </message> <message> <source>Components that have resolved dependencies:</source> <translation>包åŦå·ēč§Ģå†ģäūčĩ–éĄđįš„įŧ„äŧķïžš</translation> </message> <message> <source>Selected components without dependencies:</source> <translation>无äūčĩ–éĄđįš„æ‰€é€‰įŧ„äŧķïžš</translation> </message> <message> <source>Recursion detected, component "%1" already added with reason: "%2"</source> <translation>æĢ€æĩ‹åˆ°é€’å―’ïžŒįŧ„äŧķ“%1”å·ēæ·ŧ加原因äļšïžšâ€œ%2”</translation> </message> <message> <source>Cannot find missing dependency "%1" for "%2".</source> <translation>æ‰ūäļåˆ°â€œ%2â€įš„įžšåĪąäūčĩ–éĄđ“%1”。</translation> </message> </context> <context> <name>Job</name> <message> <source>Canceled</source> <translation>å·ē取æķˆ</translation> </message> </context> <context> <name>KDUpdater::AppendFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>无æģ•å·äŧ―文äŧķ“%1”%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>æ‰ūäļåˆ°â€œ%1â€įš„å·äŧ―文äŧķ。</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķ。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķïžš%2</translation> </message> </context> <context> <name>KDUpdater::CopyOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>无æģ•å·äŧ―文äŧķ“%1”。</translation> </message> <message> <source>Cannot copy a non-existent file: %1</source> <translation>无æģ•åĪåˆķäļå­˜åœĻįš„æ–‡äŧķïžš%1</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”%2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>无æģ•将文äŧķ“%1”åĪåˆķ到“%2”%3</translation> </message> <message> <source>Cannot delete file "%1": %2</source> <translation>无æģ•删é™Ī文äŧķ“%1”%2</translation> </message> <message> <source>Cannot restore backup file into "%1": %2</source> <translation>无æģ•å°†å·äŧ―文äŧķčŋ˜åŽŸäļšâ€œ%1”%2</translation> </message> </context> <context> <name>KDUpdater::DeleteOperation</name> <message> <source>Cannot create backup of file "%1": %2</source> <translation>无æģ•创åŧšæ–‡äŧķ“%1â€įš„å·äŧ―ïžš%2</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķïžš%2</translation> </message> </context> <context> <name>KDUpdater::FileDownloader</name> <message> <source>Download finished.</source> <translation>äļ‹č――åŪŒæˆã€‚</translation> </message> <message> <source>Cryptographic hashes do not match.</source> <translation>加åŊ†å“ˆåļŒäļåŒđ配。</translation> </message> <message> <source>Download canceled.</source> <translation>äļ‹č――å·ē取æķˆ</translation> </message> <message> <source>%1 of %2</source> <translation>%1/%2</translation> </message> <message> <source>%1 downloaded.</source> <translation>%1 å·ēäļ‹č――</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/į§’)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n åĪĐ </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n 小æ—ķ </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n 分钟</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n į§’ïžŒ</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - å‰Đä―™ %1%2%3%4。</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - å‰Đä―™æ—ķé—ī朊įŸĨ。</translation> </message> </context> <context> <name>KDUpdater::HttpDownloader</name> <message> <source>Cannot download %1. Writing to file "%2" failed: %3</source> <translation>无æģ•äļ‹č―― %1。 写å…Ĩ文äŧķ“%2”åĪąčīĨïžš%3</translation> </message> <message> <source>Cannot download %1. Cannot create file "%2": %3</source> <translation>无æģ•äļ‹č―― %1。 无æģ•创åŧšæ–‡äŧķ“%2”%3</translation> </message> <message> <source>%1 at %2</source> <translation>%1%2</translation> </message> <message> <source>Authentication request canceled.</source> <translation>čšŦäŧ―驌čŊčŊ·æą‚å·ē取æķˆã€‚</translation> </message> <message> <source>Secure Connection Failed</source> <translation>åŪ‰å…ĻčŋžæŽĨåĪąčīĨ</translation> </message> <message> <source>There was an error during connection to: %1.</source> <translation>čŋžæŽĨ到čŊĨ内åŪđæ—ķå‡šįŽ°é”™čŊŊïžš%1。</translation> </message> <message> <source>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</source> <translation>æ­Īé—ŪéǘåŊčƒ―äļŽæœåŠĄå™Ļįš„é…į―Ūį›ļå…ģïžŒæˆ–č€…æœ‰äššæ­ĢåœĻ尝čŊ•æĻĄæ‹ŸæœåŠĄå™Ļ。</translation> </message> <message> <source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source> <translation>åĶ‚æžœæ‚Ļäđ‹å‰å·ē成功čŋžæŽĨ到æ­ĪæœåŠĄå™Ļ或äŋĄäŧŧæ­ĪæœåŠĄå™Ļ则æ­Ī错čŊŊåŊčƒ―äļšæš‚æ—ķ错čŊŊåŊ重čŊ•。</translation> </message> <message> <source>Try again</source> <translation>重čŊ•</translation> </message> </context> <context> <name>KDUpdater::LocalFileDownloader</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>写å…Ĩ文äŧķ“%1”åĪąčīĨïžš%2</translation> </message> </context> <context> <name>KDUpdater::MkdirOperation</name> <message> <source>Cannot create directory "%1": %2</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”%2</translation> </message> <message> <source>Unknown error.</source> <translation>朊įŸĨ错čŊŊ。</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>无æģ•į§ŧé™Īį›Ūå―•â€œ%1”%2</translation> </message> </context> <context> <name>KDUpdater::MoveOperation</name> <message> <source>Cannot backup file "%1".</source> <translation>无æģ•å·äŧ―文äŧķ“%1”。</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”%2</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>无æģ•将文äŧķ“%1”åĪåˆķ到“%2”%3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķïžš%2</translation> </message> </context> <context> <name>KDUpdater::PrependFileOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>无æģ•å·äŧ―文äŧķ“%1”%2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Cannot find backup file for "%1".</source> <translation>æ‰ūäļåˆ°â€œ%1â€įš„å·äŧ―文äŧķ。</translation> </message> <message> <source>Cannot restore backup file for "%1".</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķ。</translation> </message> <message> <source>Cannot restore backup file for "%1": %2</source> <translation>无æģ•čŋ˜åŽŸâ€œ%1â€įš„å·äŧ―文äŧķïžš%2</translation> </message> </context> <context> <name>KDUpdater::ResourceFileDownloader</name> <message> <source>Cannot read resource file "%1": %2</source> <translation>无æģ•čŊŧ取čĩ„暐文äŧķ“%1”%2</translation> </message> </context> <context> <name>KDUpdater::RmdirOperation</name> <message> <source>Cannot remove directory "%1": %2</source> <translation>无æģ•į§ŧé™Īį›Ūå―•â€œ%1”%2</translation> </message> <message> <source>The directory does not exist.</source> <translation>į›Ūå―•äļå­˜åœĻ!</translation> </message> <message> <source>Cannot recreate directory "%1": %2</source> <translation>无æģ•重新创åŧšį›Ūå―•â€œ%1”%2</translation> </message> </context> <context> <name>KDUpdater::Task</name> <message> <source>%1 started</source> <translation>%1 å·ē垀始</translation> </message> <message> <source>%1 cannot be stopped</source> <translation>%1 无æģ•停æ­Ē</translation> </message> <message> <source>Cannot stop task %1</source> <translation>无æģ•停æ­ĒäŧŧåŠĄ %1</translation> </message> <message> <source>%1 cannot be paused</source> <translation>%1 无æģ•暂停</translation> </message> <message> <source>Cannot pause task %1</source> <translation>无æģ•暂停äŧŧåŠĄ %1</translation> </message> <message> <source>Cannot resume task %1</source> <translation>无æģ•æĒåĪäŧŧåŠĄ %1</translation> </message> <message> <source>%1 done</source> <translation>%1 å·ēåŪŒæˆ</translation> </message> </context> <context> <name>KDUpdater::UpdateFinder</name> <message> <source>Cannot access the package information of this application.</source> <translation>无æģ•čŪŋé—Ūæ­Īåš”į”ĻįĻ‹åšįš„åŒ…äŋĄæŊ。</translation> </message> <message> <source>No package sources set for this application.</source> <translation>æēĄæœ‰äļšæ­Īåš”į”ĻįĻ‹åščŪūį―Ū包暐。</translation> </message> <message numerus="yes"> <source>%n update(s) found.</source> <translation> <numerusform>æ‰ū到 %n äļŠæ›ī新。</numerusform> </translation> </message> <message> <source>Downloading Updates.xml from update sources.</source> <translation>æ­ĢåœĻäŧŽæ›ī新暐äļ‹č―― Updates.xml。</translation> </message> <message> <source>Cannot download package source %1 from "%2".</source> <translation>无æģ•äŧŽâ€œ%2”äļ‹č――包暐 %1。</translation> </message> <message> <source>Updates.xml file(s) downloaded from update sources.</source> <translation>å·ēäŧŽæ›ī新暐äļ‹č―― Updates.xml 文äŧķ。</translation> </message> <message> <source>Computing applicable updates.</source> <translation>æ­ĢåœĻčŪĄįۗ适į”Ļįš„æ›ī新。</translation> </message> <message> <source>Application updates computed.</source> <translation>å·ēčŪĄįŪ—åš”į”ĻįĻ‹åšæ›ī新。</translation> </message> </context> <context> <name>KDUpdater::UpdatesInfoData</name> <message> <source>Updates.xml contains invalid content: %1</source> <translation>Updates.xml 包åŦ无效内åŪđïžš%1</translation> </message> <message> <source>Cannot read "%1"</source> <translation>无æģ•čŊŧ取“%1”</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>%1 äļ­ %2、%3 įš„č§Ģ析错čŊŊïžš%4</translation> </message> <message> <source>Root element %1 unexpected, should be "Updates".</source> <translation>意åĪ–įš„æ đ元įī  %1嚔äļšâ€œUpdates”。</translation> </message> <message> <source>ApplicationName element is missing.</source> <translation>įžšå°‘ ApplicationName 元įī ã€‚</translation> </message> <message> <source>ApplicationVersion element is missing.</source> <translation>įžšå°‘ ApplicationVersion 元įī ã€‚</translation> </message> <message> <source>PackageUpdate element without Name</source> <translation>PackageUpdate 元įī æ—  Name</translation> </message> <message> <source>PackageUpdate element without Version</source> <translation>PackageUpdate 元įī æ—  Version</translation> </message> <message> <source>PackageUpdate element without ReleaseDate</source> <translation>PackageUpdate 元įī æ—  ReleaseDate</translation> </message> </context> <context> <name>Lib7z</name> <message> <source>internal code: %1</source> <translation>内éƒĻäŧĢį ïžš%1</translation> </message> <message> <source>not enough memory</source> <translation>内存äļčķģ</translation> </message> <message> <source>Error: %1</source> <translation>错čŊŊïžš%1</translation> </message> <message> <source>Cannot retrieve property %1 for item %2.</source> <translation>无æģ•æĢ€įīĒéĄđį›Ū %2 įš„åąžæ€§ %1。</translation> </message> <message> <source>Property %1 for item %2 not of type VT_FILETIME but %3.</source> <translation>éĄđį›Ū %2 įš„åąžæ€§ %1 äļæ˜Ŋ VT_FILETIME įąŧåž‹ïžŒč€Œæ˜Ŋ %3。</translation> </message> <message> <source>Cannot convert UTC file time to system time.</source> <translation>无æģ•å°† UTC 文äŧķæ—ķé—īč―ŽæĒäļšįģŧįŧŸæ—ķé—ī。</translation> </message> <message> <source>Cannot load codecs.</source> <translation>无æģ•åŠ č――įž–č§Ģ᠁å™Ļ。</translation> </message> <message> <source>Cannot open archive "%1".</source> <translation>无æģ•打垀存æĄĢ“%1”。</translation> </message> <message> <source>Cannot retrieve number of items in archive.</source> <translation>无æģ•æĢ€įīĒ存æĄĢäļ­įš„éĄđį›Ū数。</translation> </message> <message> <source>Cannot retrieve path of archive item "%1".</source> <translation>无æģ•æĢ€įīĒ存æĄĢéĄđ“%1â€įš„č·Ŋåū„。</translation> </message> <message> <source>Unknown exception caught (%1).</source> <translation>æ•čŽ·åˆ°æœŠįŸĨåž‚åļļ(%1)。</translation> </message> <message> <source>Cannot create temporary file: %1</source> <translation>无æģ•创åŧšäļīæ—ķæ–‡äŧķïžš%1</translation> </message> <message> <source>Unsupported archive type.</source> <translation>äļæ”ŊæŒįš„å­˜æĄĢįąŧ型。</translation> </message> <message> <source>Cannot create archive "%1"</source> <translation>无æģ•创åŧšå­˜æĄĢ“%1”</translation> </message> <message> <source>Cannot create archive "%1": %2</source> <translation>无æģ•创åŧšå­˜æĄĢ“%1”%2</translation> </message> <message> <source>Cannot remove old archive "%1": %2</source> <translation>无æģ•į§ŧé™Ī旧存æĄĢ“%1”%2</translation> </message> <message> <source>Cannot rename temporary archive "%1" to "%2": %3</source> <translation>无æģ•å°†äļīæ—ķ存æĄĢ“%1â€é‡å‘―åäļšâ€œ%2”%3</translation> </message> <message> <source>Unknown exception caught (%1)</source> <translation>æ•čŽ·åˆ°æœŠįŸĨåž‚åļļ(%1)</translation> </message> </context> <context> <name>LocalPackageHub</name> <message> <source>%1 contains invalid content: %2</source> <translation>%1 包åŦ无效内åŪđïžš%2</translation> </message> <message> <source>The file %1 does not exist.</source> <translation>文äŧķ %1 äļå­˜åœĻ。</translation> </message> <message> <source>Cannot open %1.</source> <translation>无æģ•打垀 %1。</translation> </message> <message> <source>Parse error in %1 at %2, %3: %4</source> <translation>%1 äļ­ %2、%3 įš„č§Ģ析错čŊŊïžš%4</translation> </message> <message> <source>Root element %1 unexpected, should be 'Packages'.</source> <translation>意åĪ–įš„æ đ元įī  %1嚔äļšâ€œåŒ…”。</translation> </message> </context> <context> <name>LockFile</name> <message> <source>Cannot create lock file "%1": %2</source> <translation>无æģ•创åŧšé”åŪšæ–‡äŧķ“%1”%2</translation> </message> <message> <source>Cannot write PID to lock file "%1": %2</source> <translation>无æģ•写å…Ĩ PID æĨ锁åŪšæ–‡äŧķ“%1”%2</translation> </message> <message> <source>Cannot obtain the lock for file "%1": %2</source> <translation>无æģ•čŽ·å–æ–‡äŧķ“%1â€įš„é”åŪšïžš%2</translation> </message> <message> <source>Cannot release the lock for file "%1": %2</source> <translation>无æģ•释æ”ū文äŧķ“%1â€įš„é”åŪšïžš%2</translation> </message> </context> <context> <name>QInstaller</name> <message> <source>No marker found, stopped after %1.</source> <translation>朊æ‰ū到äŧŧä―•æ ‡čŪ°ïžŒ%1 后停æ­Ē。</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>%1 å­—čŠ‚åŽčŊŧ取åĪąčīĨïžš%2</translation> </message> <message> <source>Copy failed: %1</source> <translation>åĪåˆķåĪąčīĨïžš%1</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>%1 å­—čŠ‚åŽįž–å†™åĪąčīĨïžš%2</translation> </message> <message> <source>bytes</source> <translation>å­—čŠ‚</translation> </message> <message> <source>KB</source> <translation>KB</translation> </message> <message> <source>MB</source> <translation>MB</translation> </message> <message> <source>GB</source> <translation>GB</translation> </message> <message> <source>TB</source> <translation>TB</translation> </message> <message> <source>PB</source> <translation>PB</translation> </message> <message> <source>EB</source> <translation>EB</translation> </message> <message> <source>ZB</source> <translation>ZB</translation> </message> <message> <source>YB</source> <translation>YB</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”%2</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>无æģ•į§ŧé™Īį›Ūå―•â€œ%1”%2</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”。</translation> </message> <message> <source>Cannot copy file from "%1" to "%2": %3</source> <translation>无æģ•将文äŧķäŧŽâ€œ%1”åĪåˆķ到“%2”%3</translation> </message> <message> <source>Cannot move file from "%1" to "%2": %3</source> <translation>无æģ•将文äŧķäŧŽâ€œ%1”į§ŧåŠĻ到“%2”%3</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”%2</translation> </message> <message> <source>Cannot open temporary file: %1</source> <translation>无æģ•打垀äļīæ—ķæ–‡äŧķïžš%1</translation> </message> <message> <source>Cannot open temporary file for template %1: %2</source> <translation>无æģ•打垀æĻĄæŋ %1 įš„äļīæ—ķæ–‡äŧķïžš%2</translation> </message> <message> <source>Corrupt installation</source> <translation>åŪ‰čĢ…įĻ‹åšæŸå</translation> </message> <message> <source>Your installation seems to be corrupted. Please consider re-installing from scratch.</source> <translation>æ‚Ļįš„åŪ‰čĢ…įĻ‹åšäžžäđŽå·ēčĒŦ损坏。 čŊ·č€ƒč™‘äŧŽåĪī重新åŪ‰čĢ…ã€‚</translation> </message> <message> <source>The specified module could not be found.</source> <translation>æ‰ūäļåˆ°æŒ‡åŪšįš„æĻĄå—。</translation> </message> </context> <context> <name>QInstaller::Component</name> <message> <source>Components cannot have children in updater mode.</source> <translation>æ›ī新įĻ‹åšæĻĄåžäļ‹įŧ„äŧķäļåū—包åŦ子éĄđ。</translation> </message> <message> <source>Cannot open the requested UI file "%1": %2</source> <translation>无æģ•打垀čŊ·æą‚įš„ UI 文äŧķ“%1”%2</translation> </message> <message> <source>Cannot load the requested UI file "%1": %2</source> <translation>无æģ•åŠ č――čŊ·æą‚įš„ UI 文äŧķ“%1”%2</translation> </message> <message> <source>Cannot open the requested license file "%1": %2</source> <translation>无æģ•打垀čŊ·æą‚įš„čŪļåŊ文äŧķ“%1”%2</translation> </message> <message> <source>Error</source> <translation>错čŊŊ</translation> </message> <message> <source>Error: Operation %1 does not exist.</source> <translation>错čŊŊïžšæ“ä―œ %1 äļå­˜åœĻ。</translation> </message> <message> <source>Cannot resolve isDefault in %1</source> <translation>无æģ•č§Ģå†ģ %1 äļ­įš„ isDefault</translation> </message> <message> <source>Update Info: </source> <translation>æ›ī新äŋĄæŊïžš </translation> </message> </context> <context> <name>QInstaller::ComponentModel</name> <message> <source>Component is marked for installation.</source> <translation>įŧ„äŧķæ ‡čŪ°äļšåŪ‰čĢ…ã€‚</translation> </message> <message> <source>Component is marked for uninstallation.</source> <translation>įŧ„äŧķæ ‡čŪ°äļšåļč――ã€‚</translation> </message> <message> <source>Component is installed.</source> <translation>įŧ„äŧķå·ēåŪ‰čĢ…ã€‚</translation> </message> <message> <source>Component is not installed.</source> <translation>įŧ„äŧķæœŠåŪ‰čĢ…ã€‚</translation> </message> <message> <source>Component Name</source> <translation>įŧ„äŧķåį§°</translation> </message> <message> <source>Action</source> <translation>æ“ä―œ</translation> </message> <message> <source>Installed Version</source> <translation>åŪ‰čĢ…įš„į‰ˆæœŽ</translation> </message> <message> <source>New Version</source> <translation>新åŧšį‰ˆæœŽ</translation> </message> <message> <source>Release Date</source> <translation>发å—Ĩ期</translation> </message> <message> <source>Size</source> <translation>åĪ§å°</translation> </message> </context> <context> <name>QInstaller::ComponentSelectionPage</name> <message> <source>Alt+A</source> <comment>select default components</comment> <translation>Alt+A</translation> </message> <message> <source>Def&ault</source> <translation>éŧ˜čŪĪ(&A)</translation> </message> <message> <source>Alt+R</source> <comment>reset to already installed components</comment> <translation>Alt+R</translation> </message> <message> <source>&Reset</source> <translation>重į―Ū(&R)</translation> </message> <message> <source>Alt+S</source> <comment>select all components</comment> <translation>Alt+S</translation> </message> <message> <source>&Select All</source> <translation>å…Ļ选(&S)</translation> </message> <message> <source>Alt+D</source> <comment>deselect all components</comment> <translation>Alt+D</translation> </message> <message> <source>&Deselect All</source> <translation>取æķˆå…Ļ选(&D)</translation> </message> <message> <source>To install new compressed repository, browse the repositories from your computer</source> <translation>č́åŪ‰čĢ…æ–°įš„åŽ‹įžĐčĩ„æ–™æĄĢæĄˆåš“ïžŒčŊ·äŧŽčŪĄįŪ—æœšäļ­æĩč§ˆčĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>&Browse QBSP files</source> <translation>æĩč§ˆ QBSP 文äŧķ(&B)</translation> </message> <message> <source>This component will occupy approximately %1 on your hard disk drive.</source> <translation>æ­Īįŧ„äŧķåΧįšĶ占į”Ļæ‚ĻįĄŽį›˜éĐąåŠĻå™Ļ %1 įš„įĐšé—ī。</translation> </message> <message> <source>Open File</source> <translation>打垀文äŧķ</translation> </message> <message> <source>Select Components</source> <translation>选æ‹Đįŧ„äŧķ</translation> </message> <message> <source>Please select the components you want to update.</source> <translation>čŊ·é€‰æ‹Đč́æ›īæ–°įš„įŧ„äŧķ。</translation> </message> <message> <source>Please select the components you want to install.</source> <translation>čŊ·é€‰æ‹Đč́åŪ‰čĢ…įš„įŧ„äŧķ。</translation> </message> <message> <source>Please select the components you want to uninstall.</source> <translation>čŊ·é€‰æ‹Đč́åļč――įš„įŧ„äŧķ。</translation> </message> <message> <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source> <translation>选æ‹Đč́åŪ‰čĢ…įš„įŧ„äŧķ。 取æķˆé€‰æ‹Đå·ēåŪ‰čĢ…įŧ„äŧķäŧĨåļč――åۃäŧŽã€‚ 所有å·ēåŪ‰čĢ…įš„įŧ„äŧķ均äļäžšæ›ī新。</translation> </message> </context> <context> <name>QInstaller::ConsumeOutputOperation</name> <message> <source><to be saved installer key name> <executable> [argument1] [argument2] [...]</source> <translation><åū…äŋå­˜äļšåŪ‰čĢ…įĻ‹åšåŊ†åŒ™åį§°> <åŊæ‰§čĄŒ> [argument1] [argument2] [...]</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>%1 æ“ä―œäļ­įš„æ‰€éœ€åŪ‰čĢ…įĻ‹åšåŊđ蹥äļšįĐšã€‚</translation> </message> <message> <source>Cannot save the output of "%1" to an empty installer key value.</source> <translation>无æģ•将“%1â€įš„čū“凚äŋå­˜äļšįĐšåŪ‰čĢ…įĻ‹åšåŊ†é’Ĩ倞。</translation> </message> <message> <source>File "%1" does not exist or is not an executable binary.</source> <translation>文äŧķ“%1”äļå­˜åœĻ或äļæ˜ŊåŊæ‰§čĄŒįš„äšŒčŋ›åˆķ文äŧķ。</translation> </message> <message> <source>Running "%1" resulted in a crash.</source> <translation>čŋčĄŒâ€œ%1”åŊžč‡īåīĐæšƒã€‚</translation> </message> </context> <context> <name>QInstaller::CopyDirectoryOperation</name> <message> <source><source> <target> ["forceOverwrite"]</source> <translation><暐> <į›Ū标> ["forceOverwrite"]</translation> </message> <message> <source>Invalid argument in %1: Third argument needs to be forceOverwrite, if specified.</source> <translation>%1 äļ­įš„参数无效åĶ‚æžœæŒ‡åŪšïžŒåˆ™įŽŽäļ‰äļŠå‚数需č́äļš forceOverwrite。</translation> </message> <message> <source>Invalid argument in %1: Directory "%2" is invalid.</source> <translation>%1 äļ­įš„参数无效į›Ūå―•â€œ%2”无效。</translation> </message> <message> <source>Cannot create directory "%1".</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”。</translation> </message> <message> <source>Failed to overwrite "%1".</source> <translation>čĶ†į›–â€œ%1”åĪąčīĨ。</translation> </message> <message> <source>Cannot copy file "%1" to "%2": %3</source> <translation>无æģ•将文äŧķ“%1”åĪåˆķ到“%2”%3</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”。</translation> </message> </context> <context> <name>QInstaller::CopyFileTask</name> <message> <source>Invalid task item count.</source> <translation>äŧŧåŠĄéĄđį›ŪčŪĄæ•°æ— æ•ˆã€‚</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <translation>写å…Ĩ文äŧķ“%1”åĪąčīĨïžš%2</translation> </message> </context> <context> <name>QInstaller::CreateDesktopEntryOperation</name> <message> <source>Cannot backup file "%1": %2</source> <translation>无æģ•å·äŧ―文äŧķ“%1”%2</translation> </message> <message> <source>Failed to overwrite file "%1".</source> <translation>čĶ†į›–æ–‡äŧķ“%1”åĪąčīĨ。</translation> </message> <message> <source>Cannot write desktop entry to "%1".</source> <translation>无æģ•å°†æĄŒéĒæĄį›Ū写å…Ĩ“%1”。</translation> </message> </context> <context> <name>QInstaller::CreateLinkOperation</name> <message> <source>Cannot create link from "%1" to "%2".</source> <translation>无æģ•创åŧšäŧŽâ€œ%1”到“%2â€įš„é“ūæŽĨ。</translation> </message> <message> <source>Cannot remove link from "%1" to "%2".</source> <translation>无æģ•į§ŧé™Ī“%1”到“%2â€įš„é“ūæŽĨ。</translation> </message> </context> <context> <name>QInstaller::CreateLocalRepositoryOperation</name> <message> <source>Cannot set permissions for file "%1".</source> <translation>无æģ•čŪūį―Ūæ–‡äŧķ“%1â€įš„æƒé™ã€‚</translation> </message> <message> <source>Cannot remove file "%1": %2</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”%2</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>无æģ•将文äŧķ“%1”į§ŧåŠĻ到“%2”%3</translation> </message> <message> <source>Installer at "%1" needs to be an offline one.</source> <translation>“%1â€įš„åŪ‰čĢ…įĻ‹åšéœ€č́æ˜Ŋč„ąæœšåŪ‰čĢ…įĻ‹åšã€‚</translation> </message> <message> <source>Cannot open file "%1" for reading.</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取。</translation> </message> <message> <source>Cannot read file "%1": %2</source> <translation>无æģ•čŊŧ取文äŧķ“%1”%2</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot create target directory: "%1".</source> <translation>无æģ•创åŧšį›Ū标į›Ūå―•ïžšâ€œ%1”。</translation> </message> <message> <source>Unknown exception caught: %1.</source> <translation>æ•čŽ·åˆ°æœŠįŸĨåž‚åļļïžš%1。</translation> </message> <message> <source>Removing file "%1".</source> <translation>æ­ĢåœĻį§ŧé™Ī文äŧķ“%1”。</translation> </message> <message> <source>Cannot remove file "%1".</source> <translation>无æģ•į§ŧé™Ī文äŧķ“%1”。</translation> </message> <message> <source>Cannot remove directory "%1": %2</source> <translation>无æģ•į§ŧé™Īį›Ūå―•â€œ%1”%2</translation> </message> </context> <context> <name>QInstaller::CreateShortcutOperation</name> <message> <source><target> <link location> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</source> <translation><į›Ū标> <é“ūæŽĨä―į―Ū> [target arguments] ["workingDirectory=..."] ["iconPath=..."] ["iconId=..."] ["description=..."]</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”%2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>čĶ†į›–â€œ%1”åĪąčīĨïžš%2</translation> </message> <message> <source>Cannot create link "%1": %2</source> <translation>无æģ•创åŧšé“ūæŽĨ“%1”%2</translation> </message> </context> <context> <name>QInstaller::DownloadArchivesJob</name> <message> <source>Canceled</source> <translation>å·ē取æķˆ</translation> </message> <message> <source>Downloading hash signature failed.</source> <translation>哈åļŒį­ū名äļ‹č――åĪąčīĨ。</translation> </message> <message> <source>Download Error</source> <translation>äļ‹č――错čŊŊ</translation> </message> <message> <source>Hash verification while downloading failed. This is a temporary error, please retry.</source> <translation>äļ‹č――æ—ķįš„å“ˆåļŒéЌčŊåĪąčīĨ。 æ­Ī错čŊŊäļšäļīæ—ķ错čŊŊčŊ·é‡čŊ•。</translation> </message> <message> <source>Cannot verify Hash</source> <translation>无æģ•éЌčŊå“ˆåļŒ</translation> </message> <message> <source>Cannot download archive %1: %2</source> <translation>无æģ•äļ‹č――存æĄĢ %1ïžš%2</translation> </message> <message> <source>Cannot fetch archives: %1 Error while loading %2</source> <translation>无æģ•čŽ·å–å­˜æĄĢïžš%1 åŠ č―― %2 æ—ķå‡šįŽ°é”™čŊŊ</translation> </message> <message> <source>Downloading archive "%1" for component %2.</source> <translation>æ­ĢåœĻäļ‹č――įŧ„äŧķ %2 įš„å­˜æĄĢ“%1”。</translation> </message> <message> <source>Scheme %1 not supported (URL: %2).</source> <translation>äļæ”Ŋ持æ–đæĄˆ %1 (URLïžš%2)。</translation> </message> <message> <source>Cannot find component for %1.</source> <translation>无æģ•æ‰ū到 %1 įš„įŧ„äŧķ。</translation> </message> </context> <context> <name>QInstaller::Downloader</name> <message> <source>Target file "%1" already exists but is not a file.</source> <translation>į›Ū标文äŧķ“%1”å·ē存åœĻïžŒä―†äļæ˜Ŋ文äŧķ。</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>File "%1" not open for writing: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>朊打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> <message> <source>Writing to file "%1" failed: %2</source> <extracomment>%2 is a sentence describing the error.</extracomment> <translation>写å…Ĩ文äŧķ“%1”åĪąčīĨïžš%2</translation> </message> <message> <source>Redirect loop detected for "%1".</source> <translation>æĢ€æĩ‹åˆ°â€œ%1â€įš„é‡åŪšå‘åūŠįŽŊ。</translation> </message> <message> <source>Checksum mismatch detected for "%1".</source> <translation>æĢ€æĩ‹åˆ°â€œ%1â€įš„æ ĄéŠŒå’ŒäļåŒđ配。</translation> </message> <message> <source>Network error while downloading '%1': %2.</source> <translation>äļ‹č――“%1”æ—ķå‡šįŽ°į―‘įŧœé”™čŊŊïžš%2</translation> </message> <message> <source>Unknown network error while downloading "%1".</source> <extracomment>%1 is a sentence describing the error</extracomment> <translation>äļ‹č――“%1”æ—ķå‡šįŽ°æœŠįŸĨįš„į―‘įŧœé”™čŊŊ。</translation> </message> <message> <source>Network transfers canceled.</source> <translation>į―‘įŧœč―Žį§ŧå·ē取æķˆã€‚</translation> </message> <message> <source>Pause and resume not supported by network transfers.</source> <translation>į―‘įŧœäž čū“äļæ”Ŋ持äļ­æ­Ē和æĒåĪã€‚</translation> </message> <message> <source>Invalid source URL "%1": %2</source> <extracomment>%2 is a sentence describing the error</extracomment> <translation>æ— æ•ˆįš„æš URL“%1”%2</translation> </message> </context> <context> <name>QInstaller::ElevatedExecuteOperation</name> <message> <source>Cannot start detached: "%1"</source> <translation>无æģ•åŊåŠĻ分įĶŧ“%1”</translation> </message> <message> <source>Cannot start: "%1": %2</source> <translation>无æģ•åŊåŠĻ“%1”%2</translation> </message> <message> <source>Program crashed: "%1"</source> <translation>åīĐæšƒįĻ‹åšïžšâ€œ%1”</translation> </message> <message> <source>Execution failed (Unexpected exit code: %1): "%2"</source> <translation>æ‰§čĄŒåĪąčīĨ(意åĪ–é€€å‡šäŧĢį ïžš%1)“%2”</translation> </message> </context> <context> <name>QInstaller::ExtractArchiveOperation::Runnable</name> <message> <source>Cannot open archive "%1" for reading: %2</source> <translation>无æģ•打垀存æĄĢ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>提取存æĄĢ“%1”æ—ķ凚错%2</translation> </message> <message> <source>Unknown exception caught while extracting "%1".</source> <translation>提取“%1”æ—ķæ•čŽ·åˆ°æœŠįŸĨåž‚åļļ。</translation> </message> </context> <context> <name>QInstaller::FakeStopProcessForUpdateOperation</name> <message> <source>Cannot get package manager core.</source> <translation>无æģ•čŽ·å–åŒ…įŪĄį†å™Ļæ ļåŋƒå†…åŪđ。</translation> </message> <message> <source>This process should be stopped before continuing: %1</source> <translation>嚔先停æ­Ēæ­Īčŋ‡įĻ‹åŽå†įŧ§įŧ­ïžš%1</translation> </message> <message> <source>These processes should be stopped before continuing: %1</source> <translation>嚔先停æ­Ēčŋ™äš›čŋ‡įĻ‹åŽå†įŧ§įŧ­ïžš%1</translation> </message> </context> <context> <name>QInstaller::FileTaskObserver</name> <message> <source>%1 of %2</source> <translation>%1/%2</translation> </message> <message> <source>%1 received.</source> <translation>%1 å·ēæŽĨæ”ķ。</translation> </message> <message> <source>(%1/sec)</source> <translation>(%1/į§’)</translation> </message> <message numerus="yes"> <source>%n day(s), </source> <translation> <numerusform>%n åĪĐ </numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s), </source> <translation> <numerusform>%n 小æ—ķ </numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation> <numerusform>%n 分钟</numerusform> </translation> </message> <message numerus="yes"> <source>%n second(s)</source> <translation> <numerusform>%n į§’ïžŒ</numerusform> </translation> </message> <message> <source> - %1%2%3%4 remaining.</source> <translation> - å‰Đä―™ %1%2%3%4。</translation> </message> <message> <source> - unknown time remaining.</source> <translation> - å‰Đä―™æ—ķé—ī朊įŸĨ。</translation> </message> </context> <context> <name>QInstaller::FinishedPage</name> <message> <source>Completing the %1 Wizard</source> <translation>æ­ĢåœĻåŪŒæˆ %1 向åŊž</translation> </message> <message> <source>Click %1 to exit the %2 Wizard.</source> <translation>单å‡ŧ %1 退凚 %2 向åŊžã€‚</translation> </message> <message> <source>Restart</source> <translation>重新åŊåŠĻ</translation> </message> <message> <source>Run %1 now.</source> <translation>įŦ‹åģčŋčĄŒ %1。</translation> </message> <message> <source>The %1 Wizard failed.</source> <translation>%1 向åŊžåĪąčīĨ。</translation> </message> </context> <context> <name>QInstaller::GlobalSettingsOperation</name> <message> <source>Settings are not writable.</source> <translation>čŪūį―ŪäļåŊ写å…Ĩ。</translation> </message> <message> <source>Failed to write settings.</source> <translation>写å…ĨčŪūį―ŪåĪąčīĨ。</translation> </message> </context> <context> <name>QInstaller::InstallIconsOperation</name> <message> <source><source path> [vendor prefix]</source> <translation><暐č·Ŋåū„> [vendor prefix]</translation> </message> <message> <source>Invalid Argument: source directory must not be empty.</source> <translation>参数无效暐į›Ūå―•äļåū—äļšįĐšã€‚</translation> </message> <message> <source>Cannot backup file "%1": %2</source> <translation>无æģ•å·äŧ―文äŧķ“%1”%2</translation> </message> <message> <source>Failed to overwrite "%1": %2</source> <translation>čĶ†į›–â€œ%1”åĪąčīĨïžš%2</translation> </message> <message> <source>Failed to copy file "%1": %2</source> <translation>åĪåˆķ文äŧķ“%1”åĪąčīĨïžš%2</translation> </message> <message> <source>Cannot create directory "%1": %2</source> <translation>无æģ•创åŧšį›Ūå―•â€œ%1”%2</translation> </message> </context> <context> <name>QInstaller::IntroductionPage</name> <message> <source>Setup - %1</source> <translation>åŪ‰čĢ…įĻ‹åš - %1</translation> </message> <message> <source>Welcome to the %1 Setup Wizard.</source> <translation>æŽĒčŋŽä―ŋį”Ļ %1 åŪ‰č̅向åŊžã€‚</translation> </message> <message> <source>&Add or remove components</source> <translation>æ·ŧ加或į§ŧé™Īįŧ„äŧķ</translation> </message> <message> <source>&Update components</source> <translation>æ›ī新įŧ„äŧķ</translation> </message> <message> <source>&Remove all components</source> <translation>į§ŧé™Ī所有įŧ„äŧķ</translation> </message> <message> <source>Retrieving information from remote installation sources...</source> <translation>æ­ĢåœĻäŧŽčŋœįĻ‹åŪ‰čĢ…æšæĢ€įīĒäŋĄæŊâ€Ķ</translation> </message> <message> <source>At least one valid and enabled repository required for this action to succeed.</source> <translation>æ­Īæ“ä―œč‡ģ少需č́äļ€äļŠåĪ„äšŽåŊį”ĻįŠķæ€įš„æœ‰æ•ˆčĩ„æ–™æĄĢæĄˆåš“ã€‚</translation> </message> <message> <source>No updates available.</source> <translation>无åŊį”Ļæ›ī新。</translation> </message> <message> <source> Only local package management available.</source> <translation> äŧ…朎地č―Ŋäŧķ包įŪĄį†åŊį”Ļ。</translation> </message> <message> <source>&Quit</source> <translation>退凚</translation> </message> </context> <context> <name>QInstaller::LicenseAgreementPage</name> <message> <source>License Agreement</source> <translation>čŪļåŊ协čŪŪ</translation> </message> <message> <source>Alt+A</source> <comment>agree license</comment> <translation>Alt+A</translation> </message> <message> <source>Alt+D</source> <comment>do not agree license</comment> <translation>Alt+D</translation> </message> <message> <source>Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.</source> <translation>čŊ·é˜…čŊŧäŧĨäļ‹čŪļåŊ协čŪŪ。 æ‚Ļåŋ…éĄŧæŽĨ受æ­Ī协čŪŪäļ­įš„æĄæŽūæ‰čƒ―įŧ§įŧ­åŪ‰čĢ…ã€‚</translation> </message> <message> <source>I accept the license.</source> <translation>我æŽĨ受æ­ĪčŪļåŊ。</translation> </message> <message> <source>I do not accept the license.</source> <translation>我äļæŽĨ受æ­ĪčŪļåŊ。</translation> </message> <message> <source>Please read the following license agreements. You must accept the terms contained in these agreements before continuing with the installation.</source> <translation>čŊ·é˜…čŊŧäŧĨäļ‹čŪļåŊ协čŪŪ。 æ‚Ļåŋ…éĄŧæŽĨ受čŋ™äš›åčŪŪäļ­įš„æĄæŽūæ‰čƒ―įŧ§įŧ­åŪ‰čĢ…ã€‚</translation> </message> <message> <source>I accept the licenses.</source> <translation>我æŽĨ受čŋ™äš›čŪļåŊ。</translation> </message> <message> <source>I do not accept the licenses.</source> <translation>我äļæŽĨ受čŋ™äš›čŪļåŊ。</translation> </message> </context> <context> <name>QInstaller::LicenseOperation</name> <message> <source>No license files found to copy.</source> <translation>朊æ‰ū到č́åĪåˆķįš„čŪļåŊ文äŧķ。</translation> </message> <message> <source>Needed installer object in %1 operation is empty.</source> <translation>%1 æ“ä―œäļ­įš„æ‰€éœ€åŪ‰čĢ…įĻ‹åšåŊđ蹥äļšįĐšã€‚</translation> </message> <message> <source>Can not write license file "%1".</source> <translation>无æģ•写å…ĨčŪļåŊ文äŧķ“%1”。</translation> </message> <message> <source>No license files found to delete.</source> <translation>朊æ‰ū到č́删é™Īįš„čŪļåŊ文äŧķ。</translation> </message> </context> <context> <name>QInstaller::LineReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> </context> <context> <name>QInstaller::MetadataJob</name> <message> <source>Missing package manager core engine.</source> <translation>įžšå°‘åŒ…įŪĄį†å™Ļæ ļåŋƒåž•擎。</translation> </message> <message> <source>Preparing meta information download...</source> <translation>æ­ĢåœĻ准å·äļ‹č――元äŋĄæŊ...</translation> </message> <message> <source>Unpacking compressed repositories. This may take a while...</source> <translation>č§Ģ压压įžĐčĩ„æ–™æĄĢæĄˆåš“ã€‚ čŋ™åŊčƒ―éœ€č́äļ€ä𛿗ķé—ī...</translation> </message> <message> <source>Meta data download canceled.</source> <translation>元数æŪäļ‹č――å·ē取æķˆã€‚</translation> </message> <message> <source>Unknown exception during extracting.</source> <translation>提取čŋ‡įĻ‹äļ­å‡šįŽ°æœŠįŸĨåž‚åļļ。</translation> </message> <message> <source>Missing proxy credentials.</source> <translation>įžšå°‘äŧĢᐆ凭æŪ。</translation> </message> <message> <source>Authentication failed.</source> <translation>čšŦäŧ―驌čŊåĪąčīĨ。</translation> </message> <message> <source>Unknown exception during download.</source> <translation>äļ‹č――čŋ‡įĻ‹äļ­å‡šįŽ°æœŠįŸĨåž‚åļļ。</translation> </message> <message> <source>Failure to fetch repositories.</source> <translation>无æģ•čŽ·å–čĩ„æ–™æĄĢæĄˆåš“ã€‚</translation> </message> <message> <source>Extracting meta information...</source> <translation>æ­ĢåœĻ提取元äŋĄæŊ...</translation> </message> <message> <source>Retrieving meta information from remote repository... %1/%2 </source> <translation>æ­ĢåœĻäŧŽčŋœįĻ‹čĩ„æ–™æĄĢæĄˆåš“äﭿ̀įīĒ元äŋĄæŊ... %1/%2 </translation> </message> <message> <source>Retrieving meta information from remote repository... </source> <translation>æ­ĢåœĻäŧŽčŋœįĻ‹čĩ„æ–™æĄĢæĄˆåš“äﭿ̀įīĒ元äŋĄæŊ... </translation> </message> <message> <source>Error while extracting archive "%1": %2</source> <translation>提取存æĄĢ“%1”æ—ķ凚错%2</translation> </message> <message> <source>Unknown exception caught while extracting archive "%1".</source> <translation>提取存æĄĢ“%1”æ—ķæ•čŽ·åˆ°æœŠįŸĨåž‚åļļ。</translation> </message> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> </context> <context> <name>QInstaller::PackageManagerCore</name> <message> <source>Error writing Maintenance Tool</source> <translation>įž–å†™įŧĪå·Ĩ具æ—ķ凚错</translation> </message> <message> <source> Downloading packages...</source> <translation> æ­ĢåœĻäļ‹č――包...</translation> </message> <message> <source>Installation canceled by user.</source> <translation>į”Ļ户å·ē取æķˆåŪ‰čĢ…ã€‚</translation> </message> <message> <source>All downloads finished.</source> <translation>所有äļ‹č――均å·ēåŪŒæˆã€‚</translation> </message> <message> <source>Cancelling the Installer</source> <translation>æ­ĢåœĻ取æķˆåŪ‰čĢ…įĻ‹åš</translation> </message> <message> <source>Authentication Error</source> <translation>čšŦäŧ―驌čŊé”™čŊŊ</translation> </message> <message> <source>Some components could not be removed completely because administrative rights could not be acquired: %1.</source> <translation>无æģ•åیå…Ļį§ŧé™Ī某䚛įŧ„äŧķ因äļšæ— æģ•čŽ·å–įŪĄį†æƒé™ïžš%1。</translation> </message> <message> <source>Unknown error.</source> <translation>朊įŸĨ错čŊŊ。</translation> </message> <message> <source>Some components could not be removed completely because an unknown error happened.</source> <translation>į”ąäšŽå‡šįŽ°æœŠįŸĨ错čŊŊ无æģ•å―ŧåš•į§ŧé™Ī某䚛įŧ„äŧķ。</translation> </message> <message> <source>Application not running in Package Manager mode.</source> <translation>åš”į”ĻįĻ‹åšæœŠåœĻ包įŪĄį†å™ĻæĻĄåžäļ‹čŋčĄŒã€‚</translation> </message> <message> <source>No installed packages found.</source> <translation>朊æ‰ū到äŧŧä―•å·ēåŪ‰čĢ…įš„č―Ŋäŧķ包。</translation> </message> <message> <source>Application running in Uninstaller mode.</source> <translation>åš”į”ĻįĻ‹åšåœĻåļč――įĻ‹åšæĻĄåžäļ‹čŋčĄŒã€‚</translation> </message> <message> <source>There is an important update available, please run the updater first.</source> <translation>有重čĶįš„æ›ī新åŊäū›ä―ŋį”ĻčŊ·å…ˆčŋčĄŒæ›ī新įĻ‹åšã€‚</translation> </message> <message> <source>Cannot resolve all dependencies.</source> <translation>无æģ•č§Ģ析所有äūčĩ–éĄđ。</translation> </message> <message> <source>Components about to be removed.</source> <translation>åģ将čĒŦį§ŧé™Īįš„įŧ„äŧķ。</translation> </message> <message> <source>Error while elevating access rights.</source> <translation>提升čŪŋé—Ū权限æ—ķå‘į”Ÿé”™čŊŊ。</translation> </message> <message> <source>Error</source> <translation>错čŊŊ</translation> </message> <message> <source>invalid</source> <translation>无效</translation> </message> </context> <context> <name>QInstaller::PackageManagerCorePrivate</name> <message> <source>Unresolved dependencies</source> <translation>朊č§Ģ析äūčĩ–éĄđ</translation> </message> <message> <source>Error</source> <translation>错čŊŊ</translation> </message> <message> <source>Access error</source> <translation>čŪŋé—Ū错čŊŊ</translation> </message> <message> <source>Format error</source> <translation>栞垏错čŊŊ</translation> </message> <message> <source>Cannot write installer configuration to %1: %2</source> <translation>无æģ•å°†åŪ‰čĢ…įĻ‹åšé…į―Ū写å…Ĩ %1ïžš%2</translation> </message> <message> <source>Stop Processes</source> <translation>停æ­Ēčŋ‡įĻ‹</translation> </message> <message> <source>These processes should be stopped to continue: %1</source> <translation>嚔停æ­Ēčŋ™äš›čŋ‡įĻ‹äŧĨįŧ§įŧ­ïžš %1</translation> </message> <message> <source>Installation canceled by user</source> <translation>į”Ļ户å·ē取æķˆåŪ‰čĢ…</translation> </message> <message> <source>Writing maintenance tool.</source> <translation>įž–å†™įŧĪå·Ĩ具</translation> </message> <message> <source>Failed to seek in file %1: %2</source> <translation>无æģ•åœĻ文äŧķ %1 äļ­æœįīĒïžš%2</translation> </message> <message> <source>Maintenance tool is not a bundle</source> <translation>įŧĪå·Ĩ具äļæ˜Ŋ捆įŧ‘包</translation> </message> <message> <source>Cannot remove data file "%1": %2</source> <translation>无æģ•į§ŧé™Ī数æŪ文äŧķ“%1”%2</translation> </message> <message> <source>Cannot write maintenance tool data to %1: %2</source> <translation>无æģ•å°†įŧĪå·Ĩ具数æŪ写å…Ĩ %1ïžš%2</translation> </message> <message> <source>Cannot write maintenance tool to "%1": %2</source> <translation>无æģ•å°†įŧĪå·Ĩ具写å…Ĩ“%1”%2</translation> </message> <message> <source>Cannot write maintenance tool binary data to %1: %2</source> <translation>无æģ•å°†įŧĪå·Ĩ具䚌čŋ›åˆķ数æŪ写å…Ĩ %1ïžš%2</translation> </message> <message> <source>Variable 'TargetDir' not set.</source> <translation>朊čŪūį―Ū变量“TargetDir”。</translation> </message> <message> <source>Preparing the installation...</source> <translation>æ­ĢåœĻ准å·åŪ‰čĢ…â€Ķ</translation> </message> <message> <source>It is not possible to install from network location</source> <translation>无æģ•äŧŽį―‘įŧœä―į―Ūčŋ›čĄŒåŪ‰čĢ…</translation> </message> <message> <source>Creating local repository</source> <translation>æ­ĢåœĻ创åŧšæœŽåœ°čĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>Creating Maintenance Tool</source> <translation>æ­ĢåœĻ创åŧšįŧĪå·Ĩ具</translation> </message> <message> <source> Installation finished!</source> <translation> åŪ‰čĢ…å·ēåŪŒæˆ!</translation> </message> <message> <source> Installation aborted!</source> <translation> åŪ‰čĢ…å·ēäļ­æ­Ē!</translation> </message> <message> <source>It is not possible to run that operation from a network location</source> <translation>无æģ•äŧŽį―‘įŧœä―į―ŪčŋčĄŒčŊĨæ“ä―œ</translation> </message> <message> <source>Removing deselected components...</source> <translation>æ­ĢåœĻį§ŧé™Ī朊选äļ­įš„įŧ„äŧķ...</translation> </message> <message> <source> Update finished!</source> <translation> æ›ī新å·ēåŪŒæˆ!</translation> </message> <message> <source> Update aborted!</source> <translation> æ›ī新å·ēäļ­æ­Ē!</translation> </message> <message> <source>Uninstallation completed successfully.</source> <translation>成功åļč――ã€‚</translation> </message> <message> <source>Uninstallation aborted.</source> <translation>åļč――å·ēäļ­æ­Ē。</translation> </message> <message> <source> Installing component %1</source> <translation> æ­ĢåœĻåŪ‰čĢ…įŧ„äŧķ %1</translation> </message> <message> <source>Installer Error</source> <translation>åŪ‰čĢ…įĻ‹åšé”™čŊŊ</translation> </message> <message> <source>Error during installation process (%1): %2</source> <translation>åŪ‰čĢ…čŋ‡įĻ‹äļ­å‡šįް错čŊŊ(%1) %2</translation> </message> <message> <source>Cannot prepare uninstall</source> <translation>无æģ•准å·åļč――</translation> </message> <message> <source>Cannot start uninstall</source> <translation>无æģ•垀始åļč――</translation> </message> <message> <source>Error during uninstallation process: %1</source> <translation>åļč――čŋ‡įĻ‹äļ­å‡šįް错čŊŊïžš %1</translation> </message> <message> <source>Unknown error</source> <translation>朊įŸĨ错čŊŊ</translation> </message> <message> <source>Cannot retrieve remote tree %1.</source> <translation>无æģ•æĢ€įīĒčŋœįĻ‹æ ‘ %1。</translation> </message> <message> <source>Failure to read packages from %1.</source> <translation>无æģ•äŧŽ %1 čŊŧ取包。</translation> </message> <message> <source>Cannot retrieve meta information: %1</source> <translation>无æģ•æĢ€įīĒ元äŋĄæŊïžš%1</translation> </message> <message> <source>Cannot add temporary update source information.</source> <translation>无æģ•æ·ŧ加äļīæ—ķæ›īæ–°æšäŋĄæŊ。</translation> </message> <message> <source>Cannot find any update source information.</source> <translation>æ‰ūäļåˆ°äŧŧä―•æ›ī新暐äŋĄæŊ。</translation> </message> <message> <source>Dependency cycle between components "%1" and "%2" detected.</source> <translation>æĢ€æĩ‹åˆ°įŧ„äŧķ“%1”和“%2”äđ‹é—īįš„äūčĩ–éĄđåūŠįŽŊ。</translation> </message> </context> <context> <name>QInstaller::PackageManagerGui</name> <message> <source>%1 Setup</source> <translation>%1 åŪ‰čĢ…įĻ‹åš</translation> </message> <message> <source>Maintain %1</source> <translation>įŧΠ%1</translation> </message> <message> <source>Do you want to cancel the installation process?</source> <translation>æ˜ŊåĶčĶå–æķˆåŪ‰čĢ…čŋ‡įĻ‹?</translation> </message> <message> <source>Do you want to cancel the uninstallation process?</source> <translation>æ˜ŊåĶčĶå–æķˆåļč――čŋ‡įĻ‹?</translation> </message> <message> <source>Do you want to quit the installer application?</source> <translation>æ˜ŊåĶčĶé€€å‡šåŪ‰čĢ…įĻ‹åšåš”į”ĻįĻ‹åš?</translation> </message> <message> <source>Do you want to quit the uninstaller application?</source> <translation>æ˜ŊåĶčĶé€€å‡šåļč――įĻ‹åšåš”į”ĻįĻ‹åš?</translation> </message> <message> <source>Do you want to quit the maintenance application?</source> <translation>æ˜ŊåĶčĶé€€å‡šįŧĪåš”į”ĻįĻ‹åš?</translation> </message> <message> <source>%1 Question</source> <translation>%1 é—Ūéǘ</translation> </message> <message> <source>Settings</source> <translation>čŪūį―Ū</translation> </message> <message> <source>Error</source> <translation>错čŊŊ</translation> </message> <message> <source>It is not possible to install from network location. Please copy the installer to a local drive</source> <translation>无æģ•äŧŽį―‘įŧœä―į―Ūčŋ›čĄŒåŪ‰čĢ…ã€‚ čŊ·å°†åŪ‰čĢ…įĻ‹åšåĪåˆķ到朎地éĐąåŠĻå™Ļ</translation> </message> </context> <context> <name>QInstaller::PerformInstallationForm</name> <message> <source>&Show Details</source> <translation>æ˜ūįĪščŊĶįŧ†äŋĄæŊ(%S)</translation> </message> <message> <source>&Hide Details</source> <translation>隐藏čŊĶįŧ†äŋĄæŊ(%H)</translation> </message> </context> <context> <name>QInstaller::PerformInstallationPage</name> <message> <source>U&ninstall</source> <translation>åļč――(&N)</translation> </message> <message> <source>Uninstalling %1</source> <translation>æ­ĢåœĻåļč―― %1</translation> </message> <message> <source>&Update</source> <translation>æ›ī新(&U)</translation> </message> <message> <source>Updating components of %1</source> <translation>æ­ĢåœĻæ›ī新 %1 įš„įŧ„äŧķ</translation> </message> <message> <source>&Install</source> <translation>åŪ‰čĢ…(&I)</translation> </message> <message> <source>Installing %1</source> <translation>æ­ĢåœĻåŪ‰čĢ… %1</translation> </message> </context> <context> <name>QInstaller::ProxyCredentialsDialog</name> <message> <source>Dialog</source> <translation>åŊđčŊæĄ†</translation> </message> <message> <source>The proxy %1 requires a username and password.</source> <translation>äŧĢᐆ %1 需č́čū“å…Ĩį”Ļ户名和åŊ†į ã€‚</translation> </message> <message> <source>Username:</source> <translation>į”Ļ户名</translation> </message> <message> <source>Username</source> <translation>į”Ļ户名</translation> </message> <message> <source>Password:</source> <translation>åŊ†į ïžš</translation> </message> <message> <source>Password</source> <translation>åŊ†į </translation> </message> <message> <source>Proxy Credentials</source> <translation>äŧĢᐆ凭æŪ</translation> </message> </context> <context> <name>QInstaller::ReadyForInstallationPage</name> <message> <source>U&ninstall</source> <translation>åļč――(&N)</translation> </message> <message> <source>Ready to Uninstall</source> <translation>准å·åļč――</translation> </message> <message> <source>Setup is now ready to begin removing %1 from your computer.<br><font color="red">The program directory %2 will be deleted completely</font>, including all content in that directory!</source> <translation>åŪ‰čĢ…įĻ‹åšįŽ°å·ē准å·åĨ―äŧŽæ‚Ļįš„čŪĄįŪ—æœšäļ­į§ŧé™Ī %1。<br><font color="red">将å―ŧ嚕删é™ĪįĻ‹åšį›Ūå―• %2</font>į›Ūå―•å†…æ‰€æœ‰å†…åŪđäđŸå°†čĒŦ删é™Ī!</translation> </message> <message> <source>U&pdate</source> <translation>æ›ī新(%P)</translation> </message> <message> <source>Ready to Update Packages</source> <translation>准å·æ›ī新包</translation> </message> <message> <source>Setup is now ready to begin updating your installation.</source> <translation>åŪ‰čĢ…įĻ‹åšįŽ°å·ē准å·åĨ―åŪ‰čĢ…æ‚Ļįš„æ›ī新。</translation> </message> <message> <source>&Install</source> <translation>åŪ‰čĢ…(&I)</translation> </message> <message> <source>Ready to Install</source> <translation>准å·åŪ‰čĢ…</translation> </message> <message> <source>Setup is now ready to begin installing %1 on your computer.</source> <translation>åŪ‰čĢ…įĻ‹åšįŽ°å·ē准å·åĨ―åœĻæ‚Ļįš„čŪĄįŪ—å™Ļäļ­åŪ‰čĢ… %1。</translation> </message> <message> <source>Not enough disk space to store temporary files and the installation. %1 are available, while %2 are at least required.</source> <translation>æēĄæœ‰čķģåĪŸįš„įĢį›˜įĐšé—īæĨ存å‚Ļäļīæ—ķæ–‡äŧķ和åŪ‰čĢ…ã€‚%1 åŊį”ĻïžŒä―†č‡ģ少需č́ %2。</translation> </message> <message> <source>Not enough disk space to store all selected components! %1 are available while %2 are at least required.</source> <translation>æēĄæœ‰čķģåĪŸįš„įĢį›˜įĐšé—īæĨ存å‚Ļ所有选åŪšįš„įŧ„äŧķ! %1 åŊį”ĻïžŒä―†č‡ģ少需č́ %2。</translation> </message> <message> <source>Not enough disk space to store temporary files! %1 are available while %2 are at least required.</source> <translation>æēĄæœ‰čķģåĪŸįš„įĢį›˜įĐšé—īæĨ存å‚Ļäļīæ—ķæ–‡äŧķ! %1 åŊį”ĻïžŒä―†č‡ģ少需č́ %2。</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 1% of the volume's space available afterwards. %1</source> <translation>有čķģåĪŸįš„įĐšé—īåŊäŧĨåŪ‰čĢ…æ‚Ļ所选æ‹Đįš„åŪ‰čĢ…įĻ‹åšïžŒä―†æ˜ŊåŪ‰čĢ…åŪŒæˆåŽïžŒåŊį”ĻįĐšé—ī将少䚎 1%。%1</translation> </message> <message> <source>The volume you selected for installation seems to have sufficient space for installation, but there will be less than 100 MB available afterwards. %1</source> <translation>有čķģåĪŸįš„įĐšé—īåŊäŧĨåŪ‰čĢ…æ‚Ļ所选æ‹Đįš„åŪ‰čĢ…įĻ‹åšïžŒä―†æ˜ŊåŪ‰čĢ…åŪŒæˆåŽïžŒåŊį”ĻįĐšé—ī将少䚎 100 MB。%1</translation> </message> <message> <source>Installation will use %1 of disk space.</source> <translation>åŪ‰čĢ…įĻ‹åšå°†ä―ŋį”Ļ %1 įš„įĢį›˜įĐšé—ī。</translation> </message> </context> <context> <name>QInstaller::RegisterFileTypeOperation</name> <message> <source><extension> <command> [description [contentType [icon]]]</source> <translation><æ‰Đåą•å> <å‘―äŧĪ> [description [contentType [icon]]]</translation> </message> <message> <source>Registering file types is only supported on Windows.</source> <translation>Windows äļæ”Ŋ持æģĻ册文äŧķįąŧ型。</translation> </message> <message> <source>Register File Type: Invalid arguments</source> <translation>æģĻ册文äŧķįąŧåž‹ïžšæ— æ•ˆįš„å‚æ•°</translation> </message> </context> <context> <name>QInstaller::RemoteObject</name> <message> <source>Cannot read all data after sending command: %1. Bytes expected: %2, Bytes received: %3. Error: %4</source> <translation>å‘é€å‘―äŧĪ后无æģ•čŊŧ取所有数æŪïžš%1 éĒ„æœŸå­—čŠ‚ïžš%2æ”ķåˆ°įš„å­—čŠ‚ïžš%3。 错čŊŊ: %4</translation> </message> </context> <context> <name>QInstaller::ReplaceOperation</name> <message> <source>Cannot open file "%1" for reading: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒčŊŧ取%2</translation> </message> <message> <source>Cannot open file "%1" for writing: %2</source> <translation>无æģ•打垀文äŧķ“%1”čŋ›čĄŒå†™å…Ĩïžš%2</translation> </message> </context> <context> <name>QInstaller::Resource</name> <message> <source>Cannot open resource %1 for reading.</source> <translation>无æģ•打垀čĩ„暐 %1 čŋ›čĄŒčŊŧ取。</translation> </message> <message> <source>Read failed after %1 bytes: %2</source> <translation>%1 å­—čŠ‚åŽčŊŧ取åĪąčīĨïžš%2</translation> </message> <message> <source>Write failed after %1 bytes: %2</source> <translation>%1 å­—čŠ‚åŽįž–å†™åĪąčīĨïžš%2</translation> </message> </context> <context> <name>QInstaller::RestartPage</name> <message> <source>Completing the %1 Setup Wizard</source> <translation>æ­ĢåœĻåŪŒæˆ %1 åŪ‰č̅向åŊž</translation> </message> </context> <context> <name>QInstaller::ScriptEngine</name> <message> <source>Cannot open script file at %1: %2</source> <translation>无æģ•åœĻ %1 åĪ„æ‰“åž€č„šæœŽæ–‡äŧķïžš%2</translation> </message> <message> <source>Exception while loading the component script "%1": %2</source> <translation>åŠ č――įŧ„äŧķč„šæœŽâ€œ%1”æ—ķå‡šįŽ°åž‚åļļïžš%2</translation> </message> <message> <source>Unknown error.</source> <translation>朊įŸĨ错čŊŊ。</translation> </message> <message> <source>on line number: </source> <translation>åœĻįšŋå·į ïžš </translation> </message> </context> <context> <name>QInstaller::SelfRestartOperation</name> <message> <source>Installer object needed in operation %1 is empty.</source> <translation>æ“ä―œ %1 äļ­æ‰€éœ€įš„åŪ‰čĢ…įĻ‹åšåŊđ蹥äļšįĐšã€‚</translation> </message> <message> <source>Self Restart: Only valid within updater or packagemanager mode.</source> <translation>臩åŠĻ重åŊïžšäŧ…åœĻæ›ī新įĻ‹åšæˆ–åŒ…įŪĄį†å™ĻæĻĄåžäœ‰æ•ˆã€‚</translation> </message> <message> <source>Self Restart: Invalid arguments</source> <translation>臩åŠĻ重åŊïžšæ— æ•ˆįš„å‚æ•°</translation> </message> </context> <context> <name>QInstaller::ServerAuthenticationDialog</name> <message> <source>Server Requires Authentication</source> <translation>æœåŠĄå™Ļ需č́čŋ›čĄŒčšŦäŧ―驌čŊ</translation> </message> <message> <source>You need to supply a username and password to access this site.</source> <translation>æ‚Ļ需čĶæäū›į”Ļ户名和åŊ†į æĨčŪŋé—Ūæ­ĪįŦ™į‚đ。</translation> </message> <message> <source>Username:</source> <translation>į”Ļ户名</translation> </message> <message> <source>Password:</source> <translation>åŊ†į ïžš</translation> </message> <message> <source>%1 at %2</source> <translation>%1%2</translation> </message> </context> <context> <name>QInstaller::SettingsOperation</name> <message> <source>Missing argument(s) "%1" calling %2 with arguments "%3".</source> <translation>ä―ŋį”Ļ参数“%3”调į”Ļ %2 æ—ķįžšå°‘å‚æ•°â€œ%1”。</translation> </message> <message> <source>Current method argument calling "%1" with arguments "%2" is not supported. Please use set, remove, add_array_value or remove_array_value.</source> <translation>ä―ŋį”Ļ参数“%2”调į”Ļ“%1â€įš„å―“å‰æ–đæģ•参数äļå—æ”Ŋ持。 čŊ·ä―ŋį”Ļ set、remove、add_array_value 或 remove_array_value。</translation> </message> </context> <context> <name>QInstaller::SimpleMoveFileOperation</name> <message> <source>None of the arguments can be empty: source "%1", target "%2".</source> <translation>所有参数均äļåū—äļšįĐšïžšæšâ€œ%1”į›Ū标“%2”。</translation> </message> <message> <source>Cannot move file from "%1" to "%2", because the target path exists and is not removable.</source> <translation>无æģ•将文äŧķäŧŽâ€œ%1”į§ŧåŠĻ到“%2”因äļšį›Ū标č·Ŋåū„å­˜åœĻä— æģ•į§ŧé™Ī。</translation> </message> <message> <source>Cannot move file "%1" to "%2": %3</source> <translation>无æģ•将文äŧķ“%1”į§ŧåŠĻ到“%2”%3</translation> </message> <message> <source>Moving file "%1" to "%2".</source> <translation>æ­ĢåœĻ将文äŧķ“%1”į§ŧåŠĻ到“%2”。</translation> </message> </context> <context> <name>QInstaller::StartMenuDirectoryPage</name> <message> <source>Start Menu shortcuts</source> <translation>åž€å§‹čœå•åŋŦ捷æ–đ垏</translation> </message> <message> <source>Select the Start Menu in which you would like to create the program's shortcuts. You can also enter a name to create a new directory.</source> <translation>选æ‹Đæ‚Ļč́åœĻå…ķäļ­åˆ›åŧšįĻ‹åšåŋŦ捷æ–đåžįš„â€œåž€å§‹â€čœå•ã€‚ æ‚Ļčŋ˜åŊäŧĨčū“å…Ĩåį§°äŧĨ创åŧšæ–°į›Ūå―•ã€‚</translation> </message> </context> <context> <name>QInstaller::TargetDirectoryPage</name> <message> <source>Installation Folder</source> <translation>åŪ‰čĢ…æ–‡äŧķåĪđ</translation> </message> <message> <source>Please specify the directory where %1 will be installed.</source> <translation>čŊ·æŒ‡åŪšå°†åŪ‰čĢ… %1 įš„į›Ūå―•ã€‚</translation> </message> <message> <source>Alt+R</source> <comment>browse file system to choose a file</comment> <translation>Alt+R</translation> </message> <message> <source>B&rowse...</source> <translation>æĩč§ˆ(&R)...</translation> </message> <message> <source>The directory you selected already exists and contains an installation. Choose a different target for installation.</source> <translation>æ‚Ļ选æ‹Đįš„į›Ūå―•å·ē存åœĻäļ”包åŦåŪ‰čĢ…įĻ‹åšã€‚ 选æ‹Đå…ķäŧ–į›Ū标čŋ›čĄŒåŪ‰čĢ…ã€‚</translation> </message> <message> <source>You have selected an existing, non-empty directory for installation. Note that it will be completely wiped on uninstallation of this application. It is not advisable to install into this directory as installation might fail. Do you want to continue?</source> <translation>æ‚Ļå·ē选æ‹ĐįŽ°æœ‰éžįĐšį›Ūå―•čŋ›čĄŒåŪ‰čĢ…ã€‚ čŊ·æģĻæ„ïžŒåœĻåļč――æ­Īåš”į”ĻįĻ‹åšæ—ķ将åیå…Ļ删é™ĪčŊĨį›Ūå―•ã€‚ äļåŧščŪŪåŪ‰čĢ…åˆ°æ­Īį›Ūå―•äļ­ïžŒå› äļšåŪ‰čĢ…åŊčƒ―äžšåĪąčīĨ。 æ˜ŊåĶč́įŧ§įŧ­?</translation> </message> <message> <source>You have selected an existing file or symlink, please choose a different target for installation.</source> <translation>æ‚Ļ选æ‹Đįš„æ˜ŊįŽ°æœ‰æ–‡äŧķæˆ–įŽĶ号čŋžæŽĨčŊ·é€‰æ‹Đå…ķäŧ–į›Ū标čŋ›čĄŒåŪ‰čĢ…ã€‚</translation> </message> <message> <source>Select Installation Folder</source> <translation>选æ‹ĐåŪ‰čĢ…æ–‡äŧķåĪđ</translation> </message> <message> <source>The installation path cannot be empty, please specify a valid directory.</source> <translation>åŪ‰čĢ…č·Ŋåū„äļåū—äļšįĐšïžŒčŊ·æŒ‡åŪšæœ‰æ•ˆį›Ūå―•ã€‚</translation> </message> <message> <source>The installation path cannot be relative, please specify an absolute path.</source> <translation>åŪ‰čĢ…č·Ŋåū„äļåū—äļšį›ļåŊđč·Ŋåū„čŊ·æŒ‡åۚäļ€äļŠįŧåŊđč·Ŋåū„。</translation> </message> <message> <source>The path or installation directory contains non ASCII characters. This is currently not supported! Please choose a different path or installation directory.</source> <translation>č·Ŋåū„或åŪ‰čĢ…į›Ūå―•åŒ…åŦ非 ASCII 字įŽĶ。 į›Ū前尚äļæ”Ŋ持æ­Ī内åŪđ! čŊ·é€‰æ‹ĐäļåŒįš„č·Ŋåū„或åŪ‰čĢ…į›Ūå―•ã€‚</translation> </message> <message> <source>As the install directory is completely deleted, installing in %1 is forbidden.</source> <translation>į”ąäšŽåŪ‰čĢ…č·Ŋåū„å·ēčĒŦåیå…Ļ删é™Ī因æ­Ī无æģ•åœĻ %1 äļ­åŪ‰čĢ…ã€‚</translation> </message> <message> <source>The path you have entered is too long, please make sure to specify a valid path.</source> <translation>čū“å…Ĩįš„č·Ŋåū„čŋ‡é•ŋčŊ·įĄŪäŋæŒ‡åŪšįš„č·Ŋåū„有效。</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid target.</source> <translation>čū“å…Ĩįš„č·Ŋåū„无效čŊ·įĄŪäŋæŒ‡åŪšįš„į›Ū标有效。</translation> </message> <message> <source>The path you have entered is not valid, please make sure to specify a valid drive.</source> <translation>čū“å…Ĩįš„č·Ŋåū„无效čŊ·įĄŪäŋæŒ‡åŪšįš„éĐąåŠĻå™Ļ有效。</translation> </message> <message> <source>The installation path must not end with '.', please specify a valid directory.</source> <translation>åŪ‰čĢ…č·Ŋåū„äļåū—äŧĨ“.”įŧ“å°ūčŊ·æŒ‡åۚäļ€äļŠæœ‰æ•ˆįš„į›Ūå―•ã€‚</translation> </message> <message> <source>The installation path must not contain "%1", please specify a valid directory.</source> <translation>åŪ‰čĢ…č·Ŋåū„äļåū—包åŦ“%1”čŊ·æŒ‡åۚäļ€äļŠæœ‰æ•ˆįš„į›Ūå―•ã€‚</translation> </message> <message> <source>Warning</source> <translation>č­Ķ告</translation> </message> <message> <source>Error</source> <translation>错čŊŊ</translation> </message> </context> <context> <name>QInstaller::TestRepository</name> <message> <source>Missing package manager core engine.</source> <translation>įžšå°‘åŒ…įŪĄį†å™Ļæ ļåŋƒåž•擎。</translation> </message> <message> <source>Empty repository URL.</source> <translation>įĐščĩ„æ–™æĄĢæĄˆåš“ URL。</translation> </message> <message> <source>Download canceled.</source> <translation>äļ‹č――å·ē取æķˆã€‚</translation> </message> <message> <source>Timeout while testing repository "%1".</source> <translation>æĩ‹čŊ•čĩ„æ–™æĄĢæĄˆåš“â€œ%1”æ—ķčķ…æ—ķ。</translation> </message> <message> <source>Cannot parse Updates.xml: %1</source> <translation>无æģ•č§Ģ析 Updates.xmlïžš%1</translation> </message> <message> <source>Cannot open Updates.xml for reading: %1</source> <translation>无æģ•打垀 Updates.xml čŋ›čĄŒčŊŧ取%1</translation> </message> <message> <source>Authentication failed.</source> <translation>驌čŊåĪąčīĨ。</translation> </message> <message> <source>Unknown error while testing repository "%1".</source> <translation>æĩ‹čŊ•čĩ„æ–™æĄĢæĄˆåš“â€œ%1”æ—ķå‡šįŽ°æœŠįŸĨ错čŊŊ。</translation> </message> </context> <context> <name>QObject</name> <message> <source>Authorization required</source> <translation>需čĶæŽˆæƒ</translation> </message> <message> <source>Enter your password to authorize for sudo:</source> <translation>čū“å…Ĩæ‚Ļįš„åŊ†į äļš sudo 授权</translation> </message> <message> <source>Error acquiring admin rights</source> <translation>čŽ·å–įŪĄį†å‘˜æƒé™æ—ķ凚错</translation> </message> </context> <context> <name>RemoteClient</name> <message> <source>Cannot get authorization.</source> <translation>无æģ•čŽ·å–æŽˆæƒã€‚</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Please start the setup program as a user with the appropriate rights. Or accept the elevation of access rights if being asked.</source> <translation>无æģ•获åū—įŧ§įŧ­åŪ‰čĢ…æ‰€éœ€įš„æŽˆæƒã€‚ čŊ·äŧĨå…·æœ‰é€‚å―“æƒé™įš„į”Ļ户čšŦäŧ―åŊåŠĻåŪ‰čĢ…įĻ‹åšã€‚ æˆ–č€…åœĻčĒŦčŊĒé—Ūæ—ķæŽĨ受čŪŋé—Ūæƒé™įš„æå‡ã€‚</translation> </message> <message> <source>Cannot get authorization that is needed for continuing the installation. Either abort the installation or use the fallback solution by running %1 as a user with the appropriate rights and then clicking OK.</source> <translation>无æģ•获åū—įŧ§įŧ­åŪ‰čĢ…æ‰€éœ€įš„æŽˆæƒã€‚ čŊ·äļ­æ­ĒåŪ‰čĢ…æˆ–é€ščŋ‡čŋčĄŒ %1 äŧĨå…·æœ‰é€‚å―“æƒé™įš„į”Ļ户čšŦäŧ―ä―ŋį”Ļ回退č§Ģå†ģæ–đæĄˆïžŒį„ķ后按“įĄŪåŪšâ€ã€‚</translation> </message> </context> <context> <name>ResourceCollectionManager</name> <message> <source>Cannot open resource %1: %2</source> <translation>无æģ•打垀čĩ„暐 %1ïžš%2</translation> </message> </context> <context> <name>Settings</name> <message> <source>Cannot open settings file %1 for reading: %2</source> <translation>无æģ•打垀čŪūį―Ūæ–‡äŧķ %1 čŋ›čĄŒčŊŧ取%2</translation> </message> </context> <context> <name>SettingsDialog</name> <message> <source>Settings</source> <translation>čŪūį―Ū</translation> </message> <message> <source>Network</source> <translation>į―‘įŧœ</translation> </message> <message> <source>No proxy</source> <translation>无äŧĢᐆ</translation> </message> <message> <source>System proxy settings</source> <translation>įģŧįŧŸäŧĢᐆčŪūį―Ū</translation> </message> <message> <source>Manual proxy configuration</source> <translation>手åŠĻäŧĢį†é…į―Ū</translation> </message> <message> <source>HTTP proxy:</source> <translation>HTTP äŧĢį†ïžš</translation> </message> <message> <source>Port:</source> <translation>įŦŊåĢïžš</translation> </message> <message> <source>FTP proxy:</source> <translation>FTP äŧĢį†ïžš</translation> </message> <message> <source>Repositories</source> <translation>čĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>Add Username and Password for authentication if needed.</source> <translation>åĶ‚æœ‰åŋ…čĶïžŒčŊ·æ·ŧ加į”Ļ户名和åŊ†į čŋ›čĄŒčšŦäŧ―驌čŊã€‚</translation> </message> <message> <source>Use temporary repositories only</source> <translation>äŧ…ä―ŋį”Ļäļīæ—ķčĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>Add</source> <translation>æ·ŧ加</translation> </message> <message> <source>Remove</source> <translation>į§ŧé™Ī</translation> </message> <message> <source>Test</source> <translation>æĄäŧķæĩ‹čŊ•</translation> </message> <message> <source>Show Passwords</source> <translation>æ˜ūįĪšåŊ†į </translation> </message> <message> <source>Check this to use repository during fetch.</source> <translation>驌čŊæ­Ī内åŪđäŧĨåœĻčŽ·å–æœŸé—īä―ŋį”Ļčĩ„æ–™æĄĢæĄˆåš“ã€‚</translation> </message> <message> <source>Add the username to authenticate on the server.</source> <translation>æ·ŧ加į”Ļ户名äŧĨåœĻæœåŠĄå™ĻįŦŊčŋ›čĄŒčšŦäŧ―驌čŊã€‚</translation> </message> <message> <source>Add the password to authenticate on the server.</source> <translation>æ·ŧ加åŊ†į äŧĨåœĻæœåŠĄå™ĻįŦŊčŋ›čĄŒčšŦäŧ―驌čŊã€‚</translation> </message> <message> <source>The servers URL that contains a valid repository.</source> <translation>æœåŠĄå™Ļ URL 包åŦæœ‰æ•ˆįš„čĩ„æ–™æĄĢæĄˆåš“ã€‚</translation> </message> <message> <source>An error occurred while testing this repository.</source> <translation>æĩ‹čŊ•æ­Īčĩ„æ–™æĄĢæĄˆåš“æ—ķ凚错。</translation> </message> <message> <source>The repository was tested successfully.</source> <translation>čĩ„æ–™æĄĢæĄˆåš“æĩ‹čŊ•成功。</translation> </message> <message> <source>Do you want to disable the repository?</source> <translation>æ˜ŊåĶč́į́į”Ļčĩ„æ–™æĄĢæĄˆåš“?</translation> </message> <message> <source>Do you want to enable the repository?</source> <translation>æ˜ŊåĶč́åŊį”Ļčĩ„æ–™æĄĢæĄˆåš“?</translation> </message> <message> <source>Hide Passwords</source> <translation>隐藏åŊ†į </translation> </message> <message> <source>Use</source> <translation>ä―ŋį”Ļ</translation> </message> <message> <source>Username</source> <translation>į”Ļ户名</translation> </message> <message> <source>Password</source> <translation>åŊ†į </translation> </message> <message> <source>Repository</source> <translation>čĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>Default repositories</source> <translation>éŧ˜čŪĪčĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>Temporary repositories</source> <translation>äļīæ—ķčĩ„æ–™æĄĢæĄˆåš“</translation> </message> <message> <source>User defined repositories</source> <translation>į”Ļ户åۚäđ‰įš„čĩ„æ–™æĄĢæĄˆåš“</translation> </message> </context> <context> <name>UpdateOperation</name> <message> <source>Cannot write to registry path %1.</source> <translation>无æģ•写å…ĨæģĻ册čĄĻč·Ŋåū„ %1。</translation> </message> <message> <source>Registry path %1 is not writable.</source> <translation>æģĻ册čĄĻč·Ŋåū„ %1 äļåŊ写å…Ĩ。</translation> </message> <message> <source>exactly %1</source> <translation>æ­ĢåĨ― %1</translation> </message> <message> <source>at least %1</source> <translation>č‡ģ少 %1</translation> </message> <message> <source>not more than %1</source> <translation>äļčķ…čŋ‡ %1</translation> </message> <message> <source>%1 or %2</source> <translation>%1 或 %2</translation> </message> <message> <source>%1 to %2</source> <translation>%1 č‡ģ %2</translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected.</source> <translation> <numerusform>%1 äļ­įš„参数无效įŧ™åۚ %n äļŠå‚数期望 %2 äļŠå‚数。</numerusform> </translation> </message> <message numerus="yes"> <source>Invalid arguments in %1: %n arguments given, %2 arguments expected in the form: %3.</source> <translation> <numerusform>%1 äļ­įš„参数无效įŧ™åۚ %n äļŠå‚数čĄĻæ žäļ­éĒ„æœŸįš„ %2 äļŠå‚æ•°ïžš%3。</numerusform> </translation> </message> <message> <source>Renaming file "%1" to "%2" failed: %3</source> <translation>将文äŧķ“%1â€é‡å‘―åäļšâ€œ%2”åĪąčīĨïžš%3</translation> </message> </context> </TS> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/README��������������������������������������������0100777�0000000�0000000�00000001251�13761647206�020050� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������You need to have a Qt translation for your new language, otherwise your language won't be loaded at runtime. To add a new language: 1) Run 'cd src/sdk/translations' (change to the parent directory of this file) 2) Run 'make ts-untranslated' 3) Rename ifw_untranslated.ts to ifw_<lang>.ts 4) Run 'make qmake' 5) Do your translation. Just run 'make' whenever you want to test it. 6) Run 'make commit-ts' 7) Submit the translation for review To update an existing translation, just run 'make ts-<lang>' instead of steps 2) to 4). More information is available at https://wiki.qt.io/Qt_Localization - these instructions apply here equally, except for the different directory names. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/src/sdk/translations/translations.pro����������������������������������0100777�0000000�0000000�00000002671�13761647206�022442� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = aux include(../../../installerfw.pri) !exists($$LUPDATE): return() IB_TRANSLATIONS = $$files($$PWD/*_??.ts) IB_TRANSLATIONS -= $$PWD/ifw_en.ts wd = $$toNativeSeparators($$IFW_SOURCE_TREE) sources = src lupdate_opts = -locations relative -no-ui-lines -no-sort IB_ALL_TRANSLATIONS = $$IB_TRANSLATIONS $$PWD/ifw_untranslated.ts for(file, IB_ALL_TRANSLATIONS) { lang = $$replace(file, .*_([^/]*)\\.ts, \\1) v = ts-$${lang}.commands $$v = cd $$wd && $$LUPDATE $$lupdate_opts $$sources -ts $$file QMAKE_EXTRA_TARGETS += ts-$$lang } ts-all.commands = cd $$wd && $$LUPDATE $$lupdate_opts $$sources -ts $$IB_ALL_TRANSLATIONS QMAKE_EXTRA_TARGETS += ts-all lconvert_options = -sort-contexts -locations none -i isEqual(QMAKE_DIR_SEP, /) { commit-ts.commands = \ cd $$wd; \ git add -N src/sdk/translations/*_??.ts && \ for f in `git diff-files --name-only src/sdk/translations/*_??.ts`; do \ $$LCONVERT $$lconvert_options \$\$f -o \$\$f; \ done; \ git add src/sdk/translations/*_??.ts && git commit } else { commit-ts.commands = \ cd $$wd && \ git add -N src/sdk/translations/*_??.ts && \ for /f usebackq %%f in (`git diff-files --name-only src/sdk/translations/*_??.ts`) do \ $$LCONVERT $$lconvert_options %%f -o %%f $$escape_expand(\\n\\t) \ cd $$wd && git add src/sdk/translations/*_??.ts && git commit } QMAKE_EXTRA_TARGETS += commit-ts �����������������������������������������������������������������������qt-installer-framework-4.0.1/src/src.pro������������������������������������������������������������0100777�0000000�0000000�00000000113�13761647206�015173� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = subdirs SUBDIRS += libs sdk sdk/translations sdk.depends = libs �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/sync.profile�����������������������������������������������������������0100777�0000000�0000000�00000000202�13761647206�015430� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%dependencies = ( "qtbase" => "", "qtdeclarative" => "", "qttools" => "", "qtwinextras" => "", ); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/�����������������������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�014242� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/������������������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�015212� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/auto.pro����������������������������������������������������0100777�0000000�0000000�00000000073�13761647206�016704� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TEMPLATE = subdirs SUBDIRS += \ installer \ tools ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/��������������������������������������������������0040777�0000000�0000000�00000000000�13761647206�017207� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/������������������������������0040777�0000000�0000000�00000000000�13761647206�023237� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/appendfileoperation.pro�������0100777�0000000�0000000�00000000227�13761647206�030012� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_appendfileoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/�������������������������0040777�0000000�0000000�00000000000�13761647206�024150� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/��������������0040777�0000000�0000000�00000000000�13761647206�026367� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/A/������������0040777�0000000�0000000�00000000000�13761647206�026547� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������././@LongLink���������������������������������������������������������������������������������������0100777�0000000�0000000�00000000152�13761647206�010114� L����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/A/1.0.2-1content.7z�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/A/1.0.2-1cont�0100777�0000000�0000000�00000000234�13761647206�030151� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7zžŊ'�čĸÅ��������b�������wwîU� œ,ĘnA+ ŧïyއOü|Ąĸĸ=Ø��� � �#]��€� �  <*1�� �A�.�t�x�t��� �jJį(° Ö �jJį(° Ö �jJį(° Ö� €ī����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������././@LongLink���������������������������������������������������������������������������������������0100777�0000000�0000000�00000000147�13761647206�010120� L����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/A/1.0.2-1meta.7z��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/A/1.0.2-1meta�0100777�0000000�0000000�00000001566�13761647206�030145� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7zžŊ'�aœ•84������"�������įaāæ·]�Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQr<h†+ņ›7§i!*WpËq—ŽNšųr4/t*nŊ@n—žB}œ“œ øDÕ@2īŒšôũđČ/%°ĩú‡l&0Åyb=!*…į(ô”œ:þ…#ŨünžÓ-Ãī2Šž'œŨínĀŅ,Z85aŌ2T qâ‚ŋS)eÛ―&Mcáė7ߋüÄ œLbč™ĻkjhEsþ˜tKŃæw'mŨ‡î,Ý(AGä7ĄŊŽÃë>Ėī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪĒæ�ōÍą9Ņkvߨ ëŦÍðâ†ÏŪÃëĐ9Č}2ÖĢ 4ĨŊû‚Ģ]ÆWĩ`šxÅZ(ï����3ŪÕG ÔŨ$Óþģp@hEF‹Ãˆ]æËÜk9ĩpŨ}Ņøt6ž" RķcŲô["SJ.iú\“‚(’ūÝ0}6Iþ·Ųĸ€ ?RR2ðt‡: ũÝ1GDoËhüŽÚtOæNĪ“š1Ī„}5Ķ˜y���‚ŋ u� �#]��� €ž û.~��������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/data/repository/Updates.xml���0100777�0000000�0000000�00000000664�13761647206�030524� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<Updates> <ApplicationName>{AnyApplication}</ApplicationName> <ApplicationVersion>1.0.0</ApplicationVersion> <PackageUpdate> <Name>A</Name> <DisplayName>A</DisplayName> <Description>Example component A</Description> <Version>1.0.2-1</Version> <ReleaseDate>2015-01-01</ReleaseDate> <Default>true</Default> <Script>script.qs</Script> <DownloadableArchives>content.7z</DownloadableArchives> </PackageUpdate> </Updates> ����������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/settings.qrc������������������0100777�0000000�0000000�00000000331�13761647206�025603� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<RCC> <qresource prefix="/"> <file>data/repository/Updates.xml</file> <file>data/repository/A/1.0.2-1content.7z</file> <file>data/repository/A/1.0.2-1meta.7z</file> </qresource> </RCC> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp���0100777�0000000�0000000�00000012014�13761647206�030663� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include <updateoperations.h> #include <packagemanagercore.h> #include <QFile> #include <QTest> using namespace KDUpdater; using namespace QInstaller; class tst_appendfileoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_testFilePath = qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); } void testMissingArguments() { AppendFileOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in AppendFile: " "0 arguments given, exactly 2 arguments expected.")); op.setArguments(QStringList() << "" << ""); QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified"); QTest::ignoreMessage(QtWarningMsg, "QFile::rename: Empty or null file name"); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("Cannot open file \"\" for writing: No file name specified")); } void testAppendText_data() { QTest::addColumn<QString>("source"); QTest::addColumn<QString>("append"); QTest::addColumn<QString>("expected"); QTest::newRow("newline") << "Line1\nLine2\nLine3\n" << "AppendedText" << "Line1\nLine2\nLine3\nAppendedText"; QTest::newRow("no newline") << "Lorem ipsum " << "dolore sit amet" << "Lorem ipsum dolore sit amet"; } void testAppendText() { QFETCH(QString, source); QFETCH(QString, append); QFETCH(QString, expected); QFile file(m_testFilePath); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream stream(&file); stream << source << flush; file.close(); AppendFileOperation op; op.setArguments(QStringList() << m_testFilePath << append); op.backup(); QVERIFY(QFileInfo(op.value("backupOfFile").toString()).exists()); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QCOMPARE(stream.readAll(), expected); file.close(); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QCOMPARE(stream.readAll(), source); file.close(); QVERIFY(file.remove()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); QFile file(installDir + QDir::separator() + "A.txt"); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QTextStream stream(&file); QCOMPARE(stream.readAll(), QLatin1String("Appended text: lorem ipsum")); file.close(); core->setPackageManager(); core->commitSessionOperations(); // We cannot check the file contents here as it will be deleted on // undo Extract, but at least check that the uninstallation succeeds. QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently (QStringList()<< "A")); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_testFilePath; }; QTEST_MAIN(tst_appendfileoperation) #include "tst_appendfileoperation.moc" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/binaryformat/�������������������������������������0040777�0000000�0000000�00000000000�13761647206�021704� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/binaryformat/binaryformat.pro���������������������0100777�0000000�0000000�00000000120�13761647206�025114� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../qttest.pri) QT -= gui QT += xml SOURCES += tst_binaryformat.cpp ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/binaryformat/tst_binaryformat.cpp�����������������0100777�0000000�0000000�00000037710�13761647206�026007� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include <binarycontent.h> #include <binaryformat.h> #include <errors.h> #include <fileio.h> #include <updateoperation.h> #include <QTest> #include <QTemporaryFile> static const qint64 scTinySize = 72704LL; static const qint64 scSmallSize = 524288LL; static const qint64 scLargeSize = 2097152LL; using namespace QInstaller; struct Layout : public QInstaller::BinaryLayout { qint64 metaSegmentsCount; qint64 operationsCount; qint64 collectionCount; }; class TestOperation : public KDUpdater::UpdateOperation { public: TestOperation(const QString &name) : KDUpdater::UpdateOperation(nullptr) { setName(name); } virtual void backup() {} virtual bool performOperation() { return true; } virtual bool undoOperation() { return true; } virtual bool testOperation() { return true; } virtual KDUpdater::UpdateOperation *clone() const { return 0; } }; class tst_BinaryFormat : public QObject { Q_OBJECT private slots: void initTestCase() { TestOperation op(QLatin1String("Operation 1")); op.setValue(QLatin1String("key"), QLatin1String("Operation 1 value.")); op.setArguments(QStringList() << QLatin1String("arg1") << QLatin1String("arg2")); m_operations.append(OperationBlob(op.name(), op.toXml().toString())); op = TestOperation(QLatin1String("Operation 2")); op.setValue(QLatin1String("key"), QLatin1String("Operation 2 value.")); op.setArguments(QStringList() << QLatin1String("arg1") << QLatin1String("arg2")); m_operations.append(OperationBlob(op.name(), op.toXml().toString())); } void findMagicCookieSmallFile() { QTemporaryFile file; file.open(); try { QInstaller::blockingWrite(&file, QByteArray(scSmallSize, '1')); QInstaller::appendInt64(&file, QInstaller::BinaryContent::MagicCookie); QCOMPARE(QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie), scSmallSize); } catch (const QInstaller::Error &error) { QFAIL(qPrintable(error.message())); } catch (...) { QFAIL("Unexpected error."); } } void findMagicCookieLargeFile() { QTemporaryFile file; file.open(); try { QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1')); QInstaller::appendInt64(&file, QInstaller::BinaryContent::MagicCookie); QInstaller::blockingWrite(&file, QByteArray(scTinySize, '2')); QCOMPARE(QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie), scLargeSize); } catch (const QInstaller::Error &error) { QFAIL(qPrintable(error.message())); } catch (...) { QFAIL("Unexpected error."); } } void findMagicCookieWithError() { QTemporaryFile file; file.open(); try { QInstaller::blockingWrite(&file, QByteArray(scTinySize, '1')); // throws QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie); } catch (const QInstaller::Error &error) { QCOMPARE(qPrintable(error.message()), "No marker found, stopped after 71.00 KB."); } catch (...) { QFAIL("Unexpected error."); } } void writeBinaryContent() { QTemporaryFile binary; QInstaller::openForWrite(&binary); QInstaller::blockingWrite(&binary, QByteArray(scTinySize, '1')); Layout layout; layout.endOfExectuable = binary.pos(); layout.magicMarker = BinaryContent::MagicInstallerMarker; layout.magicCookie = BinaryContent::MagicCookie; qint64 start = binary.pos(); // write default resource (fake) QInstaller::blockingWrite(&binary, QByteArray("Default resource data.")); qint64 end = binary.pos(); layout.metaResourceSegments.append(Range<qint64>::fromStartAndEnd(start, end)); start = end; // // write additional resource (fake) QInstaller::blockingWrite(&binary, QByteArray("Additional resource data.")); end = binary.pos(); layout.metaResourceSegments.append(Range<qint64>::fromStartAndEnd(start, end)); layout.metaResourcesSegment = Range<qint64>::fromStartAndEnd(layout.metaResourceSegments .first().start(), layout.metaResourceSegments.last().end()); layout.metaSegmentsCount = layout.metaResourceSegments.count(); start = end; layout.operationsCount = m_operations.count(); QInstaller::appendInt64(&binary, layout.operationsCount); foreach (const OperationBlob &operation, m_operations) { QInstaller::appendString(&binary, operation.name); QInstaller::appendString(&binary, operation.xml); } QInstaller::appendInt64(&binary, layout.operationsCount); end = binary.pos(); layout.operationsSegment = Range<qint64>::fromStartAndEnd(start, end); QTemporaryFile data; QInstaller::openForWrite(&data); QInstaller::blockingWrite(&data, QByteArray("Collection 1, Resource 1.")); data.close(); QSharedPointer<Resource> resource(new Resource(data.fileName(), QByteArray("Resource 1"))); ResourceCollection collection(QByteArray("Collection 1")); collection.appendResource(resource); QTemporaryFile data2; QInstaller::openForWrite(&data2); QInstaller::blockingWrite(&data2, QByteArray("Collection 2, Resource 2.")); data2.close(); QSharedPointer<Resource> resource2(new Resource(data2.fileName(), QByteArray("Resource 2"))); ResourceCollection collection2(QByteArray("Collection 2")); collection2.appendResource(resource2); ResourceCollectionManager manager; manager.insertCollection(collection); manager.insertCollection(collection2); layout.collectionCount = manager.collectionCount(); layout.resourceCollectionsSegment = manager.write(&binary, -layout.endOfExectuable); QInstaller::appendInt64Range(&binary, layout.resourceCollectionsSegment.moved(-layout .endOfExectuable)); foreach (const Range<qint64> &segment, layout.metaResourceSegments) QInstaller::appendInt64Range(&binary, segment.moved(-layout.endOfExectuable)); QInstaller::appendInt64Range(&binary, layout.operationsSegment.moved(-layout .endOfExectuable)); QInstaller::appendInt64(&binary, layout.metaSegmentsCount); layout.binaryContentSize = (binary.pos() + (3 * sizeof(qint64))) - layout.endOfExectuable; QInstaller::appendInt64(&binary, layout.binaryContentSize); QInstaller::appendInt64(&binary, layout.magicMarker); QInstaller::appendInt64(&binary, layout.magicCookie); layout.endOfBinaryContent = binary.pos(); binary.close(); binary.setAutoRemove(false); m_layout = layout; m_binary = binary.fileName(); } void readBinaryContent() { QFile binary(m_binary); QInstaller::openForRead(&binary); QCOMPARE(QInstaller::retrieveData(&binary, scTinySize), QByteArray(scTinySize, '1')); Layout layout; layout.endOfExectuable = binary.pos(); QCOMPARE(layout.endOfExectuable, m_layout.endOfExectuable); const qint64 pos = BinaryContent::findMagicCookie(&binary, BinaryContent::MagicCookie); layout.endOfBinaryContent = pos + sizeof(qint64); QCOMPARE(layout.endOfBinaryContent, m_layout.endOfBinaryContent); binary.seek(layout.endOfBinaryContent - (4 * sizeof(qint64))); layout.metaSegmentsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.metaSegmentsCount, m_layout.metaSegmentsCount); const qint64 offsetCollectionIndexSegments = layout.endOfBinaryContent - ((layout.metaSegmentsCount * (2 * sizeof(qint64))) // minus size of the meta segments + (8 * sizeof(qint64))); // meta count, offset/length collection index, marker, cookie... binary.seek(offsetCollectionIndexSegments); layout.resourceCollectionsSegment = QInstaller::retrieveInt64Range(&binary) .moved(layout.endOfExectuable); QCOMPARE(layout.resourceCollectionsSegment, m_layout.resourceCollectionsSegment); for (int i = 0; i < layout.metaSegmentsCount; ++i) { layout.metaResourceSegments.append(QInstaller::retrieveInt64Range(&binary) .moved(layout.endOfExectuable)); } layout.metaResourcesSegment = Range<qint64>::fromStartAndEnd(layout.metaResourceSegments .first().start(), layout.metaResourceSegments.last().end()); QCOMPARE(layout.metaResourcesSegment, m_layout.metaResourcesSegment); QCOMPARE(layout.metaResourceSegments.first(), m_layout.metaResourceSegments.first()); QCOMPARE(layout.metaResourceSegments.last(), m_layout.metaResourceSegments.last()); layout.operationsSegment = QInstaller::retrieveInt64Range(&binary).moved(layout .endOfExectuable); QCOMPARE(layout.operationsSegment, m_layout.operationsSegment); QCOMPARE(layout.metaSegmentsCount, QInstaller::retrieveInt64(&binary)); layout.binaryContentSize = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.binaryContentSize, m_layout.binaryContentSize); QCOMPARE(layout.endOfExectuable, layout.endOfBinaryContent - layout.binaryContentSize); layout.magicMarker = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.magicMarker, m_layout.magicMarker); layout.magicCookie = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.magicCookie, m_layout.magicCookie); binary.seek(layout.operationsSegment.start()); layout.operationsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.operationsCount, m_layout.operationsCount); for (int i = 0; i < layout.operationsCount; ++i) { QCOMPARE(m_operations.at(i).name, QInstaller::retrieveString(&binary)); QCOMPARE(m_operations.at(i).xml, QInstaller::retrieveString(&binary)); } layout.operationsCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.operationsCount, m_layout.operationsCount); layout.collectionCount = QInstaller::retrieveInt64(&binary); QCOMPARE(layout.collectionCount, m_layout.collectionCount); binary.seek(layout.resourceCollectionsSegment.start()); m_manager.read(&binary, layout.endOfExectuable); const QList<ResourceCollection> collections = m_manager.collections(); QCOMPARE(collections.count(), m_layout.collectionCount); ResourceCollection collection = m_manager.collectionByName(QByteArray("Collection 1")); QCOMPARE(collection.resources().count(), 1); QSharedPointer<Resource> resource(collection.resourceByName(QByteArray("Resource 1"))); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 1, Resource 1.")); resource->close(); collection = m_manager.collectionByName(QByteArray("Collection 2")); QCOMPARE(collection.resources().count(), 1); resource = collection.resourceByName(QByteArray("Resource 2")); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 2, Resource 2.")); resource->close(); } void testWriteBinaryContentFunction() { ResourceCollection collection(QByteArray("QResources")); foreach (const Range<qint64> &segment, m_layout.metaResourceSegments) collection.appendResource(QSharedPointer<Resource>(new Resource(m_binary, segment))); m_manager.insertCollection(collection); QList<OperationBlob> operations; foreach (const OperationBlob &operation, m_operations) operations.append(operation); QTemporaryFile file; QInstaller::openForWrite(&file); QInstaller::blockingWrite(&file, QByteArray(scTinySize, '1')); BinaryContent::writeBinaryContent(&file, operations, m_manager, m_layout.magicMarker, m_layout.magicCookie); file.close(); QFile existingBinary(m_binary); QInstaller::openForRead(&existingBinary); QInstaller::openForRead(&file); QCOMPARE(file.readAll(), existingBinary.readAll()); } void testReadBinaryContentFunction() { QFile file(m_binary); QInstaller::openForRead(&file); qint64 magicMarker; QList<OperationBlob> operations; ResourceCollectionManager manager; BinaryContent::readBinaryContent(&file, &operations, &manager, &magicMarker, m_layout.magicCookie); file.close(); QCOMPARE(magicMarker, m_layout.magicMarker); ResourceCollection collection = manager.collectionByName("QResources"); QCOMPARE(collection.resources().count(), m_layout.metaResourceSegments.count()); for (int i = 0; i < collection.resources().count(); ++i) QCOMPARE(collection.resources().at(i)->segment(), m_layout.metaResourceSegments.at(i)); QCOMPARE(operations.count(), m_operations.count()); for (int i = 0; i < operations.count(); ++i) { QCOMPARE(operations.at(i).name, m_operations.at(i).name); QCOMPARE(operations.at(i).xml, m_operations.at(i).xml); } QCOMPARE(manager.collectionCount(), m_manager.collectionCount()); collection = manager.collectionByName(QByteArray("Collection 1")); QCOMPARE(collection.resources().count(), 1); QSharedPointer<Resource> resource(collection.resourceByName(QByteArray("Resource 1"))); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 1, Resource 1.")); resource->close(); collection = manager.collectionByName(QByteArray("Collection 2")); QCOMPARE(collection.resources().count(), 1); resource = collection.resourceByName(QByteArray("Resource 2")); QCOMPARE(resource.isNull(), false); QCOMPARE(resource->isOpen(), false); QCOMPARE(resource->open(), true); QCOMPARE(resource->readAll(), QByteArray("Collection 2, Resource 2.")); resource->close(); } void cleanupTestCase() { m_manager.clear(); QFile::remove(m_binary); } private: Layout m_layout; QString m_binary; QList<OperationBlob> m_operations; ResourceCollectionManager m_manager; }; QTEST_MAIN(tst_BinaryFormat) #include "tst_binaryformat.moc" ��������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/����������������������������������0040777�0000000�0000000�00000000000�13761647206�022405� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/brokeninstaller.pro���������������0100777�0000000�0000000�00000000174�13761647206�026327� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../qttest.pri) QT -= gui QT += network xml qml SOURCES += tst_brokeninstaller.cpp RESOURCES += components.qrc ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/components.qrc��������������������0100777�0000000�0000000�00000000212�13761647206�025274� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<RCC> <qresource prefix="/"> <file>data/updates.xml</file> <file>data/broken_script.qs</file> </qresource> </RCC> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/data/�����������������������������0040777�0000000�0000000�00000000000�13761647206�023316� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/data/broken_script.qs�������������0100777�0000000�0000000�00000002450�13761647206�026530� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { installer.invalidScriptCall() } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/data/updates.xml������������������0100777�0000000�0000000�00000014600�13761647206�025506� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<Updates> <ApplicationName>Your application</ApplicationName> <ApplicationVersion>1.2.3</ApplicationVersion> <Checksum>true</Checksum> <PackageUpdate> <Name>componentinvalidscript</Name> <DisplayName>Invalid script component</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <SortingPriority>1</SortingPriority> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentb</Name> <DisplayName>The second root component</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <SortingPriority>1</SortingPriority> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentc</Name> <DisplayName>The third root component</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <SortingPriority>1</SortingPriority> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentc.subnode</Name> <DisplayName>A subcomponent for the third root, dependency to component with invalid script</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <SortingPriority>1</SortingPriority> <Dependencies>componentinvalidscript</Dependencies> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentc.subnode.sub</Name> <DisplayName>A subcomponent for the third roots subcomponent</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Script>installscript.qs</Script> <Default>true</Default> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentmissingdependency</Name> <DisplayName>A component that has missing sha</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentd</Name> <DisplayName>Component that depends on component which is missing dependency</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Script>installscript.qs</Script> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentmissingcontent</Name> <DisplayName>A component which is missing 7z</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <SortingPriority>0</SortingPriority> <DownloadableArchives>content.7z</DownloadableArchives> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentmissingcontent.sub</Name> <DisplayName>A subcomponent of component which is missing 7z</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Checkable>true</Checkable> <Default>true</Default> <Script>installscript.qs</Script> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> <PackageUpdate> <Name>componentE</Name> <DisplayName>A component which is dependent on subcomponent of missing 7z component</DisplayName> <Description>Install this example.</Description> <Version>0.1.0-1</Version> <ReleaseDate>2010-09-21</ReleaseDate> <Script>installscript.qs</Script> <Checkable>true</Checkable> <Default>true</Default> <Dependencies>componentmissingcontent.sub</Dependencies> <UpdateFile UncompressedSize="61" CompressedSize="61"/> <Licenses> <License name="Beer Public License Agreement" file="license.txt"/> </Licenses> </PackageUpdate> </Updates> ��������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp�����������0100777�0000000�0000000�00000023236�13761647206�027207� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "component.h" #include "componentmodel.h" #include "updatesinfo_p.h" #include "packagemanagercore.h" #include "settings.h" #include <QTest> #include <QtCore/QLocale> #include <QRegularExpression> using namespace KDUpdater; using namespace QInstaller; #define EXPECTED_COUNTS_COMPONENTS_VISIBLE 10 #define EXPECTED_COUNT_ROOT_COMPONENTS 7 #define EXPECTED_COUNT_INVALID_SCRIPT 7 #define EXPECTED_COUNT_MISSING_DEPENDENCY 8 static const char componentInvalidScript[] = "componentinvalidscript"; static const char componentB[] = "componentb"; static const char componentC[] = "componentc"; static const char componentCSubnodeDependsOnInvalidScriptComponent[] = "componentc.subnode"; static const char componentCSubnodeDependsOnInvalidScriptComponentSub[] = "componentc.subnode.sub"; static const char componentMissingDependency[] = "componentmissingdependency"; static const char componentDependsOnMissingDependency[] = "componentd"; static const char componentMissingContent[] = "componentmissingcontent"; static const char componentMissingContentSub[] = "componentmissingcontent.sub"; static const char componentDependsOnMissingContentSub[] = "componentE"; static const QMap<QString, QString> rootComponentDisplayNames = { {"", QLatin1String("The root component")}, {"ru_ru", QString::fromUtf8("КÐūŅ€Ð―ÐĩÐēÐ°Ņ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð°")}, {"de_de", QString::fromUtf8("Wurzel Komponente")} }; using namespace QInstaller; class tst_BrokenInstaller : public QObject { Q_OBJECT public: enum Option { NoFlags = 0x00, VirtualsVisible = 0x01, NoForcedInstallation = 0x02 }; Q_DECLARE_FLAGS(Options, Option); private slots: void initTestCase() { m_checkedComponentsWithBrokenScript << componentB << componentMissingDependency << componentDependsOnMissingDependency << componentMissingContent << componentMissingContentSub << componentDependsOnMissingContentSub; m_uncheckedComponentsWithBrokenScript << componentInvalidScript << componentCSubnodeDependsOnInvalidScriptComponent << componentCSubnodeDependsOnInvalidScriptComponentSub << componentC; m_checkedComponentsWithMissingDependency << componentB << componentMissingContent << componentMissingContentSub << componentDependsOnMissingContentSub << componentInvalidScript << componentCSubnodeDependsOnInvalidScriptComponent << componentCSubnodeDependsOnInvalidScriptComponentSub << componentC; m_uncheckedComponentsWithMissingDependency << componentMissingDependency << componentDependsOnMissingDependency; } void testNameToIndexAndIndexToName() { PackageManagerCore core; QList<Component*> rootComponents = loadComponents(core); ComponentModel *model = new ComponentModel(1, &core); model->setRootComponents(rootComponents); // all names should be resolvable QStringList all; all << m_checkedComponentsWithBrokenScript << m_uncheckedComponentsWithBrokenScript << m_partiallyCheckedComponentsWithBrokenScript; foreach (const QString &name, all) { QVERIFY(model->indexFromComponentName(name).isValid()); QVERIFY(model->componentFromIndex(model->indexFromComponentName(name)) != 0); QCOMPARE(model->componentFromIndex(model->indexFromComponentName(name))->name(), name); } } void testInvalidScript() { PackageManagerCore core; QList<Component*> components = loadComponents(core); core.settings().setAllowUnstableComponents(true); ComponentModel *model = new ComponentModel(1, &core); Component *invalidScriptComponent = core.componentByName("componentinvalidscript"); // Using regexp to ignore the warning message as the message contains // object address which we don't know const QString debugMessage = QString("Exception while loading the component script"); const QRegularExpression re(debugMessage); QTest::ignoreMessage(QtWarningMsg, re); invalidScriptComponent->loadComponentScript(":///data/broken_script.qs"); model->setRootComponents(components); testModelState(model, m_checkedComponentsWithBrokenScript, m_partiallyCheckedComponentsWithBrokenScript, m_uncheckedComponentsWithBrokenScript); } void testMissingDependency() { PackageManagerCore core; QList<Component*> components = loadComponents(core); core.settings().setAllowUnstableComponents(true); ComponentModel *model = new ComponentModel(1, &core); Component *invalidComponent = core.componentByName("componentmissingdependency"); invalidComponent->addDependency("missingcomponent"); Component *componentDependingOnMissingDependency = core.componentByName("componentd"); componentDependingOnMissingDependency->addDependency("componentmissingdependency"); core.componentsToInstallNeedsRecalculation(); model->setRootComponents(components); testModelState(model, m_checkedComponentsWithMissingDependency, m_partiallyCheckedComponentsWithBrokenScript, m_uncheckedComponentsWithMissingDependency); } private: QList<Component*> loadComponents(PackageManagerCore &core) { UpdatesInfo updatesInfo; updatesInfo.setFileName(":///data/updates.xml"); const QList<UpdateInfo> updateInfos = updatesInfo.updatesInfo(); QList <Component*> components; UpdateInfo info; for (int i = 0; i < updateInfos.count(); i++) { info = updateInfos.at(i); Component *component = new Component(&core); // we need at least these to be able to test the model component->setValue("Name", info.data.value("Name").toString()); component->setValue("Virtual", info.data.value("Virtual").toString()); component->setValue("DisplayName", info.data.value("DisplayName").toString()); component->setValue("Checkable", info.data.value("Checkable").toString()); component->setValue("Dependencies", info.data.value("Dependencies").toString()); component->setCheckState(Qt::Checked); QString forced = info.data.value("ForcedInstallation", scFalse).toString().toLower(); if (core.noForceInstallation()) forced = scFalse; component->setValue("ForcedInstallation", forced); if (forced == scTrue) { component->setEnabled(false); component->setCheckable(false); } //If name does not contain dot it is root component qDebug()<<"component name "<<component->name(); if (!component->name().contains('.')) { core.appendRootComponent(component); } else { //Contains dot, is previous components child component components.at(i-1)->appendComponent(component); } components.append(component); } return components; } void testModelState(ComponentModel *model, const QStringList &checked, const QStringList &partially, const QStringList &unchecked) const { QCOMPARE(model->checked().count(), checked.count()); QCOMPARE(model->partially().count(), partially.count()); QCOMPARE(model->unchecked().count(), unchecked.count()); // these components should have checked state foreach (Component *const component, model->checked()) QVERIFY(checked.contains(component->name())); // these components should not have partially checked state foreach (Component *const component, model->partially()) QVERIFY(partially.contains(component->name())); // these components should not have checked state foreach (Component *const component, model->unchecked()) QVERIFY(unchecked.contains(component->name())); } private: QStringList m_checkedComponentsWithBrokenScript; QStringList m_uncheckedComponentsWithBrokenScript; QStringList m_partiallyCheckedComponentsWithBrokenScript; QStringList m_checkedComponentsWithMissingDependency; QStringList m_uncheckedComponentsWithMissingDependency; QStringList m_partiallyCheckedComponentsWithMissingDependency; }; Q_DECLARE_OPERATORS_FOR_FLAGS(tst_BrokenInstaller::Options) QTEST_MAIN(tst_BrokenInstaller) #include "tst_brokeninstaller.moc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/clientserver/�������������������������������������0040777�0000000�0000000�00000000000�13761647206�021714� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/clientserver/clientserver.pro���������������������0100777�0000000�0000000�00000000124�13761647206�025140� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../qttest.pri) QT += network QT -= gui SOURCES += tst_clientserver.cpp ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/clientserver/tst_clientserver.cpp�����������������0100777�0000000�0000000�00000043175�13761647206�026031� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include <protocol.h> #include <qprocesswrapper.h> #include <qsettingswrapper.h> #include <remoteclient.h> #include <remotefileengine.h> #include <remoteserver.h> #include <QBuffer> #include <QSettings> #include <QLocalSocket> #include <QTest> #include <QSignalSpy> #include <QTemporaryFile> #include <QUuid> #include <QLocalServer> using namespace QInstaller; class tst_ClientServer : public QObject { Q_OBJECT private: template<typename T> void sendCommand(QIODevice *device, const QByteArray &cmd, T t) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << t; sendPacket(device, cmd, data); } template<typename T> void receiveCommand(QIODevice *device, QByteArray *cmd, T *t) { QByteArray data; while (!receivePacket(device, cmd, &data)) device->waitForReadyRead(-1); QDataStream stream(&data, QIODevice::ReadOnly); stream >> *t; QCOMPARE(stream.status(), QDataStream::Ok); QVERIFY(stream.atEnd()); } private slots: void initTestCase() { RemoteClient::instance().setActive(true); } void sendReceivePacket() { QByteArray validPackage; typedef qint32 PackageSize; // first try sendPacket ... { QBuffer device(&validPackage); device.open(QBuffer::WriteOnly); const QByteArray cmd = "say"; const QByteArray data = "hello" ; QInstaller::sendPacket(&device, cmd, data); // 1 is delimiter (\0) QCOMPARE(device.buffer().size(), (int)sizeof(PackageSize) + cmd.size() + 1 + data.size()); QCOMPARE(device.buffer().right(data.size()), data); QCOMPARE(device.buffer().mid(sizeof(PackageSize), cmd.size()), cmd); } // now try successful receivePacket ... { QBuffer device(&validPackage); device.open(QBuffer::ReadOnly); QByteArray cmd; QByteArray data; QCOMPARE(QInstaller::receivePacket(&device, &cmd, &data), true); QCOMPARE(device.pos(), device.size()); QCOMPARE(cmd, QByteArray("say")); QCOMPARE(data, QByteArray("hello")); } // now try read of incomplete packet ... { QByteArray incompletePackage = validPackage; char toStrip = validPackage.at(validPackage.size() - 1); incompletePackage.resize(incompletePackage.size() - 1); QBuffer device(&incompletePackage); device.open(QBuffer::ReadOnly); QByteArray cmd; QByteArray data; QCOMPARE(QInstaller::receivePacket(&device, &cmd, &data), false); QCOMPARE(device.pos(), 0); QCOMPARE(cmd, QByteArray()); QCOMPARE(data, QByteArray()); // make packet complete again, retry device.buffer().append(toStrip); QCOMPARE(device.buffer(), validPackage); QCOMPARE(QInstaller::receivePacket(&device, &cmd, &data), true); QCOMPARE(device.pos(), device.size()); QCOMPARE(cmd, QByteArray("say")); QCOMPARE(data, QByteArray("hello")); } } void localSocket() { // // test roundtrip of a (big) packet via QLocalSocket // const QString socketName(__FUNCTION__); QLocalServer::removeServer(socketName); QEventLoop loop; const QByteArray command = "HELLO"; const QByteArray message(10905, '0'); QLocalServer server; // server QLocalSocket *rcv = 0; auto srvDataArrived = [&]() { QByteArray command, message; if (!receivePacket(rcv, &command, &message)) return; sendPacket(rcv, command, message); }; connect(&server, &QLocalServer::newConnection, [&,srvDataArrived]() { rcv = server.nextPendingConnection(); connect(rcv, &QLocalSocket::readyRead, srvDataArrived); }); server.listen(socketName); QLocalSocket snd; // client auto clientDataArrived = [&]() { QByteArray cmd, msg; if (!receivePacket(&snd, &cmd, &msg)) return; QCOMPARE(cmd, command); QCOMPARE(msg, message); loop.exit(); }; connect(&snd, &QLocalSocket::readyRead, clientDataArrived); QTimer::singleShot(0, [&]() { snd.connect(&snd, &QLocalSocket::connected, [&](){ sendPacket(&snd, command, message); }); snd.connectToServer(socketName); }); loop.exec(); } void testServerConnectDebug() { RemoteServer server; QString socketName = QUuid::createUuid().toString(); server.init(socketName, QString(Protocol::DefaultAuthorizationKey), Protocol::Mode::Debug); server.start(); QLocalSocket socket; socket.connectToServer(socketName); QVERIFY2(socket.waitForConnected(), "Cannot connect to server."); QCOMPARE(socket.state() == QLocalSocket::ConnectedState, true); sendCommand(&socket, Protocol::Authorize, QString(Protocol::DefaultAuthorizationKey)); { QByteArray command; bool authorized; receiveCommand(&socket, &command, &authorized); QCOMPARE(command, QByteArray(Protocol::Reply)); QCOMPARE(authorized, true); } sendCommand(&socket, Protocol::Authorize, QString::fromLatin1("Some Key")); { QByteArray command; bool authorized; receiveCommand(&socket, &command, &authorized); QCOMPARE(command, QByteArray(Protocol::Reply)); QCOMPARE(authorized, false); } } void testServerConnectRelease() { RemoteServer server; QString socketName = QUuid::createUuid().toString(); server.init(socketName, QString("SomeKey"), Protocol::Mode::Production); server.start(); QLocalSocket socket; socket.connectToServer(socketName); QVERIFY2(socket.waitForConnected(), "Cannot connect to server."); QCOMPARE(socket.state() == QLocalSocket::ConnectedState, true); sendCommand(&socket, Protocol::Authorize, QString::fromLatin1("SomeKey")); { QByteArray command; bool authorized; receiveCommand(&socket, &command, &authorized); QCOMPARE(command, QByteArray(Protocol::Reply)); QCOMPARE(authorized, true); } sendCommand(&socket, Protocol::Authorize, QString::fromLatin1(Protocol::DefaultAuthorizationKey)); { QByteArray command; bool authorized; receiveCommand(&socket, &command, &authorized); QCOMPARE(command, QByteArray(Protocol::Reply)); QCOMPARE(authorized, false); } } void testQSettingsWrapper() { RemoteServer server; QString socketName = QUuid::createUuid().toString(); server.init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Production); server.start(); RemoteClient::instance().init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Debug, Protocol::StartAs::User); QSettingsWrapper wrapper("digia", "clientserver"); QCOMPARE(wrapper.isConnectedToServer(), false); wrapper.clear(); QCOMPARE(wrapper.isConnectedToServer(), true); wrapper.sync(); wrapper.setFallbacksEnabled(false); QSettings settings("digia", "clientserver"); settings.setFallbacksEnabled(false); QCOMPARE(settings.fileName(), wrapper.fileName()); QCOMPARE(int(settings.format()), int(wrapper.format())); QCOMPARE(int(settings.scope()), int(wrapper.scope())); QCOMPARE(settings.organizationName(), wrapper.organizationName()); QCOMPARE(settings.applicationName(), wrapper.applicationName()); QCOMPARE(settings.fallbacksEnabled(), wrapper.fallbacksEnabled()); wrapper.setValue("key", "value"); wrapper.setValue("contains", "value"); wrapper.sync(); QCOMPARE(wrapper.value("key").toString(), QLatin1String("value")); QCOMPARE(settings.value("key").toString(), QLatin1String("value")); QCOMPARE(wrapper.contains("contains"), true); QCOMPARE(settings.contains("contains"), true); wrapper.remove("contains"); wrapper.sync(); QCOMPARE(wrapper.contains("contains"), false); QCOMPARE(settings.contains("contains"), false); wrapper.clear(); wrapper.sync(); QCOMPARE(wrapper.contains("key"), false); QCOMPARE(settings.contains("key"), false); wrapper.beginGroup("group"); wrapper.setValue("key", "value"); wrapper.endGroup(); wrapper.sync(); wrapper.beginGroup("group"); settings.beginGroup("group"); QCOMPARE(wrapper.value("key").toString(), QLatin1String("value")); QCOMPARE(settings.value("key").toString(), QLatin1String("value")); QCOMPARE(wrapper.group(), QLatin1String("group")); QCOMPARE(settings.group(), QLatin1String("group")); settings.endGroup(); wrapper.endGroup(); wrapper.beginWriteArray("array"); wrapper.setArrayIndex(0); wrapper.setValue("key", "value"); wrapper.endArray(); wrapper.sync(); wrapper.beginReadArray("array"); settings.beginReadArray("array"); wrapper.setArrayIndex(0); settings.setArrayIndex(0); QCOMPARE(wrapper.value("key").toString(), QLatin1String("value")); QCOMPARE(settings.value("key").toString(), QLatin1String("value")); settings.endArray(); wrapper.endArray(); wrapper.setValue("fridge/color", 3); wrapper.setValue("fridge/size", QSize(32, 96)); wrapper.setValue("sofa", true); wrapper.setValue("tv", false); wrapper.remove("group"); wrapper.remove("array"); wrapper.sync(); QStringList keys = wrapper.allKeys(); QCOMPARE(keys.count(), 4); QCOMPARE(keys.contains("fridge/color"), true); QCOMPARE(keys.contains("fridge/size"), true); QCOMPARE(keys.contains("sofa"), true); QCOMPARE(keys.contains("tv"), true); wrapper.beginGroup("fridge"); keys = wrapper.allKeys(); QCOMPARE(keys.count(), 2); QCOMPARE(keys.contains("color"), true); QCOMPARE(keys.contains("size"), true); wrapper.endGroup(); keys = wrapper.childKeys(); QCOMPARE(keys.count(), 2); QCOMPARE(keys.contains("sofa"), true); QCOMPARE(keys.contains("tv"), true); wrapper.beginGroup("fridge"); keys = wrapper.childKeys(); QCOMPARE(keys.count(), 2); QCOMPARE(keys.contains("color"), true); QCOMPARE(keys.contains("size"), true); wrapper.endGroup(); QStringList groups = wrapper.childGroups(); QCOMPARE(groups.count(), 1); QCOMPARE(groups.contains("fridge"), true); wrapper.beginGroup("fridge"); groups = wrapper.childGroups(); QCOMPARE(groups.count(), 0); wrapper.endGroup(); } void testQProcessWrapper() { RemoteServer server; QString socketName = QUuid::createUuid().toString(); server.init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Production); server.start(); RemoteClient::instance().init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Debug, Protocol::StartAs::User); { QProcess process; QProcessWrapper wrapper; QCOMPARE(wrapper.isConnectedToServer(), false); QCOMPARE(int(wrapper.state()), int(QProcessWrapper::NotRunning)); QCOMPARE(wrapper.isConnectedToServer(), true); QCOMPARE(process.workingDirectory(), wrapper.workingDirectory()); process.setWorkingDirectory(QDir::tempPath()); wrapper.setWorkingDirectory(QDir::tempPath()); QCOMPARE(process.workingDirectory(), wrapper.workingDirectory()); QCOMPARE(process.environment(), wrapper.environment()); process.setEnvironment(QProcess::systemEnvironment()); wrapper.setEnvironment(QProcess::systemEnvironment()); QCOMPARE(process.environment(), wrapper.environment()); QCOMPARE(int(process.readChannel()), int(wrapper.readChannel())); process.setReadChannel(QProcess::StandardError); wrapper.setReadChannel(QProcessWrapper::StandardError); QCOMPARE(int(process.readChannel()), int(wrapper.readChannel())); QCOMPARE(int(process.processChannelMode()), int(wrapper.processChannelMode())); process.setProcessChannelMode(QProcess::ForwardedChannels); wrapper.setProcessChannelMode(QProcessWrapper::ForwardedChannels); QCOMPARE(int(process.processChannelMode()), int(wrapper.processChannelMode())); } { QProcessWrapper wrapper; QCOMPARE(wrapper.isConnectedToServer(), false); QCOMPARE(int(wrapper.exitCode()), 0); QCOMPARE(wrapper.isConnectedToServer(), true); QCOMPARE(int(wrapper.state()), int(QProcessWrapper::NotRunning)); QCOMPARE(int(wrapper.exitStatus()), int(QProcessWrapper::NormalExit)); QString fileName; { QTemporaryFile file(QDir::tempPath() + #ifdef Q_OS_WIN QLatin1String("/XXXXXX.bat") #else QLatin1String("/XXXXXX.sh") #endif ); file.setAutoRemove(false); QCOMPARE(file.open(), true); #ifdef Q_OS_WIN file.write("@echo off\necho Mega test output!"); #else file.write("#!/bin/bash\necho Mega test output!"); #endif file.setPermissions(file.permissions() | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser); fileName = file.fileName(); } QSignalSpy spy(&wrapper, SIGNAL(started())); QSignalSpy spy2(&wrapper, SIGNAL(finished(int, QProcess::ExitStatus))); #ifdef Q_OS_WIN wrapper.start(fileName); #else wrapper.start("sh", QStringList() << fileName); #endif QCOMPARE(wrapper.waitForStarted(), true); QCOMPARE(int(wrapper.state()), int(QProcessWrapper::Running)); QCOMPARE(wrapper.waitForFinished(), true); QCOMPARE(int(wrapper.state()), int(QProcessWrapper::NotRunning)); QCOMPARE(wrapper.readAll().trimmed(), QByteArray("Mega test output!")); QTest::qWait(500); QCOMPARE(spy.count(), 1); QCOMPARE(spy2.count(), 1); QList<QVariant> arguments = spy2.takeFirst(); QCOMPARE(arguments.first().toInt(), 0); QCOMPARE(arguments.last().toInt(), int(QProcessWrapper::NormalExit)); QFile::remove(fileName); } } void testRemoteFileEngine() { RemoteServer server; QString socketName = QUuid::createUuid().toString(); server.init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Production); server.start(); RemoteClient::instance().init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Debug, Protocol::StartAs::User); QString filename; { QTemporaryFile file; file.setAutoRemove(false); QCOMPARE(file.open(), true); file.write(QProcess::systemEnvironment().join(QLatin1String("\n")).toLocal8Bit()); filename = file.fileName(); } RemoteFileEngineHandler handler; QFile file; file.setFileName(filename); file.open(QIODevice::ReadWrite); const QByteArray ba = file.readLine(); file.seek(0); QCOMPARE(file.atEnd(), false); QByteArray ba2(32 * 1024 * 1024, '\0'); file.readLine(ba2.data(), ba2.size()); file.resize(0); file.write(QProcess::systemEnvironment().join(QLatin1String("\n")).toLocal8Bit()); QCOMPARE(file.atEnd(), true); } void cleanupTestCase() { RemoteClient::instance().setActive(false); RemoteClient::instance().shutdown(); } }; QTEST_MAIN(tst_ClientServer) #include "tst_clientserver.moc" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/�������������������������������������0040777�0000000�0000000�00000000000�13761647206�021637� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/cliinterface.pro���������������������0100777�0000000�0000000�00000000202�13761647206�025003� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include(../../qttest.pri) QT += qml SOURCES += tst_cliinterface.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/��������������������������������0040777�0000000�0000000�00000000000�13761647206�022550� 5����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/components.xml������������������0100777�0000000�0000000�00000001413�13761647206�025456� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<Packages> <ApplicationName>Online Installer Example</ApplicationName> <ApplicationVersion>1.0.0</ApplicationVersion> <Package> <Name>A</Name> <Title>A Title Example component A 1.0.2-1 2020-02-13 74 true B B Title Example component B 1.0.0-1 2020-02-13 74 true ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/componentsFromInstallPackagesRepository.xmlqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/componentsFromInstallPackagesRe0100777000000000000000000001376013761647206030770 0ustar00 Dependency Solving Example 1.0.0 componentA Component A This component does not depend on any other component. 1.0.0 2020-03-23 158 true componentB Component B This component does not depend on any other component. 1.0.0 2020-03-23 99 true componentC Component C (depends on A and B) This component depends on Component A and Component B. Selecting this component for installation also marks Component A and Component B for installation, which in turn marks Component D, because it has an automatic dependency on Component A and Component B. 1.0.0 2020-03-23 99 componentA,componentB true componentD Component D (auto depends on A and B) This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. 1.0.0 2020-03-23 99 componentA,componentB true componentE Component E (forced) This is a forced component that is always installed. 1.0.0 2020-03-23 99 true componentF Component F This component contains 2 subcomponents. 1.0.0 2020-03-23 99 true componentF.subcomponent1 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2020-03-23 99 true componentF.subcomponent1.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2020-03-23 99 true componentF.subcomponent1.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2020-03-23 99 true componentF.subcomponent2 Subcomponent 2 This component contains 2 leaf components. 1.0.0 2020-03-23 99 true componentF.subcomponent2.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2020-03-23 99 true componentF.subcomponent2.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2020-03-23 99 true componentG Component G (default, depends on A, dependency added dynamically) By default, this component is selected for installation. It depends on component A. Dependency is added from inside component script. 1.0.0 2020-03-23 99 componentA true componentH Component H This component does not depend on any other component. 1.0.0 2020-03-23 99 true true qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/config.xml0100777000000000000000000000043513761647206024541 0ustar00 Your application 1.2.3 qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/filequeryrepository/0040777000000000000000000000000013761647206026715 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/filequeryrepository/A/0040777000000000000000000000000013761647206027075 5ustar00././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1me0100777000000000000000000000161313761647206030137 0ustar007zžŊ' ÄÓĻJ!ÎQų*āŲß]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ{u2Fm;:ƒ7Æ4ÕŽ&ŠFįēÁ,Ŧ,NĪã9…Ĩ‘uʍ-‡ l­îÕŲzBą Þ>!2æötœūŪ"L Sˆv’Įy3VÓWøĶ{YÔ8 ģęšðÆfÏÕđwé,}–.lȖ0ú)uÔïâÔuō5Mnž7ÖÏŌüų:sY…ŪÜĒĐ]Ü=€3ŪÕGðŋG%GWÓĢX"PŽø€UņNWŽ ”>LfBËŋ6åš$ȋžwĶÄÁ$ŲĨz]&vå )”+°ĩKdņņSö{(6ĶaMŲ.Ý6ǃĖ>~Žzyų€‚į c #] n `ÎÍqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml0100777000000000000000000000056213761647206031047 0ustar00 {AnyApplication} 1.0.0 A A A component 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/0040777000000000000000000000000013761647206027755 5ustar00././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentA/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentA/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000040313761647206031012 0ustar007zžŊ'øc\Â!ém !āu<]* 'd°8sƊĮ›*&Œ,]K S%öęūļiĀáGėœïāJMrj:†ÁØbĀįĐĻÕIlÂ83ŪŌ&˜ý@Ōĸ}iMNL Ēûę+Ķū§<ūû_ķií.X°ēb.)”“Ø·åcx[a§D6öuÍE8dĢņûŅōäÏ Ąŋ&eZTZEhۏųjŲVĪžG>Ņú"éĐš­3—ō˜ßSáĄýÎ{ˆ‰bD ~ #] €Ö °2žÍ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentB/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentB/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'Qð?]?’ĩ=.|:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentB.txt Ļ/’‰‡ÚÕ Ļ/’‰‡ÚÕ ĒV’‰‡ÚÕ ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentC/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentC/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'<§˜Ũ?’+˜a0:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentC.txt ĒV’‰‡ÚÕ ĒV’‰‡ÚÕ –}’‰‡ÚÕ ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentD/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentD/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'ĸ§•"?’žwķČ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentD.txt –}’‰‡ÚÕ –}’‰‡ÚÕ –}’‰‡ÚÕ ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentE/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentE/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'Ũũð5?’ Ļ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentE.txt †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0040777000000000000000000000017013761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0040777000000000000000000000021113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000023013761647206010111 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000037113761647206031016 0ustar007zžŊ'åû?šâŽü:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_1.txt †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ ”Ë’‰‡ÚÕ ././@LongLink0040777000000000000000000000021113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000023013761647206010111 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000037113761647206031016 0ustar007zžŊ'â…øŌ?šTzs:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_2.txt ”Ë’‰‡ÚÕ ”Ë’‰‡ÚÕ uō’‰‡ÚÕ ././@LongLink0100777000000000000000000000020713761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'*?’éë:This file will be installed into the target directory....  ? !! ; KIčœ -installcontentF_1.txt uō’‰‡ÚÕ uō’‰‡ÚÕ uō’‰‡ÚÕ ././@LongLink0040777000000000000000000000017013761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0040777000000000000000000000021113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000023013761647206010111 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000037113761647206031016 0ustar007zžŊ'1æN?šĸ<3:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_1.txt i“‰‡ÚÕ i“‰‡ÚÕ i“‰‡ÚÕ ././@LongLink0040777000000000000000000000021113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000023013761647206010111 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000037113761647206031016 0ustar007zžŊ'’3ž?š<3†Ų:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_2.txt }@“‰‡ÚÕ }@“‰‡ÚÕ }@“‰‡ÚÕ ././@LongLink0100777000000000000000000000020713761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF.subcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ' =ā?’’éŽ:This file will be installed into the target directory....  ? !! ; KIčœ -installcontentF_2.txt }@“‰‡ÚÕ }@“‰‡ÚÕ Xg“‰‡ÚÕ ././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentF/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'>Гø?’ŪĻڐ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentF.txt Xg“‰‡ÚÕ Xg“‰‡ÚÕ HŽ“‰‡ÚÕ ././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentG/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentG/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000036113761647206031015 0ustar007zžŊ'ŧF{Œ?’DZðŒ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentG.txt HŽ“‰‡ÚÕ HŽ“‰‡ÚÕ HŽ“‰‡ÚÕ ././@LongLink0100777000000000000000000000016613761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentG/1.0.0meta.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000171213761647206031016 0ustar007zžŊ'ē°Ŋ:ˆ"Ū§4ā‹]Šģ7Fˆ·n66æŲ/ō?/$4ÜqlþÖ§ÏŌd―ŌķēéŽbiŅ\_šØV$·"ýœ+#õŠī‹û'Đŧö wH7á8_5É KA‰Ý lžëDņwg―bŅý}î˙ Ģ{ŋ ؁AÁTthŦĻ›ßÕp|.&Ĩ9k‰ïüį°Ô5PÖ.CTDĶ…… ™ÁŋV<šŊ\ĐÛĖōīB"Ýęo@øŠíGĮŪZ ŦaÔ"`́ŋxðZԁŲhËŊ:ā#œŪ`SJeK5r†Xģ,N#öß)9%jāØė t"dž'úýË߁‘æķķ†Í„šUR—ŦÉđOðåU{o惊?Á ™­+ÛqŸF°0ėđ―]ÜŽüâĒĶ™‘uÁ)ęõp –ĐÝH’Đ;3)ŧ° ’Û[·o°oĮúÆåsïu_§$ ‡ép•Š.j"€lŲŧ;{$8Gm€žQF/čÂÖ-R—€Pūo\ĻÐ.ûr€ÍõĘ/?ĩØÄ-{ŨĢá]qúMų˜9Á-…WŽÛeÁ-pšúÄā>}%ūĐX€)ķķNv”Ô$ļäxŪ‡ļÞå.·―"û$[˜`"nŠōPÝŽō›Ð3/& ÄŦ7kXĄėEl#<ņĢmĪJ=#2ĸ3õĄí„wØÚjÛ‰’D'^Ļī8GbĢVŲ øŋ{ó{å-++)1äbd­ ōmó~EįI^ŋ‰{Āˆs(qÃÚŠņ?ŸXeé™' Xhąo×c€)‹ ąŨÁĶm5ó‡Ėū“eÚąZ—X§%|ð-óʑšTÞoļčôöËUŨĘč0@AÔÄ0þžėdÜ Í$Î@û<Žð”ôbý:‹Üjl|ļÁ@Ná% Û&J}$˜uníg‹"·†ŌwgD+_ČWÔIgâÞk+KŲ{ņČÞO›B’9bÍdŧƓ Ô7GægPXļ2ŋ*L•{–ķ&ĄMPōī(ĨüqhŊ‘ð噛Cĸ€3ŪÕNßyÆfڍóóĢŅ·jĘęlÉhgåĪ †ã(ģ%ðy3rjMe„ÄFī*ČWWD?âMÂ]s.ŠÛdĨņb‘Sæ%æÞŠĪ+XõB˜>d§ģõŨSōDx€’ųy:.ŧļÓw.${žq ķ3’Šũ}€B|MþH0ƒ   #] €Ķ ę1N././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentH/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0040777000000000000000000000000013761647206031013 5ustar00././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/componentH/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/compo0100777000000000000000000000032113761647206031011 0ustar007zžŊ'ÆD<Ö?rĮýkî:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentH.txt HŽ“‰‡ÚÕ ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/installPackagesRepository/Updat0100777000000000000000000001650313761647206030762 0ustar00 {AnyApplication} 1.0.0 false componentA Component A This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z 92b02a74d0886bc1569ff8b3a7edd1f9d828e56c componentB Component B This component does not depend on any other component. 1.0.0 2014-08-25 90 content.7z aedfaef53cdc0f52353a8680009be405fa767811 componentC Component C (depends on A and B) This component depends on Component A and Component B. Selecting this component for installation also marks Component A and Component B for installation, which in turn marks Component D, because it has an automatic dependency on Component A and Component B. componentA, componentB 1.0.0 2014-08-25 80 content.7z 20b9463a5e06f373182b3c7c4cf879806d429409 componentD Component D (auto depends on A and B) This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. componentA, componentB 1.0.0 2014-08-25 70 content.7z 99cf24c71559c75dfae9933826ed16051fca6ea1 componentE Component E (forced) This is a forced component that is always installed. true 1.0.0 2014-08-25 60 content.7z 926bf503ccdff93351744843a95e5e2172cad5ec componentF Component F This component contains 2 subcomponents. 1.0.0 2014-08-25 40 content.7z e6443a8b5a5651f63c0604cae6d32431ca617f1a componentF.subcomponent1 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2014-08-25 100 content.7z a3bc5dce1c93add30c22e46436396c66b0b51001 componentF.subcomponent1.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z ebe4d69414a1675a7f46887e15d9bffc275b7cc4 componentF.subcomponent1.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z e4379d20320d4c173b2d8e228f5722e3f36e3114 componentF.subcomponent2 Subcomponent 2 This component contains 2 leaf components. 1.0.0 2014-08-25 50 content.7z 6462be25912c490569a7c4f3931d978e78c69dc4 componentF.subcomponent2.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z 72b224bc8f3431210834ce6db373fc8d638a3546 componentF.subcomponent2.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z 3e2744edaef06af75b3248d5935523a6e2e61551 componentG Component G (default, depends on A, dependency added dynamically) By default, this component is selected for installation. It depends on component A. Dependency is added from inside component script. 1.0.0 2014-08-25 30 content.7z 8cba36dd589492c28e0d04942b4f8aa0a09f59cc componentH This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z true qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/0040777000000000000000000000000013761647206024767 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/A/0040777000000000000000000000000013761647206025147 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/AB/0040777000000000000000000000000013761647206025251 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/AB/1.0.2-1meta.7z0100777000000000000000000000016213761647206027175 0ustar007zžŊ'WeKRŦ9Ģā€AB ZÛåāÕ ZÛåāÕ ZÛåāÕqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/A/1.0.2-1content.7z0100777000000000000000000000026613761647206027624 0ustar007zžŊ'Cņ$ržĶ^Example content for package A.  $ !!  ŲþŋI  A.txt ;Ōž†‚Õ ;Ōž†‚Õ ;Ōž†‚Õ ././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/A/1.0.2-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/A/1.0.2-1content.7z.0100777000000000000000000000005013761647206027671 0ustar00643cb71b2337d5a49d57a5bc3c636ee9b84c0802qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/A/1.0.2-1meta.7z0100777000000000000000000000015213761647206027072 0ustar007zžŊ'œ{afJš…ï9€A —’—ęūÕ —’—ęūÕ —’—ęūÕqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/B/0040777000000000000000000000000013761647206025150 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/B/1.0.0-1content.7z0100777000000000000000000000026613761647206027623 0ustar007zžŊ'Ų ĸo$rŸôExample content for package B.  $ !!  7Q [  B.txt Tųž†‚Õ Tųž†‚Õ Ōžž†‚Õ ././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/B/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/B/1.0.0-1content.7z.0100777000000000000000000000005013761647206027670 0ustar00c7b9ab370efe036171dda7b71cd95021747cb101qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/B/1.0.0-1meta.7z0100777000000000000000000000015213761647206027071 0ustar007zžŊ'đŲ―~JjīH€B N “—ęūÕ N “—ęūÕ N “—ęūÕqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/C/0040777000000000000000000000000013761647206025151 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/C/1.0.0-1content.7z0100777000000000000000000000026613761647206027624 0ustar007zžŊ' Ôq‹$r―4ĮpExample content for package B.  $ !!  7Q [  C.txt ø”žž†‚Õ ø”žž†‚Õ ø”žž†‚Õ ././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/C/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/C/1.0.0-1content.7z.0100777000000000000000000000005013761647206027671 0ustar00c8b7076fabaaf6b9d27f27350c577118c24f426bqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/C/1.0.0-1meta.7z0100777000000000000000000000015213761647206027072 0ustar007zžŊ'.NŽJaŧIï€C u­–ëūÕ u­–ëūÕ u­–ëūÕqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/repository/Updates.xml0100777000000000000000000000330013761647206027112 0ustar00 {AnyApplication} 1.0.0 true A A Example component A 1.0.2-1 2015-01-01 true content.7z 9d54e3a5adf3563913feee8ba23a99fb80d46590 B B Example component B 1.0.0-1 2015-01-01 true content.7z 9170d55a6af81c1a6a63d708a4ab6ed359775cd9 C C Example component C 1.0.0-1 2015-01-01 true content.7z 5b3939da1af492382c68388fc796837e4c36b876 AB AB Example component AB 1.0.2-1 2015-01-01 true f75e65b1a0f68abb77fc41da08fc26dda5409a18 ././@LongLink0040777000000000000000000000014713761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0040777000000000000000000000000013761647206031121 5ustar00././@LongLink0040777000000000000000000000015113761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/A/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0040777000000000000000000000000013761647206031121 5ustar00././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/AB/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0040777000000000000000000000000013761647206031121 5ustar00././@LongLink0100777000000000000000000000017013761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/AB/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000016213761647206031122 0ustar007zžŊ'Šō'RxoĨ€AB *+{áÕ *+{áÕ *+{áÕ././@LongLink0100777000000000000000000000017013761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/A/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000027013761647206031122 0ustar007zžŊ']n‰&rč˜P!Example content for package A.  & !! " įUŠƒ  A.txt ėÞdáÕ ėÞdáÕ dÞdáÕ ././@LongLink0100777000000000000000000000017513761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/A/2.0.0content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000005013761647206031116 0ustar00f33d2028e1c61061f7f29e5189f7d66800361dc2././@LongLink0100777000000000000000000000016513761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/A/2.0.0meta.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000015213761647206031121 0ustar007zžŊ'a7jJ!jWž€A h[+{áÕ h[+{áÕ h[+{áÕ././@LongLink0040777000000000000000000000015113761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/B/qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0040777000000000000000000000000013761647206031121 5ustar00././@LongLink0100777000000000000000000000017013761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/B/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000027013761647206031122 0ustar007zžŊ'>1&rņmðÃ!Example content for package B.  & !! " I'  B.txt û9ÞdáÕ û9ÞdáÕ û9ÞdáÕ ././@LongLink0100777000000000000000000000017513761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/B/2.0.0content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000005013761647206031116 0ustar00bb256f1eda0f452c7ab33d1f364a4fad062f0a73././@LongLink0100777000000000000000000000016513761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/B/2.0.0meta.7zqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000015213761647206031121 0ustar007zžŊ'é‡ÜũJ>ÛŪ€B ‚F+{áÕ ‚F+{áÕ ‚F+{áÕ././@LongLink0100777000000000000000000000016213761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsRepository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/cliinterface/data/uninstallableComponentsReposito0100777000000000000000000000260213761647206031123 0ustar00 {AnyApplication} 1.0.0 true A A Example component A 2.0.0 2015-01-01 true content.7z c1f340c9a7ad1edbef4cb6288c83c646211e5ccd autoDep AB AB Example component AB 1.0.2-1 2015-01-01 true 3c1470896a9db84092e00806b1303f3b5fa4f7ad false B B Example component B 2.0.0 2015-01-01 true content.7z cfa136fa1d7a4196896c90af72d510727ba799ae true qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/settings.qrc0100777000000000000000000000346513761647206024216 0ustar00 data/config.xml data/repository/Updates.xml data/uninstallableComponentsRepository/Updates.xml data/components.xml data/installPackagesRepository/Updates.xml data/installPackagesRepository/componentA/1.0.0content.7z data/installPackagesRepository/componentB/1.0.0content.7z data/installPackagesRepository/componentC/1.0.0content.7z data/installPackagesRepository/componentD/1.0.0content.7z data/installPackagesRepository/componentE/1.0.0content.7z data/installPackagesRepository/componentF/1.0.0content.7z data/installPackagesRepository/componentG/1.0.0content.7z data/installPackagesRepository/componentH/1.0.0content.7z data/installPackagesRepository/componentG/1.0.0meta.7z data/installPackagesRepository/componentF.subcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7z data/filequeryrepository/Updates.xml data/filequeryrepository/A/1.0.2-1meta.7z data/componentsFromInstallPackagesRepository.xml qt-installer-framework-4.0.1/tests/auto/installer/cliinterface/tst_cliinterface.cpp0100777000000000000000000006503113761647206025672 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include "../shared/verifyinstaller.h" #include #include #include #include using namespace QInstaller; class tst_CLIInterface : public QObject { Q_OBJECT private: void setIgnoreMessage() { QTest::ignoreMessage(QtDebugMsg, "Id: A"); QTest::ignoreMessage(QtDebugMsg, "Id: B"); QTest::ignoreMessage(QtDebugMsg, "Id: C"); QTest::ignoreMessage(QtDebugMsg, "Id: AB"); } private slots: void testListAvailablePackages() { QString loggingRules = (QLatin1String("ifw.* = false\n" "ifw.package.name = true\n")); QTest::ignoreMessage(QtDebugMsg, "Operations sanity check succeeded."); PackageManagerCore *core = PackageManager::getPackageManager (m_installDir, ":///data/repository"); QLoggingCategory::setFilterRules(loggingRules); setIgnoreMessage(); core->listAvailablePackages(QLatin1String(".")); QTest::ignoreMessage(QtDebugMsg, "Id: A"); QTest::ignoreMessage(QtDebugMsg, "Id: AB"); core->listAvailablePackages(QLatin1String("A")); QTest::ignoreMessage(QtDebugMsg, "Id: A"); QTest::ignoreMessage(QtDebugMsg, "Id: AB"); core->listAvailablePackages(QLatin1String("A.*")); QTest::ignoreMessage(QtDebugMsg, "Id: B"); core->listAvailablePackages(QLatin1String("^B")); QTest::ignoreMessage(QtDebugMsg, "Id: B"); core->listAvailablePackages(QLatin1String("^B.*")); QTest::ignoreMessage(QtDebugMsg, "Id: C"); core->listAvailablePackages(QLatin1String("^C")); } void testInstallPackageFails() { QString loggingRules = (QLatin1String("ifw.* = false\n" "ifw.installer.installlog = true\n")); PackageManagerCore *core = PackageManager::getPackageManager (m_installDir, ":///data/uninstallableComponentsRepository"); QLoggingCategory::setFilterRules(loggingRules); QTest::ignoreMessage(QtDebugMsg, "Preparing meta information download..."); QTest::ignoreMessage(QtDebugMsg, "Cannot install component A. Component is installed only as automatic dependency to autoDep."); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("A"))); QTest::ignoreMessage(QtDebugMsg, "Preparing meta information download..."); QTest::ignoreMessage(QtDebugMsg, "Cannot install component AB. Component is not checkable meaning you have to select one of the subcomponents."); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("AB"))); QTest::ignoreMessage(QtDebugMsg, "Preparing meta information download..."); QTest::ignoreMessage(QtDebugMsg, "Cannot install B. Component is virtual."); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("B"))); QTest::ignoreMessage(QtDebugMsg, "Preparing meta information download..."); QTest::ignoreMessage(QtDebugMsg, "Cannot install MissingComponent. Component not found."); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("MissingComponent"))); QCOMPARE(PackageManagerCore::Success, core->status()); } void testUninstallPackageFails() { QString loggingRules = (QLatin1String("ifw.installer.installog = true\n")); PackageManagerCore core; core.setPackageManager(); QString appFilePath = QCoreApplication::applicationFilePath(); core.setAllowedRunningProcesses(QStringList() << appFilePath); QLoggingCategory::setFilterRules(loggingRules); m_installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(m_installDir)); QVERIFY(QFile::copy(":/data/componentsFromInstallPackagesRepository.xml", m_installDir + "/components.xml")); core.setValue(scTargetDir, m_installDir); QTest::ignoreMessage(QtWarningMsg, "Cannot uninstall ForcedInstallation component componentE"); QCOMPARE(PackageManagerCore::Success, core.uninstallComponentsSilently(QStringList() << "componentE")); QTest::ignoreMessage(QtWarningMsg, "Cannot uninstall component componentD because it is added as auto dependency to componentA,componentB"); QCOMPARE(PackageManagerCore::Success, core.uninstallComponentsSilently(QStringList() << "componentD")); QTest::ignoreMessage(QtWarningMsg, "Cannot uninstall component MissingComponent. Component not found in install tree."); QCOMPARE(PackageManagerCore::Success, core.uninstallComponentsSilently(QStringList() << "MissingComponent")); QTest::ignoreMessage(QtWarningMsg, "Cannot uninstall virtual component componentH"); QCOMPARE(PackageManagerCore::Success, core.uninstallComponentsSilently(QStringList() << "componentH")); QCOMPARE(PackageManagerCore::Success, core.status()); } void testListInstalledPackages() { QString loggingRules = (QLatin1String("ifw.* = false\n" "ifw.package.name = true\n")); PackageManagerCore core; core.setPackageManager(); QLoggingCategory::setFilterRules(loggingRules); const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); QVERIFY(QFile::copy(":/data/components.xml", testDirectory + "/components.xml")); core.setValue(scTargetDir, testDirectory); QTest::ignoreMessage(QtDebugMsg, "Id: A"); QTest::ignoreMessage(QtDebugMsg, "Id: B"); core.listInstalledPackages(); QDir dir(testDirectory); QVERIFY(dir.removeRecursively()); } void testNoDefaultInstallations() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); core->setNoDefaultInstallation(true); QCOMPARE(PackageManagerCore::Success, core->installDefaultComponentsSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentE.txt"); core->setNoDefaultInstallation(false); } void testInstallForcedPackageSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentE"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Depends on componentA VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testInstallPackageSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentA"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Depends on componentA VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testUninstallPackageSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentA"))); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentE.txt" << "installcontentA.txt" << "installcontent.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << QLatin1String("componentA"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentA"); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentG"); //Depends on componentA VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentE.txt"); } void testRemoveAllSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentA"))); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentE.txt" << "installcontentA.txt" << "installcontent.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setUninstaller(); QCOMPARE(PackageManagerCore::Success, core->removeInstallationSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentA"); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentE"); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentG"); // On Windows we have to settle for the resources check above as maintenance // tool (if it would exists) and target directory are only removed later via // started VBScript process. On Unix platforms the target directory should // be removed in PackageManagerCorePrivate::runUninstaller(). #if defined(Q_OS_UNIX) QVERIFY(!QDir(m_installDir).exists()); #endif } void testInstallWithDependencySilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentC"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentC VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "1.0.0content.txt"); //Dependency for componentC VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Depends on componentA VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "1.0.0content.txt"); //Autodepend on componentA and componentB VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentC.txt" << "installcontent.txt" << "installcontentA.txt" << "installcontentB.txt" << "installcontentD.txt"<< "installcontentE.txt" << "installcontentG.txt"); } void testUninstallWithDependencySilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentC"))); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentC.txt" << "installcontent.txt" << "installcontentA.txt" << "installcontentB.txt" << "installcontentD.txt"<< "installcontentE.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << QLatin1String("componentC"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentC VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "1.0.0content.txt"); //Dependency for componentC VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Depends on componentA VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "1.0.0content.txt"); //Autodepend on componentA and componentB VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentC"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentB.txt" << "installcontentD.txt"<< "installcontentE.txt" << "installcontentG.txt"); } void testInstallSubcomponentSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentF.subcomponent2.subsubcomponent2"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent2.subsubcomponent2", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent2", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentG VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Default install VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentF.txt" << "installcontentF_2.txt" << "installcontentF_2_2.txt" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testUninstallSubcomponentSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << QLatin1String("componentF.subcomponent2.subsubcomponent2"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentF.txt" << "installcontentF_2.txt" << "installcontentF_2_2.txt" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << QLatin1String("componentF.subcomponent2"))); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentG VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Default install VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentF.subcomponent2.subsubcomponent2"); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentF.subcomponent2"); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentF"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testInstallDefaultPackagesSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installDefaultComponentsSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentG VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Default VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testUnInstallDefaultPackagesSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installDefaultComponentsSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << "componentG")); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentG VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentG"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt"); } void testUninstallForcedPackagesSilenly() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installDefaultComponentsSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << "componentE")); QCOMPARE(PackageManagerCore::Success, core->status()); //Nothing is uninstalled as componentE is forced install and cannot be uninstalled VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency for componentG VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Default VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testUninstallAutodependencyPackagesSilenly() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << "componentA" << "componentB")); QCOMPARE(PackageManagerCore::Success, core->status()); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << "componentD")); QCOMPARE(PackageManagerCore::Success, core->status()); //Nothing is uninstalled as componentD is installed as autodependency to componentA and componentB VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //ForcedInstall VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); //Default VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt" << "installcontentB.txt" << "installcontentD.txt"); } void testUninstallVirtualSetVisibleSilently() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_installDir, ":///data/installPackagesRepository"); core->setVirtualComponentsVisible(true); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() <<"componentH")); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentH", "1.0.0content.txt"); core->commitSessionOperations(); core->setPackageManager(); QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently(QStringList() << "componentH")); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentH"); } void testFileQuery() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit(m_installDir, ":///data/filequeryrepository"); core->setCommandLineInstance(true); core->setFileDialogAutomaticAnswer("ValidDirectory", m_installDir); QString testFile = qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); QFile file(testFile); QVERIFY(file.open(QIODevice::WriteOnly)); core->setFileDialogAutomaticAnswer("ValidFile", testFile); //File dialog launched without ID core->setFileDialogAutomaticAnswer("GetExistingDirectory", m_installDir); core->setFileDialogAutomaticAnswer("GetExistingFile", testFile); QCOMPARE(PackageManagerCore::Success, core->installDefaultComponentsSilently()); QCOMPARE(PackageManagerCore::Success, core->status()); QVERIFY(core->containsFileDialogAutomaticAnswer("ValidFile")); core->removeFileDialogAutomaticAnswer("ValidFile"); QVERIFY(!core->containsFileDialogAutomaticAnswer("ValidFile")); QVERIFY(file.remove()); core->deleteLater(); } void init() { m_installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(m_installDir)); } void cleanup() { QDir dir(m_installDir); QVERIFY(dir.removeRecursively()); } private: QString m_installDir; }; QTEST_MAIN(tst_CLIInterface) #include "tst_cliinterface.moc" qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/0040777000000000000000000000000013761647206022700 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/commandlineupdate.pro0100777000000000000000000000020713761647206027112 0ustar00include(../../qttest.pri) QT += qml SOURCES += tst_commandlineupdate.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/0040777000000000000000000000000013761647206023611 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/config.xml0100777000000000000000000000043513761647206025602 0ustar00 Your application 1.2.3 qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0040777000000000000000000000015213761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentA/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentA/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'ģZ‡°?ĒlÞą:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentA_update.txt Ĉ8ĒÕęÕ Ĉ8ĒÕęÕ ļŊ8ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentB/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentB/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'}f+v?ĒļhĀį:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentB_update.txt ­Ö8ĒÕęÕ ­Ö8ĒÕęÕ ­Ö8ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentC/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentC/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'Cļār?ĒJîpž:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentC_update.txt Ēý8ĒÕęÕ Ēý8ĒÕęÕ Ēý8ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentD/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentD/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'‰0*?Ē·î›Ð:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentD_update.txt —$9ĒÕęÕ —$9ĒÕęÕ ‹K9ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentE/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentE/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'ÁjÎ&?ǰũ:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentE_update.txt €r9ĒÕęÕ €r9ĒÕęÕ €r9ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0040777000000000000000000000020313761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0040777000000000000000000000022413761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000024313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000037113761647206031067 0ustar007zžŊ'šgÆN?šqö`Ŋ:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_1.txt z™9ĒÕęÕ z™9ĒÕęÕ z™9ĒÕęÕ ././@LongLink0040777000000000000000000000022413761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000024313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000037113761647206031067 0ustar007zžŊ'‚"š?šÄ; :This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_2.txt oĀ9ĒÕęÕ oĀ9ĒÕęÕ oĀ9ĒÕęÕ ././@LongLink0100777000000000000000000000022213761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000036113761647206031066 0ustar007zžŊ'^á?’ų§„:This file will be installed into the target directory....  ? !! ; KIčœ -installcontentF_1.txt cį9ĒÕęÕ cį9ĒÕęÕ X:ĒÕęÕ ././@LongLink0040777000000000000000000000020313761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0040777000000000000000000000022413761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000024313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000037113761647206031067 0ustar007zžŊ'ęîū?š}Š:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_1.txt M5:ĒÕęÕ M5:ĒÕęÕ M5:ĒÕęÕ ././@LongLink0040777000000000000000000000022413761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000024313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000037113761647206031067 0ustar007zžŊ'­“ŨÕ?švú$:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_2.txt A\:ĒÕęÕ A\:ĒÕęÕ A\:ĒÕęÕ ././@LongLink0100777000000000000000000000022213761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF.subcomponent2/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'îĄS?Ē<“ũ:This file will be installed into the target directory....  ? !! ; KIčœ ;installcontentF_2_update.txt 6ƒ:ĒÕęÕ 6ƒ:ĒÕęÕ 6ƒ:ĒÕęÕ ././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentF/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'.­HĘ?Ē“ĩÏ:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentF_update.txt +Š:ĒÕęÕ +Š:ĒÕęÕ %Ņ:ĒÕęÕ ././@LongLink0040777000000000000000000000016513761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentG/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0040777000000000000000000000000013761647206031064 5ustar00././@LongLink0100777000000000000000000000020413761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentG/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000040113761647206031061 0ustar007zžŊ'.K;Ō?Ē"BÄ:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentG_update.txt ø:ĒÕęÕ ø:ĒÕęÕ ø:ĒÕęÕ ././@LongLink0100777000000000000000000000020113761647206010107 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/componentG/2.0.0meta.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000000167713761647206031101 0ustar007zžŊ'˜"|#Q ĩāãæ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQr…z[>RTæRÞ~"ķüoLw/ģR› fˆónBã%,[…–‰Ac; Č]šņϕÄXbôÎÁĻ$Í"d/?ëUHýU Ö.yOD|I:ũÓgĄĘšųá†Åðą"y|"P6.ž/‰™đ+QÁ…ÕŲĢâ_›ĸu[•âž;jX‡Eíî”e܈Bþš.Čš<―…G™Mæïž óF˜mĢß41˜ŽŊ-ģð$° äÆÖ—„MÔŊ­ąz―ژKxœˆ€øJ Ðʍžœô€‹ņ~uĀæ8 4ÔŲóéÛ_måŽ`%Jn’ķHØÉÐTG~q­4äõv4Û Ÿ§·ĶĸW―_F…~ąVysËz„#Ũ<ēŅæ'I/;§Š þĪý· šÕĩ;†ƒ*î—-óāūbωĸ|Ņ‘V*I­ŅE].V cýPĐ$ŠÉĀBąÅƒi:å7Ð ,'†ĖjöŨîH,·•”Įó^]:ZcĖŲïĩzųėOƟf˘ú&™aŒÞĀUyņŧÂmM Á‰åfĩž_ŨĨĄ<ņîÕųåJPĒX'EŊøįg…d‰œÎ1ŲĨ2O“NÁEąDnÄ-@ĖÁû”}Ķƒ Xåû…ðfHī›――ÕÜ∭4ō뚝 ÅÖĸ°‹F隡 /åÁRIaÛÃíZÉõ XNÏÂā°ô·Ŧ˃í7|Œ^Ũ„ĩŲĻ+§ m€Ãķ69ððūB_˜*óuh|MĢķ―M­ŧ˜°Dó%ĀDeq=!(”ÖīӆɡÓNƒá7Tžh~Ą1L°5?NÛÔ,`ļđ]ô.š,‰5ӏ6Âī4 /#ø€3ŪÕHuw%GWÓĢX"X#įýUĢdHØ[̉(\ϊkīnzWvÃ…|Pf>XwyqŸMôĘ2ũÜZYŽúËxaghaā é DÁžî,:õ-Vyx‹„ß^―‡VģGĄīrįüÜðaÏ%ŲãÆÆÔŨFóļILĶÛNĮ{ð•ÅÎJqځ,‚î €Ž #] €Ö óŲw3././@LongLink0100777000000000000000000000016513761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryUpdate/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepositoryU0100777000000000000000000001605213761647206031072 0ustar00 {AnyApplication} 1.0.0 false componentA Component A This component does not depend on any other component. 2.0.0 2015-08-25 100 content.7z 43c8fcc544ea6d35fe5180a50d4764dcf9fd7473 true componentB Component B This component does not depend on any other component. 2.0.0 2015-08-25 90 content.7z c360591443f4f46c14cd05b0e7f93a105857b563 componentC Component C (depends on A and B) This component depends on Component A and Component B. Selecting this component for installation also marks Component A and Component B for installation, which in turn marks Component D, because it has an automatic dependency on Component A and Component B. componentA, componentB 2.0.0 2015-08-25 80 content.7z 3c5acf95ad15a2ea6e2baaf55dd79053ca439668 componentD Component D (auto depends on A and B) This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. componentA, componentB 2.0.0 2015-08-25 70 content.7z 5b014c99bf083377024f3de42553faad0c69ebbb componentE Component E (forced) This is a forced component that is always installed. true 2.0.0 2015-08-25 60 content.7z bf312c4593abaa8f6d18a1504c411e5ec8130860 componentF Component F This component contains 2 subcomponents. 2.0.0 2015-08-25 40 content.7z d8764d228cc32be0959b286cf57a30252082d2dc componentF.subcomponent1 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2014-08-25 100 content.7z fbdd255c25820331ffea46c9a80905580fb8ad4f componentF.subcomponent1.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z c96ddbefa66f5a3400e0c2f3a458c0f619d99690 componentF.subcomponent1.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z c88f52f11f22089d7efc3b65394e96ee1656702e componentF.subcomponent2 Subcomponent 2 This component contains 2 leaf components. 2.0.0 2015-08-25 50 content.7z 57120d69b22e013666b80d3954b1ee65eb37891f componentF.subcomponent2.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z 3844dc1b4805050f34b483661843a8f8a4e97864 componentF.subcomponent2.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z e1d988818cb8fd89e8863b5699b19823e38f0919 componentG Component G (default, depends on A, dependency added dynamically) By default, this component is selected for installation. It depends on component A. Dependency is added from inside component script. true 2.0.0 2015-08-25 30 content.7z 098b5ecafe8853371fd608acd9b1ccab252ef5df ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentA/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentA/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000040313761647206031015 0ustar007zžŊ'øc\Â!ém !āu<]* 'd°8sƊĮ›*&Œ,]K S%öęūļiĀáGėœïāJMrj:†ÁØbĀįĐĻÕIlÂ83ŪŌ&˜ý@Ōĸ}iMNL Ēûę+Ķū§<ūû_ķií.X°ēb.)”“Ø·åcx[a§D6öuÍE8dĢņûŅōäÏ Ąŋ&eZTZEhۏųjŲVĪžG>Ņú"éĐš­3—ō˜ßSáĄýÎ{ˆ‰bD ~ #] €Ö °2žÍ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentB/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentB/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'Qð?]?’ĩ=.|:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentB.txt Ļ/’‰‡ÚÕ Ļ/’‰‡ÚÕ ĒV’‰‡ÚÕ ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentC/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentC/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'<§˜Ũ?’+˜a0:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentC.txt ĒV’‰‡ÚÕ ĒV’‰‡ÚÕ –}’‰‡ÚÕ ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentD/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentD/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'ĸ§•"?’žwķČ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentD.txt –}’‰‡ÚÕ –}’‰‡ÚÕ –}’‰‡ÚÕ ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentE/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentE/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'Ũũð5?’ Ļ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentE.txt †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0040777000000000000000000000017513761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0040777000000000000000000000021613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000023513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000037113761647206031021 0ustar007zžŊ'åû?šâŽü:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_1.txt †Ī’‰‡ÚÕ †Ī’‰‡ÚÕ ”Ë’‰‡ÚÕ ././@LongLink0040777000000000000000000000021613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000023513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000037113761647206031021 0ustar007zžŊ'â…øŌ?šTzs:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_1_2.txt ”Ë’‰‡ÚÕ ”Ë’‰‡ÚÕ uō’‰‡ÚÕ ././@LongLink0100777000000000000000000000021413761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'*?’éë:This file will be installed into the target directory....  ? !! ; KIčœ -installcontentF_1.txt uō’‰‡ÚÕ uō’‰‡ÚÕ uō’‰‡ÚÕ ././@LongLink0040777000000000000000000000017513761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0040777000000000000000000000021613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000023513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000037113761647206031021 0ustar007zžŊ'1æN?šĸ<3:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_1.txt i“‰‡ÚÕ i“‰‡ÚÕ i“‰‡ÚÕ ././@LongLink0040777000000000000000000000021613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000023513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000037113761647206031021 0ustar007zžŊ'’3ž?š<3†Ų:This file will be installed into the target directory....  ? !! ; KIčœ 1installcontentF_2_2.txt }@“‰‡ÚÕ }@“‰‡ÚÕ }@“‰‡ÚÕ ././@LongLink0100777000000000000000000000021413761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF.subcomponent2/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ' =ā?’’éŽ:This file will be installed into the target directory....  ? !! ; KIčœ -installcontentF_2.txt }@“‰‡ÚÕ }@“‰‡ÚÕ Xg“‰‡ÚÕ ././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentF/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'>Гø?’ŪĻڐ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentF.txt Xg“‰‡ÚÕ Xg“‰‡ÚÕ HŽ“‰‡ÚÕ ././@LongLink0040777000000000000000000000015713761647206010124 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentG/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0040777000000000000000000000000013761647206031016 5ustar00././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentG/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000036113761647206031020 0ustar007zžŊ'ŧF{Œ?’DZðŒ:This file will be installed into the target directory....  ? !! ; KIčœ )installcontentG.txt HŽ“‰‡ÚÕ HŽ“‰‡ÚÕ HŽ“‰‡ÚÕ ././@LongLink0100777000000000000000000000017313761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/componentG/1.0.0meta.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000000170413761647206031022 0ustar007zžŊ'—6p7#,æāaë]Šģ7Fˆ·n66æŲ/ō?/$4ÜqlþÖ§ÏŌd―ŌķēéŽbiŅ\_šØV$·"ýœ+#õŠī‹û'Đŧö wH7á8_5É KA‰Ý lžëDņwg―bŅý}î˙ Ģ{ŋ ؁AÁTthŦĻ›ßÕp|.&Ĩ9k‰ïüį°Ô5PÖ.CTDĶ…… ™ÁŋV<šŊ\ĐÛĖōīB"Ýęo@øŠíGĮŪZ ŦaÔ"`́ŋxðZԁŲhËŊ:ā#œŪ`SJeK5r†Xģ,N#öß)9%jāØė t"dž'úýË߁‘æķķ†Í„šUR—ŦÉđOðåU{o惊?Á ™­+ÛqŸF°0ėđ―]ÜŽüâĒĶ™‘uÁ)ęõp –ĐÝH’Đ;3)ŧ° ’Û[·o°oĮúÆåsïu_§$ ‡ép•Š.j"€lŲŧ;{$8Gm€žQF/čÂÖ-R—€Pūo\ĻÐ.ûr€ÍõĘ/?ĩØÄ-{ŨĢá]qúMų˜9Á-…WŽÛeÁ-pšúÄā>}%ūĐX€)ķķNv”Ô$ļäxŪ‡ļÞå.·―"û$[˜`"nŠōPÝŽō›Ð3/& ÄŦ7kXĄėEl#<ņĢmĪJ=#2ĸ3õĄí„wØÚjÛ‰’D'^Ļī8GbĢVŲ øŋ{ó{å-++)1äbd­ ōmó~EįI^ŋ‰{Āˆs(qÃÚŠņ?ŸXeé™' Xhąo×c€)‹ ąŨÁĶm5ó‡Ėū“eÚąZ—X§%|ð-óʑšTÞoļčôöËUŨĘč0@AÔÄ0þžėdÜ Í$Î@û<Žð”ôbý:‹Üjl|ļÁ@Ná% Û&J}$˜uníg‹"·†ŌwgD+_ČWÔIgâÞk+KŲ{ņČÞO›B’9bÍdŧƓ Ô7GægPXļ2ŋ#~Y81@3ŪÕH4Ó%GWÓĢX"N1Į{ ”uĒ+ üpD–Ø}ÍĄŋÉþ;ï3O< 4ފú™ÏĢĪĖŠ‹Ũđ™ö­―'+˜ŅGš RݞšžŠUÓīšwÂbČÛũ°Õ>6™,õdŅÏ#››ĒcÝū’Ü#ú9 &Dē!Į ðČøĢ)Áė.ßŅĪ‚ó €Ž #] €Ö †š]Ú././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/installPackagesRepository/0100777000000000000000000001605313761647206031025 0ustar00 {AnyApplication} 1.0.0 false componentA Component A This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z 92b02a74d0886bc1569ff8b3a7edd1f9d828e56c true componentB Component B This component does not depend on any other component. 1.0.0 2014-08-25 90 content.7z aedfaef53cdc0f52353a8680009be405fa767811 componentC Component C (depends on A and B) This component depends on Component A and Component B. Selecting this component for installation also marks Component A and Component B for installation, which in turn marks Component D, because it has an automatic dependency on Component A and Component B. componentA, componentB 1.0.0 2014-08-25 80 content.7z 20b9463a5e06f373182b3c7c4cf879806d429409 componentD Component D (auto depends on A and B) This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. componentA, componentB 1.0.0 2014-08-25 70 content.7z 99cf24c71559c75dfae9933826ed16051fca6ea1 componentE Component E (forced) This is a forced component that is always installed. true 1.0.0 2014-08-25 60 content.7z 926bf503ccdff93351744843a95e5e2172cad5ec componentF Component F This component contains 2 subcomponents. 1.0.0 2014-08-25 40 content.7z e6443a8b5a5651f63c0604cae6d32431ca617f1a componentF.subcomponent1 Subcomponent 1 This component contains 2 leaf components. 1.0.0 2014-08-25 100 content.7z a3bc5dce1c93add30c22e46436396c66b0b51001 componentF.subcomponent1.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z ebe4d69414a1675a7f46887e15d9bffc275b7cc4 componentF.subcomponent1.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z e4379d20320d4c173b2d8e228f5722e3f36e3114 componentF.subcomponent2 Subcomponent 2 This component contains 2 leaf components. 1.0.0 2014-08-25 50 content.7z 6462be25912c490569a7c4f3931d978e78c69dc4 componentF.subcomponent2.subsubcomponent1 Subsubcomponent 1 This component does not depend on any other component. 1.0.0 2014-08-25 100 content.7z 72b224bc8f3431210834ce6db373fc8d638a3546 componentF.subcomponent2.subsubcomponent2 Subsubcomponent 2 This component does not depend on any other component. 1.0.0 2014-08-25 50 content.7z 3e2744edaef06af75b3248d5935523a6e2e61551 componentG Component G (default, depends on A, dependency added dynamically) By default, this component is selected for installation. It depends on component A. Dependency is added from inside component script. true 1.0.0 2014-08-25 30 content.7z 8cba36dd589492c28e0d04942b4f8aa0a09f59cc ././@LongLink0040777000000000000000000000015613761647206010123 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0040777000000000000000000000000013761647206031107 5ustar00././@LongLink0040777000000000000000000000017113761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/componentA/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0040777000000000000000000000000013761647206031107 5ustar00././@LongLink0040777000000000000000000000020513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/componentAutoDependOnA/qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0040777000000000000000000000000013761647206031107 5ustar00././@LongLink0100777000000000000000000000022213761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/componentAutoDependOnA/1.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0100777000000000000000000000041113761647206031105 0ustar007zžŊ'Ráįƒ?ŠtHCé:This file will be installed into the target directory....  ? !! ; KIčœ AinstallContentAutoDependOnA.txt >>eá<–Ö >>eá<–Ö ­Ö8ĒÕęÕ ././@LongLink0100777000000000000000000000021013761647206010107 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/componentA/3.0.0content.7zqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0100777000000000000000000000040113761647206031104 0ustar007zžŊ'Abc?ĒrDjt:This file will be installed into the target directory....  ? !! ; KIčœ 7installcontentA_update.txt Ĉ8ĒÕęÕ Ĉ8ĒÕęÕ ļŊ8ĒÕęÕ ././@LongLink0100777000000000000000000000017113761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyToEssential/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/data/repositoryWithDependencyTo0100777000000000000000000000177413761647206031122 0ustar00 {AnyApplication} 1.0.0 false componentA Component A This component does not depend on any other component. 3.0.0 2015-08-25 100 true content.7z componentAutoDependOnA Component, autodepends on A Component, autodepends on A 1.0 2018-03-14 componentA content.7z qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/settings.qrc0100777000000000000000000000601413761647206025250 0ustar00 data/config.xml data/installPackagesRepository/Updates.xml data/installPackagesRepository/componentA/1.0.0content.7z data/installPackagesRepository/componentB/1.0.0content.7z data/installPackagesRepository/componentC/1.0.0content.7z data/installPackagesRepository/componentD/1.0.0content.7z data/installPackagesRepository/componentE/1.0.0content.7z data/installPackagesRepository/componentF/1.0.0content.7z data/installPackagesRepository/componentG/1.0.0content.7z data/installPackagesRepository/componentG/1.0.0meta.7z data/installPackagesRepository/componentF.subcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent1.subsubcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7z data/installPackagesRepositoryUpdate/Updates.xml data/installPackagesRepositoryUpdate/componentA/2.0.0content.7z data/installPackagesRepositoryUpdate/componentB/2.0.0content.7z data/installPackagesRepositoryUpdate/componentC/2.0.0content.7z data/installPackagesRepositoryUpdate/componentD/2.0.0content.7z data/installPackagesRepositoryUpdate/componentE/2.0.0content.7z data/installPackagesRepositoryUpdate/componentF/2.0.0content.7z data/installPackagesRepositoryUpdate/componentG/2.0.0content.7z data/installPackagesRepositoryUpdate/componentG/2.0.0meta.7z data/installPackagesRepositoryUpdate/componentF.subcomponent1/1.0.0content.7z data/installPackagesRepositoryUpdate/componentF.subcomponent2/2.0.0content.7z data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent1/1.0.0content.7z data/installPackagesRepositoryUpdate/componentF.subcomponent1.subsubcomponent2/1.0.0content.7z data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent1/1.0.0content.7z data/installPackagesRepositoryUpdate/componentF.subcomponent2.subsubcomponent2/1.0.0content.7z data/repositoryWithDependencyToEssential/Updates.xml data/repositoryWithDependencyToEssential/componentAutoDependOnA/1.0content.7z data/repositoryWithDependencyToEssential/componentA/3.0.0content.7z qt-installer-framework-4.0.1/tests/auto/installer/commandlineupdate/tst_commandlineupdate.cpp0100777000000000000000000002513613761647206027776 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include "../shared/verifyinstaller.h" #include #include #include #include using namespace QInstaller; class tst_CommandLineUpdate : public QObject { Q_OBJECT private: void setRepository(const QString &repository) { core->reset(); core->cancelMetaInfoJob(); //Call cancel to reset metadata so that update repositories are fetched QSet repoList; Repository repo = Repository::fromUserInput(repository); repoList.insert(repo); core->settings().setDefaultRepositories(repoList); } private slots: void initTestCase() { m_installDir = QInstaller::generateTemporaryFileName(); core = PackageManager::getPackageManagerWithInit(m_installDir); } void testInstallWhenEssentialUpdate() { setRepository(":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << "componentA")); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); core->commitSessionOperations(); core->setPackageManager(); setRepository(":///data/installPackagesRepositoryUpdate"); QCOMPARE(PackageManagerCore::ForceUpdate, core->installSelectedComponentsSilently(QStringList() << "componentB")); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontent.txt" << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } void testUpdateEssentialPackageSilently() { QCOMPARE(PackageManagerCore::EssentialUpdated, core->updateComponentsSilently(QStringList())); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentA_update.txt" << "installcontentE.txt" << "installcontentG.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentA", "1.0.0content.txt"); //As we are using the same core in tests, clean the essentalupdate value core->setFoundEssentialUpdate(false); } void testUpdateEssentialWithAutodependOnSilently() { setRepository(":///data/repositoryWithDependencyToEssential"); QCOMPARE(PackageManagerCore::EssentialUpdated, core->updateComponentsSilently(QStringList())); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "3.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentAutoDependOnA", "1.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentA_update.txt" << "installcontentE.txt" << "installcontentG.txt" << "installContentAutoDependOnA.txt"); //As we are using the same core in tests, clean the essentalupdate value core->setFoundEssentialUpdate(false); } void testUpdatePackageSilently() { setRepository(":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << "componentB")); QCOMPARE(PackageManagerCore::Success, core->status()); VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "3.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentAutoDependOnA", "1.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentA_update.txt" << "installcontentE.txt" << "installcontentG.txt" << "installcontentB.txt" << "installcontentD.txt" << "installContentAutoDependOnA.txt"); core->commitSessionOperations(); setRepository(":///data/installPackagesRepositoryUpdate"); QCOMPARE(PackageManagerCore::Success, core->updateComponentsSilently(QStringList() << "componentB")); // componentD is autodependent and cannot be deselected // componentE is a forced component and thus will be updated VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "3.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentAutoDependOnA", "1.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentD", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentE", "1.0.0content.txt"); VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" << "installcontentA_update.txt" << "installcontentE_update.txt" << "installcontentG.txt" << "installcontentB_update.txt" << "installcontentD_update.txt" << "installContentAutoDependOnA.txt"); } void testUpdateNoUpdatesForSelectedPackage() { setRepository(":///data/installPackagesRepositoryUpdate"); // Succeeds as no updates available for component so nothing to do QCOMPARE(PackageManagerCore::Success, core->updateComponentsSilently(QStringList() << "componentInvalid")); } void testUpdateTwoPackageSilently() { setRepository(":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << "componentA" << "componentB" << "componentG")); VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "1.0.0content.txt"); core->commitSessionOperations(); setRepository(":///data/installPackagesRepositoryUpdate"); QCOMPARE(PackageManagerCore::Success, core->updateComponentsSilently(QStringList() << "componentB" << "componentG")); VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentG", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentB", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentG", "1.0.0content.txt"); } void testUpdateAllPackagesSilently() { setRepository(":///data/installPackagesRepository"); QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() << "componentA" << "componentB" << "componentG" << "componentF")); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent1", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent1.subsubcomponent1", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent2", "1.0.0content.txt"); core->commitSessionOperations(); setRepository(":///data/installPackagesRepositoryUpdate"); QCOMPARE(PackageManagerCore::Success, core->updateComponentsSilently(QStringList())); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResources(m_installDir, "componentF.subcomponent2", "2.0.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentF", "1.0.0content.txt"); VerifyInstaller::verifyInstallerResourceFileDeletion(m_installDir, "componentF.subcomponent2", "1.0.0content.txt"); } void cleanupTestCase() { QDir dir(m_installDir); QVERIFY(dir.removeRecursively()); delete core; } private: QString m_installDir; PackageManagerCore *core; }; QTEST_MAIN(tst_CommandLineUpdate) #include "tst_commandlineupdate.moc" qt-installer-framework-4.0.1/tests/auto/installer/compareversion/0040777000000000000000000000000013761647206022243 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/compareversion/compareversion.pro0100777000000000000000000000011113761647206026012 0ustar00include(../../qttest.pri) QT -= gui SOURCES += tst_compareversion.cpp qt-installer-framework-4.0.1/tests/auto/installer/compareversion/tst_compareversion.cpp0100777000000000000000000000725613761647206026707 0ustar00/************************************************************************** ** ** Copyright (C) 2017 Konstantin Podsvirov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "updater.h" #include class tst_CompareVersion : public QObject { Q_OBJECT private slots: void compareVersion(); void compareVersionX(); void compareVersionAll(); void compareVersionExtra(); }; void tst_CompareVersion::compareVersion() { QCOMPARE(KDUpdater::compareVersion("2.0", "2.1"), -1); QCOMPARE(KDUpdater::compareVersion("2.1", "2.0"), +1); QCOMPARE(KDUpdater::compareVersion("2.0", "2.0"), 0); QCOMPARE(KDUpdater::compareVersion("2.1", "2.1"), 0); QCOMPARE(KDUpdater::compareVersion("2.1", "2.1-201903190747"), -1); QCOMPARE(KDUpdater::compareVersion("2.1-201903190747", "2.1"), +1); QCOMPARE(KDUpdater::compareVersion("2.1-201903190747", "2.1-201903190747"), 0); QCOMPARE(KDUpdater::compareVersion("2.1-0", "2.1-201903190747"), -1); QCOMPARE(KDUpdater::compareVersion("2.1-201903190747", "2.1-0"), +1); QCOMPARE(KDUpdater::compareVersion("2.0.12.4", "2.1.10.4"), -1); } void tst_CompareVersion::compareVersionX() { QCOMPARE(KDUpdater::compareVersion("2.0", "2.x"), 0); QCOMPARE(KDUpdater::compareVersion("2.x", "2.0"), 0); QCOMPARE(KDUpdater::compareVersion("2.0.12.x", "2.0.x"), 0); QCOMPARE(KDUpdater::compareVersion("2.1.12.x", "2.0.x"), +1); QCOMPARE(KDUpdater::compareVersion("2.1.12.x", "2.x"), 0); QCOMPARE(KDUpdater::compareVersion("2.x", "2.1.12.x"), 0); } void tst_CompareVersion::compareVersionAll() { QCOMPARE(KDUpdater::compareVersion("version-1", "version-2"), -1); QCOMPARE(KDUpdater::compareVersion("v2.0", "v2.x"), 0); QCOMPARE(KDUpdater::compareVersion("v2.x", "v2.0"), 0); QCOMPARE(KDUpdater::compareVersion("v2.0-alpha", "v2.0-alpha"), 0); QCOMPARE(KDUpdater::compareVersion("v2.0-alpha", "v2.0-beta"), -1); QCOMPARE(KDUpdater::compareVersion("v2.0-beta", "v2.0-alpha"), +1); QCOMPARE(KDUpdater::compareVersion("v2.0-rc1", "v2.0-beta"), +1); QCOMPARE(KDUpdater::compareVersion("v2.0-rc1", "v2.0-rc2"), -1); QCOMPARE(KDUpdater::compareVersion("v2.0-rc2", "v2.0-rc11"), -1); QCOMPARE(KDUpdater::compareVersion("v2.0-rc22", "v2.0-rc2"), +1); QCOMPARE(KDUpdater::compareVersion("v2.0", "v2.0-rc3"), +1); } void tst_CompareVersion::compareVersionExtra() { QCOMPARE(KDUpdater::compareVersion("OpenSSL_1_0_2k", "OpenSSL_1_0_2l"), -1); QCOMPARE(KDUpdater::compareVersion("OpenSSL_1_1_0f", "OpenSSL_1_0_2k"), +1); } QTEST_MAIN(tst_CompareVersion) #include "tst_compareversion.moc" qt-installer-framework-4.0.1/tests/auto/installer/componentidentifier/0040777000000000000000000000000013761647206023254 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/componentidentifier/componentidentifier.pro0100777000000000000000000000011613761647206030041 0ustar00include(../../qttest.pri) QT -= gui SOURCES += tst_componentidentifier.cpp qt-installer-framework-4.0.1/tests/auto/installer/componentidentifier/tst_componentidentifier.cpp0100777000000000000000000002074713761647206030731 0ustar00/************************************************************************** ** ** Copyright (C) 2017 Konstantin Podsvirov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include using namespace QInstaller; class NamedComponent : public Component { public: NamedComponent(PackageManagerCore *core, const QString &name) : Component(core) { setValue(scName, name); setValue(scVersion, QLatin1String("1.0.0")); } NamedComponent(PackageManagerCore *core, const QString &name, const QString &version) : Component(core) { setValue(scName, name); setValue(scVersion, version); } }; class tst_ComponentIdentifier : public QObject { Q_OBJECT private slots: void testPackageManagerCoreSetterGetter_data(); void testPackageManagerCoreSetterGetter(); void testComponentDependencies(); }; void tst_ComponentIdentifier::testPackageManagerCoreSetterGetter_data() { const char *tag = 0; QTest::addColumn("core"); QTest::addColumn("requirements"); QTest::addColumn >("expectedResult"); PackageManagerCore *core = 0; QStringList req; // requirements; QList res; // expectedResult; tag = "Alphabetic name"; core = 0; req.clear(); res.clear(); { core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentRoot = new NamedComponent(core, QLatin1String("root")); core->appendRootComponent(componentRoot); req << QLatin1String("root"); res << componentRoot; } QTest::newRow(tag) << core << req << res; tag = "Alphabetic name, dash (-) and numbered version"; core = 0; req.clear(); res.clear(); { core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentRoot = new NamedComponent(core, QLatin1String("root"), QLatin1String("1.0.1")); core->appendRootComponent(componentRoot); req << QLatin1String("root-1.0.1"); res << componentRoot; req << QLatin1String("root->1"); res << componentRoot; req << QLatin1String("root-<2"); res << componentRoot; req << QLatin1String("root-"); res << componentRoot; } QTest::newRow(tag) << core << req << res; tag = "Alphabetic name, colon (:) and numbered version"; core = 0; req.clear(); res.clear(); { core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentRoot = new NamedComponent(core, QLatin1String("root"), QLatin1String("1.0.1")); core->appendRootComponent(componentRoot); req << QLatin1String("root:1.0.1"); res << componentRoot; req << QLatin1String("root:>1"); res << componentRoot; req << QLatin1String("root:<2"); res << componentRoot; req << QLatin1String("root:"); res << componentRoot; } QTest::newRow(tag) << core << req << res; tag = "Kebab-case name, dash (-) and numbered version"; core = 0; req.clear(); res.clear(); { core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentSdk = new NamedComponent(core, QLatin1String("org.qt-project.sdk.qt"), QLatin1String("4.5")); NamedComponent *componentQt = new NamedComponent(core, QLatin1String("org.qt"), QLatin1String("project.sdk.qt->=4.5")); componentQt->appendComponent(componentSdk); core->appendRootComponent(componentQt); // this example has been present for many years in // the PackageManagerCore::componentByName() method documentation, // but it does not work as expected // in this case, name is "org.qt" and version is "project.sdk.qt->=4.5" req << QLatin1String("org.qt-project.sdk.qt->=4.5"); res << componentQt; // and you expected componentSdk? } QTest::newRow(tag) << core << req << res; tag = "Kebab-case name, colon (:) and numbered version"; core = 0; req.clear(); res.clear(); { core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentSdk = new NamedComponent(core, QLatin1String("org.qt-project.sdk.qt"), QLatin1String("4.5")); core->appendRootComponent(componentSdk); req << QLatin1String("org.qt-project.sdk.qt:>=4.5"); res << componentSdk; // work as expected req << QLatin1String("org.qt-project.sdk.qt"); res << 0; // we should fix names with dash (-) while support dash (-) as separator req << PackageManagerCore::checkableName(QLatin1String("org.qt-project.sdk.qt")); res << componentSdk; } QTest::newRow(tag) << core << req << res; } void tst_ComponentIdentifier::testPackageManagerCoreSetterGetter() { QFETCH(PackageManagerCore *, core); QFETCH(QStringList, requirements); QFETCH(QList, expectedResult); QCOMPARE(requirements.count(), expectedResult.count()); for (int i = 0; i < requirements.count(); ++i) { QCOMPARE(core->componentByName(requirements.at(i)), expectedResult.at(i)); } delete core; } void tst_ComponentIdentifier::testComponentDependencies() { PackageManagerCore *core = new PackageManagerCore(); core->setPackageManager(); Component *componentA = new NamedComponent(core, "A"); Component *componentB = new NamedComponent(core, "B"); Component *componentC = new NamedComponent(core, "component-C"); Component *componentD = new NamedComponent(core, "D-backward-compatibility"); Component *componentE = new NamedComponent(core, "E"); componentA->addDependency("B-1.0.0"); componentA->addDependency("component-C:1.0.0"); componentA->addDependency("D-backward-compatibility:"); componentE->addAutoDependOn("B-1.0.0"); componentE->addAutoDependOn("component-C:1.0.0"); componentE->addAutoDependOn("D-backward-compatibility:"); core->appendRootComponent(componentA); core->appendRootComponent(componentB); core->appendRootComponent(componentC); core->appendRootComponent(componentD); core->appendRootComponent(componentE); QList expectedResult = QList() << componentB << componentC << componentD; QList dependencies; foreach (const QString &identifier, componentA->dependencies()) { dependencies.append(core->componentByName(identifier)); } QCOMPARE(expectedResult, dependencies); QList autoDependOn; foreach (const QString &identifier, componentE->autoDependencies()) { autoDependOn.append(core->componentByName(identifier)); } QCOMPARE(expectedResult, autoDependOn); delete core; } QTEST_MAIN(tst_ComponentIdentifier) #include "tst_componentidentifier.moc" qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/0040777000000000000000000000000013761647206022232 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/componentmodel.pro0100777000000000000000000000017313761647206026000 0ustar00include(../../qttest.pri) QT -= gui QT += network xml qml SOURCES += tst_componentmodel.cpp RESOURCES += components.qrc qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/components.qrc0100777000000000000000000000013713761647206025127 0ustar00 data/updates.xml qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/data/0040777000000000000000000000000013761647206023143 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/data/updates.xml0100777000000000000000000001617213761647206025341 0ustar00 Your application 1.2.3 true com.vendor.product The root component КÐūŅ€Ð―ÐĩÐēÐ°Ņ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð° Wurzel Komponente Install this example. 0.1.0-1 2010-09-21 true 1 true com.vendor.second.product The second root component Install this example. 0.1.0-1 2010-09-21 false 1 com.vendor.second.product.subnode A sub node component for the second root Install this example. 0.1.0-1 2010-09-21 false 1 com.vendor.second.product.subnode.sub A subcomponent for the second sub node of the second root Install this example. 0.1.0-1 2010-09-21 false 1 com.vendor.second.product.sub A subcomponent for the second root Install this example. 0.1.0-1 2010-09-21 true com.vendor.second.product.sub1 A subcomponent for the second root Install this example. 0.1.0-1 2010-09-21 false com.vendor.second.product.virtual A virtual subcomponent for the second root Install this example. 0.1.0-1 2010-09-21 true com.vendor.third.product.virtual A virtual root component Install this example. 0.1.0-1 2010-09-21 true 0 true com.vendor.fourth.product.checkable A checkable root component Install this example. 0.1.0-1 2010-09-21 true false com.vendor.fifth.product.noncheckable A non-checkable root component Install this example. 0.1.0-1 2010-09-21 false com.vendor.fifth.product.noncheckable.sub A sub component for non-checkable root component Install this example. 0.1.0-1 2010-09-21 0 qt-installer-framework-4.0.1/tests/auto/installer/componentmodel/tst_componentmodel.cpp0100777000000000000000000006023713761647206026663 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "component.h" #include "componentmodel.h" #include "updatesinfo_p.h" #include "packagemanagercore.h" #include #include using namespace KDUpdater; using namespace QInstaller; #define EXPECTED_COUNT_VIRTUALS_VISIBLE 11 #define EXPECTED_COUNT_VIRTUALS_INVISIBLE 10 static const char vendorProduct[] = "com.vendor.product"; static const char vendorSecondProduct[] = "com.vendor.second.product"; static const char vendorSecondProductSub[] = "com.vendor.second.product.sub"; static const char vendorSecondProductSub1[] = "com.vendor.second.product.sub1"; static const char vendorSecondProductVirtual[] = "com.vendor.second.product.virtual"; static const char vendorSecondProductSubnode[] = "com.vendor.second.product.subnode"; static const char vendorSecondProductSubnodeSub[] = "com.vendor.second.product.subnode.sub"; static const char vendorThirdProductVirtual[] = "com.vendor.third.product.virtual"; static const char vendorFourthProductCheckable[] = "com.vendor.fourth.product.checkable"; static const char vendorFifthProductNonCheckable[] = "com.vendor.fifth.product.noncheckable"; static const char vendorFifthProductSub[] = "com.vendor.fifth.product.noncheckable.sub"; static const QMap rootComponentDisplayNames = { {"", QLatin1String("The root component")}, {"ru_ru", QString::fromUtf8("КÐūŅ€Ð―ÐĩÐēÐ°Ņ КÐūОÐŋÐūÐ―ÐĩÐ―Ņ‚Ð°")}, {"de_de", QString::fromUtf8("Wurzel Komponente")} }; class tst_ComponentModel : public QObject { Q_OBJECT public: enum Option { NoFlags = 0x00, VirtualsVisible = 0x01, NoForcedInstallation = 0x02, NoDefaultInstallation = 0x04 }; Q_DECLARE_FLAGS(Options, Option); private slots: void initTestCase() { m_defaultChecked << vendorProduct << vendorSecondProductSub; m_defaultPartially << vendorSecondProduct; m_defaultUnchecked << vendorSecondProductSub1 << vendorSecondProductSubnode << vendorSecondProductSubnodeSub << vendorFourthProductCheckable << vendorFifthProductSub; m_uncheckable << vendorFifthProductNonCheckable; } void testNameToIndexAndIndexToName() { setPackageManagerOptions(NoFlags); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); // all names should be resolvable, virtual components are not indexed if they are not visible QStringList all; all << m_defaultChecked << m_defaultPartially << m_defaultUnchecked << m_uncheckable; foreach (const QString &name, all) { QVERIFY(model.indexFromComponentName(name).isValid()); QVERIFY(model.componentFromIndex(model.indexFromComponentName(name)) != 0); QCOMPARE(model.componentFromIndex(model.indexFromComponentName(name))->name(), name); } foreach (Component *const component, rootComponents) delete component; } void testNameToIndexAndIndexToNameVirtualsVisible() { setPackageManagerOptions(VirtualsVisible); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); // all names should be resolvable, including virtual components QStringList all; all << m_defaultChecked << m_defaultPartially << m_defaultUnchecked << m_uncheckable << vendorSecondProductVirtual << vendorThirdProductVirtual; foreach (const QString &name, all) { QVERIFY(model.indexFromComponentName(name).isValid()); QVERIFY(model.componentFromIndex(model.indexFromComponentName(name)) != 0); QCOMPARE(model.componentFromIndex(model.indexFromComponentName(name))->name(), name); } foreach (Component *const component, rootComponents) delete component; } void testDefault() { setPackageManagerOptions(NoFlags); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); QCOMPARE(model.core(), &m_core); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable); foreach (Component *const component, rootComponents) delete component; } void testVirtualsVisible() { setPackageManagerOptions(VirtualsVisible); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); // the virtual and non-checkable components are not checked testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual); foreach (Component *const component, rootComponents) delete component; } void testNoForcedInstallation() { setPackageManagerOptions(NoForcedInstallation); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable); foreach (Component *const component, rootComponents) delete component; } void testVirtualsVisibleNoForcedInstallation() { setPackageManagerOptions(Options(VirtualsVisible | NoForcedInstallation)); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); // the virtual components are not checked testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual); foreach (Component *const component, rootComponents) delete component; } void testSelect() { setPackageManagerOptions(NoFlags); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); // select all possible components. // Also uncheckable is checked as that is only 'visually' uncheckedable. model.setCheckedState(ComponentModel::AllChecked); QCOMPARE(model.checkedState(), ComponentModel::AllChecked); testModelState(&model, m_defaultChecked + m_defaultPartially + m_defaultUnchecked + m_uncheckable, QStringList(), QStringList()); // deselect all possible components // as the first root is a forced install, should result in partially checked state model.setCheckedState(ComponentModel::AllUnchecked); QCOMPARE(model.checkedState(), ComponentModel::PartiallyChecked); testModelState(&model, QStringList() << vendorProduct, QStringList(), m_defaultPartially + m_defaultUnchecked + QStringList(vendorSecondProductSub) + m_uncheckable); // reset all possible components model.setCheckedState(ComponentModel::DefaultChecked); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable); foreach (Component *const component, rootComponents) delete component; } void testSelectVirtualsVisible() { setPackageManagerOptions(VirtualsVisible); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); // select all possible components. model.setCheckedState(ComponentModel::AllChecked); QCOMPARE(model.checkedState(), ComponentModel::AllChecked); testModelState(&model, m_defaultChecked + m_defaultPartially + m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual, QStringList(), QStringList()); // deselect all possible components // as the first root is a forced install, should result in partially checked state model.setCheckedState(ComponentModel::AllUnchecked); QCOMPARE(model.checkedState(), ComponentModel::PartiallyChecked); testModelState(&model, QStringList() << vendorProduct, QStringList(), m_defaultPartially + m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductSub) << vendorSecondProductVirtual << vendorThirdProductVirtual); // reset all possible components model.setCheckedState(ComponentModel::DefaultChecked); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual); foreach (Component *const component, rootComponents) delete component; } void testSelectNoForcedInstallation() { setPackageManagerOptions(NoForcedInstallation); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); // select all possible components. model.setCheckedState(ComponentModel::AllChecked); QCOMPARE(model.checkedState(), ComponentModel::AllChecked); testModelState(&model, m_defaultChecked + m_defaultPartially + m_defaultUnchecked+ m_uncheckable, QStringList(), QStringList()); // deselect all possible components model.setCheckedState(ComponentModel::AllUnchecked); QCOMPARE(model.checkedState(), ComponentModel::AllUnchecked); testModelState(&model, QStringList(), QStringList(), m_defaultPartially + m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductSub) << vendorProduct); // reset all possible components model.setCheckedState(ComponentModel::DefaultChecked); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable); foreach (Component *const component, rootComponents) delete component; } void testSelectVirtualsVisibleNoForcedInstallation() { setPackageManagerOptions(Options(VirtualsVisible | NoForcedInstallation)); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); // select all possible components. model.setCheckedState(ComponentModel::AllChecked); QCOMPARE(model.checkedState(), ComponentModel::AllChecked); testModelState(&model, m_defaultChecked + m_defaultPartially + m_defaultUnchecked +m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual, QStringList(), QStringList()); // deselect all possible components model.setCheckedState(ComponentModel::AllUnchecked); QCOMPARE(model.checkedState(), ComponentModel::AllUnchecked); testModelState(&model, QStringList(), QStringList(), m_defaultPartially + m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductSub) << vendorSecondProductVirtual << vendorProduct << vendorThirdProductVirtual); // reset all possible components model.setCheckedState(ComponentModel::DefaultChecked); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, m_defaultChecked, m_defaultPartially, m_defaultUnchecked + m_uncheckable + QStringList(vendorSecondProductVirtual) << vendorThirdProductVirtual); foreach (Component *const component, rootComponents) delete component; } void testComponentsLocalization() { QStringList localesToTest = { "en_US", "ru_RU", "de_DE", "fr_FR" }; foreach (const QString &localeToTest, localesToTest) { QLocale::setDefault(localeToTest); QString expectedName = rootComponentDisplayNames.contains(localeToTest.toLower()) ? rootComponentDisplayNames[localeToTest.toLower()] : rootComponentDisplayNames[QString()]; setPackageManagerOptions(NoFlags); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); const QModelIndex root = model.indexFromComponentName(vendorProduct); QCOMPARE(model.data(root, Qt::DisplayRole).toString(), expectedName); qDeleteAll(rootComponents); } } void testNoDefaultInstallation() { setPackageManagerOptions(NoDefaultInstallation); QList rootComponents = loadComponents(); testComponentsLoaded(rootComponents); // setup the model with 1 column ComponentModel model(1, &m_core); model.setRootComponents(rootComponents); testDefaultInheritedModelBehavior(&model, 1); model.setCheckedState(ComponentModel::DefaultChecked); QCOMPARE(model.checkedState(), ComponentModel::DefaultChecked); testModelState(&model, QStringList() << vendorProduct, QStringList(), m_defaultUnchecked + m_uncheckable + m_defaultPartially + QStringList() << vendorSecondProductSub); } private: void setPackageManagerOptions(Options flags) const { m_core.setNoForceInstallation(flags.testFlag(NoForcedInstallation)); m_core.setVirtualComponentsVisible(flags.testFlag(VirtualsVisible)); m_core.setNoDefaultInstallation(flags.testFlag(NoDefaultInstallation)); } void testComponentsLoaded(const QList &rootComponents) const { // we need to have five root components QCOMPARE(rootComponents.count(), 5); QList components = rootComponents; foreach (Component *const component, rootComponents) components.append(component->childItems()); // will differ between 6 and 7 components, (2 root nodes, 1 sub node, 3 non virtual and 1 virtual) QCOMPARE(components.count(), m_core.virtualComponentsVisible() ? EXPECTED_COUNT_VIRTUALS_VISIBLE : EXPECTED_COUNT_VIRTUALS_INVISIBLE); } void testDefaultInheritedModelBehavior(ComponentModel *model, int columnCount) const { // row count with invalid model index should return: if (m_core.virtualComponentsVisible()) QCOMPARE(model->rowCount(), 5); // 5 (4 non virtual and 1 virtual root component) else QCOMPARE(model->rowCount(), 4); // 4 (the 4 non virtual root components) QCOMPARE(model->columnCount(), columnCount); const QModelIndex firstParent = model->indexFromComponentName(vendorProduct); const QModelIndex secondParent = model->indexFromComponentName(vendorSecondProduct); const QModelIndex thirdParent = model->indexFromComponentName(vendorThirdProductVirtual); // return invalid indexes, as they are the root components QCOMPARE(model->parent(firstParent), QModelIndex()); QCOMPARE(model->parent(secondParent), QModelIndex()); QCOMPARE(model->parent(thirdParent), QModelIndex()); // test valid indexes QVERIFY(firstParent.isValid()); QVERIFY(secondParent.isValid()); QVERIFY(model->indexFromComponentName(vendorSecondProductSub).isValid()); QVERIFY(model->indexFromComponentName(vendorSecondProductSub1).isValid()); QVERIFY(model->indexFromComponentName(vendorSecondProductSubnode).isValid()); QVERIFY(model->indexFromComponentName(vendorSecondProductSubnodeSub).isValid()); // they should have the same parent QCOMPARE(model->parent(model->indexFromComponentName(vendorSecondProductSub)), secondParent); QCOMPARE(model->parent(model->indexFromComponentName(vendorSecondProductSub1)), secondParent); QCOMPARE(model->parent(model->indexFromComponentName(vendorSecondProductSubnode)), secondParent); const QModelIndex forthParent = model->indexFromComponentName(vendorSecondProductSubnode); QCOMPARE(model->parent(model->indexFromComponentName(vendorSecondProductSubnodeSub)), forthParent); // row count should be 0, as they have no children QCOMPARE(model->rowCount(firstParent), 0); QCOMPARE(model->rowCount(model->indexFromComponentName(vendorSecondProductSub)), 0); QCOMPARE(model->rowCount(model->indexFromComponentName(vendorSecondProductSub1)), 0); QCOMPARE(model->rowCount(model->indexFromComponentName(vendorSecondProductSubnodeSub)), 0); if (m_core.virtualComponentsVisible()) { // test valid index QVERIFY(thirdParent.isValid()); QCOMPARE(model->rowCount(thirdParent), 0); QVERIFY(model->indexFromComponentName(vendorSecondProductVirtual).isValid()); QCOMPARE(model->rowCount(model->indexFromComponentName(vendorSecondProductVirtual)), 0); QCOMPARE(model->parent(model->indexFromComponentName(vendorSecondProductVirtual)), secondParent); // row count should be 4, (2 standard, 1 virtual, 1 sub node) QCOMPARE(model->rowCount(secondParent), 4); } else { // test invalid index QVERIFY(!thirdParent.isValid()); // row count should be 3, (2 standard, 1 sub node, omit the virtual) QCOMPARE(model->rowCount(secondParent), 3); } // row count should be 1, 1 sub node QCOMPARE(model->rowCount(model->indexFromComponentName(vendorSecondProductSubnode)), 1); } void testModelState(ComponentModel *model, const QStringList &checked, const QStringList &partially, const QStringList &unchecked) const { QCOMPARE(model->checked().count(), checked.count()); QCOMPARE(model->partially().count(), partially.count()); QCOMPARE(model->unchecked().count(), unchecked.count()); // these components should have checked state foreach (Component *const component, model->checked()) QVERIFY(checked.contains(component->name())); // these components should not have partially checked state foreach (Component *const component, model->partially()) QVERIFY(partially.contains(component->name())); // these components should not have checked state foreach (Component *const component, model->unchecked()) QVERIFY(unchecked.contains(component->name())); } QList loadComponents() const { UpdatesInfo updatesInfo; updatesInfo.setFileName(":///data/updates.xml"); const QList updateInfos = updatesInfo.updatesInfo(); QHash components; foreach (const UpdateInfo &info, updateInfos) { Component *component = new Component(const_cast(&m_core)); // we need at least these to be able to test the model component->setValue("Name", info.data.value("Name").toString()); QString isDefault = info.data.value("Default").toString(); if (m_core.noDefaultInstallation()) isDefault = scFalse; component->setValue("Default", isDefault); component->setValue("Virtual", info.data.value("Virtual").toString()); component->setValue("DisplayName", info.data.value("DisplayName").toString()); component->setValue("Checkable", info.data.value("Checkable").toString()); QString forced = info.data.value("ForcedInstallation", scFalse).toString().toLower(); if (m_core.noForceInstallation()) forced = scFalse; component->setValue("ForcedInstallation", forced); if (forced == scTrue) { component->setEnabled(false); component->setCheckable(false); component->setCheckState(Qt::Checked); } components.insert(component->name(), component); } QList rootComponents; foreach (QString id, components.keys()) { QInstaller::Component *component = components.value(id); while (!id.isEmpty() && component->parentComponent() == 0) { id = id.section(QLatin1Char('.'), 0, -2); if (components.contains(id)) components[id]->appendComponent(component); } } foreach (QInstaller::Component *component, components) { if (component->parentComponent() == 0) rootComponents.append(component); if (component->isCheckable() && component->isDefault() && (!component->isTristate())) component->setCheckState(Qt::Checked); } return rootComponents; } private: PackageManagerCore m_core; QStringList m_defaultChecked; QStringList m_defaultPartially; QStringList m_defaultUnchecked; QStringList m_uncheckable; QStringList m_defaultNoChecked; }; Q_DECLARE_OPERATORS_FOR_FLAGS(tst_ComponentModel::Options) QTEST_MAIN(tst_ComponentModel) #include "tst_componentmodel.moc" qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/0040777000000000000000000000000013761647206024762 5ustar00././@LongLink0100777000000000000000000000015413761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/consumeoutputoperationtest.proqt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/consumeoutputoperation0100777000000000000000000000034313761647206031560 0ustar00include(../../qttest.pri) QT -= gui QT += testlib qml SOURCES = tst_consumeoutputoperationtest.cpp DEFINES += "QMAKE_BINARY=$$fromNativeSeparators($$QMAKE_BINARY)" RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/0040777000000000000000000000000013761647206025673 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/0040777000000000000000000000000013761647206030112 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/A/0040777000000000000000000000000013761647206030272 5ustar00././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/A/1.0.0100777000000000000000000000157613761647206030602 0ustar007zžŊ'ÕUÝ~=!éĖā%Ô]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũėÂvūÍ;‚=tˆ;!-äŲÉĩÄw? â$vé'€SéĨŽV ‚I>aãK3č č·E žŠÉ ĻôčÅ| 6v “$ĶÎø—Áōú›&ĒäųėĻx 3ŪÕGēX$Óþģp@mQ)ŧÄ^į|AÅĩÎ"üéTМ‹1ĪS\Å *`Ø•w>uą"ĨĸAņ†SZūs1Črē°|Ņĩũݑ―â„˜/‚Ü a #] n 3’ßÍ././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/data/repository/Update0100777000000000000000000000062613761647206031263 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/settings.qrc0100777000000000000000000000024013761647206027325 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/tst_consumeoutputoperationtest.cppqt-installer-framework-4.0.1/tests/auto/installer/consumeoutputoperationtest/tst_consumeoutputopera0100777000000000000000000001123713761647206031564 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) using namespace KDUpdater; using namespace QInstaller; class tst_consumeoutputoperationtest : public QObject { Q_OBJECT private slots: void initTestCase() { // be aware that this would enable eating the qDebug output //QInstaller::init(); m_fakeQtPath = QDir::toNativeSeparators(qApp->applicationDirPath()) + QDir::separator() + "fakeQt" + QDir::separator(); QVERIFY(QDir().mkpath(m_fakeQtPath + "bin")); m_testOutput = getOutputFrom(QUOTE(QMAKE_BINARY), QStringList("-query")); qputenv("qmakePath", QUOTE(QMAKE_BINARY)); //Read from script } void testMissingArguments() { ConsumeOutputOperation operation(nullptr); QVERIFY(operation.testOperation()); QVERIFY(!operation.performOperation()); // undo does nothing so this should be true QVERIFY(operation.undoOperation()); QCOMPARE(UpdateOperation::Error(operation.error()), UpdateOperation::InvalidArguments); //qDebug() << operation.errorString(); QString compareString("Invalid arguments in ConsumeOutput: 0 arguments given, at least 2 " "arguments expected in the form: " " [argument1] [argument2] [...]."); //qDebug() << compareString; QCOMPARE(operation.errorString(), compareString); } void testGetOutputFromQmake() { ConsumeOutputOperation operation(&m_core); operation.setArguments(QStringList() << "testConsumeOutputKey" << QUOTE(QMAKE_BINARY) << "-query"); QVERIFY2(operation.performOperation(), qPrintable(operation.errorString())); QCOMPARE(Operation::Error(operation.error()), Operation::NoError); QCOMPARE(m_core.value("testConsumeOutputKey"), m_testOutput); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); QCOMPARE(core->value("testConsumeOutputKeyFromScript"), m_testOutput); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } void cleanupTestCase() { try { removeDirectory(m_fakeQtPath); } catch (const QInstaller::Error &error) { QFAIL(qPrintable(error.message())); } qunsetenv("qmakePath"); } private: QString getOutputFrom(const QString &binary, const QStringList &arguments = QStringList()) { QEventLoop loop; QProcess process; QObject::connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); process.start(binary, arguments, QIODevice::ReadOnly); if (process.state() != QProcess::NotRunning) loop.exec(); return process.readAllStandardOutput(); } PackageManagerCore m_core; QString m_fakeQtPath; QString m_testOutput; }; QTEST_MAIN(tst_consumeoutputoperationtest) #include "tst_consumeoutputoperationtest.moc" qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/0040777000000000000000000000000013761647206024027 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/copydirectoryoperation.pro0100777000000000000000000000023213761647206031366 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_copydirectoryoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/0040777000000000000000000000000013761647206024740 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/0040777000000000000000000000000013761647206027157 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/A/0040777000000000000000000000000013761647206027337 5ustar00././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/A/1.0.2-1c0100777000000000000000000000052413761647206030222 0ustar007zžŊ'Ļ-áŨ"<Ũž3IÖļJ•Mï”žŅŠylއĸþĪ83ŪÏĪ.ļëęž bÓLB?Œ™íëīö‘―}ĒC‡úD&åYÃ*s‘"nO0ĘšĀīO-Č]3v{ÞÅÏÐŌW1(yÛx\ĻīN:ÏĖĢ*ҐkþcĒ‹SƟ 3:•Ø5 `ŧy@úuą+WÐyóeöŸ ŋð!Eņ`01`ÔY7ūÏ cŠ)åޏŌ9”TüÆįvö îž^cw )ĀqĸĄZĄ!5æ•=ŪÅ|Ŧ=æAįÂ)ؚúöŸÚ+ržÓĶhuLå)'Ęä[>°Å%áŅĨîZÍŠ|EP4g ð í?ĸP„Ā €ø #]€ ‚ ÅáŊ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/A/1.0.2-1m0100777000000000000000000000160513761647206030235 0ustar007zžŊ'Ü“dC"Ôv†,ā^Å]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪy"-†ō+_œŠ<ˆĐŨsĀÐŅ!ÖChó†ĘŧCõmŨŌށ3ŪÕG]@W$Óþģp@n&Œ; ”ø6ˇ ŽŧЌ ‚Ä‘­#ĮDĢõ6#“ųšrž I8Ļ!g!mõMē€)îȁÝô_mö{&!ÕÕÏ3Õó‚ģé/Rˆņcs“É(Qîóð-z={A2‚Í v #] €ž Ŋl9ã././@LongLink0100777000000000000000000000014513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/data/repository/Updates.xm0100777000000000000000000000066413761647206031140 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true content.7z qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/settings.qrc0100777000000000000000000000033113761647206026373 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/tst_copydirectoryoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/copydirectoryoperation/tst_copydirectoryoperation0100777000000000000000000001455513761647206031476 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include "../shared/verifyinstaller.h" #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_copydirectoryoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_sourcePath = qApp->applicationDirPath() + QDir::toNativeSeparators("/source/"); m_destinationPath = generateTemporaryFileName() + QDir::toNativeSeparators("_dest/"); } void init() { QDir sourceDir; QVERIFY(sourceDir.mkpath(m_sourcePath)); QDir destinationDir; QVERIFY(destinationDir.mkpath(m_destinationPath)); } void cleanup() { QVERIFY(QDir(m_sourcePath).removeRecursively()); QVERIFY(QDir(m_destinationPath).removeRecursively()); } void testInvalidArguments() { CopyDirectoryOperation op(nullptr); QVERIFY(op.testOperation()); op.backup(); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in CopyDirectory: " "0 arguments given, 2 or 3 arguments expected in the form: " " [\"forceOverwrite\"].")); op.setArguments(QStringList() << "" << "" << "overwrite"); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid argument in CopyDirectory: " "Third argument needs to be forceOverwrite, " "if specified.")); op.setArguments(QStringList() << "" << ""); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid argument in CopyDirectory: " "Directory \"\" is invalid.")); } void testCopyDirectoryWithUndo() { QStringList fileEntries; fileEntries << "file1" << "file2" << ".hidden1" << ".hidden2"; // Populate source directory foreach (const QString &entry, fileEntries) { QFile file(m_sourcePath + entry); QVERIFY(file.open(QFileDevice::ReadWrite)); file.close(); } CopyDirectoryOperation op(nullptr); op.setArguments(QStringList() << m_sourcePath << m_destinationPath); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); foreach (const QString &entry, fileEntries) QVERIFY(QFile(m_destinationPath + entry).exists()); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); // Undo will delete the empty destination directory here QVERIFY(!QFileInfo(m_destinationPath).exists()); } void testCopyDirectoryOverwrite() { QFile file(m_sourcePath + "file"); QVERIFY(file.open(QFileDevice::ReadWrite)); file.close(); file.setFileName(m_destinationPath + "file"); QVERIFY(file.open(QFileDevice::ReadWrite)); file.close(); CopyDirectoryOperation op(nullptr); op.setArguments(QStringList() << m_sourcePath << m_destinationPath); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); op.setArguments(QStringList() << m_sourcePath << m_destinationPath << "forceOverwrite"); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->setValue(scTargetDir, installDir); core->installDefaultComponentsSilently(); // Matches path in component install script QFileInfo targetInfo(installDir + QDir::toNativeSeparators("/directory")); QMap targetMap; VerifyInstaller::addToFileMap(QDir(targetInfo.absoluteFilePath()), targetInfo, targetMap); QFileInfo destinationInfo(installDir + QDir::toNativeSeparators("/destination/directory")); QMap destinationMap; VerifyInstaller::addToFileMap(QDir(destinationInfo.absoluteFilePath()), destinationInfo, destinationMap); QVERIFY(targetMap == destinationMap); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!destinationInfo.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_sourcePath; QString m_destinationPath; }; QTEST_MAIN(tst_copydirectoryoperation) #include "tst_copydirectoryoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/0040777000000000000000000000000013761647206023002 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/copyoperationtest.pro0100777000000000000000000000022413761647206027315 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_copyoperationtest.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/0040777000000000000000000000000013761647206023713 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/0040777000000000000000000000000013761647206026132 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/A/0040777000000000000000000000000013761647206026312 5ustar00././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/A/1.0.2-1conten0100777000000000000000000000027113761647206030240 0ustar007zžŊ'ž‘@'rE*Ņ<"Line to replace. Another line.  ' !! # ·ð°―  A.txt ï•ûÕ ï•ûÕ 6Ą]Ö ././@LongLink0100777000000000000000000000014513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/A/1.0.2-1meta.70100777000000000000000000000157513761647206030055 0ustar007zžŊ'íģ,<!Ĩ])ādÓ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũėÂvūâÓÝĢþEvAUČį„ŒĪIŠĩ]󆮛”ëĐļÎ ž˜x—üÅčTé_J6øhōnĸ―.ÞŽ öœ<,æ6þúķYĻĪāSĐxjËåÄĄ6;3ŪÕGŽŦŨ$Óþģp@n=ŋ ”;ÏŪ[E&íŅ·íʑz ßÅ:ŪäX;ŅS7čx$ÛUnp™hYŋ!ïŨdké‹Gfƒ;CėÜÏþķšÂ_žÜÕÚ-ŦÁŧĒ‚Û a #] n ØÆŸ&qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/data/repository/Updates.xml0100777000000000000000000000111413761647206030256 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true content.7z 6d7a3e15d11a4d94b81452fc2aa18e705a01c922 qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/settings.qrc0100777000000000000000000000033113761647206025346 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp0100777000000000000000000001601513761647206030176 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_copyoperationtest : public QObject { Q_OBJECT private slots: void initTestCase() { //QInstaller::init(); m_testDestinationPath = qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); m_testDestinationFilePath = QDir(m_testDestinationPath).absoluteFilePath(QFileInfo( qApp->applicationFilePath()).fileName()); if (QDir(m_testDestinationPath).exists()) { QFAIL("Remove test folder first!"); } } void testMissingArguments() { CopyOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in Copy: " "0 arguments given, exactly 2 arguments expected.")); } void testCopySomething_data() { QTest::addColumn("source"); QTest::addColumn("destination"); QTest::newRow("full path syntax") << qApp->applicationFilePath() << m_testDestinationFilePath; QTest::newRow("short destination syntax") << qApp->applicationFilePath() << m_testDestinationPath; QTest::newRow("short destination syntax with ending separator") << qApp->applicationFilePath() << m_testDestinationPath + QDir::separator(); } void testCopySomething() { QFETCH(QString, source); QFETCH(QString, destination); QVERIFY2(QFileInfo(source).exists(), QString("Source file \"%1\" does not exist.").arg(source).toLatin1()); CopyOperation op; op.setArguments(QStringList() << source << destination); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY2(QFileInfo(m_testDestinationFilePath).exists(), QString("Copying from \"%1\" to \"%2\" was " "not working: '%3' does not exist").arg(source, destination, m_testDestinationFilePath).toLatin1()); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY2(!QFileInfo(m_testDestinationFilePath).exists(), QString("Undo of copying from \"%1\" to " "\"%2\" was not working.").toLatin1()); } void testCopyIfDestinationExist_data() { testCopySomething_data(); } void testCopyIfDestinationExist() { QFETCH(QString, source); QFETCH(QString, destination); QByteArray testString("This file is generated by QTest\n"); QFile testFile(m_testDestinationFilePath); testFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&testFile); out << testString; testFile.close(); QByteArray testFileHash = QInstaller::calculateHash(m_testDestinationFilePath, QCryptographicHash::Sha1); QVERIFY2(QFileInfo(source).exists(), QString("Source file \"%1\" does not exist.").arg(source).toLatin1()); CopyOperation op; op.setArguments(QStringList() << source << destination); op.backup(); QVERIFY2(!op.value("backupOfExistingDestination").toString().isEmpty(), "The CopyOperation didn't saved any backup."); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); // checking that perform did something QByteArray currentFileHash = QInstaller::calculateHash(m_testDestinationFilePath, QCryptographicHash::Sha1); QVERIFY(testFileHash != currentFileHash); QVERIFY2(QFileInfo(m_testDestinationFilePath).exists(), QString("Copying from \"%1\" to \"%2\" was " "not working: \"%3\" does not exist").arg(source, destination, m_testDestinationFilePath).toLatin1()); // undo should replace the new one with the old backuped one QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); currentFileHash = QInstaller::calculateHash(m_testDestinationFilePath, QCryptographicHash::Sha1); QVERIFY(testFileHash == currentFileHash); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit(installDir, ":///data/repository"); core->installDefaultComponentsSilently(); QFile copiedFile(installDir + QDir::separator() + "AnotherFolder/A.txt"); QVERIFY(copiedFile.exists()); QFile originalFile(installDir + QDir::separator() + "A.txt"); QVERIFY(originalFile.exists()); QByteArray destinationFileHash = QInstaller::calculateHash(copiedFile.fileName(), QCryptographicHash::Sha1); QByteArray testFileHash = QInstaller::calculateHash(originalFile.fileName(), QCryptographicHash::Sha1); QVERIFY(testFileHash == destinationFileHash); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!copiedFile.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } void init() { QVERIFY2(!QFileInfo(m_testDestinationFilePath).exists(), QString("Destination \"%1\" should not exist " "to test the copy operation.").arg(m_testDestinationFilePath).toLatin1()); QDir().mkpath(m_testDestinationPath); } void cleanup() { QFile(m_testDestinationFilePath).remove(); QDir().rmpath(m_testDestinationPath); } private: QString m_testDestinationPath; QString m_testDestinationFilePath; }; QTEST_MAIN(tst_copyoperationtest) #include "tst_copyoperationtest.moc" qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/0040777000000000000000000000000013761647206025047 5ustar00././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/createdesktopentryoperation.proqt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/createdesktopentryope0100777000000000000000000000023613761647206031416 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_createdesktopentryoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/0040777000000000000000000000000013761647206025760 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/0040777000000000000000000000000013761647206030177 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/A/0040777000000000000000000000000013761647206030357 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/A/1.00100777000000000000000000000161113761647206030577 0ustar007zžŊ'ȄšG"xėũāĘ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹'ĻĮ8ââMú'ÂS–'ëôĻŦT$QėÏcoģΚ”‰īÏ·EÄÄ(Đq'"˜8ëŋ>mó=ÜŨSÐĨGė‘ŨNv0&PŦýŌÕĄ+3æ3ŪÕGy—$Óþģp@lÎ$Vû ąD[īg$:84NæĐ‚(uþx5Uŧž’(yÆf%Úā`WÐŪßČ‚Úø•Ö†ú Û|ĻÆ0|‰ 0€Îd.æá€E]Õā€+f,'hœ‹[ø‚Ō u #] €ž ĄÞ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/data/repository/Updat0100777000000000000000000000057213761647206031203 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/settings.qrc0100777000000000000000000000024013761647206027412 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000016213761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/tst_createdesktopentryoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/createdesktopentryoperation/tst_createdesktopentr0100777000000000000000000001350313761647206031414 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_createdesktopentryoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_desktopEntryContents = "Type=Application\nName=Test\nVersion=1.0"; } void testMissingArguments() { CreateDesktopEntryOperation op(nullptr); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in CreateDesktopEntry: " "0 arguments given, exactly 2 arguments expected.")); } void testCreateDesktopEntry_data() { QTest::addColumn("filename"); QTest::newRow("relative") << "entry"; QTest::newRow("absolute") << qApp->applicationDirPath() + "/entry"; } void testCreateDesktopEntry() { QFETCH(QString, filename); CreateDesktopEntryOperation op(nullptr); op.setArguments(QStringList() << filename << m_desktopEntryContents); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(QFileInfo().exists(op.absoluteFileName())); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(op.absoluteFileName())); } void testBackupExistingEntry() { QString filename = qApp->applicationDirPath() + "/entry"; CreateDesktopEntryOperation op(nullptr); op.setArguments(QStringList() << filename << m_desktopEntryContents); op.backup(); QVERIFY(!op.hasValue("backupOfExistingDesktopEntry")); QFile existingEntry(filename); QVERIFY(existingEntry.open(QFileDevice::ReadWrite) && existingEntry.exists()); existingEntry.close(); op.backup(); QVERIFY(op.hasValue("backupOfExistingDesktopEntry")); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(op.value("backupOfExistingDesktopEntry").toString())); QVERIFY(QFileInfo().exists(filename)); QVERIFY(QFile(filename).remove()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); CreateDesktopEntryOperation *createDesktopEntryOp = nullptr; OperationList operations = core->componentByName("A")->operations(); foreach (Operation *op, operations) { if (op->name() == QLatin1String("CreateDesktopEntry")) createDesktopEntryOp = dynamic_cast(op); } QVERIFY(createDesktopEntryOp); QString entryFileName = createDesktopEntryOp->absoluteFileName(); QVERIFY(QFileInfo(entryFileName).exists()); if (QFileInfo(createDesktopEntryOp->arguments().first()).isRelative()) { QStringList directories = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")) .split(QLatin1Char(':'), QString::SkipEmptyParts); // Default path if XDG_DATA_HOME is not set directories.append(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); bool validPath = false; foreach (const QString &dir, directories) { // Desktop entry should be in one of the expected locations if (QFileInfo(entryFileName).absolutePath() == QDir(dir).absoluteFilePath("applications")) { validPath = true; break; } } QVERIFY(validPath); } core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY2(!QFileInfo(entryFileName).exists(), "Please make sure there " "does not exist a desktop entry with the same name."); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_desktopEntryContents; }; QTEST_MAIN(tst_createdesktopentryoperation) #include "tst_createdesktopentryoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/0040777000000000000000000000000013761647206024167 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/createshortcutoperation.proqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/createshortcutoperation.p0100777000000000000000000000017713761647206031335 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_createshortcutoperation.cpp RESOURCES += \ settings.qrc qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/0040777000000000000000000000000013761647206025100 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/0040777000000000000000000000000013761647206027317 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/A/0040777000000000000000000000000013761647206027477 5ustar00././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/A/1.0.2-10100777000000000000000000000027113761647206030216 0ustar007zžŊ'ž‘@'rE*Ņ<"Line to replace. Another line.  ' !! # ·ð°―  A.txt ï•ûÕ ï•ûÕ 6Ą]Ö ././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/A/1.0.2-10100777000000000000000000000171713761647206030224 0ustar007zžŊ'ĄÆđuŽ!æîāĻ%]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũéáœrýãÍLßuFĄ^ėĒ{/g"$r­ðė~-PÕˆÔ ÂË` –ÎOYs$ÁØYý†ĪŨ[·_š;ÂÜĪđRx;Ķf-,sw8ýK ÆÝB7$ƒíĩi2°ŋū>ðk˜;“Jĩ9~PÁ―Ōy=āčÎh.t.Čž{ę=Ū8)ęO1Õá,e-'īđ/;Kˆ’ņLĩöšþ™xCĨG ’\›1€3ŪÕNŌW$Óþģp#æ4…šwžgđōՖ蔀:ũ*ßį&Œ øjŽ]―ĪÛ·ųõÕyÍŇœÐ A—ĐԒ,ŸtĩåoQúßzŒuþô&9ÖNtÓóð„1Ėƒ- a #] n ę“îŽ././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/data/repository/Updates.x0100777000000000000000000000111413761647206031112 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true content.7z 6d7a3e15d11a4d94b81452fc2aa18e705a01c922 qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/installer-config/0040777000000000000000000000000013761647206027427 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/installer-config/config.xmlqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/installer-config/config.x0100777000000000000000000000026513761647206031070 0ustar00 test 1.0.0 Qt Installer Framework Unit Test qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/settings.qrc0100777000000000000000000000047613761647206026545 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z installer-config/config.xml ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/createshortcutoperation/tst_createshortcutoperati0100777000000000000000000001050613761647206031431 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_createshortcutoperation : public QObject { Q_OBJECT private slots: void testMissingArguments() { CreateShortcutOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in CreateShortcut: 0 arguments given," " 2 or 3 arguments expected in the form: " "[target arguments] [\"workingDirectory=...\"] [\"iconPath=...\"] " "[\"iconId=...\"] [\"description=...\"].")); } void testCreateShortcutForCurrentUserFromCLI() { QInstaller::init(); PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList (), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, QHash(), true); core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath()); core->disableWriteMaintenanceTool(); core->setAutoConfirmCommand(); QSet repoList; Repository repo = Repository::fromUserInput(":///data/repository"); repoList.insert(repo); core->settings().setDefaultRepositories(repoList); QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); core->setValue(scTargetDir, installDir); core->installDefaultComponentsSilently(); QSettingsWrapper user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\" "CurrentVersion\\Explorer\\User Shell Folders"), QSettingsWrapper::NativeFormat); //Replace %USERS% from "Programs" const QString programs = replaceWindowsEnvironmentVariables(user.value(QLatin1String("Programs"), QString()).toString()); const QString startMenuDir = programs + QDir::separator() + "Qt Installer Framework Unit Test"; QCOMPARE(startMenuDir, core->value("StartMenuDir")); QString linkLocation = core->value("StartMenuDir") + QDir::separator() + "A.lnk"; QFile file(linkLocation); QVERIFY(file.open(QIODevice::ReadOnly)); file.close(); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!QFile::exists(linkLocation)); core->deleteLater(); } }; QTEST_MAIN(tst_createshortcutoperation) #include "tst_createshortcutoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/0040777000000000000000000000000013761647206022372 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/data/0040777000000000000000000000000013761647206023303 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/data/repository/0040777000000000000000000000000013761647206025522 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/data/repository/A/0040777000000000000000000000000013761647206025702 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/data/repository/A/1.0.2-1meta.7z0100777000000000000000000000154713761647206027636 0ustar007zžŊ'8ƒ3%"ÞãĀāŌ§]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪĒæōÍą9Ņkvߨ ëß #įÔØķt†ké}Iēĸ6ó PŅŌŅ_3ŪÕFģŨ$Óþģp@gøSÂä]ĐŲH j9Õč TÉÎę3‹Óc㧜֧Œ†ũœuM$ Ũlâ[_yûŨiĻp°ï_ąĐũšnŅýŨæGM„ãËU é „=Ļ#Ą&ę‚.ŒØš‚Ŋ v #] €ž ~€ķŪqt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/data/repository/Updates.xml0100777000000000000000000000057213761647206027655 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/deleteoperation.pro0100777000000000000000000000022313761647206026274 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_deleteoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/settings.qrc0100777000000000000000000000024013761647206024735 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/deleteoperation/tst_deleteoperation.cpp0100777000000000000000000001072713761647206027162 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_deleteoperation : public QObject { Q_OBJECT private slots: void testMissingArguments() { DeleteOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in Delete: " "0 arguments given, exactly 1 arguments expected.")); op.setArguments(QStringList() << ""); QTest::ignoreMessage(QtWarningMsg, "QFile::copy: Empty or null file name"); op.backup(); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("Cannot create backup of file \"\": Unknown error")); // Returns true with empty file argument but does not do anything QVERIFY(op.performOperation()); } void testDeleteRestore_data() { QTest::addColumn("path"); QTest::newRow("relative") << "test"; QTest::newRow("absolute") << qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); } void testDeleteRestore() { QFETCH(QString, path); QByteArray testString("Generated by QTest\n"); QFile testFile(path); QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream out(&testFile); out << testString; testFile.close(); QVERIFY(QFileInfo(path).exists()); QByteArray testFileHash = QInstaller::calculateHash(path, QCryptographicHash::Sha1); DeleteOperation op; op.setArguments(QStringList() << path); op.backup(); QVERIFY(QFileInfo(op.value("backupOfExistingFile").toString()).exists()); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo(path).exists()); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QByteArray restoredFileHash = QInstaller::calculateHash(path, QCryptographicHash::Sha1); QVERIFY(testFileHash == restoredFileHash); QVERIFY(QFile(path).remove()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit(installDir, ":///data/repository"); // Matches filename in component install script QFile file(installDir + QDir::toNativeSeparators("/test")); QVERIFY(file.open(QIODevice::ReadWrite)); file.close(); core->installDefaultComponentsSilently(); QVERIFY(!file.exists()); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(file.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } }; QTEST_MAIN(tst_deleteoperation) #include "tst_deleteoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/0040777000000000000000000000000013761647206025202 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/0040777000000000000000000000000013761647206026113 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/0040777000000000000000000000000013761647206030332 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/A/0040777000000000000000000000000013761647206030512 5ustar00././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/A/1.0100777000000000000000000000156213761647206030657 0ustar007zžŊ'ļsfX1!7–ĖUādĮ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũð2õ4Æ>ʘšÔ+ÅWÛMžųú‡ĩD·ŊʍæšŊGŒoDʈï4Š>ËoŋįëŒÏįCąóŪ7)Qæf)ŠĒ:Ý Ú?ĘLÔÃ 3ŪÕGh˜Ũ$Óþģp@n=ŋ ”ôHsčRūyĖDļDŠeIh29eÛ?í/Ÿ ķ.Øóģ8@ÁSpÝmzé  „SukËQŽÄÅÅ;I;‰ĻOéAjÞ‚Ï b #] n 2…././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/data/repository/Upda0100777000000000000000000000062613761647206031152 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/environmentvariableoperation.proqt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/environmentvariableo0100777000000000000000000000024013761647206031352 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_environmentvariableoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/settings.qrc0100777000000000000000000000024013761647206027545 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000016413761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/tst_environmentvariableoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/environmentvariableoperation/tst_environmentvaria0100777000000000000000000001360113761647206031407 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include using namespace QInstaller; using namespace KDUpdater; class tst_environmentvariableoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_key = "IFW_TestKey"; m_value = "IFW_TestValue"; m_oldValue = "IFW_TestOldValue"; m_settings = new QSettings("HKEY_CURRENT_USER\\Environment", QSettings::NativeFormat); } void cleanup() { m_settings->remove(m_key); m_settings->remove("IFW_UNIT_TEST_PERSISTENT"); //Added from script } void testPersistentNonSystem() { #ifndef Q_OS_WIN QSKIP("This operation only works on Windows"); #endif EnvironmentVariableOperation op(nullptr); op.setArguments( QStringList() << m_key << m_value << QLatin1String("true") << QLatin1String("false")); const bool ok = op.performOperation(); QVERIFY2(ok, qPrintable(op.errorString())); QCOMPARE(m_value, m_settings->value(m_key).toString()); QVERIFY(op.undoOperation()); QVERIFY(m_settings->value(m_key).toString().isEmpty()); } void testNonPersistentNonSystem() { EnvironmentVariableOperation op(nullptr); op.setArguments( QStringList() << m_key << m_value << QLatin1String("false") << QLatin1String("false")); const bool ok = op.performOperation(); QVERIFY2(ok, qPrintable(op.errorString())); //Make sure it is not written to env variable QString comp = QString::fromLocal8Bit(qgetenv(qPrintable(m_key))); QVERIFY(comp.isEmpty()); QCOMPARE(m_value, Environment::instance().value(m_key)); } void testPersistentNonSystemOldValue() { #ifndef Q_OS_WIN QSKIP("This operation only works on Windows"); #endif m_settings->setValue(m_key, m_oldValue); EnvironmentVariableOperation op(nullptr); op.setArguments( QStringList() << m_key << m_value << QLatin1String("true") << QLatin1String("false")); const bool ok = op.performOperation(); QVERIFY2(ok, qPrintable(op.errorString())); QCOMPARE(m_value, m_settings->value(m_key).toString()); QVERIFY(op.undoOperation()); QCOMPARE(m_settings->value(m_key).toString(), m_oldValue); m_settings->remove(m_key); } void testNonPersistentNonSystemOldValue() { m_settings->setValue(m_key, m_oldValue); Environment::instance().setTemporaryValue(m_key, m_oldValue); EnvironmentVariableOperation op(nullptr); op.setArguments( QStringList() << m_key << m_value << QLatin1String("false") << QLatin1String("false")); const bool ok = op.performOperation(); QVERIFY2(ok, qPrintable(op.errorString())); QVERIFY(op.undoOperation()); QCOMPARE(m_oldValue, Environment::instance().value(m_key)); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); QVERIFY(m_settings->value("IFW_UNIT_TEST_LOCAL").toString().isEmpty()); // Persistent is in settings in Windows platform only, otherwise it is written to local env. #ifdef Q_OS_WIN QCOMPARE(QLatin1String("IFW_UNIT_TEST_PERSISTENT_VALUE"), m_settings->value("IFW_UNIT_TEST_PERSISTENT").toString()); #else QCOMPARE(QLatin1String("IFW_UNIT_TEST_PERSISTENT_VALUE"), Environment::instance().value("IFW_UNIT_TEST_PERSISTENT")); #endif QCOMPARE(QLatin1String("IFW_UNIT_TEST_VALUE"), Environment::instance().value("IFW_UNIT_TEST_LOCAL")); core->commitSessionOperations(); core->setPackageManager(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(m_settings->value("IFW_UNIT_TEST_PERSISTENT").toString().isEmpty()); QVERIFY(Environment::instance().value("IFW_UNIT_TEST_LOCAL").isEmpty()); core->deleteLater(); } private: QSettings *m_settings; QString m_key; QString m_value; QString m_oldValue; }; QTEST_MAIN(tst_environmentvariableoperation) #include "tst_environmentvariableoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/0040777000000000000000000000000013761647206025044 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/data/0040777000000000000000000000000013761647206025755 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/data.qrc0100777000000000000000000000020113761647206026455 0ustar00 data/valid.7z data/invalid.7z qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/data/invalid.7z0100777000000000000000000006200013761647206027663 0ustar00qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/data/valid.7z0100777000000000000000000000166613761647206027347 0ustar007zžŊ'ŠÖDRšnī>ĸïk]oýĸĸĢ·ĸG>Hr9aQļ’(æĢ†ųîä‚Ó/Å:<Ką~ɊŠM/Ģ ŲĶãŒ#SāYÅuŠâwøķ” jĀÞtIdâé\SēØũD Ŧ_ mFéåÃvˆ·–WŽķMáioûKˆlBˈ?\ÐNŊ&(”q=$ápž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðħ KcŸï+ėsS§ýūŪ|1Ÿ·1npž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ% HņҐ!ښėsS§ýūŪ|1Ÿ·1npž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ!‘ČÚ ƒD !! āP uģ;É valid FķNEÎ ././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/extractarchiveoperationtest.proqt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/extractarchiveoperati0100777000000000000000000000017013761647206031365 0ustar00include(../../qttest.pri) QT -= gui QT += testlib RESOURCES += data.qrc SOURCES = tst_extractarchiveoperationtest.cpp ././@LongLink0100777000000000000000000000016213761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/tst_extractarchiveoperationtest.cppqt-installer-framework-4.0.1/tests/auto/installer/extractarchiveoperationtest/tst_extractarchiveope0100777000000000000000000000601113761647206031377 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "init.h" #include "extractarchiveoperation.h" #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_extractarchiveoperationtest : public QObject { Q_OBJECT private slots: void initTestCase() { QInstaller::init(); } void testMissingArguments() { ExtractArchiveOperation op(nullptr); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); //QVERIFY(!op.undoOperation()); Can't test for failure as we run into Q_ASSERT QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in Extract: " "0 arguments given, exactly 2 arguments expected.")); } void testExtractOperationValidFile() { ExtractArchiveOperation op(nullptr); op.setArguments(QStringList() << ":///data/valid.7z" << QDir::tempPath()); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); QVERIFY(op.undoOperation()); } void testExtractOperationInvalidFile() { ExtractArchiveOperation op(nullptr); op.setArguments(QStringList() << ":///data/invalid.7z" << QDir::tempPath()); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QVERIFY(op.undoOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("Error while extracting archive \":///data/invalid.7z\": " "Cannot open archive \":///data/invalid.7z\".")); } }; QTEST_MAIN(tst_extractarchiveoperationtest) #include "tst_extractarchiveoperationtest.moc" qt-installer-framework-4.0.1/tests/auto/installer/factory/0040777000000000000000000000000013761647206020656 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/factory/factory.pro0100777000000000000000000000010113761647206023037 0ustar00include(../../qttest.pri) QT -= gui SOURCES += tst_factory.cpp qt-installer-framework-4.0.1/tests/auto/installer/factory/tst_factory.cpp0100777000000000000000000001732613761647206023734 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include class Food { public: explicit Food(int amount) : m_amount(amount) {} virtual ~Food() {} int available() const { return m_amount; } virtual QDate expireDate() const = 0; template static Food *create(Args... args) { qDebug().nospace().noquote() << "Create function."; return new T(std::forward(args)...); } private: int m_amount; }; class EggStore : public GenericFactory { public: static EggStore &instance() { static EggStore factory; return factory; } }; class Bread : public Food { public: Bread(int amount, const QDate &expireDate) : Food(amount) , m_expireDate(expireDate) { qDebug().nospace().noquote() << "Constructor."; } QDate expireDate() const { return m_expireDate; } private: QDate m_expireDate; }; class Butter : public Food { public: QDate expireDate() const { return m_expireDate; } static Food *create(int amount, const QDate expireDate) { qDebug().nospace().noquote() << "Create function."; return new Butter(amount, expireDate); } private: Butter(int amount, const QDate &expireDate) : Food(amount) , m_expireDate(expireDate) { qDebug().nospace().noquote() << "Constructor."; } private: QDate m_expireDate; }; class ColdCuts : public Food { public: ColdCuts(int amount, const QDate &expireDate) : Food(amount) , m_expireDate(expireDate) { qDebug().nospace().noquote() << "Constructor."; } QDate expireDate() const { return m_expireDate; } private: QDate m_expireDate; }; class FoodStore : public GenericFactory { public: static FoodStore &instance() { static FoodStore factory; return factory; } }; class tst_Factory : public QObject { Q_OBJECT private slots: void testSingleArg() { class Egg : public Food { public: explicit Egg(int amount) : Food(amount) { qDebug().nospace().noquote() << "Constructor."; } QDate expireDate() const { return QDate::currentDate().addDays(1); } private: QDate m_expireDate; }; class EggStore : public GenericFactory { public: static EggStore &instance() { static EggStore factory; return factory; } }; EggStore::instance().registerProduct("Egg"); QCOMPARE(EggStore::instance().containsProduct("Egg"), true); // EggStore::instance().registerProduct("Bread"); // Does not compile. QTest::ignoreMessage(QtDebugMsg, "Constructor."); auto food = EggStore::instance().create("Egg", 100); QCOMPARE(food->available(), 100); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(1)); QTest::ignoreMessage(QtDebugMsg, "Create function."); QTest::ignoreMessage(QtDebugMsg, "Constructor."); EggStore::instance().registerProduct("Egg", &Egg::create); food = EggStore::instance().create("Egg", 10); QCOMPARE(food->available(), 10); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(1)); auto lambda = [](int amount) -> Food* { return new Egg(amount); }; EggStore::instance().registerProduct("Egg", lambda); QTest::ignoreMessage(QtDebugMsg, "Constructor."); food = EggStore::instance().create("Egg", 20); QCOMPARE(food->available(), 20); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(1)); } void testMultiArg() { FoodStore::instance().registerProduct("Bread"); FoodStore::instance().registerProduct("Butter", &Butter::create); FoodStore::instance().registerProduct("ColdCuts"); // FoodStore::instance().registerProduct("Eggs"); // Does not compile. QCOMPARE(FoodStore::instance().containsProduct("Bread"), true); QCOMPARE(FoodStore::instance().containsProduct("Butter"), true); QCOMPARE(FoodStore::instance().containsProduct("ColdCuts"), true); QCOMPARE(FoodStore::instance().containsProduct("Sandwich"), false); QTest::ignoreMessage(QtDebugMsg, "Constructor."); auto food = FoodStore::instance().create("Bread", 10, QDate::currentDate().addDays(7)); QCOMPARE(food->available(), 10); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(7)); QTest::ignoreMessage(QtDebugMsg, "Create function."); QTest::ignoreMessage(QtDebugMsg, "Constructor."); food = FoodStore::instance().create("Butter", 2, QDate::currentDate().addDays(3)); QCOMPARE(food->available(), 2); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(3)); QTest::ignoreMessage(QtDebugMsg, "Constructor."); food = FoodStore::instance().create("ColdCuts", 50, QDate::currentDate().addDays(5)); QCOMPARE(food->available(), 50); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(5)); food = FoodStore::instance().create("Sandwich", 50, QDate::currentDate()); QCOMPARE(food == Q_NULLPTR, true); // overwrites the existing registration FoodStore::instance().registerProduct("ColdCuts", &ColdCuts::create); QTest::ignoreMessage(QtDebugMsg, "Create function."); QTest::ignoreMessage(QtDebugMsg, "Constructor."); food = FoodStore::instance().create("ColdCuts", 100, QDate::currentDate().addDays(4)); QCOMPARE(food->available(), 100); QCOMPARE(food->expireDate(), QDate::currentDate().addDays(4)); } }; QTEST_MAIN(tst_Factory) #include "tst_factory.moc" qt-installer-framework-4.0.1/tests/auto/installer/fakestopprocessforupdateoperation/0040777000000000000000000000000013761647206026255 5ustar00././@LongLink0100777000000000000000000000017213761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/fakestopprocessforupdateoperation/fakestopprocessforupdateoperation.proqt-installer-framework-4.0.1/tests/auto/installer/fakestopprocessforupdateoperation/fakestopprocess0100777000000000000000000000015513761647206031414 0ustar00include(../../qttest.pri) QT -= gui QT += network qml SOURCES += tst_fakestopprocessforupdateoperation.cpp ././@LongLink0100777000000000000000000000017613761647206010122 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/fakestopprocessforupdateoperation/tst_fakestopprocessforupdateoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/fakestopprocessforupdateoperation/tst_fakestoppro0100777000000000000000000000456113761647206031435 0ustar00#include "fakestopprocessforupdateoperation.h" #include "packagemanagercore.h" #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_FakeStopProcessForUpdateOperation : public QObject { Q_OBJECT private slots: void testMissingArgument() { FakeStopProcessForUpdateOperation op(&m_core); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); QVERIFY(!op.undoOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in FakeStopProcessForUpdate: " "0 arguments given, exactly 1 arguments expected.")); } void testMissingPackageManagerCore() { FakeStopProcessForUpdateOperation op(nullptr); op.setArguments(QStringList() << QFileInfo(QCoreApplication::applicationFilePath()).fileName()); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); QVERIFY(!op.undoOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("Cannot get package manager core.")); } void testRunningApplication() { const QString app = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); FakeStopProcessForUpdateOperation op(&m_core); op.setArguments(QStringList() << app); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); QVERIFY(!op.undoOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString::fromLatin1("This process should be stopped before " "continuing: %1").arg(app)); } void testRunningNonApplication() { FakeStopProcessForUpdateOperation op(&m_core); op.setArguments(QStringList() << "dummy.exe"); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); QVERIFY(op.undoOperation()); QCOMPARE(op.errorString(), QString()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::NoError); } private: PackageManagerCore m_core; }; QTEST_MAIN(tst_FakeStopProcessForUpdateOperation) #include "tst_fakestopprocessforupdateoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/fileutils/0040777000000000000000000000000013761647206021207 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/fileutils/fileutils.pro0100777000000000000000000000012113761647206023723 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_fileutils.cpp qt-installer-framework-4.0.1/tests/auto/installer/fileutils/tst_fileutils.cpp0100777000000000000000000001237313761647206024613 0ustar00/************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include using namespace QInstaller; class tst_fileutils : public QObject { Q_OBJECT private slots: void testSetDefaultFilePermissions() { #if defined(Q_OS_WIN) QString fileName = QInstaller::generateTemporaryFileName(); QFile testFile(fileName); QVERIFY(testFile.open(QIODevice::ReadWrite)); QVERIFY(testFile.exists()); testFile.close(); // Set permissions containing none of the Write* flags, this will cause // the read-only flag to be set for the file QVERIFY(testFile.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadUser | QFileDevice::ReadGroup | QFileDevice::ReadOther)); // Verify that the file cannot be opened for both reading and writing, i.e. // it should be read-only. QVERIFY(!testFile.open(QIODevice::ReadWrite)); // Now try to remove the read-only flag QVERIFY(setDefaultFilePermissions(&testFile, DefaultFilePermissions::NonExecutable)); // Verify that the file can now be opened for both reading and writing QVERIFY(testFile.open(QIODevice::ReadWrite)); testFile.close(); QVERIFY(testFile.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadUser | QFileDevice::ReadGroup | QFileDevice::ReadOther)); // Check that the behavior is same with 'Executable' argument QVERIFY(setDefaultFilePermissions(&testFile, DefaultFilePermissions::Executable)); QVERIFY(testFile.open(QIODevice::ReadWrite)); testFile.close(); QVERIFY(testFile.remove()); #elif defined(Q_OS_UNIX) // Need to include the "user" flags here as they will be returned // by QFile::permissions(). Same as owner permissions of the file. QFlags permissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); QFlags exePermissions(permissions | QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther); QString fileName = QInstaller::generateTemporaryFileName(); QFile testFile(fileName); const QString message = "Target \"%1\" does not exists."; // Test non-existing file QTest::ignoreMessage(QtWarningMsg, qPrintable(message.arg(fileName))); QVERIFY(!setDefaultFilePermissions(fileName, DefaultFilePermissions::NonExecutable)); QTest::ignoreMessage(QtWarningMsg, qPrintable(message.arg(testFile.fileName()))); QVERIFY(!setDefaultFilePermissions(&testFile, DefaultFilePermissions::NonExecutable)); QVERIFY(testFile.open(QIODevice::ReadWrite)); QVERIFY(testFile.exists()); testFile.close(); // Test with file name QVERIFY(setDefaultFilePermissions(fileName, DefaultFilePermissions::NonExecutable)); QCOMPARE(QFile().permissions(fileName), permissions); QVERIFY(setDefaultFilePermissions(fileName, DefaultFilePermissions::Executable)); QCOMPARE(QFile().permissions(fileName), exePermissions); // Test with QFile object QVERIFY(setDefaultFilePermissions(&testFile, DefaultFilePermissions::NonExecutable)); QCOMPARE(QFile().permissions(fileName), permissions); QVERIFY(setDefaultFilePermissions(&testFile, DefaultFilePermissions::Executable)); QCOMPARE(QFile().permissions(fileName), exePermissions); // Test with directory path QString testDir = QDir().tempPath() + QLatin1String("/testDir"); QVERIFY(QDir().mkdir(testDir)); QVERIFY(setDefaultFilePermissions(testDir, DefaultFilePermissions::Executable)); QCOMPARE(QFile().permissions(testDir), exePermissions); QVERIFY(QDir().rmdir(testDir)); QVERIFY(testFile.remove()); #endif } }; QTEST_MAIN(tst_fileutils) #include "tst_fileutils.moc" qt-installer-framework-4.0.1/tests/auto/installer/installer.pro0100777000000000000000000000204413761647206021726 0ustar00TEMPLATE = subdirs SUBDIRS += \ settings \ repository \ compareversion\ componentidentifier \ componentmodel \ fakestopprocessforupdateoperation \ messageboxhandler \ extractarchiveoperationtest \ lib7zfacade \ fileutils \ unicodeexecutable \ scriptengine \ consumeoutputoperationtest \ mkdiroperationtest \ copyoperationtest \ solver \ binaryformat \ packagemanagercore \ settingsoperation \ task \ clientserver \ factory \ replaceoperation \ brokeninstaller \ cliinterface \ linereplaceoperation \ metadatajob \ appendfileoperation \ simplemovefileoperation \ deleteoperation \ copydirectoryoperation \ commandlineupdate \ moveoperation \ environmentvariableoperation \ licenseagreement win32 { SUBDIRS += registerfiletypeoperation \ createshortcutoperation } linux-g++* { SUBDIRS += \ createdesktopentryoperation \ installiconsoperation } scriptengine.depends += unicodeexecutable qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/0040777000000000000000000000000013761647206023632 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/0040777000000000000000000000000013761647206024543 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/0040777000000000000000000000000013761647206026762 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/A/0040777000000000000000000000000013761647206027142 5ustar00././@LongLink0100777000000000000000000000015413761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/A/1.0.2-1co0100777000000000000000000000060013761647206030177 0ustar007zžŊ'bŠ[^>"zî|―~ŌdŅ "ÎOųé Oōv°‘gmа(§ :Ŋ&5:QĶÃęaðOâMÚi9ōÔ'D‚üĒn’9,ZŸFÄÝ\0%ðæ· Ï?%Ž‘ ‰#ķÉģJ8OsuôjōŧhÛöĶ™ĮÖī;.õ 6\b]‡ŧÐdjķ€G‚ŸŪó#@°'Udðķ†-voĸxz*sthRĻ(˜Ïë 'ŧï7Ęmnį` Óqė ÃÕyˆýí“ôéÅíxKv‡tDĢš{ķėPYI“°ŠÖ/ÔÉ3u ÉRIØ@ÏgVA^›ĮISkųKkgĐ(ÞÓí•ē΁nAEÂĖa*1‚ķáŠ1ršŌ‹NĸØĨũgFŦ,†ĸ„į‚šwĩ"‰i%•XÃÎ~ĩ… > #] ‡ Ã*―././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/A/1.0.2-1me0100777000000000000000000000153613761647206030210 0ustar007zžŊ'âwŽ"äMÛāÅŸ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýąĪx&ųEēšŦ•DyWĖÕäY.Ĩ`‰#§“ BÔšŸÏÁ%qUËŊánžÎ']ýÖŲŦA9˜ņ™dR―[KT‡•ý~{IXFîFnŌlЁ:Dģ æĘ3ŪÕF…ŪŨ$Óþģp@gÅޟÂäöUrX((ã­üZQ'Íū•đ˜ÅĘ 5uEõ+ŌęU[ö:š ĻŧQ”ĨĐ*8g Gûs„&8É rĪĒ5úVá:‰Ļ­`šsϐØLûï‚§ u #] €ž ōÔ$qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/data/repository/Updates.xml0100777000000000000000000000066413761647206031117 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true content.7z qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/installiconsoperation.pro0100777000000000000000000000023013761647206030772 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_installiconsoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/settings.qrc0100777000000000000000000000033113761647206026176 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/tst_installiconsoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/installiconsoperation/tst_installiconsoperation.c0100777000000000000000000002102513761647206031313 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include "../shared/verifyinstaller.h" #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_installiconsoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_testIconSourcePath = qApp->applicationDirPath() + "/icons"; m_testIconSubdirectoryPath = m_testIconSourcePath + "/test"; m_testIconFilePaths.append(m_testIconSubdirectoryPath + QDir::separator() + "vendor-icon1.png"); m_testIconFilePaths.append(m_testIconSubdirectoryPath + QDir::separator() + "vendor-icon2.png"); m_testIconFilePaths.append(m_testIconSubdirectoryPath + QDir::separator() + "vendor-icon3.png"); } void testMissingArguments() { InstallIconsOperation op(nullptr); op.backup(); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in InstallIcons: " "0 arguments given, 1 or 2 arguments expected " "in the form: [vendor prefix].")); op.setArguments(QStringList() << ""); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid Argument: source directory must not be empty.")); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); InstallIconsOperation *installIconsOp = nullptr; OperationList operations = core->componentByName("A")->operations(); foreach (Operation *op, operations) { if (op->name() == QLatin1String("InstallIcons")) installIconsOp = dynamic_cast(op); } QVERIFY(installIconsOp); // As the original directory containing icons will be deleted by the operation, // we will use a copy with the exact same contents. QFileInfo fakeSourceInfo(installDir + "/icons_copy/test"); QMap fakeSourceMap; VerifyInstaller::addToFileMap(QDir(fakeSourceInfo.absoluteFilePath()), fakeSourceInfo, fakeSourceMap); QFileInfo destinationInfo(installIconsOp->value("directory").toString() + "/test"); QMap destinationMap; VerifyInstaller::addToFileMap(QDir(destinationInfo.absoluteFilePath()), destinationInfo, destinationMap); QVERIFY(fakeSourceMap == destinationMap); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!destinationInfo.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } void testInstallIconsWithUndo() { QDir testIconDir(m_testIconSourcePath); QVERIFY(testIconDir.mkpath(m_testIconSubdirectoryPath)); // Populate source directory foreach (const QString &filePath, m_testIconFilePaths) { QFile file(filePath); QVERIFY(file.open(QFileDevice::ReadWrite)); file.close(); } PackageManagerCore *core = new PackageManagerCore(); InstallIconsOperation op(core); op.setArguments(QStringList() << m_testIconSourcePath); QFileInfo sourceInfo(m_testIconSubdirectoryPath); QMap sourceMap; VerifyInstaller::addToFileMap(QDir(sourceInfo.absoluteFilePath()), sourceInfo, sourceMap); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(m_testIconSourcePath)); QFileInfo destinationInfo(op.value("directory").toString() + "/test"); QMap destinationMap; VerifyInstaller::addToFileMap(QDir(destinationInfo.absoluteFilePath()), destinationInfo, destinationMap); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(op.value("directory").toString() + "/test")); QVERIFY(QFileInfo().exists(m_testIconSourcePath)); QVERIFY(sourceMap == destinationMap); QVERIFY(testIconDir.removeRecursively()); core->deleteLater(); } void testChangeVendorPrefix() { QDir testIconDir(m_testIconSourcePath); QVERIFY(testIconDir.mkpath(m_testIconSubdirectoryPath)); QFile file(m_testIconFilePaths.first()); QVERIFY(file.open(QFileDevice::ReadWrite)); file.close(); PackageManagerCore *core = new PackageManagerCore(); InstallIconsOperation op(core); op.setArguments(QStringList() << m_testIconSourcePath << "testVendor"); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(m_testIconSourcePath)); QVERIFY(QFileInfo().exists(op.value("directory").toString() + "/test/testVendor-icon1.png")); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(op.value("directory").toString() + "/test")); QVERIFY(QFileInfo().exists(m_testIconSourcePath)); QVERIFY(testIconDir.removeRecursively()); core->deleteLater(); } void testValidTargetDirectory() { QDir testIconDir(m_testIconSourcePath); QVERIFY(testIconDir.mkpath(m_testIconSubdirectoryPath)); PackageManagerCore *core = new PackageManagerCore(); InstallIconsOperation op(core); op.setArguments(QStringList() << m_testIconSourcePath); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(m_testIconSourcePath)); QString targetIconsDirectory = op.value("directory").toString(); QVERIFY(QFileInfo(targetIconsDirectory).exists()); QStringList directories = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")) .split(QLatin1Char(':'), QString::SkipEmptyParts); // Default path if XDG_DATA_HOME is not set directories.append(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); bool validPath = false; foreach (const QString &dir, directories) { // Icon directory should be one of the expected locations if (targetIconsDirectory == QDir(dir).absoluteFilePath("icons")) { validPath = true; break; } } QVERIFY(validPath); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo().exists(op.value("directory").toString() + "/test")); QVERIFY(testIconDir.removeRecursively()); core->deleteLater(); } private: QString m_testIconSourcePath; QString m_testIconSubdirectoryPath; QStringList m_testIconFilePaths; }; QTEST_MAIN(tst_installiconsoperation) #include "tst_installiconsoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/0040777000000000000000000000000013761647206021362 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/data/0040777000000000000000000000000013761647206022273 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/data.qrc0100777000000000000000000000020113761647206022773 0ustar00 data/valid.7z data/invalid.7z qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/data/invalid.7z0100777000000000000000000006200013761647206024201 0ustar00qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/data/valid.7z0100777000000000000000000000166613761647206023665 0ustar007zžŊ'ŠÖDRšnī>ĸïk]oýĸĸĢ·ĸG>Hr9aQļ’(æĢ†ųîä‚Ó/Å:<Ką~ɊŠM/Ģ ŲĶãŒ#SāYÅuŠâwøķ” jĀÞtIdâé\SēØũD Ŧ_ mFéåÃvˆ·–WŽķMáioûKˆlBˈ?\ÐNŊ&(”q=$ápž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðħ KcŸï+ėsS§ýūŪ|1Ÿ·1npž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ•(FĐü|Þûš0.VĀ…óƒĀeÄ% HņҐ!ښėsS§ýūŪ|1Ÿ·1npž§#_ė(Ë…Ņ•˜Š~*‘ō'uũĀ˜M˜ýØŊՐÄ%Søõ‘61Ĩ°îoÁpMG ґЭ`šÎą'\Y†éfRXūévŽYäå[ųĮÚ­üûR+tÍ[ BųÝS=ø)d ;€Ë*lßĩ;ðÄ―._Š>KfBĸ“øqxYø Íĸ!‘ČÚ ƒD !! āP uģ;É valid FķNEÎ qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/lib7zfacade.pro0100777000000000000000000000015013761647206024253 0ustar00include(../../qttest.pri) QT -= gui QT += testlib RESOURCES += data.qrc SOURCES = tst_lib7zfacade.cpp qt-installer-framework-4.0.1/tests/auto/installer/lib7zfacade/tst_lib7zfacade.cpp0100777000000000000000000001330413761647206025134 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include class tst_lib7zfacade : public QObject { Q_OBJECT private slots: void initTestCase() { Lib7z::initSevenZ(); m_file.path = "valid"; m_file.permissions = 0; m_file.compressedSize = 836; m_file.uncompressedSize = 5242880; m_file.isDirectory = false; m_file.archiveIndex = QPoint(0, 0); m_file.utcTime = QDateTime(QDate::fromJulianDay(2456413), QTime(10, 50, 42), Qt::UTC); } void testIsSupportedArchive() { QCOMPARE(Lib7z::isSupportedArchive(":///data/valid.7z"), true); QCOMPARE(Lib7z::isSupportedArchive(":///data/invalid.7z"), false); try { QFile file(":///data/valid.7z"); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(Lib7z::isSupportedArchive(&file), true); } catch (...) { QFAIL("Unexpected error during Lib7z::isSupportedArchive."); } try { QFile file(":///data/invalid.7z"); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(Lib7z::isSupportedArchive(&file), false); } catch (...) { QFAIL("Unexpected error during Lib7z::isSupportedArchive."); } } void testListArchive() { try { QFile file(":///data/valid.7z"); QVERIFY(file.open(QIODevice::ReadOnly)); QVector files = Lib7z::listArchive(&file); QCOMPARE(files.count(), 1); QCOMPARE(files.first(), m_file); } catch (...) { QFAIL("Unexpected error during list archive."); } try { QFile file(":///data/invalid.7z"); QVERIFY(file.open(QIODevice::ReadOnly)); QVector files = Lib7z::listArchive(&file); } catch (const Lib7z::SevenZipException& e) { QCOMPARE(e.message(), QString("Cannot open archive \":///data/invalid.7z\".")); } catch (...) { QFAIL("Unexpected error during list archive."); } } void testCreateArchive() { try { const QString path = tempSourceFile("Source File 1."); const QString path2 = tempSourceFile("Source File 2."); QTemporaryFile target; QVERIFY(target.open()); Lib7z::createArchive(&target, QStringList() << path << path2); QCOMPARE(Lib7z::listArchive(&target).count(), 2); } catch (const Lib7z::SevenZipException& e) { QFAIL(e.message().toUtf8()); } catch (...) { QFAIL("Unexpected error during create archive."); } try { const QString path1 = tempSourceFile( "Source File 1.", QDir::tempPath() + "/temp file with spaces.XXXXXX" ); const QString path2 = tempSourceFile( "Source File 2.", QDir::tempPath() + "/temp file with spaces.XXXXXX" ); QTemporaryFile target(QDir::tempPath() + "/target file with spaces.XXXXXX"); QVERIFY(target.open()); Lib7z::createArchive(&target, QStringList() << path1 << path2); QCOMPARE(Lib7z::listArchive(&target).count(), 2); } catch (const Lib7z::SevenZipException& e) { QFAIL(e.message().toUtf8()); } catch (...) { QFAIL("Unexpected error during create archive."); } } void testExtractArchive() { QFile source(":///data/valid.7z"); QVERIFY(source.open(QIODevice::ReadOnly)); try { Lib7z::extractArchive(&source, QDir::tempPath()); QCOMPARE(QFile::exists(QDir::tempPath() + QString("/valid")), true); } catch (const Lib7z::SevenZipException& e) { QFAIL(e.message().toUtf8()); } catch (...) { QFAIL("Unexpected error during extract archive."); } } private: QString tempSourceFile(const QByteArray &data, const QString &templateName = QString()) { QTemporaryFile source; if (!templateName.isEmpty()) { source.setFileTemplate(templateName); } source.open(); source.write(data); source.setAutoRemove(false); return source.fileName(); } private: Lib7z::File m_file; }; QTEST_MAIN(tst_lib7zfacade) #include "tst_lib7zfacade.moc" qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/0040777000000000000000000000000013761647206022521 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/data/0040777000000000000000000000000013761647206023432 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/data/repository/0040777000000000000000000000000013761647206025651 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/data/repository/A/0040777000000000000000000000000013761647206026031 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/data/repository/A/1.0.2-1meta.7z0100777000000000000000000002646213761647206027770 0ustar007zžŊ'lũ]ð,"Ú(„Œā‰J,i]mþG'ø"'ųyĢËĀS Tę“°“ÅÜŅ@H Vâ0ā9G}=ŋĀU%/ŽÚl[7%?æz‚$&sz…AÅķ€Žāž1ŒH75Č,Zâę]‚cĸü\zÕ ~V·t=Ýą+|ØŅ1 'vûĨÓ FĸöĸíÅ#gSūę;ð Ã; šĐFÔTSĖūŦXÐÓėwgw#0pØåŸÎÐM!z͙Ėy Vb:9}ŋŪ‘žäb\YdVžqĢ­ũėCcķÐÏ~ÚHŅ(_Ę3ÛõšÎgšÆéÉ)Ų 6Î7}ó‚Ģ'Ų9'R H(ALˆfŽEÏgwûÍØsīœŨlE– <^6îwBĻ-æy―Ŋc—*Å@ÐĐڋ •|C08˜eW4Į_{čHÉë%kįÏ[ãĶþ=|ĪŽÞ臚<ąāÅ8āūīĸ0fÝöĄÐšÏp^ĄĘc°ģ›tœīxiŠ Ĩ€Ý1FH eWRÏÉOþMģlje”ė ÉFĖĮošŧ Gåß2#GŌýō―ކAōšÜMĶÖaÍMōÞŽ ķÁÂܜr“Y%―Ÿ‘š‡ī—į;”$EāíÎzį ØA‰sØč+RД3ĸ ĮšZ*œBEÓþ8Qu.aó3§QŨcœ‰)‘3ÖÆČUEĖ̓[Ё—:ß  z%†I•l2z–úWk”\ęĢ3ÆÏĖ€MQčxjŨģKÂvÔW―â%†óĖ5(LÂeįėRJ3~`KŊ{A=ā6įÓUy$žĒGUXŌK˜tjzĢW•zúîyĀýbGþfčpˆCāÂjĪÉõ Gķ휈W/ÚÅÞĖržO&…‰čĶ#1ūV`9žÏœĒŧOŽÔÏA)hngŠt'GĨÛOˆãe RąJŨīũgÜnØëTĶ^<Āëą#|Y*ß;ĢĀĘ~ûÉŪTiÐĖ­ŧēŒcō―č…ōÐĶžãŅĶæÃĀ_…―ŒlæĶÂfýyûmTķM0ĻūGŠæZ*â?Ĩá…q@›đ^'œôl‰o,ņ·P,9ļ–ķlŽåÜ(Û‹U.“ËĻōGlxn’s ņėčm “ĮR‹63Åuø­fŌGÃQķ0ČĐÁb1ÓdįKŠ―•Đ ęũŧŠ ãF€ÝĸŠ`ĸâ2Ėdö&*Ł1@g­WĄJ€g?čdŽÍïZDŠckaEÍk[ įjy9tņ4x[æ ΰ”;~ĸĨƒßÃ,n·ķ“ĢĘhÝēōÉÐ6ōÔšDCØ &rqAovz Į†ēžčĨN݂*§Š@D™–ŨŠ7ûÁĐ{;čžč„âÕŧ?;ļëHÎe5B "ĘĖƒ8Ė#7š°Ī[ŧßūÕ$ "šŲEžĨė„xnûs#5õĒ% Âr…;áCn‹§wˆÅ՛Ü^]Ī|!šĐd!@ĖķÖ+•h<,gs ķāĪĄk)ų#yøąóŦļĄ4y°Jĩ·1@2ëĐĮY”ÕC$Ám›ÜŦŋąģDîög–al 6Œ“]Þ~1ymLžL~jÕp>Õ·óŠŠ—Jb_H―ū%:Nð!ũzÞ‡§o€Ý†JŲcņļH―šøĀËg ųØp<īWp(+S /,{xAmķIåK‡Û ųãuq`ęášxHÉāđ‚įôœ–B°q‹k Ļó„]L€Ø6[æcé4B"GôđŧG^ûÔqHŪŽâĩŊxīßĢ—kŽĪ`ĩÓäĄm‰ŽAîĨōĨk7Ýû+Ύ_ŋÚ ˆB鮓 ›Öo”nmķĸƒȄ% “ŒJ ^ƒ…î/2o ņˆg|ŌãŲ›€øÁûŊVw"ī”öIđŧk3%ÏUį`cz0Fˈ, ņó}PÖtJÔoŽ*Pöšpķ„€Į6ĩî'kþĄĨč6‡€+맗‰ÕŠw óúĩðöeŪ*‡ÝĐ-”&gsý˜ä„ŋ^~ûfö āÉAûqLį{rįX=^fēÄȋuo) ĮB0#S|ƒ‚ ō:$Ņ˰ÆŧøũŅU “Nî'֑‘‹Ó'RÕÏ dõT#&/#ր7XƒL—þąUoÃWH‡ĸ9ôƒþũŽäX'™ZĪЕķīčý„—3īŪŅÚ Ķ`āp=PŽíVXy'°ÉRŅ(ð°wģÁ;ƑðˆFīãš&~UHOūCČúy CМ JßIûJ·vg3 E+L†ēŪÅ"ÎŋŒ‚ØMÔ ēŠ.†Ęļ{‹)‰ŽÃ Ņ\―H_n―š―ôcî|įœ/]ŅŽáõąÁ“„ĮĔ}iĮÚŅIЅƒāzũ‰Ž\ČĶ tÂ[žué˜ôeOýūČðŊÂ20dY„Vĸ)€oâ\p)ÕOYho‹béĢÎöÍnCsA‹ęÄāŲz€&8bœ.ü–Íīm␰[}ēk””_`áŠSâ~ģæš!ųN—CŊþ&W›Áې:wĐöÚcŅąĒ–0ĄÚ“Té_āøÅø |@*Ņų&7Oųíėėųĩ›uÅ[ČUō~B?*büÉG}Œ]†ŧYҚũiîífk°@ãXæSnÂvû–§Ķ―ûĘ-ų2Í<ųZ|þOĢ&ē Ŋ0íQ@%Y(]gÖį2U:ā?ü~9ÓøIúQôēī{ß1/Īö˜ęņ!äŧZÜë7^'&mÝSq;sð,rĖåCYDxđÄ06fRĪĀ8ôĀeXsYîáŊ4GÛũ]0ōuėATÐ* uáŪ|EUu€Þœ‡OŦđšzóåzôŽØ]Šft}͈wh~ō †vŌ+ÓĢâ^}öĖQOPjg§‚wĨ:@[š&H/r\L’Ō$˜ŦRĖ―<ØîL !Ų “Čbė}Vz0-‰vĻl=3ûmÍĮž1[ãyĮŒģ)žmũ~5ĸ ũ?^ĮĪæzj9ļBôĘA}܋Z§ Ķ[eÔĘ"ÂR†ÛŽ0ŒĖęĘī>^}U.‰|H7ðd%·‹+J―G m°1—OÎ\āßÅĻVØĘRqmiBôģ^ržF‚î—ïųōRĢÓųIë―„ÂZ #EPĘB|įŦūsžQîp_üQ―ӕ MYå8‹#"ÆĄ(ŅŪ­)&ŅëHŽHæc4ŸŧōÎcļõĢžL~‰)ČB§†VïQ ‚f}–Miŋģ•Awqpf†ģþŋŠūÕ=–ú2+^ŠpÎÛMčųC‘Ë*%‚€čĨ#išĶū @!Ô#ÄÍCvÖÍĄC`ŋÞxI ëk­pXÛúa)]~oa2[ąŨŧōÍũã)3Ųâã0ĄM’b’™ļ―)cāyy4m;Į/Čļ0gî`]þ ‰Ē°ŅhøX’KlŦŸ™âwdUßȆČ–dKG4k ģáÂeCŪĻĀj[DÖĢgÛy’?SŌÖËtō—Ð@°ß…ģZ ^hļK ú8R3377ôß #“ÝÚ)ðýqjÐ0ˆNáö2―šä|2.Ā%ÍMðuĢļ”fėðæl+Ú>…ŧw?2~žËķPĶéŽ=č`R°ZL~DāAikqÎĖY ?@$îĐb }Mú 8û‘ˆLč=ÞķsĊæú9”*‚ņa(ÂũŽíWÄ$―ž;Ð^ũšr( Ļ2Ģß å˜ĻÄ%*ár7Æ$} ēfØð,Ð2X:éJW2ø\Ŧ#‡ 'Ōáe aH#ķô°ĻŠĄėüčģŊå!$ĸyš6ܚ€ęé˜"ņŧķŒ$U â―áhēŋ>Ũ€‰‘ðkß[i“A|‚F͔ÔՎtH>ûđy.>W sØ·ĮøÉ%k€Q=AĩhŠ˜ÉíäûiķõGcĘôŪ#ƒ {ę}~x ãüđš6<ãNT†éBq'úOē!&OˆĘĐG)pĩŧv}f&ÜCQjÃîlPg0*o.JŊ°"ąŧõazē‰ÔRÔ)"?*þŽÂŋīÅGĢŌÆŒŊųÄā%oxâč°ķAJ˜ 1ÞđžũĀ^ũ’ęýöl–|™Ð욈Þáũž…‘ÆÛ™Ý óšWQžˆfžckj[Á^AŠį*8-ąhÏ!Ō[>rq<ĮÛZNEøxÎēūUąäf}yŦŧKfGĪĢ)į8ÐˆĮÉEß{Sb™wŧ‚ĸŋJ‰žd߯`‰_MpŅ/ÚõĘūΙ rĶ]ĮSsē‰ųWXXDáą(‡n=aâF5€wlš5YMŸũ―!đ/uGþkFBČ3ŦŒ=‡ïŽRcōŅitÆË’’ŋ ĖP(?/@]Ņ1ÆvA§Ó+íĄl‡:ĐŔžœĢ*ĮãÂ7#Áī<ڋļ6§‰Ā5ôDŌrœĖŪ@Ū‡6á‘'iĘ3Ýī~LĒ|l8/⯜ŒÆ‘ }õ{íKĄÂÍúodN-ý’°=ø‡ 7'=úĒ102>eØLˆ\T"[&úQX.mv!{ŋ ”=‹˜;퐘å]˜!Õü8ąÔōĮ„ļŨ­ĄDU™7öÝ`oūų õ|zęĻÚūÅ :ĸŠ#؉ã3>šØ~aQ.tHD,FãļÔ5šu@ũĮ]›æ‰ŠÁÎ ųlžØŪbZį2sãÂ4/Ûû"͏Ķ铞æŌy- žðdrKæĻk`‰&ČQUĖ?1&āĄ˜)T\—\h§Ą'DdČqÆsēØIĀŋýûÖq2Ös-ĖŊ- 0˜íŨFž ýfí„)›*jA]Ŋč2R(>ąÎŽ―jBā-ĸžōoÉAšzÕÐðšeΖ­ýaqŪŌ+ĘÕĘ>Ä\šLī[“‡ŒˆØÔĪĶá{†!??gÅ]ĸ8#*ËKĮŒĸÄ įPx Ē" Wtmr†aóū#íT`ūč"å)íéæïäúi;-‚PëųThrÁģuŠ%NLY!pT Õ49ĪYé!ß_i#aŲŊž ›0øüÅKþ&uôÎS`ąiL-sËv~ܟ>•]@É%ÚFšhF_dĢ·&_ŋn„čmøĖšrėã.„îäQаÚĻĮž'€Ģ*Ä ķí|œlÚÛBwÓĐũƒZŠÓZ‘!ÓŸÐöÉņöYĶ7eėPû'O4ô:ËÖL™!:šX*ōâ_%jŅJ/Ž„šÞÉ6.YĪxrøÁ֊ ÓWs'âŸf“9@Óމ‚ø#5ãĶß?B67ä;€ÂīPĘŅ.€Ÿüˆâ*W1 ^é6Lø—Ģmđ<5ĶtÍ<đ­Ã}–}ÜÐøÕRŐČSd Ą}<Šýūޝœŧ’Đ’ÂISĄ‘OGÐÎT„ĶŲÄÆũÂbÛÅ;zœš~įÏė1ŽxˆŌæq$óÅI{Ö ƒūLxá Ŧ;NmrtaČ7ļįGm?ʗÄóūųf^ŋâór.ĸæŠé_ŅmĪøŸhĒIU„]ĀNíchįĄ|ŠĘ2ŽT}qĄOs?õ@eŊÉ‰ðų<ƒ 9ˆrÚõU,ifõþ féáŲú#Čs;$°Ŋȉ/žoÞõœ•~xڊōęsq9Ė—·_z"óŠ óePņŊķÍ<ūY Ô­a ĨÄī}gīIm’Ō§ÕIží,T9—óį‰éĨ=\ŅĸššƒoFRENį}oWÜ︚ŽĻdūRӚāÞïZ øã‹āÅ/Č4qļi‡õ›hãžeČđļ(XŌÂę9ũŦęwūdoĄ‡a;é°Ļ†VzÜĨ˜7ū_B ĩĻ|ŠBZŊ`MPJųŒþ­?ü ÂîĢzFÂŅ―DĒ Æ83áҟÛÝ_ĀzrÃŽ3ý ;K`ØĩqbüŽŋc8,?‚ļev‘hĪnC˜ķD7pzÉNSV"å5ûF<{Pö7ŊsC-$ ÞbRæ0qØ@Ĩöøųŧ‡•.>€:>[—@‰>R2þHārY>9rēŨŽ4uŦĄŸđ[°3ŋËBōĶđK™™īŋÉW;koŧÉ@øBöŨ5óâŧ@(}Âï§ü_O™"ä1D+ÃΘÓí0…Åņię05Ã>ųéqt=Hl6 Œ‹öš9'Û:āVČėTĸå‚ĩBœ\"“ĸHŋā‹Ž› †ĸgvVöŠgó‘š@gŸAûdtūRCĮ6%ĢfþvũdũĖúœæ˜‚Ð8ž/[Ü ĢábĪŪôWŨøn$ēŨrZÚĒ„AŌĨšËfĪEĒĘké6`c (ČīĨŨi zQŨÐŅ ę~§h‰Zr;åŦÐ7’ŸŽîŠžbdÃĖvžë1Ïv2 Î:HïeJ?sŽöûƜwþa šā Ar%2\ïõs4$v#™'Gã~ąîKڛW8Ō„uhþĨh™ÂGÃs'įœ4˜qfĘüw6ũÁũūƒ7P‚ŊĄ ČۚV98BIŨ}•@ gnēūTÐ}įĄĶÁhx™JsBIõD-+þĀ9VM‹˜I[r˓5–ŽXÄ"Ū€9ŊįšĖB§ÁŲÚ'1đ9§CÖ`ūóEzˆĸ ‚~hš<ôÕ/ĸŨóĪ;Ԑ(tڋ9“Ū4`ČãķíŠoŠĐ%äþ]|RFĸ$KuĨĐ·ĩĮh…øfÍŦ(ūHŨeŪIi―k“ ‹Qį۟YO"!ė ;Óïđ r]óĖ“ÓČģSųŌýw8ekŅ}øNŅŋūĖ+á`xýg8"0oĶ _Fų4ʰpaDųÝMm b⍠&&v [ņƒïóėņ1lėQ%îģô–N“ÎüĘ0ÄÞ?kÔîˋЋ—AąŽ/:›ĮЂ:eęėáó-―éB— ĸVO–âķā<ģ@ n:‹ÏĄą„Z$­āÛīĒÜ:€tä*åáâY Đõ,˰aqúeKWóø|ãÔą8ÝEЀ%BéÅqxŠâŠ·˜†ÕnŲTāč7ĀŪóÛiũĸYl&ņfĩŽV‘dþÝy zmmÁiä…ã7-™O„ŌĖÆŸž€“ŦĘ'QiįFĮ…þŒqg_eÂÁŽdާhęŧÕÓ•É pķ ”î`Ģ™ęīHLä_“îķ#œŽgVõYgė,öâžųų ?2!VjB7ģ"˜”b Ïn[häZēE“h†­ēæÎō/ĐōdFBÚᇜ[Ü͍š―Ąíŋ5ģ~‹@ũ…üČœûá„ŅŨōˆ;],^&’x“–ƒåߊVf§šđ›r‰ PeĄ7āgH#bĘ―'ïČï“ōĶB™Rßɒ‡IøûÍĄĘĒą lEĩÞË#›ĸyMÉ4YtwƆþQ9·đóÂb™ĘņX–G;mƒšp·*Jn&X1œlķ_`Ÿ”Sy6|cÏuõQót]œ·˜íhæ­{Ī,P7L~Ė·­|ÞKoĘŽPãiŠČ;øēÕ‰ĖšuĸG,iÏÞ'ĢĮ“ˆļMŽ0œã|‘„Ēo2{•·ųÄ&ĀāSŧÉ.nF‡ŊN~đĀ #―äÝŧ\N^ĻáĪß·Ũ Ãūâœė Č"<ß\ĻÄ ·ąKäđ’ncĮœ„%wg@$ãbUŋ Į Āíę įĪ0<Ķ| kØž ,‘ŪĒ Ũed>ėžĘjŌėÏV úЁŲĢw%01øãfŪ3‘Éb}Ą/õëU”ãy”æÃWøýßW 5Ãô!õøīおu,pŲT”Ï…üÅÂĪÎĪݧy @à Üå/8V:ų)K4Ķ2ĩŠžŲ“Ý…mjqšņĖ7Ø"ŽŌ ŽáQâ)†oķ*ôwŊldæ@‹)å―Î<ÅoėŊTÜݐ„ķÜVqÔæî­8J;ÕĮÛwމĨũˆ‚—1J―8j=­ŒüœÖ n]æl ÛA xgÚ’ĖŠŦÞĩ›Ô ĢĐepÃđ•jȊė“@iW†ä~ ?樀zMpŪáņĢæ8ä7Žd/_ctđËĮūG*äąÚeSēēW ēxÄXÓY 8ž‘P}eŧcš3äNjR~ųĖdøįŪK•ĄhÏČĘÉ&cß< Usrr?,ZT+ū3›ïĐę–ßŦO3ÚíM0ąÝĶ”Põ™Č–Ē3·u-ēÅĨÏŒßTwŊ“™5ČÃģ€5;;íôDl;%A’›æĮ·}"P6 ųX8 ŦāėÉÐЍ„bÄÏOÖCauKŒŽÖŸWb22sÔYŨÃmÛ ^‘õXƒ'õmHeÔqâĖÉŦ‘ŸĮ#Ëĸëý ø†iК/K?ręæ’čĖ4ą,9‹(ÎÕEÆđƒ NįßʰËĩÕëgKâå ė!‚KĢ%ŲāÎBžĨ“þŒ˜Ó_‡M`f]úڌÂîHŠMS#‡ã~6DċNķ°ÍĢ8@…ĮlÍی^ؙĄËŽæ‡&Īiĩ‚ĪŪ9œ x6™!Áũŋ]ŽŸ{ÛR„Úm§ëöĘķœŅŌaI˜U[ģ’„ žþ(x92Į/ÃēílB ÚuÆĄŊÉ’§ūDf^;2Ŋ UøþÂčž7ũƒíŌ€ŨĖ Ž:\íšî‰Úk§r#%íœþ4Š# ž 7Ü#LŌ“Ū'ŠSØKææĖļ°ėGxĢlHšz"ö$æ'Æý1 UÕÓüAƒˆņüWū§Ûg)™2’/R“ŋÄØ[āVú ÐŅ…kiĐ·Ëïŧė™ßFž"ĖđšŸįŋMŽÎ{ÛBWØob€ŠČŅŠŒ‰|m†ģR―Ō \ĻŌÂøų·§Ėm2j+ĘæN^Ö^BÜŦŋ% ÂPßĞA%HŠð“{Ā‚‹âdm:ŋþë-YķÍؔ)B}3@ū―1óŠ B!Óīģ^ŋztĀuL·Žfð"•Zz]‹―"͞ŦbŊ{%eV\WÜĨZ^—īĖėâ3îCėw—Lŧ—Åāís•ËF' Qtí ŽĐqK– z†’~—E‡Œ<ĄčjuH3_ĄýČ{ xPvhĄļƒ―ģ)'Ō>mmęųęë'ĀŪ–ÉOb•D›LýÛĪ]؇5bá—Ŧ/É>þøl&5Ž8•ģ0fÕó‡"ėaÓV:aÕ`&Ā;Ny`NîÃkmėsbՉ•0ŋJķTp›U‘KðŪČąf{—/QÔĪęwڍęÛÉ[§Mœ‚&cu‘ž#îĮQĄÜžSga‡ú?Ũ·óž2ӘfČ%ģGOødƋ#N'”IŠ›Ųte>ÛúžŸõ ë_ÉQĩšaįk%B&)Gþ"í—Kþ[eŊąE‹°)é>ÞF*›né·™ÎÂ9ƒFâW­^…ßڍxkbÝt~"ĀÎđĐ\ŠrßĩZŧû˄ng‹“Ēt%Ņþ NÆ/ŽĀJž1 XŋŠÃ‘CĐ7úę2)IÅ E—Ó6›_œüXNĨícE7(5ý*JĩČh`mïjdĻŲpRĒþAã‹äzm^Đ{M-iŌ‘ŒÕ—e­Ú.ģHõUg|ø‚îõšŦÖGF7bôŋ"F|RïļwQįÔÞųîĄsŨkąBú·ōę–,˜ĮĩÁĀvņ‹“KX\F%d ļ `M•K ƒy[ŋK›6ßf%úr~ōņC%1 í8sŧÅčLwОėŠoÞs|듖M–îzæb0Uô.K€Œ-1J˜ ÅØ™KÜÞðô˜ÄųÆØ^}öƒÄŨ„T :›v‘o“2eDsF›ļ9ŌâŠæ`šóŅëûkÛžf‹ãú‚p+!šbĩ―zŦŌÉM(Õ(ï] WFr‘oĸîÐPĘv#Û.šŪø2‹>2'úóǧ†Nû›45D^ ôā˜ĩL˜š­Ã#})ÃjÁhCĄ=  LhūŲībÚŪŌ’7ļ!ó…ž~ QWÜÁĖ‹ŧQŠÕÐÕBŸ?RiÍ–=ŊņŠũ‹å Dã<*3gm'Í lÝ ĮōGRŽÐBr*4ņŊž|ōįrL01uÁŨK8=ĀŊĄP+:g:F1APÝĨۜ5nËÅó{ÖLð9ð›ÞĄw3j‹6ûëó…Isaƒ`‰°dĶxÐW: •3æX—Þ­’‰æØ65˜ũƒišŠ0\ÔĩÛ+Äļï‹SZ€mÐ<ÅiŌîĩÁŊ T‹čÐ\%ĩģ/ˆN7…d9zŸ‚^G_rnÎ@ëÎüތ‚Džųþ’ïŧŒY ú` 6rpŽņ”ÁspōøfM5wĀR`ŌMm%‘‚ËM95į–<•ížšAΉžâĄúU—Əžėũ~e5ĪAÓuZÎģ•Ðx,<™§ķēÔRŠē#.ĪóŲ‹uæÝ―ŽPá˜ŌĻ―Ï%šÉÓu l*gĘCwūV’ŅoÔԂíŦŋ [„ŠIhL&b ŠÏ>'ņ _6―Á< Ĩq<1q‚X?ßAašmåe§äfč`ô8°đ<JQßģāß;kkm/3døPyAð>h §ŽûÃZ^ˆ‘ÜĻaC ašw9EsāœĄ!ïVWfŠ čËðCąUðjŸĢ­*ß{œAŌĮóJ›ĸ$â*é#Õú\Ū֐ {˜ķ”Õ°Gāëĸgœï ‰  dŲĩâ…Ļ[vJĐČ §ĩ­ŧŌčáv& ‚Ë,t^c +Kz+(&øKÓÅÍ]‹M#ŨTü<>$0ķTĮ*rŒU’'K„Ȑ{J‘EŦpŸX\A†ï:ŸÞ?>ščOÁ=C'ôz‰ysF28ûj­Aĸ-ЀqAXŦ f–Áigėõ^å+§h‹ó|Ą:…)ڑĨǘJīHÎržá}HöRƒkB:“ŒŸ)Œ“*ØÚNeģpÕŅÂ9cōI>æ§uõba‹€—9AšüØzNðSd ý1Œy(ĩg§-HŲĮsČÄgæ\RēĀZmÉÔóJĀ ýë$ÜučéĶæ>ru(8j ˆ%(  OýeÎ9åÆÜkÉ<4éė Ðuĩ.ųÉč î,N:ŧŠ3úÅYč4 “Ė^ÛmŽV―Ý)~NyÃÃĮĮÃFÛ~ð+ˆë ž–ãČ' 2‹˜X›9wšųC…$öŊ@öËq$–uß­TļūÉéŠĘ"ãj ,™īÛú—}·ō)x˜ŌĶļ<žÜØ>#ßŲ'č(ÝŽxCÝá{9ūwójâMå0Š•qņ!@8ųF)MA,†@‡„€tĻķpŊˆĶ%˜ĘÄũݐ΋.1ČЍ―|&§%ðVm ;nž‰ĒY„Ž åņŨaŧ›áKĢÉ+įŌS īU˜ÐĀ0RØãJ6WĀ,ž+QUīøŨīÆ'<]ܛ{RdïrdųiZ9<Äæ_ēįĨjeLü%‘Î5bĻéôØ9Ų…Ä­āœaēÃ~EŦiy&Ōo9{=“ĐôšwIðža%be*Đ/ĢVsë[n› ņĒŪî3ąąáH}k`ŅĸÐð1<Õ,J^ŋ. ūá DŽîDīėĐŦÆŦæ"™ÕD%§iP‡F™W 2ĸÂÝ+a'Ú0ŅŊWH{dĄ&"%Íaē?5NŨŲ‰‘cŧ`ģdhwķã'…8ĩ,[ÕY<î8nPvðd“Ö%́ĸ{Ž3PYā$:ïĀĀ ]Ūĩō+Ę(wĄ™âAIįIŅïĪâLYqÏI—ōH>‘ĸ―’[í‰û―vb8ÕBF(„ dí―dNé’ažėƒ ÎÄjËxĢ’tī›ŦWÜđJÞý}uëIĩ[í_”|ĖžÕ\ï>āÜ"üQIČ7û’:Îa8ö`ZĐĻŦlá   "ˇ$rąŽ.Chn§<Ķ“0ĄŪTq4ð$œäī~4H‰6kCÐ8īœšøĶÞb‹ógސWģZ"Hp) â/Иa5ŒĐ"k6Ũ€ķ‹čýQs•U6UË_ˆ#ŽŅáô›Ę17–yõÛôāvŨJe3\oŒzI^Ü(û)Š1þÓ?ýÐ œÎĢ&tÔ&―‹, EœSb3â6&^ĐÄ€äĘÚé8Ûø‡Ũþžm0ÆĪ…ŠŠÐ 6™cLX#ڞŒCĐzŅZ`žLžå\‹íH8JM7 6‚tF`R!ÜŋVäú@hžą$? eúéDE>8Ŧ €ŒonЄ{|ßE˜ŸcĒáÁų}LΧ†”ę§ÜfĩvaL•^xeðQĪDš”wf'TöÐē?Ët.~ÁhåÉlÝkĀKĐqxæūõ{ø‘”díہ@ßÁĖ‘ȁÅ+3M:ŸĩJÁ'OņáoüöJ, Ėļ‚mí9ôčZ81В:Ā^čšõýīęDÉ|@ČĀĢāÚŅ·1ˆH·”šÂ<đ–{"ō݋ôŊ5ė€Ĩ"egķeĸežDFœŧ=Ę…9éa”ģqÎ)8ēMýY16ôk"?õðs§ó=Ī9ôžaÐŋ1ƒMk ÄŋžųŸĀ h,įükLõÚÕcu]ŧž°ƒč·Õ!öÆËeĸ―\ŸD•öOMS8 píÍðũ%ÓâÅóG#PØŠŦ™7pŲEÂ6cĔ„ę"\Mjˆ<þ‡Ý€ï0"Uuą ÛĒ ŽH0ĐqéËēíšP)]0˜%Ŧwú>]Ž ÍŨzō&ØYLŪfÔaĨõ7 įĘuüíÓâi$!a ;a$…s3ŪŨhYW$Óþģpąaįc·/Œ ŠØī*ûšTšëNąîņe‰tŅíU ú(áԊ&Ņ ŲôÓXŽŊžUԚÞiįĖÉÏB— .1Ŋ)aĢPâ=ÃÂÔ(&Ūäģg8~šķðnĘsØQŪūY{rõ~dŽq  #] €ž ,hüqt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/data/repository/Updates.xml0100777000000000000000000000073713761647206030007 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/licenseagreement.pro0100777000000000000000000000022413761647206026553 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_licenseagreement.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/settings.qrc0100777000000000000000000000024013761647206025064 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/licenseagreement/tst_licenseagreement.cpp0100777000000000000000000000413513761647206027434 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_licenseagreement : public QObject { Q_OBJECT private slots: void testAutoAcceptFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->setAutoAcceptLicenses(); core->installDefaultComponentsSilently(); QFile file(installDir + "/Licenses/gpl3.txt"); QVERIFY(file.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } }; QTEST_MAIN(tst_licenseagreement) #include "tst_licenseagreement.moc" qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/0040777000000000000000000000000013761647206023413 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/0040777000000000000000000000000013761647206024324 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/0040777000000000000000000000000013761647206026543 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/0040777000000000000000000000000013761647206026723 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1con0100777000000000000000000000027113761647206030142 0ustar007zžŊ'ž‘@'rE*Ņ<"Line to replace. Another line.  ' !! # ·ð°―  A.txt ï•ûÕ ï•ûÕ 6Ą]Ö ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1con0100777000000000000000000000005013761647206030135 0ustar00a0268f80fd2954271fe7d2eae584c13a6d143838././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/A/1.0.2-1met0100777000000000000000000000157513761647206030160 0ustar007zžŊ'{@ļe;"2ĞāÅ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũėÂw“NEJB5ë>ī… ÁųŊŋïM'Ėķ0–Wĩhšķ1ÆŽdĖŊ—ÄSpuƒm3bŽÏņųl;fČķiô.ŊOšøA܃U 3ŪÕG]@W$Óþģp@p§gOĀ‘úÝÚu†%310åޓ 3=AE™é:+‰ f>ŒÐÍ5,aų)ĪĨhšš‡í_øh,ūĖ―‰Ûør(Lk2Ü $2`ĸPé|ũŽĻŒäĩ…Ã)k‚Í n #] €ž –ß?~qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/data/repository/Updates.xml0100777000000000000000000000111313761647206030666 0ustar00 {AnyApplication} 1.0.0 true A A Example component A 1.0.2-1 2015-01-01 true content.7z 6d7a3e15d11a4d94b81452fc2aa18e705a01c922 qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/linereplaceoperation.pro0100777000000000000000000000023013761647206030334 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_linereplaceoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/settings.qrc0100777000000000000000000000042713761647206025765 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1content.7z.sha1 data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/linereplaceoperation/tst_linereplaceoperation.cpp0100777000000000000000000001246713761647206031227 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_linereplaceoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_testFilePath = qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); } void testMissingArguments() { LineReplaceOperation op(nullptr); op.backup(); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in LineReplace: " "0 arguments given, exactly 3 arguments expected.")); op.setArguments(QStringList() << m_testFilePath << "" << "replace"); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid argument in LineReplace: " "Empty search argument is not supported.")); op.setArguments(QStringList() << "" << "search" << "replace"); QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified"); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("Cannot open file \"\" for reading: No file name specified")); } void testSearchReplace_data() { QTest::addColumn("source"); QTest::addColumn("search"); QTest::addColumn("replace"); QTest::addColumn("expected"); QTest::newRow("Lorem ipsum") << "Lorem ipsum dolore sit amet, consectetur adipiscing elit,\n" "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." << "Lorem" << "Replaced" << "Replaced\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n"; QTest::newRow(".ini syntax") << "[section]\na=x\nb=y" << "a=" << "a=y" << "[section]\na=y\nb=y\n"; QTest::newRow(".xml syntax") << "\n\n\n" "" << "" << "el" << "\n" "\nel\n\n"; } void testSearchReplace() { QFETCH(QString, source); QFETCH(QString, search); QFETCH(QString, replace); QFETCH(QString, expected); QFile file(m_testFilePath); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream stream(&file); stream << source << endl; file.close(); LineReplaceOperation op(nullptr); op.setArguments(QStringList() << m_testFilePath << search << replace); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QCOMPARE(stream.readAll(), expected); file.close(); QVERIFY(file.remove()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); QFile file(installDir + QDir::separator() + "A.txt"); QVERIFY(file.open(QIODevice::ReadOnly) | QIODevice::Text); QTextStream stream(&file); QCOMPARE(stream.readLine(), QLatin1String("This line was replaced.")); QCOMPARE(stream.readLine(), QLatin1String("Another line.")); file.close(); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_testFilePath; }; QTEST_MAIN(tst_linereplaceoperation) #include "tst_linereplaceoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/0040777000000000000000000000000013761647206022702 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/0040777000000000000000000000000013761647206023613 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/0040777000000000000000000000000013761647206026105 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/B/0040777000000000000000000000000013761647206026266 5ustar00././@LongLink0100777000000000000000000000015113761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/B/1.0.0-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/B/1.0.0-1conte0100777000000000000000000000022013761647206030026 0ustar007zžŊ'žĪNRgmĢÏExample content for B.   !!  §îF  B.txt žtj%6Ö ././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/B/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/B/1.0.0-1conte0100777000000000000000000000005013761647206030027 0ustar001c99fe9980cb71dde6a8468c9aa09b4153bc3bffqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidhash/Updates.xml0100777000000000000000000000076613761647206030245 0ustar00 {AnyApplication} 1.0.0 true B B Example component B 1.0.0-1 2015-01-01 true content.7z qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/0040777000000000000000000000000013761647206027162 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/A/0040777000000000000000000000000013761647206027342 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/A/1.0.2-10100777000000000000000000000151113761647206030057 0ustar007zžŊ'5æCé!lDNāĮ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũð2õ4Æ>ʘsnþ'Ŋú(uę9―üuK3€Ō7ŨðÏæ3ŪÕFzVW$Óþģp@g͗[ÂåuExf2|ģjđŧŪūdWQÂ}“}î0ŒČX'ČČėÔä~ņRąHđ§ëóŦĻ gkä&YũŦŒ!]™°”Ģč›ĘiilØ ‚Ĩ c #] n þml‘././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/invalidoperation/Updates.x0100777000000000000000000000057213761647206030764 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/messagebox/0040777000000000000000000000000013761647206025750 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/messagebox/A/0040777000000000000000000000000013761647206026130 5ustar00././@LongLink0100777000000000000000000000014513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/messagebox/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/messagebox/A/1.0.2-1meta.70100777000000000000000000000165113761647206027666 0ustar007zžŊ'>nÓRh!_ĩ9Nā3]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ{u2E&gp2ýÛK“ũð$#ÎcõžēMé#KQhōÚ|xÞÎw‚―/sĐPeîūcwiœÁģŠ_đNņgËŅÏÝ_ Ōģß3ļq}E9œęÂīœðąĐtQfõ)ņrėķÍîŲn1ķ`9.ČV ÔRS ŽfE„Đãʆ9Å$―;į•ņž`™›RūÃÕōzŧO °AOæÝ‹ ß"ÝLú‘V3ŪÕNyÆfڍóóĢŅ)P°Ý)eöX@0[YڄßIāÁp ~ý“;ĢÐþ#ýæ<úŧwÔÔx[i-ÕxObïĐâĩôDƒ@ä]Ŋ^>öƒ  [ #] n ĩ،wqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/messagebox/Updates.xml0100777000000000000000000000057213761647206030103 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/missingarchive/0040777000000000000000000000000013761647206026626 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/missingarchive/C/0040777000000000000000000000000013761647206027010 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/missingarchive/C/1.0.0content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/missingarchive/C/1.0.0cont0100777000000000000000000000005013761647206030246 0ustar001c99fe9980cb71dde6a8468c9aa09b4153bc3bffqt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/data/missingarchive/Updates.xml0100777000000000000000000000105413761647206030755 0ustar00 {AnyApplication} 1.0.0 true C C Example component C 1.0.0 2015-01-01 true content.7z 3c940d54a1643ae8020162797860e827f8d246ca qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/messageboxhandler.pro0100777000000000000000000000017413761647206027121 0ustar00include(../../qttest.pri) SOURCES += tst_messageboxhandler.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/settings.qrc0100777000000000000000000000106313761647206025251 0ustar00 data/invalidhash/Updates.xml data/invalidhash/B/1.0.0-1content.7z data/invalidhash/B/1.0.0-1content.7z.sha1 data/invalidoperation/Updates.xml data/invalidoperation/A/1.0.2-1meta.7z data/missingarchive/Updates.xml data/missingarchive/C/1.0.0content.7z.sha1 data/messagebox/Updates.xml data/messagebox/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp0100777000000000000000000002200113761647206027766 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* srand, rand */ #include /* time */ using namespace QInstaller; QT_BEGIN_NAMESPACE namespace QTest { template<> char *toString(const QMessageBox::StandardButton &button) { QString buttonAsString(QString::number(button)); return qstrdup(buttonAsString.toLatin1().data()); } } QT_END_NAMESPACE class tst_MessageBoxHandler : public QObject { Q_OBJECT private: void setRepository(const QString &repository) { core->cancelMetaInfoJob(); QSet repoList; Repository repo = Repository::fromUserInput(repository); repoList.insert(repo); core->settings().setDefaultRepositories(repoList); } private slots: void initTestCase() { m_maxStandardButtons = 0; const QMetaObject &messageBoxMetaObject = QMessageBox::staticMetaObject; int index = messageBoxMetaObject.indexOfEnumerator("StandardButtons"); QMetaEnum metaEnum = messageBoxMetaObject.enumerator(index); for (int i = 0; i < metaEnum.keyCount(); i++) { int enumValue = metaEnum.value(i); if (enumValue < QMessageBox::FirstButton) continue; m_standardButtonValueMap.insert(static_cast(enumValue), metaEnum.valueToKey(metaEnum.value(i))); m_maxStandardButtons += enumValue; if (enumValue == QMessageBox::LastButton) break; } QInstaller::init(); //This will eat debug output core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList (), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, QHash(), true); core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath()); core->disableWriteMaintenanceTool(); core->setAutoConfirmCommand(); m_installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(m_installDir)); core->setValue(scTargetDir, m_installDir); } void testScriptButtonValues() { ScriptEngine *scriptEngine = new ScriptEngine(core); QMapIterator i(m_standardButtonValueMap); while (i.hasNext()) { i.next(); const QString scriptString = QString::fromLatin1("QMessageBox.%1").arg(i.value()); const QJSValue scriptValue = scriptEngine->evaluate(scriptString); QVERIFY2(!scriptValue.isError(), qPrintable(scriptValue.toString())); QVERIFY2(!scriptValue.isUndefined(), qPrintable( QString::fromLatin1("It seems that %1 is undefined.").arg(scriptString))); QCOMPARE(static_cast(scriptValue.toInt()), i.key()); } } void testDefaultAction() { srand(time(0)); /* initialize random seed: */ int standardButtons = QMessageBox::NoButton; MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Reject); const QList orderedButtons = MessageBoxHandler::orderedButtons(); do { standardButtons += QMessageBox::FirstButton; /* generate secret number between 1 and 10: */ const int iSecret = rand() % 10 + 1; // use only every 5th run to reduce the time which it takes to run this test if (iSecret > 2) continue; int returnButton = MessageBoxHandler::instance()->critical(QLatin1String("TestError"), QLatin1String("A test error"), QLatin1String("This is a test error message."), static_cast(standardButtons)); QMessageBox::StandardButton wantedButton = QMessageBox::NoButton; // find the last button which is the wanted reject button in the current // standardButtons combination foreach (QMessageBox::StandardButton button, orderedButtons) { if (standardButtons & button) wantedButton = button; } QVERIFY2(wantedButton != QMessageBox::NoButton, "Cannot find a wantedButton."); QCOMPARE(static_cast(returnButton), wantedButton); } while (standardButtons < m_maxStandardButtons); } void invalidOperationAutoReject() { setRepository(":///data/invalidoperation"); core->autoRejectMessageBoxes(); core->installDefaultComponentsSilently(); QCOMPARE(PackageManagerCore::Canceled, core->status()); } void invalidOperationAutoAccept() { setRepository(":///data/invalidoperation"); core->autoAcceptMessageBoxes(); core->installDefaultComponentsSilently(); QCOMPARE(PackageManagerCore::Success, core->status()); } void invalidHashAutoReject() { setRepository(":///data/invalidhash"); core->autoRejectMessageBoxes(); core->installSelectedComponentsSilently(QStringList () << "B"); QCOMPARE(PackageManagerCore::Failure, core->status()); } void invalidHashAutoAccept() { setRepository(":///data/invalidhash"); core->autoAcceptMessageBoxes(); core->installSelectedComponentsSilently(QStringList () << "B"); QCOMPARE(PackageManagerCore::Failure, core->status()); } void missingArchiveAutoReject() { setRepository(":///data/missingarchive"); core->autoRejectMessageBoxes(); core->installSelectedComponentsSilently(QStringList () << "C"); QCOMPARE(PackageManagerCore::Canceled, core->status()); } void missingArchiveAutoAccept() { setRepository(":///data/missingarchive"); core->autoAcceptMessageBoxes(); core->installSelectedComponentsSilently(QStringList () << "C"); QCOMPARE(PackageManagerCore::Canceled, core->status()); } void messageBoxFromScriptDefaultAnswer() { setRepository(":///data/messagebox"); core->acceptMessageBoxDefaultButton(); core->installSelectedComponentsSilently(QStringList () << "A"); // These values are written in script based on default // messagebox query results. QCOMPARE(core->value("test.question.default.ok"), QLatin1String("Ok")); QCOMPARE(core->value("test.question.default.cancel"), QLatin1String("Cancel")); } void messageBoxFromScriptAutoAnswer() { setRepository(":///data/messagebox"); core->setMessageBoxAutomaticAnswer("test.question.default.ok", QMessageBox::Cancel); core->setMessageBoxAutomaticAnswer("test.question.default.cancel", QMessageBox::Ok); core->installSelectedComponentsSilently(QStringList () << "A"); // These values are written in script based on // messagebox query results. QCOMPARE(core->value("test.question.default.ok"), QLatin1String("Cancel")); QCOMPARE(core->value("test.question.default.cancel"), QLatin1String("Ok")); } void cleanupTestCase() { core->deleteLater(); QDir dir(m_installDir); QVERIFY(dir.removeRecursively()); } private: QMap m_standardButtonValueMap; int m_maxStandardButtons; PackageManagerCore *core; QString m_installDir; }; QTEST_GUILESS_MAIN(tst_MessageBoxHandler) #include "tst_messageboxhandler.moc" qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/0040777000000000000000000000000013761647206021462 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/0040777000000000000000000000000013761647206022373 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/config.xml0100777000000000000000000000043513761647206024364 0ustar00 Your application 1.2.3 qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/0040777000000000000000000000000013761647206024612 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/0040777000000000000000000000000013761647206026361 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/0040777000000000000000000000000013761647206026541 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1con0100777000000000000000000000026613761647206027764 0ustar007zžŊ'Cņ$ržĶ^Example content for package A.  $ !!  ŲþŋI  A.txt ;Ōž†‚Õ ;Ōž†‚Õ ;Ōž†‚Õ ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1con0100777000000000000000000000005013761647206027753 0ustar00643cb71b2337d5a49d57a5bc3c636ee9b84c0802././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1met0100777000000000000000000000015213761647206027764 0ustar007zžŊ'œ{afJš…ï9€A —’—ęūÕ —’—ęūÕ —’—ęūÕqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/0040777000000000000000000000000013761647206026542 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1con0100777000000000000000000000026613761647206027763 0ustar007zžŊ'Ų ĸo$rŸôExample content for package B.  $ !!  7Q [  B.txt Tųž†‚Õ Tųž†‚Õ Ōžž†‚Õ ././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1con0100777000000000000000000000005013761647206027752 0ustar00c7b9ab370efe036171dda7b71cd95021747cb101././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1met0100777000000000000000000000015213761647206027763 0ustar007zžŊ'đŲ―~JjīH€B N “—ęūÕ N “—ęūÕ N “—ęūÕqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionAdd/Updates.xml0100777000000000000000000000210213761647206030503 0ustar00 {AnyApplication} 1.0.0 true A A Example component A 1.0.2-1 2015-01-01 true content.7z 9d54e3a5adf3563913feee8ba23a99fb80d46590 B B Example component B 1.0.0-1 2015-01-01 true content.7z 9170d55a6af81c1a6a63d708a4ab6ed359775cd9 qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/0040777000000000000000000000000013761647206027126 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/0040777000000000000000000000000013761647206027310 5ustar00././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-10100777000000000000000000000026613761647206030031 0ustar007zžŊ' Ôq‹$r―4ĮpExample content for package B.  $ !!  7Q [  C.txt ø”žž†‚Õ ø”žž†‚Õ ø”žž†‚Õ ././@LongLink0100777000000000000000000000016313761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-10100777000000000000000000000005013761647206030020 0ustar00c8b7076fabaaf6b9d27f27350c577118c24f426b././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-10100777000000000000000000000015213761647206030023 0ustar007zžŊ'.NŽJaŧIï€C u­–ëūÕ u­–ëūÕ u­–ëūÕ././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repositoryActionRemove/Updates.x0100777000000000000000000000121313761647206030721 0ustar00 {AnyApplication} 1.0.0 true C C Example component C 1.0.0-1 2015-01-01 true content.7z 5b3939da1af492382c68388fc796837e4c36b876 qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/C/0040777000000000000000000000000013761647206024774 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z0100777000000000000000000000026613761647206027447 0ustar007zžŊ' Ôq‹$r―4ĮpExample content for package B.  $ !!  7Q [  C.txt ø”žž†‚Õ ø”žž†‚Õ ø”žž†‚Õ ././@LongLink0100777000000000000000000000014713761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.sha1qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.s0100777000000000000000000000005013761647206027677 0ustar00c8b7076fabaaf6b9d27f27350c577118c24f426bqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1meta.7z0100777000000000000000000000015213761647206026715 0ustar007zžŊ'.NŽJaŧIï€C u­–ëūÕ u­–ëūÕ u­–ëūÕqt-installer-framework-4.0.1/tests/auto/installer/metadatajob/data/repository/Updates.xml0100777000000000000000000000105613761647206026743 0ustar00 {AnyApplication} 1.0.0 true C C Example component C 1.0.0-1 2015-01-01 true content.7z 5b3939da1af492382c68388fc796837e4c36b876 qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/metadatajob.pro0100777000000000000000000000014613761647206024460 0ustar00include(../../qttest.pri) QT += qml SOURCES += tst_metadatajob.cpp RESOURCES += \ settings.qrc qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/settings.qrc0100777000000000000000000000040613761647206024031 0ustar00 data/config.xml data/repository/Updates.xml data/repositoryActionAdd/Updates.xml data/repositoryActionRemove/Updates.xml qt-installer-framework-4.0.1/tests/auto/installer/metadatajob/tst_metadatajob.cpp0100777000000000000000000000752713761647206025346 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "metadatajob.h" #include "settings.h" #include #include #include #include #include #include #include using namespace QInstaller; class tst_MetaDataJob : public QObject { Q_OBJECT private slots: void testRepository() { Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data"); PackageManagerCore core; core.setInstaller(); QSet repoList; Repository repo = Repository::fromUserInput(":///data/repository"); repoList.insert(repo); core.settings().setDefaultRepositories(repoList); MetadataJob metadata; metadata.setPackageManagerCore(&core); metadata.start(); metadata.waitForFinished(); QCOMPARE(metadata.metadata().count(), 1); } void testRepositoryUpdateActionAdd() { Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data"); PackageManagerCore core; core.setInstaller(); QSet repoList; Repository repo = Repository::fromUserInput(":///data/repositoryActionAdd"); repoList.insert(repo); core.settings().setDefaultRepositories(repoList); MetadataJob metadata; metadata.setPackageManagerCore(&core); QTest::ignoreMessage(QtDebugMsg, "Repository to add: \"Example repository\""); QTest::ignoreMessage(QtDebugMsg, "Repository to add: \"Example repository\""); metadata.start(); metadata.waitForFinished(); QCOMPARE(metadata.metadata().count(), 2); } void testRepositoryUpdateActionRemove() { Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data"); PackageManagerCore core; core.setInstaller(); QSet repoList; Repository repo = Repository::fromUserInput(":///data/repositoryActionRemove"); Repository repo2 = Repository::fromUserInput(":///data/repository"); repoList.insert(repo); repoList.insert(repo2); core.settings().setDefaultRepositories(repoList); MetadataJob metadata; metadata.setPackageManagerCore(&core); QTest::ignoreMessage(QtDebugMsg, "Repository to remove: \"file::///data/repository\""); QTest::ignoreMessage(QtDebugMsg, "Repository to remove: \"file::///data/repository\""); metadata.start(); metadata.waitForFinished(); QCOMPARE(metadata.metadata().count(), 1); } }; QTEST_MAIN(tst_MetaDataJob) #include "tst_metadatajob.moc" qt-installer-framework-4.0.1/tests/auto/installer/mkdiroperationtest/0040777000000000000000000000000013761647206023136 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/mkdiroperationtest/mkdiroperationtest.pro0100777000000000000000000000013113761647206027602 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_mkdiroperationtest.cpp qt-installer-framework-4.0.1/tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp0100777000000000000000000001306213761647206030465 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "init.h" #include "updateoperations.h" #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_mkdiroperationtest : public QObject { Q_OBJECT private slots: void initTestCase() { QInstaller::init(); QString path = QDir::current().path() + QDir::toNativeSeparators("/test"); if (QDir(path).exists()) { QFAIL("Remove test folder first!"); } } void testMissingArguments() { MkdirOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in Mkdir: " "0 arguments given, exactly 1 arguments expected.")); } void testCreateDirectory_data() { QTest::addColumn("directory"); QTest::newRow("/test") << "/test"; QTest::newRow("/test/test") << "/test/test"; QTest::newRow("/test/test/test") << "/test/test/test"; } void testCreateDirectory() { QFETCH(QString, directory); QString path = QDir::current().path() + QDir::toNativeSeparators(directory); QVERIFY2(!QDir(path).exists(), path.toLatin1()); MkdirOperation op; op.setArguments(QStringList() << path); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY2(QDir(path).exists(), path.toLatin1()); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY2(!QDir(path).exists(), path.toLatin1()); } void testCreateDirectory_customFile_data() { QTest::addColumn("directory"); QTest::addColumn("filename"); QTest::newRow("/test") << "/test" << "/test/file.txt"; QTest::newRow("/test/test") << "/test/test" << "/test/file.txt"; QTest::newRow("/test/test/test") << "/test/test/test" << "/test/test/test/file.txt"; } void testCreateDirectory_customFile() { QFETCH(QString, directory); QFETCH(QString, filename); QString path = QDir::current().path() + QDir::toNativeSeparators(directory); QString filepath = QDir::current().path() + QDir::toNativeSeparators(filename); QVERIFY2(!QDir(path).exists(), path.toLatin1()); MkdirOperation op; op.setArguments(QStringList() << path); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY2(QDir(path).exists(), path.toLatin1()); QFile file(filepath); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out << "This file is generated by QTest\n"; file.close(); QVERIFY2(!op.undoOperation(), op.errorString().toLatin1()); QVERIFY2(file.exists(), filepath.toLatin1()); QVERIFY2(QDir(filepath).remove(filepath), "Cannot remove file"); QVERIFY2(!file.exists(), filepath.toLatin1()); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY2(!QDir(path).exists(), path.toLatin1()); } void testCreateDirectory_customFile_force_data() { testCreateDirectory_customFile_data(); } void testCreateDirectory_customFile_force() { QFETCH(QString, directory); QFETCH(QString, filename); QString path = QDir::current().path() + QDir::toNativeSeparators(directory); QString filepath = QDir::current().path() + QDir::toNativeSeparators(filename); QVERIFY2(!QDir(path).exists(), path.toLatin1()); MkdirOperation op; op.setArguments(QStringList() << path); op.setValue("forceremoval",true); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY2(QDir(path).exists(), path.toLatin1()); QFile file(filepath); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out << "This file is generated by QTest\n"; file.close(); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY2(!file.exists(), path.toLatin1()); } }; QTEST_MAIN(tst_mkdiroperationtest) #include "tst_mkdiroperationtest.moc" qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/0040777000000000000000000000000013761647206022076 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/data/0040777000000000000000000000000013761647206023007 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/data/repository/0040777000000000000000000000000013761647206025226 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/data/repository/A/0040777000000000000000000000000013761647206025406 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/data/repository/A/1.0.2-1meta.7z0100777000000000000000000000161513761647206027336 0ustar007zžŊ'æ‘ėDL!Ę\~ęāēâ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũėÂvūyËc…žĄRų†^õųTîl}­Ũ& ÕXÜ \‘ĄšUĖbáÍK!PŌŌ›"č oŌ™bF 0UN§qã ;„ûĸwVoEˆ\7[ķÝ^*Ōð–‚aVZ)ŨŲQÔB3ŪÕHÄ7%GWÓĢX"Ofû·Âã‘›>O}ŸØ†ÁɒƒmŠ'FQG: G` CbcËāŧ+2ðx”(XLģa8ŲØýAœŦĂo‚VÚČé‚ę b #] n îbŲ qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/data/repository/Updates.xml0100777000000000000000000000062613761647206027361 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/moveoperation.pro0100777000000000000000000000022013761647206025501 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_moveoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/settings.qrc0100777000000000000000000000024013761647206024441 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/moveoperation/tst_moveoperation.cpp0100777000000000000000000001124513761647206026366 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_moveoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(m_testDirectory)); QVERIFY(QDir(m_testDirectory).exists()); QString testFile = QDir::toNativeSeparators("/testFile.txt"); m_sourceFile = qApp->applicationDirPath() + testFile; QFile file(m_sourceFile); QVERIFY(file.open(QIODevice::WriteOnly)); //Generates the m_sourceFile file.close(); m_destinationDirectory = m_testDirectory + QDir::toNativeSeparators("/test"); QVERIFY(QDir().mkpath(m_destinationDirectory)); m_destinationFile = m_destinationDirectory + QDir::toNativeSeparators(testFile); } void testMissingArguments() { MoveOperation op; QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in Move: " "0 arguments given, exactly 2 arguments expected.")); } void testMoveFile() { MoveOperation op; op.setArguments(QStringList() << m_sourceFile << m_destinationFile); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFile::exists(m_sourceFile)); QVERIFY(QFile::exists(m_destinationFile)); QVERIFY(op.undoOperation()); QVERIFY(QFile::exists(m_sourceFile)); QVERIFY(!QFile::exists(m_destinationFile)); } void testMoveFileDestinationExists() { QFile file(m_destinationFile); QVERIFY(file.open(QIODevice::WriteOnly)); //Creates the destination file file.close(); MoveOperation op; op.setArguments(QStringList() << m_sourceFile << m_destinationFile); op.backup(); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFile::exists(m_sourceFile)); QVERIFY(QFile::exists(m_destinationFile)); QVERIFY(op.undoOperation()); QVERIFY(QFile::exists(m_sourceFile)); QVERIFY(QFile::exists(m_destinationFile)); } void testPerformingFromCLI() { PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_testDirectory, ":///data/repository"); core->installDefaultComponentsSilently(); QFile movedFile(m_testDirectory + QDir::separator() + "DestinationFolder/testFile.txt"); QVERIFY(movedFile.exists()); QFile originalFile(m_sourceFile); QVERIFY(!originalFile.exists()); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!movedFile.exists()); QVERIFY(originalFile.exists()); core->deleteLater(); } void cleanupTestCase() { QDir dir(m_testDirectory); QVERIFY(dir.removeRecursively()); QVERIFY(QFile::remove(m_sourceFile)); } private: QString m_testDirectory; QString m_sourceFile; QString m_destinationDirectory; QString m_destinationFile; }; QTEST_MAIN(tst_moveoperation) #include "tst_moveoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/0040777000000000000000000000000013761647206023006 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/installer-config/0040777000000000000000000000000013761647206026246 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/installer-config/config.xml0100777000000000000000000000044413761647206030237 0ustar00 Unit Test Application Unit Test Application Title 1.0.0 The Qt Company UnitTestMaintenancetool qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/packagemanagercore.pro0100777000000000000000000000015513761647206027330 0ustar00include(../../qttest.pri) QT += qml SOURCES += tst_packagemanagercore.cpp RESOURCES += \ settings.qrc qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/settings.qrc0100777000000000000000000000016313761647206025355 0ustar00 installer-config/config.xml qt-installer-framework-4.0.1/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp0100777000000000000000000003522213761647206030207 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace QInstaller; class DummyComponent : public Component { public: DummyComponent(PackageManagerCore *core) : Component(core) { setCheckState(Qt::Checked); } void beginInstallation() { throw Error(tr("Force crash to test rollback!")); } ~DummyComponent() { } }; class NamedComponent : public Component { public: NamedComponent(PackageManagerCore *core, const QString &name) : Component(core) { setValue(scName, name); setValue(scVersion, QLatin1String("1.0.0")); } NamedComponent(PackageManagerCore *core, const QString &name, const QString &version) : Component(core) { setValue(scName, name); setValue(scVersion, version); } }; class tst_PackageManagerCore : public QObject { Q_OBJECT private: void setIgnoreMessage(const QString &testDirectory) { const QString message = "\t- arguments: %1"; QTest::ignoreMessage(QtDebugMsg, "Operations sanity check succeeded."); QTest::ignoreMessage(QtDebugMsg, "backup operation: Mkdir"); QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(testDirectory))); QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(testDirectory))); QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(testDirectory))); QTest::ignoreMessage(QtDebugMsg, "perform operation: Mkdir"); QTest::ignoreMessage(QtDebugMsg, "Install size: 1 components"); QTest::ignoreMessage(QtDebugMsg, "ROLLING BACK operations= 1"); QTest::ignoreMessage(QtDebugMsg, "undo operation: Mkdir"); QTest::ignoreMessage(QtDebugMsg, "Done"); QTest::ignoreMessage(QtDebugMsg, "Done"); QTest::ignoreMessage(QtDebugMsg, "Done"); } private slots: void testRollBackInstallationKeepTarget() { const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); setIgnoreMessage(testDirectory); PackageManagerCore core(QInstaller::BinaryContent::MagicInstallerMarker, QList()); // cancel the installer in error case core.autoRejectMessageBoxes(); core.appendRootComponent(new DummyComponent(&core)); core.setValue(QLatin1String("TargetDir"), testDirectory); core.setValue(QLatin1String("RemoveTargetDir"), QLatin1String("true")); QVERIFY(core.calculateComponentsToInstall()); { QFile dummy(testDirectory + QLatin1String("/dummy")); QVERIFY(dummy.open(QIODevice::ReadWrite)); core.runInstaller(); QVERIFY(QDir(testDirectory).exists()); QVERIFY(QFileInfo(dummy.fileName()).exists()); dummy.close(); QVERIFY(dummy.remove()); } QVERIFY(QDir().rmdir(testDirectory)); ProgressCoordinator::instance()->reset(); } void testRollBackInstallationRemoveTarget() { const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); setIgnoreMessage(testDirectory); PackageManagerCore core(QInstaller::BinaryContent::MagicInstallerMarker, QList()); // cancel the installer in error case core.autoRejectMessageBoxes(); core.appendRootComponent(new DummyComponent(&core)); core.setValue(QLatin1String("TargetDir"), testDirectory); core.setValue(QLatin1String("RemoveTargetDir"), QLatin1String("true")); QVERIFY(core.calculateComponentsToInstall()); core.runInstaller(); QVERIFY(!QDir(testDirectory).exists()); ProgressCoordinator::instance()->reset(); } void testComponentSetterGetter() { { PackageManagerCore core; core.setPackageManager(); QCOMPARE(core.components(PackageManagerCore::ComponentType::Root).count(), 0); QCOMPARE(core.components(PackageManagerCore::ComponentType::All).count(), 0); Component *root = new NamedComponent(&core, QLatin1String("root1")); root->appendComponent(new NamedComponent(&core, QLatin1String("root1.foo"), QLatin1String("1.0.1"))); root->appendComponent(new NamedComponent(&core, QLatin1String("root1.bar"))); core.appendRootComponent(root); QCOMPARE(core.components(PackageManagerCore::ComponentType::Root).count(), 1); QCOMPARE(core.components(PackageManagerCore::ComponentType::All).count(), 3); Component *foo = core.componentByName(QLatin1String("root1.foo-1.0.1")); QVERIFY(foo != 0); QCOMPARE(foo->name(), QLatin1String("root1.foo")); QCOMPARE(foo->value(scVersion), QLatin1String("1.0.1")); foo->appendComponent(new NamedComponent(&core, QLatin1String("root1.foo.child"))); Component *v = new NamedComponent(&core, QLatin1String("root1.foo.virtual.child")); v->setValue(scVirtual, QLatin1String("true")); foo->appendComponent(v); QCOMPARE(core.components(PackageManagerCore::ComponentType::Root).count(), 1); QCOMPARE(core.components(PackageManagerCore::ComponentType::All).count(), 5); core.appendRootComponent(new NamedComponent(&core, QLatin1String("root2"))); QCOMPARE(core.components(PackageManagerCore::ComponentType::Root).count(), 2); QCOMPARE(core.components(PackageManagerCore::ComponentType::All).count(), 6); } { PackageManagerCore core; core.setUpdater(); Component *root = new NamedComponent(&core, QLatin1String("root1")); try { root->appendComponent(new NamedComponent(&core, QLatin1String("root1.foo"))); QFAIL("Components cannot have children in updater mode."); } catch (const QInstaller::Error &error) { QCOMPARE(error.message(), QString("Components cannot have children in updater mode.")); } core.appendUpdaterComponent(root); core.appendUpdaterComponent(new NamedComponent(&core, QLatin1String("root2"))); Component *v = new NamedComponent(&core, QLatin1String("root3"), QLatin1String("2.0.1")); v->setValue(scVirtual, QLatin1String("true")); core.appendUpdaterComponent(v); QCOMPARE(core.components(PackageManagerCore::ComponentType::Root).count(), 3); QCOMPARE(core.components(PackageManagerCore::ComponentType::All).count(), 3); Component *root3 = core.componentByName(QLatin1String("root3->2.0.2")); QVERIFY(root3 == 0); root3 = core.componentByName(QLatin1String("root3->2.0.0")); QVERIFY(root3 != 0); QCOMPARE(root3->name(), QLatin1String("root3")); QCOMPARE(root3->value(scVersion), QLatin1String("2.0.1")); } } void testRequiredDiskSpace() { // test installer QTest::ignoreMessage(QtDebugMsg, "Operations sanity check succeeded."); PackageManagerCore core(QInstaller::BinaryContent::MagicInstallerMarker, QList()); DummyComponent *root = new DummyComponent(&core); root->setValue(scName, "root"); root->setValue(scUncompressedSize, QString::number(1000)); core.appendRootComponent(root); DummyComponent *child1 = new DummyComponent(&core); child1->setValue(scName, "root.child1"); child1->setValue(scUncompressedSize, QString::number(1500)); root->appendComponent(child1); DummyComponent *child2 = new DummyComponent(&core); child2->setValue(scName, "root.child2"); child2->setValue(scUncompressedSize, QString::number(250)); root->appendComponent(child2); // install root, child1 (child2 remains uninstalled) root->setUninstalled(); child1->setUninstalled(); child2->setInstalled(); core.calculateComponentsToInstall(); QCOMPARE(core.requiredDiskSpace(), 2500ULL); // additionally install child2 root->setInstalled(); child1->setInstalled(); child2->setUninstalled(); core.componentsToInstallNeedsRecalculation(); core.calculateComponentsToInstall(); QCOMPARE(core.requiredDiskSpace(), 250ULL); } void testDirectoryWritable() { PackageManagerCore core; const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); QVERIFY(QDir(testDirectory).exists()); // should be writable QVERIFY(core.directoryWritable(testDirectory)); #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) QFile dirDevice(testDirectory); dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::ExeOwner); // should not be writable QVERIFY(!core.directoryWritable(testDirectory)); dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); #endif QVERIFY(QDir().rmdir(testDirectory)); } void testAllowRunningProcess() { #ifdef Q_OS_MACOS QSKIP("In macOS the app path and maintenancetool differ, not possible to test running processes."); #endif PackageManagerCore core; core.setPackageManager(); const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); core.setValue(scTargetDir, testDirectory); QString appFilePath = QCoreApplication::applicationFilePath(); core.setAllowedRunningProcesses(QStringList() << appFilePath); const QString warningMessage = QString("Failure to read packages from "); const QRegularExpression re(warningMessage); QTest::ignoreMessage(QtWarningMsg, re); QTest::ignoreMessage(QtDebugMsg, "No updates available."); QCOMPARE(PackageManagerCore::Failure, core.updateComponentsSilently(QStringList())); QVERIFY(QDir().rmdir(testDirectory)); } void testDisallowRunningProcess() { #ifdef Q_OS_MACOS QSKIP("In macOS the app path and maintenancetool differ, not possible to test running processes."); #endif PackageManagerCore core; core.setPackageManager(); const QString testDirectory = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(testDirectory)); core.setValue(scTargetDir, testDirectory); const QString warningMessageUp = QString("Unable to update components. Please stop these processes: "); const QRegularExpression reUp(warningMessageUp); QTest::ignoreMessage(QtWarningMsg, reUp); QVERIFY_EXCEPTION_THROWN(core.updateComponentsSilently(QStringList()), Error); const QString warningMessageRm = QString("Unable to remove components. Please stop these processes: "); const QRegularExpression reRm(warningMessageRm); QTest::ignoreMessage(QtWarningMsg, reRm); QVERIFY_EXCEPTION_THROWN(core.removeInstallationSilently(), Error); QVERIFY(QDir().rmdir(testDirectory)); } void testCoreDataValues() { QHash userValues; PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList (), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, userValues, true); QCOMPARE(core->value("AllUsers"), QLatin1String("")); QCOMPARE(core->value("ProductName"), QLatin1String("Unit Test Application")); QCOMPARE(core->value("ProductVersion"), QLatin1String("1.0.0")); QCOMPARE(core->value("Title"), QLatin1String("Unit Test Application Title")); QCOMPARE(core->value("RootDir"), QDir::rootPath()); core->deleteLater(); core->deleteLater(); } void testOverwrittenCoreDataValues() { QHash userValues; userValues.insert("AllUsers", "true"); userValues.insert("ProductName", "Overwritten ProductName"); userValues.insert("ProductVersion", "2.0.0"); userValues.insert("Title", "Overwritten Title"); userValues.insert("RootDir", "Overwritten RootDir"); PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList (), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, userValues, true); QCOMPARE(core->value("AllUsers"), QLatin1String("true")); QCOMPARE(core->value("ProductName"), QLatin1String("Overwritten ProductName")); QCOMPARE(core->value("ProductVersion"), QLatin1String("2.0.0")); QCOMPARE(core->value("Title"), QLatin1String("Overwritten Title")); QCOMPARE(core->value("RootDir"), QLatin1String("Overwritten RootDir")); core->deleteLater(); } }; QTEST_MAIN(tst_PackageManagerCore) #include "tst_packagemanagercore.moc" qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/0040777000000000000000000000000013761647206024516 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/0040777000000000000000000000000013761647206025427 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/0040777000000000000000000000000013761647206027646 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/A/0040777000000000000000000000000013761647206030026 5ustar00././@LongLink0100777000000000000000000000016013761647206010113 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/A/1.0.20100777000000000000000000000027113761647206030407 0ustar007zžŊ'ž‘@'rE*Ņ<"Line to replace. Another line.  ' !! # ·ð°―  A.txt ï•ûÕ ï•ûÕ 6Ą]Ö ././@LongLink0100777000000000000000000000015513761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/A/1.0.20100777000000000000000000000171713761647206030415 0ustar007zžŊ'›=ûގ!ŋ|Ęnāđ$]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÚôėtWĄ‰ļąŊŠnÓÞęŠČ ‚ÁŠĄæīQ3G.‹ Ôw“;ųøG€Ï/ĪÆÕB­‚Ð[ZŊˆ8$5ÛC 6‚ũėÂw“ƒ–JŸēÄTfÁ PD-þÓ$îŋŠöƒ, b #] n ^uåv././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/Updates.xmlqt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/data/repository/Updates0100777000000000000000000000111413761647206031173 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 1.0.2-1 2015-01-01 true content.7z 6d7a3e15d11a4d94b81452fc2aa18e705a01c922 ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/registerfiletypeoperation.proqt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/registerfiletypeoperati0100777000000000000000000000024413761647206031413 0ustar00include(../../qttest.pri) QT -= gui QT += testlib network SOURCES = tst_registerfiletypeoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/settings.qrc0100777000000000000000000000033113761647206027062 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000015613761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/tst_registerfiletypeoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/registerfiletypeoperation/tst_registerfiletypeope0100777000000000000000000001335513761647206031434 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include #include #include #include #include "qsettingswrapper.h" using namespace KDUpdater; using namespace QInstaller; class tst_registerfiletypeoperation : public QObject { Q_OBJECT private: void verifySettings() { QCOMPARE(m_settings->value(m_defaultKey).toString(), m_progId); QCOMPARE(m_settings->value(m_openWithProgIdkey).toString(), QString()); QCOMPARE(m_settings->value(m_shellKey).toString(), m_command); QCOMPARE(m_settings->value(m_shellAppkey).toString(), m_command); } void verifySettingsCleaned() { //Test that values have been removed after undo operation QCOMPARE(m_settings->value(m_defaultKey).toString(), QString()); QCOMPARE(m_settings->value(m_openWithProgIdkey).toString(), QString()); QCOMPARE(m_settings->value(m_shellKey).toString(), QString()); QCOMPARE(m_settings->value(m_shellAppkey).toString(), QString()); } private slots: void initTestCase() { QInstaller::init(); QString randomString = ""; const QString possible = "abcdefghijklmnopqrstuvwxyz0123456789"; qsrand(QTime::currentTime().msec()); for (int i = 0; i < 5; i++) { int index = qrand() % possible.length(); QChar nextChar = possible.at(index); randomString.append(nextChar); } m_fileType = randomString; m_command = m_core.environmentVariable("SystemRoot") + "\\notepad.exe"; m_progId = "QtProject.QtInstallerFramework." + m_fileType; qputenv("ifw_random_filetype", m_fileType.toUtf8()); qputenv("ifw_random_programid", m_progId.toUtf8()); const QString settingsPath = QString::fromLatin1("HKEY_CURRENT_USER\\Software\\Classes\\"); m_settings = new QSettings(settingsPath, QSettings::NativeFormat); m_defaultKey = "." + m_fileType + "/Default"; m_openWithProgIdkey = "." + m_fileType + "/OpenWithProgIds/" + m_progId; m_shellKey = m_progId + "/shell/Open/Command/Default/"; m_shellAppkey = "/Applications/" + m_progId + "/shell/Open/Command/Default/"; } void cleanupTestCase() { qunsetenv("ifw_random_filetype"); qunsetenv("ifw_random_programid"); delete m_settings; } void testMissingArguments() { RegisterFileTypeOperation op(&m_core); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in RegisterFileType: 0 arguments given, " "2 to 5 arguments expected in the form: [description [contentType [icon]]].")); } void testRegisterFileType() { RegisterFileTypeOperation op(&m_core); op.setArguments(QStringList() << m_fileType << m_command << "test filetype" << "text/plain" << 0 << "ProgId="+m_progId); QVERIFY(op.testOperation()); QVERIFY(op.performOperation()); verifySettings(); QVERIFY(op.undoOperation()); verifySettingsCleaned(); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); core->installDefaultComponentsSilently(); verifySettings(); core->commitSessionOperations(); core->setPackageManager(); core->uninstallComponentsSilently(QStringList() << "A"); verifySettingsCleaned(); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_fileType; QString m_command; QString m_progId; PackageManagerCore m_core; QSettings *m_settings; QString m_defaultKey = "."+m_fileType+ "/Default"; QString m_openWithProgIdkey = "." + m_fileType + "/OpenWithProgIds/" +m_progId; QString m_shellKey = m_progId + "/shell/Open/Command/Default/"; QString m_shellAppkey = "/Applications/" + m_progId + "/shell/Open/Command/Default/"; }; QTEST_MAIN(tst_registerfiletypeoperation) #include "tst_registerfiletypeoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/0040777000000000000000000000000013761647206022543 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/0040777000000000000000000000000013761647206023454 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/0040777000000000000000000000000013761647206025673 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/A/0040777000000000000000000000000013761647206026053 5ustar00././@LongLink0100777000000000000000000000014713761647206010120 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/A/1.0.2-1content.7zqt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/A/1.0.2-1content0100777000000000000000000000027113761647206030165 0ustar007zžŊ'ž‘@'rE*Ņ<"Line to replace. Another line.  ' !! # ·ð°―  A.txt ï•ûÕ ï•ûÕ 6Ą]Ö qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/A/1.0.2-1meta.7z0100777000000000000000000000162013761647206027777 0ustar007zžŊ',<3=N"ĨõXSā Ņ]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪĒæōÍą9Ņkvߨ ëŦÍðâ†ÏŪÃëĐ:°Ę<Í&•(ĒīVT•ôz ä-ĻŋŨæ`úĪ–ï›tAIËO[1Á/Šë9iZ”{Z[=3ŪÕGĄSW$Óþģp@ló“vûžÛLÏĢđďšP‡ä2ChÂjâČōëKŅV—BŲá=ƒĘLÐGQŋĀÖāø, o?BŪŅ){‘ņŋ䀀Ô5"lÚĸĀŅ~ - įc†Lac><čąįÆ‚Ų u #] €ž ęŒâÝqt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/data/repository/Updates.xml0100777000000000000000000000077013761647206030026 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true content.7z qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/replaceoperation.pro0100777000000000000000000000022413761647206026617 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_replaceoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/settings.qrc0100777000000000000000000000033113761647206025107 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1content.7z data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/replaceoperation/tst_replaceoperation.cpp0100777000000000000000000001661313761647206027504 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_replaceoperation : public QObject { Q_OBJECT private slots: void initTestCase() { m_testDirectory = QInstaller::generateTemporaryFileName(); m_testFilePath = m_testDirectory + "/test." + QString::number(qrand() % 1000); } void testWrongArguments() { ReplaceOperation missingArgumentsOperation(nullptr); missingArgumentsOperation.setArguments(QStringList() << "testFile" << "testSearch"); // should do nothing if there are missing arguments QVERIFY(missingArgumentsOperation.testOperation()); QCOMPARE(missingArgumentsOperation.performOperation(), false); ReplaceOperation invalidModeArgumentOperation(nullptr); invalidModeArgumentOperation.setArguments(QStringList() << "testFile" << "testSearch" << "testReplace" << "invalid"); // should do nothing if there is an invalid mode argument QVERIFY(invalidModeArgumentOperation.testOperation()); QCOMPARE(invalidModeArgumentOperation.performOperation(), false); QCOMPARE(UpdateOperation::Error(invalidModeArgumentOperation.error()), UpdateOperation::InvalidArguments); QString compareString = "Current mode argument calling \"Replace\" with " "arguments \"testFile; testSearch; testReplace; invalid\" is not supported. " "Please use string or regex."; QCOMPARE(invalidModeArgumentOperation.errorString(), compareString); ReplaceOperation emptySearchArgumentOperation(nullptr); emptySearchArgumentOperation.setArguments(QStringList() << "testFile" << "" << "testReplace" << "regex"); // should do nothing if there is an empty search argument QVERIFY(emptySearchArgumentOperation.testOperation()); QCOMPARE(emptySearchArgumentOperation.performOperation(), false); QCOMPARE(UpdateOperation::Error(emptySearchArgumentOperation.error()), UpdateOperation::InvalidArguments); compareString = "Current search argument calling \"Replace\" with " "empty search argument is not supported."; QCOMPARE(emptySearchArgumentOperation.errorString(), compareString); } void testStringSearchReplace() { QVERIFY(QDir().mkpath(m_testDirectory)); QVERIFY(QDir(m_testDirectory).exists()); QFile file(m_testFilePath); QVERIFY(file.open(QIODevice::WriteOnly)); QTextStream stream(&file); stream << "Lorem ipsum dolore sit amet, consectetur adipiscing elit, sed do eiusmod " "tempor incididunt ut labore et dolore magna aliqua." << endl; file.close(); ReplaceOperation searchReplaceOperation(nullptr); searchReplaceOperation.setArguments(QStringList() << m_testFilePath << "dolore" << "test"); // should succeed QVERIFY(searchReplaceOperation.testOperation()); QCOMPARE(searchReplaceOperation.performOperation(), true); QVERIFY(file.open(QIODevice::ReadOnly)); QString fileContent = stream.readAll(); QCOMPARE(fileContent, QLatin1String( "Lorem ipsum test sit amet, consectetur adipiscing elit, sed do eiusmod " "tempor incididunt ut labore et test magna aliqua.\n")); file.close(); QVERIFY(file.remove()); QVERIFY(QDir().rmdir(m_testDirectory)); } void testRegexSearchReplace() { // Test with three different regexes, one containing // a capturing group QVERIFY(QDir().mkpath(m_testDirectory)); QVERIFY(QDir(m_testDirectory).exists()); QFile file(m_testFilePath); QVERIFY(file.open(QIODevice::WriteOnly)); QTextStream stream(&file); stream << "one | 10/10/2010 | three | 1.2345 | 0.00001 " "| 7 | A bon mot." << endl; file.close(); ReplaceOperation searchReplaceOperation(nullptr); searchReplaceOperation.setArguments(QStringList() << m_testFilePath << "\\d{1,2}/\\d{1,2}/\\d{4}" << "date-match" << "regex"); // should succeed QVERIFY(searchReplaceOperation.testOperation()); QCOMPARE(searchReplaceOperation.performOperation(), true); searchReplaceOperation.setArguments(QStringList() << m_testFilePath << "[-+]?[0-9]*\\.?[0-9]+" << "number-match" << "regex"); // should succeed QVERIFY(searchReplaceOperation.testOperation()); QCOMPARE(searchReplaceOperation.performOperation(), true); searchReplaceOperation.setArguments(QStringList() << m_testFilePath << "([^<]*)" << "\\emph{\\1}" << "regex"); // should succeed QVERIFY(searchReplaceOperation.testOperation()); QCOMPARE(searchReplaceOperation.performOperation(), true); QVERIFY(file.open(QIODevice::ReadOnly)); QString fileContent = stream.readAll(); QCOMPARE(fileContent, QLatin1String("one | date-match | three " "| number-match | number-match | number-match | A \\emph{bon mot}.\n")); file.close(); QVERIFY(file.remove()); QVERIFY(QDir().rmdir(m_testDirectory)); } void testPerformingFromCLI() { QVERIFY(QDir().mkpath(m_testDirectory)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (m_testDirectory, ":///data/repository"); core->installDefaultComponentsSilently(); QFile file(m_testDirectory + QDir::separator() + "A.txt"); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QTextStream stream(&file); QCOMPARE(stream.readLine(), QLatin1String("text to replace.")); QCOMPARE(stream.readLine(), QLatin1String("Another text.")); file.close(); QDir dir(m_testDirectory); QVERIFY(dir.removeRecursively()); core->deleteLater(); } private: QString m_testDirectory; QString m_testFilePath; }; QTEST_MAIN(tst_replaceoperation) #include "tst_replaceoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/repository/0040777000000000000000000000000013761647206021426 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/repository/repository.pro0100777000000000000000000000012213761647206024362 0ustar00include(../../qttest.pri) QT += network QT -= gui SOURCES += tst_repository.cpp qt-installer-framework-4.0.1/tests/auto/installer/repository/tst_repository.cpp0100777000000000000000000001135513761647206025250 0ustar00#include "repository.h" #include "repositorycategory.h" #include "settings.h" #include #include #include using namespace QInstaller; class tst_Repository : public QObject { Q_OBJECT private slots: void testRepository() { Repository repo; QCOMPARE(repo.isValid(), false); QCOMPARE(repo.isDefault(), false); QCOMPARE(repo.isEnabled(), false); QCOMPARE(repo.url(), QUrl()); QCOMPARE(repo.username(), QString()); QCOMPARE(repo.password(), QString()); repo.setUrl(QUrl("http://www.digia.com")); QCOMPARE(repo.isValid(), true); QCOMPARE(repo.url(), QUrl("http://www.digia.com")); repo.setEnabled(true); QCOMPARE(repo.isEnabled(), true); repo.setUsername("tester"); QCOMPARE(repo.username(), QString("tester")); repo.setPassword("test"); QCOMPARE(repo.password(), QString("test")); } void testRepositoryFromUrl() { Repository repo(QUrl("http://www.digia.com"), true); QCOMPARE(repo.isValid(), true); QCOMPARE(repo.isDefault(), true); QCOMPARE(repo.isEnabled(), true); QCOMPARE(repo.url(), QUrl("http://www.digia.com")); QCOMPARE(repo.username(), QString()); QCOMPARE(repo.password(), QString()); repo.setUrl(QUrl()); QCOMPARE(repo.isValid(), false); repo.setEnabled(false); QCOMPARE(repo.isEnabled(), false); repo.setUsername("tester"); QCOMPARE(repo.username(), QString("tester")); repo.setPassword("test"); QCOMPARE(repo.password(), QString("test")); } void testRepositoryFromUserInput() { Repository repo = Repository::fromUserInput("ftp://tester:test@www.digia.com"); QCOMPARE(repo.isValid(), true); QCOMPARE(repo.isDefault(), false); QCOMPARE(repo.isEnabled(), true); QCOMPARE(repo.url(), QUrl("ftp://www.digia.com")); QCOMPARE(repo.username(), QString("tester")); QCOMPARE(repo.password(), QString("test")); repo.setUrl(QUrl()); QCOMPARE(repo.isValid(), false); repo.setEnabled(false); QCOMPARE(repo.isEnabled(), false); repo.setUsername(""); QCOMPARE(repo.username(), QString()); repo.setPassword(""); QCOMPARE(repo.password(), QString()); } void testRepositoryOperators() { Repository lhs, rhs; // operator== QVERIFY(lhs == rhs); // assignment operator rhs = Repository::fromUserInput("ftp://tester:test@www.digia.com"); // operator!= QVERIFY(lhs != rhs); // copy constructor Repository clhs(rhs); // operator== QVERIFY(clhs == rhs); QByteArray ba1, ba2; QDataStream s1(&ba1, QIODevice::ReadWrite), s2(&ba2, QIODevice::ReadWrite); // QDatastream operator s1 << clhs; s2 << rhs; QCOMPARE(ba1, ba2); Repository r1, r2; s1 >> r1; s2 >> r2; QCOMPARE(r1, r2); } void testUpdateRepositoryCategories() { Settings settings; RepositoryCategory category; category.setEnabled(true); category.setDisplayName(QLatin1String("category")); Repository original(QUrl("http://example.com/"), true); original.setEnabled(true); category.addRepository(original); Repository replacement = original; replacement.setUsername(QLatin1String("user")); replacement.setPassword(QLatin1String("pass")); QSet categories; categories.insert(category); settings.setRepositoryCategories(categories); QHash> update; // non-empty update update.insert(QLatin1String("replace"), qMakePair(original, replacement)); QVERIFY(settings.updateRepositoryCategories(update) == Settings::UpdatesApplied); // verify that the values really updated QVERIFY(settings.repositoryCategories().values().at(0) .repositories().values().at(0).username() == "user"); QVERIFY(settings.repositoryCategories().values().at(0) .repositories().values().at(0).password() == "pass"); // empty update update.clear(); QVERIFY(settings.updateRepositoryCategories(update) == Settings::NoUpdatesApplied); // non-matching repository update Repository nonMatching(QUrl("https://www.qt.io/"), true); nonMatching.setEnabled(true); update.insert(QLatin1String("replace"), qMakePair(nonMatching, replacement)); QVERIFY(settings.updateRepositoryCategories(update) == Settings::NoUpdatesApplied); } }; QTEST_MAIN(tst_Repository) #include "tst_repository.moc" qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/0040777000000000000000000000000013761647206021701 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/0040777000000000000000000000000013761647206022612 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/addOperation.qs0100777000000000000000000000363213761647206025574 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { } Component.prototype.createOperations = function () { console.log("Component::createOperations()"); component.createOperations(); component.addOperation("EmptyArg", "Arg", "Arg2", ""); component.addOperation("EmptyArg", "Arg", "", "Arg3"); component.addOperation("EmptyArg", "", "Arg2", "Arg3"); component.addOperation("EmptyArg", ["Arg", "Arg2", ""]); component.addElevatedOperation("EmptyArg", "eArg", "eArg2", ""); component.addElevatedOperation("EmptyArg", "eArg", "", "eArg3"); component.addElevatedOperation("EmptyArg", "", "eArg2", "eArg3"); component.addElevatedOperation("EmptyArg", ["eArg", "eArg2", ""]); } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/auto-install.qs0100777000000000000000000000366613761647206025606 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Controller() { installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes); installer.setValue("GuiTestValue", "hello"); } Controller.prototype.IntroductionPageCallback = function() { var widget = gui.currentPageWidget(); var updaterRadioButton = widget.findChild("UpdaterRadioButton"); updaterRadioButton.checked = true; gui.clickButton(buttons.NextButton); } Controller.prototype.ComponentSelectionPageCallback = function() { var notExistingButtonId = 9999999; gui.clickButton(notExistingButtonId); } Controller.prototype.FinishedPageCallback = function() { print("FinishedPageCallback - OK") } // Trailing comment to exercise QTIFW-1062qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/broken_connect.qs0100777000000000000000000000263713761647206026160 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function BrokenConnect() { emiter.emitted.connect(receive) } function receive() { print("function receive()"); // this will print an error. foo.bar = "test"; } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/component1.qs0100777000000000000000000000431413761647206025244 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { print("Component constructor - OK"); } Component.prototype.retranslateUi = function() { // arguments.callee to get the current function name doesn't work in that case print("retranslateUi - OK"); // no default implementation for this method // component.languageChanged(); } Component.prototype.createOperationsForPath = function(path) { print("createOperationsForPath - OK"); component.createOperationsForPath(path); } Component.prototype.createOperationsForArchive = function(archive) { print("createOperationsForArchive - OK"); component.createOperationsForArchive(archive); } Component.prototype.beginInstallation = function() { print("beginInstallation - OK"); component.beginInstallation(); } Component.prototype.createOperations = function() { print("createOperations - OK"); component.createOperations(); } Component.prototype.isDefault = function() { print("isDefault - OK"); return false; } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/component2.qs0100777000000000000000000000260213761647206025243 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { print("script function: " + arguments.callee.name); // adding some broken javascript code here broken + 789634 } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/dynamicpage.qs0100777000000000000000000000433013761647206025440 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function assert(condition) { if (!condition) throw new Error("Assertion failed!"); } function Controller() { var widget = gui.pageWidgetByObjectName("DynamicWidget"); assert(typeof widget === 'object'); var button = widget.Button; assert(typeof button === 'object'); } Controller.prototype.ReadAndSetValues = function() { var widget = gui.pageWidgetByObjectName("DynamicWidget"); installer.setValue("DynamicWidget.final", widget.final); installer.setValue("DynamicWidget.commit", widget.commit); installer.setValue("DynamicWidget.complete", widget.complete); } Controller.prototype.UpdateAndSetValues = function () { var widget = gui.pageWidgetByObjectName("DynamicWidget"); widget.final = false; widget.commit = false; widget.complete = true; installer.setValue("DynamicWidget.final", widget.final); installer.setValue("DynamicWidget.commit", widget.commit); installer.setValue("DynamicWidget.complete", widget.complete); } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/enteringpage.qs0100777000000000000000000000263413761647206025634 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Controller() { } Controller.prototype.EnteringPageCallback = function() { var page = gui.pageWidgetByObjectName("EnteringPage"); page.callbackInvoked(); } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/form.ui0100777000000000000000000000120713761647206024114 0ustar00 form 0 0 400 300 Form 90 90 78 19 CheckBox qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/data/userinterface.qs0100777000000000000000000000262013761647206026016 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ function Component() { // check that the .ui file has been properly loaded console.log("checked: " + component.userInterface("form").checkBox.checked); } qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/scriptengine.pro0100777000000000000000000000023413761647206025114 0ustar00include(../../qttest.pri) QT += qml widgets SOURCES += tst_scriptengine.cpp DEFINES += "BUILDDIR=\\\"$$OUT_PWD\\\"" RESOURCES += \ scriptengine.qrc qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/scriptengine.qrc0100777000000000000000000000065113761647206025104 0ustar00 data/auto-install.qs data/component1.qs data/component2.qs data/broken_connect.qs data/dynamicpage.qs data/enteringpage.qs data/form.ui data/userinterface.qs data/addOperation.qs qt-installer-framework-4.0.1/tests/auto/installer/scriptengine/tst_scriptengine.cpp0100777000000000000000000005636413761647206026007 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include <../unicodeexecutable/stringdata.h> #include #include #include #include using namespace QInstaller; class TestGui : public QInstaller::PackageManagerGui { Q_OBJECT public: explicit TestGui(QInstaller::PackageManagerCore *core) : PackageManagerGui(core, 0) { setPage(PackageManagerCore::Introduction, new IntroductionPage(core)); setPage(PackageManagerCore::ComponentSelection, new ComponentSelectionPage(core)); setPage(PackageManagerCore::InstallationFinished, new FinishedPage(core)); foreach (const int id, pageIds()) { packageManagerCore()->controlScriptEngine()->addToGlobalObject(page(id)); packageManagerCore()->componentScriptEngine()->addToGlobalObject(page(id)); } } virtual void init() {} void callProtectedDelayedExecuteControlScript(int id) { executeControlScript(id); } }; class DynamicPageGui : public PackageManagerGui { Q_OBJECT public: explicit DynamicPageGui(PackageManagerCore *core) : PackageManagerGui(core) {} void init() { m_widget = new QWidget; m_widget->setObjectName("Widget"); QWidget *button = new QWidget(m_widget); button->setObjectName("Button"); packageManagerCore()->wizardPageInsertionRequested(m_widget, PackageManagerCore::Introduction); } QWidget *widget() const { return m_widget; } private: QWidget *m_widget; }; class EnteringPage : public PackageManagerPage { Q_OBJECT Q_PROPERTY(QStringList invocationOrder READ invocationOrder) public: explicit EnteringPage(PackageManagerCore *core) : PackageManagerPage(core) { setObjectName(QLatin1String("EnteringPage")); } QStringList invocationOrder() const { return m_invocationOrder; } public slots: Q_INVOKABLE void enteringInvoked() { m_invocationOrder << QLatin1String("Entering"); } Q_INVOKABLE void callbackInvoked() { m_invocationOrder << QLatin1String("Callback"); } protected: void entering() { enteringInvoked(); } private: QStringList m_invocationOrder; }; class EnteringGui : public PackageManagerGui { Q_OBJECT public: explicit EnteringGui(PackageManagerCore *core) : PackageManagerGui(core) {} EnteringPage *enteringPage() const { return m_enteringPage; } void init() { m_enteringPage = new EnteringPage(packageManagerCore()); setPage(0, m_enteringPage); } private: EnteringPage *m_enteringPage; }; class EmitSignalObject : public QObject { Q_OBJECT public: EmitSignalObject() {} ~EmitSignalObject() {} void produceSignal() { emit emitted(); } signals: void emitted(); }; class EmptyArgOperation : public KDUpdater::UpdateOperation { public: explicit EmptyArgOperation(QInstaller::PackageManagerCore *core) : KDUpdater::UpdateOperation(core) { setName("EmptyArg"); } void backup() {} bool performOperation() { return true; } bool undoOperation() { return true; } bool testOperation() { return true; } }; // -- tst_ScriptEngine class tst_ScriptEngine : public QObject { Q_OBJECT private slots: void initTestCase() { m_component = new Component(&m_core); // append the component to the package manager which deletes it at destructor // (it calls clearAllComponentLists which calls qDeleteAll(m_rootComponents);) m_core.appendRootComponent(m_component); m_component->setValue("Default", "Script"); m_component->setValue(scName, "component.test.name"); Component *component = new Component(&m_core); component->setValue(scName, "component.test.addOperation"); m_core.appendRootComponent(component); m_scriptEngine = m_core.componentScriptEngine(); m_applicatonDirPath = qApp->applicationDirPath(); } void testDefaultScriptEngineValues() { const QJSValue global = m_scriptEngine->globalObject(); QCOMPARE(global.hasProperty(QLatin1String("print")), true); QCOMPARE(global.hasProperty(QLatin1String("installer")), true); QCOMPARE(global.property(QLatin1String("installer")) .hasProperty(QLatin1String("componentByName")), true); QCOMPARE(global.property(QLatin1String("installer")) .hasProperty(QLatin1String("components")), true); QCOMPARE(global.hasProperty(QLatin1String("console")), true); QCOMPARE(global.property(QLatin1String("console")) .hasProperty(QLatin1String("log")), true); QCOMPARE(global.hasProperty(QLatin1String("QFileDialog")), true); QCOMPARE(global.property(QLatin1String("QFileDialog")) .hasProperty(QLatin1String("getExistingDirectory")), true); QCOMPARE(global.property(QLatin1String("QFileDialog")) .hasProperty(QLatin1String("getOpenFileName")), true); QCOMPARE(global.hasProperty(QLatin1String("InstallerProxy")), true); QCOMPARE(global.property(QLatin1String("InstallerProxy")) .hasProperty(QLatin1String("componentByName")), true); QCOMPARE(global.property(QLatin1String("InstallerProxy")) .hasProperty(QLatin1String("components")), true); QCOMPARE(global.hasProperty(QLatin1String("QDesktopServices")), true); QCOMPARE(global.property(QLatin1String("QDesktopServices")) .hasProperty(QLatin1String("openUrl")), true); QCOMPARE(global.property(QLatin1String("QDesktopServices")) .hasProperty(QLatin1String("displayName")), true); QCOMPARE(global.property(QLatin1String("QDesktopServices")) .hasProperty(QLatin1String("storageLocation")), true); QCOMPARE(global.property(QLatin1String("QDesktopServices")) .hasProperty(QLatin1String("findFiles")), true); QCOMPARE(global.hasProperty(QLatin1String("buttons")), true); QCOMPARE(global.hasProperty(QLatin1String("QInstaller")), true); QCOMPARE(global.hasProperty(QLatin1String("QMessageBox")), true); QCOMPARE(global.hasProperty(QLatin1String("gui")), true); QCOMPARE(global.hasProperty(QLatin1String("qsTr")), true); QCOMPARE(global.hasProperty(QLatin1String("systemInfo")), true); QJSValue sinfo = global.property(QLatin1String("systemInfo")); QCOMPARE(sinfo.property(QLatin1String("currentCpuArchitecture")).toString(), QSysInfo::currentCpuArchitecture()); QCOMPARE(sinfo.property(QLatin1String("kernelType")).toString(), QSysInfo::kernelType()); QCOMPARE(sinfo.property(QLatin1String("kernelVersion")).toString(), QSysInfo::kernelVersion()); QCOMPARE(sinfo.property(QLatin1String("productType")).toString(), QSysInfo::productType()); QCOMPARE(sinfo.property(QLatin1String("productVersion")).toString(), QSysInfo::productVersion()); QCOMPARE(sinfo.property(QLatin1String("prettyProductName")).toString(), QSysInfo::prettyProductName()); } void testBrokenJSMethodConnect() { #if QT_VERSION <= 0x50400 QSKIP("Behavior changed from 5.4.1 onwards"); #endif EmitSignalObject emiter; m_scriptEngine->globalObject().setProperty(QLatin1String("emiter"), m_scriptEngine->newQObject(&emiter)); QJSValue context = m_scriptEngine->loadInContext(QLatin1String("BrokenConnect"), ":///data/broken_connect.qs"); if (context.isError()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error:\n %1").arg( context.toString()))); } QCOMPARE(context.isError(), false); // ignore Output from script setExpectedScriptOutput("function receive()"); #if QT_VERSION >= QT_VERSION_CHECK(5,12,0) QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined"); #else QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined"); #endif emiter.produceSignal(); const QJSValue value = m_scriptEngine->evaluate(""); QCOMPARE(value.isError(), false); } void testScriptPrint() { setExpectedScriptOutput("test"); const QJSValue value = m_scriptEngine->evaluate("print(\"test\");"); if (value.isError()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error:\n %1").arg( value.toString()))); } } void testExistingInstallerObject() { setExpectedScriptOutput("object"); const QJSValue value = m_scriptEngine->evaluate("print(typeof installer)"); if (value.isError()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error:\n %1").arg( value.toString()))); } } void testComponentByName() { const QString script = QString::fromLatin1("var component = installer.componentByName('%1');" "\n" "print(component.name);").arg(m_component->name()); setExpectedScriptOutput("component.test.name"); const QJSValue value = m_scriptEngine->evaluate(script); if (value.isError()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error:\n %1").arg( value.toString()))); } } void testComponentByWrongName() { const QString script = QString::fromLatin1( "var component = installer.componentByName('%1');" "\n" "print(brokenComponent.name);").arg("NotExistingComponentName"); const QJSValue value = m_scriptEngine->evaluate(script); QCOMPARE(value.isError(), true); } void testComponents() { const QString script = QString::fromLatin1("var components = installer.components();" "\n" "print(components[0].name);"); setExpectedScriptOutput("component.test.name"); const QJSValue value = m_scriptEngine->evaluate(script); if (value.isError()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error:\n %1").arg( value.toString()))); } } void testFindFiles() { const QString expectedOutput = QString::fromLatin1("Found file %1/tst_scriptengine.moc").arg(m_applicatonDirPath); QByteArray array = expectedOutput.toLatin1(); const char *c_str2 = array.data(); setExpectedScriptOutput(c_str2); const QString script = QString::fromLatin1("var directory = \"C:/Qt/test\";" "\n" "var pattern = \"*.moc\";" "\n" "var fileArray = QDesktopServices.findFiles('%1', pattern)" "\n" "for (i = 0; i < fileArray.length; i++) {" "print(\"Found file \"+fileArray[i]);" "}").arg(m_applicatonDirPath); const QJSValue result = m_scriptEngine->evaluate(script); qDebug()<loadComponentScript(":///data/component1.qs"); setExpectedScriptOutput("retranslateUi - OK"); m_component->languageChanged(); setExpectedScriptOutput("createOperationsForPath - OK"); m_component->createOperationsForPath(":///data/"); setExpectedScriptOutput("createOperationsForArchive - OK"); // ignore createOperationsForPath which is called by createOperationsForArchive setExpectedScriptOutput("createOperationsForPath - OK"); m_component->createOperationsForArchive("test.7z"); setExpectedScriptOutput("beginInstallation - OK"); m_component->beginInstallation(); setExpectedScriptOutput("createOperations - OK"); m_component->createOperations(); setExpectedScriptOutput("isDefault - OK"); bool returnIsDefault = m_component->isDefault(); QCOMPARE(returnIsDefault, false); } catch (const Error &error) { QFAIL(qPrintable(error.message())); } } void loadBrokenComponentScript() { Component *testComponent = new Component(&m_core); testComponent->setValue(scName, "broken.component"); // m_core becomes the owner of testComponent, it will delete it in the destructor m_core.appendRootComponent(testComponent); try { // ignore Output from script setExpectedScriptOutput("script function: Component"); testComponent->loadComponentScript(":///data/component2.qs"); } catch (const Error &error) { const QString debugMessage( QString("create Error-Exception: \"Exception while loading the component script \"%1\": " "ReferenceError: broken is not defined\"").arg(QDir::toNativeSeparators(":///data/component2.qs"))); QVERIFY2(debugMessage.contains(error.message()), "(ReferenceError: broken is not defined)"); } } void loadComponentUserInterfaces() { try { setExpectedScriptOutput("checked: false"); m_component->loadUserInterfaces(QDir(":///data"), QStringList() << QLatin1String("form.ui")); m_component->loadComponentScript(":///data/userinterface.qs"); } catch (const Error &error) { QFAIL(qPrintable(error.message())); } } void loadSimpleAutoRunScript() { try { TestGui testGui(&m_core); setExpectedScriptOutput("Loaded control script \":///data/auto-install.qs\" "); testGui.loadControlScript(":///data/auto-install.qs"); QCOMPARE(m_core.value("GuiTestValue"), QString("hello")); testGui.show(); // inside the auto-install script we are clicking the next button, with a not existing button QTest::ignoreMessage(QtWarningMsg, "Button with type: \"unknown button\" not found! "); testGui.callProtectedDelayedExecuteControlScript(PackageManagerCore::ComponentSelection); setExpectedScriptOutput("FinishedPageCallback - OK"); testGui.callProtectedDelayedExecuteControlScript(PackageManagerCore::InstallationFinished); } catch (const Error &error) { QFAIL(qPrintable(error.message())); } } void testDynamicPage() { DynamicPageGui gui(&m_core); gui.init(); setExpectedScriptOutput("Loaded control script \":///data/dynamicpage.qs\" "); gui.loadControlScript(":///data/dynamicpage.qs"); gui.callControlScriptMethod("ReadAndSetValues"); QCOMPARE(m_core.value("DynamicWidget.final"), QString("false")); QCOMPARE(gui.widget()->property("final").toString(), QString("false")); QCOMPARE(m_core.value("DynamicWidget.commit"), QString("false")); QCOMPARE(gui.widget()->property("commit").toString(), QString("false")); QCOMPARE(m_core.value("DynamicWidget.complete"), QString("true")); QCOMPARE(gui.widget()->property("complete").toString(), QString("true")); gui.widget()->setProperty("final", true); gui.widget()->setProperty("commit", true); gui.widget()->setProperty("complete", false); gui.callControlScriptMethod("ReadAndSetValues"); QCOMPARE(m_core.value("DynamicWidget.final"), QString("true")); QCOMPARE(gui.widget()->property("final").toString(), QString("true")); QCOMPARE(m_core.value("DynamicWidget.commit"), QString("true")); QCOMPARE(gui.widget()->property("commit").toString(), QString("true")); QCOMPARE(m_core.value("DynamicWidget.complete"), QString("false")); QCOMPARE(gui.widget()->property("complete").toString(), QString("false")); gui.callControlScriptMethod("UpdateAndSetValues"); QCOMPARE(m_core.value("DynamicWidget.final"), QString("false")); QCOMPARE(gui.widget()->property("final").toString(), QString("false")); QCOMPARE(m_core.value("DynamicWidget.commit"), QString("false")); QCOMPARE(gui.widget()->property("commit").toString(), QString("false")); QCOMPARE(m_core.value("DynamicWidget.complete"), QString("true")); QCOMPARE(gui.widget()->property("complete").toString(), QString("true")); } void testInstallerExecuteEncodings_data() { QTest::addColumn("argumentsToInstallerExecute"); QTest::addColumn("expectedOutput"); QTest::addColumn("expectedExitCode"); QTest::newRow("default_encoding_ascii_output_exit_code_0") << QString::fromLatin1("['ascii', '0']") << QString::fromLatin1(asciiText) << 0; QTest::newRow("default_encoding_ascii_output_exit_code_52") << QString::fromLatin1("['ascii', '52']") << QString::fromLatin1(asciiText) << 52; QTest::newRow("latin1_encoding_ascii_output") << QString::fromLatin1("['ascii', '0'], '', 'latin1', 'latin1'") << QString::fromLatin1(asciiText) << 0; QTest::newRow("latin1_encoding_utf8_output") << QString::fromLatin1("['utf8', '0'], '', 'latin1', 'latin1'") << QString::fromLatin1(utf8Text) << 0; QTest::newRow("utf8_encoding_ascii_output") << QString::fromLatin1("['ascii', '0'], '', 'utf8', 'utf8'") << QString::fromUtf8(asciiText) << 0; QTest::newRow("utf8_encoding_utf8_output") << QString::fromLatin1("['utf8', '0'], '', 'utf8', 'utf8'") << QString::fromUtf8(utf8Text) << 0; } void testInstallerExecuteEncodings() { QString unicodeExecutableName = QLatin1String(BUILDDIR "/../unicodeexecutable/unicodeexecutable"); #if defined(Q_OS_WIN) unicodeExecutableName += QLatin1String(".exe"); #endif QFileInfo unicodeExecutable(unicodeExecutableName); if (!unicodeExecutable.isExecutable()) { QFAIL(qPrintable(QString::fromLatin1("ScriptEngine error: test program %1 is not executable") .arg(unicodeExecutable.absoluteFilePath()))); return; } const QString testProgramPath = unicodeExecutable.absoluteFilePath(); QFETCH(QString, argumentsToInstallerExecute); QFETCH(QString, expectedOutput); QFETCH(int, expectedExitCode); QJSValue result = m_scriptEngine->evaluate(QString::fromLatin1("installer.execute('%1', %2);") .arg(testProgramPath) .arg(argumentsToInstallerExecute)); QCOMPARE(result.isArray(), true); QCOMPARE(result.property(0).toString(), expectedOutput); QCOMPARE(result.property(1).toString(), QString::number(expectedExitCode)); } void checkEnteringCalledBeforePageCallback() { EnteringGui gui(&m_core); gui.init(); setExpectedScriptOutput("Loaded control script \":///data/enteringpage.qs\" "); gui.loadControlScript(":///data/enteringpage.qs"); gui.show(); EnteringPage *enteringPage = gui.enteringPage(); QStringList expectedOrder; expectedOrder << QLatin1String("Entering") << QLatin1String("Callback"); QCOMPARE(enteringPage->invocationOrder(), expectedOrder); } void testAddOperation_AddElevatedOperation() { #if QT_VERSION < 0x50600 QSKIP("Behavior changed from 5.6.0 onwards."); #endif using namespace KDUpdater; UpdateOperationFactory &factory = UpdateOperationFactory::instance(); factory.registerUpdateOperation(QLatin1String("EmptyArg")); try { m_core.setPackageManager(); Component *component = m_core.componentByName("component.test.addOperation"); component->loadComponentScript(":///data/addOperation.qs"); setExpectedScriptOutput("Component::createOperations()"); component->createOperations(); const OperationList operations = component->operations(); QCOMPARE(operations.count(), 8); struct { const char* args[3]; const char* operator[](int i) const { return args[i]; } } expectedArgs[] = { { "Arg", "Arg2", "" }, { "Arg", "", "Arg3" }, { "", "Arg2", "Arg3" }, { "Arg", "Arg2", "" }, { "eArg", "eArg2", "" }, { "eArg", "", "eArg3" }, { "", "eArg2", "eArg3" }, { "eArg", "eArg2", "" } }; for (int i = 0; i < operations.count(); ++i) { const QStringList arguments = operations[i]->arguments(); QCOMPARE(arguments.count(), 3); for (int j = 0; j < 3; ++j) QCOMPARE(arguments[j], QString(expectedArgs[i][j])); } } catch (const QInstaller::Error &error) { QFAIL(qPrintable(error.message())); } } private: void setExpectedScriptOutput(const char *message) { // Using setExpectedScriptOutput(...); inside the test method // as a simple test that the scripts are called. QTest::ignoreMessage(QtDebugMsg, message); } PackageManagerCore m_core; Component *m_component; ScriptEngine *m_scriptEngine; QString m_applicatonDirPath; }; QTEST_MAIN(tst_ScriptEngine) #include "tst_scriptengine.moc" qt-installer-framework-4.0.1/tests/auto/installer/settings/0040777000000000000000000000000013761647206021047 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/0040777000000000000000000000000013761647206022770 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/0040777000000000000000000000000013761647206023701 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/repository/0040777000000000000000000000000013761647206026120 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/repository/A/0040777000000000000000000000000013761647206026300 5ustar00././@LongLink0100777000000000000000000000014513761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/repository/A/1.0.2-1meta.70100777000000000000000000000163713761647206030042 0ustar007zžŊ'ðD^!ŧ<āˆō]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪĒæōÍą\Ķz  …ąŽÅ›ÖŒüaÐóĻĻG―zÆ4ŪĐŦáȊ`ÔF pŊŽ{ŊM›$4đ·įR• ŠTĩĢ{Ü‚ e’ŊÂĶ…íÕ3GBwí]ÔĘũĶø„‚‹ŦĻę{Ÿ ęŌhŅ)&Ym” ą—с3ŪÕH\‰7%GWÓĢX"NÄÖÖLzģŨ.ïÖēIßĩ‘ŌŠaĮ'ë[5;ÝŠ=h؎øÅČ84@ӆdœĀˆG4Ģ›s žœøü•€=\c•€Ó§Éŧi‚ú d #] n Î4Iqt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/data/repository/Updates.xml0100777000000000000000000000057213761647206030253 0ustar00 {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/settings.qrc0100777000000000000000000000024013761647206025333 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/settingsoperation.pro0100777000000000000000000000022213761647206027267 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES += tst_settingsoperation.cpp RESOURCES += settings.qrc\ ..\shared\config.qrc qt-installer-framework-4.0.1/tests/auto/installer/settingsoperation/tst_settingsoperation.cpp0100777000000000000000000003543713761647206030163 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_settingsoperation : public QObject { Q_OBJECT private slots: // called before all tests void initTestCase() { m_testSettingsDirPath = qApp->applicationDirPath(); m_testSettingsFilename = "test.ini"; QSettings testSettings(QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename), QSettings::IniFormat); m_cleanupFilePaths << QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename); testSettings.setValue("testkey", "testvalue"); testSettings.setValue("testcategory/categorytestkey", "categorytestvalue"); testSettings.setValue("testcategory/categoryarrayvalue1", QStringList() << "value1" << "value2" << "value3"); testSettings.setValue("testcategory/categoryarrayvalue2", "value1,value2,value3"); testSettings.setValue("testcategory/categoryarrayvalue3", "value1 ,value2, value3"); } void testWrongArguments() { SettingsOperation noArgumentsOperation(nullptr); QVERIFY(noArgumentsOperation.testOperation()); // operation should do nothing if there are no arguments QCOMPARE(noArgumentsOperation.performOperation(), false); QCOMPARE(UpdateOperation::Error(noArgumentsOperation.error()), UpdateOperation::InvalidArguments); QString compareString("Missing argument(s) \"path; method; key; value\" calling Settings " "with arguments \"\"."); QCOMPARE(noArgumentsOperation.errorString(), compareString); // same for undo QCOMPARE(noArgumentsOperation.undoOperation(), false); SettingsOperation wrongMethodArgumentOperation(nullptr); wrongMethodArgumentOperation.setArguments(QStringList() << "path=first" << "method=second" << "key=third" << "value=fourth"); QVERIFY(wrongMethodArgumentOperation.testOperation()); // operation should do nothing if there are no arguments QCOMPARE(wrongMethodArgumentOperation.performOperation(), false); QCOMPARE(UpdateOperation::Error(wrongMethodArgumentOperation.error()), UpdateOperation::InvalidArguments); compareString = "Current method argument calling \"Settings\" with arguments \"path=first; " "method=second; key=third; value=fourth\" is not supported. Please use set, remove, " "add_array_value or remove_array_value."; QCOMPARE(wrongMethodArgumentOperation.errorString(), compareString); // same for undo QCOMPARE(wrongMethodArgumentOperation.undoOperation(), false); } void setSettingsValue() { const QString verifyFilePath = createFilePath(QTest::currentTestFunction()); const QString testFilePath = createFilePath(QString("_") + QTest::currentTestFunction()); m_cleanupFilePaths << verifyFilePath << testFilePath; const QString key = "category/key"; const QString value = "value"; { QSettings testSettings(verifyFilePath, QSettings::IniFormat); testSettings.setValue(key, value); } SettingsOperation settingsOperation(nullptr); settingsOperation.setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=set" << QString("key=%1").arg(key) << QString("value=%1").arg(value)); settingsOperation.backup(); QVERIFY2(settingsOperation.performOperation(), settingsOperation.errorString().toLatin1()); QVERIFY2(compareFiles(verifyFilePath, testFilePath), QString("\"%1\" and \"%2\" are different.") .arg(verifyFilePath, testFilePath).toLatin1()); } void undoSettingsValueInCreatedSubDirectories() { const QString testFilePath = createFilePath(QString("sub/directory/") + QTest::currentTestFunction()); const QString key = "key"; const QString value = "value"; SettingsOperation settingsOperation(nullptr); settingsOperation.setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=set" << QString("key=%1").arg(key) << QString("value=%1").arg(value)); settingsOperation.backup(); QVERIFY2(settingsOperation.performOperation(), settingsOperation.errorString().toLatin1()); QCOMPARE(QFile(testFilePath).exists(), true); QVERIFY2(settingsOperation.undoOperation(), settingsOperation.errorString().toLatin1()); QCOMPARE(QFile(testFilePath).exists(), false); QCOMPARE(QDir(QFileInfo(testFilePath).absolutePath()).exists(), false); } void removeSettingsValue() { const QString testFilePath = createFilePath(QTest::currentTestFunction()); QFile testFile(QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename)); QVERIFY2(testFile.copy(testFilePath), testFile.errorString().toLatin1()); m_cleanupFilePaths << testFilePath; const QString key = "testkey"; QString testValueString; { QSettings testSettings(testFilePath, QSettings::IniFormat); testValueString = testSettings.value(key).toString(); } QCOMPARE(testValueString.isEmpty(), false); SettingsOperation settingsOperation(nullptr); settingsOperation.setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=remove" << QString("key=%1").arg(key)); settingsOperation.backup(); QVERIFY2(settingsOperation.performOperation(), settingsOperation.errorString().toLatin1()); QVariant testValueVariant; { QSettings testSettings(testFilePath, QSettings::IniFormat); testValueVariant = testSettings.value(key); } QVERIFY(testValueVariant.isNull()); } void addSettingsArrayValue() { const QString testFilePath = createFilePath(QTest::currentTestFunction()); QFile contentFile(QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename)); QVERIFY2(contentFile.open(QIODevice::ReadOnly | QIODevice::Text), contentFile.errorString().toLatin1()); QFile testFile(testFilePath); QVERIFY2(testFile.open(QIODevice::WriteOnly | QIODevice::Text), contentFile.errorString().toLatin1()); QTextStream out(&testFile); QTextStream in(&contentFile); QString line = in.readLine(); while (!line.isNull()) { // remove the " to have some maybe invalid data out << line.replace("\"", QLatin1String("")) << QLatin1String("\n"); line = in.readLine(); } testFile.close(); QMap testSettingsOperationMap; testSettingsOperationMap["testcategory/categoryarrayvalue1"] = new SettingsOperation(nullptr); testSettingsOperationMap["testcategory/categoryarrayvalue2"] = new SettingsOperation(nullptr); testSettingsOperationMap["testcategory/categoryarrayvalue3"] = new SettingsOperation(nullptr); testSettingsOperationMap["testcategory/categoryarrayvalue4"] = new SettingsOperation(nullptr); QMap::iterator i = testSettingsOperationMap.begin(); while (i != testSettingsOperationMap.end()) { i.value()->setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=add_array_value" << QString("key=%1").arg(i.key()) << "value=value4"); i.value()->backup(); QVERIFY2(i.value()->performOperation(), i.value()->errorString().toLatin1()); ++i; } QStringList testKeys(testSettingsOperationMap.keys()); { QSettings verifySettings(testFilePath, QSettings::IniFormat); QCOMPARE(verifySettings.value(testKeys.at(0)).isNull(), false); QCOMPARE(verifySettings.value(testKeys.at(0)), verifySettings.value(testKeys.at(1))); QCOMPARE(verifySettings.value(testKeys.at(1)), verifySettings.value(testKeys.at(2))); QCOMPARE(verifySettings.value(testKeys.at(3)).toString(), QLatin1String("value4")); } i = testSettingsOperationMap.begin(); while (i != testSettingsOperationMap.end()) { i.value()->setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=add_array_value" << QString("key=%1").arg(i.key()) << "value=value4"); QVERIFY2(i.value()->undoOperation(), i.value()->errorString().toLatin1()); ++i; } { QStringList verifyStringList; verifyStringList << "value1" << "value2" << "value3"; QVariant verifyUndoValue = verifyStringList; QSettings verifySettings(testFilePath, QSettings::IniFormat); QCOMPARE(verifySettings.value(testKeys.at(0)), verifyUndoValue); QCOMPARE(verifySettings.value(testKeys.at(1)), verifyUndoValue); QCOMPARE(verifySettings.value(testKeys.at(2)), verifyUndoValue); // checking the none array value is removed QVERIFY(verifySettings.value(testKeys.at(3)).isNull()); } } void removeSettingsArrayValue() { const QString testFilePath = createFilePath(QTest::currentTestFunction()); QFile contentFile(QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename)); QVERIFY2(contentFile.open(QIODevice::ReadOnly | QIODevice::Text), contentFile.errorString() .toLatin1()); QFile testFile(testFilePath); QVERIFY2(testFile.open(QIODevice::WriteOnly | QIODevice::Text), contentFile.errorString() .toLatin1()); QTextStream out(&testFile); QTextStream in(&contentFile); QString line = in.readLine(); while (!line.isNull()) { // remove the " to have some maybe invalid data out << line.replace("\"", QLatin1String("")) << QLatin1String("\n"); line = in.readLine(); } testFile.close(); QMap testSettingsOperationMap; testSettingsOperationMap["testcategory/categoryarrayvalue1"] = new SettingsOperation(nullptr); testSettingsOperationMap["testcategory/categoryarrayvalue2"] = new SettingsOperation(nullptr); testSettingsOperationMap["testcategory/categoryarrayvalue3"] = new SettingsOperation(nullptr); QMap::iterator i = testSettingsOperationMap.begin(); while (i != testSettingsOperationMap.end()) { i.value()->setArguments(QStringList() << QString("path=%1").arg(testFilePath) << "method=remove_array_value" << QString("key=%1").arg(i.key()) << "value=value3"); i.value()->backup(); QVERIFY2(i.value()->performOperation(), i.value()->errorString().toLatin1()); ++i; } QStringList testKeys(testSettingsOperationMap.keys()); { QSettings verifySettings(testFilePath, QSettings::IniFormat); QCOMPARE(verifySettings.value(testKeys.at(0)).isNull(), false); QStringList verifyFirstValue = verifySettings.value(testKeys.at(0)).toStringList(); QCOMPARE(verifyFirstValue.contains(QLatin1String("value3")), false); QCOMPARE(verifySettings.value(testKeys.at(0)), verifySettings.value(testKeys.at(1))); QCOMPARE(verifySettings.value(testKeys.at(1)), verifySettings.value(testKeys.at(2))); } } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); QSettings testSettings(QDir(m_testSettingsDirPath).filePath(m_testSettingsFilename), QSettings::IniFormat); QCOMPARE(testSettings.value("testcategory/categoryarrayvalue1").toStringList(), QStringList() << "value1" << "value2" << "value3"); core->installDefaultComponentsSilently(); QCOMPARE(testSettings.value("testcategory/categoryarrayvalue1").toStringList(), QStringList() << "value1" << "value2" << "value3" << "valueFromScript"); core->commitSessionOperations(); core->setPackageManager(); core->uninstallComponentsSilently(QStringList() << "A"); QCOMPARE(testSettings.value("testcategory/categoryarrayvalue1").toStringList(), QStringList() << "value1" << "value2" << "value3"); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } // called after all tests void cleanupTestCase() { foreach (const QString &filePath, m_cleanupFilePaths) QFile(filePath).remove(); } private: QString createFilePath(const QString &fileNamePrependix) { return QDir(m_testSettingsDirPath).filePath(QString(fileNamePrependix) + m_testSettingsFilename); } bool compareFiles(const QString &filePath1, const QString &filePath2) { if (!QFile::exists(filePath1) || !QFile::exists(filePath2)) return false; const QByteArray fileHash1 = QInstaller::calculateHash(filePath1, QCryptographicHash::Sha1); const QByteArray fileHash2 = QInstaller::calculateHash(filePath2, QCryptographicHash::Sha1); return fileHash1 == fileHash2; } QString m_testSettingsFilename; QString m_testSettingsDirPath; QStringList m_cleanupFilePaths; }; QTEST_MAIN(tst_settingsoperation) #include "tst_settingsoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/settings/data/0040777000000000000000000000000013761647206021760 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/settings/data/empty_config.xml0100777000000000000000000000010013761647206025154 0ustar00 qt-installer-framework-4.0.1/tests/auto/installer/settings/data/full_config.xml0100777000000000000000000000424313761647206024774 0ustar00 Your application 1.2.3 Your application Installer Your vendor Your vendor @HomeDir@InstallationDirectory @RootDir@InstallationDirectory icon icon logo watermark banner background Modern 800 600 Super App maintenancetool maintenancetool.ini true myapp foo bar Launch MyApp true true true true true false false components.xml http://www.yourcompany.com/packages 1 user password de_de qt_de controlscript.js true qt-installer-framework-4.0.1/tests/auto/installer/settings/data/length_units_invalid.xml0100777000000000000000000000034713761647206026717 0ustar00 Your application 1.2.3 800pt 600pt qt-installer-framework-4.0.1/tests/auto/installer/settings/data/length_units_valid_em.xml0100777000000000000000000000034713761647206027051 0ustar00 Your application 1.2.3 800em 600em qt-installer-framework-4.0.1/tests/auto/installer/settings/data/length_units_valid_ex.xml0100777000000000000000000000034713761647206027064 0ustar00 Your application 1.2.3 800ex 600ex qt-installer-framework-4.0.1/tests/auto/installer/settings/data/length_units_valid_px.xml0100777000000000000000000000034713761647206027077 0ustar00 Your application 1.2.3 800px 600px qt-installer-framework-4.0.1/tests/auto/installer/settings/data/malformed_config.xml0100777000000000000000000000045413761647206026000 0ustar00 Your application 1.2.3 Your application Installer Your vendor Super App @RootDir@InstallationDirectory qt-installer-framework-4.0.1/tests/auto/installer/settings/data/minimal_config.xml0100777000000000000000000000017713761647206025462 0ustar00 Your application 1.2.3 qt-installer-framework-4.0.1/tests/auto/installer/settings/data/minimal_config_tag_defaults.xml0100777000000000000000000000043513761647206030201 0ustar00 Your application 1.2.3 qt-installer-framework-4.0.1/tests/auto/installer/settings/data/tutorial_config.xml0100777000000000000000000000047113761647206025674 0ustar00 Your application 1.2.3 Your application Installer Your vendor Super App @RootDir@InstallationDirectory qt-installer-framework-4.0.1/tests/auto/installer/settings/data/unexpectedattribute_config.xml0100777000000000000000000000033713761647206030122 0ustar00 Your application 1.2.3 Test qt-installer-framework-4.0.1/tests/auto/installer/settings/data/unexpectedtag_config.xml0100777000000000000000000000031213761647206026663 0ustar00 Your application 1.2.3 Bar qt-installer-framework-4.0.1/tests/auto/installer/settings/data/unknown_element_config.xml0100777000000000000000000000030513761647206027235 0ustar00 Your application 1.2.3 Your application Installer qt-installer-framework-4.0.1/tests/auto/installer/settings/settings.pro0100777000000000000000000000016113761647206023427 0ustar00include(../../qttest.pri) QT += network QT -= gui SOURCES += tst_settings.cpp RESOURCES += \ settings.qrc qt-installer-framework-4.0.1/tests/auto/installer/settings/settings.qrc0100777000000000000000000000130213761647206023412 0ustar00 data/empty_config.xml data/full_config.xml data/malformed_config.xml data/minimal_config.xml data/tutorial_config.xml data/unknown_element_config.xml data/minimal_config_tag_defaults.xml data/unexpectedtag_config.xml data/unexpectedattribute_config.xml data/length_units_valid_px.xml data/length_units_valid_em.xml data/length_units_valid_ex.xml data/length_units_invalid.xml qt-installer-framework-4.0.1/tests/auto/installer/settings/tst_settings.cpp0100777000000000000000000002473513761647206024320 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "settings.h" #include "errors.h" #include "repository.h" #include #include #include using namespace QInstaller; class tst_Settings : public QObject { Q_OBJECT private slots: void loadTutorialConfig(); void loadFullConfig(); void loadEmptyConfig(); void loadNotExistingConfig(); void loadMalformedConfig(); void loadUnknownElementConfigInStrictParseMode(); void loadUnknownElementConfigInRelaxedParseMode(); void loadMinimalConfigTagDefaults(); void loadUnexpectedAttributeConfig(); void loadUnexpectedTagConfig(); void loadConfigWithValidLengthUnits(); void loadConfigWithInvalidLengthUnits(); }; void tst_Settings::loadTutorialConfig() { Settings settings = Settings::fromFileAndPrefix(":///data/tutorial_config.xml", ":///data"); // specified values QCOMPARE(settings.applicationName(), QLatin1String("Your application")); QCOMPARE(settings.version(), QLatin1String("1.2.3")); QCOMPARE(settings.title(), QLatin1String("Your application Installer")); QCOMPARE(settings.publisher(), QLatin1String("Your vendor")); QCOMPARE(settings.startMenuDir(), QLatin1String("Super App")); QCOMPARE(settings.targetDir(), QLatin1String("@RootDir@InstallationDirectory")); // default values QCOMPARE(settings.logo(), QString()); QCOMPARE(settings.url(), QString()); QCOMPARE(settings.watermark(), QString()); QCOMPARE(settings.banner(), QString()); QCOMPARE(settings.background(), QString()); QCOMPARE(settings.pageListPixmap(), QString()); #if defined(Q_OS_WIN) QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".ico")); #elif defined(Q_OS_MACOS) QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".icns")); #else QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.png")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.png")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".png")); #endif QCOMPARE(settings.wizardStyle(), QString()); QCOMPARE(settings.wizardDefaultWidth(), settings.wizardShowPageList() ? 800 : 0); QCOMPARE(settings.wizardDefaultHeight(), 0); QCOMPARE(settings.wizardShowPageList(), true); QCOMPARE(settings.productImages(), QStringList()); QCOMPARE(settings.titleColor(), QString()); QCOMPARE(settings.runProgram(), QString()); QCOMPARE(settings.runProgramArguments(), QStringList()); QCOMPARE(settings.runProgramDescription(), QString()); QCOMPARE(settings.adminTargetDir(), QString()); QCOMPARE(settings.removeTargetDir(), QLatin1String("true")); QCOMPARE(settings.maintenanceToolName(), QLatin1String("maintenancetool")); QCOMPARE(settings.maintenanceToolIniFile(), QLatin1String("maintenancetool.ini")); QCOMPARE(settings.configurationFileName(), QLatin1String("components.xml")); QCOMPARE(settings.dependsOnLocalInstallerBinary(), false); QCOMPARE(settings.repositorySettingsPageVisible(), true); QCOMPARE(settings.allowSpaceInPath(), true); QCOMPARE(settings.allowNonAsciiCharacters(), false); QCOMPARE(settings.disableAuthorizationFallback(), false); QCOMPARE(settings.disableCommandLineInterface(), false); QCOMPARE(settings.createLocalRepository(), false); QCOMPARE(settings.installActionColumnVisible(), false); QCOMPARE(settings.hasReplacementRepos(), false); QCOMPARE(settings.repositories(), QSet()); QCOMPARE(settings.defaultRepositories(), QSet()); QCOMPARE(settings.temporaryRepositories(), QSet()); QCOMPARE(settings.userRepositories(), QSet()); QCOMPARE(settings.proxyType(), Settings::NoProxy); QCOMPARE(settings.ftpProxy(), QNetworkProxy()); QCOMPARE(settings.httpProxy(), QNetworkProxy()); QCOMPARE(settings.translations(), QStringList()); QCOMPARE(settings.controlScript(), QString()); QCOMPARE(settings.supportsModify(), true); } void tst_Settings::loadFullConfig() { Settings settings = Settings::fromFileAndPrefix(":///data/full_config.xml", ":///data"); } void tst_Settings::loadEmptyConfig() { try { Settings::fromFileAndPrefix(":/data/empty_config.xml", ":/data"); } catch (const Error &error) { QCOMPARE(error.message(), QLatin1String("Missing or empty tag in :/data/empty_config.xml.")); return; } QFAIL("No exception thrown"); } void tst_Settings::loadNotExistingConfig() { QString configFile = QLatin1String(":/data/inexisting_config.xml"); QFile file(configFile); QString errorString; if (!file.open(QIODevice::ReadOnly)) { errorString = file.errorString(); } try { Settings::fromFileAndPrefix(configFile, ":/data"); } catch (const Error &error) { QCOMPARE(error.message(), QString::fromLatin1("Cannot open settings file " "%1 for reading: %2").arg(configFile).arg(errorString)); return; } QFAIL("No exception thrown"); } void tst_Settings::loadMalformedConfig() { try { Settings::fromFileAndPrefix(":/data/malformed_config.xml", ":/data"); } catch (const Error &error) { QCOMPARE(error.message(), QLatin1String("Error in :/data/malformed_config.xml, line 9, column 0: " "Premature end of document.")); return; } QFAIL("No exception thrown"); } void tst_Settings::loadUnknownElementConfigInStrictParseMode() { try { Settings::fromFileAndPrefix(":/data/unknown_element_config.xml", ":/data"); } catch (const Error &error) { QCOMPARE(error.message(), QLatin1String("Error in :/data/unknown_element_config.xml, line 5, " "column 13: Unexpected element \"unknown\".")); return; } QFAIL("No exception thrown"); } void tst_Settings::loadUnknownElementConfigInRelaxedParseMode() { QTest::ignoreMessage(QtWarningMsg, "Ignoring following settings reader error in " ":/data/unknown_element_config.xml, line 5, column 13: Unexpected element \"unknown\"."); try { Settings settings = Settings::fromFileAndPrefix(":/data/unknown_element_config.xml", ":/data", Settings::RelaxedParseMode); QCOMPARE(settings.title(), QLatin1String("Your application Installer")); } catch (const Error &error) { QFAIL(qPrintable(QString::fromLatin1("Got an exception in TolerantParseMode: %1").arg(error.message()))); } } void tst_Settings::loadMinimalConfigTagDefaults() { Settings settings = Settings::fromFileAndPrefix(":///data/minimal_config_tag_defaults.xml", ":///data"); // These tags are not mandatory, though need to be set to default values. QCOMPARE(settings.configurationFileName(), QLatin1String("components.xml")); QCOMPARE(settings.maintenanceToolName(), QLatin1String("maintenancetool")); QCOMPARE(settings.maintenanceToolIniFile(), QLatin1String("maintenancetool.ini")); } void tst_Settings::loadUnexpectedAttributeConfig() { try { Settings::fromFileAndPrefix(":///data/unexpectedattribute_config.xml", ":///data"); } catch (const Error &error) { QCOMPARE(error.message(), QLatin1String("Error in :///data/unexpectedattribute_config.xml," " line 6, column 27: Unexpected attribute for element \"Argument\".")); return; } QFAIL("No exception thrown"); return; } void tst_Settings::loadUnexpectedTagConfig() { try { Settings::fromFileAndPrefix(":///data/unexpectedtag_config.xml", ":///data"); } catch (const Error &error) { QCOMPARE(error.message(), QLatin1String("Error in :///data/unexpectedtag_config.xml," " line 6, column 12: Unexpected element \"Foo\".")); return; } QFAIL("No exception thrown"); return; } void tst_Settings::loadConfigWithValidLengthUnits() { try { Settings settings = Settings::fromFileAndPrefix(":///data/length_units_valid_px.xml", ":///data"); QCOMPARE(settings.wizardDefaultWidth(), 800); QCOMPARE(settings.wizardDefaultHeight(), 600); // Cannot test the parsed values for these units portably since the // pixel value depends on the font metrics. Let's just check for parse // errors. (void)Settings::fromFileAndPrefix(":///data/length_units_valid_em.xml", ":///data"); (void)Settings::fromFileAndPrefix(":///data/length_units_valid_ex.xml", ":///data"); } catch (const Error &error) { QFAIL(qPrintable(QString::fromLatin1("Exception caught: %1").arg(error.message()))); } } void tst_Settings::loadConfigWithInvalidLengthUnits() { try { Settings settings = Settings::fromFileAndPrefix(":///data/length_units_invalid.xml", ":///data"); QCOMPARE(settings.wizardDefaultWidth(), 0); QCOMPARE(settings.wizardDefaultHeight(), 0); } catch (const Error &error) { QFAIL(qPrintable(QString::fromLatin1("Exception caught: %1").arg(error.message()))); } } QTEST_MAIN(tst_Settings) #include "tst_settings.moc" qt-installer-framework-4.0.1/tests/auto/installer/shared/0040777000000000000000000000000013761647206020455 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/shared/config.qrc0100777000000000000000000000016213761647206022430 0ustar00 installer-config/config.xml qt-installer-framework-4.0.1/tests/auto/installer/shared/installer-config/0040777000000000000000000000000013761647206023715 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/shared/installer-config/config.xml0100777000000000000000000000016313761647206025704 0ustar00 test 1.0.0 qt-installer-framework-4.0.1/tests/auto/installer/shared/packagemanager.h0100777000000000000000000000464713761647206023567 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef PACKAGEMANAGER_H #define PACKAGEMANAGER_H #include #include #include #include #include #include using namespace QInstaller; struct PackageManager { static PackageManagerCore *getPackageManager(const QString &targetDir, const QString &repository = QString()) { PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList ()); QString appFilePath = QCoreApplication::applicationFilePath(); core->setAllowedRunningProcesses(QStringList() << appFilePath); core->disableWriteMaintenanceTool(); core->setAutoConfirmCommand(); QSet repoList; Repository repo = Repository::fromUserInput(repository); repoList.insert(repo); core->settings().setDefaultRepositories(repoList); core->setValue(scTargetDir, targetDir); return core; } static PackageManagerCore *getPackageManagerWithInit(const QString &targetDir, const QString &repository = QString()) { QInstaller::init(); return getPackageManager(targetDir, repository); } }; #endif qt-installer-framework-4.0.1/tests/auto/installer/shared/verifyinstaller.h0100777000000000000000000001043313761647206024051 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef VERIFYINSTALLER_H #define VERIFYINSTALLER_H #include #include #include #include #include #include struct VerifyInstaller { static void verifyInstallerResources(const QString &installDir, const QString &componentName, const QString &fileName) { QDir dir(installDir + QDir::separator() + "installerResources" + QDir::separator() + componentName); QVERIFY(dir.exists()); QFileInfo fileInfo; fileInfo.setFile(dir, fileName); QVERIFY(fileInfo.exists()); } static void verifyInstallerResourcesDeletion(const QString &installDir, const QString &componentName) { QDir dir(installDir + QDir::separator() + "installerResources" + QDir::separator() + componentName); QVERIFY(!dir.exists()); } static void verifyInstallerResourceFileDeletion(const QString &installDir, const QString &componentName, const QString &fileName) { QDir dir(installDir + QDir::separator() + "installerResources" + QDir::separator() + componentName); QFileInfo fileInfo; fileInfo.setFile(dir, fileName); QVERIFY(!fileInfo.exists()); } static void verifyFileExistence(const QString &installDir, const QStringList &fileList) { for (int i = 0; i < fileList.count(); i++) QVERIFY(QFileInfo::exists(installDir + QDir::separator() + fileList.at(i))); QDir dir(installDir); QCOMPARE(dir.entryList(QStringList() << "*.*", QDir::Files).count(), fileList.count()); } static QString fileContent(const QString &fileName) { QFile file(fileName); QTextStream stream(&file); file.open(QIODevice::ReadOnly); QString str = stream.readAll(); file.close(); return str; } static void verifyFileContent(const QString &fileName, const QString &content) { QVERIFY(fileContent(fileName).contains(content)); } static void verifyFileHasNoContent(const QString &fileName, const QString &content) { QVERIFY(!fileContent(fileName).contains(content)); } static void addToFileMap(const QDir &baseDir, const QFileInfo &fileInfo, QMap &map) { QDir directory(fileInfo.absoluteFilePath()); directory.setFilter(QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::AllDirs | QDir::Files); QFileInfoList fileInfoList = directory.entryInfoList(); foreach (const QFileInfo &info, fileInfoList) { if (info.isDir()) { map.insert(baseDir.relativeFilePath(info.filePath()), QByteArray()); addToFileMap(baseDir, info, map); } else { QCryptographicHash hash(QCryptographicHash::Sha1); QFile file(info.absoluteFilePath()); QVERIFY(file.open(QIODevice::ReadOnly)); QVERIFY(hash.addData(&file)); map.insert(baseDir.relativeFilePath(info.filePath()), hash.result().toHex()); file.close(); } } } }; #endif qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/0040777000000000000000000000000013761647206024150 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/data/0040777000000000000000000000000013761647206025061 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/data/repository/0040777000000000000000000000000013761647206027300 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/data/repository/A/0040777000000000000000000000000013761647206027460 5ustar00././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/data/repository/A/1.0.2-1meta.7zqt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/data/repository/A/1.0.2-10100777000000000000000000000157413761647206030206 0ustar007zžŊ'kāė:"@>UPā―]Šģ7‚ļ{ĢkōĮ„ōüÕ†ģ*I7eNŧIđ5ņÝVSžæ:€™hīUÝäôQrĖī{hY)DÜģļŽÜČpÃS Ŋ:ĩŠŠøTęxŠ.œf•~ ĩÛy ļdžF=5hcäŨN\7ˆā]üû†“8Mđc2"üŽ$ÔýļÉ_ĨDē9Ð`Ą]ÝmPqeäÚËÚÖÐ/ĢÖ§ĸŠûÆÁˆ^Ŧsûŋ5ŸÃļE0âÛÔĒåUļÉä ĸûPއ(tDÅýœ›q#5ž ÖBßũȗ0Vė|ĸ­ČĻP·”>„3= tЇ­ĻTģųÞ'|ôõd°–xi0óĩšTB˜üC˜üŸ0õ~[―(­ĮāÉĮŽP 8Ž”úÆÎĸV„Šų:Đ.ŅlĪ$,šŌ‘ļÛÉåøĄžõ&!@ggb™…Nj)ˆEMĮBޟĪNoņõþŽ‘zėĻņmq5–Ë8žŪ8›ÄÝÆĢėXԓwŠ+M“óŧÝöWMļÉχðüAÏ1ĨĢŅÛŊýĨKIxvßK‰$/•‰FxĮšyZŪ­úvAȈŠ= ZYSîōc(xe’súÖQKëhâĮÓã‹&ęĪĒæōÍą9Ņkvߨ ëß #ņiŽ@…|já§ïûFÃ_ {AnyApplication} 1.0.0 A A Example component A 1.0.2-1 2015-01-01 true qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/settings.qrc0100777000000000000000000000024013761647206026513 0ustar00 data/repository/Updates.xml data/repository/A/1.0.2-1meta.7z ././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/simplemovefileoperation.proqt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/simplemovefileoperation.p0100777000000000000000000000023213761647206031267 0ustar00include(../../qttest.pri) QT -= gui QT += testlib SOURCES = tst_simplemovefileoperation.cpp RESOURCES += \ settings.qrc \ ..\shared\config.qrc ././@LongLink0100777000000000000000000000015213761647206010114 Lustar00qt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/tst_simplemovefileoperation.cppqt-installer-framework-4.0.1/tests/auto/installer/simplemovefileoperation/tst_simplemovefileoperati0100777000000000000000000001231713761647206031375 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../shared/packagemanager.h" #include #include #include #include #include #include using namespace KDUpdater; using namespace QInstaller; class tst_simplemovefileoperation : public QObject { Q_OBJECT private slots: void testMissingArguments() { SimpleMoveFileOperation op(nullptr); op.backup(); QVERIFY(op.testOperation()); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments); QCOMPARE(op.errorString(), QString("Invalid arguments in SimpleMoveFile: " "0 arguments given, exactly 2 arguments expected.")); op.setArguments(QStringList() << "" << ""); QVERIFY(!op.performOperation()); QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError); QCOMPARE(op.errorString(), QString("None of the arguments can be empty: " "source \"\", target \"\".")); } void testMoveFileWithOverwrite_data() { QTest::addColumn("source"); QTest::addColumn("destination"); QTest::newRow("relative") << "test1" << "test2"; QTest::newRow("absolute") << qApp->applicationDirPath() + QDir::toNativeSeparators("/test") << generateTemporaryFileName(); } void testMoveFileWithOverwrite() { QFETCH(QString, source); QFETCH(QString, destination); // Create dummy original file for move destination QFile destFile(destination); QVERIFY(destFile.open(QIODevice::WriteOnly)); destFile.close(); QByteArray testString("Generated by QTest\n"); QFile testFile(source); QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream out(&testFile); out << testString; testFile.close(); QVERIFY(QFileInfo(source).exists()); QByteArray testFileHash = QInstaller::calculateHash(source, QCryptographicHash::Sha1); SimpleMoveFileOperation op(nullptr); op.setArguments(QStringList() << source << destination); QVERIFY2(op.performOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo(source).exists()); QByteArray destinationFileHash = QInstaller::calculateHash(destination, QCryptographicHash::Sha1); QVERIFY(testFileHash == destinationFileHash); QVERIFY2(op.undoOperation(), op.errorString().toLatin1()); QVERIFY(!QFileInfo(destination).exists()); QByteArray sourceFileHash = QInstaller::calculateHash(source, QCryptographicHash::Sha1); QVERIFY(testFileHash == sourceFileHash); QVERIFY(QFile(source).remove()); } void testPerformingFromCLI() { QString installDir = QInstaller::generateTemporaryFileName(); QVERIFY(QDir().mkpath(installDir)); PackageManagerCore *core = PackageManager::getPackageManagerWithInit (installDir, ":///data/repository"); QString destinationDir = installDir + QDir::separator() + "destination"; QVERIFY(QDir().mkpath(destinationDir)); // Matches filename in component install script QFile file(installDir + QDir::toNativeSeparators("/test")); QVERIFY(file.open(QIODevice::ReadWrite)); file.close(); core->installDefaultComponentsSilently(); QVERIFY(!file.exists()); QFile movedFile(destinationDir + QDir::separator() + "test"); QVERIFY(movedFile.exists()); core->setPackageManager(); core->commitSessionOperations(); core->uninstallComponentsSilently(QStringList() << "A"); QVERIFY(!movedFile.exists() && file.exists()); QDir dir(installDir); QVERIFY(dir.removeRecursively()); core->deleteLater(); } }; QTEST_MAIN(tst_simplemovefileoperation) #include "tst_simplemovefileoperation.moc" qt-installer-framework-4.0.1/tests/auto/installer/solver/0040777000000000000000000000000013761647206020521 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/solver/solver.pro0100777000000000000000000000011213761647206022547 0ustar00include(../../qttest.pri) QT -= gui QT += qml SOURCES += tst_solver.cpp qt-installer-framework-4.0.1/tests/auto/installer/solver/tst_solver.cpp0100777000000000000000000003413413761647206023436 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include using namespace QInstaller; typedef QMap ComponentToStringList; class Data { public: Data() {} explicit Data(const QString &data) : m_data(data) {} inline uint qHash(const Data &test); QString data() const { return m_data; } bool operator==(const Data &rhs) const { return m_data == rhs.m_data; } const Data &operator=(const Data &rhs) { if (this != &rhs) { m_data = rhs.m_data; } return *this; } private: QString m_data; }; inline uint qHash(const Data &data) { return qHash(data.data()); } class NamedComponent : public Component { public: NamedComponent(PackageManagerCore *core, const QString &name) : Component(core) { setValue(scName, name); setValue(scVersion, QLatin1String("1.0.0")); } NamedComponent(PackageManagerCore *core, const QString &name, const QString &version) : Component(core) { setValue(scName, name); setValue(scVersion, version); } }; class tst_Solver : public QObject { Q_OBJECT private slots: // TODO: add failing cases void sortGraph() { Graph graph; graph.addNode("Hut"); graph.addEdge("Jacke", "Shirt"); graph.addEdge("Guertel", "Hose"); graph.addEdge("Guertel", "Shirt"); graph.addEdge("Shirt", "Socken"); graph.addEdge("Socken", "Unterwaesche"); graph.addEdge("Shirt", "Unterwaesche"); graph.addEdges("Hose", QStringList() << "Unterwaesche" << "Socken"); graph.addEdges("Krawatte", QStringList() << "Shirt" << "Hose" << "Guertel"); graph.addEdges("Schuhe", QStringList() << "Socken" << "Unterwaesche" << "Hose"); graph.addEdges("Jacke", QStringList() << "Hose" << "Shirt" << "Guertel" << "Schuhe" << "Krawatte"); QList resolved = graph.sort(); foreach (const QString &value, resolved) qDebug("%s", qPrintable(value)); } void sortGraphReverse() { Graph graph; graph.addEdge("Krawatte", "Jacke"); graph.addEdge("Guertel", "Jacke"); graph.addEdge("Shirt", "Guertel"); graph.addEdges("Shirt", QList() << "Krawatte" << "Schuhe"); graph.addEdges("Hose", QList() << "Schuhe" << "Guertel" << "Shirt"); graph.addEdges("Socken", QList() << "Schuhe" << "Hose"); graph.addEdges("Unterwaesche", QList() << "Socken" << "Hose" << "Guertel" << "Shirt" << "Krawatte" << "Schuhe"); QList resolved = graph.sortReverse(); foreach (const QString &value, resolved) qDebug("%s", qPrintable(value)); } void sortGraphCycle() { Data a("A"), b("B"), c("C"), d("D"), e("E"); Graph graph; graph.addEdge(a, b); graph.addEdge(b, c); graph.addEdge(c, d); graph.addEdge(d, e); graph.addEdge(e, a); QList resolved = graph.sort(); foreach (const Data &value, resolved) qDebug("%s", qPrintable(value.data())); QPair cycle = graph.cycle(); qDebug("Found cycle: %s", graph.hasCycle() ? "true" : "false"); qDebug("(%s) has a indirect dependency on (%s).", qPrintable(cycle.second.data()), qPrintable(cycle.first.data())); } void resolveInstaller_data() { QTest::addColumn("core"); QTest::addColumn >("selectedComponents"); QTest::addColumn >("expectedResult"); QTest::addColumn >("installReason"); PackageManagerCore *core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentA = new NamedComponent(core, QLatin1String("A")); NamedComponent *componentAA = new NamedComponent(core, QLatin1String("A.A")); NamedComponent *componentAB = new NamedComponent(core, QLatin1String("A.B")); componentA->appendComponent(componentAA); componentA->appendComponent(componentAB); NamedComponent *componentB = new NamedComponent(core, QLatin1String("B")); NamedComponent *componentB_NewVersion = new NamedComponent(core, QLatin1String("B_version"), QLatin1String("2.0.0")); NamedComponent *componentB_Auto = new NamedComponent(core, QLatin1String("B_auto")); componentB->addDependency(QLatin1String("A.B")); componentAB->addDependency(QLatin1String("B_version->=2.0.0")); componentB_Auto->addAutoDependOn(QLatin1String("B_version")); core->appendRootComponent(componentA); core->appendRootComponent(componentB); core->appendRootComponent(componentB_NewVersion); core->appendRootComponent(componentB_Auto); QTest::newRow("Installer resolved") << core << (QList() << componentB) << (QList() << componentB_NewVersion << componentAB << componentB << componentB_Auto) << (QList() << InstallerCalculator::Dependent << InstallerCalculator::Dependent << InstallerCalculator::Resolved << InstallerCalculator::Automatic); } void resolveInstaller() { QFETCH(PackageManagerCore *, core); QFETCH(QList , selectedComponents); QFETCH(QList , expectedResult); QFETCH(QList, installReason); InstallerCalculator calc(core->components(PackageManagerCore::ComponentType::AllNoReplacements)); calc.appendComponentsToInstall(selectedComponents); QList result = calc.orderedComponentsToInstall(); QCOMPARE(result.count(), expectedResult.count()); for (int i = 0; i < result.count(); i++) { QCOMPARE(result.at(i), expectedResult.at(i)); QCOMPARE((int)calc.installReasonType(result.at(i)), installReason.at(i)); } delete core; } void unresolvedDependencyVersion_data() { QTest::addColumn("core"); QTest::addColumn >("selectedComponents"); QTest::addColumn >("expectedResult"); PackageManagerCore *core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentA = new NamedComponent(core, QLatin1String("A")); NamedComponent *componentB = new NamedComponent(core, QLatin1String("B"), QLatin1String("1.0.0")); componentA->addDependency(QLatin1String("B->=2.0.0")); core->appendRootComponent(componentA); core->appendRootComponent(componentB); if (core->settings().allowUnstableComponents()) { QTest::newRow("Installer resolved") << core << (QList() << componentA) << (QList() << componentA); } else { QTest::newRow("Installer resolved") << core << (QList() << componentA) << (QList()); } } void unresolvedDependencyVersion() { QFETCH(PackageManagerCore *, core); QFETCH(QList , selectedComponents); QFETCH(QList , expectedResult); InstallerCalculator calc(core->components(PackageManagerCore::ComponentType::AllNoReplacements)); QTest::ignoreMessage(QtWarningMsg, "Cannot find missing dependency \"B->=2.0.0\" for \"A\"."); calc.appendComponentsToInstall(selectedComponents); QList result = calc.orderedComponentsToInstall(); QCOMPARE(result.count(), expectedResult.count()); delete core; } void resolveUninstaller_data() { QTest::addColumn("core"); QTest::addColumn >("selectedToUninstall"); QTest::addColumn >("installedComponents"); QTest::addColumn >("expectedResult"); PackageManagerCore *core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentA = new NamedComponent(core, QLatin1String("A")); NamedComponent *componentAA = new NamedComponent(core, QLatin1String("A.A")); NamedComponent *componentAB = new NamedComponent(core, QLatin1String("A.B")); componentA->appendComponent(componentAA); componentA->appendComponent(componentAB); NamedComponent *componentB = new NamedComponent(core, QLatin1String("B")); componentB->addDependency(QLatin1String("A.B")); core->appendRootComponent(componentA); core->appendRootComponent(componentB); componentA->setInstalled(); componentB->setInstalled(); componentAB->setInstalled(); QTest::newRow("Uninstaller resolved") << core << (QList() << componentAB) << (QList() << componentA << componentB) << (QSet() << componentAB << componentB); core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *compA = new NamedComponent(core, QLatin1String("A")); NamedComponent *compB = new NamedComponent(core, QLatin1String("B")); NamedComponent *compC = new NamedComponent(core, QLatin1String("C")); compB->addDependency(QLatin1String("A")); compC->addDependency(QLatin1String("B")); core->appendRootComponent(compA); core->appendRootComponent(compB); core->appendRootComponent(compC); compA->setInstalled(); compB->setInstalled(); QTest::newRow("Cascade dependencies") << core << (QList() << compA) << (QList() << compB) << (QSet() << compA << compB); } void resolveUninstaller() { QFETCH(PackageManagerCore *, core); QFETCH(QList , selectedToUninstall); QFETCH(QList , installedComponents); QFETCH(QSet , expectedResult); UninstallerCalculator calc(installedComponents); calc.appendComponentsToUninstall(selectedToUninstall); QSet result = calc.componentsToUninstall(); QCOMPARE(result.count(), expectedResult.count()); QCOMPARE(result, expectedResult); delete core; } void checkComponent_data() { QTest::addColumn >("componentsToCheck"); QTest::addColumn("expectedResult"); PackageManagerCore *core = new PackageManagerCore(); core->setPackageManager(); NamedComponent *componentA = new NamedComponent(core, QLatin1String("A")); NamedComponent *componentB = new NamedComponent(core, QLatin1String("B")); componentB->addAutoDependOn(QLatin1String("A")); componentB->setValue(QLatin1String("Default"), QLatin1String("true")); core->appendRootComponent(componentA); core->appendRootComponent(componentB); ComponentToStringList result; result[componentB].append(QLatin1String("Component B specifies \"Default\" property " "together with \"AutoDependOn\" list. This combination of states " "may not work properly.")); QTest::newRow("AutoDepend and default") << (QList() << componentA << componentB) << result; NamedComponent *componentC = new NamedComponent(core, QLatin1String("C")); NamedComponent *componentD = new NamedComponent(core, QLatin1String("D")); NamedComponent *componentE = new NamedComponent(core, QLatin1String("E")); componentD->setValue(QLatin1String("AutoDependOn"), QLatin1String("C")); componentE->addDependency(QLatin1String("D")); core->appendRootComponent(componentC); core->appendRootComponent(componentD); core->appendRootComponent(componentE); result.clear(); result[componentD].append(QLatin1String("Other components depend on auto dependent " "component D. This may not work properly.")); QTest::newRow("AutoDepend and dependency") << (QList() << componentC << componentD << componentE) << result; } void checkComponent() { QFETCH(QList, componentsToCheck); QFETCH(ComponentToStringList, expectedResult); foreach (Component *component, componentsToCheck) { const QStringList result = ComponentChecker::checkComponent(component); QCOMPARE(result, expectedResult.value(component)); } } }; QTEST_MAIN(tst_Solver) #include "tst_solver.moc" qt-installer-framework-4.0.1/tests/auto/installer/task/0040777000000000000000000000000013761647206020151 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/task/task.pro0100777000000000000000000000012713761647206021635 0ustar00include(../../qttest.pri) QT -= gui QT += network concurrent SOURCES += tst_task.cpp qt-installer-framework-4.0.1/tests/auto/installer/task/tst_task.cpp0100777000000000000000000001000413761647206022504 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include using namespace QInstaller; static const qint64 scLargeSize = 4194304LL; class tst_Task : public QObject { Q_OBJECT private slots: void copyFile() { QTemporaryFile file; file.setAutoRemove(false); if (file.open()) { const QString filename = file.fileName(); QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1')); file.close(); CopyFileTask fileTask(filename); QFutureWatcher watcher; QSignalSpy started(&watcher, SIGNAL(started())); QSignalSpy finished(&watcher, SIGNAL(finished())); QSignalSpy progress(&watcher, SIGNAL(progressValueChanged(int))); watcher.setFuture(QtConcurrent::run(&CopyFileTask::doTask, &fileTask)); watcher.waitForFinished(); QTest::qWait(10); // Spin the event loop to deliver queued signals. QCOMPARE(started.count(), 1); QCOMPARE(finished.count(), 1); FileTaskResult result = watcher.result(); QCOMPARE(watcher.future().resultCount(), 1); QVERIFY(QFile(result.target()).exists()); QCOMPARE(file.size(), QFile(result.target()).size()); QCOMPARE(result.checkSum().toHex(), QByteArray("85304f87b8d90554a63c6f6d1e9cc974fbef8d32")); } } void downloadFile() { QTemporaryFile file; file.setAutoRemove(false); if (file.open()) { const QString filename = file.fileName(); QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1')); file.close(); DownloadFileTask fileTask(QLatin1String("file:///") + filename); QFutureWatcher watcher; QSignalSpy started(&watcher, SIGNAL(started())); QSignalSpy finished(&watcher, SIGNAL(finished())); QSignalSpy progress(&watcher, SIGNAL(progressValueChanged(int))); watcher.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, &fileTask)); watcher.waitForFinished(); QTest::qWait(10); // Spin the event loop to deliver queued signals. QCOMPARE(started.count(), 1); QCOMPARE(finished.count(), 1); FileTaskResult result = watcher.result(); QCOMPARE(watcher.future().resultCount(), 1); QVERIFY(QFile(result.target()).exists()); QCOMPARE(file.size(), QFile(result.target()).size()); QCOMPARE(result.checkSum().toHex(), QByteArray("85304f87b8d90554a63c6f6d1e9cc974fbef8d32")); } } }; QTEST_MAIN(tst_Task) #include "tst_task.moc" qt-installer-framework-4.0.1/tests/auto/installer/unicodeexecutable/0040777000000000000000000000000013761647206022677 5ustar00qt-installer-framework-4.0.1/tests/auto/installer/unicodeexecutable/main.c0100777000000000000000000000432013761647206023766 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "stringdata.h" #include #include #include #include int main(int argc, char **argv) { assert(argc == 3 || !"incorrect number of arguments"); if (!strcmp(argv[1], "utf8")) { printf("%s", utf8Text); } else { printf("%s", asciiText); } return atoi(argv[2]); } qt-installer-framework-4.0.1/tests/auto/installer/unicodeexecutable/stringdata.h0100777000000000000000000000417513761647206025217 0ustar00/************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef STRINGDATA_H #define STRINGDATA_H const char asciiText[] = "This is some ASCII text."; const char utf8Text[] = "\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78"; #endif // !defined(STRINGDATA_H) qt-installer-framework-4.0.1/tests/auto/installer/unicodeexecutable/unicodeexecutable.pro0100777000000000000000000000013613761647206027111 0ustar00SOURCES = main.c CONFIG -= qt app_bundle CONFIG += console win32: DESTDIR = $$OUT_PWD QT = qt-installer-framework-4.0.1/tests/auto/qttest.pri0100777000000000000000000000074613761647206017261 0ustar00include(../../installerfw.pri) #include(qttestrpath.pri) isEmpty(TEMPLATE):TEMPLATE=app QT += testlib CONFIG += qt warn_on console depend_includepath testcase DEFINES -= QT_NO_CAST_FROM_ASCII # prefix test binary with tst_ !contains(TARGET, ^tst_.*):TARGET = $$join(TARGET,,"tst_") #win32 { # lib = ../../ # lib ~= s,/,\\,g # # the below gets added to later by testcase.prf # check.commands = cd . & set PATH=$$lib;%PATH%& cmd /c #} macx:include(../../no_app_bundle.pri) qt-installer-framework-4.0.1/tests/auto/tools/0040777000000000000000000000000013761647206016352 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/0040777000000000000000000000000013761647206020217 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/0040777000000000000000000000000013761647206021775 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/0040777000000000000000000000000013761647206022155 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/data/0040777000000000000000000000000013761647206023066 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/data/A.txt0100777000000000000000000000004013761647206024001 0ustar00Example content for package A. qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/meta/0040777000000000000000000000000013761647206023103 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/meta/package.xml0100777000000000000000000000042713761647206025223 0ustar00 A Example component A 1.0.0 2020-01-01 true qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/A/meta/script1.0.0.qs0100777000000000000000000000003113761647206025323 0ustar00function Component() { } qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/B/0040777000000000000000000000000013761647206022156 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/B/data/0040777000000000000000000000000013761647206023067 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/B/data/B.txt0100777000000000000000000000004013761647206024003 0ustar00Example content for package B. qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/B/meta/0040777000000000000000000000000013761647206023104 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages/B/meta/package.xml0100777000000000000000000000036313761647206025223 0ustar00 B Example component B 1.0.0 2020-01-01 true qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/0040777000000000000000000000000013761647206023337 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/0040777000000000000000000000000013761647206023517 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/data/0040777000000000000000000000000013761647206024430 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/data/A_update.txt0100777000000000000000000000004013761647206026705 0ustar00Example content for package A. qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/meta/0040777000000000000000000000000013761647206024445 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/meta/package.xml0100777000000000000000000000042713761647206026565 0ustar00 A Example component A 2.0.0 2020-01-01 true qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/A/meta/script2.0.0.qs0100777000000000000000000000003113761647206026666 0ustar00function Component() { } qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/B/0040777000000000000000000000000013761647206023520 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/B/data/0040777000000000000000000000000013761647206024431 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/B/data/B_update.txt0100777000000000000000000000004013761647206026707 0ustar00Example content for package B. qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/B/meta/0040777000000000000000000000000013761647206024446 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/packages_update/B/meta/package.xml0100777000000000000000000000036313761647206026565 0ustar00 B Example component B 1.0.0 2020-01-01 true qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/0040777000000000000000000000000013761647206024520 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/0040777000000000000000000000000013761647206026150 5ustar00././@LongLink0100777000000000000000000000015413761647206010116 Lustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/2020-11-10-0816_meta.7zqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/2020-11-10-08160100777000000000000000000000033213761647206027505 0ustar007zžŊ'Ÿ+{6™!CĘ\function Component() { } 3Ūа<Ÿ?GA ģ†5/ý#;!_ōT"BÐVJ˜†b­ú#y•kûÝîœX"=žIPŨŦk֓þjĪYųųc:Šëą S˜ÛîÎĖðâK•'å%+Õ@ôõĖ‘o>hÔŪčÁĩökú ‰ðzîîYŲi  y #] €Ę j9Xqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/0040777000000000000000000000000013761647206026330 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/2.0.0content.7zqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/2.0.0content.0100777000000000000000000000031013761647206030353 0ustar007zžŊ'Ȱ@u&‚”kžŅ!Example content for package A.  & !! " įUŠƒ A_update.txt Õķ•ĩąÖ Õķ•ĩąÖ Õķ•ĩąÖ ././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/2.0.0content.7z.sha1qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/2.0.0content.0100777000000000000000000000005013761647206030354 0ustar00c7cca768ebfe60c4295a79762d4e19e63f2c21d2qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/A/2.0.0meta.7z0100777000000000000000000000032713761647206030120 0ustar007zžŊ'YG–!Ô]G?function Component() { } 3Ūа<Ÿ?GA ģ†5/ý#;!_ōT"Bυ•ųŌÜOd7KÅƟZ~ 2ŒæÐnĐŠŒ8ƒ_ ne‘ĩĢlފf\)]ø)FũĨÂ3E]˜á? ácōĐ;sÃŒ-ųĻZ{ųÕ QâÛXbՙ€  v #] €Ū {i0qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/0040777000000000000000000000000013761647206026332 5ustar00././@LongLink0100777000000000000000000000014613761647206010117 Lustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/1.0.0content.7zqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/1.0.0content.0100777000000000000000000000030713761647206030362 0ustar007zžŊ'&r*P5rOÎ 60Example content for package A (new version!).  5 !! 1 /Îą  A.txt âĐVŲžķÖ âĐVŲžķÖ ŊĪ­Y>Ö ././@LongLink0100777000000000000000000000015313761647206010115 Lustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/1.0.0content.7z.sha1qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/1.0.0content.0100777000000000000000000000005013761647206030355 0ustar000e995c11dc35bd2b4ac04d408eb7091f8322ea49qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/C/1.0.0meta.7z0100777000000000000000000000015213761647206030115 0ustar007zžŊ'žļũūJé]üQ€C ÃÞU)·Ö ÃÞU)·Ö ÃÞU)·Öqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_componentAndUnite/Updates.xml0100777000000000000000000000212313761647206030275 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 2.0.0 2020-01-01 true content.7z 11f74e8fbc7d6c155dd6503c460c2c1955340cc1 C C Example component C 1.0.0 2015-01-01 true content.7z 4558f31428ef88eb23521b4f119465967945e2f7 d674e6574895c02d3a02fb97a46b159d35f17c68 2020-11-10-0816_meta.7z qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/A/0040777000000000000000000000000013761647206024700 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/A/2.0.0content.7z0100777000000000000000000000004013761647206027204 0ustar007zžŊ'›Õqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/A/2.0.0content.7z.sha10100777000000000000000000000005013761647206030040 0ustar00059e5ed8cd3a1fbca08cccfa4075265192603e3fqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/A/2.0.0meta.7z0100777000000000000000000000032113761647206026462 0ustar007zžŊ'7ŌƐ!ÆÜ’function Component() { } 3Ūа<Ÿ?GA ģ†5/ý#;!_ōT"Bυ•ųŌÜOd7KÅƟZ~ 2ŒæÐnĐŠŒ8ƒ_ ne‘ĩĢlފf+ķc +āÔQH?rõþ@ƒëÆÁP—Dn “œØäģģ>í ŋ3XØ  p #] €Ū Ξ€Sqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/B/0040777000000000000000000000000013761647206024701 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/B/1.0.0content.7z0100777000000000000000000000004013761647206027204 0ustar007zžŊ'›Õqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/B/1.0.0content.7z.sha10100777000000000000000000000005013761647206030040 0ustar00059e5ed8cd3a1fbca08cccfa4075265192603e3fqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/B/1.0.0meta.7z0100777000000000000000000000015213761647206026464 0ustar007zžŊ'—1=ÜJŌŽ4"€B F?G.ĄÖ F?G.ĄÖ F?G.ĄÖqt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_component/Updates.xml0100777000000000000000000000174313761647206026654 0ustar00 {AnyApplication} 1.0.0 true A A Example component A 2.0.0 2020-01-01 true content.7z da6dae55a8cc3fb9f012e33fa7b9c187a823aa9a B B Example component B 1.0.0 2020-01-01 true content.7z d88b373458b4bbec38132692061bf1e7aa68e7f7 qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_unite/0040777000000000000000000000000013761647206023642 5ustar00qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_unite/2020-11-10-0931_meta.7z0100777000000000000000000000033113761647206026541 0ustar007zžŊ'įÆB˜!Ö qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_unite/C/1.0.0content.7z.sha10100777000000000000000000000005013761647206027163 0ustar000e995c11dc35bd2b4ac04d408eb7091f8322ea49qt-installer-framework-4.0.1/tests/auto/tools/repotest/repository_unite/Updates.xml0100777000000000000000000000174313761647206025776 0ustar00 {AnyApplication} 1.0.0 false A A Example component A 2.0.0 2020-01-01 true content.7z C C Example component C 1.0.0 2015-01-01 true content.7z 3b46ef65a751d9498205412fc22de43ce29e5d8a 2020-11-10-0931_meta.7z qt-installer-framework-4.0.1/tests/auto/tools/repotest/repotest.pro0100777000000000000000000000022313761647206022603 0ustar00include(../../qttest.pri) include(../../../../tools/repogen/repogen.pri) QT -= gui SOURCES += tst_repotest.cpp RESOURCES += \ settings.qrc qt-installer-framework-4.0.1/tests/auto/tools/repotest/settings.qrc0100777000000000000000000000354213761647206022572 0ustar00 packages/A/data/A.txt packages/A/meta/package.xml packages/A/meta/script1.0.0.qs packages/B/data/B.txt packages/B/meta/package.xml packages_update/A/data/A_update.txt packages_update/A/meta/package.xml packages_update/A/meta/script2.0.0.qs packages_update/B/data/B_update.txt packages_update/B/meta/package.xml repository_component/A/2.0.0content.7z repository_component/A/2.0.0content.7z.sha1 repository_component/A/2.0.0meta.7z repository_component/B/1.0.0content.7z repository_component/B/1.0.0content.7z.sha1 repository_component/B/1.0.0meta.7z repository_component/Updates.xml repository_componentAndUnite/A/2.0.0content.7z repository_componentAndUnite/A/2.0.0content.7z.sha1 repository_componentAndUnite/A/2.0.0meta.7z repository_componentAndUnite/C/1.0.0content.7z repository_componentAndUnite/C/1.0.0content.7z.sha1 repository_componentAndUnite/C/1.0.0meta.7z repository_componentAndUnite/2020-11-10-0816_meta.7z repository_componentAndUnite/Updates.xml repository_unite/A/2.0.0content.7z repository_unite/A/2.0.0content.7z.sha1 repository_unite/C/1.0.0content.7z repository_unite/C/1.0.0content.7z.sha1 repository_unite/2020-11-10-0931_meta.7z repository_unite/Updates.xml qt-installer-framework-4.0.1/tests/auto/tools/repotest/tst_repotest.cpp0100777000000000000000000005301313761647206023464 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "../../installer/shared/verifyinstaller.h" #include #include #include #include #include #include class tst_repotest : public QObject { Q_OBJECT private: // TODO generateRepo() is almost direct copy from repogen.cpp. // Move the needed parts of repogen.cpp to a usable function for easier maintenance. void generateRepo(bool createSplitMetadata, bool createUnifiedMetadata, bool updateNewComponents) { QStringList filteredPackages; QInstallerTools::FilterType filterType = QInstallerTools::Exclude; QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages (m_repositoryDirectories, &filteredPackages, filterType); m_packages.append(precompressedPackages); QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(m_packagesDirectories, &filteredPackages, filterType); m_packages.append(preparedPackages); if (updateNewComponents) QInstallerTools::filterNewComponents(m_repositoryDir, m_packages); QHash pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(m_packages); foreach (const QInstallerTools::PackageInfo &package, m_packages) { const QFileInfo fi(m_repositoryDir, package.name); if (fi.exists()) removeDirectory(fi.absoluteFilePath()); } if (updateNewComponents) { //Verify that component B exists as that is not updated if (createSplitMetadata) { VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1" << "1.0.0meta.7z"); } else { VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1"); } } else { QDir dir(m_repositoryDir + "/B"); QVERIFY(!dir.exists()); } QStringList directories; directories.append(m_packagesDirectories); directories.append(m_repositoryDirectories); QStringList unite7zFiles; foreach (const QString &repositoryDirectory, m_repositoryDirectories) { QDirIterator it(repositoryDirectory, QStringList(QLatin1String("*_meta.7z")) , QDir::Files | QDir::CaseSensitive); while (it.hasNext()) { it.next(); unite7zFiles.append(it.fileInfo().absoluteFilePath()); } } QInstallerTools::copyComponentData(directories, m_repositoryDir, &m_packages); QInstallerTools::copyMetaData(m_tmpMetaDir, m_repositoryDir, m_packages, QLatin1String("{AnyApplication}"), QLatin1String("1.0.0"), unite7zFiles); QString existing7z = QInstallerTools::existingUniteMeta7z(m_repositoryDir); if (!existing7z.isEmpty()) existing7z = m_repositoryDir + QDir::separator() + existing7z; QInstallerTools::compressMetaDirectories(m_tmpMetaDir, existing7z, pathToVersionMapping, createSplitMetadata, createUnifiedMetadata); QDirIterator it(m_repositoryDir, QStringList(QLatin1String("Updates*.xml")) << QLatin1String("*_meta.7z"), QDir::Files | QDir::CaseSensitive); while (it.hasNext()) { it.next(); QFile::remove(it.fileInfo().absoluteFilePath()); } QInstaller::moveDirectoryContents(m_tmpMetaDir, m_repositoryDir); } void generateTempMetaDir() { if (!m_tmpMetaDir.isEmpty()) m_tempDirDeleter.releaseAndDelete(m_tmpMetaDir); QTemporaryDir tmp; tmp.setAutoRemove(false); m_tmpMetaDir = tmp.path(); m_tempDirDeleter.add(m_tmpMetaDir); } void clearData() { generateTempMetaDir(); m_packagesDirectories.clear(); m_repositoryDirectories.clear(); m_packages.clear(); } void initRepoUpdate() { clearData(); m_packagesDirectories << ":///packages_update"; } void initRepoUpdateFromRepository(const QString &repository) { clearData(); m_repositoryDirectories << repository; } void verifyUniteMetadata(const QString &scriptVersion) { QString fileContent = VerifyInstaller::fileContent(m_repositoryDir + QDir::separator() + "Updates.xml"); QRegularExpression re("(.*)<.MetadataName>"); QStringList matches = re.match(fileContent).capturedTexts(); QString existingUniteMeta7z = QInstallerTools::existingUniteMeta7z(m_repositoryDir); QCOMPARE(2, matches.count()); QCOMPARE(existingUniteMeta7z, matches.at(1)); QFile file(m_repositoryDir + QDir::separator() + matches.at(1)); QVERIFY(file.open(QIODevice::ReadOnly)); //We have script.qs for package A in the unite metadata QVector::const_iterator fileIt; const QVector files = Lib7z::listArchive(&file); for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) { if (fileIt->isDirectory) continue; QString fileName = "A/script%1.qs"; QCOMPARE(qPrintable(fileName.arg(scriptVersion)), fileIt->path); } VerifyInstaller::verifyFileExistence(m_repositoryDir, QStringList() << "Updates.xml" << matches.at(1)); VerifyInstaller::verifyFileContent(m_repositoryDir + QDir::separator() + "Updates.xml", "SHA1"); VerifyInstaller::verifyFileContent(m_repositoryDir + QDir::separator() + "Updates.xml", "MetadataName"); } void verifyComponentRepository(const QString &componentAVersion, bool hasComponentMeta) { const QString content = "%1content.7z"; const QString contentSha = "%1content.7z.sha1"; const QString meta = "%1meta.7z"; QStringList componentA; QStringList componentB; componentA << qPrintable(content.arg(componentAVersion)) << qPrintable(contentSha.arg(componentAVersion)); componentB << "1.0.0content.7z" << "1.0.0content.7z.sha1"; if (hasComponentMeta) { componentA << qPrintable(meta.arg(componentAVersion)); componentB << "1.0.0meta.7z"; } VerifyInstaller::verifyFileExistence(m_repositoryDir + "/A", componentA); VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", componentB); } void verifyComponentMetaUpdatesXml() { VerifyInstaller::verifyFileExistence(m_repositoryDir, QStringList() << "Updates.xml"); VerifyInstaller::verifyFileHasNoContent(m_repositoryDir + QDir::separator() + "Updates.xml", "MetadataName"); } void ignoreMessagesForComponentHash(const QStringList &components, bool update) { foreach (const QString component, components) { QString message = "Copying component data for \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); if (update) message = "Compressing files found in data directory: (\":/packages_update/%1/data/%1_update.txt\")"; else message = "Compressing files found in data directory: (\":/packages/%1/data/%1.txt\")"; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Hash is stored in *")); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Creating hash of archive *")); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Generated sha1 hash: *")); } } void ignoreMessagesForCopyRepository(const QString &component, const QString &version, const QString &repository) { QStringList contentFiles; contentFiles << "content.7z" << "content.7z.sha1"; QString message = "Copying component data for \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); foreach (const QString &fileName, contentFiles) { message = "Copying file from \":///%5/%1/%2%4\" to \"%3/%1/%2%4\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component).arg(version) .arg(m_repositoryDir).arg(fileName).arg(repository))); } } void ignoreMessageForCollectingRepository(const QString &repository) { const QString message = "Process repository \"%2\""; QTest::ignoreMessage(QtDebugMsg, "Collecting information about available repository packages..."); QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(repository))); QTest::ignoreMessage(QtDebugMsg, "Collecting information about available packages..."); QTest::ignoreMessage(QtDebugMsg, "No available packages found at the specified location."); QTest::ignoreMessage(QtDebugMsg, "- it provides the package \"A\" - \"2.0.0\""); } void ignoreMessagesForCopyMetadata(const QString &component, bool hasMeta, bool update) { QString message; if (update) message = "Copy meta data for package \"%1\" using \":///packages_update/%1/meta/package.xml\""; else message = "Copy meta data for package \"%1\" using \":///packages/%1/meta/package.xml\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("calculate size of directory *")); if (hasMeta) { if (update) message = "Copying associated \"script\" file \":///packages_update/%1/meta/script2.0.0.qs\""; else message = "Copying associated \"script\" file \":///packages/%1/meta/script1.0.0.qs\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); QTest::ignoreMessage(QtDebugMsg, "done."); } } void ignoreMessagesForComponentSha(const QStringList &components, bool clearOldChecksum) { foreach (const QString component, components) { const QString message = "Searching sha1sum node for \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component))); if (clearOldChecksum) QTest::ignoreMessage(QtDebugMsg, QRegularExpression("- clearing the old sha1sum *")); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("- writing the sha1sum *")); } } void ignoreMessagesForUniteMeta(bool update) { QTest::ignoreMessage(QtDebugMsg, "Writing sha1sum node."); if (update) QTest::ignoreMessage(QtDebugMsg, QRegularExpression("- clearing the old sha1sum *")); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("- writing the sha1sum")); QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Updating the metadata node with name *")); } void ignoreMessageForCollectingPackages(const QString &versionA, const QString &versionB) { QTest::ignoreMessage(QtDebugMsg, "Collecting information about available repository packages..."); QTest::ignoreMessage(QtDebugMsg, "Collecting information about available packages..."); QTest::ignoreMessage(QtDebugMsg, "Found subdirectory \"A\""); QString message = "- it provides the package \"A\" - \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(versionA))); QTest::ignoreMessage(QtDebugMsg, "Found subdirectory \"B\""); message = "- it provides the package \"B\" - \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(versionB))); } void ignoreMessageForCollectingPackagesFromRepository(const QString &versionA, const QString &versionB) { QString message = "- it provides the package \"B\" - \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(versionB))); message = "- it provides the package \"A\" - \"%1\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(versionA))); QTest::ignoreMessage(QtDebugMsg, "Collecting information about available packages..."); QTest::ignoreMessage(QtDebugMsg, "No available packages found at the specified location."); } void ignoreMessagesForUpdateComponents() { ignoreMessageForCollectingPackages("2.0.0", "1.0.0"); ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); ignoreMessagesForComponentHash(QStringList() << "A" << "B", true); ignoreMessagesForCopyMetadata("A", true, true); ignoreMessagesForCopyMetadata("B", false, true); } void ignoreMessageForUpdateComponent() { QString message = "Update component \"A\" in \"%1\" ."; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); message = "Update component \"C\" in \"%1\" ."; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); } private slots: void init() { ignoreMessageForCollectingPackages("1.0.0", "1.0.0"); m_repositoryDir = QInstallerTools::makePathAbsolute(QInstaller::generateTemporaryFileName()); m_tempDirDeleter.add(m_repositoryDir); generateTempMetaDir(); m_packagesDirectories << ":///packages"; ignoreMessagesForComponentHash(QStringList() << "A" << "B", false); ignoreMessagesForCopyMetadata("A", true, false); //Only A has metadata ignoreMessagesForCopyMetadata("B", false, false); } void initTestCase() { Lib7z::initSevenZ(); } void testWithComponentMeta() { ignoreMessagesForComponentSha(QStringList () << "A" << "B", false); generateRepo(true, false, false); verifyComponentRepository("1.0.0", true); verifyComponentMetaUpdatesXml(); } void testWithComponentAndUniteMeta() { ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); ignoreMessagesForUniteMeta(false); generateRepo(true, true, false); verifyComponentRepository("1.0.0", true); verifyUniteMetadata("1.0.0"); } void testWithUniteMeta() { ignoreMessagesForUniteMeta(false); generateRepo(false, true, false); verifyComponentRepository("1.0.0", false); verifyUniteMetadata("1.0.0"); } void testUpdateNewComponents() { // Create 'base' repository which will be updated ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); generateRepo(true, false, false); verifyComponentRepository("1.0.0", true); // Update the 'base' repository initRepoUpdate(); ignoreMessageForCollectingPackages("2.0.0", "1.0.0"); ignoreMessagesForComponentSha(QStringList() << "A", false); //Only A has update ignoreMessagesForComponentHash(QStringList() << "A", true); ignoreMessagesForCopyMetadata("A", true, true); const QString &message = "Update component \"A\" in \"%1\" ."; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); generateRepo(true, false, true); verifyComponentRepository("2.0.0", true); verifyComponentMetaUpdatesXml(); } void testUpdateComponents() { ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); generateRepo(true, false, false); verifyComponentRepository("1.0.0",true); initRepoUpdate(); ignoreMessagesForUpdateComponents(); generateRepo(true, false, false); verifyComponentRepository("2.0.0", true); verifyComponentMetaUpdatesXml(); } void testUpdateComponentsWithUniteMetadata() { ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); ignoreMessagesForUniteMeta(false); generateRepo(true, true, false); verifyComponentRepository("1.0.0", true); initRepoUpdate(); ignoreMessagesForUpdateComponents(); ignoreMessagesForUniteMeta(true); generateRepo(true, true, false); verifyComponentRepository("2.0.0", true); verifyUniteMetadata("2.0.0"); } void testUpdateComponentsWithOnlyUniteMetadata() { ignoreMessagesForUniteMeta(false); generateRepo(false, true, false); verifyComponentRepository("1.0.0", false); initRepoUpdate(); ignoreMessageForCollectingPackages("2.0.0", "1.0.0"); ignoreMessagesForComponentHash(QStringList() << "A" << "B", true); ignoreMessagesForCopyMetadata("A", true, true); ignoreMessagesForCopyMetadata("B", false, true); ignoreMessagesForUniteMeta(true); generateRepo(false, true, false); verifyComponentRepository("2.0.0", false); verifyUniteMetadata("2.0.0"); } void testUpdateComponentsFromRepository() { ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); generateRepo(true, false, false); verifyComponentRepository("1.0.0", true); initRepoUpdateFromRepository(":///repository_component"); ignoreMessageForCollectingRepository("repository_component"); QTest::ignoreMessage(QtDebugMsg, "- it provides the package \"B\" - \"1.0.0\""); ignoreMessagesForCopyRepository("B", "1.0.0", "repository_component"); ignoreMessagesForCopyRepository("A", "2.0.0", "repository_component"); ignoreMessagesForComponentSha(QStringList() << "A" << "B", true); generateRepo(true, false, false); verifyComponentRepository("2.0.0", true); verifyComponentMetaUpdatesXml(); } void testUpdateComponentsFromRepositoryWithUniteMetadata() { ignoreMessagesForComponentSha(QStringList() << "A" << "B", false); ignoreMessagesForUniteMeta(false); generateRepo(true, true, false); verifyComponentRepository("1.0.0", true); initRepoUpdateFromRepository(":///repository_componentAndUnite"); ignoreMessageForCollectingRepository("repository_componentAndUnite"); QTest::ignoreMessage(QtDebugMsg, "- it provides the package \"C\" - \"1.0.0\""); ignoreMessageForUpdateComponent(); ignoreMessagesForCopyRepository("A", "2.0.0", "repository_componentAndUnite"); ignoreMessagesForCopyRepository("C", "1.0.0", "repository_componentAndUnite"); ignoreMessagesForUniteMeta(true); ignoreMessagesForComponentSha(QStringList() << "A" << "C", true); generateRepo(true, true, true); verifyComponentRepository("2.0.0", true); VerifyInstaller::verifyFileExistence(m_repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1" << "1.0.0meta.7z"); verifyUniteMetadata("2.0.0"); } void testUpdateComponentsFromRepositoryWithOnlyUniteMetadata() { ignoreMessagesForUniteMeta(false); generateRepo(false, true, false); verifyComponentRepository("1.0.0", false); initRepoUpdateFromRepository(":///repository_unite"); ignoreMessageForCollectingRepository("repository_unite"); QTest::ignoreMessage(QtDebugMsg, "- it provides the package \"C\" - \"1.0.0\""); ignoreMessageForUpdateComponent(); ignoreMessagesForCopyRepository("A", "2.0.0", "repository_unite"); ignoreMessagesForCopyRepository("C", "1.0.0", "repository_unite"); ignoreMessagesForUniteMeta(true); generateRepo(false, true, true); verifyComponentRepository("2.0.0", false); VerifyInstaller::verifyFileExistence(m_repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1"); verifyUniteMetadata("2.0.0"); } void cleanup() { m_tempDirDeleter.releaseAndDeleteAll(); m_packagesDirectories.clear(); m_packages.clear(); m_repositoryDirectories.clear(); } private: QString m_tmpMetaDir; QString m_repositoryDir; QStringList m_packagesDirectories; QStringList m_repositoryDirectories; QInstallerTools::PackageInfoVector m_packages; TempDirDeleter m_tempDirDeleter; }; QTEST_MAIN(tst_repotest) #include "tst_repotest.moc" qt-installer-framework-4.0.1/tests/auto/tools/tools.pro0100777000000000000000000000005613761647206020235 0ustar00TEMPLATE = subdirs SUBDIRS += \ repotest qt-installer-framework-4.0.1/tests/downloadspeed/0040777000000000000000000000000013761647206017072 5ustar00qt-installer-framework-4.0.1/tests/downloadspeed/downloadspeed.pro0100777000000000000000000000030213761647206022437 0ustar00TEMPLATE = app INCLUDEPATH += . .. TARGET = downloadspeed include(../../installerfw.pri) QT -= gui QT += network CONFIG += console SOURCES += main.cpp macx:include(../../no_app_bundle.pri) qt-installer-framework-4.0.1/tests/downloadspeed/main.cpp0100777000000000000000000001311513761647206020523 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include // -- Receiver class Receiver : public QObject { Q_OBJECT public: Receiver() : QObject(), m_downloadFinished(false) {} ~Receiver() {} inline bool downloaded() { return m_downloadFinished; } public slots: void downloadStarted() { m_downloadFinished = false; } void downloadFinished() { m_downloadFinished = true; } void downloadAborted(const QString &error) { m_downloadFinished = true; qDebug() << "Error:" << error; } void downloadSpeed(qint64 speed) { qDebug() << "Download speed:" << QInstaller::humanReadableSize(speed) + QLatin1String("/sec"); } void downloadProgress(double progress) { qDebug() << "Progress:" << progress; } void estimatedDownloadTime(int time) { if (time <= 0) { qDebug() << "Unknown time remaining."; return; } const int d = time / 86400; const int h = (time / 3600) - (d * 24); const int m = (time / 60) - (d * 1440) - (h * 60); const int s = time % 60; QString days; if (d > 0) days = QString::number(d) + QLatin1String(d < 2 ? " day" : " days") + QLatin1String(", "); QString hours; if (h > 0) hours = QString::number(h) + QLatin1String(h < 2 ? " hour" : " hours") + QLatin1String(", "); QString minutes; if (m > 0) minutes = QString::number(m) + QLatin1String(m < 2 ? " minute" : " minutes"); QString seconds; if (s >= 0 && minutes.isEmpty()) seconds = QString::number(s) + QLatin1String(s < 2 ? " second" : " seconds"); qDebug() << days + hours + minutes + seconds + tr("remaining."); } void downloadStatus(const QString &status) { qDebug() << status; } void downloadProgress(qint64 bytesReceived, qint64 bytesToReceive) { qDebug() << "Bytes received:" << bytesReceived << ", Bytes to receive:" << bytesToReceive; } private: bool m_downloadFinished; }; // http://get.qt.nokia.com/qt/source/qt-mac-opensource-4.7.4.dmg // ftp://ftp.trolltech.com/qt/source/qt-mac-opensource-4.7.4.dmg class ProxyFactory : public KDUpdater::FileDownloaderProxyFactory { public: ProxyFactory() {} ProxyFactory *clone() const { return new ProxyFactory(); } QList queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) { return QNetworkProxyFactory::systemProxyForQuery(query); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); if (a.arguments().count() < 2) return EXIT_FAILURE; const QUrl url(a.arguments().value(1)); KDUpdater::FileDownloaderFactory::setFollowRedirects(true); qDebug() << url.toString(); KDUpdater::FileDownloader *loader = KDUpdater::FileDownloaderFactory::instance().create(url.scheme(), 0); if (loader) { loader->setUrl(url); loader->setProxyFactory(new ProxyFactory()); Receiver r; r.connect(loader, &KDUpdater::FileDownloader::downloadStarted, &r, &Receiver::downloadStarted); r.connect(loader, &KDUpdater::FileDownloader::downloadCanceled, &r, &Receiver::downloadFinished); r.connect(loader, &KDUpdater::FileDownloader::downloadCompleted, &r, &Receiver::downloadFinished); r.connect(loader, &KDUpdater::FileDownloader::downloadAborted, &r, &Receiver::downloadAborted); r.connect(loader, &KDUpdater::FileDownloader::downloadSpeed, &r, &Receiver::downloadSpeed); r.connect(loader, &KDUpdater::FileDownloader::downloadStatus, &r, &Receiver::downloadStatus); r.connect(loader, SIGNAL(downloadProgress(double)), &r, SLOT(downloadProgress(double))); r.connect(loader, &KDUpdater::FileDownloader::estimatedDownloadTime, &r, &Receiver::estimatedDownloadTime); r.connect(loader, SIGNAL(downloadProgress(qint64,qint64)), &r, SLOT(downloadProgress(qint64,qint64))); loader->download(); while (!r.downloaded()) QCoreApplication::processEvents(); delete loader; } return EXIT_SUCCESS; } #include "main.moc" qt-installer-framework-4.0.1/tests/README0100777000000000000000000000011513761647206015117 0ustar00These are files for the unfinished test framework of the installer framework.qt-installer-framework-4.0.1/tests/test-framework/0040777000000000000000000000000013761647206017214 5ustar00qt-installer-framework-4.0.1/tests/test-framework/checker/0040777000000000000000000000000013761647206020620 5ustar00qt-installer-framework-4.0.1/tests/test-framework/checker/run.py0100777000000000000000000000556413761647206022010 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import optparse, sys from testrunner import testrunner from xml.sax.saxutils import XMLGenerator from xml.sax.xmlreader import AttributesNSImpl class Writer: def __init__( self, out ): self._out = out self.gen = XMLGenerator( out, 'utf-8' ) self.gen.startDocument() self.gen.startElement( 'results', {} ) def addResult( self, name, status, errstr ): self.gen.startElement('result', { 'name':name, 'status':status } ) self.gen.characters( errstr ) self.gen.endElement('result' ) def addFailed( self, name, errstr ): self.addResult( name, "failed", errstr ) def addPassed( self, status, errstr ): self.addResult( name, "passed", errstr ) def finalize( self ): self.gen.endElement( 'results' ) self.gen.endDocument self._out.write( '\n' ) optionParser = optparse.OptionParser(usage="%prog [options] testcaseDir", version="%prog 0.1") optionParser.add_option("-p", "--omit-prefix", dest="prefix", help="for file checks, prefix relative paths with this prefix", metavar="PREFIX" ) optionParser.add_option("-o", "--output", dest="output", help="write results to file (instead of stdout)", metavar="OUTPUT" ) (options, args) = optionParser.parse_args() try: testdir = args[0] except IndexError: optionParser.print_usage( sys.stderr ) sys.exit( 1 ) out = sys.stdout if options.output != None: out = file( options.output, 'wb' ) writer = Writer( out ) try: runner = testrunner.TestRunner( testdir, options.prefix, writer ) runner.run() finally: writer.finalize()qt-installer-framework-4.0.1/tests/test-framework/checker/scripts/0040777000000000000000000000000013761647206022307 5ustar00qt-installer-framework-4.0.1/tests/test-framework/checker/scripts/generate-filelist.py0100777000000000000000000000507013761647206026266 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import optparse, os, sys from testrunner import files, testrunner class GenerateException( Exception ): def __init__( self, value ): self.value = value def __str__( self ): return repr( self.value ) def relpath( path, prefix ): if prefix != None: return os.path.relpath( path, prefix ) else: return path; out = sys.stdout def walker( prefix, current_dir, children ): for c in children: child = current_dir + os.sep + c if os.path.isdir( child ): continue fileObj = file( child, 'rb' ) md5 = files.md5sum( fileObj ) out.write( "{0}; {1}; {2}\n".format( relpath( child, prefix ), os.path.getsize( child ), md5 ) ) optionParser = optparse.OptionParser(usage="%prog [options] directory", version="%prog 0.1") optionParser.add_option("-p", "--omit-prefix", dest="prefix", help="make entries relative to this prefix", metavar="PREFIX" ) optionParser.add_option("-o", "--output", dest="output", help="save file list to file (instead of stdout)", metavar="OUTPUT" ) (options, args) = optionParser.parse_args() try: directory = args[0] except IndexError: raise GenerateException( "No directory given.") if options.output != None: out = file( options.output, 'wb' ) os.path.walk( directory, walker, options.prefix ) qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/0040777000000000000000000000000013761647206023031 5ustar00qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/files.py0100777000000000000000000000470313761647206024511 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# from testexception import TestException import fnmatch, hashlib, os def md5sum( fileObj ): md5 = hashlib.md5() while True: chunk = fileObj.read( 4096 ) if not chunk: break md5.update( chunk ) return md5.hexdigest() def locateFiles( rootPath, pattern ): for path, dirs, files in os.walk( os.path.abspath( rootPath ) ): for filename in fnmatch.filter( files, pattern ): yield os.path.join( path, filename ) def checkFileImpl( path, expectedSize=-1, expectedMd5=None ): #TODO: normalize path/convert to platform if not os.path.exists( path ): raise TestException( '{0}: file does not exist'.format( path ) ) size = os.path.getsize( path ) if expectedSize >= 0 and size != expectedSize: raise TestException( '{0}: unexpected size. Actual: {1} Expected: {2}'.format( path, size, expectedSize ) ) if ( expectedMd5 != None ): fileObj = file( path, 'rb' ) md5 = md5sum( fileObj ) fileObj.close() if md5 != expectedMd5: raise TestException( '{0}: md5sum mismatch. Actual: {1} Expected: {2}'.format( path, md5, expectedMd5 ) ) qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/logger.py0100777000000000000000000000000013761647206024650 0ustar00qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/registry.py0100777000000000000000000000411613761647206025255 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# from testexception import TestException import _winreg _registry = dict() _registry["HKEY_CLASSES_ROOT"] = _winreg.HKEY_CLASSES_ROOT _registry["HKEY_CURRENT_USER"] = _winreg.HKEY_CURRENT_USER _registry["HKEY_LOCAL_MACHINE"] = _winreg.HKEY_LOCAL_MACHINE _registry["HKEY_USERS"] = _winreg.HKEY_USERS _registry["HKEY_CURRENT_CONFIG"] = _winreg.HKEY_CURRENT_CONFIG def splitKey( key ): key, separator, subKey = key.partition( '\\' ) return _registry[key], subKey def checkKey( key, value, expectedData ): baseKey, subKey = splitKey( key ) keyHandle = _winreg.OpenKey( baseKey, subKey ) data, _ = _winreg.QueryValueEx( keyHandle, value ) if data != expectedData: raise TestException( '{0}: unexpected registry data. Actual: {1} Expected: {2}'.format( key, data, expectedData ) ) qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/testexception.py0100777000000000000000000000263713761647206026311 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# class TestException( Exception ): def __init__( self, value ): self.value = value def __str__( self ): return repr( self.value ) qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/testrunner.py0100777000000000000000000001064213761647206025617 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import files, os, string, platform from testexception import TestException if ( platform.system() == "Windows" ): import registry def makeAbsolutePath( path, relativeTo ): if os.path.isabs( path ) or relativeTo == None: return path else: return relativeTo + os.sep + path class TestRunner: def __init__( self, testDir, basedir, result ): self._testDir = testDir self._basedir = basedir self._result = result def checkFile( self, name, size=-1, expectedMd5=None ): try: files.checkFileImpl( name, size, expectedMd5 ) except TestException as e: self._result.addFailed( name, e.value ) def checkFileList( self, path ): lineNum = 0 haveError = False with open( path, 'r' ) as f: while True: line = f.readline() lineNum += 1 if not line: break line = string.strip( line ) if len( line ) == 0: continue segments = string.split( line, ';' ) if len( segments ) == 3: fp = makeAbsolutePath( segments[0], self._basedir ) try: fs = int( segments[1] ) except ValueError: fs = -1 #TODO handle error femd5 = segments[2] femd5 = string.strip( femd5 ) self.checkFile( fp, fs, femd5 ) else: self._result.addFailed( path + '_' + str( lineNum ), "Could not parse file list entry: " + line ) haveError = True if not haveError: self._result.addPassed( path, "" ) def checkRegistryList( self, path ): haveError = False lineNum = 0 with open( path, 'r' ) as f: while True: lineNum += 1 line = f.readline() if not line: break line = string.strip( line ) if len( line ) == 0: continue segments = string.split( line, ';' ) if len( segments ) == 3: key = segments[0].strip() value = segments[1].strip() expectedData = segments[2].strip() registry.checkKey( key, value, expectedData ) else: self._result.addFailed( path + '_' + str( lineNum ), "Could not parse registry list entry: " + line ) haveError = True if not haveError: self._result.addPassed( path, "" ) def run( self ): fileLists = files.locateFiles( self._testDir, "*.filelist" ) for i in fileLists: self.checkFileList( i ) if ( platform.system() == "Windows" ): registryLists = files.locateFiles( self._testDir, "*.registrylist" ) for i in registryLists: self.checkRegistryList( i ) # run all .py's in testdir # execute all filelists qt-installer-framework-4.0.1/tests/test-framework/checker/testrunner/__init__.py0100777000000000000000000000001213761647206025133 0ustar00# init.py qt-installer-framework-4.0.1/tests/test-framework/README0100777000000000000000000002561213761647206020102 0ustar00= Testing Framework = == Overview == The "testing framework" was developed to continuously run automated, non-interactive tests for the Nokia NDK installers on a set of test systems. It uses remote-controlled VMWare virtual machines (VMs) to execute the tests on. Both the actual controlling process and the post installation checks on the VMs are implemented in Python. Additionally, a set of test cases is created and configured. A test case consists of a) a QtScript script specifying the user input for non-interactive installation and b) post-installation checks to perform after installation. This way various user behaviour can be tested (e.g. different component selections) and whether installation succeeds and certain post-conditions are met (e.g. files end up in in specific locations). A test case can also contain additional steps to test updating and package management. For each compatible VM/Test case combination, the VM is reset to a predefined state, the installer is run using the QtScript script and the post-installation checks are performed. The test results are aggregated and submitted to a CDash dashboard. == Setup at Nokia == The VMs run on a VMWare server installation on bersrv16723. The VMWare server web frontend requires a IE (32-bit) plugin to get the guest system's shell. (Nokia internal: http://hegel.europe.nokia.com/binaries/vmware_client_plugin/vmware-vmrc-win32-x86.exe). As far as I know there is no way atm to get it running on other platforms. Web frontend URL: http://bersrv16723:8222/ui (redirect to https://bersrv16723:8333/ui, but in some cases it is not working without this redirection) The testing framework itself is configured and runs on the controller VM. It it supposed to be accessed via ssh. Controller VM: 172.25.167.111 [get a fixed IP/hostname]. Attach/Start a screen session: screen -D -R Start the test runner: cd $HOME/test/installerfw/installer/test-framework vmware/run.py -s 2010-05-17 site/host-config.cfg # insert your date here For more explanations on run.py see below. The CDash location presenting the build results is http://172.25.167.111/CDash (the controller VM). The project used is NDKInstallerTests (TODO: actually use that one). The current setup with working examples of configuration files is in $TODO:/home/kdab/test/ (TODO: commit to repo) == run.py == The central python script executing test runs is vmware/run.py. Usage:run.py [options] host-config Options: -s | --only-since YYYY-MM-DD when checking /path/to/vmware/run.py -s 2010-05-14 host-config.cfg run.py does the following: It collects the information about configured VMs and test cases from the host configuration file. It then checks the configured installer sources for new installers, and sequentially executes the test for each new installer on all VM/test case combinations that apply to the installer (there can be specific tests cases for certain platforms only). For each installer x VM x test case run, the result is added to CDash. Once all installers on the FTP server (or the ones matching the --only-since restriction) were tested, the process goes to sleep and checks every hour for new installers. run.py only executes all test runs sequentially, with a single test at a time. If this turns out to be too much of a bottleneck, multiple run.py instances in different working directories and with different host-config files could be run in parallel (e.g. each one monitoring a different path on the FTP server). == Virtual Machine Setup == Any VMWare virtual machine can be used for testing, if some preparations are made: * Add a virtual CD/DVD drive (for VMWare Tools; Choose a random ISO file when asked) * Install VMWare Tools (important: The test run might just hang and do nothing if the VM has no VMWare tools installed) * Install Python 2.6 * Create a snapshot of the VM in the state that should be used as initial state for each test run [TODO: relate to UI] * Create a configuration file for the VM. The configuration file provides information to run.py about the VM, such as the user/password combination to use to login, the location of the python installation or the path in the VM to use for temporary files, such as the downloaded installer and result output files. (See Virtual Machine Configuration File Options for details) * To enable the VM, add the path to the VM config file to the host config file (See Host Configuration File Options). == Virtual Machine Configuration File Options == Example: TODO === Section: General === snapshot: identifier (Default: "base") The baseline snapshot to revert to when start a test run. This option is only relevant VMWare Fusion and Workstation (as Server/ESX only support a single unnamed snapshot) username: string password: string The username and password to authenticate with inside the VM. vmx: string The path to the VM's vmx file. Relative paths are understood relative to the configuration file. For remote setups, the name as listed by the TODO tool must be used. TODO: explain how to list snapshots. tempDir: guest path Path inside the VM to use for temporary data (installer, checker copy, test script...). It must be writable by the user. os: windows|linux|mac The OS running inside the VM python: guest path (Default: "python") The path to the installed python executable inside the VM. == Test Cases == === Configuration File === General/platforms: string list comma-separated list of platforms the testcase should be run on. Valid platform names are "windows", "linux", "mac" General/targetDirectory: guest path The target directory to use for the post-installation checks (see below). Note that the actual installation directory is specified in the installscript and must be kept in sync. See the section on post-installation checks for details. General/maintenanceToolLocation The path to the maintenance tool (updater/package manager) after installation. Required for multi-step tests ==== Steps ==== Each test case can consist of of n steps and must have at least one. The first step is the actual installation and will execute the installer, the following steps will start the maintenance tool. Step section must be consecutive and start at 0: Step0, Step1, Step2 etc. StepN/installscript: path The path to the QtScript used for non-interactive execution of the installer/maintenance tool. relative paths are interpreted relative to the configuration file. StepN/checkerTestDir: string The path to a directory containing a set of tests to perform after a successful installer/maintenance tool run. relative paths are interpreted relative to the configuration file. Example: [General] platforms=windows,linux targetDirectory=c:\testinstall maintenanceToolLocation=c:\testInstall\TestUninstaller.exe [Step0] installscript=testscript.qs checkerTestDir=checker === Install scripts === see non-interactive installation section in installerbuilder/installerbuilder.dox TODO: merge === Post-installation checks === The framework can execute post-installation tests on the VM to check if the installation is in the expected state. The python code executing those checks is called "checker". Each testcase can contain a "checker test directory" to contain checks to be executed. The framework copies both the checker code and the test case into the VM, executes the checks and reports the results. Currently, the following checks are supported: ==== Files ==== It can be checked for files to exist in the installation and their file size and md5sum. To add such a check, place a file with extension .filelist in the test directory. The format of a .filelist file is: filename; file size; md5sum file size and md5sum are optional and can be empty. Example: components.xml; 2050; 6813144fd09f7d39764702e5adb91679wrong index.html; 46; fd40a94472ea1d13d93221c5ce62c321 include\QtGui\qwidget.h; 108; 67dc776dd5aa66741dab6a2eeec4ac3c Relative paths are understood relative to the targetDirectory. Such files can be generated using the script test-framework/checker/scripts/generate-filelist.py ==== Windows Registry ==== Similar to .filelist, .registrylist files can be used to check for the existance and content of windows registry keys. The format is ; ; HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion; SM_GamesName; Games ==== Arbitrary python code ==== Not yet done but easy to implement: Run tests from python code from .py files in the test dir. == Host Configuration File Options == === Section: General === vmrun: path (Default: "vmrun") vmrun specifies the location of the vmrun executable to use. vmrun is part of VMRun Workstation, Fusion, Server and ESX. If the framework not on the same system as the VMWare server, you must sure that the executable installed supports the VMWare edition used (At the time of writing, this is VMWare Server). checkerInstallation: path The path to the "checker" python files which will be copied to each VM and executed to perform postinstallation checks. Example: checkerInstallation=/home/kdab/test/installerfw/installer/test-framework/checker testcase{0..n}: path The configuration files of the test cases to use. Relative paths are understood relative to the configuration file. vm{0..n}: path n configuration files of the virtual machines to use. Relative paths are understood relative to the configuration file. gui: True|False (default: False TODO: ensure) Whether VMWare/vmrun should bring up . Only relevant when used with VMWare Workstation or Fusion. createErrorSnapshots True|False (default: False TODO: ensure) Specifies if the framework should create error snapshots if the installation or post-installation checks fail. This is currently only supported for VMWare Workstation and Fusion (the server editions unfortunately only support a single snapshot per VM, which is reserved for the baseline. === Section: Host === This section is optional. It is used if the VMWare host is different from the local machine (VMWare Server or esx). type: string The VMWare edition to talk against, one of "server" and "esx" location: URL The URL of the server/esx installation to talk to Example: location=https://172.25.167.23:8333/sdk username: string The user used to login on the VMWare server password: string The user used to login on the VMWare server === Section: CDash === The framework is able to generate test reports in CDash format. If this section does not exist, the results are just printed to stdout. host: hostname The host of the CDash installation location: The path to the CDash installation on host project The CDash project to report the test results to. Example: [Host] host=localhost location=/CDash project=NokiaSDKInstallerTest === Section: Source{0..n} === Each source provides installers to be tested, for a specific platform. Currently, FTP is assumed and the only supported protocol. The Example: [Source0] host=hegel path=/projects/ndk/installers/windows platform=windows [Source1] host=hegel path=/projects/ndk/installers/linux platform=linux qt-installer-framework-4.0.1/tests/test-framework/site/0040777000000000000000000000000013761647206020160 5ustar00qt-installer-framework-4.0.1/tests/test-framework/site/host-config.cfg0100777000000000000000000000137013761647206023062 0ustar00[General] vmrun=vmrun checkerInstallation=/home/kdab/test/installerfw/installer/test-framework/checker testcase0=TestCases/testcase1/testcase1.cfg testcase1=TestCases/testcase-linux64/testcase-linux64.cfg vm0=VMConfigs/WindowsXp32Bit.cfg vm1=VMConfigs/WindowsXp64Bit.cfg vm2=VMConfigs/WindowsVista32Bit.cfg vm3=VMConfigs/LinuxUbuntu9.1064Bit.cfg gui=False createErrorSnapshots=False [Host] type=server location=https://172.25.167.23:8333/sdk username=kdab password=kdab [CDash] host=localhost location=/CDash project=test1 [Source0] host=hegel path=/projects/ndk/installers/windows platform=windows [Source1] host=hegel path=/projects/ndk/installers/linux/x32 platform=linux32 [Source2] host=hegel path=/projects/ndk/installers/linux/x64 platform=linux64 qt-installer-framework-4.0.1/tests/test-framework/site/listVMs.sh0100777000000000000000000000250513761647206022117 0ustar00############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# vmrun -u kdab -p kdab -T server -h https://172.25.167.23:8333/sdk listRegisteredVM qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/0040777000000000000000000000000013761647206022056 5ustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/0040777000000000000000000000000013761647206025200 5ustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/checker/0040777000000000000000000000000013761647206026604 5ustar00././@LongLink0100777000000000000000000000015713761647206010121 Lustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/checker/testinstall.filelistqt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/checker/testinsta0100777000000000000000000000044613761647206030551 0ustar00components.xml; 2050; 6813144fd09f7d39764702e5adb91679wrong index.html; 46; fd40a94472ea1d13d93221c5ce62c321 uninstall.exe; 13598393; 44945e7d3507d294b5e9e096ac3269b1 include\QtCore\qobject.h; 108; 9e50d789f32d1651e16b6ae55699eb71 include\QtGui\qwidget.h; 108; 67dc776dd5aa66741dab6a2eeec4ac3c ././@LongLink0100777000000000000000000000014713761647206010120 Lustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/testcase-linux64.cfgqt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/testcase-linux64.0100777000000000000000000000016613761647206030326 0ustar00[General] installscript=testscript.qs platforms=linux64 targetDirectory=/home/kdab/testinstall checkerTestDir=checker qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase-linux64/testscript.qs0100777000000000000000000000614313761647206027755 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Controller() { installer.autoRejectMessageBoxes installer.setMessageBoxAutomaticAnswer( "overwriteTargetDirectory", QMessageBox.Yes ) } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.LicenseAgreementPageCallback = function() { var page = gui.pageWidgetByObjectName( "LicenseAgreementPage" ) page.acceptLicenseRB.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.TargetDirectoryPageCallback = function() { var page = gui.pageWidgetByObjectName( "TargetDirectoryPage" ) page.targetDirectoryLE.setText( "/home/kdab/testinstall" ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.deselectComponent( "com.nokia.ndk.tools.maemo.usbdriver" ) gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicQtGuiPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicQtGuiPage" ) page.checkBoxLib.setChecked( false ) gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicErrorPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicErrorPage" ) page.checkBoxMakeSure.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.StartMenuDirectoryPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.PerformInstallationPageCallback = function() { var page = gui.pageWidgetByObjectName( "PerformInstallationPage" ) page.details.button.click } Controller.prototype.FinishedPageCallback = function() { gui.clickButton( buttons.FinishButton ) } qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/0040777000000000000000000000000013761647206023752 5ustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/checker/0040777000000000000000000000000013761647206025356 5ustar00././@LongLink0100777000000000000000000000015013761647206010112 Lustar00qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/checker/testinstall.filelistqt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/checker/testinstall.file0100777000000000000000000000044613761647206030571 0ustar00components.xml; 2050; 6813144fd09f7d39764702e5adb91679wrong index.html; 46; fd40a94472ea1d13d93221c5ce62c321 uninstall.exe; 13598393; 44945e7d3507d294b5e9e096ac3269b1 include\QtCore\qobject.h; 108; 9e50d789f32d1651e16b6ae55699eb71 include\QtGui\qwidget.h; 108; 67dc776dd5aa66741dab6a2eeec4ac3c qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/testcase1.cfg0100777000000000000000000000016413761647206026330 0ustar00[General] installscript=testscript.qs platforms=windows,linux targetDirectory=c:\testinstall checkerTestDir=checker qt-installer-framework-4.0.1/tests/test-framework/site/TestCases/testcase1/testscript.qs0100777000000000000000000000613413761647206026527 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Controller() { installer.autoRejectMessageBoxes installer.setMessageBoxAutomaticAnswer( "overwriteTargetDirectory", QMessageBox.Yes ) } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.LicenseAgreementPageCallback = function() { var page = gui.pageWidgetByObjectName( "LicenseAgreementPage" ) page.acceptLicenseRB.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.TargetDirectoryPageCallback = function() { var page = gui.pageWidgetByObjectName( "TargetDirectoryPage" ) page.targetDirectoryLE.setText( "c:\\testinstall" ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.deselectComponent( "com.nokia.ndk.tools.maemo.usbdriver" ) gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicQtGuiPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicQtGuiPage" ) page.checkBoxLib.setChecked( false ) gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicErrorPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicErrorPage" ) page.checkBoxMakeSure.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.StartMenuDirectoryPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.PerformInstallationPageCallback = function() { var page = gui.pageWidgetByObjectName( "PerformInstallationPage" ) page.details.button.click } Controller.prototype.FinishedPageCallback = function() { gui.clickButton( buttons.FinishButton ) } qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/0040777000000000000000000000000013761647206022013 5ustar00qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/LinuxUbuntu9.1064Bit.cfg0100777000000000000000000000025613761647206026122 0ustar00[General] snapshot=base username=kdab password=kdab vmx=[standard] Linux Ubuntu 9.10 64 Bit/Linux Ubuntu 9.10 64 Bit.vmx tempDir=/home/kdab os=linux64 python=/usr/bin/python qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/WindowsVista32Bit.cfg0100777000000000000000000000027113761647206025741 0ustar00[General] snapshot=base username=kdab password=kdab vmx=[standard] Windows Vista 32 Bit/Windows Vista 32 Bit.vmx tempDir=c:\Users\kdab\Desktop os=windows python=c:\Python26\python.exe qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/WindowsVista64Bit.cfg0100777000000000000000000000031113761647206025741 0ustar00[General] snapshot=base username=kdab password=kdab vmx=[standard] Windows XP 32 Bit/Windows XP 32 Bit.vmx tempDir=c:\Dokumente und Einstellungen\kdab\Desktop os=windows python=c:\Python26\python.exe qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/WindowsXp32Bit.cfg0100777000000000000000000000031113761647206025235 0ustar00[General] snapshot=base username=kdab password=kdab vmx=[standard] Windows XP 32 Bit/Windows XP 32 Bit.vmx tempDir=c:\Dokumente und Einstellungen\kdab\Desktop os=windows python=c:\Python26\python.exe qt-installer-framework-4.0.1/tests/test-framework/site/VMConfigs/WindowsXp64Bit.cfg0100777000000000000000000000030413761647206025244 0ustar00[General] snapshot=base username=kdab password=kdab vmx=[standard] Windows XP 64 Bit/Windows XP 64 Bit.vmx tempDir=c:\Documents and Settings\kdab\Desktop os=windows python=c:\Python26\python.exe qt-installer-framework-4.0.1/tests/test-framework/tests/0040777000000000000000000000000013761647206020356 5ustar00qt-installer-framework-4.0.1/tests/test-framework/tests/simpletest.py0100777000000000000000000000272613761647206023130 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import sys from testrunner import testrunner class Result: def addError( self, errstr ): print errstr result = Result() runner = testrunner.TestRunner( sys.argv[1], result ) runner.run() qt-installer-framework-4.0.1/tests/test-framework/tests/testfiles/0040777000000000000000000000000013761647206022360 5ustar00qt-installer-framework-4.0.1/tests/test-framework/tests/testfiles/test.filelist0100777000000000000000000000021113761647206025066 0ustar00/home/frank/.ssh/id_dsa.pub; 1113; 1fddf250c364370b7936c1b7256c7eda /home/frank/.ssh/id_dsa.pub; 1113; 1fddf250c364370b7936c1b7256c7edb qt-installer-framework-4.0.1/tests/test-framework/vmware/0040777000000000000000000000000013761647206020515 5ustar00qt-installer-framework-4.0.1/tests/test-framework/vmware/cdashreporter.py0100777000000000000000000001706013761647206023740 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import datetime, socket, os, sys, traceback, time, tempfile, httplib, urllib from xml.sax.saxutils import XMLGenerator from xml.sax.xmlreader import AttributesNSImpl import result, utils from result import exitStatusAsString from xmlutils import startElement, endElement, writeElement checkerResultAsString = { result.CheckerResult.Passed:u"passed", result.CheckerResult.Failed:u"failed", result.CheckerResult.NotRun:u"notRun" } def formatDate( date ): return date.strftime( '%Y%m%d-%H%M' ) def writeExecutionResult( gen, name, r ): if r == None or r.hasError(): stat = "failed" else: stat = "passed" startElement( gen, None, "Test", { u"Status":stat } ) writeElement( gen, None, "Name", name ) writeElement( gen, None, "FullName", name ) startElement( gen, None, "NamedMeasurement", { u"type":u"text/string", u"name":u"Exit Code"} ) if r: msg = "(Unexpected)" ec = r.exitCode if ec == 0: msg = "(Success)" elif ec == 1: msg = "(Failed)" elif ec == 2: msg = "(Canceled)" writeElement( gen, None, "Value", "Exit status: {0}; Installer exit code: {1} {2}".format( exitStatusAsString( r.exitStatus ), str( r.exitCode ), msg ) ) else: writeElement( gen, None, "Value", "Could not determine installation result." ) endElement( gen, None, "NamedMeasurement" ) if r: startElement( gen, None, "NamedMeasurement", { u"type":u"numeric/double", u"name":u"Execution Time"} ) writeElement( gen, None, "Value", str( r.executionTime ) ) endElement( gen, None, "NamedMeasurement" ) endElement( gen, None, "Test" ) def writeInternalError( gen, errorstr, num ): startElement( gen, None, "Test", { u"Status":u"failed"} ) name = "InternalError{0}".format( num ) writeElement( gen, None, "Name", name ) writeElement( gen, None, "FullName", name ) startElement( gen, None, "NamedMeasurement", { u"type":u"text/string", u"name":u"Completion Status"} ) writeElement( gen, None, "Value", errorstr ) endElement( gen, None, "NamedMeasurement" ) endElement( gen, None, "Test" ) def writeTest( gen, test ): startElement( gen, None, "Test", { u"Status":checkerResultAsString[test.result]} ) writeElement( gen, None, "Name", test.name ) writeElement( gen, None, "FullName", test.name ) startElement( gen, None, "NamedMeasurement", { u"type":u"text/string", u"name":u"Completion Status"} ) writeElement( gen, None, "Value", test.errorString ) endElement( gen, None, "NamedMeasurement" ) endElement( gen, None, "Test" ) class CDashReporter: def __init__( self, host, location, project ): self._host = host self._location = location self._project = project def reportException( self ): sys.stderr.write( traceback.format_exc( 15 ) + '\n' ) #TODO def reportResult( self, result ): self._buildStamp = '{0}-Nightly'.format( datetime.datetime.now().strftime( '%Y%m%d-%H%M' ), utils.randomString( 4 ) ) try: #generate XML self.genXml( self.genTestXml, result ) #generate Tests.xml #submitFile('Tests.xml') except: raise def genTestXml( self, gen, result ): name = "{0} on {1}".format( result._installer.sourceFilename, result._vm.name() ) startElement( gen, None, "Site", { u"BuildStamp":self._buildStamp, u"Name":name, u"Generator":u"VMTester 0.1" } ) startElement( gen, None, "Testing" ) writeElement( gen, None, "StartDateTime", formatDate( result._testStart ) ) startElement( gen, None, "TestList" ) internal = result._internalErrors for i in range( 0, len( internal ) - 1 ): writeElement( gen, None, "Test", "InternalError{0}".format( i ) ) for stepNum in range( len( result._stepResults ) ): step = result._stepResults[stepNum] writeElement( gen, None, "Test", "installer-run{0}".format( stepNum ) ) for i in step.checkerResults: writeElement( gen, None, "Test", i.name ) endElement( gen, None, "TestList" ) for i in range( 0, len( internal ) - 1 ): writeInternalError( gen, internal[i], i ) for stepNum in range( len( result._stepResults ) ): step = result._stepResults[stepNum] writeExecutionResult( gen, "installer-run{0}".format( stepNum ), step.executionResult ) for i in step.checkerResults: writeTest( gen, i ) endElement( gen, None, "Testing" ) endElement( gen, None, "Site" ) def genXml( self, fillFunc, result ): f = None try: f = tempfile.NamedTemporaryFile( delete=False ) gen = XMLGenerator( f, 'utf-8' ) gen.startDocument() fillFunc( gen, result ) gen.endDocument() f.close() self.submitFile( f.name ) finally: if f: os.unlink( f.name ) def submitFile( self, path ): f = file( path ) params = urllib.urlencode( {'project': self._project} ) conn = None try: try: conn = httplib.HTTPConnection( self._host ) conn.request( "POST", "{0}/submit.php?project={1}".format( self._location, self._project ), f ) response = conn.getresponse() print response.status, response.reason #TODO check result finally: if conn: conn.close() except: #TODO: if submitting to cdash fails, try to notify the admin (mail?) raise if __name__ == "__main__": r = result.Result() r.testStarted() r.addCheckerResult( result.CheckerResult( "test1", result.CheckerResult.Passed, "" ) ) r.addCheckerResult( result.CheckerResult( "test2", result.CheckerResult.Failed, "Something went wrong, dude!" ) ) time.sleep( 1 ) r.testFinished() cr = CDashReporter( "http://localhost", "/CDash", "test1" ) cr.reportResult( r ) qt-installer-framework-4.0.1/tests/test-framework/vmware/control.py0100777000000000000000000002534513761647206022560 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import ConfigParser, datetime, os, string, sys, time, platform import testcase, utils, result, virtualmachine from virtualmachine import VMException from xml.sax import make_parser from xml.sax.handler import ContentHandler class ControlException( Exception ): def __init__( self, value ): self.value = value def __str__( self ): return repr( self.value ) class Handler( ContentHandler ): def __init__( self, res ): self._res = res self._inResult = False self._buf = "" def startElement( self, name, attrs ): self._inResult = False if name == "result": self._inResult = True self._name = attrs['name'] self._status = attrs['status'] def endElement( self, name ): if name == 'result': trimmed = string.strip( self._buf ) if self._status == "passed": stat = result.CheckerResult.Passed else: stat = result.CheckerResult.Failed self._res.addCheckerResult( result.CheckerResult( self._name, stat, trimmed ) ) self._inResult = False self._buf = "" def characters( self, ch ): if self._inResult: self._buf += ch class Control: def __init__( self, vmrun, checkerDir, source, reporter ): self._vmrun = vmrun self._checkerDir = checkerDir self._vms = [] self._testcases = [] self._source = source self._reporter = reporter self._guiEnabled = True self._createErrorSnapshots = False self._hostType = "" self._hostLocation = "" self._hostUsername = "" self._hostPassword = "" def setGuiEnabled( self, usegui ): self._guiEnabled = usegui for i in self._vms: i.setGuiEnabled( usegui ) def setCreateErrorSnapshots( self, createSnapshots ): self._createErrorSnapshots = createSnapshots def setRemoteHost( self, type, loc, user, pw ): self._hostType = type self._hostLocation = loc self._hostUsername = user self._hostPassword = pw for vm in self._vms: if not vm.isRemote(): vm.setRemoteHost( self._hostType, self._hostLocation, self._hostUsername, self._hostPassword ) def addVM( self, cfgpath ): config = ConfigParser.SafeConfigParser() config.read( cfgpath ) vm = virtualmachine.fromVMRunAndPath( self._vmrun, cfgpath ) vm.setGuiEnabled( self._guiEnabled ) if len( self._hostType ) > 0 and not vm.isRemote(): vm.setRemoteHost( self._hostType, self._hostLocation, self._hostUsername, self._hostPassword ) self._vms.append( vm ) #TODO catch/transform exceptions def addTestCase( self, path ): self._testcases.append( testcase.TestCase( path ) ) def run( self ): while True: try: inst = self._source.nextInstaller() if inst == None: print( "** Installer source returned None, aborting" ) return if inst.error: raise ControlException( inst.error ) print( "** New installer: {0}".format( inst.path ) ) self.testInstaller( inst, inst.platform ) except KeyboardInterrupt: raise except: self._reporter.reportException() def testInstaller( self, inst, platform ): for vm in self._vms: if vm.ostype() != platform: continue for case in self._testcases: if not case.supportsPlatform( platform ): continue res = result.Result() try: try: res.setInstaller( inst ) res.setTestCase( case ) res.setVirtualMachine( vm ) res.testStarted() self.run_test( inst.path, vm, case, res ) res.testFinished() inst.markAsTested() except KeyboardInterrupt: raise except: res.addException() finally: self._reporter.reportResult( res ) def convertCheckerResults( self, filename, res ): parser = make_parser() parser.setContentHandler( Handler( res ) ) f = file( filename, 'rb' ) parser.parse( f ) def run_test( self, installerPath, vm, testcase, res ): steps = testcase.steps() if len( steps ) == 0: raise ControlException( "No steps found for testcase {0}".format( testcase.name() ) ) revertStatus, _ = vm.revertToSnapshot() if revertStatus != 0: raise VMException( "Failed to revert to snapshot '{0}'".format( vm.snapshot() ) ) time.sleep( 5 ) # Trying to avoid a possible race between restore and start vm.start() try: try: vm.checkPythonInstalled() wrapperpath = vm.copyToTemp( utils.execution_path( 'guest.py' ) ) for stepNum in range( len( steps ) ): needSnapshot = False step = steps[stepNum] if stepNum == 0: executableguestpath = vm.copyToTemp( installerPath ) else: executableguestpath = testcase.maintenanceToolLocation() outputFileName = 'output{0}.log'.format( stepNum ) outputpath = vm.mkTempPath( outputFileName ) scriptguestpath = vm.copyToTemp( step.installscript() ) timeout = step.timeout() checkerguestpath = vm.copyToTemp( step.checkerTestDir(), "checkerTestDir{0}".format( stepNum ) ) if len( string.strip( step.checkerTestDir() ) ) > 0 else None vm.command( 'Execute installer', "runProgramInGuest", "'{0}' '{1}' '{2}' '{3}' '{4}' --script '{5}'".format( vm.python(), wrapperpath, outputpath, timeout, executableguestpath, scriptguestpath ) ) vm.copyFromTemp( outputFileName, outputFileName ) r = ConfigParser.SafeConfigParser() r.read( outputFileName ) try: s = r.get( 'Result', 'ExitCode' ) exitCode = int( s ) except ValueError: res.addInternalError( "Could not parse integer exit code from '{0}'".format( r.get( 'Result', 'ExitCode' ) ) ) exitCode = -1 try: s = r.get( 'Result', 'ExecutionTime' ) executionTime = float( s ) except ValueError: res.addInternalError( "Could not parse float execution time from '{0}'".format( r.get( 'Result', 'ExecutionTime' ) ) ) executionTime = 0.0 exitStatus = result.exitStatusFromString( r.get( 'Result', 'ExitStatus' ) ) instR = result.ExecutionResult( exitCode, exitStatus, executionTime ) if instR.hasError(): needSnapshot = True checkerResults = [] if checkerguestpath and not instR.hasError(): if ( platform.system() == "Darwin" ): # Have to sleep to work around VMware Fusion bug time.sleep( 30 ) run_py = vm.copyToTemp( self._checkerDir ) + vm.pathSep() + "run.py" if ( platform.system() == "Darwin" ): # Have to sleep to work around VMware Fusion bug time.sleep( 30 ) checkeroutputFileName = 'checker-output{0}.xml'.format( stepNum ) checkeroutput = vm.mkTempPath( checkeroutputFileName ) vm.command( 'Execute checker tests', "runProgramInGuest", "'{0}' '{1}' '{2}' -o '{3}' -p '{4}'".format( vm.python(), run_py, checkerguestpath, checkeroutput, testcase.targetDirectory() ) ) vm.copyFromTemp( checkeroutputFileName, checkeroutputFileName ) self.convertCheckerResults( localcheckeroutput, checkerResults ) if res.hasCheckerErrors(): needSnapshot = True if self._createErrorSnapshots and needSnapshot: snapshot = 'error-{0}-{1}'.format( datetime.datetime.now().strftime( '%Y%m%d_%H%M%S' ), utils.randomString( 4 ) ) status, _ = vm.createSnapshot( snapshot ) if status == 0: res.setErrorSnapshot( snapshot ) else: res.addInternalError( 'Could not create error snapshot "{0}"'.format( snapshot ) ) res.addStepResult( result.StepResult( instR, checkerResults ) ) #TODO handle timeouts? finally: vm.kill() except e: print( e ) res.addInternalError( str( e ) ) qt-installer-framework-4.0.1/tests/test-framework/vmware/ftpsource.py0100777000000000000000000001210313761647206023076 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# from ftplib import FTP import datetime, functools, os, time, tempfile from source import Installer import utils def _timestampFromFilename( platform, fn ): # windows: assumed format is YYYY_mm_dd_HH_MM as prefix # linux: assumed format is YYYY-mm-dd as suffix if platform.startswith( 'windows' ): format = '%Y_%m_%d_%H_%M' length = len( 'YYYY_mm_dd_HH_MM' ) return datetime.datetime.strptime( fn[0:length], format ) else: format = '%Y-%m-%d' length = len( 'YYYY-mm-dd' ) return datetime.datetime.strptime( fn[-length:], format ) def timestampFromFilename( platform, fn ): try: return _timestampFromFilename( platform, fn ) except ValueError: return None def filesNewerThan( files, dt ): if dt: return filter( lambda (x,y): y >= dt, files ) else: return files #internal to FtpSource class Location: def __init__( self, host, path, platform ): self.host = host self.path = path self.platform = platform self.testedFiles = [] def ls( self ): ftp = FTP( self.host ) ftp.login() try: return map( utils.basename, ftp.nlst( self.path ) ) finally: ftp.close() def filesSortedByTimestamp( self ): files = self.ls() withTS = [( i, timestampFromFilename( self.platform, i ) ) for i in files] filtered = filter( lambda (x,y): y != None, withTS ) filtered.sort( key=lambda (x,y): y ) return filtered def untestedFilesSortedByTimestamp( self ): l = self.filesSortedByTimestamp() return filter( lambda ( x, y ): not self.isTested( x ), l ) def markAsTested( self, filename ): self.testedFiles.append( filename ) def isTested( self, filename ): return filename in self.testedFiles def description( self ): return "host={0} path={1} platform={2}".format( self.host, self.path, self.platform ) def download( self, fn, target ): ftp = FTP( self.host ) ftp.login() try: ftp.retrbinary( 'RETR {0}/{1}'.format( self.path, fn ), target.write ) finally: ftp.close() class FtpSource: def __init__( self, delay=60*60, tempdir='/tmp' ): self._locations = [] self._delay = delay self._tempdir = tempdir self._startDate = None def setStartDate( self, date ): self._startDate = date def addLocation( self, host, path, platform ): self._locations.append( Location( host, path, platform ) ) def nextInstaller( self ): while True: for i in self._locations: print( "** Checking FTP location: " + i.description() ) files = i.untestedFilesSortedByTimestamp() if self._startDate != None: files = filesNewerThan( files, self._startDate ) if len( files ) == 0: continue; fn, ts = files[0] print( "** Downloading new installer: {0}...".format( fn ) ) tmp = tempfile.NamedTemporaryFile( dir=self._tempdir, prefix=fn ) i.download( fn, tmp ) print( "** Download completed. ({0})".format( tmp.name ) ) i.lastTested = ts inst = Installer( tmp.name, i.platform, i, ts, tmp ) inst.sourceFilename = fn return inst print( "** No installers found. Going to sleep for {0} seconds...".format( self._delay ) ) time.sleep( self._delay ) if __name__ == "__main__": src = FtpSource() src.addLocation( "hegel", "/projects/ndk/installers/windows", "windows" ) while True: inst = src.nextInstaller() print inst inst.markAsTested() qt-installer-framework-4.0.1/tests/test-framework/vmware/guest.py0100777000000000000000000001322513761647206022221 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # -*- coding: utf-8 -*- import sys, subprocess, ConfigParser, platform, os # begin Autobuild/helpers/runcommand.py import os import re import time import sys import signal from subprocess import Popen from threading import Thread from subprocess import PIPE import subprocess import platform def DebugN( l, m ): pass def windowskill( pid ): """ replace os.kill on Windows, where it is not available""" Cmd = 'taskkill /PID ' + str( int( pid ) ) + ' /T /F' if os.system( Cmd ) == 0: DebugN( 4, 'windowskill: process ' + str( pid ) + ' killed.' ) def kill( pid, signal ): if 'Windows' in platform.platform(): windowskill( pid ) else: os.kill( pid, signal ) class CommandRunner( Thread ): def __init__ ( self, Cmd ): Thread.__init__( self ) self.__started = None self.mCmd = Cmd self.mOutput = () self.mPid = -1 self.mReturnCode = -1 self.mError = () self.__combinedOutput = False def setCombinedOutput(self, combine): if combine: # make sure combine is usable as a boolean self.__combinedOutput = True else: self.__combinedOutput = False def getCombineOutput(self): return self.__combinedOutput def run( self ): DebugN( 4, 'RunCommand: ' + str( self.mCmd ) ) stderrValue = subprocess.PIPE if self.__combinedOutput: stderrValue = subprocess.STDOUT self.__started = True #nokia-sdk: changed to shell=False, as shell=True requires manual quoting of args p = Popen ( self.mCmd, shell = False, stdout=subprocess.PIPE, stderr=stderrValue ) self.mPid = p.pid self.mOutput, self.mError = p.communicate() self.mReturnCode = p.returncode DebugN( 4, 'ReturnCode of RunCommand: ' + str( p.returncode ) ) def started(self): return self.__started def output( self ): return self.mOutput, self.mError def terminate( self ): # FIXME logic? if self.mPid != -1: kill( self.mPid, signal.SIGTERM ) if self.mPid == True: self.join( 5 ) kill( self.mPid, signal.SIGKILL ) self.mPid = -1 def RunCommand( Cmd, TimeOutSeconds=-1, CombineOutput = False ): timeoutString = ' without a timeout' if TimeOutSeconds > 0: timeoutString = ' with timeout of ' + str( TimeOutSeconds ) combinedOutputString = ' and separate output for stdout and stderr' if CombineOutput: combinedOutputString = ' and combined stdout and stderr output' DebugN ( 3, 'RunCommand: executing ' + str( Cmd ) + timeoutString + combinedOutputString ) runner = CommandRunner ( Cmd ) runner.setCombinedOutput( CombineOutput ) runner.start() # poor man's mutex: while not runner.started(): time.sleep( 0.1 ) # if "CYGWIN" in platform.platform() or 'Windows' in platform.platform(): # time.sleep( 1 ) if TimeOutSeconds == -1: runner.join() else: runner.join( TimeOutSeconds ) if runner.isAlive(): runner.terminate() # if "CYGWIN" in platform.platform() or 'Windows' in platform.platform(): # time.sleep(1) runner.join( 5 ) DebugN( 3, 'RunCommand: command timed out, returncode is ' + str( runner.mReturnCode ) ) return ( runner.mReturnCode, runner.output(), True ) else: DebugN( 3, 'RunCommand: command completed, returncode is ' + str( runner.mReturnCode ) ) return ( runner.mReturnCode, runner.output(), False ) # end Autobuild/helpers/runcommand.py def printUsage(): print( "Usage: {0} [*]".format( sys.argv[0] ) ) if len( sys.argv ) < 4: printUsage() sys.exit( 1 ) output = sys.argv[1] timeout = int( sys.argv[2] ) cmd = sys.argv[3:] start = time.clock() exitCode, pout, timedOut = RunCommand( cmd, timeout ) end = time.clock() if timedOut: exitStatus = 'Timeout' else: exitStatus = 'Normal' #TODO: detect crash config = ConfigParser.SafeConfigParser() config.add_section( 'Result' ) config.set( 'Result', 'ExitCode', str( exitCode ) ) config.set( 'Result', 'ExitStatus', exitStatus ) config.set( 'Result', 'Filename', cmd[0] ) config.set( 'Result', 'Arguments', " ".join( cmd[1:] ) ) config.set( 'Result', 'Timeout', str( timeout ) ) config.set( 'Result', 'ExecutionTime', str( end - start ) ) config.set( 'Result', 'Stdout', pout[0] ) config.set( 'Result', 'Stderr', pout[1] ) config.add_section( 'Platform' ) config.set( 'Platform', 'system', platform.system() ) config.set( 'Platform', 'release', platform.release() ) config.set( 'Platform', 'version', platform.version() ) config.set( 'Platform', 'machine', platform.machine() ) with open( output, 'w' ) as configFile: config.write(configFile ) sys.exit( exitCode ) qt-installer-framework-4.0.1/tests/test-framework/vmware/guestconfig.py0100777000000000000000000000336213761647206023410 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import os, ConfigParser, tempfile, platform config = ConfigParser.SafeConfigParser() config.add_section('Guest') config.set('Guest', 'temp_dir', str(tempfile.gettempdir())) config.set('Guest', 'path_sep', os.sep) config.set('Guest', 'system', platform.system()) config.set('Guest', 'release', platform.release()) config.set('Guest', 'version', platform.version()) config.set('Guest', 'machine', platform.machine()) with open('example.cfg', 'wb') as configFile: config.write(configFile) qt-installer-framework-4.0.1/tests/test-framework/vmware/reporter.py0100777000000000000000000001175713761647206022744 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import datetime, socket, sys, traceback from xml.sax.saxutils import XMLGenerator from xml.sax.xmlreader import AttributesNSImpl import result from result import exitStatusAsString from xmlutils import startElement, endElement, writeElement class Reporter: def __init__( self ): pass def reportException( self ): sys.stderr.write( traceback.format_exc( 15 ) + '\n' ) def reportResult( self, result ): try: self.toXml( result, sys.stdout ) finally: sys.stdout.flush() def toXml( self, result, out ): atom = "http://www.w3.org/2005/Atom" tf = "http://sdk.nokia.com/test-framework/ns/1.0" gen = XMLGenerator( out, 'utf-8' ) gen.startDocument() gen.startPrefixMapping( 'atom', atom) gen.startPrefixMapping( 'tf', tf ) startElement( gen, atom, 'entry' ) writeElement( gen, atom, 'title', result.constructTitle() ) writeElement( gen, atom, 'updated', datetime.datetime.now().isoformat() ) writeElement( gen, tf, 'errorSummary', exitStatusAsString( result.status() ) ) writeElement( gen, tf, 'host', socket.gethostname() ) if result._testStart != None: writeElement( gen, tf, 'testStart', result._testStart.isoformat() ) else: result._internalErrors.append( "Result generator: no start timestamp found." ) if result._testEnd != None: writeElement( gen, tf, 'testEnd', result._testEnd.isoformat() ) else: result._internalErrors.append( "Result generator: no end timestamp found." ) startElement( gen, tf, 'installer' ) writeElement( gen, tf, 'sourceUrl', result._installerSourceLocation ) writeElement( gen, tf, 'platform', result._installerTargetPlatform ) #TODO revision endElement( gen, tf, 'installer' ) if result._testcase != None: startElement( gen, tf, 'testCase' ) writeElement( gen, tf, 'name', result._testcase.name() ) writeElement( gen, tf, 'path', result._testcase.path() ) writeElement( gen, tf, 'installScript', result._testcase.installscript() ) endElement( gen, tf, 'testCase' ) else: result._internalErrors.append( "Result generator: No test case given." ) if result._installationResult != None: startElement( gen, tf, 'installationResult' ) writeElement( gen, tf, 'exitCode', str( result._installationResult.exitCode ) ) writeElement( gen, tf, 'exitStatus', exitStatusAsString( result._installationResult.exitStatus ) ) endElement( gen, tf, 'installationResult' ) else: result._internalErrors.append( "Result generator: No installation result given." ) startElement( gen, tf, 'checkerResult' ) for err in result._checkerErrors: writeElement( gen, tf, 'error', err ) endElement( gen, tf, 'checkerResult' ) startElement( gen, tf, 'virtualMachine' ) writeElement( gen, tf, 'path', result._vm.vmxPath() ) writeElement( gen, tf, 'platform', result._vm.ostype() ) writeElement( gen, tf, 'snapshot', result._vm.snapshot() ) endElement( gen, tf, 'virtualMachine' ) startElement( gen, tf, 'internalErrors' ) for i in result._internalErrors: writeElement( gen, tf, 'internalError', str( i ) ) endElement( gen, tf, 'internalErrors' ) if result._errorSnapshot != None: writeElement( gen, tf, 'errorSnapshot', result._errorSnapshot ) endElement( gen, atom, 'entry' ) gen.endDocument() qt-installer-framework-4.0.1/tests/test-framework/vmware/result.py0100777000000000000000000001373313761647206022414 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import control, testcase, datetime, source, tempfile, traceback, utils from source import Installer class ExecutionResult: #return codes: Success = 0 InstallationFailed = 1 InstallationCanceled = 2 #exit status: Normal = 0 Crash = 1 Timeout = 2 def __init__( self, exitCode, exitStatus, executionTime ): self.exitCode = exitCode self.exitStatus = exitStatus self.executionTime = executionTime def hasError( self ): return self.exitCode != 0 or self.exitStatus != ExecutionResult.Normal class CheckerResult: Passed = 0 Failed = 1 NotRun = 2 def hasError( list ): #the following would more efficient with something find_if-like (stopping if test with error is found) return len( [x for i in list if i.hasError() ] ) > 0 def __init__( self, name, result, errorString ): self.name = utils.randomString( 3 ) + '_' + name self.result = result self.errorString = errorString def hasError( self ): return self.result != CheckerResult.Passed class StepResult: def __init__( self, executionResult, checkerResults ): self.executionResult = executionResult self.checkerResults = checkerResults def hasCheckerErrors( self ): return CheckerResult.hasError( self.checkerResults ) def exitStatusFromString( s ): if s == 'Crash': return ExecutionResult.Crash if s == 'Timeout': return ExecutionResult.Timeout if s == 'Normal': return ExecutionResult.Normal raise control.ControlException( "Unknown exit status string: {0}".format( s ) ) #there is probably a cooler way with introspection and stuff: def exitStatusAsString( status ): if status == ExecutionResult.Crash: return 'Crash' if status == ExecutionResult.Normal: return 'Normal' if status == ExecutionResult.Timeout: return 'Timeout' raise control.ControlException( "Unknown exit status: {0}".format( status ) ) class Result: NoError=0 # Everything ok InstallerError=1 #Installer failed, or post-conditions not met InternalError=2 #Internal test framework error def __init__( self ): self._internalErrors = [] self._stepResults = [] self._installer = None self._testStart = None self._testEnd = None self._testcase = None self._vm = None self._errorSnapshot = None self._revision = "revision-todo" def setInstaller( self, installer ): self._installer = installer def testStarted( self ): self._testStart = datetime.datetime.now() def testFinished( self ): self._testEnd = datetime.datetime.now() def setTestCase( self, testcase ): self._testcase = testcase def setErrorSnapshot( self, name ): self._errorSnapshot = name def setVirtualMachine( self, vm ): self._vm = vm def addInternalError( self, errstr ): self._internalErrors.append( errstr ) def hasInternalErrors( self ): return len( self._internalErrors ) > 0 def addException( self ): s = 'Unexpected exception: {0}'.format( traceback.format_exc( 15 ) ) self._internalErrors.append( s ) def hasCheckerErrors( self ): for step in self._stepResults: if CheckerResult.hasError( step.checkerResults ): return True return False def addStepResult( self, result ): self._stepResults.append( result ) def status( self ): if len( self._internalErrors ) > 0: return Result.InternalError if len( self._stepResults ) == 0: return Result.InternalError for step in self._stepResults: if step.executionResult.exitCode != ExecutionResult.Success or step.exitStatus != ExecutionResult.Normal: return Result.InstallerError if step.hasCheckerErrors(): return Result.InstallerError #TODO: check test results return Result.NoError def statusAsNiceString( self ): s = self.status() if s == Result.InternalError: return "Internal framework errors" if s == Result.InstallerError: return "Installation error" return "OK" def constructTitle( self ): smiley = ":-)" if self.status() == Result.NoError else ":-(" return "{0}: {1} on {2} testing {3} - {4} {5}".format( self._revision, utils.basename( self._installerSourceLocation ), self._vm.name(), self._testcase.name(), self.statusAsNiceString(), smiley ) qt-installer-framework-4.0.1/tests/test-framework/vmware/run-test.py0100777000000000000000000001355113761647206022655 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import sys, os, ConfigParser, optparse, time, virtualmachine, utils # TODO: - Look in sensible locations for python in the guest VM # - Try and work-around VMware Fusion needing to be closed def check_option( option, optionName ): if option: return print("** Could not find a value for {0}".format(optionName) ) print("** Please specify it on the commandline or configuration file.") print optionParser.print_help(); sys.exit(-1) def die(message): print "** " + str(message) sys.exit(1); # # Parse options # optionParser = optparse.OptionParser(usage="%prog [options] vmx-file", version="%prog 0.9") optionParser.add_option("-u", "--username", dest="username", help="username for VM", metavar="USERNAME" ) optionParser.add_option("-p", "--password", dest="password", help="password for VM", metavar="PASSWORD" ) optionParser.add_option("-S", "--script", dest="script", help="script for VM", metavar="SCRIPT" ) optionParser.add_option("-s", "--snapshot", dest="snapshot", help="snapshot for VM", metavar="SNAPSHOT" ) optionParser.add_option("-P", "--python", dest="python", help="python location in VM", metavar="PYTHON" ) optionParser.add_option("-v", "--vmrun", dest="vmrun", help="vmrun command for VM", metavar="VMRUN") optionParser.add_option("-c", "--config", dest="config", help="configuration file for VM", metavar="CONFIG") optionParser.add_option("-i", "--installer", dest="installer", help="installer executable to command inside the VM", metavar="INSTALLER") optionParser.add_option("-e", "--installscript", dest="installscript", help="QtScript script to use for non-interactive installation", metavar="INSTALLSCRIPT") (options, args) = optionParser.parse_args() try: options.vmx = args[0] except IndexError: options.vmx = None options.ostype = None options.guestTempDir = None config = ConfigParser.SafeConfigParser() if options.config: print("** Reading config: " + options.config ) config.read( options.config ) else: print("** No config given") options.username = utils.get_config_option( config, options.username, "username", "nokia" ) options.password = utils.get_config_option( config, options.password, "password", "nokia" ) options.script = utils.get_config_option( config, options.script, "script", "guest.py" ) options.python = utils.get_config_option( config, options.python, "python", "c:/python26/python.exe" ) options.snapshot = utils.get_config_option( config, options.snapshot, "snapshot", "base" ) options.vmrun = utils.get_config_option( config, options.vmrun, "vmrun" ) options.vmx = utils.get_config_option( config, options.vmx, "vmx" ) options.guestTempDir = utils.get_config_option( config, options.guestTempDir, "tempDir", "c:\\windows\\temp" ) options.ostype = utils.get_config_option( config, options.ostype, "os", "windows" ) check_option( options.vmx, "vmx-file" ) # Search the PATH and the a few extra locations for 'vmrun' if not options.vmrun: options.vmrun = utils.findVMRun() check_option( options.vmrun, "VMRUN" ) check_option( options.installer, "INSTALLER" ) check_option( options.installscript, "INSTALLSCRIPT" ) # # VM actions # vm = virtualmachine.VirtualMachine( options.vmrun, options.vmx, options.username, options.password, options.guestTempDir, options.ostype ) snapshotExists = vm.snapshotExists( options.snapshot ) if not snapshotExists: die("Could not find '{0}' snapshot, please create it in the VM.".format( options.snapshot ) ) revertStatus, _ = vm.revertToSnapshot( options.snapshot ) if revertStatus != 0: die("Failed to revert to snapshot") time.sleep( 5 ) # Trying to avoid a possible race between restore and start vm.start() try: pythonStatus, _ = vm.command("Checking for guest installed Python", "fileExistsInGuest", options.python) if pythonStatus != 0: raise virtualmachine.VMException("Please install Python in the VM from http://www.python.org/download/") wrapperpath = vm.copyToTemp( 'guest.py' ) installerpath = vm.copyToTemp( options.installer ) scriptpath = vm.copyToTemp( options.installscript ) outputpath = vm.mkTempPath( 'output.log' ) vm.command( 'Execute installer', "runProgramInGuest", "-interactive -activeWindow '{0}' '{1}' '{2}' '{3}' --script '{4}'".format( options.python, wrapperpath, outputpath, installerpath, scriptpath ) ) vm.copyFromTemp( 'output.log', 'output.log' ) result = ConfigParser.SafeConfigParser() result.read( 'output.log' ) print( "Installer exit code: " + result.get( 'Result', 'ExitCode' ) ) #TODO parse output and do something with it except virtualmachine.VMException as exception: die( exception ) finally: vm.kill() qt-installer-framework-4.0.1/tests/test-framework/vmware/run.py0100777000000000000000000001335413761647206021701 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # -*- coding: utf-8 -*- import ConfigParser, datetime, optparse, os, sys from functools import partial import cdashreporter, control, ftpsource, source, reporter, utils def die( msg ): sys.stderr( msg + '\n' ) sys.exit( 1 ) optionParser = optparse.OptionParser(usage="%prog [options] configfile installer0 [installer1 ...]", version="%prog 0.1") optionParser.add_option("-r", "--vmrun", dest="vmrun", help="vmrun executable to use", metavar="VMRUN" ) optionParser.add_option("-s", "--only-since", dest="since", help="test only installers newer than timestamp (YYYY-MM-DD or YYYY-MM-DD-hh-mm)", metavar="SINCE" ) optionParser.add_option("-c", "--checkerInstallation", dest="checkerInstallation", help="checker installation to use for post-installation checks", metavar="CHECKERINSTALLATION" ) (options, args) = optionParser.parse_args() try: configpath = utils.makeAbsolutePath( args[0], os.getcwd() ) except IndexError: optionParser.print_usage( sys.stderr ) sys.exit( 1 ) config = ConfigParser.SafeConfigParser() config.read( configpath ) #make an unary functor to create absolute paths abspath = partial( utils.makeAbsolutePath, relativeTo=os.path.dirname( configpath ) ) vmrun = utils.get_config_option( config, options.vmrun, "vmrun", utils.findVMRun() ) useGui = utils.get_config_option( config, None, "gui", "true" ).lower() == "true" createErrorSnapshots = utils.get_config_option( config, None, "createErrorSnapshots", "true" ).lower() == "true" hostType = utils.get_config_option( config, None, "type", "", "Host" ) hostLocation = utils.get_config_option( config, None, "location", "", "Host" ) hostUsername = utils.get_config_option( config, None, "username", "", "Host" ) hostPassword = utils.get_config_option( config, None, "password", "", "Host" ) cdashHost = utils.get_config_option( config, None, "host", "", "CDash" ) cdashLocation = utils.get_config_option( config, None, "location", "", "CDash" ) cdashProject = utils.get_config_option( config, None, "project", "", "CDash" ) if vmrun == None: die( "Could not find vmrun executable. Please specify it in the config file (vmrun=...) or via the --vmrun option" ) checkerInstallation = utils.get_config_option( config, options.checkerInstallation, "checkerInstallation" ) if checkerInstallation == None: die( "Could not find checker installation. Please specify it in the config file (checkerInstallation=...) or via the --checkerInstallation option" ) #apply functor to list to get absolute paths: testcases = map( abspath, utils.get_enumerated_config_option( config, 'testcase' ) ) if len( testcases ) == 0: die( "No testcases specified. Please specify at least one test case in the configuration" ) vms = map( abspath, utils.get_enumerated_config_option( config, 'vm' ) ) if len( vms ) == 0: die( "No VMs specified. Please specify at least one VM in the configuration" ) installers = args[1:] if len( installers ) > 0: source = source.Source() for i in installers: source.addDummy( 5, i ) else: source = ftpsource.FtpSource() if options.since: try: sdt = datetime.datetime.strptime( options.since, '%Y-%m-%d' ) except ValueError: sdt = datetime.datetime.strptime( options.since, '%Y-%m-%d-%H-%M' ) source.setStartDate( sdt ) found = True nextsec = 0 while found: sec = "Source{0}".format( nextsec ) nextsec += 1 try: host = config.get( sec, "host" ) path = config.get( sec, "path" ) platform = config.get( sec, "platform" ) print( "** Add FTP location {0}:{1} ({2})".format( host, path, platform ) ) source.addLocation( host, path, platform ) except ConfigParser.NoSectionError: found = False cdashHost = utils.get_config_option( config, None, "host", "", "CDash" ) cdashLocation = utils.get_config_option( config, None, "location", "", "CDash" ) cdashProject = utils.get_config_option( config, None, "project", "", "CDash" ) if len( cdashHost ) > 0: reporter = cdashreporter.CDashReporter( cdashHost, cdashLocation, cdashProject ) else: reporter = reporter.Reporter() control = control.Control( vmrun, checkerInstallation, source, reporter ) control.setGuiEnabled( useGui ) control.setCreateErrorSnapshots( createErrorSnapshots ) if len( hostType ) > 0: control.setRemoteHost( hostType, hostLocation, hostUsername, hostPassword ) for i in vms: control.addVM( i ) for i in testcases: control.addTestCase( i ) control.run() qt-installer-framework-4.0.1/tests/test-framework/vmware/source.py0100777000000000000000000000453313761647206022374 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import os, time class Installer: def __init__( self, path, platform, location, timestamp=None, tempfile=None ): self.path = path self.platform = platform self.error = None self.timestamp = timestamp self.tempfile = tempfile self.sourceLocation = location def markAsTested( self ): self.sourceLocation.markAsTested( self.sourceFilename ) class Source: def __init__( self ): self._dummies = [] def nextInstaller( self ): if len( self._dummies ) == 0: return None delay, path = self._dummies.pop() time.sleep( delay ) if os.path.exists( path ): inst = Installer( path, "linux", None ) inst.sourceFilename = path return inst else: inst = Installer( None, None ) #simulating download errors inst.error = "Installer '{0}' does not exist".format( path ) return inst def addDummy( self, delay, path ): self._dummies.insert( 0, ( delay, path ) ) qt-installer-framework-4.0.1/tests/test-framework/vmware/testcase.py0100777000000000000000000000722713761647206022712 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import ConfigParser, os, utils class Step: def __init__( self, installscript, checkerTestDir, timeout ): self._installscript = installscript self._checkerTestDir = checkerTestDir self._timeout = timeout def installscript( self ): return self._installscript def checkerTestDir( self ): return self._checkerTestDir def timeout( self ): return self._timeout class TestCase: def __init__( self, path ): self._steps = [] config = ConfigParser.SafeConfigParser() config.read( path ) self._path = path self._platforms = [] found = True stepNum = 0 while found: sec = "Step{0}".format( stepNum ) if not config.has_section( sec ): found = False continue stepNum += 1 installscript = utils.makeAbsolutePath( utils.get_config_option( config, None, "installscript", None, sec ), os.path.dirname( path ) ) checkerTestDir = utils.get_config_option( config, None, "checkerTestDir", None, sec ) checkerTestDir = utils.makeAbsolutePath( checkerTestDir, os.path.dirname( path ) ) if checkerTestDir else "" timeout = int( utils.get_config_option( config, None, "timeout", 60 * 60, sec ) ) self._steps.append( Step( installscript, checkerTestDir, timeout ) ) self._name = utils.get_config_option( config, None, "name", utils.basename( path ) ) self._targetDirectory = utils.get_config_option( config, None, "targetDirectory", "" ) self._maintenanceToolLocation = utils.get_config_option( config, None, "maintenanceToolLocation", "" ) platforms = utils.get_config_option( config, None, "platforms" ) if platforms != None: self._platforms = platforms.split( ',' ) def supportsPlatform( self, platform ): return platform in self._platforms def installerTimeout( self ): return self._installerTimeout def platforms( self ): return self._platforms def name( self ): return self._name def targetDirectory( self ): return self._targetDirectory def steps( self ): return self._steps def path( self ): return self._path def maintenanceToolLocation( self ): return self._maintenanceToolLocation qt-installer-framework-4.0.1/tests/test-framework/vmware/utils.py0100777000000000000000000000626613761647206022241 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import ConfigParser, inspect, os, string, sys from random import Random def findVMRun(): searchDirectories = os.environ['PATH'].split(os.pathsep) searchDirectories.append("/Library/Application Support/VMware Fusion") for directory in searchDirectories: possibleFile = os.path.join(directory, 'vmrun') if os.path.isfile(possibleFile): return possibleFile return None def basename( path ): if path.endswith( os.path.sep ): return os.path.basename( path[0,-1] ) else: return os.path.basename( path ) def makeAbsolutePath( path, relativeTo ): if os.path.isabs( path ) or relativeTo == None: return path else: return relativeTo + os.sep + path def execution_path( filename ): return os.path.join( os.path.dirname( inspect.getfile( sys._getframe( 1 ) ) ), filename ) def unixPathSep( s ): return s.replace( '\\', '/' ) def get_config_option( config, initial, option, default=None, section="General" ): # If there's already a valid option from the commandline, # override the value from the configuration file. if initial != None: print( "** Overridden {0}={1}".format( option, initial ) ) return initial try: tmp = config.get( section, option ) print( "** Read config value {0}={1}".format( option, tmp ) ) return tmp except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): print( "** Using default value {0}={1}".format( option, default ) ) return default def get_enumerated_config_option( config, option ): res = [] i = 0 while True: key = option + str( i ) val = get_config_option( config, None, key ) if val == None: print res return res res.append( val ) i += 1 def randomString( length ): return ''.join( Random().sample( string.letters + string.digits, length ) ) qt-installer-framework-4.0.1/tests/test-framework/vmware/virtualmachine.py0100777000000000000000000001764313761647206024115 0ustar00# -*- coding: utf-8 -*- #!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import commands, ConfigParser, os, string, utils, platform class VMException(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class VirtualMachine: def __init__( self, vmrun, vmx, username, password, tempDir, ostype ): self._vmrun = vmrun self._vmx = vmx self._username = username self._password = password self._tempDir = tempDir self._ostype = ostype self._useGui = True self._name = "no name" self._hostType = "" self._hostLocation = None self._hostUsername = None self._hostPassword = None def setGuiEnabled( self, usegui ): self._useGui = usegui def name( self ): return self._name def isRemote( self ): return len( self._hostType ) > 0; def setRemoteHost( self, type, loc, user, pw ): self._hostType = type self._hostLocation = loc self._hostUsername = user self._hostPassword = pw def command( self, message, command, parameters=None ): if len( self._hostType ) > 0: remote = "-T {0} -h '{1}' -u {2} -p {3}".format( self._hostType, self._hostLocation, self._hostUsername, self._hostPassword ) else: remote = "" vmcommand = "'{0}' {1} -gu {2} -gp {3} {4} '{5}' ".format( self._vmrun, remote, self._username, self._password, command, self._vmx ) if parameters: vmcommand += parameters print "** " + message status, output = commands.getstatusoutput(vmcommand) if status != 0: print "* Return code: {0}".format(status) print "* Output:" print output print return status, output def copyFileToGuest( self, source, target ): #TODO convert paths to guest system? status, _ = self.command( 'Copying {0} to {1}'.format( source, target ), 'copyFileFromHostToGuest', "'{0}' '{1}'".format( source, target ) ) if status != 0: raise VMException( "Could not copy from host to guest: source {0} target {1}".format( source, target ) ) def copyFileFromGuest( self, source, target ): #TODO convert paths to guest system? status, _ = self.command( 'Copying {0} to {1}'.format( source, target ), 'copyFileFromGuestToHost', "'{0}' '{1}'".format( source, target ) ) if status != 0: raise VMException( "Could not copy from guest to host: source {0} target {1}".format( source, target ) ) def ostype( self ): return self._ostype def vmxPath( self ): return self._vmx def mkTempPath( self, filename ): return self._tempDir + self.pathSep() + utils.basename( filename ) def pathSep( self ): if self._ostype == "windows": return "\\" else: return "/" def copyToTemp( self, source, targetN=None ): if source == None or len( string.strip( source ) ) == 0: return None if targetN == None: targetN = source target = self.mkTempPath( targetN ) self.copyFileToGuest( source, target ) return target def copyFromTemp( self, filename, target ): source = self.mkTempPath( filename ) self.copyFileFromGuest( source, target ) return target def start( self ): arg = "gui" if self._useGui else "nogui" self.command("Starting VM ({0})".format( arg ), "start", arg ) def kill( self ): self.command("Stopping VM", "stop", "hard" ) def isRunning( self ): _, vmList = self.command("Checking running VMs", "list") _, _, vmFilename = self._vmx.rpartition( os.sep ) return vmList.find(vmFilename) is not -1 def snapshotExists( self, snapshot ): _, output = self.command("Checking snapshots", "listSnapshots") snapshotList = output.split("\n") # Remove first entry which contains number of snapshots snapshotList.pop(0) return snapshotList.count( snapshot ) > 0 def checkPythonInstalled( self ): pp = utils.unixPathSep( self._python ) pythonStatus, _ = self.command("Checking for guest installed Python", "fileExistsInGuest", pp ) print pythonStatus if pythonStatus != 0: raise VMException("Could not find python in {0}: Please specify the path/install Python in the VM from http://www.python.org/download/".format( pp ) ) else: print("Python found ({0})".format( pp ) ) def python( self ): return self._python def snapshot( self ): return self._snapshot def revertToSnapshot( self, snapshot=None ): if snapshot != None: snap = snapshot else: snap = self._snapshot # VMware Fusion needs to be closed before you can restore snapshots so kill it if ( platform.system() == "Darwin" ): commands.getstatusoutput( "ps x|grep 'VMware Fusion'|cut -d ' ' -f1|xargs kill" ) return self.command("Reverting to '{0}' snapshot".format( snap ), "revertToSnapshot", snap ) def createSnapshot( self, name ): return self.command("Creating error snapshot '{0}'".format( name ), "snapshot", name ) def fromVMRunAndPath( vmrun, path ): config = ConfigParser.SafeConfigParser() config.read( path ) hostType = utils.get_config_option( config, None, "type", "", "Host" ) hostLocation = utils.get_config_option( config, None, "location", "", "Host" ) hostUsername = utils.get_config_option( config, None, "username", "", "Host" ) hostPassword = utils.get_config_option( config, None, "password", "", "Host" ) vmxVal = utils.get_config_option( config, None, "vmx" ) if not len( hostType ) == 0: vmx = utils.makeAbsolutePath( vmxVal, os.path.dirname( path ) ) else: vmx = vmxVal username = utils.get_config_option( config, None, "username", "nokia" ) password = utils.get_config_option( config, None, "password", "nokia" ) tempDir = utils.get_config_option( config, None, "tempDir", "c:\\windows\\temp" ) ostype = utils.get_config_option( config, None, "os", "windows" ) vm = VirtualMachine( vmrun, vmx, username, password, tempDir, ostype ) vm._name = utils.get_config_option( config, None, "name", utils.basename( path ) ) vm._snapshot = utils.get_config_option( config, None, "snapshot", "base" ) vm._python = utils.get_config_option( config, None, "python", "c:/python26/python.exe" ) vm._hostType = hostType vm._hostLocation = hostLocation vm._hostUsername = hostUsername vm._hostPassword = hostPassword return vm qt-installer-framework-4.0.1/tests/test-framework/vmware/xmlutils.py0100777000000000000000000000323413761647206022752 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# def startElement( gen, ns, name, attrsb={} ): attrs = {} for i in attrsb: attrs[(None, i)] = attrsb[i] gen.startElementNS( ( ns, name ), name, attrs ) def endElement( gen, ns, name ): gen.endElementNS( ( ns, name ), name ) def writeElement( gen, ns, name, text, attrs={} ): startElement( gen, ns, name, attrs ) gen.characters( text ) endElement( gen, ns, name ) qt-installer-framework-4.0.1/tests/test-installer/0040777000000000000000000000000013761647206017214 5ustar00qt-installer-framework-4.0.1/tests/test-installer/auto_installations_script.qs0100777000000000000000000000714113761647206025064 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var installerTargetDirectory="c:\\auto-test-installation"; function Controller() { installer.autoRejectMessageBoxes; installer.setMessageBoxAutomaticAnswer( "OverwriteTargetDirectory", QMessageBox.Yes); //maybe we want something like this //installer.execute("D:\\cleanup_directory.bat", new Array(installerTargetDirectory)); installer.setMessageBoxAutomaticAnswer( "stopProcessesForUpdates", QMessageBox.Ignore); } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.TargetDirectoryPageCallback = function() { var page = gui.pageWidgetByObjectName("TargetDirectoryPage"); page.TargetDirectoryLineEdit.setText(installerTargetDirectory); gui.clickButton(buttons.NextButton); } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName("ComponentSelectionPage"); gui.clickButton(buttons.NextButton); } Controller.prototype.LicenseAgreementPageCallback = function() { var page = gui.pageWidgetByObjectName("LicenseAgreementPage"); page.AcceptLicenseRadioButton.setChecked( true); gui.clickButton(buttons.NextButton); } ////in the current installer we don't have this //Controller.prototype.DynamicQtGuiPageCallback = function() //{ // var page = gui.pageWidgetByObjectName("DynamicQtGuiPage"); // page.checkBoxLib.setChecked( false); // gui.clickButton(buttons.NextButton); //} ////in the current installer we don't have this //Controller.prototype.DynamicErrorPageCallback = function() //{ // var page = gui.pageWidgetByObjectName("DynamicErrorPage"); // page.checkBoxMakeSure.setChecked( true); // gui.clickButton(buttons.NextButton); //} Controller.prototype.StartMenuDirectoryPageCallback = function() { var page = gui.pageWidgetByObjectName("StartMenuDirectoryPage"); //page.LineEdit.text = "test"; gui.clickButton(buttons.NextButton); } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.PerformInstallationPageCallback = function() { var page = gui.pageWidgetByObjectName("PerformInstallationPage"); gui.clickButton(buttons.NextButton); } Controller.prototype.FinishedPageCallback = function() { var page = gui.pageWidgetByObjectName("FinishedPage"); gui.clickButton(buttons.FinishButton); } qt-installer-framework-4.0.1/tests/test-installer/BatchSubstitute.bat0100777000000000000000000000366113761647206023027 0ustar00::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: :: Copyright (C) 2020 The Qt Company Ltd. :: Contact: http://www.qt.io/licensing/ :: :: This file is part of the Qt Installer Framework. :: :: $QT_BEGIN_LICENSE:GPL-EXCEPT$ :: Commercial License Usage :: Licensees holding valid commercial Qt licenses may use this file in :: accordance with the commercial license agreement provided with the :: Software or, alternatively, in accordance with the terms contained in :: a written agreement between you and The Qt Company. For licensing terms :: and conditions see https://www.qt.io/terms-conditions. For further :: information use the contact form at https://www.qt.io/contact-us. :: :: GNU General Public License Usage :: Alternatively, this file may be used under the terms of the GNU :: General Public License version 3 as published by the Free Software :: Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT :: included in the packaging of this file. Please review the following :: information to ensure the GNU General Public License requirements will :: be met: https://www.gnu.org/licenses/gpl-3.0.html. :: :: $QT_END_LICENSE$ :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: @echo off REM -- Prepare the Command Processor -- SETLOCAL ENABLEEXTENSIONS SETLOCAL DISABLEDELAYEDEXPANSION ::BatchSubstitude - parses a File line by line and replaces a substring" ::syntax: BatchSubstitude.bat OldStr NewStr File :: OldStr [in] - string to be replaced :: NewStr [in] - string to replace with :: File [in] - file to be parsed :$changed 20100115 :$source http://www.dostips.com if "%~1"=="" findstr "^::" "%~f0"&GOTO:EOF for /f "tokens=1,* delims=]" %%A in ('"type %3|find /n /v """') do ( set "line=%%B" if defined line ( call set "line=echo.%%line:%~1=%~2%%" for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X ) ELSE echo. ) qt-installer-framework-4.0.1/tests/test-installer/create-test-installer.bat0100777000000000000000000001033313761647206024117 0ustar00::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: :: Copyright (C) 2017 The Qt Company Ltd. :: Contact: http://www.qt.io/licensing/ :: :: This file is part of the Qt Installer Framework. :: :: $QT_BEGIN_LICENSE:GPL-EXCEPT$ :: Commercial License Usage :: Licensees holding valid commercial Qt licenses may use this file in :: accordance with the commercial license agreement provided with the :: Software or, alternatively, in accordance with the terms contained in :: a written agreement between you and The Qt Company. For licensing terms :: and conditions see https://www.qt.io/terms-conditions. For further :: information use the contact form at https://www.qt.io/contact-us. :: :: GNU General Public License Usage :: Alternatively, this file may be used under the terms of the GNU :: General Public License version 3 as published by the Free Software :: Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT :: included in the packaging of this file. Please review the following :: information to ensure the GNU General Public License requirements will :: be met: https://www.gnu.org/licenses/gpl-3.0.html. :: :: $QT_END_LICENSE$ :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: @IF "%1" EQU "" ( @set OFFLINE_INSTALLER=true @set ONLINE_INSTALLER=true @set REPOGEN=true @set TEST_ONLINE_INSTALLER=false @set TEST_OFFLINE_INSTALLER=false ) else ( @set OFFLINE_INSTALLER=false @set ONLINE_INSTALLER=false @set REPOGEN=false @set TEST_ONLINE_INSTALLER=false @set TEST_OFFLINE_INSTALLER=false ) @for %%i in (%1,%2,%3,%4,%5,%6,%7,%8,%9) DO ( @IF "%%i" EQU "offline" ( @set OFFLINE_INSTALLER=true ) @IF "%%i" EQU "online" ( @set ONLINE_INSTALLER=true ) @IF "%%i" EQU "repogen" ( @set REPOGEN=true ) @IF "%%i" EQU "test_online" ( @set TEST_ONLINE_INSTALLER=true ) @IF "%%i" EQU "test_offline" ( @set TEST_OFFLINE_INSTALLER=true ) ) @set AUTO_INSTALLATION_SCRIPT=--script %CD%\auto_installations_script.qs @set BINARY_PATH_RELATIVE=%CD%\..\..\bin @pushd . @cd %BINARY_PATH_RELATIVE% @set BINARY_PATH_ABSOLUTE=%CD% @popd @set LOCAL_REPOSITORY=file:///%BINARY_PATH_ABSOLUTE%/repository @set LOCAL_REPOSITORY_PATH=%LOCAL_REPOSITORY:\=/% call BatchSubstitute.bat http://www.xxxx.com/repository %LOCAL_REPOSITORY_PATH% ..\..\examples\testapp\config\config.xml > ..\..\examples\testapp\config\config.xml_new @if %ERRORLEVEL% NEQ 0 goto error_marker copy /Y ..\..\examples\testapp\config\config.xml ..\..\examples\testapp\config\config.xml_old @if %ERRORLEVEL% NEQ 0 goto error_marker move /Y ..\..\examples\testapp\config\config.xml_new ..\..\examples\testapp\config\config.xml @if %ERRORLEVEL% NEQ 0 goto error_marker IF "%OFFLINE_INSTALLER%" EQU "true" ( echo create offline installer ..\..\bin\binarycreator -t ..\..\bin\installerbase.exe -v -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config\config.xml --offline-only ..\..\bin\test-installer-offline.exe @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) IF "%ONLINE_INSTALLER%" EQU "true" ( echo create online installer ..\..\bin\binarycreator -t ..\..\bin\installerbase.exe -v -n -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config\config.xml ..\..\bin\test-installer-online.exe @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) IF "%REPOGEN%" EQU "true" ( echo create online repository @IF exist ..\..\bin\repository rmdir /S /Q ..\..\bin\repository ..\..\bin\repogen.exe -p ..\..\examples\testapp\packages ..\..\bin\repository @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) @IF "%TEST_OFFLINE_INSTALLER%" EQU "true" ( ..\..\bin\test-installer-offline.exe --verbose %AUTO_INSTALLATION_SCRIPT% @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) @IF "%TEST_ONLINE_INSTALLER%" EQU "true" ( ..\..\bin\test-installer-online.exe --verbose %AUTO_INSTALLATION_SCRIPT% @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) copy /Y ..\..\examples\testapp\config\config.xml_old ..\..\examples\testapp\config\config.xml @if %ERRORLEVEL% NEQ 0 goto error_marker goto done_marker :error_marker echo *** Error compiling ifw *** pause :done_marker echo ...done qt-installer-framework-4.0.1/tests/test-installer/create-test-installer.sh0100777000000000000000000000264713761647206023774 0ustar00############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# ../../bin/binarycreator --offline-only -v -t ../../bin/installerbase -p ../../examples/testapp/packages -c ../../examples/testapp/config/config.xml ../../bin/test-installer-offline qt-installer-framework-4.0.1/tests/testcases/0040777000000000000000000000000013761647206016240 5ustar00qt-installer-framework-4.0.1/tests/testcases/result-example.xml0100777000000000000000000000314113761647206021730 0ustar00 ab12cd34ef - installer-20090310.exe - checks failed :-( 2010-03-10T14:00Z test-machine_1.local 2010-03-10T13:00Z 2010-03-10T13:49Z ftp://buildmachine/installers/installer-20090310.exe ab12cd34ef windows /home/testuser/VMs/WindowsXp/WindowsXp.vmx windows base Basic Installation /home/testuser/testcases/basic/basic.cfg /home/testuser/testcases/basic/testscript.qs 0 normal NoError c:\sdk\bin\qmake.exe: md5 sum mismatch: expected: abcd1234 actual: 1234abcd InstallerError InstallerError qt-installer-framework-4.0.1/tests/testcases/testcase1/0040777000000000000000000000000013761647206020134 5ustar00qt-installer-framework-4.0.1/tests/testcases/testcase1/packagemanagement.qs0100777000000000000000000000426313761647206024136 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Controller() { installer.autoRejectMessageBoxes this.componentSelectionCounter = 0 } Controller.prototype.UpdaterSelectedCallback = function() { tabController.setCurrentTab( TabController.PACKAGE_MANAGER ) } Controller.prototype.ComponentSelectionPageCallback = function() { if ( this.componentSelectionCounter == 0 ) { print( "first time, uninstall" ) var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.deselectComponent( "com.nokia.sdk.doc.qtcreator" ) gui.clickButton( buttons.NextButton, 3000 ) this.componentSelectionCounter += 1 } else { print( "second time, click cancel" ) gui.clickButton( buttons.CancelButton ) } } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.FinishedPageCallback = function() { gui.clickButton( buttons.CommitButton ) } qt-installer-framework-4.0.1/tests/testcases/testcase1/test-uninstall.qs0100777000000000000000000000414313761647206023471 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Controller() { installer.autoRejectMessageBoxes } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.keepSelectedComponentsRB.setChecked( true ) page.deselectComponent( "com.nokia.sdk.qt.gui" ) page.deselectComponent( "hgrmpfl (non-existing package)" ) // bad case for component lookup page.selectComponent( "hgrmpfl2 (another non-existing package)" ) // bad case for component lookup gui.clickButton( buttons.NextButton ) } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.FinishedPageCallback = function() { gui.clickButton( buttons.FinishButton ) } qt-installer-framework-4.0.1/tests/testcases/testcase1/testcase1.cfg0100777000000000000000000000020713761647206022510 0ustar00[General] installscript=testscript.qs platforms=windows,linux targetDirectory=c:\Users\kdab\Desktop\testinstall checkerTestDir=checker qt-installer-framework-4.0.1/tests/testcases/testcase1/testscript.qs0100777000000000000000000000645513761647206022717 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the FOO module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ function Controller() { installer.autoRejectMessageBoxes installer.setMessageBoxAutomaticAnswer( "overwriteTargetDirectory", QMessageBox.Yes ) } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.LicenseAgreementPageCallback = function() { var page = gui.pageWidgetByObjectName( "LicenseAgreementPage" ) page.acceptLicenseRB.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.TargetDirectoryPageCallback = function() { var page = gui.pageWidgetByObjectName( "TargetDirectoryPage" ) page.targetDirectoryLE.setText( "c:\\Users\\kdab\\Desktop\\testinstall" ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.deselectComponent( "com.nokia.sdk.qtcreator" ) page.deselectComponent( "hgrmpfl (non-existing package)" ) // bad case for component lookup page.selectComponent( "hgrmpfl2 (another non-existing package)" ) // bad case for component lookup gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicQtGuiPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicQtGuiPage" ) page.checkBoxLib.setChecked( false ) gui.clickButton( buttons.NextButton ) } Controller.prototype.DynamicErrorPageCallback = function() { var page = gui.pageWidgetByObjectName( "DynamicErrorPage" ) page.checkBoxMakeSure.setChecked( true ) gui.clickButton( buttons.NextButton ) } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.StartMenuDirectoryPageCallback = function() { gui.clickButton( buttons.NextButton ) } Controller.prototype.PerformInstallationPageCallback = function() { var page = gui.pageWidgetByObjectName( "PerformInstallationPage" ) page.details.button.click } Controller.prototype.FinishedPageCallback = function() { gui.clickButton( buttons.FinishButton ) } qt-installer-framework-4.0.1/tests/testreturn/0040777000000000000000000000000013761647206016461 5ustar00qt-installer-framework-4.0.1/tests/testreturn/main.cpp0100777000000000000000000000434213761647206020114 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include static void crash() { QString* nemesis = 0; nemesis->clear(); } int main( int argc, char** argv ) { std::cout << "Hello." << std::endl; if ( argc < 2 ) return 0; const QString arg = QString::fromLocal8Bit( argv[1] ); bool ok = false; const int num = arg.toInt( &ok ); if ( ok ) return num; if ( arg == QLatin1String("crash") ) { std::cout << "Yeth, mather. I Crash." << std::endl; crash(); } if ( arg == QLatin1String("--script") ) { const QString fn = QString::fromLocal8Bit( argv[2] ); QFile f( fn ); if ( !f.open( QIODevice::ReadOnly ) ) { std::cerr << "Could not open file for reading: " << qPrintable(f.errorString()) << std::endl; crash(); } bool ok; const int rv = QString::fromLatin1( f.readAll() ).toInt( &ok ); if ( ok ) return rv; else crash(); } } qt-installer-framework-4.0.1/tests/testreturn/testreturn.pro0100777000000000000000000000014413761647206021421 0ustar00TEMPLATE = app TARGET = INCLUDEPATH += . QT -= gui CONFIG += console # Input SOURCES += main.cpp qt-installer-framework-4.0.1/tests/tests.pro0100777000000000000000000000010513761647206016122 0ustar00TEMPLATE = subdirs SUBDIRS = \ auto \ downloadspeed qt-installer-framework-4.0.1/tools/0040777000000000000000000000000013761647206014240 5ustar00qt-installer-framework-4.0.1/tools/archivegen/0040777000000000000000000000000013761647206016353 5ustar00qt-installer-framework-4.0.1/tools/archivegen/archive.cpp0100777000000000000000000001567013761647206020511 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include #include #include #include #include using namespace QInstaller; class FailOnErrorCallback : public Lib7z::UpdateCallback { HRESULT OpenFileError(const wchar_t*, DWORD) { return S_FALSE; } HRESULT CanNotFindError(const wchar_t*, DWORD) { return S_FALSE; } HRESULT OpenResult(const wchar_t*, HRESULT result, const wchar_t*) { return result; } }; class VerbosePrinterCallback : public Lib7z::UpdateCallback { public: ~VerbosePrinterCallback() { m_PercentPrinter.ClosePrint(); } private: HRESULT SetTotal(UInt64 size) { m_PercentPrinter.SetTotal(size); return S_OK; } HRESULT SetCompleted(const UInt64 *size) { if (size) { m_PercentPrinter.SetRatio(*size); m_PercentPrinter.PrintRatio(); } return S_OK; } HRESULT OpenResult(const wchar_t *file, HRESULT result, const wchar_t*) { if (result != S_OK) { printBlock(QCoreApplication::translate("archivegen", "Cannot update file \"%1\". " "Unsupported archive.").arg(QDir::toNativeSeparators(QString::fromWCharArray(file))), Q_NULLPTR); } return result; } HRESULT OpenFileError(const wchar_t *file, DWORD) { printBlock(QCoreApplication::translate("archivegen", "Cannot open file "), file); return S_FALSE; } HRESULT CanNotFindError(const wchar_t *file, DWORD) { printBlock(QCoreApplication::translate("archivegen", "Cannot find file "), file); return S_FALSE; } HRESULT StartArchive(const wchar_t *name, bool) { printLine(QCoreApplication::translate("archivegen", "Create archive.")); if (name) { m_PercentPrinter.PrintNewLine(); m_PercentPrinter.PrintString(name); } return S_OK; } HRESULT FinishArchive() { m_PercentPrinter.PrintNewLine(); printLine(QCoreApplication::translate("archivegen", "Finished archive.")); return S_OK; } void printLine(const QString &message) { m_PercentPrinter.PrintString(message.toStdWString().c_str()); } void printBlock(const QString &message, const wchar_t *message2) { m_PercentPrinter.PrintNewLine(); m_PercentPrinter.PrintString(message.toStdWString().c_str()); if (message2) m_PercentPrinter.PrintString(message2); m_PercentPrinter.PrintNewLine(); } Lib7z::PercentPrinter m_PercentPrinter; }; int main(int argc, char *argv[]) { try { QCoreApplication app(argc, argv); #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) QCoreApplication::setApplicationVersion(QLatin1String(QUOTE(IFW_VERSION_STR))); #undef QUOTE #undef QUOTE_ QCommandLineParser parser; const QCommandLineOption help = parser.addHelpOption(); const QCommandLineOption version = parser.addVersionOption(); QCommandLineOption verbose(QLatin1String("verbose"), QCoreApplication::translate("archivegen", "Verbose mode. Prints out more information.")); const QCommandLineOption compression = QCommandLineOption(QStringList() << QLatin1String("c") << QLatin1String("compression"), QCoreApplication::translate("archivegen", "0 (No compression)\n" "1 (Fastest compressing)\n" "3 (Fast compressing)\n" "5 (Normal compressing)\n" "7 (Maximum compressing)\n" "9 (Ultra compressing)\n" "Defaults to 5 (Normal compression)." ), QLatin1String("5"), QLatin1String("5")); parser.addOption(verbose); parser.addOption(compression); parser.addPositionalArgument(QLatin1String("archive"), QCoreApplication::translate("archivegen", "Compressed archive to create.")); parser.addPositionalArgument(QLatin1String("sources"), QCoreApplication::translate("archivegen", "List of files and directories to compress.")); parser.parse(app.arguments()); if (parser.isSet(help)) { std::cout << parser.helpText() << std::endl; return EXIT_SUCCESS; } if (parser.isSet(version)) { parser.showVersion(); return EXIT_SUCCESS; } const QStringList args = parser.positionalArguments(); if (args.count() < 2) { std::cerr << QCoreApplication::translate("archivegen", "Wrong argument count. See " "'archivgen --help'.") << std::endl; return EXIT_FAILURE; } bool ok = false; const int values[6] = { 0, 1, 3, 5, 7, 9 }; const int value = parser.value(compression).toInt(&ok); if (!ok || (std::find(std::begin(values), std::end(values), value) == std::end(values))) { throw QInstaller::Error(QCoreApplication::translate("archivegen", "Unknown compression level \"%1\". See 'archivgen --help'.").arg(value)); } Lib7z::initSevenZ(); Lib7z::createArchive(args[0], args.mid(1), Lib7z::TmpFile::No, Lib7z::Compression(value), [&] () -> Lib7z::UpdateCallback * { if (parser.isSet(verbose)) return new VerbosePrinterCallback; return new FailOnErrorCallback; } () ); return EXIT_SUCCESS; } catch (const QInstaller::Error &e) { std::cerr << e.message() << std::endl; } catch (...) { std::cerr << QCoreApplication::translate("archivegen", "Unknown exception caught.") << std::endl; } return EXIT_FAILURE; } qt-installer-framework-4.0.1/tools/archivegen/archivegen.pro0100777000000000000000000000056313761647206021214 0ustar00TEMPLATE = app TARGET = archivegen INCLUDEPATH += . .. ../common include(../../installerfw.pri) QT -= gui QT += qml xml LIBS += -l7z CONFIG += console DESTDIR = $$IFW_APP_PATH SOURCES += archive.cpp \ ../common/repositorygen.cpp HEADERS += ../common/repositorygen.h macx:include(../../no_app_bundle.pri) target.path = $$[QT_INSTALL_BINS] INSTALLS += target qt-installer-framework-4.0.1/tools/binarycreator/0040777000000000000000000000000013761647206017104 5ustar00qt-installer-framework-4.0.1/tools/binarycreator/binarycreator.cpp0100777000000000000000000012277713761647206022474 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "common/repositorygen.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_MACOS #include #include #include #include #include #endif using namespace QInstaller; struct Input { QString outputPath; QString installerExePath; QInstallerTools::PackageInfoVector packages; QInstaller::ResourceCollectionManager manager; }; class BundleBackup { public: explicit BundleBackup(const QString &bundle = QString()) : bundle(bundle) { if (!bundle.isEmpty() && QFileInfo(bundle).exists()) { backup = generateTemporaryFileName(bundle); QFile::rename(bundle, backup); } } ~BundleBackup() { if (!backup.isEmpty()) { removeDirectory(bundle); QFile::rename(backup, bundle); } } void release() const { if (!backup.isEmpty()) removeDirectory(backup); backup.clear(); } private: const QString bundle; mutable QString backup; }; #ifndef Q_OS_WIN static void chmod755(const QString &absolutFilePath) { QFile::setPermissions(absolutFilePath, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup | QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther); } #endif #ifdef Q_OS_MACOS template T readInt(QIODevice *ioDevice, bool *ok, bool swap, bool peek = false) { const auto bytes = peek ? ioDevice->peek(sizeof(T)) : ioDevice->read(sizeof(T)); if (bytes.size() != sizeof(T)) { if (ok) *ok = false; return T(); } if (ok) *ok = true; T n = *reinterpret_cast(bytes.constData()); return swap ? qbswap(n) : n; } static QVersionNumber readMachOMinimumSystemVersion(QIODevice *device) { bool ok; std::vector machoOffsets; qint64 pos = device->pos(); uint32_t magic = readInt(device, &ok, false); if (magic == FAT_MAGIC || magic == FAT_CIGAM || magic == FAT_MAGIC_64 || magic == FAT_CIGAM_64) { bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64; uint32_t nfat = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); for (uint32_t n = 0; n < nfat; ++n) { const bool is64bit = magic == FAT_MAGIC_64 || magic == FAT_CIGAM_64; fat_arch_64 fat_arch; fat_arch.cputype = static_cast(readInt(device, &ok, swap)); if (!ok) return QVersionNumber(); fat_arch.cpusubtype = static_cast(readInt(device, &ok, swap)); if (!ok) return QVersionNumber(); fat_arch.offset = is64bit ? readInt(device, &ok, swap) : readInt(device, &ok, swap); if (!ok) return QVersionNumber(); fat_arch.size = is64bit ? readInt(device, &ok, swap) : readInt(device, &ok, swap); if (!ok) return QVersionNumber(); fat_arch.align = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); fat_arch.reserved = is64bit ? readInt(device, &ok, swap) : 0; if (!ok) return QVersionNumber(); machoOffsets.push_back(static_cast(fat_arch.offset)); } } else if (!ok) { return QVersionNumber(); } // Wasn't a fat file, so we just read a thin Mach-O from the original offset if (machoOffsets.empty()) machoOffsets.push_back(pos); std::vector versions; for (const auto &offset : machoOffsets) { if (!device->seek(offset)) return QVersionNumber(); bool swap = false; mach_header_64 header; header.magic = readInt(device, nullptr, swap); switch (header.magic) { case MH_CIGAM: case MH_CIGAM_64: swap = true; break; case MH_MAGIC: case MH_MAGIC_64: break; default: return QVersionNumber(); } header.cputype = static_cast(readInt(device, &ok, swap)); if (!ok) return QVersionNumber(); header.cpusubtype = static_cast(readInt(device, &ok, swap)); if (!ok) return QVersionNumber(); header.filetype = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); header.ncmds = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); header.sizeofcmds = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); header.flags = readInt(device, &ok, swap); if (!ok) return QVersionNumber(); header.reserved = header.magic == MH_MAGIC_64 || header.magic == MH_CIGAM_64 ? readInt(device, &ok, swap) : 0; if (!ok) return QVersionNumber(); for (uint32_t i = 0; i < header.ncmds; ++i) { const uint32_t cmd = readInt(device, nullptr, swap); const uint32_t cmdsize = readInt(device, nullptr, swap); if (cmd == 0 || cmdsize == 0) return QVersionNumber(); switch (cmd) { case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: case LC_VERSION_MIN_TVOS: case LC_VERSION_MIN_WATCHOS: const uint32_t version = readInt(device, &ok, swap, true); if (!ok) return QVersionNumber(); versions.push_back(QVersionNumber( static_cast(version >> 16), static_cast((version >> 8) & 0xff), static_cast(version & 0xff))); break; } const qint64 remaining = static_cast(cmdsize - sizeof(cmd) - sizeof(cmdsize)); if (device->read(remaining).size() != remaining) return QVersionNumber(); } } std::sort(versions.begin(), versions.end()); return !versions.empty() ? versions.front() : QVersionNumber(); } #endif static int assemble(Input input, const QInstaller::Settings &settings, const QString &signingIdentity) { #ifdef Q_OS_MACOS if (QInstaller::isInBundle(input.installerExePath)) { const QString bundle = input.installerExePath; // if the input file was a bundle const QSettings s(QString::fromLatin1("%1/Contents/Info.plist").arg(input.installerExePath), QSettings::NativeFormat); input.installerExePath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(bundle) .arg(s.value(QLatin1String("CFBundleExecutable"), QFileInfo(input.installerExePath).completeBaseName()).toString()); } const bool createDMG = input.outputPath.endsWith(QLatin1String(".dmg")); if (createDMG) input.outputPath.replace(input.outputPath.length() - 4, 4, QLatin1String(".app")); const bool isBundle = input.outputPath.endsWith(QLatin1String(".app")); const QString bundle = isBundle ? input.outputPath : QString(); const BundleBackup bundleBackup(bundle); if (isBundle) { // output should be a bundle const QFileInfo fi(input.outputPath); QString minimumSystemVersion; QFile file(input.installerExePath); if (file.open(QIODevice::ReadOnly)) minimumSystemVersion = readMachOMinimumSystemVersion(&file).normalized().toString(); const QString contentsResourcesPath = fi.filePath() + QLatin1String("/Contents/Resources/"); QInstaller::mkpath(fi.filePath() + QLatin1String("/Contents/MacOS")); QInstaller::mkpath(contentsResourcesPath); { QFile pkgInfo(fi.filePath() + QLatin1String("/Contents/PkgInfo")); pkgInfo.open(QIODevice::WriteOnly); QTextStream pkgInfoStream(&pkgInfo); pkgInfoStream << QLatin1String("APPL????") << endl; } QString iconFile; if (QFile::exists(settings.installerApplicationIcon())) { iconFile = settings.installerApplicationIcon(); } else { iconFile = QString::fromLatin1(":/resources/default_icon_mac.icns"); } const QString iconTargetFile = fi.completeBaseName() + QLatin1String(".icns"); QFile::copy(iconFile, contentsResourcesPath + iconTargetFile); if (QDir(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib")).exists()) { copyDirectoryContents(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib"), contentsResourcesPath + QLatin1String("/qt_menu.nib")); } QFile infoPList(fi.filePath() + QLatin1String("/Contents/Info.plist")); infoPList.open(QIODevice::WriteOnly); QTextStream plistStream(&infoPList); plistStream << QLatin1String("") << endl; plistStream << QLatin1String("") << endl; plistStream << QLatin1String("") << endl; plistStream << QLatin1String("") << endl; plistStream << QLatin1String("\tCFBundleIconFile") << endl; plistStream << QLatin1String("\t") << iconTargetFile << QLatin1String("") << endl; plistStream << QLatin1String("\tCFBundlePackageType") << endl; plistStream << QLatin1String("\tAPPL") << endl; #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) plistStream << QLatin1String("\tCFBundleShortVersionString") << endl; plistStream << QLatin1String("\t") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("") << endl; plistStream << QLatin1String("\tCFBundleVersion") << endl; plistStream << QLatin1String("\t") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("") << endl; #undef QUOTE #undef QUOTE_ plistStream << QLatin1String("\tCFBundleSignature") << endl; plistStream << QLatin1String("\t\?\?\?\?") << endl; plistStream << QLatin1String("\tCFBundleExecutable") << endl; plistStream << QLatin1String("\t") << fi.completeBaseName() << QLatin1String("") << endl; plistStream << QLatin1String("\tCFBundleIdentifier") << endl; plistStream << QLatin1String("\tcom.yourcompany.installerbase") << endl; plistStream << QLatin1String("\tNOTE") << endl; plistStream << QLatin1String("\tThis file was generated by Qt Installer Framework.") << endl; plistStream << QLatin1String("\tNSPrincipalClass") << endl; plistStream << QLatin1String("\tNSApplication") << endl; if (!minimumSystemVersion.isEmpty()) { plistStream << QLatin1String("\tLSMinimumSystemVersion") << endl; plistStream << QLatin1String("\t") << minimumSystemVersion << QLatin1String("") << endl; } plistStream << QLatin1String("") << endl; plistStream << QLatin1String("") << endl; input.outputPath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(input.outputPath) .arg(fi.completeBaseName()); } #elif defined(Q_OS_LINUX) Q_UNUSED(settings) #endif QTemporaryFile file(input.outputPath); if (!file.open()) { throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(input.installerExePath, input.outputPath, file.errorString())); } const QString tempFile = file.fileName(); file.close(); file.remove(); QFile instExe(input.installerExePath); if (!instExe.copy(tempFile)) { throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(instExe.fileName(), tempFile, instExe.errorString())); } QtPatch::patchBinaryFile(tempFile, QByteArray("MY_InstallerCreateDateTime_MY"), QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-dd - HH:mm:ss")).toLatin1()); input.installerExePath = tempFile; #if defined(Q_OS_WIN) // setting the windows icon must happen before we append our binary data - otherwise they get lost :-/ if (QFile::exists(settings.installerApplicationIcon())) { // no error handling as this is not fatal setApplicationIcon(tempFile, settings.installerApplicationIcon()); } #elif defined(Q_OS_MACOS) if (isBundle) { // no error handling as this is not fatal const QString copyscript = QDir::temp().absoluteFilePath(QLatin1String("copylibsintobundle.sh")); QFile::copy(QLatin1String(":/resources/copylibsintobundle.sh"), copyscript); QFile::rename(tempFile, input.outputPath); chmod755(copyscript); QProcess p; p.start(copyscript, QStringList() << bundle); p.waitForFinished(-1); QFile::rename(input.outputPath, tempFile); QFile::remove(copyscript); } #endif QFile out(generateTemporaryFileName()); QString targetName = input.outputPath; #ifdef Q_OS_MACOS QDir resourcePath(QFileInfo(input.outputPath).dir()); resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); targetName = resourcePath.filePath(QLatin1String("installer.dat")); #endif { QFile target(targetName); if (target.exists() && !target.remove()) { qCritical("Cannot remove target %s: %s", qPrintable(target.fileName()), qPrintable(target.errorString())); QFile::remove(tempFile); return EXIT_FAILURE; } } try { QInstaller::openForWrite(&out); QFile exe(input.installerExePath); #ifdef Q_OS_MACOS if (!exe.copy(input.outputPath)) { throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(exe.fileName(), input.outputPath, exe.errorString())); } #else QInstaller::openForRead(&exe); QInstaller::appendData(&out, &exe, exe.size()); #endif foreach (const QInstallerTools::PackageInfo &info, input.packages) { QInstaller::ResourceCollection collection; collection.setName(info.name.toUtf8()); qDebug() << "Creating resource archive for" << info.name; foreach (const QString &file, info.copiedFiles) { const QSharedPointer resource(new Resource(file)); qDebug().nospace() << "Appending " << file << " (" << humanReadableSize(resource->size()) << ")"; collection.appendResource(resource); } input.manager.insertCollection(collection); } const QList operations; BinaryContent::writeBinaryContent(&out, operations, input.manager, BinaryContent::MagicInstallerMarker, BinaryContent::MagicCookie); } catch (const Error &e) { qCritical("Error occurred while assembling the installer: %s", qPrintable(e.message())); QFile::remove(tempFile); return EXIT_FAILURE; } if (!out.rename(targetName)) { qCritical("Cannot write installer to %s: %s", targetName.toUtf8().constData(), out.errorString().toUtf8().constData()); QFile::remove(tempFile); return EXIT_FAILURE; } #ifndef Q_OS_WIN chmod755(out.fileName()); #endif QFile::remove(tempFile); #ifdef Q_OS_MACOS if (isBundle && !signingIdentity.isEmpty()) { qDebug() << "Signing .app bundle..."; QProcess p; p.start(QLatin1String("codesign"), QStringList() << QLatin1String("--force") << QLatin1String("--deep") << QLatin1String("--sign") << signingIdentity << bundle); if (!p.waitForFinished(-1)) { qCritical("Failed to sign app bundle: error while running '%s %s': %s", p.program().toUtf8().constData(), p.arguments().join(QLatin1Char(' ')).toUtf8().constData(), p.errorString().toUtf8().constData()); return EXIT_FAILURE; } if (p.exitStatus() == QProcess::NormalExit) { if (p.exitCode() != 0) { qCritical("Failed to sign app bundle: running codesign failed " "with exit code %d: %s", p.exitCode(), p.readAllStandardError().constData()); return EXIT_FAILURE; } } qDebug() << "done."; } bundleBackup.release(); if (createDMG) { qDebug() << "creating a DMG disk image..."; const QString volumeName = QFileInfo(input.outputPath).fileName(); const QString imagePath = QString::fromLatin1("%1/%2.dmg") .arg(QFileInfo(bundle).path()) .arg(volumeName); // no error handling as this is not fatal QProcess p; p.start(QLatin1String("/usr/bin/hdiutil"), QStringList() << QLatin1String("create") << imagePath << QLatin1String("-srcfolder") << bundle << QLatin1String("-ov") << QLatin1String("-volname") << volumeName << QLatin1String("-fs") << QLatin1String("HFS+")); qDebug() << "running " << p.program() << p.arguments(); p.waitForFinished(-1); qDebug() << "removing" << bundle; QDir(bundle).removeRecursively(); qDebug() << "done."; } #else Q_UNUSED(signingIdentity) #endif return EXIT_SUCCESS; } QT_BEGIN_NAMESPACE int runRcc(int argc, char *argv[]); QT_END_NAMESPACE static int runRcc(const QStringList &args) { const int argc = args.count(); QVector argv(argc, nullptr); for (int i = 0; i < argc; ++i) argv[i] = qstrdup(qPrintable(args[i])); // Note: this does not run the rcc provided by Qt, this one is using the compiled in binarycreator // version. If it happens that resource mapping fails, we might need to adapt the code here... const int result = runRcc(argc, argv.data()); foreach (char *arg, argv) delete [] arg; return result; } class WorkingDirectoryChange { public: explicit WorkingDirectoryChange(const QString &path) : oldPath(QDir::currentPath()) { QDir::setCurrent(path); } virtual ~WorkingDirectoryChange() { QDir::setCurrent(oldPath); } private: const QString oldPath; }; static QSharedPointer createDefaultResourceFile(const QString &directory, const QString &binaryName) { QTemporaryFile projectFile(directory + QLatin1String("/rccprojectXXXXXX.qrc")); if (!projectFile.open()) throw Error(QString::fromLatin1("Cannot create temporary file for generated rcc project file")); projectFile.close(); const WorkingDirectoryChange wd(directory); const QString projectFileName = QFileInfo(projectFile.fileName()).absoluteFilePath(); // 1. create the .qrc file if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") << QLatin1String("-o") << projectFileName) != EXIT_SUCCESS) { throw Error(QString::fromLatin1("Cannot create rcc project file.")); } // 2. create the binary resource file from the .qrc file if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") << QLatin1String("-o") << binaryName << projectFileName) != EXIT_SUCCESS) { throw Error(QString::fromLatin1("Cannot compile rcc project file.")); } return QSharedPointer(new QInstaller::Resource(binaryName, binaryName .toUtf8())); } static QList > createBinaryResourceFiles(const QStringList &resources) { QList > result; foreach (const QString &resource, resources) { QFile file(resource); if (file.exists()) { const QString binaryName = generateTemporaryFileName(); const QString fileName = QFileInfo(file.fileName()).absoluteFilePath(); const int status = runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") << QLatin1String("-o") << binaryName << fileName); if (status != EXIT_SUCCESS) continue; result.append(QSharedPointer (new QInstaller::Resource(binaryName, binaryName.toUtf8()))); } } return result; } static void printUsage() { QString suffix; #ifdef Q_OS_WIN suffix = QLatin1String(".exe"); #endif const QString appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); std::cout << "Usage: " << appName << " [options] target" << std::endl; std::cout << std::endl; std::cout << "Options:" << std::endl; std::cout << " -t|--template file Use file as installer template binary" << std::endl; std::cout << " If this parameter is not given, the template used" << std::endl; std::cout << " defaults to installerbase." << std::endl; QInstallerTools::printRepositoryGenOptions(); std::cout << " -c|--config file The file containing the installer configuration" << std::endl; std::cout << " -n|--online-only Do not add any package into the installer" << std::endl; std::cout << " (for online only installers)" << std::endl; std::cout << " -f|--offline-only Forces the installer to act as an offline installer, " << std::endl; std::cout << " i.e. never access online repositories" << std::endl; std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl; std::cout << " -v|--verbose Verbose output" << std::endl; std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into" << std::endl; std::cout << " 'update.rcc' in the current path." << std::endl; #ifdef Q_OS_MACOS std::cout << " -s|--sign identity Sign generated app bundle using the given code " << std::endl; std::cout << " signing identity" << std::endl; #endif std::cout << std::endl; std::cout << "Packages are to be found in the current working directory and get listed as " "their names" << std::endl << std::endl; std::cout << "Example (offline installer):" << std::endl; char sep = QDir::separator().toLatin1(); std::cout << " " << appName << " --offline-only -c installer-config" << sep << "config.xml -p " "packages-directory -t installerbase" << suffix << " SDKInstaller" << suffix << std::endl; std::cout << "Creates an offline installer for the SDK, containing all dependencies." << std::endl; std::cout << std::endl; std::cout << "Example (online installer):" << std::endl; std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " "-e org.qt-project.sdk.qt,org.qt-project.qtcreator -t installerbase" << suffix << " SDKInstaller" << suffix << std::endl; std::cout << std::endl; std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl; std::cout << std::endl; std::cout << "Example update.rcc:" << std::endl; std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " "-rcc" << std::endl; } void copyConfigData(const QString &configFile, const QString &targetDir) { qDebug() << "Begin to copy configuration file and data."; const QString sourceConfigFile = QFileInfo(configFile).absoluteFilePath(); const QString targetConfigFile = targetDir + QLatin1String("/config.xml"); QInstallerTools::copyWithException(sourceConfigFile, targetConfigFile, QLatin1String("configuration")); QFile configXml(targetConfigFile); QInstaller::openForRead(&configXml); QDomDocument dom; dom.setContent(&configXml); configXml.close(); // iterate over all child elements, searching for relative file names const QDomNodeList children = dom.documentElement().childNodes(); const QString sourceConfigFilePath = QFileInfo(sourceConfigFile).absolutePath(); for (int i = 0; i < children.count(); ++i) { QDomElement domElement = children.at(i).toElement(); if (domElement.isNull()) continue; const QString tagName = domElement.tagName(); const QString elementText = domElement.text(); qDebug().noquote() << QString::fromLatin1("Read dom element: <%1>%2.").arg(tagName, elementText); if (tagName == QLatin1String("ProductImages")) { const QDomNodeList childNodes = domElement.childNodes(); for (int i = 0; i < childNodes.count(); ++i) { const QDomElement childElement = childNodes.at(i).toElement(); const QString childName = childElement.tagName(); if (childName != QLatin1String("Image")) continue; const QString targetFile = targetDir + QLatin1Char('/') + childElement.text(); const QFileInfo childFileInfo = QFileInfo(sourceConfigFilePath, childElement.text()); QInstallerTools::copyWithException(childFileInfo.absoluteFilePath(), targetFile, childName); } continue; } QString newName = domElement.text().replace(QRegExp(QLatin1String("\\\\|/|\\.|:")), QLatin1String("_")); QString targetFile; QFileInfo elementFileInfo; if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { #if defined(Q_OS_MACOS) const QString suffix = QLatin1String(".icns"); #elif defined(Q_OS_WIN) const QString suffix = QLatin1String(".ico"); #else const QString suffix = QLatin1String(".png"); #endif elementFileInfo = QFileInfo(sourceConfigFilePath, elementText + suffix); targetFile = targetDir + QLatin1Char('/') + newName + suffix; } else { elementFileInfo = QFileInfo(sourceConfigFilePath, elementText); const QString suffix = elementFileInfo.completeSuffix(); if (!suffix.isEmpty()) newName.append(QLatin1Char('.') + suffix); targetFile = targetDir + QLatin1Char('/') + newName; } if (!elementFileInfo.exists() || elementFileInfo.isDir()) continue; domElement.replaceChild(dom.createTextNode(newName), domElement.firstChild()); QInstallerTools::copyWithException(elementFileInfo.absoluteFilePath(), targetFile, tagName); } QInstaller::openForWrite(&configXml); QTextStream stream(&configXml); dom.save(stream, 4); qDebug() << "done.\n"; } static int printErrorAndUsageAndExit(const QString &err) { std::cerr << qPrintable(err) << std::endl << std::endl; printUsage(); return EXIT_FAILURE; } int main(int argc, char **argv) { // increase maximum numbers of file descriptors #if defined (Q_OS_MACOS) struct rlimit rl; getrlimit(RLIMIT_NOFILE, &rl); rl.rlim_cur = qMin(static_cast(OPEN_MAX), rl.rlim_max); setrlimit(RLIMIT_NOFILE, &rl); #endif QCoreApplication app(argc, argv); QInstaller::init(); QString templateBinary = QLatin1String("installerbase"); QString suffix; #ifdef Q_OS_WIN suffix = QLatin1String(".exe"); templateBinary = templateBinary + suffix; #endif if (!QFileInfo(templateBinary).exists()) templateBinary = QString::fromLatin1("%1/%2").arg(qApp->applicationDirPath(), templateBinary); QString target; QString configFile; QStringList packagesDirectories; QStringList repositoryDirectories; bool onlineOnly = false; bool offlineOnly = false; QStringList resources; QStringList filteredPackages; QInstallerTools::FilterType ftype = QInstallerTools::Exclude; bool compileResource = false; QString signingIdentity; const QStringList args = app.arguments().mid(1); for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { if (*it == QLatin1String("-h") || *it == QLatin1String("--help")) { printUsage(); return 0; } else if (*it == QLatin1String("-p") || *it == QLatin1String("--packages")) { ++it; if (it == args.end()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Packages parameter missing argument.")); } if (!QFileInfo(*it).exists()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package directory not found at the " "specified location.")); } packagesDirectories.append(*it); } else if (*it == QLatin1String("--repository")) { ++it; if (it == args.end()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Repository parameter missing argument.")); } if (QFileInfo(*it).exists()) { repositoryDirectories.append(*it); } else { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Only local filesystem repositories now supported.")); } } else if (*it == QLatin1String("-e") || *it == QLatin1String("--exclude")) { ++it; if (!filteredPackages.isEmpty()) return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " "exclusive. Use either one or the other.")); if (it == args.end() || it->startsWith(QLatin1String("-"))) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to exclude missing.")); filteredPackages = it->split(QLatin1Char(',')); } else if (*it == QLatin1String("-i") || *it == QLatin1String("--include")) { ++it; if (!filteredPackages.isEmpty()) return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " "exclusive. Use either one or the other.")); if (it == args.end() || it->startsWith(QLatin1String("-"))) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to include missing.")); filteredPackages = it->split(QLatin1Char(',')); ftype = QInstallerTools::Include; } else if (*it == QLatin1String("-v") || *it == QLatin1String("--verbose")) { QInstaller::setVerbose(true); } else if (*it == QLatin1String("-n") || *it == QLatin1String("--online-only")) { if (!filteredPackages.isEmpty()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: 'online-only' option cannot be used " "in conjunction with the 'include' or 'exclude' option. An 'online-only' installer will never " "contain any components apart from the root component.")); } onlineOnly = true; } else if (*it == QLatin1String("-f") || *it == QLatin1String("--offline-only")) { offlineOnly = true; } else if (*it == QLatin1String("-t") || *it == QLatin1String("--template")) { ++it; if (it == args.end()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Template parameter missing argument.")); } templateBinary = *it; #ifdef Q_OS_WIN if (!templateBinary.endsWith(suffix)) templateBinary = templateBinary + suffix; #endif if (!QFileInfo(templateBinary).exists()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Template not found at the specified " "location.")); } } else if (*it == QLatin1String("-c") || *it == QLatin1String("--config")) { ++it; if (it == args.end()) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config parameter missing argument.")); const QFileInfo fi(*it); if (!fi.exists()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config file %1 not found at the " "specified location.").arg(*it)); } if (!fi.isFile()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Configuration %1 is not a file.") .arg(*it)); } if (!fi.isReadable()) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config file %1 is not readable.") .arg(*it)); } configFile = *it; } else if (*it == QLatin1String("-r") || *it == QLatin1String("--resources")) { ++it; if (it == args.end() || it->startsWith(QLatin1String("-"))) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Resource files to include are missing.")); resources = it->split(QLatin1Char(',')); } else if (*it == QLatin1String("--ignore-translations") || *it == QLatin1String("--ignore-invalid-packages")) { continue; } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { compileResource = true; #ifdef Q_OS_MACOS } else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) { ++it; if (it == args.end() || it->startsWith(QLatin1String("-"))) return printErrorAndUsageAndExit(QString::fromLatin1("Error: No code signing identity specified.")); signingIdentity = *it; #endif } else { if (it->startsWith(QLatin1String("-"))) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you " "are using an old syntax.").arg(*it)); } else if (target.isEmpty()) { target = *it; #ifdef Q_OS_WIN if (!target.endsWith(suffix)) target = target + suffix; #endif } else { return printErrorAndUsageAndExit(QString::fromLatin1("Error: You are using an old syntax please add the " "component name with the include option") .arg(*it)); } } } if (onlineOnly && offlineOnly) { return printErrorAndUsageAndExit(QString::fromLatin1("You cannot use --online-only and " "--offline-only at the same time.")); } if (onlineOnly) { filteredPackages.append(QLatin1String("X_fake_filter_component_for_online_only_installer_X")); ftype = QInstallerTools::Include; } if (target.isEmpty() && !compileResource) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing.")); if (configFile.isEmpty()) return printErrorAndUsageAndExit(QString::fromLatin1("Error: No configuration file selected.")); if (packagesDirectories.isEmpty() && repositoryDirectories.isEmpty()) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Both Package directory and Repository parameters missing.")); qDebug() << "Parsed arguments, ok."; Input input; int exitCode = EXIT_FAILURE; QTemporaryDir tmp; tmp.setAutoRemove(false); const QString tmpMetaDir = tmp.path(); QTemporaryDir tmp2; tmp2.setAutoRemove(false); const QString tmpRepoDir = tmp2.path(); try { const Settings settings = Settings::fromFileAndPrefix(configFile, QFileInfo(configFile) .absolutePath()); // Note: the order here is important QInstallerTools::PackageInfoVector packages; // 1; update the list of available compressed packages if (!repositoryDirectories.isEmpty()) { // 1.1; search packages QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories, &filteredPackages, ftype); // 1.2; add to common vector packages.append(precompressedPackages); } // 2; update the list of available prepared packages if (!packagesDirectories.isEmpty()) { // 2.1; search packages QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories, &filteredPackages, ftype); // 2.2; copy the packages data and setup the packages vector with the files we copied, // must happen before copying meta data because files will be compressed if // needed and meta data generation relies on this QInstallerTools::copyComponentData(packagesDirectories, tmpRepoDir, &preparedPackages); // 2.3; add to common vector packages.append(preparedPackages); } // 3; copy the meta data of the available packages, generate Updates.xml QInstallerTools::copyMetaData(tmpMetaDir, tmpRepoDir, packages, settings .applicationName(), settings.version(), QStringList()); // 4; copy the configuration file and and icons etc. copyConfigData(configFile, tmpMetaDir + QLatin1String("/installer-config")); { QSettings confInternal(tmpMetaDir + QLatin1String("/config/config-internal.ini") , QSettings::IniFormat); // assume offline installer if there are no repositories and no //--online-only not set offlineOnly = offlineOnly | settings.repositories().isEmpty(); if (onlineOnly) offlineOnly = !onlineOnly; confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly); } #ifdef Q_OS_MACOS // on mac, we enforce building a bundle if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) target += QLatin1String(".app"); #endif if (!compileResource) { // 5; put the copied resources into a resource file QInstaller::ResourceCollection metaCollection("QResources"); metaCollection.appendResource(createDefaultResourceFile(tmpMetaDir, generateTemporaryFileName())); metaCollection.appendResources(createBinaryResourceFiles(resources)); input.manager.insertCollection(metaCollection); input.packages = packages; input.outputPath = target; input.installerExePath = templateBinary; qDebug() << "Creating the binary"; exitCode = assemble(input, settings, signingIdentity); } else { createDefaultResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc")); exitCode = EXIT_SUCCESS; } } catch (const Error &e) { QFile::remove(input.outputPath); std::cerr << "Caught exception: " << e.message() << std::endl; } catch (...) { QFile::remove(input.outputPath); std::cerr << "Unknown exception caught" << std::endl; } qDebug() << "Cleaning up..."; const QInstaller::ResourceCollection collection = input.manager.collectionByName("QResources"); foreach (const QSharedPointer &resource, collection.resources()) QFile::remove(QString::fromUtf8(resource->name())); QInstaller::removeDirectory(tmpMetaDir, true); QInstaller::removeDirectory(tmpRepoDir, true); return exitCode; } qt-installer-framework-4.0.1/tools/binarycreator/binarycreator.pro0100777000000000000000000000066513761647206022501 0ustar00TEMPLATE = app TARGET = binarycreator INCLUDEPATH += . .. rcc ../common include(../../installerfw.pri) QT -= gui QT += qml xml CONFIG += console DESTDIR = $$IFW_APP_PATH SOURCES = binarycreator.cpp \ rcc/rcc.cpp \ rcc/rccmain.cpp \ ../common/repositorygen.cpp HEADERS = rcc/rcc.h RESOURCES += binarycreator.qrc macx:include(../../no_app_bundle.pri) target.path = $$[QT_INSTALL_BINS] INSTALLS += target qt-installer-framework-4.0.1/tools/binarycreator/binarycreator.qrc0100777000000000000000000000037113761647206022460 0ustar00 resources/default_icon_mac.icns resources/copylibsintobundle.sh ../../src/sdk/installerbase.ico qt-installer-framework-4.0.1/tools/binarycreator/rcc/0040777000000000000000000000000013761647206017653 5ustar00qt-installer-framework-4.0.1/tools/binarycreator/rcc/qcorecmdlineargs_p.h0100777000000000000000000000356013761647206023671 0ustar00/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QCORECMDLINEARGS_P_H #define QCORECMDLINEARGS_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "QtCore/qstring.h" #include "QtCore/qstringlist.h" QT_BEGIN_NAMESPACE static inline QStringList qCmdLineArgs(int argc, char *argv[]) { QStringList args; for (int i = 0; i != argc; ++i) args += QString::fromLocal8Bit(argv[i]); return args; } QT_END_NAMESPACE #endif // QCORECMDLINEARGS_WIN_P_H qt-installer-framework-4.0.1/tools/binarycreator/rcc/rcc.cpp0100777000000000000000000010332713761647206021134 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "rcc.h" #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE enum { CONSTANT_USENAMESPACE = 1, CONSTANT_COMPRESSLEVEL_DEFAULT = -1, CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70 }; #define writeString(s) write(s, sizeof(s)) void RCCResourceLibrary::write(const char *str, int len) { --len; // trailing \0 on string literals... int n = m_out.size(); m_out.resize(n + len); memcpy(m_out.data() + n, str, len); } void RCCResourceLibrary::writeByteArray(const QByteArray &other) { m_out.append(other); } static inline QString msgOpenReadFailed(const QString &fname, const QString &why) { return QString::fromUtf8("Unable to open %1 for reading: %2\n").arg(fname).arg(why); } /////////////////////////////////////////////////////////// // // RCCFileInfo // /////////////////////////////////////////////////////////// class RCCFileInfo { public: enum Flags { NoFlags = 0x00, Compressed = 0x01, Directory = 0x02 }; RCCFileInfo(const QString &name = QString(), const QFileInfo &fileInfo = QFileInfo(), QLocale::Language language = QLocale::C, QLocale::Country country = QLocale::AnyCountry, uint flags = NoFlags, int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT, int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT); ~RCCFileInfo(); QString resourceName() const; public: qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage); qint64 writeDataName(RCCResourceLibrary &, qint64 offset); void writeDataInfo(RCCResourceLibrary &lib); int m_flags; QString m_name; QLocale::Language m_language; QLocale::Country m_country; QFileInfo m_fileInfo; RCCFileInfo *m_parent; QHash m_children; int m_compressLevel; int m_compressThreshold; qint64 m_nameOffset; qint64 m_dataOffset; qint64 m_childOffset; }; RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, QLocale::Country country, uint flags, int compressLevel, int compressThreshold) { m_name = name; m_fileInfo = fileInfo; m_language = language; m_country = country; m_flags = flags; m_parent = nullptr; m_nameOffset = 0; m_dataOffset = 0; m_childOffset = 0; m_compressLevel = compressLevel; m_compressThreshold = compressThreshold; } RCCFileInfo::~RCCFileInfo() { qDeleteAll(m_children); } QString RCCFileInfo::resourceName() const { QString resource = m_name; for (RCCFileInfo *p = m_parent; p; p = p->m_parent) resource = resource.prepend(p->m_name + QLatin1Char('/')); return QLatin1Char(':') + resource; } void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) { const bool text = (lib.m_format == RCCResourceLibrary::C_Code); //some info if (text) { if (m_language != QLocale::C) { lib.writeString(" // "); lib.writeByteArray(resourceName().toLocal8Bit()); lib.writeString(" ["); lib.writeByteArray(QByteArray::number(m_country)); lib.writeString("::"); lib.writeByteArray(QByteArray::number(m_language)); lib.writeString("[\n "); } else { lib.writeString(" // "); lib.writeByteArray(resourceName().toLocal8Bit()); lib.writeString("\n "); } } //pointer data if (m_flags & RCCFileInfo::Directory) { // name offset lib.writeNumber4(m_nameOffset); // flags lib.writeNumber2(m_flags); // child count lib.writeNumber4(m_children.size()); // first child offset lib.writeNumber4(m_childOffset); } else { // name offset lib.writeNumber4(m_nameOffset); // flags lib.writeNumber2(m_flags); // locale lib.writeNumber2(m_country); lib.writeNumber2(m_language); //data offset lib.writeNumber4(m_dataOffset); } if (text) lib.writeChar('\n'); } qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage) { const bool text = (lib.m_format == RCCResourceLibrary::C_Code); //capture the offset m_dataOffset = offset; //find the data to be written QFile file(m_fileInfo.absoluteFilePath()); if (!file.open(QFile::ReadOnly)) { *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString()); return 0; } QByteArray data = file.readAll(); #ifndef QT_NO_COMPRESS // Check if compression is useful for this file if (m_compressLevel != 0 && data.size() != 0) { QByteArray compressed = qCompress(reinterpret_cast(data.data()), data.size(), m_compressLevel); int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size()); if (compressRatio >= m_compressThreshold) { data = compressed; m_flags |= Compressed; } } #endif // QT_NO_COMPRESS // some info if (text) { lib.writeString(" // "); lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit()); lib.writeString("\n "); } // write the length lib.writeNumber4(data.size()); if (text) lib.writeString("\n "); offset += 4; // write the payload const char *p = data.constData(); if (text) { for (int i = data.size(), j = 0; --i >= 0; --j) { lib.writeHex(*p++); if (j == 0) { lib.writeString("\n "); j = 16; } } } else { for (int i = data.size(); --i >= 0; ) lib.writeChar(*p++); } offset += data.size(); // done if (text) lib.writeString("\n "); return offset; } qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) { const bool text = (lib.m_format == RCCResourceLibrary::C_Code); // capture the offset m_nameOffset = offset; // some info if (text) { lib.writeString(" // "); lib.writeByteArray(m_name.toLocal8Bit()); lib.writeString("\n "); } // write the length lib.writeNumber2(m_name.length()); if (text) lib.writeString("\n "); offset += 2; // write the hash lib.writeNumber4(qt_hash(m_name)); if (text) lib.writeString("\n "); offset += 4; // write the m_name const QChar *unicode = m_name.unicode(); for (int i = 0; i < m_name.length(); ++i) { lib.writeNumber2(unicode[i].unicode()); if (text && i % 16 == 0) lib.writeString("\n "); } offset += m_name.length()*2; // done if (text) lib.writeString("\n "); return offset; } /////////////////////////////////////////////////////////// // // RCCResourceLibrary // /////////////////////////////////////////////////////////// RCCResourceLibrary::Strings::Strings() : TAG_RCC(QLatin1String("RCC")), TAG_RESOURCE(QLatin1String("qresource")), TAG_FILE(QLatin1String("file")), ATTRIBUTE_LANG(QLatin1String("lang")), ATTRIBUTE_PREFIX(QLatin1String("prefix")), ATTRIBUTE_ALIAS(QLatin1String("alias")), ATTRIBUTE_THRESHOLD(QLatin1String("threshold")), ATTRIBUTE_COMPRESS(QLatin1String("compress")) { } RCCResourceLibrary::RCCResourceLibrary() : m_root(nullptr), m_format(C_Code), m_verbose(false), m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT), m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT), m_treeOffset(0), m_namesOffset(0), m_dataOffset(0), m_useNameSpace(CONSTANT_USENAMESPACE), m_errorDevice(nullptr) { m_out.reserve(30 * 1000 * 1000); } RCCResourceLibrary::~RCCResourceLibrary() { delete m_root; } enum RCCXmlTag { RccTag, ResourceTag, FileTag }; bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, const QString &fname, QString currentPath, bool ignoreErrors) { Q_ASSERT(m_errorDevice); const QChar slash = QLatin1Char('/'); if (!currentPath.isEmpty() && !currentPath.endsWith(slash)) currentPath += slash; QXmlStreamReader reader(inputDevice); QStack tokens; QString prefix; QLocale::Language language = QLocale::c().language(); QLocale::Country country = QLocale::c().country(); QString alias; int compressLevel = m_compressLevel; int compressThreshold = m_compressThreshold; while (!reader.atEnd()) { QXmlStreamReader::TokenType t = reader.readNext(); switch (t) { case QXmlStreamReader::StartElement: if (reader.name() == m_strings.TAG_RCC) { if (!tokens.isEmpty()) reader.raiseError(QLatin1String("expected tag")); else tokens.push(RccTag); } else if (reader.name() == m_strings.TAG_RESOURCE) { if (tokens.isEmpty() || tokens.top() != RccTag) { reader.raiseError(QLatin1String("unexpected tag")); } else { tokens.push(ResourceTag); QXmlStreamAttributes attributes = reader.attributes(); language = QLocale::c().language(); country = QLocale::c().country(); if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) { QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString(); QLocale lang = QLocale(attribute); language = lang.language(); if (2 == attribute.length()) { // Language only country = QLocale::AnyCountry; } else { country = lang.country(); } } prefix.clear(); if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX)) prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString(); if (!prefix.startsWith(slash)) prefix.prepend(slash); if (!prefix.endsWith(slash)) prefix += slash; } } else if (reader.name() == m_strings.TAG_FILE) { if (tokens.isEmpty() || tokens.top() != ResourceTag) { reader.raiseError(QLatin1String("unexpected tag")); } else { tokens.push(FileTag); QXmlStreamAttributes attributes = reader.attributes(); alias.clear(); if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS)) alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString(); compressLevel = m_compressLevel; if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt(); compressThreshold = m_compressThreshold; if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD)) compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt(); // Special case for -no-compress. Overrides all other settings. if (m_compressLevel == -2) compressLevel = 0; } } else { reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString())); } break; case QXmlStreamReader::EndElement: if (reader.name() == m_strings.TAG_RCC) { if (!tokens.isEmpty() && tokens.top() == RccTag) tokens.pop(); else reader.raiseError(QLatin1String("unexpected closing tag")); } else if (reader.name() == m_strings.TAG_RESOURCE) { if (!tokens.isEmpty() && tokens.top() == ResourceTag) tokens.pop(); else reader.raiseError(QLatin1String("unexpected closing tag")); } else if (reader.name() == m_strings.TAG_FILE) { if (!tokens.isEmpty() && tokens.top() == FileTag) tokens.pop(); else reader.raiseError(QLatin1String("unexpected closing tag")); } break; case QXmlStreamReader::Characters: if (reader.isWhitespace()) break; if (tokens.isEmpty() || tokens.top() != FileTag) { reader.raiseError(QLatin1String("unexpected text")); } else { QString fileName = reader.text().toString(); if (fileName.isEmpty()) { const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname); m_errorDevice->write(msg.toUtf8()); } if (alias.isNull()) alias = fileName; alias = QDir::cleanPath(alias); while (alias.startsWith(QLatin1String("../"))) alias.remove(0, 3); alias = QDir::cleanPath(m_resourceRoot) + prefix + alias; QString absFileName = fileName; if (QDir::isRelativePath(absFileName)) absFileName.prepend(currentPath); QFileInfo file(absFileName); if (!file.exists()) { m_failedResources.push_back(absFileName); const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName); m_errorDevice->write(msg.toUtf8()); if (ignoreErrors) continue; else return false; } else if (file.isFile()) { const bool arc = addFile(alias, RCCFileInfo(alias.section(slash, -1), file, language, country, RCCFileInfo::NoFlags, compressLevel, compressThreshold) ); if (!arc) m_failedResources.push_back(absFileName); } else { QDir dir; if (file.isDir()) { dir.setPath(file.filePath()); } else { dir.setPath(file.path()); dir.setNameFilters(QStringList(file.fileName())); if (alias.endsWith(file.fileName())) alias = alias.left(alias.length()-file.fileName().length()); } if (!alias.endsWith(slash)) alias += slash; QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); QFileInfo child(it.fileInfo()); if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) { const bool arc = addFile(alias + child.fileName(), RCCFileInfo(child.fileName(), child, language, country, child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags, compressLevel, compressThreshold) ); if (!arc) m_failedResources.push_back(child.fileName()); } } } } break; default: break; } } if (reader.hasError()) { if (ignoreErrors) return true; int errorLine = reader.lineNumber(); int errorColumn = reader.columnNumber(); QString errorMessage = reader.errorString(); QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage); m_errorDevice->write(msg.toUtf8()); return false; } if (m_root == nullptr) { const QString msg = QString::fromUtf8("RCC: Warning: No resources in '%1'.\n").arg(fname); m_errorDevice->write(msg.toUtf8()); if (!ignoreErrors && m_format == Binary) { // create dummy entry, otherwise loading with QResource will crash m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); } } return true; } bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) { Q_ASSERT(m_errorDevice); if (file.m_fileInfo.size() > 0xffffffff) { const QString msg = QString::fromUtf8("File too big: %1\n").arg(file.m_fileInfo.absoluteFilePath()); m_errorDevice->write(msg.toUtf8()); return false; } if (!m_root) m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); RCCFileInfo *parent = m_root; const QStringList nodes = alias.split(QLatin1Char('/')); for (int i = 1; i < nodes.size()-1; ++i) { const QString node = nodes.at(i); if (node.isEmpty()) continue; if (!parent->m_children.contains(node)) { RCCFileInfo *s = new RCCFileInfo(node, QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); s->m_parent = parent; parent->m_children.insert(node, s); parent = s; } else { parent = parent->m_children[node]; } } const QString filename = nodes.at(nodes.size()-1); RCCFileInfo *s = new RCCFileInfo(file); s->m_parent = parent; if (parent->m_children.contains(filename)) { foreach (const QString &fileName, m_fileNames) qWarning("%s: Warning: potential duplicate alias detected: '%s'", qPrintable(fileName), qPrintable(filename)); } parent->m_children.insertMulti(filename, s); return true; } void RCCResourceLibrary::reset() { if (m_root) { delete m_root; m_root = nullptr; } m_errorDevice = nullptr; m_failedResources.clear(); } bool RCCResourceLibrary::readFiles(bool ignoreErrors, QIODevice &errorDevice) { reset(); m_errorDevice = &errorDevice; //read in data if (m_verbose) { const QString msg = QString::fromUtf8("Processing %1 files [%2]\n") .arg(m_fileNames.size()).arg(static_cast(ignoreErrors)); m_errorDevice->write(msg.toUtf8()); } for (int i = 0; i < m_fileNames.size(); ++i) { QFile fileIn; QString fname = m_fileNames.at(i); QString pwd; if (fname == QLatin1String("-")) { fname = QLatin1String("(stdin)"); pwd = QDir::currentPath(); fileIn.setFileName(fname); if (!fileIn.open(stdin, QIODevice::ReadOnly)) { m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8()); return false; } } else { pwd = QFileInfo(fname).path(); fileIn.setFileName(fname); if (!fileIn.open(QIODevice::ReadOnly)) { m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8()); return false; } } if (m_verbose) { const QString msg = QString::fromUtf8("Interpreting %1\n").arg(fname); m_errorDevice->write(msg.toUtf8()); } if (!interpretResourceFile(&fileIn, fname, pwd, ignoreErrors)) return false; } return true; } QStringList RCCResourceLibrary::dataFiles() const { QStringList ret; QStack pending; if (!m_root) return ret; pending.push(m_root); while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for (QHash::iterator it = file->m_children.begin(); it != file->m_children.end(); ++it) { RCCFileInfo *child = it.value(); if (child->m_flags & RCCFileInfo::Directory) pending.push(child); ret.append(child->m_fileInfo.filePath()); } } return ret; } // Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m) { typedef QHash::const_iterator ChildConstIterator; const QChar slash = QLatin1Char('/'); const ChildConstIterator cend = m_root->m_children.constEnd(); for (ChildConstIterator it = m_root->m_children.constBegin(); it != cend; ++it) { const RCCFileInfo *child = it.value(); QString childName = path; childName += slash; childName += child->m_name; if (child->m_flags & RCCFileInfo::Directory) { resourceDataFileMapRecursion(child, childName, m); } else { m.insert(childName, child->m_fileInfo.filePath()); } } } RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap() const { ResourceDataFileMap rc; if (m_root) resourceDataFileMapRecursion(m_root, QString(QLatin1Char(':')), rc); return rc; } bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice) { m_errorDevice = &errorDevice; //write out if (m_verbose) m_errorDevice->write("Outputting code\n"); if (!writeHeader()) { m_errorDevice->write("Cannot write header\n"); return false; } if (m_root) { if (!writeDataBlobs()) { m_errorDevice->write("Cannot write data blobs.\n"); return false; } if (!writeDataNames()) { m_errorDevice->write("Cannot write file names\n"); return false; } if (!writeDataStructure()) { m_errorDevice->write("Cannot write data tree\n"); return false; } } if (!writeInitializer()) { m_errorDevice->write("Cannot write footer\n"); return false; } outDevice.write(m_out.constData(), m_out.size()); return true; } void RCCResourceLibrary::writeHex(quint8 tmp) { const char digits[] = "0123456789abcdef"; writeChar('0'); writeChar('x'); if (tmp < 16) { writeChar(digits[tmp]); } else { writeChar(digits[tmp >> 4]); writeChar(digits[tmp & 0xf]); } writeChar(','); } void RCCResourceLibrary::writeNumber2(quint16 number) { if (m_format == RCCResourceLibrary::Binary) { writeChar(number >> 8); writeChar(number); } else { writeHex(number >> 8); writeHex(number); } } void RCCResourceLibrary::writeNumber4(quint32 number) { if (m_format == RCCResourceLibrary::Binary) { writeChar(number >> 24); writeChar(number >> 16); writeChar(number >> 8); writeChar(number); } else { writeHex(number >> 24); writeHex(number >> 16); writeHex(number >> 8); writeHex(number); } } bool RCCResourceLibrary::writeHeader() { if (m_format == C_Code) { writeString("/****************************************************************************\n"); writeString("** Resource object code\n"); writeString("**\n"); writeString("** Created: "); writeByteArray(QDateTime::currentDateTime().toString().toLatin1()); writeString("\n** by: The Resource Compiler for Qt version "); writeByteArray(QT_VERSION_STR); writeString("\n**\n"); writeString("** WARNING! All changes made in this file will be lost!\n"); writeString( "*****************************************************************************/\n\n"); writeString("#include \n\n"); } else if (m_format == Binary) { writeString("qres"); writeNumber4(0); writeNumber4(0); writeNumber4(0); writeNumber4(0); } return true; } bool RCCResourceLibrary::writeDataBlobs() { Q_ASSERT(m_errorDevice); if (m_format == C_Code) writeString("static const unsigned char qt_resource_data[] = {\n"); else if (m_format == Binary) m_dataOffset = m_out.size(); QStack pending; if (!m_root) return false; pending.push(m_root); qint64 offset = 0; QString errorMessage; while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for (QHash::iterator it = file->m_children.begin(); it != file->m_children.end(); ++it) { RCCFileInfo *child = it.value(); if (child->m_flags & RCCFileInfo::Directory) pending.push(child); else { offset = child->writeDataBlob(*this, offset, &errorMessage); if (offset == 0) { m_errorDevice->write(errorMessage.toUtf8()); return false; } } } } if (m_format == C_Code) writeString("\n};\n\n"); return true; } bool RCCResourceLibrary::writeDataNames() { if (m_format == C_Code) writeString("static const unsigned char qt_resource_name[] = {\n"); else if (m_format == Binary) m_namesOffset = m_out.size(); QHash names; QStack pending; if (!m_root) return false; pending.push(m_root); qint64 offset = 0; while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for (QHash::iterator it = file->m_children.begin(); it != file->m_children.end(); ++it) { RCCFileInfo *child = it.value(); if (child->m_flags & RCCFileInfo::Directory) pending.push(child); if (names.contains(child->m_name)) { child->m_nameOffset = names.value(child->m_name); } else { names.insert(child->m_name, offset); offset = child->writeDataName(*this, offset); } } } if (m_format == C_Code) writeString("\n};\n\n"); return true; } static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right) { return qt_hash(left->m_name) < qt_hash(right->m_name); } bool RCCResourceLibrary::writeDataStructure() { if (m_format == C_Code) writeString("static const unsigned char qt_resource_struct[] = {\n"); else if (m_format == Binary) m_treeOffset = m_out.size(); QStack pending; if (!m_root) return false; //calculate the child offsets (flat) pending.push(m_root); int offset = 1; while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); file->m_childOffset = offset; //sort by hash value for binary lookup QList m_children = file->m_children.values(); qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); //write out the actual data now for (int i = 0; i < m_children.size(); ++i) { RCCFileInfo *child = m_children.at(i); ++offset; if (child->m_flags & RCCFileInfo::Directory) pending.push(child); } } //write out the structure (ie iterate again!) pending.push(m_root); m_root->writeDataInfo(*this); while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); //sort by hash value for binary lookup QList m_children = file->m_children.values(); qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); //write out the actual data now for (int i = 0; i < m_children.size(); ++i) { RCCFileInfo *child = m_children.at(i); child->writeDataInfo(*this); if (child->m_flags & RCCFileInfo::Directory) pending.push(child); } } if (m_format == C_Code) writeString("\n};\n\n"); return true; } void RCCResourceLibrary::writeMangleNamespaceFunction(const QByteArray &name) { if (m_useNameSpace) { writeString("QT_MANGLE_NAMESPACE("); writeByteArray(name); writeChar(')'); } else { writeByteArray(name); } } void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name) { if (m_useNameSpace) { writeString("QT_PREPEND_NAMESPACE("); writeByteArray(name); writeChar(')'); } else { writeByteArray(name); } } bool RCCResourceLibrary::writeInitializer() { if (m_format == C_Code) { //write("\nQT_BEGIN_NAMESPACE\n"); QString initName = m_initName; if (!initName.isEmpty()) { initName.prepend(QLatin1Char('_')); initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_")); } //init if (m_useNameSpace) writeString("QT_BEGIN_NAMESPACE\n\n"); if (m_root) { writeString("extern Q_CORE_EXPORT bool qRegisterResourceData\n " "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n " "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); } if (m_useNameSpace) writeString("QT_END_NAMESPACE\n\n\n"); QString initResources = QLatin1String("qInitResources"); initResources += initName; writeString("int "); writeMangleNamespaceFunction(initResources.toLatin1()); writeString("()\n{\n"); if (m_root) { writeString(" "); writeAddNamespaceFunction("qRegisterResourceData"); writeString("\n (0x01, qt_resource_struct, " "qt_resource_name, qt_resource_data);\n"); } writeString(" return 1;\n"); writeString("}\n\n"); writeString("Q_CONSTRUCTOR_FUNCTION("); writeMangleNamespaceFunction(initResources.toLatin1()); writeString(")\n\n"); //cleanup QString cleanResources = QLatin1String("qCleanupResources"); cleanResources += initName; writeString("int "); writeMangleNamespaceFunction(cleanResources.toLatin1()); writeString("()\n{\n"); if (m_root) { writeString(" "); writeAddNamespaceFunction("qUnregisterResourceData"); writeString("\n (0x01, qt_resource_struct, " "qt_resource_name, qt_resource_data);\n"); } writeString(" return 1;\n"); writeString("}\n\n"); writeString("Q_DESTRUCTOR_FUNCTION("); writeMangleNamespaceFunction(cleanResources.toLatin1()); writeString(")\n\n"); } else if (m_format == Binary) { int i = 4; char *p = m_out.data(); p[i++] = 0; // 0x01 p[i++] = 0; p[i++] = 0; p[i++] = 1; p[i++] = (m_treeOffset >> 24) & 0xff; p[i++] = (m_treeOffset >> 16) & 0xff; p[i++] = (m_treeOffset >> 8) & 0xff; p[i++] = (m_treeOffset >> 0) & 0xff; p[i++] = (m_dataOffset >> 24) & 0xff; p[i++] = (m_dataOffset >> 16) & 0xff; p[i++] = (m_dataOffset >> 8) & 0xff; p[i++] = (m_dataOffset >> 0) & 0xff; p[i++] = (m_namesOffset >> 24) & 0xff; p[i++] = (m_namesOffset >> 16) & 0xff; p[i++] = (m_namesOffset >> 8) & 0xff; p[i++] = (m_namesOffset >> 0) & 0xff; } return true; } QT_END_NAMESPACE qt-installer-framework-4.0.1/tools/binarycreator/rcc/rcc.h0100777000000000000000000001102513761647206020572 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef RCC_H #define RCC_H #include #include #include QT_BEGIN_NAMESPACE class RCCFileInfo; class QIODevice; class QTextStream; class RCCResourceLibrary { RCCResourceLibrary(const RCCResourceLibrary &); RCCResourceLibrary &operator=(const RCCResourceLibrary &); public: RCCResourceLibrary(); ~RCCResourceLibrary(); bool output(QIODevice &out, QIODevice &errorDevice); bool readFiles(bool ignoreErrors, QIODevice &errorDevice); enum Format { Binary, C_Code }; void setFormat(Format f) { m_format = f; } Format format() const { return m_format; } void setInputFiles(const QStringList &files) { m_fileNames = files; } QStringList inputFiles() const { return m_fileNames; } QStringList dataFiles() const; // Return a map of resource identifier (':/newPrefix/images/p1.png') to file. typedef QHash ResourceDataFileMap; ResourceDataFileMap resourceDataFileMap() const; void setVerbose(bool b) { m_verbose = b; } bool verbose() const { return m_verbose; } void setInitName(const QString &name) { m_initName = name; } QString initName() const { return m_initName; } void setCompressLevel(int c) { m_compressLevel = c; } int compressLevel() const { return m_compressLevel; } void setCompressThreshold(int t) { m_compressThreshold = t; } int compressThreshold() const { return m_compressThreshold; } void setResourceRoot(const QString &root) { m_resourceRoot = root; } QString resourceRoot() const { return m_resourceRoot; } void setUseNameSpace(bool v) { m_useNameSpace = v; } bool useNameSpace() const { return m_useNameSpace; } QStringList failedResources() const { return m_failedResources; } private: struct Strings { Strings(); const QString TAG_RCC; const QString TAG_RESOURCE; const QString TAG_FILE; const QString ATTRIBUTE_LANG; const QString ATTRIBUTE_PREFIX; const QString ATTRIBUTE_ALIAS; const QString ATTRIBUTE_THRESHOLD; const QString ATTRIBUTE_COMPRESS; }; friend class RCCFileInfo; void reset(); bool addFile(const QString &alias, const RCCFileInfo &file); bool interpretResourceFile(QIODevice *inputDevice, const QString &file, QString currentPath = QString(), bool ignoreErrors = false); bool writeHeader(); bool writeDataBlobs(); bool writeDataNames(); bool writeDataStructure(); bool writeInitializer(); void writeMangleNamespaceFunction(const QByteArray &name); void writeAddNamespaceFunction(const QByteArray &name); void writeHex(quint8 number); void writeNumber2(quint16 number); void writeNumber4(quint32 number); void writeChar(char c) { m_out.append(c); } void writeByteArray(const QByteArray &); void write(const char *, int len); const Strings m_strings; RCCFileInfo *m_root; QStringList m_fileNames; QString m_resourceRoot; QString m_initName; Format m_format; bool m_verbose; int m_compressLevel; int m_compressThreshold; int m_treeOffset; int m_namesOffset; int m_dataOffset; bool m_useNameSpace; QStringList m_failedResources; QIODevice *m_errorDevice; QByteArray m_out; }; QT_END_NAMESPACE #endif // RCC_H qt-installer-framework-4.0.1/tools/binarycreator/rcc/rccmain.cpp0100777000000000000000000002147713761647206022006 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include "qcorecmdlineargs_p.h" #include #include #include #include #include QT_BEGIN_NAMESPACE void showHelp(const QString &argv0, const QString &error) { fprintf(stderr, "Qt resource compiler\n"); if (!error.isEmpty()) fprintf(stderr, "%s: %s\n", qPrintable(argv0), qPrintable(error)); fprintf(stderr, "Usage: %s [options] \n\n" "Options:\n" " -o file write output to file rather than stdout\n" " -name name create an external initialization function with name\n" " -threshold level threshold to consider compressing files\n" " -compress level compress input files by level\n" " -root path prefix resource access path with root path\n" " -no-compress disable all compression\n" " -binary output a binary file for use as a dynamic resource\n" " -namespace turn off namespace macros\n" " -project Output a resource file containing all\n" " files from the current directory\n" " -version display version\n" " -help display this information\n", qPrintable(argv0)); } void dumpRecursive(const QDir &dir, QTextStream &out) { QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); foreach (const QFileInfo &entry, entries) { if (entry.isDir()) { dumpRecursive(entry.filePath(), out); } else { out << QLatin1String("") << entry.filePath() << QLatin1String("\n"); } } } int createProject(const QString &outFileName) { QDir currentDir = QDir::current(); QString currentDirName = currentDir.dirName(); if (currentDirName.isEmpty()) currentDirName = QLatin1String("root"); QFile file; bool isOk = false; if (outFileName.isEmpty()) { isOk = file.open(stdout, QFile::WriteOnly | QFile::Text); } else { file.setFileName(outFileName); isOk = file.open(QFile::WriteOnly | QFile::Text); } if (!isOk) { fprintf(stderr, "Unable to open %s: %s\n", outFileName.isEmpty() ? qPrintable(outFileName) : "standard output", qPrintable(file.errorString())); return 1; } QTextStream out(&file); out << QLatin1String("\n" "\n"); // use "." as dir to get relative file paths dumpRecursive(QDir(QLatin1String(".")), out); out << QLatin1String("\n" "\n"); return 0; } int runRcc(int argc, char *argv[]) { QString outFilename; bool helpRequested = false; bool list = false; bool projectRequested = false; QStringList filenamesIn; QStringList args = qCmdLineArgs(argc, argv); RCCResourceLibrary library; //parse options QString errorMsg; for (int i = 1; i < args.count() && errorMsg.isEmpty(); i++) { if (args[i].isEmpty()) continue; if (args[i][0] == QLatin1Char('-')) { // option QString opt = args[i]; if (opt == QLatin1String("-o")) { if (!(i < argc-1)) { errorMsg = QLatin1String("Missing output name"); break; } outFilename = args[++i]; } else if (opt == QLatin1String("-name")) { if (!(i < argc-1)) { errorMsg = QLatin1String("Missing target name"); break; } library.setInitName(args[++i]); } else if (opt == QLatin1String("-root")) { if (!(i < argc-1)) { errorMsg = QLatin1String("Missing root path"); break; } library.setResourceRoot(QDir::cleanPath(args[++i])); if (library.resourceRoot().isEmpty() || library.resourceRoot().at(0) != QLatin1Char('/')) errorMsg = QLatin1String("Root must start with a /"); } else if (opt == QLatin1String("-compress")) { if (!(i < argc-1)) { errorMsg = QLatin1String("Missing compression level"); break; } library.setCompressLevel(args[++i].toInt()); } else if (opt == QLatin1String("-threshold")) { if (!(i < argc-1)) { errorMsg = QLatin1String("Missing compression threshold"); break; } library.setCompressThreshold(args[++i].toInt()); } else if (opt == QLatin1String("-binary")) { library.setFormat(RCCResourceLibrary::Binary); } else if (opt == QLatin1String("-namespace")) { library.setUseNameSpace(!library.useNameSpace()); } else if (opt == QLatin1String("-verbose")) { library.setVerbose(true); } else if (opt == QLatin1String("-list")) { list = true; } else if (opt == QLatin1String("-version") || opt == QLatin1String("-v")) { fprintf(stderr, "Qt Resource Compiler version %s\n", QT_VERSION_STR); return 1; } else if (opt == QLatin1String("-help") || opt == QLatin1String("-h")) { helpRequested = true; } else if (opt == QLatin1String("-no-compress")) { library.setCompressLevel(-2); } else if (opt == QLatin1String("-project")) { projectRequested = true; } else { errorMsg = QString::fromLatin1("Unknown option: '%1'").arg(args[i]); } } else { if (!QFile::exists(args[i])) { qWarning("%s: File does not exist '%s'", qPrintable(args[0]), qPrintable(args[i])); return 1; } filenamesIn.append(args[i]); } } if (projectRequested && !helpRequested) { return createProject(outFilename); } if (!filenamesIn.size() || !errorMsg.isEmpty() || helpRequested) { showHelp(args[0], errorMsg); return 1; } QFile errorDevice; errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text); if (library.verbose()) errorDevice.write("Qt resource compiler\n"); library.setInputFiles(filenamesIn); if (!library.readFiles(list, errorDevice)) return 1; // open output QFile out; QIODevice::OpenMode mode = QIODevice::WriteOnly; if (library.format() == RCCResourceLibrary::C_Code) mode |= QIODevice::Text; if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { // using this overload close() only flushes. out.open(stdout, mode); } else { out.setFileName(outFilename); if (!out.open(mode)) { const QString msg = QString::fromUtf8("Unable to open %1 for writing: %2\n").arg(outFilename).arg(out.errorString()); errorDevice.write(msg.toUtf8()); return 1; } } // do the task if (list) { const QStringList data = library.dataFiles(); for (int i = 0; i < data.size(); ++i) { out.write(qPrintable(QDir::cleanPath(data.at(i)))); out.write("\n"); } return 0; } return library.output(out, errorDevice) ? 0 : 1; } QT_END_NAMESPACE qt-installer-framework-4.0.1/tools/binarycreator/resources/0040777000000000000000000000000013761647206021116 5ustar00qt-installer-framework-4.0.1/tools/binarycreator/resources/copylibsintobundle.sh0100777000000000000000000001550713761647206025372 0ustar00#!/bin/sh ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # this script puts all libs directly needed by the bundle into it QTDIR="" IS_DEBUG=0 HAVE_CORE=0 HAVE_SVG=0 HAVE_PHONON=0 HAVE_SCRIPT=0 HAVE_SQL=0 HAVE_WEBKIT=0 function handleFile() { local FILE=$1 local BUNDLE=$2 # all dynamic libs directly needed by the bundle, which are not in /System/Library or in /usr/lib (which are system default libs, which we don't want) local LIBS=`xcrun otool -L $FILE | grep -v 'executable_path' | grep -v '/System/Library' | grep -v '/usr/lib' | grep '/' | sed -ne 's,^ *\(.*\) (.*,\1,p'` local lib for lib in $LIBS; do local NAME=`basename $lib` if echo $NAME | grep 'QtCore' >/dev/null; then HAVE_CORE=1 QTDIR=`echo $lib | sed -ne 's,^\(.*\)/lib/[^/]*QtCore.*$,\1,p'` if echo $NAME | grep 'debug' >/dev/null; then IS_DEBUG=1 fi elif echo $NAME | grep 'QtSvg' >/dev/null; then HAVE_SVG=1 elif echo $NAME | grep 'phonon' >/dev/null; then HAVE_PHONON=1 elif echo $NAME | grep 'QtScript' >/dev/null; then HAVE_SCRIPT=1 elif echo $NAME | grep 'QtSql' >/dev/null; then HAVE_SQL=1 elif echo $NAME | grep 'QtWebKit' >/dev/null; then HAVE_WEBKIT=1 fi if [ `basename $FILE` != $NAME ]; then # this part handles libraries which are macOS frameworks if echo $lib | grep '\.framework' >/dev/null; then local FRAMEWORKPATH=`echo $lib | sed -ne 's,\(.*\.framework\).*,\1,p'` local FRAMEWORKNAME=`basename $FRAMEWORKPATH` local NEWFRAMEWORKPATH=`echo $lib | sed -ne "s,.*\($FRAMEWORKNAME\),\1,p"` # Qt installed via the precompled binaries... if [ $FRAMEWORKPATH = $FRAMEWORKNAME ]; then FRAMEWORKPATH="/Library/Frameworks/$FRAMEWORKNAME" if [ ! -e "$FRAMEWORKPATH" ]; then echo "Framework $FRAMEWORKNAME not found." exit 1 fi fi if [ ! -e "$BUNDLE/Contents/Frameworks/$NEWFRAMEWORKPATH" ]; then echo Embedding framework $FRAMEWORKNAME # copy the framework into the bundle cp -R $FRAMEWORKPATH $BUNDLE/Contents/Frameworks # remove debug libs we've copied find $BUNDLE/Contents/Frameworks/$FRAMEWORKNAME -regex '.*_debug\(\.dSYM\)*' | xargs rm -rf handleFile "$BUNDLE/Contents/Frameworks/$NEWFRAMEWORKPATH" "$BUNDLE" fi # and inform the dynamic linker about this xcrun install_name_tool -change $lib @executable_path/../Frameworks/$NEWFRAMEWORKPATH $FILE # this part handles 'normal' dynamic libraries (.dylib) else if [ ! -e "$BUNDLE/Contents/Frameworks/$NAME" ]; then echo Embedding library $NAME # Qt installed via the precompled binaries... if [ $lib = $NAME ]; then lib="/Library/Frameworks/$NAME" if [ ! -e "$lib" ]; then lib="/usr/lib/$NAME" fi if [ ! -e "$lib" ]; then echo "Library $NAME not found." exit 1 fi fi # copy the lib into the bundle cp $lib $BUNDLE/Contents/Frameworks handleFile "$BUNDLE/Contents/Frameworks/$NAME" "$BUNDLE" fi # and inform the dynamic linker about this xcrun install_name_tool -change $lib @executable_path/../Frameworks/$NAME $FILE fi fi done } function handleQtPlugins() { local PLUGINPATH=$QTDIR/plugins # QTDIR was not found, then we're using /Developer/Applications/Qt if [ "$PLUGINPATH" = "/plugins" ]; then PLUGINPATH="/Developer/Applications/Qt/plugins" fi CLASS=$1 EXECUTABLE=$2 BUNDLE=$3 mkdir -p $BUNDLE/Contents/plugins/$CLASS echo Add $CLASS plugins for plugin in `ls $PLUGINPATH/$CLASS/*`; do plugin=`basename $plugin` if echo $plugin | grep 'debug' >/dev/null; then #if [ $IS_DEBUG -eq 1 ]; then cp "$PLUGINPATH/$CLASS/$plugin" $BUNDLE/Contents/plugins/$CLASS xcrun install_name_tool -change $plugin @executable_path/../plugins/$CLASS/$plugin $EXECUTABLE handleFile $BUNDLE/Contents/plugins/$CLASS/$plugin $BUNDLE #fi else #if [ $IS_DEBUG -eq 0 ]; then cp "$PLUGINPATH/$CLASS/$plugin" $BUNDLE/Contents/plugins/$CLASS xcrun install_name_tool -change $plugin @executable_path/../plugins/$CLASS/$plugin $EXECUTABLE handleFile $BUNDLE/Contents/plugins/$CLASS/$plugin $BUNDLE #fi fi done } # the app bundle we're working with BUNDLE=$1 # the executable inside of the bundle EXECUTABLE=$BUNDLE/Contents/MacOS/`xargs < $BUNDLE/Contents/Info.plist | sed -ne 's,.*CFBundleExecutable \([^<]*\).*,\1,p'` mkdir -p $BUNDLE/Contents/Frameworks handleFile $EXECUTABLE $BUNDLE if [ $HAVE_CORE -eq 1 ]; then handleQtPlugins "imageformats" "$EXECUTABLE" "$BUNDLE" fi if [ $HAVE_SVG -eq 1 ]; then handleQtPlugins "iconengines" "$EXECUTABLE" "$BUNDLE" fi if [ $HAVE_PHONON -eq 1 ]; then handleQtPlugins "phonon_backend" "$EXECUTABLE" "$BUNDLE" fi if [ $HAVE_SQL -eq 1 ]; then handleQtPlugins "sqldrivers" "$EXECUTABLE" "$BUNDLE" fi if [ $HAVE_WEBKIT -eq 1 ]; then handleQtPlugins "codecs" "$EXECUTABLE" "$BUNDLE" fi qt-installer-framework-4.0.1/tools/binarycreator/resources/default_icon_mac.icns0100777000000000000000000035032013761647206025253 0ustar00icnsÐÐis32·ƒ1rlr1ˆ8‘Ž‘8ˆ@ĻĪĻ@… FjrtĄĢĒl`V- “ŅÜŠŽĨ’žŧŠ\ ĨŧŽz†‰f #ąÉ\UpjoY`p € 0ŊĘÆJ?Y?GŽo€ :Ŧšš™48Īs€ GŊđĀŧĨ^›ĨĶ”{€ SķģģēÎÚšœ™‚'€ `ÄĮĩĄ˜’•ž›Š-€ fĩķĖÆŧļļĐ Š5€ XœĄ›ĨŦ§ ‘Ž€3€ ,b;Wc]CBDitf€!€ %#ƒ1rlr1ˆ8‘Ž‘8ˆ@ĻĪĻ@… FjrtĄĢĒl`V- “ŅÜŠŽĨ’žŧŠ\ ĨŧŽ‚z…‰f #ąÉ\UpjoY_p € 0ŊĘÆJ@X?GŽo€ :Ŧšš™58Īs€ GŊđĀŧĨ^›ĨĶ”{€ SķģģēÎÚšœ™‚'€ `ÄĮĩĄ˜’•ž›Š-€ fĩķĖÆŧļļĐ Š5€ XœĄ›ĨŦ§ €3€ ,b;Wc]CBDivf€!€ %#ƒ1rlq1ˆ8‘Ž‘8ˆ@ĻĪĻ@… IlttĄĢĒmbX- —ÕÞŠŽĨ’ĄÁŪ_ Đŋ‘€Ž}‡k )·Î^TpkpX`–s € 0īÏĖL>Z?Gģ•s€ =ēŋŋž68•Ļ”x€ GĩŋÅĀŦa Ŧޚ€ € V―đđļŅßĀĄŸ•†'€ dĘĖŧĐ ˜–šĪĄ‘0€ iŧŧÐËĀ――ŊĶŽ‡8€ ]Ē§ĒŠŊŠĨ•”˜‡5€ 2kCbogKJOokr!€ %"" ' s8mk]·ŧ·]væëæv |ðõð| T‚ŧũúũŧ‚}?ģųúüĸĸĸüúö‹ Æĸĸĸĸĸĸĸĸý ,Ôĸĸĸĸĸĸĸĸþē;āĸĸĸĸĸĸĸĸĸÃKęĸĸĸĸĸĸĸĸĸŌ)]ņĸĸĸĸĸĸĸĸĸÞ7qöĸĸĸĸĸĸĸĸĸčH…úĸĸĸĸĸĸĸĸĸðZ ™ýĸĸĸĸĸĸĸĸĸõnýĸĸĸĸĸĸĸĸĸös …õúúúúúúúúúë]G’˜˜˜˜˜˜˜˜˜Š0il32ω)bf€hfb%”0{}€}{0”+ˆ†‰Š‰†ˆ+”0ĨŽēēģŽĨ.”-žĒĢĒž+”-™ŸĢĨ̟š-Z^y{{wešĢĪĶĢ̚_iki[M4‡*ŪĩØßÞᝋĶĒĢĒĨŽŒÁđšĻža‡8ÆČŽŌÃՉˆŸž Œ|š­Ļwķk‡GÎąĻäČ݈}–””’–}…ÎđÁgŪv †VŌÃÞĒ™Šmv‹‡‰ˆ‰z`•ƒmŠ~†cÓÏÛ:_|Xqzy{y{q^€dOk̇†tÖĮÕš>aud€k lietc<Đxš"†ÖĮČÜĀ6LaZ^]^Z_M8œĮp“—.…‰ÖČĮŧÍē5BUMPMSC4ŠĐuŒ™4…Ž…ŋĀšžŸ.5I?I5-ŽˆŦ„O€@… ĀĪÆÁķžŽ‚-%B$.y„‘ž§Ž›I…%ŽķĨÍ―ŋŧŦ‡,2ƒŽĄĪĄĢ}œU…1ī•đÄŧššđ‘‰O”†xģ  ›Ļh\…=ž‹ĩÁļđ·ĐâÞĐŊđÖĪ ž—Ķk‰f „KÂĶĒÂļīģēĶĖäÞÕŦœ žš™˜u’l„VÂļÎąģķŊąŪž››•š ›ššŽ—”’t„dÃŊČðĻĨąŪŽŽĐĨ̟ž–ƒĢŊ‰Žy„oÁīĐŋņÄ ™žĄžž›“Ž“ŧŧ„‹‰}%ƒ zÄĩīĻĐŲįÕŧĐĄœžĻļģŧĨ…Š‹+ƒ}n‘ĩ§Ī”žđÏÖÛÚÕŌī}|„†Jj4ƒ€ŠŋËÃÃÄ―°ŦĻŽŠĐĒĪŽŪĻĨĢĒ‘ˆ3„;vyCSZ_emxvS[W[YW]€yxw~h„#Yf(6KPSW[\8A6886>\qySfN „ Yf?4?KUZ^^GI€EDK_jl\mC„€‚€ Ą‰)bffhhfb%”0{}€}{0”+ˆ†‰Š‰†ˆ+”.ĨŽēģģŽĨ.”+žĒĢĒž+”-™ŸĢĨ̟›-Z^y{{we™ĢĢĶĢĄš_iki[M4‡*ŪĩØßÞᝌĶĒĢĒĨŽÁđšĻža‡8ÆČŽŌÃՉˆ žŸ‹|š­Ļwķk‡GÎąĻäČ݈}–’”’–~…ÎđÂgŪv †VŌÃÞ̚Šmv‹‡‰‡‰z`•ƒmŠ~†cÓÏÛ:`|Xqz{z{{q^dOk̇†tÖĮÕš>cudikmiidtd<Đxš"†ÖĮČÜĀ6LaZ^]\ZaL7œĮp“—.…‰ÖČĮŧÍē5BUMPMSC4ŠĐuŒ™4…Ž…ŋĀšžŸ/5I?I5-ŽˆŦ„O€@… ĀĪÆÁķžŽ‚-%B$.y„‘ž§Ž›I…%ŽķĨÍ―ŋŧŦ‡,0„ŽĄĪĄĢ}œU…1ī•đÄŧššđ‘‰O“†xģ  ›Ļh\…=ž‹ĩÁļđ·ĐâÞĐŊđÖĪ ž—Ķk‰f „KÂĶĒÂļīģēĶĖäÞÕŦœ žš™˜u’l„VÂļÎąģķŊąŪž››•š ›ššŽ—”’t„dÃŊČðĻĨąŪŽŽĐĨ̟ž–ƒĢŊ‰Žy„oÁīĐŋņÄ ™žĄžž›“Ž“ŧŧ„‹‰}%ƒ zÄĩīĻĐŲįÕŧĐĄœžĻļģŧĨ…Š‹+ƒ}n‘ĩ§Ī”žđÏÖÛÚÕŌī}|„†Jj4ƒ€ŠŋËÃÃÄ―°ŦĻŽŠĐĒĪŽŽĻĨĢĒ‘ˆ3„;vyCSZ_emxvS[W[ZW]€yxw~h„#Yf(6KPSW[\8A6866>\rzSfN „Yf?4?KUZ^^GIEFEEK_ln\mC„€‚€ Ą‰)bf€hfb%”0{}€}{0”+ˆ†‰Š‰†ˆ+”.ĨŽēģģŽĨ.”-žĒĢĒž+”-™ŸĢĨ̟š-Z`}{g™ĢĪĨĪ̚`€m]O9‡*ģžÞåãæ ‹ĶĒĢĒĨސĮĀĀŽĨe‡=ĘϰŅÁՈ‰ ž ŠĀą­|žn‡GÓķŪåČ߈}–’”’–}ˆÔūĮlģy †YŲĮā͜Žnv‰‰Š‡‹wc˜‡’pŊ„†eÚÕā8^~Xq|xz{zq\dNqό†xÜÍÚŋ>bvdkkmkietc;Ŋ}Ÿ”"†„ÜÍÍäÆ6JaZ_]^Z_L8ĒÎs™.…ÛÍÍŋŌđ5AUNONUC6ĢąŊ{‘ 7…’‰ÃÅĀĢĒ’.5I?I5-…“°ŠT†C…ĨÆĐËĮžĢ’†.%B$/~ˆ–ĪŪ“‡ĄK…+ēŧŠÓÃÄÁąŠ-2‡’ĶЧĒЂĢW…5š›ŋĘÁĀŋū˜ĒRšŒ}đĨ§ Ūm“`…@ÁŧÉŋū―ŊæáŪķūÚŠĶĶΜŽpi „MČŽĻĮūš·ļŦÏįāÜēĒĶĒ Ÿžz˜q„YČ―Ó·đ―īĩķĶĄĄ› ĶĪ Ą”š˜y„gÉĩÎņŊŦ·īēą­ŦĐĨĢĄœ‹Đģ”„sĮšŊÃņČĶĄĪ§ĨĨĄš•”™ÁÁŒ‘ƒ%ƒ ~ÉŧšŪŊÞëŨŋ°§ĒĢŽ―šĀŦ‹•ˆ.ƒt—ŧ­ŽœĢūŌŨÜÝØÔš“ƒ‚ІŒQp7ƒ†ŊÄÏÉĮČÁķą­ąąŪĐϰēŪĻǧ–8„@ƒH\cjpw‚Zc^aa^f‡‘”~ˆo„&es->UZ_bhg?J=??=DtURmpW „drE:EV_fjhNRKLLKRqMHnxI„€‚€ $Ąl8mk>‚……………‚>pÚßßßßßÚp~ðõõõõõð~{ðõõõôõð{wïõõõõõïw xðõõõõõïw ^€ƒšũúúúúúũđƒz6+Ėųųųųųüĸĸĸĸĸĸĸüųųųųóƒ;Þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü› Kčĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸþ­\ïĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸūoõĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖ'‚ųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŲ4 •üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸäCĻýĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸėTđþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸóg$Éĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũz0Öĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸû ?áĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸý Pëĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸþēcņĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ vöĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŅ, ŠúĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÝ;žüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸčK°þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸï^ Āĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõp#ŋþĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸôr üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸįTŒųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÜA wíũũũũũũøøøøøøøøøøøøøøũĘ4@ŸŸŸŸŸŸ              r*222222222222222222220! it32ghŽ€<˜;<ÛKc™|bKÛhž™™žhÛ“Īŧķ‘ĩķŧĢ“Û:>€G„F€EDEƒFGGF>:Û!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û}―œ€ž€žœūzÛ|ŋĄƒĢ‹ĪƒĢĄŋyÛ|ūĄ†Ģ…ΆĢĄūyÛ{― €Ē‘̀Ǡ―xÛzŧ ‚ĒĢ‚Ē ―xÛzšŸĄ…Ē…Ģ†ĒŸžvÛx🡕ĒĄŸđuÛx·ž‚ĄĒ‚ĄžđtÛwĩ€ ƒĄ…ĒƒĄ€ ķsÛvĩ€Ÿ  Ą  €ŸĩrÛuģ›žƒŸ‰ ƒŸž›ģqÛt皜žŸžœšēpÛq°™›€œž…Ÿž€œ›™°oÛrۘ›œˆ€œ›˜ŪnÛqŽ—š‚›œƒ›œƒ›€š™ŽmÃŌÎÍŨÔŨÐÏŌŌŅŅÐÐÏπÎ̀ĖË^nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl[šđļļ·ķĩĩīģ ēąŪŠĐŪŠ°ŽĐÆŠ ‘ÖŌ҇O|ÏŅÓӁŅÐÎÐρÎÍËumĻ•——˜‚™šƒ™€˜ ——–Đjpžŧšđļļ··€ķ ĩĩīģŊŦĻj8]Ķ­ĩšĐ~ÛŲ–!‹ÝÔÕÔÓŌŌ€Ņ ÐÎÎÏÎÎÍukĶ“––‚—‰˜‚— ––“§ip―ŧšđđļ··€ķ ĩĩīēŊ°€(hīģ_Ļ X‹ß۝3ƒIœÝ€ÖÔӀŌŅЀπÎujĢ“”€•–‡—–€• ”“Ģhpžŧšđđļ··€ķĩīģģ°ą>…Huģķj5§WšâÖÜžÎÛÕÕÔÔÓÓŌŌŅ€ÐρÎuiĒ‘’’“€”‰•€”“’’‘Ēgoŧ€šļ€·ķ€ĩ īīēą°īŠĪ§°­ķv7§ VĒáŨŨÝÜŲÕØŲÕԀÓŌŌŅŅЁÏÎth ‘‚’“‚’‘  eožŧššđđļ ķķ――ģąģąąŪ­ķ6§V­āŨŨÖÕÔŨĘĐŅÓŌÓŌÔŌÓŌŅÐÏŌÐÐufž€Ž€€‡‘€€€Ž ždnšđļļ·ķķĩīģąĩĶ·ēŊŪŪ­Ŧē‹7§XžÞÖցÕ}yŨŌÔÄÁŊšīķšļžąķēgeœŒŒ‚އ‚Ž€Œœbnđ€ļ·ķĩīģēģļJOŊ°ŪŪŽŠ°–:§[ĮÚրÕØÏh‡ØŅÔÄšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbnđļļ·ķĩīģēēąŧ[&Ģē­ŽŽŦŪĄ@§aŅŲրÕØÉd’ÚŅÔÂĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜anđļļ·ķ€ĩīģ€ēąŧf%›ī­€ŦŽĶC§eÔŨÕŲĀ_˜ÚÐŌĀīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_mđļ·ķķĩĩī€ģēą°ŧm"īŽŽŦĐŦĐH§nŲÖÕÕÔÔŲ·[žÚÐÐūģąđļšđīŧ·ķši`”‚„„€…†€…„„‚”^mļ·ķķĩĩīīģģēēą°šx„ĩŽŦŠĐŠŊQ§{݀ÔÓÓÚ­X§ŲÐÐÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]mļ·ķķĩĩī€ģēēą°ļƒ yģŠŦŠĐĐē\ĶU‰ß€ÓŌŌÛĶY°ŨÐŌÃķŊĩķĩą°īīēŊf]Ž}€€‚‰‚‚€}[l··ķ€ĩīģēē€ą°ķ"sī‚Đąi6ĨT—ß€Ó ŌŌڟZļÖÏŌŋŋ€―žū‚―j\Ž{}€~‡€€~}{ŽZk·ķĩīģē€ą°Ŋī—&hīĐϰt5ĨR Þ€Ó ŌŅŲ‘WšÓÎÍπÎÍ€Ë ĘÉÉČp[Œy{{|}ƒ~}|{{yŒYkĩķ€ĩīģģē€ą°ŊēŸ*\īŠĐ€ĻŊ|4ĨTŦÜÓŌŌŅÐ֋ŠÞÕĖĖ€ÍĖ€ĘÉȀĮnZŠwyyzŒ{€z yyw‹Xiģ°ēĩĩģ€ēąą°ŊŊēĒ.QēŦĐϧ§Ūˆ5ĨVđ؃ŅÃëþũúų†ø‹Y‡uwxyx wu‰WŒóōÅąī€ē ą°°ŊŊŪŊĶ6FŪŠ€Ļ§Š’8ĨYÃւŅÐÐâūŸĶœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’emprsvwxyz{„ƒ“?=ĻЧĶĨĨĻ›=Ĩ_ËÕŅŅ€ÐÏÏːixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj„H8ĨЧĶĨĨ§ AĨdŅÔŅŅЁÏΜtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s‘S2ŸŠ€ĶĨĨĢFĨlŨÓŅÐЁÏÎΈ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆš]+—Ŧ€ĶĨĪĻPĨyÚŅЁπПZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\YŽe&­€ĶĨĪŠ]ĪO†ÜŅ€ÐρÎÍpJCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:RN=;=$<=MR@W{.$ƒ‘“•—™›žŸŸĐimœj\e-27*%'%)73,a` 6loqsvy~ƒ‡Œ”–™›œ€ž ž €‰Ąžœ€šĄf6ŸIÓ€Į ÆĘđgĪËÃÃÂÁ€Ā7ūŧš·ĩąŦĶĄš”Ž†{xtsCWf,.5(#%%#(40+c[Clkoquz…ŠŽ‘•™›œžŸ€ Ÿ NJf– œšš˜Ÿo7ŸI™Ō€ĮÆÎfÁČÄÀÂ7Áŋŋū―ŧļķēŽ§Ģœ•†€{vpoCQh,,3( &3-*dV8s{ppuz€†Œ‘”—›œœžŸ€ ‚Ÿ žŸœWq̜šš˜žv7Ÿ IĢŅĮĮÆĮÂeƒÍĂÂ6ÁĀŋūū―ŧđīēŪŠĪž–ŽˆlbnkELh,)2$$1**fP@BCFGHILMOPRSVXZ€[€\aH4B9>>?>\WX\`defhijjln[LZsrqqR: ›$,N]aa_cioqSA:=BEILMOPRTUVXZ\]^_adeg€fhglV D)P G#$L L )M M#icdhlnopqsttuweYh}{{y[>œ#(L]`a`cioqV><.ƒ20029CNUZ]^__`acd‚efjZ L4 )WP. /TT* 3UU& /jfgkR,O:Lmnqrl[^qusucJ 9Ubcbchnvh>2†4 2137=FKQVZ]_aab7afW'%I:%3R&%L6&7O&&O4%:P%&P2&5bZTRQRUZYP[ddilnh[buwvwdHž DTUUWZZXLA…B‚CBA@@ABDEF€G‚HGEEFHEFH€F HGGHGGHIFFH€GHDBBCB€A CCDFIKLLQ[€fgO(ž$€%€&(€*ƒ+‚,†-„.//1202€3€4 55657769889::9€;:<==>?@@€A@@??A?ĸĸĸĸĸĸĸĸŽ€<˜;<ÛKc™|bKÛhž™™žhÛ“Īŧķ‘ĩķŧĢ“Û:>€G„F€EDEƒFGGF>:Û!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û}―œ€ž€žœūzÛ|ŋĄƒĢ‹ĪƒĢĄŋyÛ|ūĄ†Ģ…ΆĢĄūyÛ{― €Ē‘̀Ǡ―xÛzŧ ‚ĒĢ‚Ē ―xÛzšŸĄ…Ē…Ģ†ĒŸžvÛx🡕ĒĄŸđuÛx·ž‚ĄĒ‚ĄžđtÛwĩ€ ƒĄ…ĒƒĄ€ ķsÛvĩ€Ÿ  Ą  €ŸĩrÛuģ›žƒŸ‰ ƒŸž›ģqÛt皜žŸžœšēpÛq°™›€œž…Ÿž€œ›™°oÛrۘ›œˆ€œ›˜ŪnÛqŽ—š‚›œƒ›œƒ›€š™ŽmÃŌÎÍŨÔŨÐÏŌŌŅŅÐÐÏπÎ̀ĖË^nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl[šđļļ·ķĩĩīģ ēąŪŠĐŪŠ°ŽĐÆŠ ‘ÖŌ҇O|ÏŅÓӁŅÐÎÐρÎÍËumĻ•——˜‚™šƒ™€˜ ——–Đjpžŧšđļļ··€ķ ĩĩīģŊŦĻj8]Ķ­ĩšĐ~ÛŲ–!‹ÝÔÕÔÓŌŌ€Ņ ÐÎÎÏÎÎÍukĶ“––‚—‰˜‚— ––“§ip―ŧšđđļ··€ķ ĩĩīēŊ°€)hīģ_Ļ X‹ß۝3ƒIœÝ€ÖÔӀŌŅЀπÎujĢ“”€•–‡—–€• ”“Ģhpžŧšđđļ··€ķĩīģģ°ą>†Huģķj5§WšâÖÜžÎÛÕÕÔÔÓÓŌŌŅ€ÐρÎuiĒ‘’’“€”‰•€”“’’‘Ēgoŧ€šļ€·ķ€ĩ īīēą°īŠĪ§°­ķv7§ VĒáŨŨÝÜŲÕØŲÕԀÓŌŌŅŅЁÏÎth ‘‚’“‚’‘  eožŧššđđļ ķķ――ģąģąąŪ­ķ6§V­āŨŨÖÕÔŨĘĐŅÓŌÓŌÔŌÓŌŅÐÏŌÐÐufž€Ž€€‡‘€€€Ž ždnšđļļ·ķķĩīģąĩĶ·ēŊŪŪ­Ŧē‹7§XžÞÖցÕ}yŨŌÔÄÁŊšīķšļžąķēgeœŒŒ‚އ‚Ž€Œœbnđ€ļ·ķĩīģēģļJOŊ°ŪŪŽŠ°–:§[ĮÚրÕØÏh‡ØŅÔÄšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbnđļļ·ķĩīģēēąŧ[&Ģē­ŽŽŦŪĄ@§aŅŲրÕØÉd’ÚŅÔÂĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜anđļļ·ķ€ĩīģ€ēąŧf%›ī­€ŦŽĶC§eÔŨÕŲĀ_˜ÚÐŌĀīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_mđļ·ķķĩĩī€ģēą°ŧm"īŽŽŦĐŦĐH§nŲÖÕÕÔÔŲ·[žÚÐÐūģąđļšđīŧ·ķši`”‚„„€…†€…„„‚”^mļ·ķķĩĩīīģģēēą°šx„ĩŽŦŠĐŠŊQ§{݀ÔÓÓÚ­X§ŲÐÐÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]mļ·ķķĩĩī€ģēēą°ļƒ yģŠŦŠĐĐē\ĶU‰ß€ÓŌŌÛĶY°ŨÐŌÃķŊĩķĩą°īīēŊf]Ž}€€‚‰‚‚€}[l··ķ€ĩīģēē€ą°ķ"sī‚Đąi6ĨT—ß€Ó ŌŌڟZļÖÏŌŋŋ€―žū‚―j\Ž{}€~‡€€~}{ŽZk·ķĩīģē€ą°Ŋī—&hīĐϰt5ĨR Þ€Ó ŌŅŲ‘WšÓÎÍπÎÍ€Ë ĘÉÉČp[Œy{{|}ƒ~}|{{yŒYkĩķ€ĩīģģē€ą°ŊēŸ*\īŠĐ€ĻŊ|4ĨTŦÜÓŌŌŅÐ֋ŠÞÕĖĖ€ÍĖ€ĘÉȀĮnZŠwyyzŒ{€z yyw‹Xiģ°ēĩĩģ€ēąą°ŊŊēĒ.QēŦĐϧ§Ūˆ5ĨVđ؃ŅÃëþũúų†ø‹Y‡uwxyx wu‰WŒóōÅąī€ē ą°°ŊŊŪŊĶ6FŪŠ€Ļ§Š’8ĨYÃւŅÐÐâūŸĶœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’emprsvwxyz{„ƒ“?=ĻЧĶĨĨĻ›=Ĩ_ËÕŅŅ€ÐÏÏːixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj„H8ĨЧĶĨĨ§ AĨdŅÔŅŅЁÏΜtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s‘S2ŸŠ€ĶĨĨĢFĨlŨÓŅÐЁÏÎΈ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆš]+—Ŧ€ĶĨĪĻPĨyÚŅЁπПZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\YŽe&­€ĶĨĪŠ]ĪO†ÜŅ€ÐρÎÍpJCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:RN=;=$<=MR@W{.$ƒ‘“•—™›žŸŸĐimœj\e-27*%'%)73,a` 6loqsvy~ƒ‡Œ”–™›œ€ž ž €‰Ąžœ€šĄf6ŸIÓ€Į ÆĘđgĪËÃÃÂÁ€Ā7ūŧš·ĩąŦĶĄš”Ž†{xtsCWf,.5(#%%#(40+c[Clkoquz…ŠŽ‘•™›œžŸ€ Ÿ NJf– œšš˜Ÿo7ŸI™Ō€ĮÆÎfÁČÄÀÂ7Áŋŋū―ŧļķēŽ§Ģœ•†€{vpoCQh,,3( &3-*dV8s{ppuz€†Œ‘”—›œœžŸ€ ‚Ÿ žŸœWq̜šš˜žv7Ÿ IĢŅĮĮÆĮÂeƒÍĂÂ6ÁĀŋūū―ŧđīēŪŠĪž–ŽˆlbnkELh,)2$$1**fP@BCFGHILMOPRSVXZ€[€\aH4B9>>?>\WX\`defhijjln[LZsrqqR: ›$,N]aa_cioqSA:=BEILMOPRTUVXZ\]^_adeg€fhglV D)P G#$L L )M M#icdhlnopqsttuweYh}{{y[>œ#(L]`a`cinqV><.ƒ20029CNUZ]^__`acd‚efjZ L4 )WP. /TT* 3UU& /jfgkR,O:Lmnqrl[^qusucJ 9Ubcbdhnvh>2†4 3137=FKQVZ]_aab7afW'%I:&3R'%L6&7O&&O4%:P%&P2&5bZTRQRUZYP[ddilnh[buwvwdHž DTUUWYZXLA…B‚CBA@@ABDEF€G‚HGEEFHEFH€F HGGHGGHIFFH€GHDBBCB€A CCDFIKLLQ[€fgO(ž$€%'&&(€*ƒ+‚,†-„.//1202€3€4 55657769889::9€;:<==>?@@€A@@??A?ĸĸĸĸĸĸĸĸŽ€<˜;<ÛKc™|bKÛhž™™žhÛ“Īŧķ‘ĩķŧĢ“Û:>€G„F€EDEƒFGGF>:Û!Vœ—™™›žŸĄĒĪĨĶĻĐŠŠĐĻĶĨĪĒĄŸž›™™—TÛ!Íąģĩī··ļđššžž―ūū―žžŧšđļ··īĩģąÍ~Û}―œ€ž€žœūzÛ|ŋĄƒĢ‹ĪƒĢĄŋyÛ|ūĄ†Ģ…ΆĢĄūyÛ{― €Ē‘̀Ǡ―xÛzŧ ‚ĒĢ‚Ē ―xÛzšŸĄ…Ē…Ģ†ĒŸžvÛx🡕ĒĄŸđuÛx·ž‚ĄĒ‚ĄžđtÛwĩ€ ƒĄ…ĒƒĄ€ ķsÛvĩ€Ÿ  Ą  €ŸĩrÛuģ›žƒŸ‰ ƒŸž›ģqÛt皜žŸžœšēpÛq°™›€œž…Ÿž€œ›™°oÛrۘ›œˆ€œ›˜ŪnÛqŽ—š‚›œƒ›œƒ›€š™ŽmÃÔÓŌÚØÚÕӁՁԀÓŌ€ŅÐ`nŦ–˜€™ƒš„›‚š€™ ˜–Ŧl^Āŋū―ŧŧšš€đ ļ··ĩģŊ­ēŊīą­ËŠ”ÚŨՌSÓÖØØŨÕŨŨԀՁŌŅÏwmĻ•——˜‚™šƒ™€˜——–ĐjsÁÁĀŋūū―žŧ€š đđ·ģ°­p=bŦģŧŧĐƒāޚ'â€Ų؀ŨÖÖՀÔÓŌŅwkĶ“––‚—‰˜‚— ––“§irÂÁĀŋŋū―ž€ŧ šđļ·ģĩ…/mšđdĻ \ãßĒ;RĒâ€Ú؁ØŨրÕÔÓŌwjĢ“”€•–‡—–€• ”“ĢhrÂÁĀŋŋū―ž€ŧšđļ·ĩķ•FRz·žo:§ [žįÛāÆÁÓāÚ€ŲØŨÖ€Õ ÓŌŌŅwiĒ‘’’“€”‰•€” “’’‘ĒgrÁĀŋŋū―€žŧšđļđ·ķĩđŊŦ­ķģž|<§ Z§æÛÜāāÞÚÜÝŲØ€ŨÖÕՀÓŌvh ‘‚’“‚’‘ erÁÁĀŋūū――ž€ŧ ššÁÁķĩļ·ķģēŧ„;§ZēäÛÚÚŲŲÜÏ­ÕŲØŨÖØÖŨŨÔÔÓÕÓÓwfž€Ž€€‡‘€€€Ž ždqĀŋū――žŧŧš€đļķđŠž·ī€ģąļ‘<§]ĀâÛڀŲڂ~ÜØÚĮĀŊšīķšļžą·ągeœŒŒ‚އ‚Ž€Œœbqŋ€ū―ŧ€šđđļ··ŧOSķĩģģē°ķœ?§^ĖßڀŲÜÓnÞŨÚÅšĪáīÉÛâåŽŲÐxcšˆ€‹€Œ‹€Œ€‹Ššbqŋūū―ž€š đļļ··ķŋ_+Đļē€ąīĶD§eÕÞڀŲÝÎj—ßŨÚÃĩąŨÉĖÓŅŌÉÏÏub˜…ˆ‰‰€Š‹‹€Š ‰‰ˆ…˜aqŋūū―ŧ€šđķĀj*Ąđē€ąēŽH§iŲہŲÝÅeāÖØÁīŪŋūđÃū°Á―ēka•…††‡€ˆ…‰€ˆ‡ ††…•_pŋū―ŧŧšđđ€ļ·ķĩĀq&–š€ąŊ°ŊM§rÞÛŲŲØØÞ―aĪßŨÖŋģąđļšđīŧ·ķši`”‚„„€…†€… „„‚”^pū―ŧŧšđļ··ķĩŋ|#‰ŧąą°ŊŊīW§â€ŲØØāģ^­ßŨÖÁąžÃŋÁ·īŋ―ļķn_’€‚‚€ƒ„€ƒ ‚‚€’]pū―ŧŧšđļ··ķĩ―ˆ#š°ą°ŊŊ·bĶXã‚ØāŽ_ķÝÖÖÂĩŊīĩĩ°°īīēŊf]Ž}€€‚‰‚‚€}[o――ŧšđđļļ··€ķĩž’%xš‚Ŋ·o;ĨW›ä‚ØßĨ`ūÜÕŨÁÁ€ŋ ūŋŋ――ūŋk\Ž{}€~‡€€~ }{ŽZo―žššđđļļ·€ķĩĩš)lšŊŪķx:ĨVĪâØŨߗ]ĀŲÔӀÔÓŌŅŅÐπÎs[Œy{{|}ƒ~}|{{yŒYnŧŧššđđļļ·€ķĩĩļĪ.aš°Ŋ€Ūķ‚9ĨWąá€ØŨÖݑâۀŌŅÐЀÏ΁ÍrZŠwyyzŒ{€z yyw‹Xlđĩļšđķĩ ·Ļ3Uļ°ŊŪ­­ī:ĨYūރŨÉïĸųû€ú‡ų‹Y‡uwxyx wu‰WŒôôÉķķĩ ģĩŽ:KģŊŪۭް—>Ĩ^ČۂŨÖŨæÁ Ķœšš™—•’‘‹‹‘QT…r€u€v‹wv uur‡SS’€gprtvxy{||}†…—CAŪŊ­ŽŦŠŪĄBĨcŅÚŨŨ€ÖÕÔŌ“ixve`_]ZWTQMKHK+R„pr€st‡ut€srp…P,KHKNQTW\]a`evxj†N=Ŧ°ŽŦŠŠŽĶGĨhÖÚŨŨցÕԞtz‹‰wrsqnliecae6N‚oqrqo„L7daceilnpssv‡‹{s“X7Ĩ°ŽŦŦŠŦĐLĨrÜŲŨŨÖÕÕÔÔÓĨˆ‡Š—–ˆ‚}xwsqw?Kmo‚p‹q‚pomI@wqswy|ƒ‡–˜‹‡ˆc0ą€ŦŠĐŪUĨ~ßŨ€ÖÕÕÓŌŌĄZ\YT_`URRQP€NS/N€jlmn€mllj€M0R€NPQRRT`_UW\Y‘k,•ģŽŦŦŠĐ°bĪTŒâŨ€ÖÕԀŌŅrJCPRJGFDB?<:@jzfhƒi‰jƒi hf{i@:DŦŦĐЀϧLĢpŲÕÓŌŌŅÐπÎĖĖËËÉČÆÉÎŦH„VUk]N›PN[kVTƒNˆŠŦŽŦŽŦŠŦŽŠF>ĨŽĐϧĶĶŠWĢ|܀ŌŅÐÏÎÎÍĖĖËĘČĮĮĖÍÅŋĪ BƒWQdZKK—L KKXeRTƒGĻĻ‚ĐŠĻĐ­N: Ŧ§€ĶĨŽ`>ĄVŠÜŌŌŅŅÐÏÎÎÍĖËʀĮĘÄū―žŧĶ=WKaWFF•HGFVaMTBŽĨĪĶĨĨͧ§Ķ§§ŊW3™Ŧ€ĶĨĪŦl>ĄS˜ÜςÎÍÍĖËĘČÆÆÅŋžŧđ·ķīŸ%5XG]TDC“ECBS]HV; ŸŸ ĄĒĪĨĶŪ`,ŠĢĪĒĒĢŦx>ĄRĄØËÉŅÓÐɀĖËÉĮÁÂūžđļĩēąŊ­Ÿ)/}YCVP@?‘A#?@PXDV}4Ššš››œžŸĄĒĢĪĨĨŊf&ĢĄĪĪĄĄŠ<Ą RŦÔĮÄ~Q…ĘʀĖÆŧŋĀ―ŧ·ĩąŪŽĐ§Ĩ™+)z[>RN=;=<=MR@W{.$ˆ•”•–—™™œž Ē€Ī Ŋm#rĄn@W• Ļˆ<Ą%U·ŅĖ{ŠŌËÎĮīŋÂŋžđĩą­Š§ĪĄŸž–2"w\;MI:8:%8:IM=Yy'#†ŽŽ’“•—šœžĄĒĢĢŪw$m"RĒĶ’=Ą&XÂÐÐY6~2wÔÍÉĐžĮÁŋž·ī°ŽĻĢĄž›˜•.t]8GF74‹6&46FI8Zv",‡ˆŠ‹‘•–˜œž ĒĒĨށ)lt,zL? ĪšBĄ']ĖŅзt—œÅÏÍĄĩĖÆÃĀ―ļĩ°Ŧ§ĒŸ›—”‘ŽŠ4p_5CD41‰3'14CD5[r&|‚…‡‰‹‘•˜™œŸ ĒĪĪŠŠ-dĐvˆ€ŠĢĢ IĄ(cŅŅÏÔŲÓÖÏŅĒĢÏČÆÅÁ―šķ°ŽĻĢž™•‘Ž‹‰…4k`3?@1.‡0(.1??2]n.x|~€‚„ˆ‹Ž“–˜šœŸĄĢĪĪĻ“,WŽŠĶϧĄĒĒMĄjÔÐπÎ"ÍÓ°‰ČËČĮÄÂĀžļģŊŦĨ š–‘ŽŠ‡„‚=ga0;=.*…,)*.<;0_i0vxz|‚†‰‘”˜šœŸĄĒĒĢĪĶĨvbĶĢĒĒĄ  ĨWĄxŨ€ÎÍĖÐÆ~ŪπČÆÄÂūŧļēŪĐΟ™”Š†‚|< ac/7:,(ƒ*+(+:7.`e5tuwy|€„ˆŒ”—šžŸĒĢĢĪĨĶͧĨ•ĒĢĒĒĄ  Ļ`>ŸO†Ø€ÎÍĖŌ•ÎËɀĮÅÃÂūŧķēŊŠĪŸ™’‡‚~{x@\e-27*%',%)73,a` 8psuwz~„ˆ‹“˜›Ÿ ĄĒĢĪĶĶĨĨĢĨ…ĨĒĄĄ Ÿ§k=ŸJM•ØÎÎÍĖÐūkĐŅÉÉČĮÆÅÅÃĀŋžļī°Ŧ͟™’‹…€|xvDWf,.5(#%%#(40+c[Dposuz„ŠŽ’–š ĒĢĢĪ€ĨĪ ϐišĨĄĄ žĶu=ŸGMžØÎÍĖËӒmČÍĘÉČČĮÆÄÄÃÂĀžš·ē­ĻĄš’‹…yrrEQh,,3( &3-*dV:v}tty†‹‘–™ ĄĒ΁ĨĪĨĨĪĢĒĪĄ[vĻĄĄŸžĨ|;Ÿ MĐÖÍĖËÍČiˆŌɀČ5ĮÆÆÅÄÃÃÁŋ―ŧļīŊĐ̜”Œ…odrnGLh,)2$$1**fP>ij_k|€†Ž”™œ ĢĪ€Ĩ§€Ķ€ĨĪ€Ē ŠkLĪ ŸŸĢƒ<Ÿ OĩÓĖËËŅ­WĒŅ€ČĮƁÅ.ÄÂÁĀĀ―ŧš·ģ­§ ™‚[mxpkIFh,(11(*fKCfjr[9p‘—ĄĢĨ…§Ķ€ĨĪ€Ē Đ€5€§ŸŸžĄ?ŸSŋЀËӐVĩÎČČĮĮ€ÆÅĀÂ)ÁÁŋū―ŧšķēŽ§uY|~sniJ?i,'()gEDehnxo&GšĄĨρĐĻĻĐϧĶĨĢ€Ē §“3b§ŸŸž •CŸ [ČÎËĘÉÏw]ÁĖĮÆÅĂÂ*ÁÁĀŋūūžš·ķ­oeˆˆ{skgH9i+'h?Fcglu‚~<:šĻ§ĐĐρĐĻϧ§€ĶĨĢĒ Ī›;IĒ ž›HŸ `ÍĖÉÉËĮf`ÂʀÆÅÃÂÁ€Āŋū€―"ŧšīƒ‰œ˜Š}rjeM3hg8Eagnwƒ’‹fZĒŽŦŠĐĻ€Đϧ§€ĶĨĪĢ‚ĒĢžB>™ €œNŸgÐËÉÉËĀ_bÂČÆÅāÁĀĀŋū!―žŧŠīĀĻ›€ticM05J`fo|‰•Ÿž’Ū­ŽŠŠ€ĐĻĻ€§ĶĪĪĢƒĒ ĢŸG<• ›šŸUŸtÓÉÉČÉū_bÁÉÅÄÃÀÁĀĀŋū―žŧŧđŋÖįŨ§Ą—‡wkcQ Kaht‚›ĒēģĐŠ­€ŠĐ€Ļ€§ĶĶĪĪĢ‚Ē ĄĄĢH@” œš™ _@ J‚ÔÉČĮÉÁb`ŧČĀÀ€ÁĀŋŋ€ū―žŧŧ€š·Þųþâ°Ē›~pfHHdnz‰–ŸĻĀČĀĩŽ€ŠĐĻ‚§ĶĨ€ĪĢ€ĒĄĄ  Ē˜KF•žšš™Ÿi> I‘ÔÉČĮČĮm_ŪĘĀÀ€ÁĀŋ€ūžŧššđķŧōĸĸðÅŠœ‚vnnu€šĪ·ŌØÐÃ­ŠŠĐĐĻ §§ĶĨĨĪĢĢĒĒ€Ą ŸŸĢKQ™š™˜r?JšÓȀĮĖ‚cËÃÂÂÁĀĀŋŋūūž€ŧššđđļļīđėĸüõęÔ𠐇‡ŽžīŋÍØÝÝʭЊЁĻ§§ĶĨ́ĒĄĄ €Ÿ ΁Pbž›š˜—x> JĪŅČĮĮÆĖšlĮÂÂÁĀ€ŋū―žŧŧššđđ€ļ··ģąÐïöýýúóæÞÝæōųäŲØÕĀŠĐŠĻ§§ĶĶ€ĨĪ́ĒĄ €Ÿ žžĄvZwĄš™˜˜œ? KąÎČĮĮÆÉąz…ŧŀÂÁÁŋū―ŧŧšƒđļ·ķķīŊīĖėþþýûúúûýþįΞŪĻŠŠ€ĐϧĶĶ‚Ĩ΁ĒĄ €Ÿžž˜qfŠŸš™˜˜š‰APžĖĮÆÅÅÆÃ‹ŦÆÂÁÁ€Āŋŋūū――žšđ€ļ·€ķĩĩģŪŊšÉŲãææãŲĮģŠĻ€Š€Đϧ€Ķ€ĨĪ́ǀ  ŸŸžŸŒuv™š€˜—˜DXÄÉÆÆÅÅÄČŠ—ĨĀÃÁ€Āŋūū€―žšđđƒļ·ķķĩĩīģģēŪŦĐĐĻĻĶͧ€ŠĐϧ§ĶĨĪĢ́ǀ ŸŸž€ œ†{‡™˜˜—–—”I^ČĮÆÆÅÄÃÅŋĶŽšÃÁÁĀŋŋūū€―ŧšđ„ļ··ķĩĩīģēąą°°Ŋ­Ž­ŽŦ€Š€Đ€Ļ§ĶĨĪĢĒĄ€ Ÿžžž”ˆ…–›™˜—––——N fËĮÅÄÃÃÂÂÄļĩŋÂ€Āū――ŧššđ…·ķ€ĩģē€ąŊŊ€ŪŽŦ€ŠĐ€Ļ§ĶĶĨĪĪĢĢĒĒ€Ą ŸŸž›’Œ‘›™™˜€–•™TœLsÎÅÄÂÂÁĀČÏĀūŋ€ū―žŧššđ‚·€ķ‚ĩģē€ąŊŊ€ŪŽŦŠŠĐσ§ĶĨ€Ī̀ǀĄ Ÿž››š–’™šš™˜––•”š^A›I€ÐĀÀÂÁÁÄÓÝŲŧžūūžŧŧššđļ··€ķ…ĩģē€ą ŊŊŪŪ­ŽŦŠŠĐρ§ĶĶĨĪĢ̀ǀĄ  Ÿ€žœ›šŸž™™€š™˜—–•”›g=›HŽÎÃÁ ĀūÏčņÞđžžŧ€šđļļ·ķ…ĩīēą°€ŊŪ­€ŦŠĐĻϧ§ĶĶ€ĨĪ́ĒĄĄ ŸŸžžœš™ĄĪĄœ€š ™˜——•””™o>›H—ÍÃÁÁ ĀĀ――āũúā·ļŧššđ€ļ·ķ‚ĩīģēąą°€Ŋ­Ž€ŦŠĐĻϧĶ́ĨĪĢ€ĒĄĄ Ÿ žœœ›šĢЧ ™˜—–•””’—t>›HĒĖÃÂÂÁÁŋ žūęýĸåļ·šđđ€ļ·ķ€ĩīģģ€ēąą°€ŊŪŪŽ€ŦŠĐĻϧ͂ĨĪ́ĒĄ €Ÿ žžœ›š˜§Ū­Ķ™€˜——€•“’‘”|?›JŊʀÂÁŋ ū―đžïĸĸï―ē€ļ·ķķ€ĩīģēą°ŊŪ­­ŽŦŠ€ĐϧĶĶ€ĨĪĪ́ĒĄ €Ÿžœœ™›Žģ°Ļ™–˜—––€•“’‘‘“ƒ@›QļĮÂÂÁÁĀŋŋū―žŧŧļšëĸĸųĖąĩĩ€ķĩīīģģēą‚°ŊŊŪ­­ŽŦЁĐĻĶĶĨ€Ī€ĢĒĒĄ€ Ÿžž€š˜ ąĩīŠ˜•€–€•”“’‘‘‘ŠC› WĀÅÂÂÁÁĀŋŋū―ž€ŧ·ķā€ĸāļ°īĩĩī€ģąąƒ°ŊŪ­­Ž€ŠĐ§ĶĶĨ€Ģ‚ĒĄ€  Ÿž›ššŠ·ķīĻ–•€–€• ”“’‘‘ŽH›]ÄÄÂÁ€Āŋū――ŧ€š đ·ģÏúĸýōÍ簁ģ瀰ŊŪŪ­­ŦЃĐϧĶĶĪ€ĢĒĄ€ žž››Īēļ·īĒ–——––••””€’‘ŽŽL›cČÃÁĀĀŋū€―žšƒđ ąžæüųöâÄēŊą°°ŊŪ­ŽŦ€ŠĐЀϧ§ĶĪ΀̀ĒĄĄ Ÿžž›œĢŪĩ··­œ—˜˜—––•”“€’‘Ž’Sš IpËÃĀĀŋū――žŧŧšđļļ·ģąÉëôîčÛÆģŽ­€°Ŋ€Ū­Ŧ€ŠĐĐĻρ§ĶĨĪ̃ĒĄ Ÿžœ›ĪŽēīīąĢ˜™™˜——––•”€’€Ž“\A™F~ËĀĀŋ€ū―ŧ€šđđļķīŊģĖâįææáÔĀŊ§ĻŦ­Ū­­Ŧ€ŠĐĐρ§ĶĨĪ΁ǀĄŸœ›Ą§ŽŊ°°ŪĨš˜šš™˜——–€” “‘ŽŽŒŒ‘e@™FŒËÁŋū―ŧššđļķ€ĩģ°īÆÚåéðöðāĮīŠĶĶĻĻ€ŠĐ€Ļ§ĶĶĨĨĪĒĒĄŸššĒаģģ°Ŋ­Ŧ̚—˜——–•€”“€‘Ž€Œ‘l@™F”Éūžŧžšŧžŧššđļķ‚ĩēŊąūÕëøþĸĸþïßËžēŠĨĢǁ žžœ›šœ ĻēÃŅÕÓÉÁđīŪ§Ÿ™–˜˜——˜€—•”“€’ ‘‘Œ‹ŠŠ‹Œ‘p?™ GžÄļĩŧū―đķđšđ‚ĩīī€ēą­ŦīËčýƒĸýôëäÜÕÏĖĮĮĘÍŌŲāčóýĸĸüíÜËūąĨœ˜—˜„—–••”’€‘ Ž‹†…ˆˆ‰†‰ŽxB™ AĐūēī‡JYĄļķ€ļ·ķķĩīģē ą°ŊŪ­ĐĐģÆÜðü“ĸõÛŋŠž˜—€˜—–‚•’’‘ Œ†wK8[ƒ„‹4™(ķšĩ‹ A°·ļļ·ķ€ĩīīģēąą°ŊŪŽŠĶΧŊūËÚčðöüþƒĸ þüöïįŨŷʘ˜™™€˜——–ƒ•”’€‘€ ŽŠƒ~D[ˆ‰Š%™ >―·š`(gN(Ģđ··ķĩģģ€ēąą€°ŊŊŪ€­ŽŽŦĐĶĪĄŸĄĒĶŦŊģĩķķĩąŦĶ ˜––—šœš€™˜—€–€•€”’€‘€Ž ‰…z(Lf4@ˆ‡Œ2™ HÂđŧ™=i{oļķ€ĩīģģēēą€°ŊŊŪ€­ŽŦŠŠ€ĐϧĶĨĪĢĒ …€Ÿž€œ›š€™˜—€– ••””““’‘Ž ŒŠ‹_HŠKd‰‡=™ LžđūĩĄĩ―·ķĩĩīģģēą°ŊŪŪ­ŽŦŦŠŠĐϧ§ĶĶĨĪ„ĒĄ Ÿžœšš™˜—€–••““€’‘ƒŽ Œƒ‡‡‹‡ˆŽI™pØļīīķļģąŊ ŪŪ­­ŽŠŠĐĐĻ€§ĶĶĨĪĢĢ€ĒĄ Ÿžœœ›€š™˜˜–••””’’‘‘€Œ‹ŠŠ‰ˆ‡€…ƒ„ ‚‚ƒ€~~…’[™9ãÛëįįæåääããæęæį῁äãâáā€ßށÝÜÜÛÛÜââÞßáāÝāāÜÝßÝÚÞÝŲÛÜÚŨÛÛŨÛÛ؃ÓŅŅÐςΠÍÍÎÎÍĖËĘË͝yš}ķŋÁÃÅÆļĢķ°īĩ·ļšŧžž€ūĀÁÁ€ÃÅÆĮČ€É ĘĘËĖÃϧ―ģ§ŊÃĐĐĀģĻģÃĐŠÄģŠļÅŦ­ÆģŽķҁÐŅÓÕÖŨŨØØŲŲÚÛÖÏÕÞÞÝßփ›$-O`ecbflrsM D28?DGILOQTTVXY[\^`cegjijkrU>!MCII JJkeflprsuwwxy{|jZj‚€€`E ›"4Ykpompw|~_LDFMPTVZ[]^`adefijknoq€tu{b M. "[ Q( (W V#.W X 'wq€prwy|}~€ƒ…revЇˆ†iI œ!/Xjoonqv{€c HFEMQSVZ[]_abdegijknprt€uzc O1 $] T* +X X% 1Y Z" )wqrwz{}~€‚ƒpfx‰‡ˆ…fCœ"*Uhoonpv{e#CIDLQSVY[]_abdeghiknprs‚tuzd Q4 &_ V, -Z Z( 3Z \$ -wqrwz{|}~€‚‚nfzˆ…‡‚d>œ#%Sgoonpu{€h'8IELPSVY[]_abdeghikmprss‚tze T6 )a X/ 0\ ]+ 5\ ^' 0wqrwy|}~~€€€mg{‡…†a: Pf€npuz€k04BNPSVY[]_abceghikmpq€styf U9 ,c Z1 2^ ^- 8^ `) 3wqruwulpy~~€€lh|‡„†}_3!Menmmptz€m4//=MUWY[\_`bceghijmoq‚sttyf V: ,c Z3 2_ _- 8_ `* 4vqruY9‡Tdv~~€~ii~†ƒ†y]-"Jcnmmotz€o9#30/4BPY]^_`bcefhijmoqr‚styf V: ,c Z3 2_ _- 8_ `* 4vqti)&ģNBd~}|ij~…‚…v['Fa€motz€r?+766436>LW_bccdfhijloqrr‚sxf V:,c Z22^ _,8_ `*3vqtk+*i~}~zhkƒƒtX B_€mosy€tH5‚;:88:BMZcgjkklnpqs€uyfU: -bZ3 3]^. 9^_+ 4xtt€uyb62`{{~€ygl‚‚pU  Capqpqv}„vI<„> ==<:;@GPW\bgkmo9pqqtb.,TC-:].-W>-?Z,-Z;-BZ--Z9-€@AA@BCCDDEDDEFFGFEEGF$ĸĸĸĸĸĸĸĸt8mk@tøęęęęęęęęęęęęęęęęęęęęęęęęęęęęęęønĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸy~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx*œšššššššššššššššššššššĖĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸƚššššššššššššššššššššœƒ0DėĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņPģĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÁÏĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÚäĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸíōĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõ!*úĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ4@ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸN[ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸiwĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸƒŒĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ•Ąĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ­žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸČÓĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÞ įĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸïóĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũ$-ýĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ8EĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸR`ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸm|ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‡Žĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ˜ĨĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸģĀĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĖÖĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸá ęĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸðôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸų'1ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ<JĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸWeĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸs‚ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŽ—ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ Ŧĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ·ÄĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÏÚĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸåîĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸô%øĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü,5ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸAOĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ\iĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸx‡ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ’šĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĢŪĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸžÉĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÓ Þĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸčðĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸõ!(ųĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸý/9ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸESĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸaoĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ~‹ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ•ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ§ģĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÁĖĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŨ âĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸëóĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸũ#*úĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ2=ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸJXĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸfsĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‚ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ— ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŦļĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÅÐĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÛåĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸïôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸø%,üĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ5AĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸO\ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸjyĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‡’ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸšĢĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸŊžĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÉÔĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÞ čĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸņ$ũĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸü,3ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ:FĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸSbĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸo~ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸšĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĪŽĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸķÅĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÏŧĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÆPôĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸų[ ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ  wĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ„  hĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸs  Xĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸd  NüĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸU  GũĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸúN  =ėĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸôF  6āĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸį<  1ÓĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÜ6 +ÃĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÍ/)ŋĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸÉ,%·ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸū)#€ĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸĸ‰%#B’ÛîïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïݘE$5NkˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‚mP6  ,@Q]dfgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggd^RA-  !2@JPSSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSPJ@2"  !+38:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:83,"  "######################################################################################"   ic09 jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cĸOĸQ2ĸR ĸ\ PXX`XX`XX`XX`XX`ĸdKakadu-3.2ĸ Øĸ“Ïūö—zYÝdŅ€†h&’‚ŋōĨ‡æ CFE°9D“þŪ!Á·"“ĻĮøŨ-B^ð͌ōJY9…[τ„ƒdÏãÂĻoiĸŒŊŋŲøĄWÐËÁ=0B=ËWšä9ŠL6Úœô([okĄęė™3-ņ‹Ōŧøþųņó™ĘõŽ3ŽĄxĻprųVúh(ôÔĶũ–>ņT=i†SÞ]íģw„NÍxîįé úęĒÆ/S‹WĀ“īBĶĻHŊޜJVĄķœCSlįŠ\ņH ðTę^Å%‰YÉį'cē,­ŠÓ+Œv1[Å,―Š`sī'~qŋÖū ÁóW@Ą ĩķŧG<cóÕ|[“ú­Zv]+XĻøFúA~!wĶý§E°šŧQB|‘ þõuĨƒŠ„9ā˜jŽĄŽ§íÂ7Ļ} #Æã#F(ŨHĸ) ü[u .ø=e‰MŪ€ÏūÔOþŦ…č5å'ęóÚðǁR/)ļĩKŠ Vkįî+ÅjÍ̆e čŧōÍ'Øï΂Đož đĪß2ãĐĄš'ÄR{wĀž›ýŧ§ē‹[šOŅ#0./`üĢČGŌ}üË7:G*w$ÞåaŠüO‰*™Í°ÕäI=Ā:ϧx.æj”Z#”WŌ·ïßA‡jjĄ‘―TI5ï/ŠēŽ‘ømJjZþúR{ęb(ØĮ™’•ëz‡Âiėh1Ī˜ÝŽŽ5šÉí’ĢW]aØþáæô “œį9Ė~ÏĘÆŸ•w•vžYZoÜę’]‹a›īs Ôîï2p_ĢQ þü3ĮÆ/6^‹3ã=Ūģ”ą ssk9j"ÁôæÏNdˆ q@o F9:j$]rp]‡ŲĒ„ûÎôwtÉ Ã$ÝÏč„BA ˆ žKnóv%7…h ĶąVx€rŌF‡°AĶÏå^*ô:‚NËÅ|öęáŌbŧÜšï —ƒzo B^ĻŊ,T;ІŧÝp-ß cFŒy*ŸvÆį“ZŋŨ‰!ūÉĪplKη-/éÉ`™ó_i‡Ā-ČéĮK*k­BYĢcĩ6‘Šę*ú™đ@ņį“$1Îr҈…ŦNžŋņx`Ū6Ÿ{ƒ)ą1âXL?íY1!·ņĘĄæĄmķ~z­qLųül Ģ.óÎ| RqüM`3ƒŒ“=3ûØøė äíIĪ“'[ĖŠb Or/í9BÛE€jŧ… ”=P[ÝËIŨēóO™ęGtSYcy1B‰ūēĀQ°ÚÞÅ:Ģ4DņØõ@€·#Ģuv_™čßý$d”‰ÖôŽV’qŋHe#ąGĩÆ>s 9^Æp§†ŧ É,•ēė4B6ĀčOŋWõ;ŽoAāãėÃQĮcãŽíĘÍQ"žÐX§‹Š6ØĨ– o+$€4>+Œ‰3!ĸ`6!ýÎZƒšũVōÝAY_ÅÂ,ŪōÓ°6Áē’ÞúĶ–GpēĮđ$øķķW_.cŌÎÛōL'ū^Üžëg–žÚÐ+͝‚ÃÃj›o>ĄĮĶ{0-ÁôÓáöĐAö§ŠŸ[ÜŨðZŨWŨ(oŽ.ÝĨČf‘öģ°ïZ˜öŽŽ>}œ ė&îHZ&æ%ÃŒļk a ð݂7•w8‡ ā‡b2QeMī4e Ų`wŠŠ‘IÓRCÂļë…ũKį=Ŧĸ>.Åm=zäLļþ›eŌýŧņóŅ-8gÆ(ņ›ÚčŪ/žßĻ9ˆęŅĖÔņņ4Õâ-xå%ž"ú=öaũ~RDóO'ЉÓ,~~ŧJ J[/í īsCŠW’ÐņÄiØąúö{ýmUq7ĨkÍßŪ r_zöïYûzÓąĢ%z+īątæïâW=T ˆb~ĸ5>Ü€ĮÞÁ‚äjPĒņL‰ŧÏíL—Ŋ$rž•žņ)íãęĢlĨ`;ƒí |ą 2G}žG°]Â\yW7l‰˜-ņsš‹0Āŧ1œ~>œuĘdîZïg–šF$ĻÏŽŽŠĪüú\ģðŦTä–ĒzĐ"á­ĩýÖĖ–æL”ðTē'œŨ(ßHpÔnČŠiæ(~MÝÄÐ|ąĐaQ2| _ Ȗ/Ērԝ$Jڋ 'ęCÁ€Ÿ3[ƒĮœQmæķ8-û4o~’įJ)önûŦTĒŋáQgí4ĮœõÓDÅLĨq'įčL‡П dNņųįã <tX#] ō)>árģb_žÁ]Ļ?aóŠKëČØÉĮáŅt~ ĮįūzЧ]ßØ_Õîā]ãë°?Ð8[x­kBÍ―ū›%ŧ"KÎvPĸ_Ÿ—ãÃÍ3ââ]Ŋ"f}§ûctäþâÏVĪ\#ņL8Ÿ ĶõÞVÜņC0S‰…Vƒ_.q­L} ;ÍĸÕ=Ïí”s˜3ÛöĶâD€!Lã č€āßô@†ąM’,…Ï}ģwĶ–įŸ!ĩJ#š–ŲÍWä1NĘÜÃlHMÕŨ"CįÞąēÄížæzų X/bLkŅŋ_ ~“imå›ý>pþ}]4.Ý ·rõjEûtauð%:ųŨUę [€­ķÁĻ_‰[ķ/ØFm*ŠMߘÚo>ŽÔ8DëĶH6ïģÁ x%ëTô*_:YŲl€*c؞ējˆ‹vŨãņäú"āĖ< œČÕÓåŠ―"™NeŊĸOœpŌKy9W^X ņÆĨ\Ō SXÔĶ%{ŠĘĐęĖ Ž6c õp—TÝԂd™ëbEݔēö+€šm,ˆû6šþ7jCŸĢzņ ]ÞÄåovačd2507*ŧŅ,‹RŽäi'$ÚPk^‡āČžC /^0Žĩ'‹uˆQ ­ũyņFëdÕ&Eû#ĩ}(čÄcēūĖ=Ō"KRį:ÞöŠÂš€šĢdJzU +îäoSl·Ž@kq[~°ĩÛų,đ‘ŽÍŪ”Ųúū•™`ö%Ä―/Į ‚3ðÔa'“™ķYīöÍčĸSäÁęÂFûý<—å#oÉĻŋ ð ĨŊāé€ÔĢW9jäZ]‚vxÞp:›••LpTššøĀĢ3Gĩ•ŲęØŠÂwĮĘ{ ‹dzŸ!…b œĪ4C:φ―“I Ō藛l,^›ãI'ō>tĀ@ulđĖė―Zë―·Þž5H˜$^ð­ËÆŋ°62·ž'ę<­šÂtYĸPāÉķ–;ƒŧģ>īBD‘ĸ}›ÕSdĪŊ!o}ĐÝíũˆÎÞYó†ZîßÛŌąļ=YũŋŽß—ĄÁģpëĶĄŦ` šĖÃą&XĄ æįūž>QˆĶFŽïþŽŪÕļqÐÖ 9âØė›zâî—u™cc{)‹ÞáóÎm*ᰓųBjXO·!ýŌĩ’ĖŠîHīŲÜ·Ï0Ž—ŊôĻĨœKi|[Zô-Ō_ļŲ++ï7œ$ ŋ3ĘðbˆÁ>%/e ˜˜Õîģđ>>m™’ĘŪīü•ƒœhKiszlĘU·Ķ9a3É5Ŧh °6`mņŊorāč%)zUŧ'!ūā=jx$2b0ÎÏā–ųK~ÓóĪí^švÎÚJ—a˜―T;l$*ŨÛÉ%”ÚîhÍ ã€ ŠNNd°‡Ā3aŋ<â2‰V˜Ps„ÝuÚQ{ íūÅ6ÃŦÄo`/†ÖLæ?7ÅÍ8ęĪĄėû3#$ĢrÝÆhPž·'bë ƒĐĖpŊL@-…y<_XÖýģwčC*‰!ÛEkņțÁ-æÁø>‰)ĄÕ!Û2TÁSĸoyÄ ĖĐwãmû~€'īBĪ\‡Ũq^cš­{ąHjÝXä6OÜyųWŒk.Â.áOsAX{InÉ@cGÕM*väīœÍŧĀqĄqqIÍŠ`/œR:4Ķ-ã]ę,ÓÁĖâáa`NÐyš+*D!Ú­‚øĻø) Áw-~t`Óaņē“v7ū`uT~ôPqäWÛeäÛöäIÃĩų+u`~Ž‚ņ&ŒæH0fA‘b^G·ķŌū―ÖvđÂxxLŒ€)ķë&ļđũŅ|gN1ĀpÝOģ-OhģąĮŨĢМ–ayč} /\ë!V?ã˜ČdĒ2F_$)ØŠÁaĪI—Āf‘•Q•ÕĘĖΊHĩ@øZ;ÓK}“É&dĐЏmŽ|B[þ·(ī óŽ―ë™gö‡ÉÓI€ĮßSĮáWAö>€Ju(8/*vq)‹3’\JJģ.ÎÚģkŋø§―V&<ģžÛë˜ysÐũÚî‹öœq†•|PO‰7ßC@Ï<ē"ĸĪj“røk™ðö§(bdČŧ@ W—éĐjüցjlũí‘a:—2p‡ÄkĻCÎ3Ũb;Ū“ÃCaÚÐjTĒāé”Ā'Xīĩ<äïéH*'ąJÅļ#šdįE<’]ŊĄšSÛx_9XöšĮ:·ŽŲÔü”‹ÓČWß0úxčКÓrĸoÄ^þ…æīŽ \ų:‰%/tƒ*ų|?7}s’ŠŋEÖےI$’?^ĮŨ…*öøÅ=yŠZĄÛˆéþnúþÂ5ý8JąsGĩį` đ$’I#c–nķÝӘ,ew’ėč€qkÐĄ‡8ęƒŸ­C*4­ČÐeë x9-Q…†Ü’I$’ÚÁ”Đ—ąįæĩžļĨ֋eóW>G˜‡RT­āõ”š@{iKŠ^F Äģd›F/Šʰ‘æh2Ė{$ðvš$Ā<ąPkŽ‚€K‡/DŦē"Nė―šsJâė áĖ5ƒC2ŠØN~ĩƒF™ŨÔļÍ<ĶPŅ §‚Ķ€<)}§ĘĮáė-‡­Ž>ĸ&ļ•-QŊzÅēHÐäČ .ĩļÃíĶ'JP팘īŊJ<ė7ĢŌéȄ79+…Í{}ZČÛS‚sėW›$ŠþNĘð gpŲ”ÍōŒ#cļgÃč°ëqzžųĐdøló{…ŌīzŅýļEÞEhŐB •P°lNV™Ø0ƒdZqŠ Įļ#}ĻŦËŠ9‹éîДýƒB3ũe‡)šÚkmpÐÖøƒ3Û^8$ā UŅaoÓAæāļĮĀa3ΞåšâāýrėĪûÐ,k…>mß<úƒú`äŊ5Ōíģ ”jÏĄĢ{DGUŪå:Äû.{N—Tþ2 õđī8€Šˆ!, ōÚ*Ši·Ā FeĪÄKílÜ7Ī(”ŸÞÎ͜ūÜÜ}#·Á†ÚĄrįŲãó‹"Â―īéØ[‘8-–+ØGŲ‚r?ĘkđÉ.^Ŧœ( ķUgĒPáÓÕL8ë~a•+b+SíáóÞ0·Ķž,7g•d‚P§į―•œŲšœ%·Iþ4Ž-™Đ,°9ϔüô‚,ú’sÂV‚ûJÛ2―Dąķ9ũŌ͖“æ(įgÏ&Fu―Ų†'hŧņ)jvß§ŲƋģgĘŲKƒ‘(|cō%ņ|ݓú>ÛBF_@RĪÆ‚HÖ(éįPËÓOnW,­?"õ[ĒïĖ·’}Vęũķ Â.%“^t ›šX“53 ŧ”ŪÝ­^\Į“žõGķ1þŋÁül%u_›eęųMÎ)Þ8Īœđ˜°īĐXH‚ē{ĢŌËb Č}ĩPā!-F#ۘâüŽdč^N'ĄžíëĪJĻtkĪ(óØ#ĮhqÅeæL@;ĐĮd=Â)°~Îôw§Pę.ĘÛIū―FõžZņäčŸChĢ:\ĮbÃ{ųûĶĸaĻ_Į’Åß!ĖÚIąĶüÁúæ’ÜŽõ·ū‡ î,G3‹Þ=HM~8oĄņ`Ôi:!GG,õÙäĩQģGU!ÜįĒæ›–m Zå†ú*Ē_*.õž Į:šz*ĢOJ$ū“6Įę=tČNjŲ>+”ĀÛïϐDPڐðÂĨ‚ð<†Z5GÝØÝ%ɃÕļ$m1ŲĪ3riŠĒâi;8-@”:æũm‘–'—ĩð‹ãUa?úûÎïIĨöJP…!Ĩr|@lõït֏íҘ1đfÛŲi\@ úĄý:ģ9%æ4 –ęĀÝu$‡ í„š6Šuęéĩy-Vø$ĸ ðŠaĖv[")eI‡…íóųYtqĶ>ß+FiøĢ,ÃHƒ”…Š+Yų°aÃĮ?&LbTWŸôZ‚ð~ÓP§>îíž>•t؃-ĢmÏjUđ€#Ól}Į“þCï˜LÐ%i5–ĶĩL6ŪläkŊÅøö|s=Z(bQį…Elâø―œ ķÕáÕNølݖpþwĩNä/訓ë=ēEÎSXIš."ĩŲX“NŅßyŸĸsĻ•ûxĶč2ÔŲA‚qĸPžýĨXœ­õî3œQýõKh'HY“W§ pv’ ČūÞ\ĩ0[™‚ÜÝjŸ,‘õ0æsĩ ąC˜ÃÕ3>V…õ Ö霜œp&eš‡M!dH[Ū;p"Ï WöÃۅą4ōiþ"Vt$rwïŲy*AáQ§{pvöĶ%oGŌ›ŧg=%_ķ‚ĢapžåRĪdĸu>·Z…û]ŽĀ[ é*#lĩO4ąú=W ëí;sÕ|Rŋnü§Þõ}›˜œ#ļŪkēï“tôKýÝĻÚĨĖQûÜOōbԌ^Nh† cķ(‹CĒUgáÖ E”vMf―,VÄBÍ)ōäÁ…īĻLhŋ‰3YŽŠ ŸM(.Ֆ`avéĩ/Á܏ރĒÃģH„žęÐĸpÓúЌnŠjÍ™…ąŸÏĘÃōØãSGX~ņâõJÆ3Oüĸ5ܝhâļ‘Ģ•āŪæŸÞ1ĩš°cJa yxÕZ'ŠC/ÅÛŨóĖA™lļĩA“õgöĀ‘Vōēī7ņ%―ÐHÐiû_SĖĒ_ŸXųÂ:ŠŽ‘t°Äĸ#Ā\܀ÐŨŨ&z•īTŒËÞŲbŠíŌ{YŅŊéĢAZGāy ī2þmĸWN—kQŊäŲûæ-Ęøiˊ…pīõnŠĒĀ (þ›Âš“|ƘrՒfDoŸ[ÁŲ·ßTcÕÛÍ7>'aú ,õk“°PŧŲ0áŒH;\þg,ŋ5zæn|,WÄÎĐûŋÞfÂJåĶ@Aãõžß@4 Ėž|Ž\MuŠAŪwĢŧäWfĨVWl/ug§JÞåÃMyóņ^ƒ”Æ 7,ŧr‚þÁYÆ·5ĻgŸūƒ 7t'™‡įĮA\S.|š#Ŋų TJøķ˜î[ÓTūž 1-?óÜ˜ß Ÿ›g'ŋeĒýĨÏFđŽŽõˆÖ0‚CŋPŒHˆ™ÖQfuð -äĩ ų/Ž™ ūmÏĄČņ#1äí―í`ŨÜ\ÅÛTeÜ]Ve ŊÁlā‡ïgõšāēņNs@r)Öv|#Ėcķ.Ã1á‹J”*FT˜ôĻD[Ģðų}õãûÓ9ēŽÂYÏÆT ĄxÁˆĮ'Ęm‰,/XöĪ%ӕ”øÔ%]ûÐð6)=ŋúÞäÅgz ï{īÔĘâÚėéâßYc™V•ɏíÞ„T@ƒ3aĨwwī|2Ï] ĘĀėãŽēúýîīoEÄōG'0>â Į þs}NHUúŸV‚Î_zŲQðŌī^Ïą spp bŒ‘(7óaÃ87 @æÃt~|Æv`ČÕEsxį̜ÜNQ{Øž„č™ĸ€ČëŅ\(íķÓ8ØîŒ ŅĮĮi֚Ö;ŧāNīBz­ÔXHĪęZœŊ ŋa Ý‡ŽzLVíįÅQ)†ģPôŨÝXaä(hc% 2…ÁëęÖÚ‡ 4‰—3Wđ.Z(>ÞC,úE)C}Î@ýk!ĪrvŦßhqnnX‚”<03#ąČ—BYšü1š–íúŒÞŽų;Ō2’Ýf―8ęŪŦsïLúØs 7+ž° iûŨĘCM’UŲrĄpÓVŦŠÃ9M΅ōøgóœuXĨiĨÉŌDšŊÝĀĄ2{]Žâ\žDŪÂ{ĢŦÄM1EQbdĻąīŽãJFŪ4gĮĀEŦï4’Ä”K\ą,zÕ-ņ[$v ‚·}S‹*•šeÛU:@TŽÄđ‹{čįšĮ## KôŦAÎ`”i\raå–ŋV†Č:óyZkũ˜1ßPÆ_ũS–BŒ―>FW—æ 7ËJcQ%ė75įTŪîJÚØđYĨã‚& ŽYqŨ6„ÃVFßýÜz(ófσ!ųКŦd­ēŲûðÓDhÎdŸÚÐgSŲãŋ”œ"pŊ"åmaŽŊ!ËT$‡"‚rķíBk…ÂóÄø](ē{Šö}Ąt*"”ąīlp>ę3"ŊļĻT…L`ŋu-$R6øŧė\Ó-nxP^OČq5ïv‚Þāīy $B°$ų hø‘(˜DÔnûIT€‚&ę#‰…ęÓœM^žÞz+f‰aßļAwt3ŠÆ$Üõļĸ,cP—īR§Öõð:Ÿ(iĮ’‡zCÉ#ŨlĘDÖ[SC‰ß /^fžjÛZĪÃwĘ{áMJdsÎOëJÅ6ūŸÓ.tÚūîæ"kCoģKIÞ`ĖzŪÐpڐ[Üķ„qðwëR–ī‘ĄŨįƒJĄïöã„ō†šýmĖ;GgL/ģ-Č(J.xĘĀvĶūXlNĸ-ųl&beŸTLŦ.īĶŋĐųÚ1˜@ėâ—r+Œ~=ÝôŌ︘đðYÂŪũGĨM čũð4ß~ošĮ]ý›ŽE:mŦĩĸ;õ3 “DčŒģkāNšDÄ.Í,ž§=í6ėŊēþY ĀcpxĖû^=ŒčŪÖõĶāRĪĀĻ›ģ>Åk/Ą˜'hęy!KŦ°.ļ 'ôÔ vëũe“öÜŸ—r1,g)Þ)ðr‹lÏå'ļŒ'GSŊāĀĶDÂKބoG?힟ĢēQĐSJjĨÅ;Ob8XâöˆĶ―ôæ0ÉøŠĮˆ·á€žēO‘øiÛlĩsŧjĨÍøĀA}Ë(  €xÄā4A*HÕ ĻėqøōN2Äč™<ð“üä+ëķ}ėäųsó%ĖŒãÚęÜ=ŋíŦ˜^9~ąËĮs‡ãÎ/5„?ūŽ bï)áĨÔ˞āƒŧÆáąĸ,UēöÖ§ųĐö‘(nxčá4ž`wt~ĒôîËÁQL64Ū§ĩœēĘûy'NĐX'°gō=Š•ÓÞĢÝėÔi”vģĻr‹™o8ÄÅÎ=Ôŧâ]ÆÜMPīó›ŒHOvėđ@_đ>JX]§ áŲVfĻ–cŧðsDĀLðyÏ|úĨ„–TÍo5ðn8—‚Ã_äĀUaŧËįgņœw:Þ―œƒ Ņ0؀،—],-ŋÞ>€§ŦmŌ,PiýR0ŪFÁЇå͕z―fŨkuô ææĖ•ę§Ąō‹VäŧŨ{úĘWޚ?-hšÉŽŪfžõŨ—ģ˜ęwÔρ2$oQ•#ϔúģ•œĻ’š€zĖVrcėPģP‚Ŋ…‹ßĖ:{ÚĜĘŲ1Ņ,‚âðzW] )ËsžKw†ųNĨŋ6ȌŨĢ*^NÓ`bėdݘ›DÄėÎĀÆ‹ŌŅhåüŠÔĒÆéÎÖg–? "š•ÎJ`­cý ­ COäXėôģ™ÃéŅąöUøÅø:îãúîĒYšÃSžFūô†bI`(BōcmšY5zŧøÔdKĖlܒžWÏ‚õNZ›Rō(›8HØØÖýõvw`Ú―GŽĸ)6Ų)BEÂÃĨĘō#ïŊ·iÖã7õz{ëûŽdl%ŋKĒýđx;z(Úzî1lô,ĸmž‘ęHš„M0ø=íĖpęä$…‹Bė1Ķ―ŸĐŸĨƒ­ÃČõėĪEũĢ6Yy Ā/)‘ŧûm…Čéx"ĸ#_įދĒ`GŪ,ĮÁ˜―H{u”;“€Iîņhí†x§đąÂŊÜæ:5•ĐŲ·~âīmÝįåð>ĀyĻK .íOiUĪīýPŊvŽÜnDmĘP‚ąĻéoũ™ÞBÎ݃BįPßnHAK1:eŽŲ6xE iŪķĐ֖[[@ l?ģĸƒ 3Ðũ 5Ւ­`˜æ:đRä'ÔQįŒP~ɕ›T‘ĮiŠŽs#ZAôU ãý †Mū9ÄM#ø‡TâΧwļEđ;oúÐ*<=Úõ˜Ē6QEžXnl_Í2cýï…ƒ“å Ÿ>$īƒéc]žģđšð^Į)ŋ 1ĸov,>ZÍĐ|ĩĒĨėóh7æŋ:įšáևԅljü‘Ģ@&™/YČ.ž,þß"ŧĖųž ‡Ą‚ĩ|§'K>åï+.wfsIú?ŌVđi9ocš˜Ĩ`ėgėCš―ģúģOÉdā‡đčą_œ\ËdŌØ‘–~AÝæšÐ5‰―Q+IÃy œŒUįaå /œ‘LũÁzš $J"ŪÎ~đĄ˜Ēv{ i5 é}ío)r?ŌÃpfōčÅ6T0Ô[īÚ|pkJ˜üÍņtï-ģ5)—č4OâĐP|€—YAĘGNÝņ ž ô3đԇ ïÏM >rŦĐ&Ĩ2{þ óðéÎĀęm—ŠÐ1mģûNPcÏŌЏĸLļÕVi^ =[v?Ēðóˆ°+_… ûˆ?ļpH˜Fe[›†Ī7ÕbķHŪēÓ|ŽšŌĘ~Z\Ĩ°Pyžâ(âĘG-”Ÿå‹hŒÞŸéĮ`zÄąWĐcZÂŦé›BI_Õ Âĸtē'nŊãe"ėķ;8ÐđÝŊDKôt/0 ĻŸÐÅڗ<2Ø/pßB&oÝđˆõBžĘæFeĖR…ąÃAø…ŸˆÚV4Ō6ūφœŧD^’ÁuŪâ ŌLëÝMėÛÜíĩ;ûéĘ 4ðm-§fįTx„‹XĶ%õšÎޔ=ó€ĐC|2âd4dąŲČânēŋ-ÔSgþxę1ÂÓ…Ü'Ë5ĨiĖ’Ęõ!‹ąZ‘eÄŽÂLÄãũö;}}~þâ Ö_sííųú ?D ?VĪþŦįõiëØpČ ĀŧĩýĪØŽIƒw[#g^?‰ï ņî Ŧđ Ī-‡eÅI%&t H“$RKR_!gĖĒ’9Þᨭb]X?„Vë^í<žÃ+6Ú^eŧMŨôkđũ–ÓĐBQđԖ‹Ä BZōļ ^péjIãËôbjŠŊ'tbúÉø(‰ã*Ũŧ·āR.äŧ#čBœŦ^Ųn›aí…ö†)‹ ― Ð3ĄDįŊÚAƒáÓÐEīHŌã3Ŧ}‹đÂcíøáöÝCƒį^ n;”VBBå‚BÁ ”ybFēīÆ.öāāįûķķ?øÎûĮÜļ_,˜uÍĀi,ĒĻ­GĩÔŨĀDą\Ÿ`p#y;hÅ/aȚ˜$ž}r#ĄÐRösąúl”4ÍMbIzĄfÅ{ĩ‡ûŊîÍĨMîI8XÂgbO'Ũ’Í+hŪÍït*Ãâ+Yf?á.H’žÆhwŽðī›ū%”&#“ŸgvkĻ7Í äŲ‘—Ū\íÛÔIžhÎįqĶ™HõóŽH7j ûŽ–Åm“ĢŽ`MĨK*ÅAčÏf[)+RؘõmÍKhģo,2FėU˜AĀJ5ŋãŀÅLÎ―‡Ģ>ČĘ~U<ōšŧ9QĒeŪž7ûUA}gaBôąĪ+đmlíeӑq9óĒĩĩ ĖwŽgžEBŲĒÄ"ģ`ī82>%ąTū Â'š$ŒŽ™Ø:YˑËŨšÓĮ-ŽŲ-R2:―bŌųubLŌR,-MJFmĀA?'Æđ=;ģ€gŠååąĪq0Ú Ŧû ðŨ—‘œS‰ŸOņ=ZƒŠŊ1ā>/rC™1‡LÛڍ巭–­\y•G*Š"ŪÝZ3õĒzj=Éf9t`d }‰ø֋}ėp’Ž­ ĨŊK2zǁ Ž„ĸXõ‘tž0ЙĘwfÔ =ā‡DķŊ0ŊðĒCvčiēÕE–@ÂÝđiÎ`û…úĢķ Ģę5ŽÂ< GūĀqë‹āuxž)‹ ŠTEXâKfþĐvÄøyŋ0û―Ŧa‰V4ną…b\?nŽ^Û=hiœĮÜpï )pĀÐŊTа7(ûN°qrU*rĸŠcÛÉĘy ?ēÜ.ßÍ —Ģ‚%úŪšX4RZIŨč!đû· Ü>fŚ“ósGZáĻ{bHHkEŽÓG36|8!ƒóÐ _XiĶË@ėó†đ6LˆāŲØ:a2ØðýJ fäôMl€Ѕ“đÝԂŧ?=+ŊoÔSx dŅënlRäŅĘQÓĖúø‰Ũæ”3ŨDĨÐ Įý;'TųãÎdr.b%ãsė†Pæ00;§ĸKHô§Œ pīDZeß/’a3~"ē›v8ŽãÃ_û‹V…Ïr xĘ+vŲĩžNî\į,öó\9ĪĻâĶADdߨï·zÃĢč?“ĸ(čKÅÅ&Ģne‹õ$ųšf5$ëāOŽ —‚.’”đ傄šēÞ\8ąýŒX ÄxŨ#ũ§ PnBd1Ņņ=‡L’§uÏ ôÆĩõOäg5íRg;蒄x@]þHĸ>:?ŅŅýčMáāT 0ö<ģýËŪ‰*júž,"Ëó^bĻņĄō“/GjfÁčŽy\šŒĒŨCŽŲAŅYˆw/4CĮ5ÞĮŦ=ũ<’0KzÕįäđ[ĸKXæ%ūg°ˍÉ·ÄzųaŠĮ>cČLó+Ÿpk”Ģ=ÓQ+БÉáôö3fß/°3F/Îá0˟z6éĘ]ßVŧö–öX‰b ój^Ôi'”žĀPÏÁ“ëĩ§Å įÜ­øīŊá =ũzŊ@ˆïėNĮâōČā§l0ž’…œ*2r{L–Ü ÖôÎŅ‹ ›w3ü=GŦčĘÏå Zå3zÍ͚ *!;…“ €ģ ßšó&Đü֓ÃēžzTņz·š iüäūYČķ‚]/݃viGÏB9Ũ9~CĪ\[sZJË1?R―\˜üÕý߉4lōãÜÂāœÚļ#æ‡@ũÕ|w†ķAËBŽØ‹ĩðčC6aU‚ˆ(ŀDV8mz8eþã1kQFÄtŒ{8BwÚj• 'âāMĀœaÆŨ]ņB,ņčC‹VOßtŸŌdŠCčbđhâį? “„0,œIAPēÛ†4Å[ï뭆•T•Ā6žņÚįŌÃcýČŦÁŌ―nŠË‘ŲĢå0ÚúâØáģðÂģn@7™Ĩûóâũ3XčūÕdõ…ãÄ˃„mžÛœ…Ķ6~ėģĻĩÅķlÏOÆïĩ―‘KiÂĨ3wzUõÔĻm(ä’åúÛIļ‘đ+ųĩAĸ5–@]đâ§lóĢ?fëĢđā(Ôŋ]ĢÖØ(ķåSŋ<‚8hýJVī°īUJį}3;'ÎkÄYeĒ@öķfĄ†LĖËØŠbUâ‚óISÍmßŦýÁvä“ĢŠ;ššĸ.Č(Ū­û€ úXR{†OdtXãó]v>á݅ÝÔVØĩļĶīzžŠÜü  Bœ/ )5`^ȑ$?ĩĘO(”Đ.âj=eöݘðåBŦ:)'ôĄĩr•P}ÂŊŠ--ŧŸ2”Āö“îeĢš ÅZ2"ČäĪ~Ļ8Sm–rþðĶÁ"âSCQšˆ―…i:–”åg™…đƒgIRŌë0šTYōÁói Ž„ĪęÁbžrĄ]Út;;LÃ<ØÄÐyÉÏŅí*„ûlž›kļxÂ[ްy”#}„öOŋđ Ú‚•F?EŸ"ŲĐZ‘4YLĨЇc SēZĸ?―Ŧa:˜d92Xč.M7w` Ä †ķ`…ČZ62Œ’îÓsŌŌ뚂–0gyy2Äøä đĻ6ïŨ€3ëïč&Ë·!E MWđSĖ sšNûrĘĨ§•nåÞïü†ō OAČKņŠÎtI:l'ôÎþ(JŧũŽŠ„9Ú:X·ÍÏŋč™ ˆ]f!Qd$Z—‰ŠmT―õģčķuĨOÓ@ÔŊˆi0Ōæs3ÞüU'|2^méÝÉÖú%čgHŲÃÐxŋv"óI™ĩš9%Ē.Jüxž’4GÅũQüÔg.káB>þH!–qÝCuūӊÆÖYįIہ?âŽŋ’`ū&ÍøÜ…ÎX KC”ÄëW/ÖMk€ĘW?Ųu}:Vœ}Z{P”ėõQėŧܚ}ĪdYJE^ÆðEu‰īšPõ d:ũ sjĒ­? æĮÂwō!—j—S‘éÉ;·qŧ‰ķÆĶRi{ūÏĪęyĄÅó&·šõōW a vMl2 ĢĸĄkJý›ŌJ(ÅÃ> ÕššÞ~Áš {ĮõĖ_>Ļ RļÄw›+U–ž1ęIĀiE•5 {ķį6Ÿ 1É`!§‡FÝÚU Ų.ĢYÉĮĖüŸ<'ŪŦ―ŋš:ŅU>7ü™š=>6€é­ž@U]Swų ÎGÖ7öŌ“[ĸ[ĄþāØSŽ&oÎÛõ‹-ŠĶfe ʆŪ|ĮVŪä”ŨPSAüōÇZ—þ™ŧÁū-X$ Ž ­CØa•Ԝ"{þ8 úËŨYĶökŪ­å ͆Éˉƒæýí4HĐÕgP.6―ßKó]‡·v%čknÁ‚Æó ģrËÛ{,Ōc m‰ēã?īŠų.“‚@üšón1á‡;Ÿq ó7ŅedÜæPúÕŲĪėIFųĩ-ĐS—LYnÆ9ˆIZĪhŽ7~üĩ =ý9ĒĨ˜å4q ģģ4*=ƒ*uC-š}^šģcĮ*ļiĨē}†ŲBŒ ŠĘĻļŒ1ĻyâŽÅļ„k܇þęËņY-îŊĪōgĸfnY/ YÜUó}ïˆÝx€%ũ ÜØą6čđø#Ygó›vS-73ēŨSÝpģŨ_ģĻݓ->Ä/–!Ī Wƒģ'ë"|K]ŨįŠ+€Q{ŲÓŧƒ—ýöáIÅm ·á5 ž?%ėbūjaäj_ŒhЭ)–~Á"õdõjØ-Ú{КæÂŠ.€”š $P6ðēÕ^ö„_:yŒëūĖS=wyĻŊĮĢšM§‹v󒚄 éWTØ;ßFéSaÁÕđ7MÂX%Č‚æŧĖFciœĖʘĒeŪ‘ipŲ&ÔáۈŠ.@ķõû—ė`™|KqČŋņ”ãW\V=ķÚI]â ÆIYŨüŒ]{<bĒ(Ä%”îĒH·KL݃7ӆĢíhĮ0‘šóĩԂö,īąs― ~vcŠaÏĪVHU’ėÜŦüļRg,ÃbĢ&Á|óļw’þ î›Ïī“™ö_픡njØöĶkQįTlķēIÃ<’b@ē.jö;‚čƒ˜?ÉÓzļ›c„'Ęá9+úJˆēÄõĸq ADøkŲeÝĸ)IįTFðŽĐiãŨ…ĸ>Ÿ2ÏlĄÜqŽŽŽ ĻÜyâĒ“áþfę”Wks’^ŒĘŌŋüŨðĮm‹ ųļßéK€\_―s8IK)ÍĖį{&*ų'Až@ÜAŠëQŧī9NƒtUÃôEF$Y ūā\‚Í€FŌĮAäÔúaũÜų(hŽ8c;“—O†ĩ3 aåđuË|ČCÄF}ŪŽ)ę=SmÁâN!ã·—™ÖŸ4­ŽüO”Z á§&4CR1D3u‚c}åEcĻŋâ>Ŋ2õ~ķœ;Lę[0fÞįí!oÐY\gĪkšešVûĻ—ŅĒwn°čŠfūę’äžĩ’ķčE[čŦf0 "§ķ ązĮŌÛŋ4,™\ČkžÁÚ@3$ÂAĩÀ[—‘Ð)Þ/HķV\Vô@Ęã=CÉ&ÜRĄĖëD1ó8ˆ›ÍŸßíŦcŽH+Qh…° AŅû^+ØļŽŦÉó€üSB }”ô!Õ ę(zl‡p%ŒOė:JĪXŌÐņu˜gŦiũˆāš Ýf-t6΍ÛXô‹!‘FīŒ‰|Ï+Ā}Šþíž+cxGî+!Ā+ũ―ƚûBv(ÜÓ6·_ÃĢ™X‡G' MĻÎmNũųá&ÍBđ0úw=ÏŲ!d‹ÏĶŋ3v’Đ<žũœuūƒdũÚHu˜‰?ĸoœÝú“8Yý$Ĩib˜ŊŽXĒlā,đ2)ÆŊR°þÉ-åîS­TëŋŽ ã=sŧũėęY›Ū›T?į ˛mJŽ ČŦ6QJŒ#E3†]f eþÏÝđ]2ž'ë„ÓbÃá!k,iÂ}Fëe"Ŧ-ž?PÎîÂlö\§wÃ!PÝI3TėU ÓâŨč'PmäΆö`|:˜]§ĘÉ= ųbPģāV•č؛ Ĩbý@įBņīvŪC™ë;’Ņy`ŨéĮüݐōۃÍ$Ķ–Ģ‘ĖÁÜSvôW‚(EÄ4ýJŋ2°ŪÍgœĐ| =šlÜcTînņÓúȌ~ÝĻÎûtĨ„žd™ -û2ąsōNŲÖ`‡ WPÏüîē ę+ ‘ŠwÃG™ LšŠwîį6žãhŪÖ:$ĨDō"jĪ,Ę__kžr}~+ē%ÎuŸõČŌōąA`ŸÞ•h)`%$vÂ.ÝgýF*fāų"ī Oéâ1!FÜÄkÅ1ĶwGg4ûv'ïn3ÕîËČAüŒS§ƒ? L‹ @ÃF„ĸ[ö'ÔiQ‘ąQ:Ų—þđ Pč?ĸĸ{ÅĄ+xåųóō/,Y7s(Œ q‰ú E.;ÔÛ[3Ŧj æcāŒŊ ã6]ŦVŌ0“ļŽ/ŌĶŽ ŠnäĖĒĶ[Ąīc0?―6đƒ–bjąŋ™ĮôHÂē”đ™ģÉßͰ-ŊKžÐį,W āÅPkŨMÂ7ĶÐû™&=ĮāœW8:6TÐëJ=čŽ'åĩ”’ðŲįG*ņų â•ëÃÏŊ3ŽžßqQÚ*Žr?V€dƒM譅ũ…QĢÉE=|eÍ`'ϑwŋÖ=ŌPō|D @4ąåUÍœæ3C1Ü}><š*įIų‹Ą‡ĩėĊčôFŪgũ75)(ōœ 5‚)ÛHa9 5Ã)ô=ė_e3ûuÎ9­:.롎f‹rq67ˆŦ<ž\O†ņ 1ûņēúžÉ+`ā_Ū°3fž #}\—БÔÝęĩpīyĻšu(=_/ũØqåúý mÚ§Âø^ >lŪ‚'<_cVŌČÁBJ‘-~ÃY†dÝ[ķs·,Ä֝WVč°yÛÍōvÁk“5ÓéÄ;úkĶ=oúôÅäęHÝ<ĸoö­8Ÿ"'‚Dc`,6ÏýĪTÏäZ1ūĪ :ÛUx‰fŪžQ˜ ÛýĪqwEūŪŪnļgQ9ðbl!’ <š„aFc(5<]k„ęoå)—žĐjˆÍn;.ɔî-―ûNƚLķO̘ž]íßb›ē؛^XŊP§+Nó-^õBÓDYÎĀgYŋŧÚýŪýÐ4PÕUÆžyė^_áyÚG6.·Nå„cŸÖū(ņd(?Ø&˂č)īR0fëđ=Šx*€Ļ‹ckéžÏįŒūãqžŽ…XMīM™›^?é“Ģ4σLßŊŠîÞ)åŦ1~€Ķsk_ë ĢbĮĸ\°ĩ(Wðˆß „îÁėM)EE[)yö„Ņk |")·ËZ•|ô? īųCÔ"/G'’€%―ބZNĮļ7â#zöîL$"  ;ð~ŌâCŠþ  úV'ˆWV9åĢ·ÓŧŨōÎÄυ2ųPĀnč~W49;%QĸU&DVˆįy&ŧ•w8’AnxjÅÛí­loËþŽ&71HĶ%€Ąųpâ;Zģ,SÜ–āt‡ŪœžäJôʇō†ŽÞ qœŦžĒ+ý{“–kÓО xÄðÞĖuƒ7H u6,‰ŠČY…ƒâŌۏ˜YéĪdŠ+ŨĄ2ŲsymA^”čåŅx'>gŦ_,SŸúæUģĘ\ĘāãˆõšØK‡ž‚>ō’@Ē \šqr*dēŊĀ|YlNaĩ+ŽŪß+‰Ĩúîį„āÓ0čš,Ŧ =§š‰ģ6k:}í…ý™")=”NƒP"yiZ=CîUU>Čič}ËtXÞ8•“Tŧæa0ŧā?F†éÎeĻÍÆÄÚÄ{Ūr:ģÞpXĒ8ļíweÐŠ1öœ‚ødŠŊ%ėoÛÚÆŧš•…gŠLŊ›žĪóÃLŠ0ũîYð`oËáå3EЉ}’·âØ$7Æå™dđÁ–IR3=­ĩ*čkuâ*žÕao.3?ņ8ŦW~Ž6íĐ0°|„ĐM͜đZj”ŧōïĖ S]Z) øŒbĶP2ˆ‹Š‹ÆvqģŠš3Ôą0uĮūÆJp- Ö§ ä°Ŋ“Kôíß@(|e‚ķdŸŲ‡īÛïðéÔZhžž"ŪuÛÜųĒÛĀ­(Dq>?sæģþ7|mtO&FžąžŠeÆČĒïÆwüxFD!jóDPkÍ|ę`[yvS–īî§§þc‡ƒē%DOBuũÂfH{úâFWŦĨŋÂŨ k>)"˜†Ū HfŠƒÞ•nĐ4ЉmVóž^ÞÔúÞē4 ŽÚ}Rö˃Úņ8KIöO%0Ž_Îïî$Wü ĖéP˜}åtÜŋ^m*óš2Ĩv7prF·—b­é›Ô€6ĒeQ5ĐN)0:—šĶZ!I5Ą2œ+“%UWDČÁeåĖSĀ~Z<j ŦĪæõØN/’Ißo|ÃýĩNä‹ žĸ.BÜÎ6õĻz‘ F*Ķ0ĸÛR°/ÛsËšĀčïCdGãû‡/l6õSQ˜+^œãičXĨŨAx{Ü,@Ņ:ląō"4ĩ˚ 7Đ-,6tÛę7!eÎچ&„!)ÍÁĘđQ"ūÍ,R°`a‘D[š\ó°ŸøŪÃ"F Ë)Čx‚Y€ē!Ō†Æ6ÅŋÄŪ3-•RÐn>@/ęä)”H89ęïüŸę߯ĸty0īü’ŠPØSûɋ'ÝÁ\Šnbö\Þ€(šž J3ˆÕZ CŒ:ŋöG+ÞäĐdL(Ģ8ē͇J|Ū"WÉ1úërœWŊĄ‡ŠÝC4І Óõî_‡ņĶ™ĻfŧĖöt=…Ä6―ÛÆ ģL"čaQHp­‹šËŠŽ(>`ļ’ƒš9*GÍúVĄŲĘp…Õ>\žYÝ Ãũl8Īō`j‹–/Å0f`kŠžTþšĘGÐŨ]täīm1Ũļå2DŠ"K/Q'Š…Ã]ĄuôݘÐaËg ĒԗLčï9úķ“y?Q1ÉäÛđÍĮ‡“‰k‹Ļ-Ōe\Ėã€óļveÞÎ;æ þPūÅڝ;˜ĩu…eî8nt§I($ҁ§6v“ģ^üøÆķÄ<3åMā(p(w]/`ÝF tŨÃŅÜ]# T­Ú-\xēķûæ\Ôϕīq=ûNû€øŊQí!ŧĘį ôfųÉRgæeëeZRĀjĻĀw,ÎyëîI86} āGnĒEÅn^Vïw“vôŲ :p@ģ1–p…?Þēą2ÓS2õ˜8@ô\JÉ[M#įoðũrFĒÏ|˜Ø―‚íC(†™.)áß%ĻŠ0Ė@ņ9ŠŠīʁ%Ė ŅÂŅaßĪYī”ïŸBž@Ö~KÉ,øCĐĀR24íĘ 0ÓĖÐ;4āĸ·Šķ1$F†5$Ã[žd„{kõöXNXÄĒî|^öf7ĢŪ{ïŠïÜĘ·#}kВ߉BÚŅõæ>ŪvņOIĨ(åūŧųÕö nJÉ(F|z—r+.ŧt€”ŒÔOâp>øŪģCÅ:[F~ ŠÕuũ*ÎGãÕhuŦ°āŲDĨ%ÂãZ!TÁëây+!œ9‚ŊŠ ėø*X­Ąŋ.>ü01 á=ÁßփK ŒMG˜Tt†ÐöčŦŽýYqþŠ0ĸ+ž XĩëŠ(VĶKë›j’/Ę­Ą îę"bČp5Ūvį%œ~Y‡uę=ĖJ^bE9ĐÛ2 hô4Ɏ‹œōjÓ/›Ë‰!ŠĒsÝÍũīôä ĄĘä3rs~ĢYũ0É―ã§llmmPaŠlÝÂáy5ŧŸ0Ķ!D•ęŒôÖ Sfuoô<‘íM9ČÐDá*iRšīĻåČÉÆö\Þ,^mđ5õ)šãŪWØýļ =5’ŅŒ7Ûæ ĄŽ$ܛG”JWȋvNÁ™tÍ5·ņōĶČI\æÚ:_údx{âÞÅ@ý|~2]J Čë́D1 $wŠĢý+ÚÆï2D:Έo™ ßæ! a;}A õžĸ$ÔÎMA5ĪX˜5ŽĨ{sĘŽ%ĩĨmāN\>ĪČ<?ãĢhā§v ŧ)œĘŒ:€`îĨôäPšļÃÝ1ĪēP)ïđjÔļŽD•-”=ؙōE›5ĖØãáüũānJ>wOWLc}ŋĖĒq…đJšë”A? Āc…öĐLÁæ–ō―QĻ*pý@õÝĮ-“žÂŒg:ÝĀõÝ>ĐQ8ĪCÕKT rúļGlƒ “E@.óęÄĢÝČ&…jŧÜĸƒÞ'u­ÉCYݜÝBPAõÕ ’Me’d€K߯Æũä9AYÏ{æfw3ÂGJMōĄ™ā3ą‘ãĸ €°ÃyPƒ˜3?åIBCcōüK3ãŌËĖÐkŲG-Æ{ję7•T0äq}Þũå‰;cšŨ3ļČ·Ģ” ÖÉĘĒÕķÛBëå]-šnã_E{ÐĢúŊpW§z}Ž;ŋBÍ2IsûœŠü]%6€ÁūŽqgæĘéÁąūïœ`ŋËÜvÞyw’5 }…âåĸ4ÜÝo åĐÖ% 4"#AÆÂą\ŽČ‚øŒdĪŧuļ€Náä§ĩU‘ø·…ĮÔË―øčņŽõŲŊ2ģ9zÝŒ™ū6Ä#ršBØs؉ÃíčÎõIßŧa ĒDĘڐå43ģDÖG‚,-YĄå#74ĀôŽÏrHĩ+ý‹ĩä?ŦÓ.c&Lú\4ä á[ƒrrÚĨh–<Á†GdÃïó‡J]ęEĮ„S+―ģ$‘ZUJށįÔÁ9WæŠ+ģ<(☌ė2§°?pOÖĻ\ĸšÄŧ"aLÁčR…wu4;­Z‡ˆÅCJ 3dýóđ‘F―ĢUĀÛÖ8Į™ú‹n/ë&%ÖF@pˆ­—Å―ę’!5Ēč/'vïŒxãų`›Đ[“ ԎCǰ=yh3=OĘĩg.•CĘ8Ēĸ$ĮųŨĄÁ―{åoAvv!°ã_ؕFÚTýw|fxWDCFŋ7†Ž6§æ^iz‹zkw =•­ēx†˜Š‹-ŧOčYŦŦŸVlŽ%ô7āÄģFîķÜ.ī4ŪÍĀȅoį]ųŠD? óûÄ~°ĨfĸsõôöNB9ûÕÔx' b ˆęý2'Ė+ĐÛ5UՔ‡S…vÎö―ēþO`ÂÞ\:öNđÁB;%üý>W[íÆĐĩI)WAöOY§3ĄŧoDäâtq€ãö9þĮoØõûą}4/؋}L3į­a|ęQgę,ūu íL°h;}\îSüՕŨÚAōŊÅ gčâeÃĢB ^›q$ʐwކÖĀŦąAã˜6qĪQGG$ŲĶ|‰CƅšÎãt[Ņí&û‘Á-ÅØųŠlï8ũũŸōMoÏīOÝâŧYîŊķũžî’ú*“ß‹ë&á‰Mu , Ísý“%ó&xFr­ßY?ÎÖO`ÞreACåĒxi\ÝŪđh|=V7›‚øņCbž5ÝĒö2`ØlÁîWo="Ōę,ŲC :yQƒ jm^BūT1‰…# Āí=ŊZ"U"ÜÖ:Åæ SVdÃ)$ŧĸN3vVžöåiXߘŦge—ŊĒčÃ6‹ƒ&dïĶĖŲįہÛÝ D†ÄĶ˜ðĘė6bįē‘@2ƒŸåėˆČpJ·{••Ō?3ģ,2ōÛnƒ™ý‡Eøąuz°`Ī=_bē4}~þ|1ôđÜJĒ=ã}wîsüĻofú:dNýöûēl••"kãŋŠōB ؂'~ÔËj9t )Gšŧ0?t@đ˜—á’DŦߨ%ÂK˜@4œ'·ÔūdĒ―X˜óæÂČĻðIXíéH/øj‰íˆíŊKĸElŦ[YðÏŨÍ•ãÞô+ĖpģÎ_qŦ7~kfūŧŧ“qĒĄŨg2Ã+xoędTÉjobŠ?‚rŒð@C1įŠ`v}Úðę|C·N<qū{DRâ-84KÓG76&ö!<ý™õCļŒũë:TŽÁíóū|F*@Ĩí`Ą?þ;Ї܂döÂ$y.ĻídAčŊïų"á Õ`ÅV‰Đ„Ðwï#Ї0ú<ž+ÎĻx`°]‚Cb†8účðéþcÉŊFýЖ 2 ZYHbRƒĶųJÂhöčĐøā'ã5p!nĸ>C}SE/í­x $X6xiāvūT.äĞĒmS7éI…ē`\>éL âAŊCđĪL^C‘f-‡ŒÂ—Āž†Ë ÅīpŽ 4Åü°Ë éIģQu{Éž \b§)íÖ?†N 9<ķœ°ûL…aÎō@ũŪkÚ WęqüŋU5î>áŧ0–Vj“G Ī.;ÁšōŒðjŠ<ƒLi~BWģ#îóđC7É+ĻuŨl)""đ&k*§Ó4#k ÖÍ|ÕĖkô™ŦÉcÚ]*t™ôU Ļe|$M 5Ža@Féņ”Žr  lŅ‘t›{ó”âëšĘũááS=ņ~JwåŅ›ņĶütßɧ/M.­üšïūM9ÖđðčũÉĒ?F̟iņjßŅĶđ?%ņßģóUŋ3ōR/[?.ėüŪx*#áém>ęøÅ~ŠBųõWįØĸQē8^œŠŪŦö·Ũ–rÆŦŸ€ÓĀópÁāšČŽGŲv›Éø&ynD#ó.ŽbPĩf‹—ĮÞījĶuøha7ŠĄ‘Ķ>BÁčAØģ}FŨgÍ]į þė`―y―“KŠ%ĪōMyZŨ°bá͒ŧÎTþg}ļ―EÔþ_YžĸˆiõĘČëSYOäwãągckgi7ÕÕÏģđ+Ž6úÕ7-!ŪeOquÜ1zĪ(æ ĩęŲar'–%ũ b;?TÂ'c{ëYdÁĸ]Q?þ‘+ $1Å5fš–3ŸüåŦ^ėĨ‚%rNßÔ^"ÄŨw—Ũˆũä3_X|IgĀžš’?ƒÚĖ–ōU5ŌâŨOm·K|y›cDą”čaŸZ~bņŧ§~" â'Þcm7ÄŊÜbôˆ ?3ąČ#›ß/vkâqßéõ\’>G؉Ž-+ņ‘™1OõélÂm}ĶDšŊcFÆYeBĖ*,ĮŽ>Ýϰƒ–ôį0 Ø7•FĢkđ’ę5Ī ę ˆÃãÉw%ėÜāŅu5Ąƒö9a+öđŪ_ߞž˜ŠĒíčė„˜ÖN{ûdrÚČÁY Ë#KéïlåönŌôČōüšé\kĸH r€ožxĻðÄļÎþö*aŒzOį/Á°@–ftøþþŊōĮ?ā‘ĩÁļ-Í(lËh}LĄ•§áå ]ũŅ: ֋öü‰Qí7\ðâœMV}vĄč°íĩāfēÜÃÚŅBaĨ j­ĒrþpÏïõŦĘØĀ$~ZíƒF–ÖøĢû tG–ûĩD'ĩ…x`‚ŋ―Á؅rïK?ÐŊ›<ÖūÞ"oļíjw#Îŧ{įä‚é˚ĢB=NÉG›Aâw…ŽŪrŒ‚J nę>î1‚ęoæ.›RąōN#·}]…=“RŊõlWĘ+\d†Īĩļ,5ęu ý 3’ÏĻfįˆlæŪ%ó&ĻT†D-‡@“Ļ)óYs^†ÖĒÉO~([―Ķ_tĐ·~Õ! ‘šE1PŽ·Y‘áŽŅIöĀ?ķ<`Ž”$\cDČČžÜTĶLĸ ôã’ę”đŽa]ÍKÜIcîv­Kdā[v•Uû\<ž)]2›ûGI<*S’iy„(‡âoē0Ü*Ŋ‡&gSĄØīëōOĸ>ņ„‚ēÂôm2.’dæMÖAïâØéņųNwĐ>R6ã7‚r+žEȉ!į°‡Ð•1ýûœkč―s_[v/ýeÃĸ–ZýlŒ‰@1ÏõÖôƒļŠÜČBIŸ3f1€·°" …–†žąą.ä8Ėïp‰ŋ›0}šŧØĐïa""%ĐÐÓ nŽ~i# VäJ—ČĮwũĘĸ):ļʑđF5ûãĀĨÕaöúx ])xŌÍeōËæĐsΊ~ü;Zö‡‰ķfēNmėgļFĩ]™ų`―į‚BRLĒėČó:eÛŽt ÔÅD―BïL°_]ŽŲbÔēðĘnŧō[ęޝ‰Ų8Ÿč>+ö}Āģ·ĸVÚ­Ī„âšŠäĪÚKįĒTģ%ŅáIŽÄÍÜÜÔËÔB=ÔÆo'ášųkö'+BiŌķšŊņ-ÆN‚mó·Ž›Vé.ZN‹GáŋqHÆ@ÃCÛŲ$@ŲfĒYg―ėa·ZâĮc€Ą^ÂŅicæ>c4 ūŠĀƒĀJژr^1k#ģ^čĮ9ŦĨ’ĸ~‹Ö;éĸ7(Γúf†*ƑxrœØQSũĨĖþØŠ§.Ī#Øs Qkï—"ŰΕÅ0Öø&;õ†LĄ-úϞąÕgS]}ķ&aį‚gá 7@ÂþĪĩĢTŨXīį՛—ųrüKáóŲx:q^QŸÐÚ4a—'dāŊĖVÍôÓNÖWš:Ž%Ž{.(fX;^pIũn[fDBĀÛjå n\F0TĩHĢ!w‰@1Ā}M?„%vþˆF7üJ–[’ĘíÉ*jŠNJûL˕áĪ#aXáÅZ*§ØÉŌ8ĐđōōĘbđŪÆ.Á|Aąôē4A­RŽííø]yë$aŋĸ8Ÿsíļ@e^ĐH1 4„:l$$Đ+IföN· &Ķ`ũsÝM›<€1ŽíMXÂÐ@FþŦT$%@đÉĢI'ÏûuŊDįköĶčo1bÐ[ä&Ýb7ŋ_ģqÅāußū%ërõRįüĨ-ƒĀ|§$ä\€NgŽÍJé˜6ã-‘ÓݒÕcđiŨ4ëūĒ. sÞ80Û+}1Óž .zI38THÁō;R؋•qÓĀ‹fED<îíüĢ|8x° ŠÚÝ*ļQ d@Ž\ë1ÎĪVą&%8:€0žß·â—„ÂÓÞːðŊ6šäIp#z ĒxŽ;ōŒ‰ō…Oļߋ óMÂCĄJD9…üi%†#zŨä+zÞUŪ%ķæŧ= ŋáÝįsƒŪÛ5įĒ0fƒx ŽWvïá%ķ” Ā%XÔPí9HąÂóm"EūôČ{LœÐ™5Ų={öâļ/W­õPAĮDėw•ö@‹(ÉZöõŪHyŋәĩžâxIČŲš”ėĮæ^ũVÜŨÝv~ï@ˆ€2œęœf&~Š]ęžÝ+D3{ņQfÉ\cŨę‘V܏ōW]E7ķĢzn">!ýųÆŪ–ŦÂÚKÛý‘á^šŅŒK2<'1܍xFáņ!PÃu›Xƒí^Đ)ŸQŠ‹uR[$šŌLģŋũIŪÂ0Aĩ8J™šVÍUjî>ðķDdvÃd "Iƒ3ČH”ÔSß(ũ~ƓÕ5MʖÝw?ÅúuąoÂ,7ŌŠkģð;ëæīÂY/ŪAóŠ“ŋųrâĻóå…Ý $ÉäâŦĻ)ýqÖ[I2Ōfý;ÓØæ.wãV—1Ÿ*/ŌAuØÆ§WÉĻĀPÅķū”GÕx <)>―Ï.G ˜&zZ7w.û—ÞP@a—ŦQ†hd ―ÁˆR‘^[oĸc_wĒ^Ī‘>LŋÕĄvĘËã4“;ą™;đ ZßĖrï>lzŊۊ0Ŋa€lIĒĻËĖųũĻē_E`„{l—ĖŪģà Š^îóv2SFéJXJHg8ጠî‚`õŪđþČ$7īNģ܆pŠāÄ1 Vn†â:xb–]ĀtzoĮčžđ}šĸ§Iþ{–ķ–EÓnv\žÂ]šĀA ĻĄ4ĸl79` Ūgz™ąÍÓžĀŠü.õËBČ_F ßŨ 8ææ“tŧK Æ.ņ~ÖÁbWžY…Đ­n7’ûš6ģĪCƒfĄŌdĘ-wē ĪI ïĩäpó_Æ+d>ĸ~ÕÖÅ)·Šãl m"ÐŪ—T(âÓWŅ…TČ͎ˮxâÜiK6FÕĩŠö™Ū‡<~Ėþŧū ČļXSĮļ=ĘTv[˧…ĸ2/·ÓÝx`T!ÛЕũTS5IŒ oUŲ‰ũąZėoAߐ%æ2ķënĘčÂf@Į>嚍ęôؘl΃˜yÍۓĪ>%ÕŋÓíMÚvZėŸŧÎKņĄ#oښJß7îóøï@ĻevŋDýnī†*t€_\CŅ„+døÏóZ:Ōïi l’y™į6ßÜSzf0'bï‰užŪ“ëææüēuũųŒīdĄC ë††TzÓÝD*ŦÓĻô•W@-Ū·Ēđ`·3I•3DŠcŸy(žÓõ ‚ļĻoC8+‚ŲDŊSÔū9'å †Ųr°čG„~mY€Ä îWĒäzž7äŸ[âP\čšĪcԄÜ`ŠˆėûŠÜúvÞčņHPïý&'6đŌS…Õ—IJÍą #ZßDÖ·ïõn? ÚÛ·l0ëýØz+,ŧ,āBÔE§čõ'›ūcåŽĻĩ•­qžāķøâŒ#ĖYP€ Y#úRIï·i7žÃ%@Xõ5cĨü5=-āˆÎ)=ið…˜0â;ũäa"?JþŒ• ôžÓ•ÁPÜŋ5ĘĢŽuo@öĖ øÆūÃ@ųę@ðu(Í~ēk#œÁ=ö;Ӆp#ûVdžï{ÔMæŽË4&ðũö;ø$@Mû§õDëī[Ī–/‡@õ*'ŪeäQ‡nöFïýēÁHÍ |+ÄþúÝĩŸôųLöVĸ#qI”þþXˆ;ęoŒbކIũ@<Ž18å†ärĐņïDϟÚïgÝï^“0Põ"^!$-D˜Āë.YWv?ÞAßØlÚĮß瀀€€€€€€€Ã‰Ý,ŸoĻ·ˆb|x@}­ĒiĨL=ånlQt?‰0s’åÉ=ø·œ!oˆmÖvāĂq·Čö™ÁÖ*›ē€â9ÆüĢoNÞVqō"“Ø€bz -oMAOōū%ÝļJ’>ßaYCø=zīû­ rDӏý}lÁրąôT:G· \o_OŋŌ§>ūåQ3·ŋNQÁSĐæšb…ļpM?ížiWڜ- €ßhÉ:€‘Ø”<{iĸ#+ēËmĀŌ[@ÂOSGJIguÂaRN._sVÓŧÕN:þÅÜAbŋ1$›1ö8FĶÐčÍũyûÞ?†Čũ’"‹[J‡Ž5YfCŽýRïxeŽ`GŠŲO‰Ķ―ÐtóÁŠ>ęÄÃüÝþ'ô͝Â7zjîÆ—M‚ģâ‡*ņ8Wų1MÔTŌ&o‰ģs.ũFRā݊L\FFQˆĻšcŽpœē]þô§E•ũ/ør·ręžē+KQ)#œôšĻ!yũ€õņBļ‚,)ʐaÁÜēķę†ĢŋŪg­ĘY…zīžĘƒÏüŽEŅĀ#6(e*2ŠÐėØã)|Ŧ}WÎEŊYŦiæÅŅĄÞē)LØd2‘,ģâü\Ļ—2ļoĒ8+Ä2đ dqiū|ĮExķwð+Å ŠuýlįöÍN{[֐ˆØjũļæõ@­‡ ŒX2†Ų †‘ū&-§—ņÉnՅāyžúb$ekÕYO6ĄQ tÖ!o‰•šØ!6Ų@ÄÜd%AEöÞÆ›vgą†î(ēŦ_Sx Ž €é6nÏ ­z>™ũăzVĩĨšęŽch <óebBÍ äŸ3:ą.ÓY—Α”n]P;ģŦĖ ģÏæųģšk–ÃįZDí~Y„mĮmēP̅ސå@Y6ˆÛĨ<ŋ‚ŠøĸRdŽČ#Cr c… Tc*`žŧ — 5ÓßÍė_pƞŋOڋãbÞąP@Ӆ'wėüąâÏÏĒý=KG1#ųö–„—•°KG6]dũ+ *'\ۃŒŧCS8þäu-ęä•Ã:i‰ãÜŨYØZ .ņëN›ĘđÚwh>%GŠ™ÄŧmÜæNhsÏl!“>™ŅÔĩÚ\ĻÎēazRŸrœ“ïL;ïôï†q-™ÜŠýWðc5›p·1ú „đėŽ Ã›Tđ†Yj>TÅ17ļ{“ė:IŠę3R·2D'ū9?68ýĄÏžļÉđĻwR‹ļmf*™*•}ŊÕž"ČŊžzäLĸÝ(Ûí]Īú ĸ% ’\”s('Ïß8ŌZ–NÂÍ|KĀsð߁ Y§ũ Uû ›”ÞąÖ|’wJ68j‰Ędõ‹l+ŋŨNyđ ·ÕčzîŽŌrxQĐÓ― :Ę3„2ģyÚG-e$eÓĸhĐÝŨŸ°ö/_ËšīÂĘg‡ôœ°Ŋ/uļā‹3ĸ‹cš% /za~Æw~U:K Á*|‹ÏeVžu˜=€ņ\ŪãŸÕÎcÅŎ0á­/ÓB:_Ĩϊ}Ĩ Fjð0ÔŋĘH—hj;n—4tÝ7uņJ9D˜kï…EZ$ļw E€ ŧJcēhĩĮÉkXėdŪŨĐ-' ŧ#[Î9Е(E$ĸ:f ÍkjRhũū?QĪžÐ…ÄÚøY‹`› Yū … nÉÁ[~hóēāyFÕ*É_f™(öŦ{ĻþڞëšÞ…KĖ”8JķgrdþóŽ‘Ø’ãUíŽÅaŽdKÂāņQ‘ ͟ĪT‰ķl]šEÜi}‰iø4D|―'á-žĀ{ ýēļ@i[­Í™‘öæa—eĨ$äïSâ†ï՜ǰ‘Ëų§koė&Įüއ ōE”î)æļĘ"§īĒDYØ"ÄŪ=&9nn_ĄÛQ…ƒķė|AšB=>ŋt·ãģž9ž;ŌÄj;!$–Ó%ƒrm?9øä}û-Ē+úVËÄō1š.ŸŪéD"å- q5æ!U-ęõÃâ počî3‹°sޜqĨ ĀwÖxœô“ÕėzdČÆęØhŦę4!îsąœ G =La–‡ĮJķ” <Ý6đ€ŸūÆÞŠgVÐ45& ˃Ž'cÉė”OĨ‹&§Ïä-\š.Å3Ų‹"įW1lũ:†Ę+VƒŅąüŌĩŠ?wĖiu( €Ņís='Š\Z‰ūƒ ý_"ļX#ýÆĪJŌN‚^xõĖũ—‘ÅāHš–ûÐނ`Xŧ?~KôÎlÕė/š~ŲŦÓg–NŸ• &ĢĻōÓCæ 6ĒÚÃe7īĻŽX"4Pæ`é/PæØ›ō2P%qšj„ũū+gϝŦĸQ,˜é­Ó^Ã―j†š\ŋĮ;\ ŚóėZoŪðļEå]p°>Ž7ä^W‡Š'Ä8°O‹“ū$ģŽ/2*Ž_N‹Cå!·{ßf―yR°ĮÎĩ”ÍÁæi'zė‰ąœĪø—Aĸg]„„Ūh1š―Pę0$­ÂūRŽį‡:U–ˆ—• =hƒzÔØĶøĀ2Pž°~U~Uëþ،‡·€8EwĄ1ĐŽr Ÿ]pÕjdšĶp ŧ_VûiJųĮWÂËðoŊæ )=Z7+ĸGœĘât€øũ˜fÕ3– į~TkĻtD"j3Ė ČđfAVZĩýĢ-X2‘@ŧÓáŦĀģĪÍTcōœVO4@Ų€·ę Ļüo Ïm8tī\ðV˜‹Ė_ãZ ð˜2båeS§ÓZó“›LzŌsɊčx?#―+_ؖáōđ$„Л:,Ū―s”ō)žzĀŠÅP^Ũ:ũŋ#@K˜ÝÎ ņN9ąR•Ï” ?ÔziÉņ@ĘßÞģļWێĄœî] åÜģļ{ņ^ˆŋ‹ÜÆ Ũ“"Ë"(NŋŸZëʖ$WėŌA9 „26ÔĮÓ·•œ:T]ãĶöĮŨ[NÃn@“gŦĨ†úhQüąNĪ`_­Nō!qÞėûÉēP”ųŌã+RhÆwusČÃI!ān$|tÂņ™"~Ā\<ķØRžhYƒlðķėÃÁ%ëFŦ“õŠėȕÄþI6Ŧ:o €Ļô2;ũîh1siŦŽŒļkĒÛÍžĘĢĪļĸĀ33ƒũcžYÔí[ÉõÕ$ ýŅX†…ũĪöã―,v‹žūŅŽ ļ7ōn‡āAîÄāîúZ/XsŧvE˜ÂĄ—‹š•BĀuØËėûŪ“į/zĨÁļÛdząMU—ïÏxZ(=™Ó?1’ÞzBø/Kd\ĖņGĀ&šŽÝŋÚO/ųôęQāĄU^ó5zĖ āL@Œ74m€Ÿ ý„N<-Y9ũöxŽī-OmŸ_ƒĒĘŊfļĄŽBŊÖâ°rB|ëåīð3zXû.ÄPLMާ(åT‹j·Å·iĪcäõ [Ë….š —ō8ÎŽ|"Ó­āz=Ļ™7ę-Eã_6ÔCM…äT]pvq1Ó!Ō―WįáæGŦRDĐ(Qōõ‡Ō9æŠčč4ĀžUĨ7čnáA52ŲG/ĩ=Á‰˜·—yҊwNëĩc,€šŌgPļÏĐ―ļ`‹›ÉáLŽü„VßL:ãv– {*j'þ?ӎcsĀÁdŋ(Gý} Mđ Ųþ˜ō—K§ņ_YiīÆōÉ›ųRšó#‰ ­Ŧm˜ŨX„ėŠčáD۝žt]mqcžPSoNÎė[ ÃݧrÜF·…}ŊðhTv3Núāã–38p \~ąb°æĘ{äÔlę­YđéÉĶ#rGō^ Ē(~ ‡„ôļ}OrÐ1čÐQÔ^Ą9ĸiP++0Î>đĖôæXšĘa8ēüfĻtïįl8{bAcīLJ=éXĻÖ4%ļp<éŽ`É―Ę;• 0ęĪ}u:åïŠAW-á"oĖĻ$ē‡dd™ãūh›6Äjd<īĨŽ(<€ēáN•Ÿ-8 [”—ęcÍ8ŠcÔĩīë۝ņÓÏ6•Ýģåk™CÏ ĩhŅJô5Éþ; X–điā9Īþsĸ ĮĀüM0ĮÁ(þޟį$BųŅų<Čð3sĄŸíaŧ‚.ŧOĻŪūo›Ņ5žB}ø\š ū:DGË?ũO<9ĄTŲ–KŌ*PwžÏgUë‡Į@ÐÖXFĒ.2ó 4ŲhÞ@ĖĪ%ūŧ‘ýēÄSiÞ yĐÜĸĀwģ{Ï댨!wŅï$qęZô,ĻYDĒO{ĢG€0š„Ė)9đQxåA€ĒUsHÖõ&ô•†QWɇ.%X ‹'Žö}\cŦšFcâËIĐēX°Ï4þ™›·ÅĀô•xiöÅ0VžĮsžŪÖ$ČPë•ļxūjcđk[œČ0T!Įī#žnzKfBï+Ū:ņ7) q ŨŲŦ€ú™ąŧ#ÞC*ð-šŠŠu7ŠWF|–ye_ĸ;Ąėé"Fü„ß’AÛĸKCî(§pj! žā؀npâäF·ŊöÝōdý‘â"Ôm ‘dnÍũH~wœŠa·íqHïDĸŸ& Ž)ï?ÛņŒZ ą2Ÿĸ=)*AĀޅzÍ+ ûĻqŒgŊN}ЌĶ}‡ÕĮ§Ā-~ėx·J“‘ߝ{ÝZ:ųZÓp1•e#ĸ%N҃\Ԏį.L 4Įyšs;„·ŌœŦʙįÉÃkķ!ÃĒë/e›ë4b(Ÿįni]OyJ‘‚įĻĸaņK‘ZĄÉM―]7]Œķ8ÐiņÏ3ržõ|'™õëīĩ§ŽÎūzīõ;֞đwIåĸjcÔoƒBrŨáŠüw•ũ4^Ō|'ĘVŸP{IúīõŧŨ~ĩyûĪôŨSwIw\―A>6ŊÖŋ:T|ōĨ~JĢ=’)^ÕøÅŲ†·Ëš'Ķû^qžާ›ũ-&ïo°\cąÃóēūģą1!þ˛CVJYĐø4‚ *ĸێpdjM>Ļ‚Ý^9#üÆV4ĄĨ}LjAÞßkZË–)”BÉWÅbtå22§æ, ŌôDĨߥą/įbvr ŌÞĄęåŠ$cÐc\š§j0P:•Ī‚`ī‘âKiūþH>Š?d[––°IŋBņ}ąˆÓĖ‘/•2Qï/GėbĨĶ!ƒv}Ķ6îöýß勨“3k†Ų:‚‰=ŪāZĀīëƒokÝíÔ·SŽS/rõŸõ#ÏļąðŠ/G°q•F―Ó]ŋ­Öy}r‡Zß=ó•l[ûÉý+Đ}_•I@­AtĒf*Ų% K·SņũÉą€ pÎC ŸTK‹ó'áÖKī’Ę-Ýۜ0Î3 gšNwî+ĒMķ.~1Œ5þuellМJģÓm!pû€-֟ËŦ̓oUwŅ„ē0R‰ÐÂß͚‚Ši_یOoy*†…é?9`íģyþ $΃­ßjšcĪŋŲÃe#Ũq0ý­“Í-+XčfmóG‡A ÑōoļÎÖVO&X+ķĮ:"Hû‰ôÏŠŧuĪCI"ÎķU’ēJXĨĻĨŒ )ßĀ†ÍĄĮŋrŽ·Úžß#m%dÐŧŠ, 2ąŋCę6H&Ī'—é šũõå ƒÔĄNq2QųBP?ïb7d­đjŨ?ā$šMđöŽĖ z\čBˆ‘ßš°Ðí^†HËH$„ÞŲxīåäVŌÖb,wé!Õŧ%ó„/ęR=ØÄȏōô^Ņ;•·Œ–ËãŦH€äJĀĖÂÉC–ŊŅ”âßð]Ā„į—ŊĒ`|†ŠzĶTšĒkË9CWËÎs0ĶĶ=žÛóý8,CK'‡ƒŽ­--]ÓAųámE‰"OÃÎ—đÆšŸ)úāVÅJUdÝ â‚ūDšv’$Nđsņv—Ýë[wÃz;:žÕÄQņĖÕcÕu^ģIð“Š>䞆‚H·hį=ļ}į3Žŧsö- ļŠĘíC\s—ƒžFÎ`âĢ―eŠ cÎýčË–CMŸM§^ũ+Ό žýŅī­ŲÛöĄå\*)ķx‚QŠ+cք Á–ïŠ54ð ņ•ȉzƎ3Mëu―ôU4{%+Éadm(xŒš ðŪîbĮ,F‘§Š‹ VÚ1Í\ō8áOãõBÝ ŽĐuÚ áĸ:°&<5Šž ų[Ũ’t0‚Vée}/øn%$6”Íã9“ęâmÝ„í4ðqaôÞšUkÆ#ō8"ņ8`F*>į­[›đ}ĻÛ?ųė\­XoÂÓý!IÖtļģlg+üÆū?8&9ŊŨMŽUýCÏj”Ý–BÜ2Ÿr4XîG“ó5Ø"ۜ–u[ŌPi3ũ ĩMŽ›Ø9ūņŧÓgE—°—=Ü~Z ÝüzÔ&š†)ĪIfØlcŠÖÍYGH]ĐķĀÌZQ]ĢE7ÏÆļf5ې2R+Jôßþ];f:ï~Ģ(ŠÄœgŸ0bc­éūčdúäAųv_ … å0ąĢŪ…Ë•-@„ģ›+―ëëE3ĻîEÆ6bē‰žáĢjœ˜Ū}nđ˜ĪÁl#Â]Þú暉Īj­ÁųewÃC ō‚9AŽ?‚ûyë!ð7%ĸ~ÞáŲÝŧkũĸ8æĸoŠų~ Šr›b1dã•°VÞų*ąhĨ õĀĪÔūŊmiŽ™æO…A‡îįŅAãŠĒÄeIŒ/N”ûÝÚ% ü<­l°-uĄņeČN‹ôė “·ĩąõ\ƒ€†âčJMŧå R›)'IM°rëhdhlsMĖA†rŦ'mĶᙃ{‹kðá3ĩ,Û<Â)Âj„ū KļގžŽĢĪÔę3Ċô5ĸ‚ē’Ø6•ǐ·ķŋ™ãsà ·S=ãĐžÆŽ…“1[žë`_I>Ûyfä`"zÝĶž2ó‘T@U~ 2õķŽŽÆ†AhUŋ‚)Íá}ē[ûqmũPu!T 'ū qņwJGõÂF57+Nä'Ôëû yO#ŌĘÍ ˆóÍ, 1DÜĮJ2?Pōk˜Š:ė]*;‡ā|Üæ’#ãö‚M|€tï›ŧuĩJ”ų|Ųę“_ ŋQ…F ï`Ōzï5:%R“& Ï†0jÐbz‰ėuūũNú-ā·Ð„n{―ŦKÖbÐwϟõäp’+ĸX} ”ž\ƒīĒņĪ „ˆ°ß '|Eĸuņ”ũŧbąlŒWõÅiž Ø9wææžЍgœ™o3åŠŦ\szˆčĨ˜‰mbÛŊÂJtrXĖØ5ļsßĐf,Čn.ÅRFT―‹ī:#*|€aâĨđ?d‰{ĩ̈́žÅË{…y•5\5RHŸ –ïkŦ“ÃåAtšðĒĒ1y4*S&øČU0ų4Ō°óī•íz•ÎōŊÏēO ÞÓįr€Ýķ8ĢA,ĸXœ/ˆÅŽã%˜ŠRÜšŨaĪûōąÅ…æÚF&A16­RĀ ö`f0 r_ ŪÁ+ցd Mē@-@ÛÏ&ĶLĸU['};đĻ™:-<ū&ãŒÉnÁ•…°Q·pÝíŋä9Â1'šäģÜkðšT‚ƒð—ŅŠ0$œLĐOķ<Đ­BĮ᠗uMūégƊ1ôûŧĻ”$”ĘÜ(x+t—rīÝÚā|ÔYĒhé|ãhũÖ7Žû§Ūã 2Į­æ›°ï‚lvęYũ) ‚>†xmG…Œņak6"PlÕÄRI2]ÔøXqŅ;ŪaE;/ĩ°ãҐĨ1ߨãó5=Ũ†Ų5Fo—…0I‹›lÆO`q·ÕŽrŪÕĐâû5zYp/=ūfä›óŽŨĶsšœ æo/Äûį%čßí“ų‰š"ĩŽC”Œ“j@ŅN6ŒËúŸĻāõŽ‰|„:ė M[úï4ø8ô9ÓGēõė?‹·đÁc&,1ŲrDâū= YÎþÄæŨÞéVß Vų ĀĐuh]~Kråv/Yâllšð_’e-Tšv―Db§*óžŨĸfqīĄ+Žø/+°ŠRU?AþAĢ4ÂlAAtvlˆJÝeŅ?R‰â#āÔVÄęÉÚ[G䌯! ĸ-WįuŨåkŧuAVwÍ ;hŠeu~A}‡øå(œæo]*Íj “ßí ĖðĪ*.ýŦéĸ/ŧ|ļÕ žûUŋēUýÆÏ•B(9ŨĐĨäu™N 2âŽį [6—óĶý·ž&#6zëōá/ü7ߒ•QU īxOŅ”}AnĩOšjŽ=â0’fš‹đÕ§ŒPZwîąõÔ*vœŊ"GųV:Cŧ)é˜~v.99ž‚‘,RžVš\†_šËƒ_;  ĐÞ :ú#ðSj(IÎ_Ó$( –―čŒžØƒáˆíVwÅávšƒ-2Zī“DV“č―%p‘ŽāũėAŋÜŊ‘@€ß kĄ"#įėÐUO4ÅÁŧ:‘č*:Ï5€:,և1Ó/ôšA^ö ƒÚØN=7%ē·=ú ãވqÚScėÛýâ0õåAķĶó$ého,įŅzš0‚õ™]: äFrÏÞVô%|ĀÝY͘›YoŅ—…IĻ_ŸDÎWēȈdŪvd―EĄķĐb„ÛGĸo—Aų>ÎöÐņfz~o2úīŸ8SkÜ<ĘĩôVuQe=$a8%ĶĶdųō(Ņb?ų•gŽIČíˆ8Šy !&BeĪąĶH;OÝũ/$ÏĶV7°›<-ķ™é eõ›&Ôē}?Ų@ŌŲf“ ŸÏ.ĀųÝÉËôšęÉä9:]ŧļ39ŲčG̈k(PũĩÐBw”›Ą ÁÞņu"45ëlūāŨŋ…ŅĖë~œBÆÄEė„ĸŽ^aŪ@―•ōNĄž—d‡"…ĨÜŊåZþE4<ũü![N=CžXAqļ%ŽĨD§·ģ+3{ ŧåŒqÅ\ĶÄô0A˜s#ä"_ų‘üŲ:ÉP(eQÐÖR“CŠĶPnd%ĸ|OļØMVö„„…þgÐę qĖâŦÄĘÍ^ėÄ8—ũÛqJ:šb~Ė>ŧÅ}â>Pß ņUËYEW‘›C.čûý(C4ŒæĶ'Á-_;”G&‰F>+,ÛĩþCķbðF_ᎄĖųę\”ag5ũž?%XP4vŨÆŠōFN(G.G ·͇ĻP阎’‡ēGXįïˆ&―Ėķ^>ô0Ļ-q‹ä2qŋĀÓŅķ"+‚ü… õÔ·cÂBA‹tz*IxĶČcd=æ—ęHpi ðd\kõâ*ýūGž5"[6;þJžãä‚*ZyHōĢß4(‡=œŌÕõÕ6]W'ŒÎoâW!A,J0ÎQŅl<>ęķ čŠÍo7Ŋn‰vĨ+ïõģ^•Îwƒĩ͓ˆNZņ;ĐóĀՌéģe”—ķķÝ <Ã4 ß'ĄãbdÜļLļũ)˜rŅÜIý&įIË֞ãÛBZRX·ÆĪLjīĨ“IäšĐ$Š+ Ôy™Øt=x%ŌåbÛŅ4CLOxëšĻGx?Öōųī— ŊÕ ūˆė ‚ÉAŋņ2—ú ÁæųQ&ā‹R™€^0:čbŌgî'~ÉąÎŨÝVJųĘ%šōßīžúA0}s€ųV9„”GÐY %Ōō$ŔōîÕóôݔŪãĄÃúŊ–ņÏ2(8RR>0 ėŽ[ó·o6€Ú@R‚./Š!žœJģÚ0Ý;ïtvŋ ÃûâþNģcé89įÅ ÍūĢ=Ā &ƒÅŨžļs F Û1ģ­Ž&ŪÅĀ·ŋĨˆķiPilF[ĪXáđ;‰20ÎSÕG-ÆÓD-KHõĶæĀíã=›õ|åˆö˜<·â1nŒ°jNđĐé=wIþÓf'Áú:/šH*sīÞ€1|ĖŊW+Ē~]ņœŲ;„čŠĨŋøj{ÚCN–ú/UūόCĀũÝHÛčLŧpzŠã€ųÎÜ>ąiė :Ũë+‹ĀD AātŠjõĖQŦūmÔvßĻ\ôŋnû–“‹)˜PũāüïϟR87ËjÉĻķSWą öëé<抛 iË šėütQ0ĶŽ§4ÂŧŽü .öޚáÚðÕzŨ†Ní#ōFĸ6ÁeRųÜģ Ģ{°ŋðéŒō‘ãxïŌ―CýšVŦn}Âg˜ÂũÏlî„1”jģļVđņSq3‡ābą…Ú9YwãYĶđ―·ī.usr0ˆ–kdÚMbōūÕŅÏĄïĢxA !Ý­ļ˜mXož^ÄdĪîoĀ™Twh‡ņģhCĀ.éTÔŋå{iŌvö%öąō•ņ€åÝÆ~Þ―gãíQ'Īkx…ņ t|k9x€éɑŅōŸŦŽõ‘Šöží5ú?ãĖiQÚCöĐų@ĪøÝ a tū4„ˆ>IŠˆy+ē<5OÂķëæųūo›æųŧpïaÁYņŌ?ĩö\š'‘ģÃųĄÅŪï.ķ1Ā5éÐ|q‡Ē‡! liØđ~ĻÛNówýNŒā‰Ķōōú)â•_Ûû€Ōp3ē–eĢÐĮčØïQkĀ5ÎĀIúe0N&h ƒdģčŽ*\ĻīTäËÉŦĶ\ÅįVõ“ î•ĸnðÉ6lŪôö'ŅÐˊQ˜§đGhqĀûŸ1ŅĢX›66å0ÞF˜é‘1FÉøFGâf€îî_<Ęó&Þžã‹ą*:Xðyû=ōÓ?å„b7Ķϝ ëÎŧ&‚Q2†ØD–ņZĒ;hŦÍĸƒ>IdJÜĀû*ÆŅĀ.ü07ĮáÐaoœũ”BZ}+N‡"Ūā}0†ý#Yr~+™ūU킚OģwŲƒDü-8ÎĨäf/ĒSŽä‚Ļ‚C"?øŨĞĘ)Ŧ€1žMŅLFDzĄWEŋ~J€p/ręIM’ ú6ntūē`<–ąöÃøRĻĄÎaĨƒïóÉ,yÕôíjD zŋŦ)îR Õcxé‰8ąÝm óžû)đyĘIŽá2úĸė#äDĢ%j~ÝUđ:^ōœœŲĢý‡äápr'Œĸ+}ðn&·lfƆ0ĻŽLZð0Sø(Ó ĻÖsŠnBmâŲžWāÄ{~™ÄÜGza"ą‡%ӞŽiŽ‹$= Ōôë†SįþZ•ʧ'qƒ%ˆYþ)•›ÛjÁd#ŽúŅ*Įīė Œ‹ĸčĀuų‰ĒĘ ĸvč4įðFļ PmVøþŠíšO ŦŸ―œ#â^ā[M`Ą&šPĸLbrËRų^éįŦ3ΖŊŋVĐæū―ˆ>ëéņPó|eđäí“ørĢēą ũ›:@8ėo@ÝĪԘ-ásŊe•b˜Wƒ6i° y―öēCˆÚûĨÞņ=š}DVLËM$šĮg|•æ`d–6H*rŸÎUÃeS›#ŠĄĘ|NÓÖĒ< JxE< /E'­0“*3hgÚ?öŸWö(Ú·ĘDBƒfŽ$žŅSbģŨÏIš5 q'{'+Þī0)$@ŽˆØ5ąøõŅüOãƒÚÉ~ l;‚ī’Í.dÉnuōÉæs§Þvï}§8 Þ,ÂD­7M/)7 LÃËw+kīŽ31ï&ØĩĖ~(|=þÖ$ÛþĪŲÝËúĖ&9ģi*5zŋÁ‰øįÁÆ;ðŨĘ:―ŸóŒ8Šĩņa,! -āl%„ęĖôa’ģ<ėô^"Úā!Ąt5[Šú79ӋöN˜›æÉ/bEāQīgī@SĻã”―bđW|/( /?gI8#(‡ãĪ–þ<š†bU·<æãdļDQđ.ĻgÏÞL$t_ŽÃÛkt_T a>•1^á8WÆË†} ïm@ãŊËŧ‹îœxĖs’HØ?;Ln{ŌDð―ýíLÎĢs~vė`ū*ŧĘŧ‚§ÉâÞĨĢnŪ‡…éVÐĪ)M§Ų40ÛÉīMâØ ÛŒOÂ#Ï$ΐCŅÂýøāŲôũˆ§ėíĄr-R Ï}Æ1Šė€€€€€€€€€€á退ŸĶõk§5Ļđâ&õękĒ­“ĩÃß —q ‘w>0€D†5X1äĒ>ëõ%96ÓbœvŨûŽČðvĘþë@Žpjb­ÖæÂKģD—‹*čŦĐ{|QhdPļÞq6ųn*Æ&Žk•ņ5PtG~!JÏąJÔĪ $ïļ-M‡ÓÐþŸāK\2ËÁ’û‹ŅWÆv‰ïݰ. ‘ųŠ“ cWėí]XĄ4œGĀm‘öÛļüUįË*q;Ē·îúūp?Į‘7ß‚ȈCŠiē—`"ŏŽóëØÉ{Ž_Ũ7ãĘä‡ĸ}ō\ģÕôf*:ũó$ Ō7”ßþ5ëSīgPęÆDž PˆûŅãy&|v4ģ™ +~[šžĸ=3I '2sÔPaÄdÞL—'é79âÂû) 6dMOėÓgÁNķĶŦöWŋ+`þûIĒŌ§žíē „åi]|­'đmF4b­3)sūy|š”aœNÝ6\Jļ ;J…~ï zl50 ŅLũķšŲ[åþ^ū†‰Oïų!Ĩåč€jpÞĩJŒĻŪ% ~JļŪ”ęĮ]óWū"&Ëü‹c=ï•DˆMøŊßōč8Ĩ#/+!Ō% lDė䅘AGęEĶũ­>F€Í”˜ž)1ĀĶWWMGr]ÚĘ4âšt,Ļļ…€E|&s€ĩhFÅĒ=L”E!ŲÕíīžÖŽ^}ÐNë—c—st2ÆÜíåŽ ^–ŦÔđoþûÍ)ˆ8l A8ãŽXãęįꘝdŽQ`ėĘ ShéÖ0Q!>ĀÐĀ ˆ$é õņēŌoovø‚Sø:Ų•ļœl€€K“MFÎā8ã°Ûš öQ8íóÞËÚŠd71Ųū  Ą‘Ys1Īž&á‚ĪˆÝ ‰čä#^õšÚ0ũ]x_ųūælAĒ ž-bRúßUW]3fT‹G„›ŽÄrûĖÄéq'°Ã%ÞÖmC›ëË―}ïä3.b_~MābLĨœĀ(EnėųQï{s °‹:Ų<”ĄËŋŽÚýŨ-Þ$C#'dįRƗÁ`9Ũ (šēĩū8,e:pŅĻí•ߒĻĶqŠx^ûB ØŅókĪaķ5!ՋjyÂÓŅęŋ™w†VĀZrÍûąėlDŽM?4aWmŋ-#Ĩ€gs,đFģđ)ÜiŲ&ļ˜āņ ũ—~RŋƒÎœNÅ―ÉKú-ō—„–‰‰þ.mQīė4ÕŨvsRĢ{é]aŽðÍģNĒKč Īd‘ ä.‚Ýc ‘}xÃj|Ø TįņŪU{[Tĩß\`Df2šD‘iĨÕGŽüÐúĄÔDÉ!VJōsÔzÁˆ^á€]DD›î>FtÖþ1yŦvôņĸHbÚ0”œ‘)ūŨAeU)Ų3Ņö!õ‚FŽĩÍq†ĐR(ýę|â֚=ģž8ˆß  Áðt|WwAûe`ø;’ƒŪ9ĩ~îHø톌ŊĻŅ$wĮĐ ðÅ%ýÁŲyĀ“öÛ=`?&ímvŧA$ûS'HúĨ|Rژ)óĀWĀS+$fŲ\ž&øŊ8|ðtFŊýC„éį˜Ėŋ§ēeL‡ó!O†*°qdSïÁŠŽĨcŒáŊdhz@Xīĸ„îvnҟ+åŒûoĸskđqKūú‡Čę0n&{\*D›ā5Ųt8'fĉð7>G6”ó{<ų|”XæF ޑŠüvÎ—ĶŽ#+ƒĢí7r“Ųå…Č ē"…éē,X •.―‚·IËödøĒôü$*˜ĩŸēxÞGPV#~+3˜Ūƒ*"dúI-üZ Ģi}i>· nxšX|B%ķĶą‚ģšÁ…ÓïŋÆÃķ ÔvĪëÃENBČ"8õ1ýðKôíņ+‘ĘË:dVÄ ïŸ•Ōœ™0™ Ą‡ÄÔ,-aÍ%YlŽŽh–ŋ^vâėb5ÔS8iBOp”Į*Üáqúš ĒŅĮ3Ð{ ŠĪá{„˜  'ŨIĀ )riŨcéðuĨyGęîņíg éĪÅ(„ivüˆˆ~’ĪŊŸĸXpĀë\59†ŋīüÃíó Ö2YU~žˆ<öÞą^ĐœĀļĀtRR/ðŊKĘįĢßûŽšŅĶÛÎ1-õķ?2€ôå§WqzÅËūú{āŽôÓïĖnãý7Uʁ}Ī€ÜElĻŽEüž #ÄFTd…―ô;2ōˆ‘\ëhų"%îzS ŋŧķĀvęDÅØ:;ŠD2—IÓuåU°ÖS}CۉEšĶÛę$Fũ]ŽīžĀ…Å+ߎEnF î·ÁšĻ6é›Ĩ T dÆvsÏ =”gŨ7ú’Ëķ§6ÖOˆsÛīū3ŧ؏ķï/ÅĒ5lËgÛ~óo's·élnļę+Ëĸ%MnM6ÆM{”ųũ-}ĸtŒNûHšý*š’î–S–АĢMye#_ €äŲĪĻ&g•^ōœWfąyÎŊú‰X)f<5Ę|ØŦØí (5#'qųn8Šdėí81ÄnÉ­HÉĖW;ŨXEVžž„Œ”ža8ՊxxˆÁ@“Ī4ž sčēWæ›ģ?Ë­ē+ŽH$æ&y9ŊíŦđw:W‘õ {ĶĮÖV`ÆWgŠ! Í3Žæ°šũ°­š˜Ð šæ{ҘŌėŅ ›d/"ÚieįF$PuģōĨrUŒlsüĒŪčįpÝiР“:ûžXÂo†ųrŧm‚Ÿ/š†^'Ü―…ž‡:>.ßY2ŧøïZ0â(uÍ8Gt0ŋÏī6\ [―ōH8øĀÃ@ĘÁÃ{üžęýšÜ=KÝÎJ%úݔ„H•@ÍAL [fÓč}Šd™C!W5˜óüķÕĀÎwÍjŨ7Š ųåÎ!g,:ež'ũ. ąļĐŌÓ[š6ÔæFa‹ę@æI›đo@ Ļoecfõī ‹páĘvíģĨm§y Ųųę6Trâ3“ÎÝVšÁéÐCoø-@õU· ŅPŨŠ1™ĸW›Îv!ØE>pĩ €`õ$7nĸ}ÝÝ(Œįž•KN8;˜^yÚB IÞŽ_ą§Š(Aį†ĩūYÁãõ+OÉPZkNýCū۝L™Ũ l[‹rp)íÜóJÁoL ÃQ`3ĸ6ĸ|N:!,ÚÜnþGæ-ģ“K)jþãvP6ÏĨÓX{Ā„ó§#edîy%­`üŦ_#ąžÄœ°_pF dQeߌðYiPJhóEz”~õKŒõín_v(ƒqĘŪģ筈BûĪNŒGčÍUOiÜ#úSp B.íkēüŨ`ų4šŽ‹J―Fų1…gÝ{’ÃÃģAƒĨpIm/ú+ŽÝ1:Ï˘ŧ…H‰öäįĶņZ­ņ"Ā,Yįę š~väŲ&~€(ĐX%`ËC~Ļvqđč ę .­ ąé Í~ŠV,’_Š#ĸövÐĄZũ­NCŒÝPeM\ú͛ó—Ž3ŧXü‡Zę]{Ųī1ŧÞpfAŨ0R­tŒ3dŽ^túĖ2EЃÅnFZf?]ŽWNðÚcōŽxvļҐãš Ņ{+ ĨĀŠŽD‹ßv Nz$M c ÓĶýNÔ'ÂėRŸššØKÏbæ8`}dŌ'ēĮh w§Œ’Sō :€z#œfr]·šæŋĒÆ0zņD!™ Ķ^8ŋ–ß[ŲŽAao݉Þc‘më=eVóĨjäÖĸy(šfÃ>ģĩŠ_wœTų‚PĄšz]v†]Ģyj^+qÐĸ*†X=RZŨ‡2jƒGېh5tkðÏqÖÆ$ pgâT(™b°9vl%îÕ&#·3=ņ&Ī’zÜg„{j s& k‘XŦČ&.ÆsÅ(!ŽHŌ4.' Ææm[b˜|čËd-‹!Vũ„Wýs›H#Týž8‹zųĪ~'™>ƒīuÅPĸs&þéŸxsČÂ$ڀũQĐ/ōē‹™r‘\ q”ÂG$.LÖfXŌØ3öģ2ŨŊškë°Ðūś)9W1ļΉ‚žUÁØÄÞMģúŊëëķ'ĐÞļúŌvŨõ™ëóퟷ7Ú+Ûãšąë™Ë·ŦĪ]ŋyOåwęyõ |ŲËŨķ'ĩïš ŨghgitGŠõï ӝ[å·ĐŸ9æŦĮ/_~"Ŧ†ßΚČ`$i뇁6Eč\âíäĮŧ0&ģ‡_<ļqiü”‰‹ÁŨq}ÚEÖĶ>TÍ‚MmšNđ'ïrą%;ŨlIŋíó“ã=ÎĀú85m†7Ãũ›mĒūĩ/+ū/“ũVdJŅĄåK―ÅŨ†ˆþ€‘hÖ)~ßÕ ę-ïšQp”Ģ=ŧąŊf \Tƒž@pÄ…pcT€Ų”åĪXü0w ŠāíÖĮUA6 ™Ŋ…1aĘĀ€Gó=ÖĀŋļĘÍø†;ÝĶauÏ/ĮðĮ}™Ú―Ķ[;°_#ƒ˜ÏhøøãĶųOˆx7ó…°SdšÍI~f2TĘēj0[zᇯ‚ŋ<ļn+ Ž øŨ·WbÓãÉī™a8qĩOQdËß@Ú(QiáîV ÏI=sā{ŋũ9%ņ|{Š―ÜD_=ī›WNŸčA~ČIÔJŒqömĸ5ĉũRĻŪĖobžI>åˆÖĪheDÎÕęĸʇÚpMędŧ§Ū]'žõ\„Â1tk-þ3†A`MĄËę·‹å=Þ"4nā Ī4r0Lĸ/c‡ĸÎ@ÉJęJ>“jYõĮĖ€‘ē=ė°’.ŸýY 04ŪÍ&ņ!6š@"ÉnũĘŠĐ+ßĀyûô‹_§ą[ˆåzqy'OÐÓŲĶ}Cĩ%.C‘o<°%§m+‚•ĩ€Faý:“ĸ;ąøV~=Ïîi'Ūu#€Žo—ÉŌëÅēâÜÏĄG–’ÁĘĢDJæ˜QËų-_ļŦž‰?Úæ:elũ7QÉÁˆz-]Cnģ€õôYƒH‘d­veŪ|Sg[]ôųŌĀņļ>76›i9S~ae3 ,{V9ŠQŧWĢ~›Ų8ÞūĐëBOb75ØĘžÂGE!3)_ņķ„L‰G_ë迃f OœWQ$°I"rėv‡M!\'8Ú3w†$Bà öĶĢ9ĀįXiróó_Č8.XŅuŊĸCÞüp;ûŸC<ðĐ?j"ÎÍtšc|ĄåÞ°n‘IcyAÂWüó%ŧāĘëĩŸ#nĶU&AIu ‡ðšO˜xCž \xŲĒEé^üđ‚­úĒ‚J]=íōĒĪð€”ÜðČņ›rķ” ÛÖÏĸ/ԎIØ54Įf|9‘žÜN―ĢsâĶĢÖ*Ŧ đ uyÆŌ$ī”uzw)7EuVĪËŎ}ēÄ(Ũžō­juØÄ3eój•Ûėƒ‡›ŊuåþŦä1ĸzPzĘZū.† dd°ģ„­žHÚ„9æ( 휨N‰^SSå{‘—Ũ4ß<ë!†ŸĄdøÓŧ45<Ö§vËÕyû[!°\ëéd†QÏ oKOą"ĘŽĮOT=þēðđ–ĮLšŸŦ€č‰žýÃŋS!įÜWꙃčDaÁĀ♇{ƒ†,ūDūÂG*9uinŌTŌg()§ž+n]æiĒïžþ­ ĘĻ1ö–tx+ZŽģ€―­ØņmWåە—/Oš}âYŅRÓĸ)‹äé·QÁJ?Ö™ōįf?o0Tƈ[ÅKŒLŧ…ašŠâ―‹žë%ØšwãA „ĸ"ĪRð։ŽĮG™‹ė.Ü@Ó|þpæŋÉ+‹*0efn ™Ų·Ķw‡0jâ‹ðaų4ĐВ<‘8‰l_‡Œ˜q­Þ`Ņ―mVv[*íP˜ÄŊ;Ýzû„5"_uų/’ĩöïÖŌrų†wĪĮƒíVgâqPĨäh9ôėĒ’Žð3mA;ü+q~íŨĶs˜raŪĄSîēGØYúLwRŸ–NFík.ŲĸYQF…ŠĩKņÕđÁKŠe>(]éWedŽŸ6ØeĩĻŠÓt―ÅĢð­ËTTŅĶÂŅhĶ’Ķžę›4ēô4̘f›ĩß\/XÃ,y—7"ÁãíŪ;œšíĖņŊ^YĶ/Q xō]oÓåíCąÁĶóėÆĘIĶB°‚ĪƒŸW“1MŸ‰aÆßĸ…Ą0IĒïôÝĻÃ2ļY2ŽqÜ?ĪĪo0I_ũüîÏŪ?—aUâîę;ĸjĒ9O`ŦÂ^~ -âÐÞE‰įõ‡Ög˜~xõib‡}ÎmPȁ:3T6Z@XĘŽÜÛ§…š?ĻĒYúé+{́åšĖÜ#pĮ éŠgä §žĨ^Ëógģþ=―ŰT:Š ]Ó Þ‚5â,sĶ1ēĩk5đäzųĒ}Ōžšg†ÚÍĐŦ0Ŧ+Roü­%˰zSՊĀ–>Ðxîj/ÜíšV`ĒīŸ úYb°xįWgŠiĮÛnų[(ā4ï„MC'\?YVúí*sڋqUðĖ]ĘãAÃuÉ|_DÆÁ ïx‡·„z?ÄvîŽĀŨån/V]ũ4ĸ%―HCÉpÕTķSŲ9Ŧ}5. A* ĒđĐNØōânpáĻeĒ"ĻSģūqgcÖ­°ˆFtđrJœĸ7ÔCkUx/mÕë+Gr~ĩĀŨä§AųÄ|ļ˜ųþM͉Ɯpd[ôĄÕŽ‚ļ`UÁóŒ‹=üMˆŠŲ°›ÃĄšt„ ՚ÔīVT”­+åĸlšþA‘ôøĒ`Ģ pÞöĸϜP4ÆĶŒ€áģq óĢāî#n īūČïØĩû3$ ;,ËN2„ņw+0ēģņƒE…QĶė<‚Ĩ‘ g)âXƒ@gAG\ÛÔ^Ū} „Q…o##zÜ0igĒæÃ^ļyðWõíąnŽ ˊKYg'ĨTßü Ē •kDL›4 ōS”ÎĶų=•EōĨˆä†Ų)š•(BsÎ\&NÉšûyÓéýdGāEīĀj?pÏČŋžgÃđí$ĨŌĐŪĀŦˆ– däĄŸ3ļjŲŌU—ÂęjŊÐĖŦ CB#l’ÉX Ž€&jķ–MÔ+ŽU=ČkaģÏp-üč7į2ú'ŽjäßũqÍ8·wzØÞÜÉ‹ŠŋNÜ;8ėýË;LߜGŊœü=!lŧ…yxĘkoZŅôÓ?›b<ķųVãųEq„ÁF· ]aŽi(b”`ÚđĻsąb;#ī6Ä'ÓÂ@xãáMŦ`ÃĢēŌ@°đ{EÂ#ëzK(ē oÔSž'ú-7Q—L ;g~(aē8FMEVŪ1ƒË Ķģĸ@‚=ÅqJŌ›įķõ‰ˆĨo‰ģ‹ûïŌ("`ļ‘36EŒŅÜ:ÚexĒ*Ōp}ûķ pĪ—~YCY- îwV{Ŋpæ22OuâŊ’LâåāGČ+Â`Vē$ÏNe7đėDZ”ï† 'ąĪ(88ÔÖÚ%ë§9ęļxk|<+–v›uĻÐ ^){Ĩ(t–A·óQLv ýÖ-OⰉ•éƒøAå øðUõ;y*ŨÐÃPQZ—ÓœMŅcHĀ}ãCSžĢ6åčĸāޜ€ų:ô!Dš kļ|šĖxb`m&ðLÄN0_ wgMāSæ†Mv‘õ6ˆŊęÁaņ>'Ü`ĀĶacčŊ/3'°Pø―úÍĪč ,Fëõd3ŦOýŠ)|1Á݃ŋ†ķÏ<‰7A‰$ėÜíZNaPļÂôõĒĢJžóó?Đ <į:m­ŦīČtÉČŋYƒ…ōĻ­T=Ģâ1óqm(šīü–$f1ÞSzÖiéÞø‡ŌFb<&όē+ÏÆüå―å &°ģ-ču"ó‡0#ósvė~wtŒk”Ī’P>'ˆåՆSBũÅ7œōí !mR~Ôĸa1ēŪ”mvð),Ҝƒ Mŋ7[ūymPL"-ĩČ2›°ï­‰“ŌK&pė1L*kŲ“ĸ!Åh.OĻ*§œ%pz§í]ãX^ĪĨsÛVgMœÓĄ”s†,ýĻ›šÁ Æę;ï·ĻgŲÖĢt&Ė–@h{ļh|#Įtô3ZŅ5ŪųK%FKČŽÅæ•ū„ ũoÁ8SęâEkėžgf ú '!ĻüŽĸ2ËT}öi?8vđ„|ß1tVFđYũĘŅa–L2ļäIŒq‚ęĮ·7Ķð<Â:š0ö ôÔÁa€|ÚïÚŲšNQą<ļ·{Mc.OĪžk·‡•\Ÿg"$)ðEúšxõtÏëĒ nōJgc\Qln2e\6ĢÚ#R1˜ Vl.Š&IãÏËĨNmâ;j9~Ņ”‹Į,(ŽBÃ{ž„ĩĖ\Ģ5€Ģi1k”· øė^dýÖ…ę%Fô^šPƒ;6Ú§АËŧ͈‚Ŧ;įþė\DŲ}9ÔQuĒšSĮ°íëōš2ÔýxMķg*íiRDŒæs%ÔåðÏšķ ÝąūnŋOęøĩxpÐŊß){;sAd>6ĩ”šRiŲ€‚üæ‰aš—:LBĐ{ß§NAąmųkāŅҰ+" )Z’*6ócÛ\ū}îﯕ­ĮEsoݰÆ/ĮlâKįƒiĶĀýtIZKÞ[ûkĪ`cŅNĄ<—(°ÁHD߈/5v"ī™ŧÅĮ!\ÎėulƒļƒÆš!ēFĘqÜãōQōœš„Ģ‘Î“zĻQîy@FÜŨĢßRŸN{ĀH~ĨÁ3ĮAČ#e ,ČåÉú/ƒ Đ įļÏšˆ„kíG;ÛýËCŽ‚NĘģ|üŽ–—CCŒ`n!ų诐0‚IĄïu°:ėm~šĻģ―7ĩBdØąJšö/yk Īčˆë I`Ÿp=”įņôÃëä~āėnŨĻŌĀ*ėŋƒ=8xú25DŪÕŨOËŅô9 ædZ*Ą™k|ĻL`fHÉ2<ÏSdžî IÄĒyøB™ųz `ĸH‚ô$ß_›NÏebK.˰ævŋõÐ:ÓĪFÛ1lDïē‹ëk ?ÆŽÞ ĐXņ―ežGÄÎĻ0%BBĀ“Üį [NDŠŅĒvŸĐÁõ˜%‚äÉþ%?^UÞPnәk‡oHĻ\™ÖU0kqĐ2æøxąX Ąbá•Ū*Ų“&­õņ`uîazz„ï‚ÎLEĮVĮöðôŨŪ ŧIßa(JČ(n– ē ÆyŠhš}<šúÛĨT~HĀ ž–n> 8Å}]‚ ŅÓ~á{/OjEßA|˜qŸõ|ĻwLĘīÎï- u#›āŦáŽĸ ™k<‹ŅK|—VЋõ& Ņá|Ž=ĄŽGžAôc’õU’VG„VĶBWš‰1-~|„]ʉMŒlŦSųĪĪ’Ti†ląœeHš ôI…4$/Ę1 éåÔ;ĨÄ"Ņß OpĨ/ h —[)ˆl‹cåŪeŅu!z,æ“6.5KŲ&‹-―óvĩ+ 0Ŋmj°1üĶJûœ‹XÞÏÄ0’x Nš.K[ĢėlHÕC”/JopNHLNóÂså–Pæđ⨖”ÜÆ  0ÄyËâėôģø‘…íHq8 AĢ6Ođāɘ<‘NAgeôōĐGM3ĢTZ ŧ0Ņũ6ë\øwĪ t‘õ€†ĖČšü.šđÅ:\ē’C8a{dXoZ˜1ÁÝķ—ũĢ9vŊrjŅĄīTRdQ@âÐĮ* ėóĀ/@þ$šžū/wž_К/Š$U’āÛČ\QX ![âĐ.€Â=0lL„ Ū [ž*īũ\GÚĶcĖBÆāßHzZ)vĩMmÎrÚ,kDvP-CąFüų,ÞĒlÎņ‘îÔYޑžrĨ‰Ï–1„öɀĢ j2õÄŌ‘ÃÖŋöĖzT‹ëpŅ·ß…ĖLïŨÓÐĢ\HMÄ―Áoę\quīó3PTicpļÏd'e:˜XŦĩ/…õÜŋzÕĖBu1ĨpšŋmäēęÚĮÞ/Ø14–ØąVēęωMŨÁևZ~Øój![jw‹h:…’‰D<{šāKQE, š/Iéh6.N!°šĘ›õlƒž4A·ð&C[Ĩû8+Q’ÂNI_JÔØbë·a·ņ=ĶEĨÐû4á0ÂEg!†ģŊü'‰€ð†UóPĖÁەNŌFAGSÎÂĸ]Œ\)ŽÅüIũXâþķj/ų a %öî`<—Õj‚Z§$’I$ŧ™c-’›Y•ũ'<Ō|p}ŽØ:ųö%pÐŨęļl\ˆÃŦÜõ„ĸHžAŦ]/ÛY~}ūŨÁɈúáät‘ŋWŨ5ålk?noÁČíSî)šf§Gķ[û§‹;ðųÏžŠüð!ðjú…ø ąžÝõōĮŽÔfŽŨRĖk )Z―J%éëéXßgŠ ųŽzN0}‹ĩ§ė{^ŪĮž@”VA)YÖ ĐdŸĢ0!•Š*Ą„]N6ĸĸLŽ1ęī~pq'•NĨiīŠ]ÂEÉā%`5Ųqž(°ļ,đåđՒąD/SīÚĨø4ÜÍĘڗ {A+ĘÎ?DĢāØ*JQEŦ%j“ĸ+—ôĄöĮĸ}úQ4ápQ`C–XéÛ·Å.ĒwÍŲ]˜Ïí`<†xyä=6Tųb^KĪ-īķ˟B+#”Ó†FėKs&LĪĢÖĩ/•Ė·Ŧ°S5ûž ›&ŅŅ<ĸÕ-Æ&ē&ĖKl‡Ģku1 ĢuđédŲlčB§ĖŪā%Jsę:ėākY,é‰UÆI†GP6Ųæ2·•-]Û7ĢÞ'ĩ(-5Ōģ>HŽÏpßzŦÓn›ŅJ)ÞqÚo ƒ!fL9~Hˆę?ãl ŲãĒI[äĢ)äZšƒˆâocÉqũԟPá_d›q.SCķ]݇*m[ËL歔ŨuuŧĪüĮåyáØ8 M1Kž“ÛÄÅaœ~3œĻĻ–\ŧŽ3ŠÂ‡ExFũŨ#ģú4až5Æ-ŲĐ09O‰;?2ČĘĪĻb"-I|ë*VB e.þžœœu~TæaĶ‚}kŌ–#ķE ŽAozôT­ÍmjŒŨ§“É2XEÜ}Õ―›.ŅĖÆãD/DDÞóŨŧkuĸSų_‹JÝ)zŨÆB(Ārû^EÅkoüôcfŪ‡ ­T!‹öƒfIþ>ð&ä(—ÐÜ!ü.Yw;v·Į‡…9ŲČąéLâ#vÂ(óq’Ų’ŅjIāëOę‰x傄UL‡ÍČC’[hh[BīA@ãeĘÐbÝšjHS=jĩŌöIčėņdö鞝 8ÕŪ@ŋSķŦtđ F}ŸPŦœJí`m:ĒÞn—JÛ9Ęū'€ČēFõęD-HÍgÏ ð’šĶŧÃ(ZRýA%XĒŅ‚5›Æ“L[ēŦUë$žĖjefeYwXI˔ķökŋ-Üg9Hod{€ŋ %Šö.B(āĩN†Uå\CUZ‰-.ó›WŸF>;HEķq… |—éöĶï&ĶŌâēļ…ûFß0ķ‹ĸ|iÃhø?óûøíþ!sh_GЃ™―ßĀH€―NĘA$é§ÏH“+Ŋ›aÓāˆđ]ü>oÁ[Ɏ”0ÓÜY•Mȇ€§‹―Ĩv’É^žIūĀ5Ä(CŌ”Ŧ°‡I˜ ŋŽŪŠYã%”ö%OĪ þhíTfŸ8ņÄ-ČĘBAë ™ókĐÔā5 ͰБ}9MžÃá VXŌ§EŸ?žáXœJC2Š5RI ýëE˜aļŽ0üæ~S(ý"LoÂâŲuūï,ūAwīQFŽšGÄg4F°JÏöÝh3}i_FۚÄÃļęv5āŒL›Āļ7ĪĢb5Ą;‰Øk€úΐ Œ0G=Þ'H[oWŠ5tŧÆĒ]Æ@0-fŽåýÅHÂÖ?Ð#ĨKTÁ~ŊП ”;,ų’·â]$Ē?/[+- ŋđ1ļÄÔ R‹ ZņÞ.ÚŪĄŦvŠ%dŋ)Z§­7jŸÅĻį"s %ųpČ#jįÚ+Ԙô Æwæ2d‘ĮMu2―@^’ƒŊĮó+ ‰Œ?åc“HŅŨqÍĀč/‘.w ũ(ęgnÞūþ,ëeLŽ#w‹­kW hË ][XÝÕoNå:ģ:pÉ}æá^ņŸ€ˆ–ĖʋTË(ëdIApŠÕ™°ÖŒHRø1“ƒ=nī–^o—"V:Ðđ…ËLÆ­;pWA ĸJŠÂ[6Py `Ŋ{Z‡îÖŧNõ—/-ŸPGtČ䧜-$Ķ†ĢšôTĢo›E€ß›“”V–F=Â,zD3t0öcߓĻe$œį9Îa?"øy `-,R―GĘœæeÆeŦžÖO†°\Á—yéb ™U4tËĐD§0›œîvņčåÃÆPšyr Ųm95†j‹NÉB _―Ŋk æĢAĶÂ)öï25ð Ü ÖE1nn•ŧĀÓ@‹,Ø―ÐāHeD·Å[ŸĀäü œ“3― ‘.Ā֔ķlžŠÓē{‚^Ô@}ЈõIB&{D> ūؔPÜGú7݅> 4ĮÖVd–öTî2Ę|ŠĄąpƒ0ąˆV/nƒGŲĀGšAh“#p%ī'tĪZē: þAČpK9qÞtú‰˜ØŲW5å$=„ÛZRl·m9îŪPÃņzF$˜WžžđÂĸ)ó(HĖËŋŸ5o(Č"@~ĒüÖú5ÖG;t]’šÂō`{ĐÏôj―濨•ó•ÍxČô Įos Û(ŦAÍdÐæŽ1ŸuLŲ‚" LˆĖé)>sÔ(–Je t/1ÔÖyõd/āö‹Õš8Îrņh2oþ/<?åØQ•=+ïî=á$z‹ĄÕø—Î.eäË+ýÄ-(Dø~vnÝų+út­)›|°'ŧ -ð=ûÂââO™-§9[ ―8ôŠ}>z“mÃŅiņī­Óózų(ĩ―"ĒÐ(ëĻ3—<Ąš> DFMvóRō‰^Fp*}l$F&šŋ•ŠË2(†nvIF’iml†™ĢLŲTÎ"GjÚ]Į}M{ŠÁSˆƒJąīwĸVnþ|zķÏŲ”Ū^_ĩlYg ŦÐXÅdDÁėRīŅ „öžĐŅÜéÝ­ø‚Ýš‡áÖa$DŽblaqu{D;I7UFĖÁA˕î·ÔúPēû7}eZ—­mÚ_ bÜŪøÍ­v0Í4É*―qÐķ•ęÝķC,"ŲÛô€―ž°špčã#Ũ§Ņ€:Õ;DžDĸģÝqX%‰BäŊü NF†qDxJ‚Å20Ú./0åƒŲvúÅCģ^!Í#ĢÝžÜûÃįbŽĄkų݆"˜;åH„ŅųAŽzn<üJåt0õeĻīcÔrŽ+\:yÄ_ØuÎj7þŸ;ÆwNmø ,Ž`mz”s^ ?-ƒ†GRėą―p†$t‡„†ZŽÝÏ‹ĐŠ ,:CN/€0–ÚP”dãŽhŊæ-–ųČ đÝ·—žýtýWÎ(g<æ/ŠÄ3°6Ïā'_ŦŊņ ˘‰ É)â,Œ›ôDdɗ:"‚Ôđߕï,.‚ōÖRæŌíūũĀ'ŽP`Ęq―vIzŨtl^IRŋEô7ūŧ–ë5zŧ―!AĻŌrIψ‰ GNˆÂĀ Û:Bā3ĪdŒSō íwGĪ)?iÝÁpïÉäíÅüøþi4zÛi°°ë!ģ‚hsýqTČlåXH@æx7`ũÐÜĩ“PŨ1}`ė h˜ĢĨþ”ßâÁxĮéļëØĒŠ M" ,ähī‚ ˜þW<^æŠâ̐ŽNN{M|[)„}ĨėļōwLF ß ‚]`Ļōī/đ D'ø&å/!ÎęōÛ(Ũ(þėK­%if\f{ūtų_Ļ bō0Ļņ —?^ýĘ\€9V SŽ?ØĪÂv+EÝ[ŧbjų;Óđ"S֍z.ā—núšÍų‹X”SÃz?eYʍˆsaÍ&ã[Ŋ}ÄôUŦ&ōuēˆÕŸW`đę‡ Þ€ĶÆēÐûW°­[köĶaģܕ™ÄĀĀâ!û‰šĘDŲ9?}&órÍ]öaâ @qųŦúƜ<Ε둗ŠÓĨŸšŠ(1åHŒí|‰þ9‚õýļsģïŸßVÛQ+%˜.ęr<â”J^Ž)ĢÔWY@snĩÅwõØ5:―·Ō4f|ûM Ņ8[2Ø üD+ĘVDãá° ØˆČėĒÜĒMTIýŨó–ŠŸÓ=焯72 ĸy‡cÚ!YØ—ĐžpCÃZ`Ū3hēœŧį›dƕč†Ŧé ôû|$§ó”ä%Zŧ„ÉXÐ^š3yōâ7O^Ÿë4;KČæĢ)ókPÂ]Ūî­Í-‹#x暉5mQÖIlūÂūRā)ö݃Ze1ðČh‡“ÛwLüžØxŅlt·nÂ―+ũū…VÉėØÄÃåU Ũ`OTÚyG,/é(SI{U-―O–ũs8rƒówIäĢgMÄjBy}ʀ‚#DŽôÏ'âŽģj•‚ž pĪ·ŽŠĖQ\žĘ8PÞ|_?ķ6 ‹ũHjFÚ=ĖÁ/QÓĸhŨt ^^”zópüī§d, ÅÁZĪQĸ äûŒGdWãĢ?đĻÞĻâ—ä/”/ôŽ %…ģ$vŽ}ÕŪYéÛo@GÔÎ^ūþ|,ĐGų{’/iŋĩR?SˆČXzœæģ…“°|˂~NðÕxfýā’ïëv"ĢGݟ9H(ää€ó(Ý*n. ЉīwĐũZ%—ÆŲ7ó …Ą ķŨŌF‘>ÚÎdRšį·SÆÁŦŲŌžžbíRÏ ĄÛ|á迁Ķ !‚Ę :ðú8K$ĐâLÆwðĢcæHîßžŲ †ŒÚã§GXŨ@ūáZ4ĄSZR”O,ÓEČ'W “KwÏ=Z—ãÖ˅$–QįŨ(aãjíĸũ…4dëþŧ/Ķ5~ļXþņFgYøŸúUÞŠXæā_*YhóËp†·Ĩ—ÔۜĄ1ŪqæęTéɃ<`š$CÛ;“ÖžĖø4ĢūeŨšąÅuؐ,é·1ØĪøđVžS'~`]ˆZ™ÔF[J\Ÿƒųė†%_{TõíĶÄGm‡‰đÖ}ņ-ŲžýÜÉ„ Ų‰ĨÚB*äąÄ’ķˆëæYį+[ėš,?ž@Éûœå uĸė&jŦaąYäõíršmRæÖó& —*·@š-_yú0pWš|ŧPøjîTƚ& ž1ˆæ­)ˆvėh=Y4ķؚUĐŒ  ŸŲ:j&LÚXŅøéęÐđ~žïŸ Ļ%€kŸh–GÁrqM)ûōpÏĒŽ„*_üŽŽJ‰O1$>Éą”q/Ŋýk“ņ2‘žÃĒ,…Øģ႐hMô^zK<ÄDÄ= ēĀCĻ=lāëÚSe7å―ÐuúúGŸ;5HßÓį0ƒfÜāēųUĀ-Cä0û[0“LDV _<:·Ž*6æe#Ėōfųr3Aé'š”[ųųJ‡ŸĮ&ø4x°šÁ―ŽVđtŽmtÔÁä~W‡› +īxôQŊ˜|bQEvH6 ī:·Í9á}K‡ 1ŧ §Ös!ķąû’ Ô*‹ŽXHâ ũĶ‘bxs0ČËú%õ••GÛi\ō>—žŦÂmQ:r§ ·đũ#ķkFĻŋah åk@hoģ:†elŌnū aUðkoĨž‡ úžR?đvśCļŪnE~ÔÝLĄöäĩģRĶažʎqõ9ĒMxžąR=0ĮįE‰Fá§šFK(>1ϘL‡„ÉŪąø\Čl“ßJ’U]éGïu*ú#=ęb;k:aϋ4’ēVõ‘ këÕxH‰–žGÆ4ūE)H‰ŠĄƒęfŋÝčŸ ƒö‚ãã!šRŒ‚4‰k$,C‹)3ĮYSbžė)Í<ëÜ3›SßDËø)lK5ö=vÉÖSY6âĒzÜoUgÆz|† ˆųËŌ8óCĐáSVKëŧ"_ˆé^uœP(4ö  2ÞĨ%ՒōE~ņ8ß$<€€ŌJä(„dô.ƒ‘Į=•:›iÍĀFô„ēlTäôýĄZÐĨØ:>ŧHôWë"4NŠ?fßl_ƒ“þÜ$qkˆB™MH7ŋü,}Įä/ŅV4MôdáčÛ⃐~%ßЁ;ð/€õĶh "•ü,õœÝÎÕ%1ŊvP.ÓJ ÞáwVrP?˜ƒ/†ŪqØÚQāó5ŧ[?žŽžƒĪ-Âd7ąÖs\ 8Ahę2Ė―Ž…ČmÄĻË ÓäŲ#ˆŪ"ßkЙĻō/ŋð†=‡ŒĀå/*úEŊ™į—Ëyęōųš\'^ŲMˆŸîiR/ÆÞ sŊ‘•Y-Æ^ŒÃ~˜ķ™ÃręÐú,X•jâ\!N,>I[CŦY5öü0™† ĶcҟoæĘø@ØŠ˜Ų"튚€šWø›‡—‡ĪÛį7H&šlI\T”z°VĒY}ŋŦöļĀ=―^­oģVŠ ŋĨĶĶ} Đ'ĪŅ―aēHÐmͰâb"%ęt:—å#ˆRõm߄æÝYDŅi"ĻJčw‰{ ôĘY!}"dzÕîe "ôAšœÖӠϙ|šúáhãc d‘åę‘CæÉü:‡"%h åÁeGþÕí^ß™ß0žßéģŽ„RáÄj7Îęj^šĀ€€€€€Ā@€€€Ā€ÔʋÍđŠéEŽģÔvÃäÝð|?FßŌ@ĸ ŌÕŲ#uӗ-ÏÉĢvũYøN‘DÆÆ5X*Ũåjŋ’} –ƒš!þÏ01Ņ4ãÛ?ÆÅ øyUŦ‘+Nã ü r°”å ōa&˧—‘ĻdĶ.î~%Č,ã|aT&KyW„ï)UDoØŨaé7|ĩýNē˜mL4õf‰ •Ī˜ aâiĀPléö•B|q·šËá%f9ŧGŽúý…=ūœ ‰’ZÆŦmüąvįt"ЋPr|2AZ~Đ/žĐŨÆÖĢeÍNxjg25ÅWÔ 'ûƒ ę•%ú5`^• ÞŦábĨՃ$Āˈâ'l„péšxÂĐ ™."úŲÖWe”“SFœ^ē’Ėí“JĒ[·üÔÏ[ÃÂïlĐĶ=ĐWãë”B wŽYŠ]Č(Åĸ|iCÔéw’]Ôr-ŠA7nŗ{$ÃzãįĩŽ‹w‘~ŨįŪe<‘óßæĒŧļˆ(v!íųŨŠd9ÁĖĪ”S‰ÝC{ÔZþ―™Ï\KW7ħ—gD3ÚŅNįÖĖž'ĶóürDĸ/|æJžčŧĩ-Sū·ßģ肒ųöCWÉåI'īČ+óãQfÃóty‰ČíņÄōØn.DtCĢUŽÍ Yɍþ!ŽÆyJrå)Ũ}<æ–ÉrŦ Pč-m>#D~ú­ Ï@6ßļ—;ō8ß―ĘŊéÜļÜÔķķ3ŋóCÞaP4,ÁÏCmĀĻA4Óī  Ä>f]įūLà Ē@ņļ…ĐóÆ BJ0Ūúæ9<–ŊßLs„ͰôäŽ[ŅRėžksÞîäĻRZ œ$Ճl`°ŋĨ4ōĢ?Žëv"rhĪt 9X>Ж`Ģ’!Š-Q.”Ē*{%†d H‰ĢYp\Ē ŊŪ8}›Ÿ{ÆSÄЎķ B›JC*š §Þ~―0ŊdB–á·įÉ-ŧųė(aÆ)įSžïÜϖÝ_ÖF…|7ųW Ÿ”Ųˆ– €ĻiŸóķž1éogjúYEwŊwŒĮC ü– TâXđŸĮSdŧ)Y˜úŠOđŒĻĪ-CW3jg(>iIÍį,“ÚįSvÅz)o[ ôéyJgŠũÁÜŨr^Af6 šøõG8dĄĄÍ­-™üĶ|Žþ|ŠizũLĢš| ,••ÄŊ’Nx .›ģtã‹ģüy‡i‘·;ĀĶΜƁiBč°þí•æ9Čc†"kÕÎĀ#~ÓlSTt’|#ęęÉlF‚øãœÆ/›ŅŽBYåïĢ9ÛaŊ/ąäĮïßīJ§CšŦÕ}|ÝÓ6UĩUP_˜YįĸAæX.A6z+g%éœvl0e A<€E'Ðl“(,nŽā>Å0oWĸbgŧKNï5$Ģï―ČÏ!FļŠ›•šÛšôŅO°ņŋé‰6é)ã_ÔaÝpįFŽ<˜ÃOØýū)ėßãøēÓ4Ÿî ôx]Ņ _^ŋģMē*Uڜð>ę–ĒDËCå+Į0 lÄ%\ũ“Øu);b%Æ(2fŲuÂÜ-ëČ\Ã|Pŧ:ëÔŪôSÁû]HÃōįđ§Ė‚Z[ßt™,Ú/9Wáń&ĮäH, ҇ Ih€wYõ„IÖĘ }úÅČ2CL5ē‚Z]“5w3“ô0üŠÚ€˜!ĸnþßJ‡Ð1Î?IƒĄŊΚæ.{í38sšŨ–ļ&Tģa–zýÜPA`ÏKowð·ýõ7ø}ɊOpŽ`rŪjĨŌØīŧ@ĖkĘÅwU“0!‚šÅ‰@•ÚąËQÍG8Ghϊwîļ%i>ĘĶķÏdĸkÕ ‚W -č·“)D<°‰ûĮfp‘ÅwmGĮóé…Dĸg9Úéįo™+‡æ‰QčBcȜÖýÄų û˰Ü" ”Í>yÅf2[d˜•Ę8}ō|y*jlFôÝÖÉ>‘ˆáāÚÄŲ9‚oČąQ6Ÿ+pl5õq}1YÄĪæÄIWO ^Ī^ic_c―/,|ŠŨŨýg)՟Îgēņ° iĸ&ā‡Š3aÄqe9/åO.Ö„ãëpÏÔēĻ8ĸœC]%m—’ €ÓTĨŠ%îv­T-[‚Ó_šĶÂnÕ^BÆ'^ū KĒļÉ Ýˆ5Ž—Ķ>Ā^ÐÄAßÓF736TPŨ}PŽéuĢ"jDøÄåö>…4Iâü‹}eÛĮ―đt—ķûD–øļæúKņĪĻ—›Žýƒ[Æ45뚆fg`DåÞo1…lßųō0Ėä4$-›ú!―ޑ%9Æ–‚Vâ!·ũŧØ-FfO /_‚/Îð$û:§“åG] ÉĶļ ;―ӋXeD%!ĻÛņ―ĘŽ&81Ņ_Ÿî·ČČÄīå(Ëôm\cËwöÆ7ųË3ˆŅÞNžGޟ=Qx*Gō!ÚӒę,ï:YāÄE9-―Ԁ$·ü`5ðjŨ“kØŦų#57ýqsöA@W’ė[xóxūŠē―‰„Qũև4q™ á·ĀV fNæJŽšF‹­Zŧ4Kúd‰ųÅ@<―ĖŨžnđ"fâWdb7îÝ;?Ā›āx åĩ:S õęBĢzB§ā(đnü–Ũ3ļw–ņ~̙ȑÜļCÛķm-ņisâŌ2Ä;‹rôfôĨ/_/“ęÍũ`­{!ņ„ŊũĀ ž› Îërïm&ŋŒŒņBWŪĢČĻI{t#mųáŨņšéÔVĘĒúæ^Ū@BāOːkðÕīnT8\ĮÏ,“>âŽäåEĀØåe§Zŋ§ˆ ’]”up)ĨŧwPüÕP•“ö;>›"ÞÉ{ĮSéŋ uPâÁwÂŽč…Šӛž8ðwčņ*ØëœD< ųvBŌŦ0âýŧŸ:ĐdR6ĻYģ0":äm9a6 ûÐ"Š'‘O]—ę8Ļ)Ī>ĪÏÞ7ōžc5ëÎ|LŒ9mąĀ,UCo\HĐCsļ'$ ĀU;GÜ'ögĸ[8đ(iĸkEĻ›áÏîyŽ…k íŽð•‘VÕĘÖqÝšûO^žtX‰++ķ̧ũđ "’ÓːĐæRĮÜb‰Éhƒoýø`ïę­RKĻÖĘûp`UÅų‘mĐí\+ŧq?,ņrƒĖdp2PôD/—ģ•óĮ0+;6œ!‘–E[0ąårŸ<ÜÆj§FŨø==\ÝŧØjN.āąkk’8Ī!d‰&›uēOG}~û€ËĘÚ(Hρu“ōövąį)Öã$}óІ­ûQï°v‚,˜S†ųJН–/qø tæģāĮŽd‰č{ģƚ"=}ÄĖŨ‘%ŒoMĖø:ķwląÄ2ęŽ`Ö1šˆŽžåC5,ĪH…Oyā‡ŦÐt -,™#v…ĄNԘģ1$ZD^æ,ē-’øūŊš0-\ę,øÔë=7č}øģ ûéĸnï}ÕaėGé\æ]5Ū–IŨ Eėį&8ëÏ·)?’ö ī>ũaŦõ<$|đíĨNÆ‹'|=aŅŠi†lĢz8í™Ũ"Ũ―É4Möð93!~ũTŅž íŸŌō°šWĘiný‹“(Ûs§ŽH=§öïåƒĐØĀ€€|;wÃßß\|6‡Ą“~ ü<øt§āšŋäü>Ą|:9ðt›áëĮÁԐ†[M+úc#”īSŋmnėų‹ųÃaŨ(ýüăŦî6Ģ<1ąôBøD*ųnZVäL PŧԌūtCÖ@DŅ$cũŪOGįÜ}sĘPŠķu„öŦSÛ^M(Ą YžŪßĩzh~Ė`’Č3bz‚DXr›‹ã|>ÐÃNŠŪž k!MļӊņZk}― ­ˆeR)f Î/IýēSÜ ą<Örälô‚™­,éqj=Í#_0Ŋë†ä‘FHôÂR=pČŨ:œQNTÅÂĨ•‹‘œþ•7ĖAÉ\Íjęōýnjåu)tkŅ>ÚĒnÞ<Īéšŋ-įĩP8Üį4ZŜ<åÏŠžĄLĄ$Ķ%Æ î‚<ö'ˆđ€–9œpā&]՜!:ðėӉFMy1íjpóSí8oGЎē‚+ī2+mÖūĖ ]Ë&å|!sýdōƒošPó0vŪxĘÅyQ[ÕÕEZȌ9†þt—CA[ožå™š|û”aX•_É~cŅ ËŸÝ5ÄX ‹€BuJ%ŅUZ9Ÿ|ēŧH893N,˜eūUū\!ŪJĨŲ úþʏ Ā)æRIxdo+óŋ9˧pa ŒZŽ#—!kĨæļݗB%ĻŠæËĮėԝLÍáKĀå6j<ĐÚ]4éÉ"úÃŊEq iėič>4<ûŋ9ūCĻŽILK‹/hþmŦ7ōč—YŲÝŽNžX"ðŠ&’ä,F`"!ĨũŊĨY`ŸÅEme^ƒ<˜Ž=ÃîAŠ`†âĮō·œ‘5f)ïebōÎë2Ė;TpQ mƒk”žŅJ\‚“BB>> 7a…ōÐą Ũwļ›T·ļ’ÚYFšUkÐõíä"Đød3• 6mØš+kĩGõTNīĐ|“žŨĒ „kšUrŠ\·ŪË]NĻ 0úÆŋ.KydKÚ^žĸ;#xŽįĘZ:„č·î<`å+%ū#m=iŽėĀJ? :Ŧ44/ŋpķhqŪ&})æEoGˆĸhYÝŨę]ž•ų%lÜūšãˆAĻ‚élĻß8PZĸ*W ģōæ2qЙjÏʗĀF.ˆÜČpĶØK Xļó #Ú·­#…d]ŸíwqIз‘Ķšņīģ…žD-NÏ·RN7•čO@Āīč<Ô­Ų€ÓÔï Óķũĸ><ƒMÐ:TNæ8ģßÓ5KpyWĸ}ÓÞÝļ‘lrģ‹*€Ö`ULzÛφÕ Đ‡nr3šæt9ĩ]ˆĨu‘›r/s­`?MĢŧwÕäi˜w흋ÐpFîyl0ii”Wïåmn ܧ'CĮÐ É{‚ËИ\V―%FύŠXøčEîũėũÂ8ĩŠåōéðÔ5ųÆū&–þ|õ’VīW3ũ€-ŠOd~…pƒá*q ïŋo/ˆ†v?‚4ãegįČSJ$e]*f#ī‘f/―ÆeÄŽpoå Óåę/ŋ††Ä ąy\"}ÏŽÂ{ūWxHð äĶĒrųų8%(îC\%,ŦĒķï|·ĸqƌDJ1·u,Ę.cû?Ø7ŋÂr``qī[˜bAþØÝŊ6ŊýtŠļ›ŲAp›wŪ ĒNÞ;”3i.ßJ45šåÜÕ_{8ßwÔŋC͜šĩĪÓYƒäŋøŒŒŒjŦ71ĄepŊÞĒ Œó1.pÓīēvU :~|W<Ëϋ[^yŦūé'ōØîĻPlļocâ]Zp2󠁓šÍ\ÚRó%ž=[FN"áÆMEĄcÍóÅRø€dëûžÍô3?DCļʆs‚FBN,"@UäúéŲîɍœóåAûŌãL’õ[Ēt&Gx[âpIU$Sž‰.ā“"Lyõ ˆš-ÖxA`þj(˜á öčÚ@"nŒ2ß*ŒaŠ™)dYžE,UĨÝ߆ūĸ8Ũ =įŌ*x͚+@ސ!Â,Rô%IĐÖõPÅô>P (ŨĨnþüŌ>ŌÖ·wŦ:uą™œqagŒÜÎ0ÎR‹LWu=0ý ļËąT…ũð9][·ũ™ĖŋjÎo[Ŧū$™ āˆxB·yNĖóŸŲ‚ÔÝĀ&.ĩ^:ŸāŠËĪušŧÂa›éŊAįBcŒ•ŦŧsģîĘåKŊāfˆ_ŸŽp_›ĢcšXmK‰ĄÆÂ\ÛJļ}ûFšF@Ŋ†(-qYœēŦŲïDļýōúĮ…ßP_oĨ7Īq7>HŠË?~―šŌÅV†TsÚSx QVm&íßĸ@û*”ō;cðĨēfVzæÐø­r§Ō‹ÖeÓü4 ˆÓ åã―Å Q”—ŦĐŧXļ x~9DHÂĐÅ·X_Õb6ÞKΆCwžâļĐĖ΍ʉēDą)"K°"ÔÝąÞēˆž›ûM#ēįG4svđdßÕmÅ9“­™ÁiïH=ŪfJõÖ]ņõĩ#uØl‹WÝëWæ˜^‰Ŋč}ą<„ø<ķŸv?z“ũ?„å‚ ÚîcGÛŃęZü 8ĒN.ÕđV›RuWS$t īũ[5ĮŨĪJï91>Ģ;ČL{ė|Ũ&–đ"hU@Ė;>8}ý3XûáĄøĐN”…ýX>UNä^ĪZĒ /H­7㉔K‡!đЉ'īģũïCâv­ßcÞ ŌF§Đ‡õÝî%ËqÁ™ž$ YŌ ‡8ĖVũ†ŽŦæāiÔ2S\ár3l‡$Ӆ,ĞĘc‚ PĻI+ƒĸ éÚB6Ĩ6–ķ.00ø`QŦņúSXĄŸēÓē{ˈŧ|.sC ē6Ē‹žÉ#āZ éŽsûėv' F h nĐĢr*nÓ{­é/EÓ·ŪėOž*“€IĄœØHÐ"ÎäĐ6iēåį+'‹ ÔJÐ(J}Íäķ^TķĄŲ}P(—| 7 å_ĶjŨÃĩI ;ˆļ‚Ö}”™§Ü-­hÄķ7‹†čĘ͛Äp!.Ō'ĩ‡Œx|äåĀß8hūY?Wg!6í’.ÁÂAšVAÔĶā/;Ó ŋŊŨ2ûÁíĶú•rbŽ”š°Ą˜#Í―Ŧ]m{ïĩ&uDĄá„4hŠąÔD}Œ§ÄQøŸÜ(•ÁŋĐ$1ZëP+zwįŅBØRéOQ*|žG=ã‘šūZ}Jņũŋ ãÆōõ›QlD_ZąI$+,T2ÞÁ Ýč‘5ö‹*‰cĸę0lqĶ zŠ"õž‹>gqé?Ŋę—.㐞ęÅXūˆ:‚Ý1Š]ûā$1xÃ―C°Ėų9P˜Ï5øåĻ8ånӓIĸĸ_·6óevûzŽôFųöĶŌ|Y’fðī[ã†všŅúQļÄĮ‡}]‘yŦB-ûų§ĶdjÛÉa­éLþ‹>ģ·ô1Ëþũ‰ąØÆē‚HߓOœ,„þ―†VąŽ1ë@‚ĩ%áÕ‘ôâÛũa›JÃFīÔ#āÓšG§MŒÛF%žÄšoĪsӒți/þOzž‚ĪūŲ w}&HÖëCī˜mGrĻUŽSŊSÄ(ŋâčq‚šýsÚu#ë‰eÉw9Ųäî™^tŧäęLä™âN4.έāõļ4ŦžęZ–NK•ljÄn-•ĐĪĨĪ]à Ļnõū“Štúē+ôæĮÍófü\(îĸF þzÚoĪ5ĒUҧ>Š Ą?=HQĸIęĐësõĪvI―*éĐ3wˆÕgI JŲzđŪTŋXRlP Eš$öˆŌ/…Ý8éÓE™…Üšđ2ÅîEBoōÎĀMę*ϊĢM!â‘=—­ŨbĒĮ‡C3·OÉ3Ôy2+‡€YūËɍĂ 7ūt€,…đHïĖxZq$úy˜'ŽgþÔ'g“Œ+c’ĖØBü{_įõ”Ąð&üĨ=9âüå\ËVėéį%“Ē™ÁewŨG’"4+ŌDŊ ī.›ÚĖ[90zøQPIT†2žC\‰ÐúW$jšKIFcą˜Ōš3Üeīo KSÎÞúáĐbÝqŽ$lĻū˜ËÐJ·Æ9͞ÕŲ3ģãК ’’BÉíųÖÓģÝĢžw|ž[Ō&AhJę˜ĨŪjÚ|UČÓŦƒ mĩAh{Sņ8=ŌlbóO& 6Y%‘Þ1ÝŋρšlĄÛý―7bó§gæĘG*Œ2~ßŒÛ `ĘïúïJTęÛsÐ|8FĢXÜ+Cgė_­:nzkÝUZ3”é?xėGƒ–Û8•“ũþXžË֏âũxÐõ]@<Î―Éxģî ôÚY†eÅĪĄoŌÂÅMT”ÁiJpsĸPÉģ~ĪŊ ĩ…tïÖQäš=ΐf“R;ŽŪž§+ܟēðBۄō"Ėï/,rÏãniÂ~‰éÚہE‰T•âĖeĒų‡Ũô ŽŋmŸNx9!—TEîAå 28„ķÎIĄŨ"CĮóZð Î!—ÏĀ>axS—fÁ æ R6‹―ˆÁÍƟMWŪ‚`Ë ĮB–!380°X›7üđžĩĐ{4đū„SõššuԋN˜UÕĪ<Č3ęuUø :ë%Gœö[ŽÎ#ē;ŪpJŲŲ1ÁīǐėØĩ/_ĩðŋĐ eŋ§ Íú‚ðØĮė‚ĩÞŌÜ^o€$WŅyŊ3tH&Ä —đ„Ïå–ût.0ę>ęŨd“’KFiä*(#u+áÔ9ņœ%=ŠóĮBBĢ5SĀOBS\.ųėuÕ –Æą.ü]Ž:é=Ëb>NEšđņšÁ·–,+ČöWuÝï“īšÂRįhžl/R€$æfúULēÄáĸpU>yØ`<ۏÔ2ó]GšKā›š…ZIĸ|‘wĢąNąų/ĶŲï ĸFqøÏÎГēķF+oƒ Úmėž>0Õvyfۊ:^ėkĢBÄyFĮüý(dSb>] ;Ÿ›‘°ĸ8ēfÛ(ۜ0õ!ŽÁ!Ä4Å9óÕøŧMÍÆß[]ŽÝ"QĶ›'9ĸ (3SuuK æoĻ{’<ĨÄöîj~Y0―’ę;Ũ"9ēSö•?cũœQûĶŋœ™oĄŲ9ü‚`s<"01kðþ$°ˆŒ‘ĪÎßïTƒr@Páđþäęú%*ųy؝Š&A(#nå>–Į’Þâ<•ēígŨ”ōó*($˜þ‰% SÐČ,K‘4Ũią暒áøuŦ·ļ]ąü:Ïáïk―YwąĸŅ<_ĶSūŨAßf!ðúm|>ĒþNāüŧōuáÝnęØ.é_‡wü>„þŅŧ؟‡Ņl‡ŨÃîlûmūģþTŋķ?'u>Nŧáwd—o…Úûŧ'áîk―{ø{3ðú …ßFšwÚ;čŨáôŌfŅ}=]öl8Oĸ\â›OĪčÞ%t›ž2ŠOėãœ2ĐũøSSŽM–ݧx-ëĶĄŦūþĀþÝ>aĒvöāõ°ōŽï>ÐĨ”EĘPmėV5—õĮþŽĒæėØŦāÚNv~īķôĐ$'–†zæe,1Î^ƒüņGĪ3?‚Ŧb7GœŦVŌĪŪådŋļbžWŌ5Síã>þ đMęBbvũw5ųI"ö<Ų=jÄu#â•āč^ŋ]o•ŊCŋWôŠŽ(å_ĒÆƒĄõÛá&ŒF-ÛÜ8žŸĢūH4s:,"įu4ĮápÛzÖA"V3ūøx|œŒĘ?@ĻoÃ2•]2ēM~æG#Háx”ĖQ‰ĸSîUEĢnQE:dÆįŦŽ9‚Ë™$ģäƒôī―^ãVkžcĄ1˜h/ð_"į0Qž_Ī.*jCgžĒgG#™đ™ėŌū°"0OĻ1™?IŸÍ$5UaœôÂ-*îÂė–ø‹VÜNIĸzŸ‰ũ„n#· cÅÃj[㏭Æ#°,ÔÕxā•Šā›håæī—ĪŠP’ŠŧØØðŧÅŧųðÂv'Ō#jƒcYüHĮĶ’M’%9KaŽ‰ž%Å9Ė)ĘXIž9ØÕGM40GX'hæ^}S§ô·wRdfuQûóDß&ϝ4 V„xŽ 'Ջ7~ v‘íWBÏ*ãóēl3'ð1F„1QaįāY˜š·m; *"‰ŠÔ7ū@éą ÔĀVÖėch”ņž&̀Dž+ûžvƎÓ$ķ`ƒ§6ÃļÚHĮÖ,vE–~ÜÞ{8Īßh^ Ūúk9—%Cãŧû·ŠĸĻlW˜žĀI+fÝüuœWe&_>Ã5ü:ˆG°ģâo—„Âī°Ý IÛ5ƒÐ’Aœ€4Þ$“ã4ž„Ü݌Fą‹7D:*…vđ‘ĪT‹ėN3Ü"Į7éķaf#ÞķŠöa§(ë<T ĒýúdsÎYNUį·•{*~Ÿæ*Pš$;Ōî>+ þa°v-|™–Ėi—q?@k m&·`DŲLˆĪÅ؟úŽęûŦό…Īrå˜Ï ݊.0TÐ5Šüú2ôãíUīsāš]ząÉ:âũŲ1zjK4Cq;cĪ€ãŧ“7Œ"ÝÉDĖOwģũÆīÔ4ݍÓS§âĢ6ČŅą6#ËBōÝaÆ7Û4ąÝMųÏņ>1ŸæzPc€wÐ îŪ3€ŽƂ,3°™ÜŠˆv_ę…Ęųnē†h‡wÎrƒ"Ũ~7Wĸ}ÂŌŋ_Ũ–I,ö|Y ōx./ąĻÅbķVōiŠoz ^•QÐqXžOFīíeyÞX\ŪxLQŧĮHņáī'K^“(§Oü%øwS!3A­s Ð2p6š‡ĩŅ}݀…0ŨYB”"ĻŅ6WĪā`2ŽĶlĶÂZ)ŽE7^TæĨfæ$Ĩ\ÜP<ũČð?‡ 2―ü“tp&īTfTT—°æąą~ŧTŌāpũš†bgŊÍüįã”ōãM3bĨƒĒؒnRcŨ|ó܄ÂN2BQÄ]Ž` '5…U ^M13ūâ<Փ%äØáÍĀd†uÅNīڞ(·pÄÐÕۊcgÄ ýŠ[Õ3īpę’}Ž]~AņzK9sz•ö,čÜē(Ār:Šĸ;É'đ;~ĐŽ`\°­$ZÁ…ˆ^ûØOŅtW”vš_ÚĢˀšˆķÔ―Ãl7xī(ģ‡Ä†w’Õ•ū…ýl={HƊPËFA0}kāžļb˜oŪ•|yp*ômR!IÉwŅĩĒ‚q†`įš{é‡įĶâ6a‡áG^Ü*,訓ð$"AŒYËÂOœĪ"úˆ ÎŪ„ÝG3!zĖÂRŸŒŦ—AĒ,ēŧåVö’E#wU2Ĩ4ÂkˆI—rkSį8 –Cd~õ!AĶ­9ˆŋŸ Ę',TÐ=yšt‚u#Ē•.YüQ–Ž ĮIĨ5q1GäISĀkķþŠįũߖ6ÔZđCk6zíōY967äW\s’€ *Œïƒá 5û0―[yâÜnįņ_ݞāL“/?ØÏF{ ‡[<āhœÐØíķÚû(  ÅîððeĮeôŌ~.~ĻÂũHbMĻ~Tû8ĸ`ty „ðāÜxôC›ō8ĶÕÛt+jāÛ-ļōkčãd W‚@ģ‚ˆQ|3\wčVĢÎäi™7žq…čˆĮŋYqeŠ#•KŲip<Ï]G𙑷ī\å`ÛË}mā>bo4ŒyýĢ%āý<ŠØwJ3šāgÆtŅĻÔ&ŽĖ~bHEŦ2û  aƒuLž†5ëV„˜äĨãĐđ €OUƒŸÛĩ9ü”FKKjĢcũGc­ïŠwãČŽÖ6ˌŌÕâxŽō:§LĨj•ŋaā˜ĒŪHã4ŽĢIÔ~]Æŋõžp9œÓÏds@wã―&E§ZŸ Îæƒ8x%áŒFt%–Ū.BŅVh%ŪĩŸäÂŨĘ'.ýDbxęŧ…ÄųE·ZĶ5öNŪÕ/%4ęZ“Ëߖ \fÛ,oĢ―'3­’úæTӊöĘ%jŨq–.p^‚úG™‘ð›°hD°ðÕ|?ƎÚrū0D‚rôeƒhÃzāįUlQM&ŦÎąîgkũ,æ&·ēr=6ŦÏG=fôõŽb홷Ü!ū“.xÐŋtĩÔbtš“P#7œĩæHĸgīzAģFyŸãŧō1ø ŋ2)bHbÄú]Ï—Ū›^ũôð€ąë―ŽĖ ĩęƒ$ĮcŧÐL„ŽcZ”Ô5>Ũܗ §îtīmĻseËyŠŽ 'ëļdÁÛïŋƒž;}øį"Á)ô ßÖüŽÞ>ōĀ[3ü;ā6"Ķ E͗|Ä{΁]`ԙšÆXŋwÏš0ģX:mœ’øø€ŋȧwKōā­—>røžT·ŅÁRĀ6OF6ŠýÛ*q#ýOĐĻ#Īx*(Ý Es‹>[З|#gĻ'ŒL3FĨE†AĄd7/čķ°a Öčw­Ō@eیr§{NÛt6F9=@ ÉŲûžáo#―Ÿ2Ģę•·OöÔb!t§þĄ&ĀīÁ ēāƒÓ ÛęĢ·þLūÝ―•ēÃd<â€ļÍoŅ7\ʔ‘Ÿ}ĖĀ4lÛí]*zČðČ5`’ƘóÝYFni-ęģXfš&PV8[BJ!b0D~įÐAžs1–Í]ÆĐÏĄ%å{[9ãgæÉĐ58ĄAŽ`ðÄģÔo3OŌēî3€ĸĸsÍËĸ ÍĐ"‡îîųÃū6įïaV[§î'ÅéXw˜ë]hĨāTĀųï{'œpétēÞE\1°_Кųī zĮh‡RÁØRlēęïėĄĸG―ŪGï5/ŧŅ2–§ŒęƧZz^QRKĐã>Āâ~b”ˁJĻVklUö8l+\ī5Ģ‹IA֐ӷ+&ΐ>é 4VöĨ%m[Qóāýߍ-{Fļ’Ënū·đũ+PģjĖd’Ô͌yAač‚Ó:ĀĢ$ķŽ<ĻQĒâcrH` zl"ėÉœėœ8ŸĖf>·;ĢßéEĀ„Są Ũūj^aáŊ™/;#|Ó-H"9„/BPߎÃDFL “6ô&öæ,jųø á°ÉÏ3ôP åōW5āŊŽķHĩZ™ŊCz17ðūZˆ- cJ›ū-Uø>žŠoō^Ęō$Į”ÕMï=ā~ü*&ĻūX)ô+Q”°†æ õĩ<æÍŲĪúHōūëžpëßĩŋzâdÚ^üjŠtXZYKäpÜÓÓlŌŋu›BŠ! ― ōņT ­yņc 4Ãž"fÞÝėN”‹=‹ōhn ĸ76^K ēĊū2âã-ð$֊ãŽN“™o#îúč8@_W-þÅó‚Į˜Bgb–+cĒĶ"V0§/ēuĒíUęo‹eb”ŽWËų1ū‚6†TmË ŅÎnčh7ĘâęĢ&)ÂZĪÁīälÅō™MW˜Â_Ãö/Ą€p°b•°\Ą H=˜Pā˜T{BVÚoÖ (N(Ø…ÃÚ2b]X—ĀŠ nę*&TĀüŋŌYđ: aŦSSƒBŸÞޑĖÚ‘ģŊšĪŠ0Î^Öļ―Æ~xNRēŸ­äŽĘāš;Ō0@Ï9^j’b–[xåĢ}R-&Ē|Äý_:…ŧ éļņÄxã;—]…‡ÝĪ`g)8Øö“L5l "=Hð7āpųCû™"ąï™*Ҙ 3ÁéDęŧTr š.%Ū2ēeÜt?ē7PhKdģKóŅĨcāČŽÂz""ĀÐÏ?þĩē1åŽÓɄˆ>?ô Ó5ķ ~Åņvĸ$BŧS·+{Ž<܏R3+ýr5ą‡Î’ĒĨ/…dZíŲ·4áĮ>ãDRl’^ĐŅÂûlÉ) ‚6îi‡ļEd/gwݜŌðHĻ`—PÛrîeĮß8;ûϔ”gŠ3ŠĄûtŠÄ#ŠcŊ6'+Já]SOöf\‚ozûlPf<ī‚—7GblxĒđYđõ )á Uð8Ǝč$ė·°|šÔE>Gžõ7QÎ6ZLŦ†;ĀæŸūVŧŸ4mũÄŋĄûÐ"—é(X;XÍÜō·MÎýPîüø°™° ڇpįËYj ZËPiđ—›Åâö^Z;œ@,JГÅUk="ˍˆŸv3eęT^‹f5 {ĸ[6ĐÕ|Ã6þãŨ_ú”ŦŠTGzķŌcļý1î_ļCÖŽŠŧ@+MTĒĪāĻåÜšĒOwžFdčKŠĄĻŸtĄÜĨ!Q›tēĮE–l#_gîÁ*æBcný ïŨÁČ藛˜Y2.čįĻOž:ƒ 9žē!0ĨhąęÎlžĻ‹ë‘'œš'óÕųĒp(võÚtĄŊÏFTūÎ/qUōi<ĨiũƒólÁŪ_‘8ëdƒUÏÖš„ÐĸŊëf:Ng(IGM0`ĶŌæewÄ"/ðėžĖr? Ü&9 BŨŲš4Ō`&rĐ/ĒðĢM#–Ā!O"eđ·ß&ëÃU‚/z™ž˜SŸb} ûáīÄ äï}ÆTØn‡ ęþÅ G@‹dÍ$Ni'âDÄģŸr†’ŋĨŋr“gŪ—Ygž6šwJĨŋ{œ―ō$āö”Ī­·ã–\°įy ÅĖ]lbF)o ˆXs”5-%ņ&8p„>!Ų―ÆNoĩ IĶ_ŅįÕ ũ=ÏQĒig™žöZV-õŸ†Vn‘"āܑa8 gÍČf‘‡Þ†FāËIâ”Zģ vÛΆ ‡îïãnÉč ÂZgĮä–n'Åv•ĻIđ@ýėHCVčĩ Į”RË·H9(Ã}ĪÜđM„Į|Œ Ķ―/GIpSMS!˛uŒ”<[”―*>ôŸųÏ,ÁĪýï•~HyÚŦKP˜žĐD Ļ˜―Ģ<žØÁgQĪãþ­{ķÛ!Ake4™pĸ “:ŌÓu=Xï*늊ÍėO94Yw1ĩ9õ5cĪ'hë?öģŒ!wB|$ÜŌ?īĢ(Tģ]ÉÎ ÛīÅ?điNŪÝ@åÖËĘtÃcBJu0Do°óÐ_U•54øBĨĖ [ēhôČˈŠj6Îãi4Oüđ ú3MQĪO fOÝÎðŌzį Íģ}SzŒĒVˆÔCU–Ē;':x!lï‘ė+aŲÕï―UBÛ>†Þ]š>ŊqŅF>ĩd!žģĄB7É)ūŦkÂ_WÆ!ŧ$œōZ―ßŋæž―ö[9)ŪÓQ!á{GT鎖Ëé;wëEĄŊOlkDKą{tų*‚o9ɄjG\―xžöKāĒĨ!rXŦß2 đaĘķĸCœą4Œã Aö%žÐūz؃˜ mÁéQ ûnĩ:­‹ŧĩžęÐ6Žūa]6Ōę2ßÚJ+ýŪ@–ÍÚp“úÞ 7žÐŧUüĸÚŨ Ōŧur@K M&„߅ĨæĮŽégNąęÅØ0ĨΒ/}Ī;Ú*ČPmËķ‡ÍÞúƒ]§ÎžÏÅæŠgCÍŽdĩ*ĨÞTҁ9Yģ„O3Rníų› FĶ+ī>ūp‡3ų>ęPČ WÎ{Ÿ‹áaX(Ķä,‚váĄā5å JæUïX‡Į„zÁv>k̰Šņ2,ų•xTƒY|Œ˜ž`Y"Ų‡mïÆ%•ę^ļ“:yL˜WᩋáņlĄtéĀAåmIš­ÚEĒ-€—r-ŋŅw]RÃé 7z îLĄáxŨQ[‰ĩŲ;‚ŪOïÅũ_vįŋvÐ;ÂOúšXĶTĢ­–ÍLĐwä! (æ(ˆ?ÓIžM'xc։ 6Û·Z‹@ã ýÓîÐ?§TxŽÐ)·MÆŨ>]nH˜)Üēû6*dŲō*ŊoŅŦƒ_ûN/ģýEÁó$‰ÚŸ/.„û&ądckt&·„Á4ä +ë’LƒžzŸïdaĨä}­þÜŊō ōĀĨ6īcžāÜŅéƒÓ1› „ÎM1ûW<6v!,EEeč°Ūïē9—\ðÍ{û…’āMǰðVį'ū^R—ęēírӒ;Ņ•ũ”ĪVŠ^Ú@ļ$YŋÔŪGMjðÏņŧŠLãÂę/ŠÔíå’m2aū9ï$ðeŲdkøĮÚĘĨ—ō·’NDäUmeN)ȧŊâïŦē„ûĪ:i<žČí%a€3rūNöuüĢĒĘ@‹„ÃúÓÁQö í;ô!Ēž3š=@WäËdÓŽœ&åë=PĪxĀþ"AýđEąũ j”HđM$V™ËŲ Â›ŋ|&Ÿ8ō”ÎŨ9n1äŦō‡ÃŪoÝĒĢĐÍåp9qVL“ éÉžîĘČ0В CbØÅ‚œ€6ÆsYëVýše†―qe/,bØšýđŪCï ēÁÖiåÝEå4`öņyĒŨEâj§7ÄĀĒƒ‹ĖO‰ų|EGįh‹‰:ýd{y%yė–Ė+?·ÖïxĪå\\Óėģũ՟å"[(†Ķ ‰Ņz~x)’ Öà J0@4Ý0UĮþŠ,uĩĩÆ/›QÉōĶþAoi·EÉÝ+å0RÐŪinkz؆PwlXLÐŲVä5…(™”…Ô nÎWw\†_ÛRƒcø7ÉLdj#›€–V(ųŊïā-Į$Øų…]Ž^bŪoÄþtõ ”Š2!NBô x*˜ŊĶÉÓēĶUÏ―ĒøH°éŦēņŠNŲj5ėĪ~āÁéÛyƒėmŦļ—Ę“ÆÐþ†’jƒ‡‚üiđL:a‡đŋó\ÔNŨÁˆÖīZķ‰;þÏ ãMjûÍŧÖĨ(˜ƒ2jU·|ZžYÝý™Ū~Ĩ7 ĮCŅuðÃâ{öҐÜhŲ\ĮŪ4F"^<ŊYö›•=ķŁĪD|Ž"Ý­yC8Ëýe녡[Š.MŪ{Đ― ƒWJ[ĨūÕ|QZņŌÔbyË'āïŨ$!–qēØÜCãŋ;ĪL^Û čŽ`-@vb:ķ†ģ“QēžĪėŽJnĮDøkļ‚ĪíÝ-É&ū―zv·ŦPÔ3Úėƒ‘gXĶų•å” “đLŸ‚b§QįjÎjÆdČæŊW{$ĸBSĩSĘŠ ų8q,ĒUs‡Nw+ŽâG!æ&e6Ęc=―1ÐČîį>$õNâfĻ<ĩži CdG™ÐÚÎĻl—ėš—Ü;B^$üķ^Ý`ļ.°ZÕtīˆ 3…?Ėņŧ— h˜ųq„ŌFäóę,iHuËėpYĶ }t4ņuKŒ€t`Á%Þ ąÃĻߓŦuüĨ)Đ6…ðâWë4?Q‰Ôgč‰s8[.e}ĸ·KøÔã…P`.5ðLŦš‹ß"įtÝûþS}ŠķĻØīËĻŊ`üŅcN;‹•„Õņ§ âïA)ۜņ0ü•ökķMŸIŪ=3Žņ0þr[þ “˜Š^JˆÍ!(/$ ŒaĖA!ōuķož é?íįČČ@ĪįPwsó‚˜-Qi„ōĪR‹þ§đųįĐwcQΈPŧafwDXŌ;)ûÄðDë%îlaBšþ‹F‰evv5(Ã~†Ļã`PŸT•RHOoký#€=Øīc‘ĪðHær’?vp|Â…ėJĢY7!TŪópK îyĖD ‹IRgŅ|‡š–OœĻ‹z}ßgB˜T<Ē ĸBųj‰žŧh4hŊØ}Gú^;D=0ÉVŠ[˜ĒŠËg0î-XČhV‚Ó"͌L)č_[;l—=›ŧ 1"Ŧ2ÚÐtÖõsŨÜĘgŧSÖ-+EŲz€Î–|§€äŠ­úq:Ð*ZtŧÎ õ{°Ą|ôJM3qtĮķæcēœáŒdēÜx+å=ÓCāĮ֓ãAYd1qŊÛũâ Ž‘ŦFo?MĪûÏa(ĸŨ0ZQ”-YOPbņ ŋÎ=ŋK?J<ÖCĀČŊ2؞ju3v’í9SäðBAÄ{S­ÔdũTŽœQø9^a-Ļ* u8ß">úCƒņ1B|ʉįļÆo’ŠĨ—‰<Š ÏÜöėė2‘ŲÄMڅō0Ó>ŽcW”ãĨÏÝž ˜Ļ8ð!—ę?`BŧڌļÐōīū/ŋqč.ˆ―§˜ÖAŦ;Î―ðĸMZBăāGŒeõëöŽ‘ŋ―ũ„9)Ĩrö!ņ‰8â)îŧR‹O(1BŒœ]™ŽaáãDü•b ~Đq)`AúË gĩV”øY=5Š+‚§Øõ2á;‰Ø&VĖ’ö—–X@ "PĶHkxĘOZģų}îŊûņĐp=đœß‡dÃ<%ņō†—·Ļ€7n•Äb(―YS˜/ķýïųŽÐoSY†‡Ø$)ōiŌæ1-˜NA€Ð&Đ,,ÄTu!cïíĶÛxœÃ6‘SÓō1ŠáĢÒDŽĶ9(6ę8ĪIæÐõåTļoÓ°;ïēxžîo ĄęqūÚČ9ĀļbXïaføŸ_>šâ uvįq›ō ąšøā=―\„{m’Ģƒ&―ĮŽZ_ą5˜ŧŪë=gÞuŅ0&Æ2:ë…ę"‚)ÝDđ―žã=ÞHŊo“ęē sÁŠ\ã$É37A ÔņŒ­―šRëé‰`t€šR44*Þ­Ī™ÜÕâą'`’ëič™iJ*ŠĶũļf]lxhÛą@–|ēÓē ëN6‡3\Yū§6đGŧN3F A›h™ ēņÉ8y€ MïaŠ‹ŊsQ@ÄÜ îbū3…fĘĖIŠ,}Įč]&Ū— žob;\owM_߀WnÔ5i&Ą#g­ys‘(CÁtAUBmÎŪÍW·Û=„FN€ĶEx4ÂĖ#TȍACÜZ“[äĖoųäēŧáö8‰‡ËYī­ō3L )·ČŽlÐäôF“Pē·-0―ūĒōGu?œš=dÚķ(mūðïįa3}u/ É9™ųísnʘ*ŅyåTû OņŲ)bŦéB.z;ÓüíĸSâŠ3âCB&<\ÝQœĮZčð”ZX>E3"ˆOƒ9a9œj*7KoĒ‹ėËjĶ”Œŧ-;ÂÖųŅ~Äír%ĐqTĩ‰HÂÞ:Z4xŒĸ~C€úČDŸ [‡zkķD4O ŨˁģóÛqjépð\厛BüÆ8m_‚Ï… ˗Č+0}ņ%Ũ—‹Ū•–xpŽAĢ( 4Ûď“ðl―ïĖt{?}CŠëģŽîŽøĀšđáš~/ĘĢēiŠÚ ß(#sz9‘Ð⊎+ĸ æEų*:^æŽ"Öš’žĐ<ÏĐōv ɋ/;í%Y2w"xtrN_}“°yž U-ËÞĨ?t•īöVņĨ,”-°íýJ°`äĨ .§?īŪYą"hî{žķŽL‰>`”SųĀj'ŠÏ–iēĶĒõ_ŽJOæļÓý"Hc‹˜ĶÃËÐd―lCŦŪ떓ŧ5Qiœ  Ē“VjІĢӏšžPZĮÍZ8ޝeŪæļ˜zÜ­~ÝwŨdgāŪ*ŠRƒoXM§]ČęR_cOÛjÞ2dēČÝ<>KJž­ŸJúĀ’ íHãI§þąĢ­Å ĻĩĄb ņČuRkzRϐ―`Ũį›NÎĀËĸRs*’Dr֝wÓŽąQĐ@’jÐt‡øLĩũFaĘŋmbƒŽšŨ§8ũ\ýĢÆwÅóW^įC-’ĒHÆÏ"îz·hģÃ9îČ\ÔŠ>&ē][Û6Š`Sû9tAxį—ųûđ˜pëĩgũZB™Ļp;ĒČ1dØXNóŌ8ī$Њ WËĢģð‹›í.E-Ïð$$ĢÓß;xelÄĩHâžUš<CĖ9ß―žþūriúbU―ãÂ%Ę Eņ ­ĮðđâúÚĮā4o7_IM1Weæ*Ū âbŽĒ’zĒ/.ëy*>*ž* ÜĨöÔÉ,ü0žŦĮāŽę”ĐpéŋjLČQ&|ßĀ2/? „TöšþF™Šą~1šŅÜVxOýÍÆēSūáĀēŲ !a Jäąāßģ ĀŲq”‹ đú†ärú-ƒrļhvYŽĻ‘åCĶüĶCaÚp·Ôæ`ÅV|ĩĄÕ K„b„VMiþïéãĩKĐï°{ÛŠ„ÂŽņØi<žÝvOúÓũ<ŽŌxbĸ?ņsðƒÝy3īåSÜâĶnņ'ۙž  mą{/Šō—Ķ—ÂĻú‘]E˜ W-E‚Ūa&79 e`*ôlŠBŽ„Ū:%NЌķ@I@Ļ*ɛ 7%ė§ÖĮÆjÉŲĒÎŧƒlWë,änh,Ä9rú›@Öė†ÂĻ’ ŠýĪa —ŒÖ ›đÐzÎ!’-2­„ĀïÄNzó‹ĀmáoĨ‡hóü@;ßKÃÉBļ’˜›nĀĨiÃ%wAz“ð m6ædŨÄų­õrŨßyåŒŪe„l]Æ'ÞëõâåVĨå]AÂhÜPhĄB…ėeĻAŨÐïDŽ=\užį3Ý%l(Œ?YQÎ Ð3ŨÏ(ĶÜ}ĘĨ‡ōėč!§$šLwq5õnNŧ{ÜffĖ3(é›4zše2n„ļ ĶíæÞ ôܗųČ B8AôĒ%juÝ‰ ę}Ükš[€/ĨýŨŅķjNĀï™{øģþĸ;°BJ‹/.B3Æē_JR7 þ xûß!ôĪ ’O…ø8þ^o^1Žû™d.üĪ)”įôÛåĖv4ŋ~óƒŠ>Š rdéīƒĖ lpVõ1Šũš„“„‘Ój!XŅŧ@čþ  ā°û“{p―AÕÚÃųÏï…Kžâď˜Å2ôų^äaļļO þmzē•%tdIá˜åJĢ‘ˆV Ļ$Ĩ9R##.†Ŧ‹Ã§ŒZKE ›ü(Nîj Q}Wŋōä́õOšŽĪWŧ|(Ymsģƒ§ĄOÆdøŊ7 VũĀW™ĩWTB †›ÝpÂRģG&­ß}ŊÆ šsTŸ VŒ“ĪU’ÄUūaaÅfŒ>œÓ”ëmŽ{{ƒė‰uZ}ĸ ÃÝá°~n*ˆëá֞ßā^wðūa}ŌgsÉAâ\qČv=Mï\>Į,õ(ū\~nÏN[ð ˆDÄųĘt7āeãŲäJG>zĘÍŊT+4~īó”ð!)́va 69lĸh-ņ§Ôęžį „ŊČ~ø‡ÂÏFČ`Å_HÝļūb―°ęÃŋî?|T‚+Íą8ÉĨiY>VR3Ds-c‹Ô–öYK+|―o+noÛÍqŅÆũFDĀēúŸÍģy–ã?*ĩm:Š<ËĮēļ“4ąž§*œlpŋFoöí;ˆîŧfD Q0. €°õ“ĨK+đï°ŅRūMŊ W ?Ma;ïC„âyo{UĻgÕ­–ÃĻ<ۃëÛĩē/Vc+ o™*Ã;ó(žČ/5/ļúüq;lû0õ kœš9)ó°‚ē VáuĀU‡J ļ•|Ø@ NJbōKsr€―Õž%ũ# KÖv/žBs"Ļ‹,ˆ%lä5ī­íķÏäŊĢC`ĩ}‡‘BtCîTôčïmÄ%zĨC<Ū0tĪ'G—"$!)Ķģ>ö Bþaâ_Uĸ[ëÖ·Y^Ķ.•ũYĘ&BïÞEEųsô$éŅĩĸN ļI1ïŠvŠ;„ķ˜Ĩ/ã6ŅMÍŸNre —ĩŊÛš3Ō 1Ė:~ÚČ迯[Јaûæ~ÖÕKWęŊÍ Ėá f3!įé<°ÉifŽ}Éh#K‰Ä”šÃ„„x—€/øãyĩĒá] ·_dŌ/iý[BčŦ­·ƒóížž;\tm( ŸoÃ‰ŲÆv<Ģ‘MĪģ6ū.‰„Ā'SY˜ČŦ čû~mĄX‰ Ė Ý/9:·đï E%ĻiDŋ/P;!øž§ļō-ž―!?Ģũ§ŊĢmðę;[GĢ ĘÂ΅ujÓ ŽŅ朇Ûëmq”Aæü þ.!!öĄjGˆtą„’<ĸŋ`í9―Ј@{̈́č\ųęó)é(‰c!aĸJEéDŲØŠĘC‡óΟc …3ŒWš]$ö$*‚pÓwہ•ēkõÄ3Mō ŲA%ĻlīEEa}~Y0+ÄđŽŊpøÑļĸP ųÄ åoÍ*—ÃÚĶĀĒ ļg#&įEëčSI•đ^‰~EĘoũ‰7tŧ<í ܓâ“ų›Ý‚tïî̆W‡Č2īĄÂģŲ•ŋėî&\ĨĖOijF­ŸHŊį"ŧĀH„p ·úwFsUzÉē 71*—üSޗOĐiŽÅcæ+3îÛ#u.ū[3íðJ47 <(ßļjÖ<Ė5Ïnۋ­7(JNvmãGu9ø;īĒŌKæ+4Jø;—ã"%T”‚:W—Gý Rl Ëɗ`þ’õâŽĀĩĩ>§)ūä:vŦGIĻsčoÕËŋą Ãĸ*­ĮgCGsã˜yuÐÁģk@ĘUí'“ģ=ŒļTģ1Í―€JGĶæVoaņÍÜāˆđęWĖŽßHg Đķ(f˜°æ)2ó/Óh1’Į>84ï)Vo,­GTí(„AŊrðŋč‡zY†eô>KŒžČۉlzØã†ņžŲ}ØÛ …(—ý|tCÃ+ÆųBĩ™#ā3#ģëý ˜95‚Úxƒø"Œįƒjw‚A'I5Oâ |ų’6™bCnüĩĨlûūŧ—oïÎÂę~!1ņgW#pé­ĒŒ6}6Aw ĪÞðY=dL/QËØƒÝ ášs…ė8 ‹Ë0ČÅOÕõaÖÂČ/‘fÓ/!“æ‘°č#W\Î9ïA$*å{ĀČ8Ž’$C!āa°·ŧMi8ذoöĪČP î‹ėŦÆx·Ļ…ëé!|“ĩ“úëØAũ!š\ečõpĢÎÂĸ/1ĩ‹'ŽŠōĐģ_Ž)B$eæ'ĶÖVC‚­ÝģŪo\ā„awlˆsą9=a™ Ēīęø<˜†­ÍŪЕŌë4ũKŅq}ŒĀŽj˜0ĶÐđē3ĻCĩ ūīU—ō>ˆFųč$nY)žIOØįFũ%E ņ*Ÿ6ŋdðe^;ôCÏJWŦÄ#žŠ$þü‹ƒ?ĸíˆvLTŋjæą4S}HAąƒŌ™9‹)ÞÁŌdĢYÔđÉ C9‚TE  MðĖĩæÆ7ÕáķI(hf`ïüþ:iĶâÖ_ânžs@ëŒÓ mētNՎ~Ž(–ædĖKĀ™Ũ̘\đ‘ābρåôÛøČwS·H–]›YÛŨ˜•QÞn=gūS\Dq?sčŧN'#L~čĀ}ēt§ũB]oĒŠÎ]ļĘ<ÖŠŠ|K,eÂó“Á7•kŧ áÍödåV89 %\õēÃ4ė„öbxšĪ„!)RéĨôPW9ģi•"Ģ`yÝŸ!|Ä|wšôĢât,čļúÕį‹ā.dÜ>8同č͎čäd‹ÐGüœŒ–`0jÆĐ aîėH å ūZ<ßΧzzÉzčր―qŧuëā.R6†d‰=‰Õ uëô-06~ZņNTER|zpĶU—LbOϑŸŒYč” ÉŲũ|ã(,2ē–°Ķ.ķI–Ÿ}d5E–’]o“ģšđ\W­f%3(#bGZ’â °ÆÞēį‘@Ó§z.yëŋWÛNĄŅ›ŊAĐē^)šw!DdįNZîĄũQrõiŊ]i0‡zâíÓM=6 Ę%Ø 2·Ï*ÔIÚ:EĐš!‰ĶZø―īžĀõÅϒD>ÓKõģĀ%ÖTؘĸ"ŽæjfJĪ"ũœðÔTК&“Œ—íˆĮé\ÜÍŲũŸ57%Č8ĸn›ÆÔKŒÆŒįb ÝÜ&õ‘Ē™FÁÕæÐ #ÚÅEϘ4›ÏęE~Iš;r"ŨĸpâÝlЉĢÔEupĶmMV5cØÉPý)š—ĢDÛĖø&ņøŲrį3*čXO.`ݟCģãÜą–ïįq i7yķ(‰ …ļĩ?ÕbũX_Ð ž€nZûüļ6YxęáÄ[‘kGßŧ|ï‘]ðʝ—ÏōG5Ø-#Ï&GÐXûéŊÓu@žëË/3:äÆXSgâĀӋŧ‚ļl‘ ęĨƒ7Ļ€ĻĖX+rä˜_ËۊĄØHĖž―ÍÓĘ? Úš†”å”\]Ęæ1(ę“ðl=uųî&'ëÅëev§ïGPĻÆŸģmÓý‹b;DëþO3vs„…L‰wšþ–į€öE_8ĶßúrČ ŠÏÜĄ,%e`'Ĩðé7Føþ{Jq&xHIWĨøz@'D`$ÈÆĒ$‡~ĩųÄûc<ųëķÐēž3ÉĪ6øû=Œëˆaý§K+ûÜ9ŠÄí°S{oԆÛ.mŨÕ8Ÿ]•Ē˰ĶčõĶMw‰BÝšŊC\“`‰įWÕY™ /]6öš=ú\ōOï„ĸ]-OÆðÏŪ@˜{ųDŒbŠÜÁ[?ŽÞ•§gđ(cCß­­ŅHNéĢ―Đč6ˆžļž/3O|Ė#sļFēĸ8ÕۚļQčū•°Ąš*‰'ë™hˆqÔ#–ÄïČ>G›ŊČĸqÎl쿀Jþā‘ĄöϗŽũĘ3Į Â^uĢNHcÛÐEFāĄŊīŠđ-#M tąÁ™LÕIÁ€·þ™—L­”7üWöýĮŲ|dŠFĨ(>,§Z%ï%\âĄéqšRïŸ)―.| ß\šMӍ+Icdógy7~–Vfžęð`ûųVįFŸņŲüUŅfĩXeÍÄđŽąR*~č‚ūÕîâé›F^+ë(GKŅqßŪäVōŋŠ- n,q<ŽŲŊd{ā' ›X.SŽÓïŠÃÃÝŧČÄ<·B:Â@ĐpJĶ1 MFE%õ9ûēƒļ‚0ÖŪBŧ†`"šô&ÄŠÞŲs‹š{ݙ]ëJŦ3+‡…5eÂDČZ—]Ú‰UƒĀŸWĩô Õ#ÝĢ-õu ­ÔˆÛÄ +9V8$ëX,h†jÕ2°\xžžîŠLoĄņãsÐXHíYĻ·5æüĮ+ƒƒŠLbÝáųėã; &zĶv\-ĘBøïös?ž‘6/eQmdf)ė§åŌ\Åė-^ðËã.˜ë€ŌŽLcL‰ĸ]ܚŸRWņ;=°a|žÂõËFđ傧ųrję›Y9—"Ûa•nå _°E!,…~qÓ“`%^ŽīaŲîL9’jmNmó4kŪzF8Ēó}Ē-4güĒ4˜ÎØ>?1Ú{žNÍļÄ W!Ļ―Đt,b2F1iˆ"1)ąNŠļ‚cĩĖü­0îĸjýĘđ*Xî …I=Ē𠟂e°%‰Q5ņŽęԒš™ÅŲĮ`kæ(€ëˆ Qõ–æ§4jâÚn'wŸ8@`Óãå y<ŧāëJ!Ųtąîu*–ÚĨļ*PĐÆd Ýŧņ°ŧ8ŨwŸēÜUíîėÝŠo2ūŋ4}āïdCaį4‘8lœ‹Ó37ÚČó;ZnwWmõĻÐ1æÄĒ–a ūņc)kÎ ĨOŠŽ°ģ=Ž<[ŋ2ĩ7šFj0ðYą™$ûeW}-ĀFVj34Ÿm=kęîYU““îëĸ4T`öžæõÝVš%'ø=ũ,}øîĖãsūÛC)/€+ˉ[”ƒ=#5“D<ĮÃCmu‡Ō"Pŧėņí ÁĢ)rč%Š=Ŧå]ōVW !ö°ÎaßÂëóŲ0Z…TđÓčNöģÜŽĄõãžļqũĮĢũ(3aiîāï°Wvû$$ÂK]įĨVÏæ8ûģđÃá ôšö#h(įßmúhœû &øĒŅōc―hp ņSéÜ― Ũ!@ãKļī•ČOó’8Ö?ëĒÃL–m$ĸOĄ˜ ð™GöŪŠÛõëyũĮLŨļÉ"7”ôO0øÛķmRýZfÖ,‚Dû;æ-3ôíņsÂl…ū`üwÔ# r·šhÃvÖ3Ō!vAŨ…ŋ ōkO3œïO…Ā8Pޕ!6]ėq§Ó ØðĄ~ó“ÏÖeā;7ĄHĩ°lýÔMoąÎ°øĶÄÛu5“3ķ1J”?ŌŋÁ@ @  ‚AAõqōĸŲqt-installer-framework-4.0.1/tools/build_installer.py0100777000000000000000000001304513761647206017771 0ustar00#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the Qt Installer Framework. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ ## Commercial License Usage ## Licensees holding valid commercial Qt licenses may use this file in ## accordance with the commercial license agreement provided with the ## Software or, alternatively, in accordance with the terms contained in ## a written agreement between you and The Qt Company. For licensing terms ## and conditions see https://www.qt.io/terms-conditions. For further ## information use the contact form at https://www.qt.io/contact-us. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 3 as published by the Free Software ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# import argparse import os import shutil import string import subprocess import sys args = {} src_dir = '' build_dir = '' package_dir = '' archive_file = '' target_path = '' def parse_arguments(): global args parser = argparse.ArgumentParser(description='Build installer for installer framework.') parser.add_argument('--clean', dest='clean', action='store_true', help='delete all previous build artifacts') parser.add_argument('--static-qmake', dest='qmake', required=True, help='path to qmake that will be used to build the tools') parser.add_argument('--doc-qmake', dest='doc_qmake', required=True, help='path to qmake that will be used to generate the documentation') parser.add_argument('--make', dest='make', required=True, help='make command') parser.add_argument('--targetdir', dest='target_dir', required=True, help='directory the generated installer will be placed in') if sys.platform == 'darwin': parser.add_argument('--qt_menu_nib', dest='menu_nib', required=True, help='location of qt_menu.nib (usually src/gui/mac/qt_menu.nib)') args = parser.parse_args() def run(args): print 'calling ' + string.join(args) subprocess.check_call(args) def init(): global src_dir global build_dir global package_dir global target_path src_dir = os.path.dirname(os.path.abspath(os.path.dirname(sys.argv[0]))) root_dir = os.path.dirname(src_dir) basename = os.path.basename(src_dir) build_dir = os.path.join(root_dir, basename + '_build') package_dir = os.path.join(root_dir, basename + '_pkg') target_path = os.path.join(args.target_dir, 'Qt Installer Framework') print 'source dir: ' + src_dir print 'build dir: ' + build_dir print 'package dir: ' + package_dir print 'target path: ' + target_path if args.clean and os.path.exists(build_dir): print 'delete existing build dir ...' shutil.rmtree(build_dir) if not os.path.exists(build_dir): os.makedirs(build_dir) if os.path.exists(args.target_dir): print 'delete existing target dir ...' shutil.rmtree(args.target_dir) os.makedirs(args.target_dir) if os.path.exists(package_dir): print 'delete existing package dir ...' shutil.rmtree(package_dir) os.makedirs(package_dir) def build_docs(): print 'building documentation ...' os.chdir(build_dir) run((args.doc_qmake, src_dir)) run((args.make, 'docs')) print 'success!' def build(): print 'building sources ...' os.chdir(build_dir) run((args.qmake, src_dir)) run((args.make)) def package(): global package_dir print 'package ...' os.chdir(package_dir) shutil.copytree(os.path.join(build_dir, 'bin'), os.path.join(package_dir, 'bin'), ignore = shutil.ignore_patterns("*.exe.manifest","*.exp","*.lib")) if sys.platform == 'linux2': run(('strip',os.path.join(package_dir, 'bin/archivegen'))) run(('strip',os.path.join(package_dir, 'bin/binarycreator'))) run(('strip',os.path.join(package_dir, 'bin/devtool'))) run(('strip',os.path.join(package_dir, 'bin/installerbase'))) run(('strip',os.path.join(package_dir, 'bin/repogen'))) shutil.copytree(os.path.join(build_dir, 'doc'), os.path.join(package_dir, 'doc')) shutil.copytree(os.path.join(src_dir, 'examples'), os.path.join(package_dir, 'examples')) shutil.copy(os.path.join(src_dir, 'README'), package_dir) # create 7z archive_file = os.path.join(src_dir, 'dist', 'packages', 'org.qtproject.ifw.binaries', 'data', 'data.7z') if not os.path.exists(os.path.dirname(archive_file)): os.makedirs(os.path.dirname(archive_file)) run((os.path.join(package_dir, 'bin', 'archivegen'), archive_file, '*')) # run installer binary_creator = os.path.join(build_dir, 'bin', 'binarycreator') config_file = os.path.join(src_dir, 'dist', 'config', 'config.xml') package_dir = os.path.join(src_dir, 'dist', 'packages') installer_path = os.path.join(src_dir, 'dist', 'packages') run((binary_creator, '--offline-only', '-c', config_file, '-p', package_dir, target_path)) if sys.platform == 'darwin': shutil.copytree(args.menu_nib, target_path + '.app/Contents/Resources/qt_menu.nib') parse_arguments() init() build_docs() build() package() print 'DONE, installer is at ' + target_path qt-installer-framework-4.0.1/tools/common/0040777000000000000000000000000013761647206015530 5ustar00qt-installer-framework-4.0.1/tools/common/repositorygen.cpp0100777000000000000000000013503413761647206021153 0ustar00/************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "repositorygen.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace QInstaller; using namespace QInstallerTools; void QInstallerTools::printRepositoryGenOptions() { std::cout << " -p|--packages dir The directory containing the available packages." << std::endl; std::cout << " This entry can be given multiple times." << std::endl; std::cout << " --repository dir The directory containing the available repository." << std::endl; std::cout << " This entry can be given multiple times." << std::endl; std::cout << " -e|--exclude p1,...,pn Exclude the given packages." << std::endl; std::cout << " -i|--include p1,...,pn Include the given packages and their dependencies" << std::endl; std::cout << " from the repository." << std::endl; std::cout << " --ignore-translations Do not use any translation" << std::endl; std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl; std::cout << " --ignore-invalid-repositories Ignore all invalid repositories instead of aborting." << std::endl; } QString QInstallerTools::makePathAbsolute(const QString &path) { if (QFileInfo(path).isRelative()) return QDir::current().absoluteFilePath(path); return path; } void QInstallerTools::copyWithException(const QString &source, const QString &target, const QString &kind) { qDebug() << "Copying associated" << kind << "file" << source; const QFileInfo targetFileInfo(target); if (!targetFileInfo.dir().exists()) QInstaller::mkpath(targetFileInfo.absolutePath()); QFile sourceFile(source); if (!sourceFile.copy(target)) { qDebug() << "failed!\n"; throw QInstaller::Error(QString::fromLatin1("Cannot copy the %1 file from \"%2\" to \"%3\": " "%4").arg(kind, QDir::toNativeSeparators(source), QDir::toNativeSeparators(target), /* in case of an existing target the error String does not show the file */ (targetFileInfo.exists() ? QLatin1String("Target already exist.") : sourceFile.errorString()))); } qDebug() << "done."; } static QStringList copyFilesFromNode(const QString &parentNode, const QString &childNode, const QString &attr, const QString &kind, const QDomNode &package, const PackageInfo &info, const QString &targetDir) { QStringList copiedFiles; const QDomNodeList nodes = package.firstChildElement(parentNode).childNodes(); for (int i = 0; i < nodes.count(); ++i) { const QDomNode node = nodes.at(i); if (node.nodeName() != childNode) continue; const QDir dir(QString::fromLatin1("%1/meta").arg(info.directory)); const QString filter = attr.isEmpty() ? node.toElement().text() : node.toElement().attribute(attr); const QStringList files = dir.entryList(QStringList(filter), QDir::Files); if (files.isEmpty()) { throw QInstaller::Error(QString::fromLatin1("Cannot find any %1 matching \"%2\" " "while copying %1 of \"%3\".").arg(kind, filter, info.name)); } foreach (const QString &file, files) { const QString source(QString::fromLatin1("%1/meta/%2").arg(info.directory, file)); const QString target(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, file)); copyWithException(source, target, kind); copiedFiles.append(file); } } return copiedFiles; } void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &metaDataDir, const PackageInfoVector &packages, const QString &appName, const QString &appVersion, const QStringList &uniteMetadatas) { const QString targetDir = makePathAbsolute(_targetDir); if (!QFile::exists(targetDir)) QInstaller::mkpath(targetDir); bool componentMetaExtracted = false; QDomDocument doc; QDomElement root; QFile existingUpdatesXml(QFileInfo(metaDataDir, QLatin1String("Updates.xml")).absoluteFilePath()); if (existingUpdatesXml.open(QIODevice::ReadOnly) && doc.setContent(&existingUpdatesXml)) { root = doc.documentElement(); // remove entry for this component from existing Updates.xml, if found foreach (const PackageInfo &info, packages) { const QDomNodeList packageNodes = root.childNodes(); for (int i = packageNodes.count() - 1; i >= 0; --i) { const QDomNode node = packageNodes.at(i); if (node.nodeName() != QLatin1String("PackageUpdate")) continue; if (node.firstChildElement(QLatin1String("Name")).text() != info.name) continue; root.removeChild(node); } } existingUpdatesXml.close(); } else { root = doc.createElement(QLatin1String("Updates")); root.appendChild(doc.createElement(QLatin1String("ApplicationName"))).appendChild(doc .createTextNode(appName)); root.appendChild(doc.createElement(QLatin1String("ApplicationVersion"))).appendChild(doc .createTextNode(appVersion)); root.appendChild(doc.createElement(QLatin1String("Checksum"))).appendChild(doc .createTextNode(QLatin1String("true"))); } foreach (const PackageInfo &info, packages) { if (info.metaFile.isEmpty() && info.metaNode.isEmpty()) { if (!QDir(targetDir).mkpath(info.name)) throw QInstaller::Error(QString::fromLatin1("Cannot create directory \"%1\".").arg(info.name)); const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(info.directory); qDebug() << "Copy meta data for package" << info.name << "using" << packageXmlPath; QFile file(packageXmlPath); QInstaller::openForRead(&file); QString errMsg; int line = 0; int column = 0; QDomDocument packageXml; if (!packageXml.setContent(&file, &errMsg, &line, &column)) { throw QInstaller::Error(QString::fromLatin1("Cannot parse \"%1\": line: %2, column: %3: %4 (%5)") .arg(QDir::toNativeSeparators(packageXmlPath)).arg(line).arg(column).arg(errMsg, info.name)); } QDomElement update = doc.createElement(QLatin1String("PackageUpdate")); QDomNode nameElement = update.appendChild(doc.createElement(QLatin1String("Name"))); nameElement.appendChild(doc.createTextNode(info.name)); // list of current unused or later transformed tags QStringList blackList; blackList << QLatin1String("UserInterfaces") << QLatin1String("Translations") << QLatin1String("Licenses") << QLatin1String("Name"); bool foundDefault = false; bool foundVirtual = false; bool foundDisplayName = false; bool foundDownloadableArchives = false; bool foundCheckable = false; const QDomNode package = packageXml.firstChildElement(QLatin1String("Package")); const QDomNodeList childNodes = package.childNodes(); for (int i = 0; i < childNodes.count(); ++i) { const QDomNode node = childNodes.at(i); const QString key = node.nodeName(); if (key == QLatin1String("Default")) foundDefault = true; if (key == QLatin1String("Virtual")) foundVirtual = true; if (key == QLatin1String("DisplayName")) foundDisplayName = true; if (key == QLatin1String("DownloadableArchives")) foundDownloadableArchives = true; if (key == QLatin1String("Checkable")) foundCheckable = true; if (node.isComment() || blackList.contains(key)) continue; // just skip comments and some tags... QDomElement element = doc.createElement(key); for (int j = 0; j < node.attributes().size(); ++j) { element.setAttribute(node.attributes().item(j).toAttr().name(), node.attributes().item(j).toAttr().value()); } update.appendChild(element).appendChild(doc.createTextNode(node.toElement().text())); } if (foundDefault && foundVirtual) { throw QInstaller::Error(QString::fromLatin1("Error: and elements are " "mutually exclusive in file \"%1\".").arg(QDir::toNativeSeparators(packageXmlPath))); } if (foundDefault && foundCheckable) { throw QInstaller::Error(QString::fromLatin1("Error: and " "elements are mutually exclusive in file \"%1\".") .arg(QDir::toNativeSeparators(packageXmlPath))); } if (!foundDisplayName) { qWarning() << "No DisplayName tag found at" << info.name << ", using component Name instead."; QDomElement displayNameElement = doc.createElement(QLatin1String("DisplayName")); update.appendChild(displayNameElement).appendChild(doc.createTextNode(info.name)); } // get the size of the data quint64 componentSize = 0; quint64 compressedComponentSize = 0; const QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot; const QDir dataDir = QString::fromLatin1("%1/%2/data").arg(metaDataDir, info.name); const QFileInfoList entries = dataDir.exists() ? dataDir.entryInfoList(filters | QDir::Dirs) : QDir(QString::fromLatin1("%1/%2").arg(metaDataDir, info.name)).entryInfoList(filters); qDebug() << "calculate size of directory" << dataDir.absolutePath(); foreach (const QFileInfo &fi, entries) { try { if (fi.isDir()) { QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories); while (recursDirIt.hasNext()) { recursDirIt.next(); const quint64 size = QInstaller::fileSize(recursDirIt.fileInfo()); componentSize += size; compressedComponentSize += size; } } else if (Lib7z::isSupportedArchive(fi.filePath())) { // if it's an archive already, list its files and sum the uncompressed sizes QFile archive(fi.filePath()); compressedComponentSize += archive.size(); QInstaller::openForRead(&archive); QVector::const_iterator fileIt; const QVector files = Lib7z::listArchive(&archive); for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) componentSize += fileIt->uncompressedSize; } else { // otherwise just add its size const quint64 size = QInstaller::fileSize(fi); componentSize += size; compressedComponentSize += size; } } catch (const QInstaller::Error &error) { qDebug().noquote() << error.message(); } catch(...) { // ignore, that's just about the sizes - and size doesn't matter, you know? } } QDomElement fileElement = doc.createElement(QLatin1String("UpdateFile")); fileElement.setAttribute(QLatin1String("UncompressedSize"), componentSize); fileElement.setAttribute(QLatin1String("CompressedSize"), compressedComponentSize); // adding the OS attribute to be compatible with old sdks fileElement.setAttribute(QLatin1String("OS"), QLatin1String("Any")); update.appendChild(fileElement); root.appendChild(update); // copy script file const QString script = package.firstChildElement(QLatin1String("Script")).text(); if (!script.isEmpty()) { QFile scriptFile(QString::fromLatin1("%1/meta/%2").arg(info.directory, script)); if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) { throw QInstaller::Error(QString::fromLatin1("Cannot open component script at \"%1\".") .arg(QDir::toNativeSeparators(scriptFile.fileName()))); } const QString scriptContent = QLatin1String("(function() {") + QString::fromUtf8(scriptFile.readAll()) + QLatin1String(";" " if (typeof Component == \"undefined\")" " throw \"Missing Component constructor. Please check your script.\";" "})();"); // if the user isn't aware of the downloadable archives value we will add it automatically later foundDownloadableArchives |= scriptContent.contains(QLatin1String("addDownloadableArchive")) || scriptContent.contains(QLatin1String("removeDownloadableArchive")); static QInstaller::ScriptEngine testScriptEngine; const QJSValue value = testScriptEngine.evaluate(scriptContent, scriptFile.fileName()); if (value.isError()) { throw QInstaller::Error(QString::fromLatin1("Exception while loading component " "script at \"%1\": %2").arg(QDir::toNativeSeparators(scriptFile.fileName()), value.toString().isEmpty() ? QString::fromLatin1("Unknown error.") : value.toString() + QStringLiteral(" on line number: ") + value.property(QStringLiteral("lineNumber")).toString())); } const QString toLocation(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, script)); copyWithException(scriptFile.fileName(), toLocation, QInstaller::scScript); } // write DownloadableArchives tag if that is missed by the user if (!foundDownloadableArchives && !info.copiedFiles.isEmpty()) { QStringList realContentFiles; foreach (const QString &filePath, info.copiedFiles) { if (!filePath.endsWith(QLatin1String(".sha1"), Qt::CaseInsensitive)) { const QString fileName = QFileInfo(filePath).fileName(); // remove unnecessary version string from filename and add it to the list realContentFiles.append(fileName.mid(info.version.count())); } } update.appendChild(doc.createElement(QLatin1String("DownloadableArchives"))).appendChild(doc .createTextNode(realContentFiles.join(QChar::fromLatin1(',')))); } // copy user interfaces const QStringList uiFiles = copyFilesFromNode(QLatin1String("UserInterfaces"), QLatin1String("UserInterface"), QString(), QLatin1String("user interface"), package, info, targetDir); if (!uiFiles.isEmpty()) { update.appendChild(doc.createElement(QLatin1String("UserInterfaces"))).appendChild(doc .createTextNode(uiFiles.join(QChar::fromLatin1(',')))); } // copy translations QStringList trFiles; if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) { trFiles = copyFilesFromNode(QLatin1String("Translations"), QLatin1String("Translation"), QString(), QLatin1String("translation"), package, info, targetDir); if (!trFiles.isEmpty()) { update.appendChild(doc.createElement(QLatin1String("Translations"))).appendChild(doc .createTextNode(trFiles.join(QChar::fromLatin1(',')))); } } // copy license files const QStringList licenses = copyFilesFromNode(QLatin1String("Licenses"), QLatin1String("License"), QLatin1String("file"), QLatin1String("license"), package, info, targetDir); if (!licenses.isEmpty()) { foreach (const QString &trFile, trFiles) { // Copy translated license file based on the assumption that it will have the same base name // as the original license plus the file name of an existing translation file without suffix. foreach (const QString &license, licenses) { const QFileInfo untranslated(license); const QString translatedLicense = QString::fromLatin1("%2_%3.%4").arg(untranslated .baseName(), QFileInfo(trFile).baseName(), untranslated.completeSuffix()); // ignore copy failure, that's just about the translations QFile::copy(QString::fromLatin1("%1/meta/%2").arg(info.directory).arg(translatedLicense), QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, translatedLicense)); } } update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode()); } } else { // Extract metadata from archive if (!info.metaFile.isEmpty()){ QFile metaFile(info.metaFile); QInstaller::openForRead(&metaFile); Lib7z::extractArchive(&metaFile, targetDir); componentMetaExtracted = true; } // Restore "PackageUpdate" node; QDomDocument update; if (!update.setContent(info.metaNode)) { throw QInstaller::Error(QString::fromLatin1("Cannot restore \"PackageUpdate\" description for node %1").arg(info.name)); } root.appendChild(update.documentElement()); } } if (!componentMetaExtracted) { foreach (const QString uniteMetadata, uniteMetadatas) { QFile metaFile(QFileInfo(metaDataDir, uniteMetadata).absoluteFilePath()); QInstaller::openForRead(&metaFile); Lib7z::extractArchive(&metaFile, targetDir); } } doc.appendChild(root); QFile targetUpdatesXml(targetDir + QLatin1String("/Updates.xml")); QInstaller::openForWrite(&targetUpdatesXml); QInstaller::blockingWrite(&targetUpdatesXml, doc.toByteArray()); } PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packagesDirectories, QStringList *packagesToFilter, FilterType filterType) { qDebug() << "Collecting information about available packages..."; bool ignoreInvalidPackages = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-packages")); PackageInfoVector dict; QFileInfoList entries; foreach (const QString &packagesDirectory, packagesDirectories) entries.append(QDir(packagesDirectory).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)); for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) { if (filterType == Exclude) { // Check for current file in exclude list, if found, skip it and remove it from exclude list if (packagesToFilter->contains(it->fileName())) { packagesToFilter->removeAll(it->fileName()); continue; } } else { // Check for current file in include list, if not found, skip it; if found, remove it from include list if (!packagesToFilter->contains(it->fileName())) continue; packagesToFilter->removeAll(it->fileName()); } qDebug() << "Found subdirectory" << it->fileName(); // because the filter is QDir::Dirs - filename means the name of the subdirectory if (it->fileName().contains(QLatin1Char('-'))) { qDebug("When using the component \"%s\" as a dependency, " "to ensure backward compatibility, you must add a colon symbol at the end, " "even if you do not specify a version.", qUtf8Printable(it->fileName())); } QFile file(QString::fromLatin1("%1/meta/package.xml").arg(it->filePath())); QFileInfo fileInfo(file); if (!fileInfo.exists()) { if (ignoreInvalidPackages) continue; throw QInstaller::Error(QString::fromLatin1("Component \"%1\" does not contain a package " "description (meta/package.xml is missing).").arg(QDir::toNativeSeparators(it->fileName()))); } file.open(QIODevice::ReadOnly); QDomDocument doc; QString error; int errorLine = 0; int errorColumn = 0; if (!doc.setContent(&file, &error, &errorLine, &errorColumn)) { if (ignoreInvalidPackages) continue; throw QInstaller::Error(QString::fromLatin1("Component package description in \"%1\" is invalid. " "Error at line: %2, column: %3 -> %4").arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()), QString::number(errorLine), QString::number(errorColumn), error)); } const QDomElement packageElement = doc.firstChildElement(QLatin1String("Package")); const QString name = packageElement.firstChildElement(QLatin1String("Name")).text(); if (!name.isEmpty() && name != it->fileName()) { qWarning().nospace() << "The tag in the file " << fileInfo.absoluteFilePath() << " is ignored - the installer uses the path element right before the 'meta'" << " (" << it->fileName() << ")"; } QString releaseDate = packageElement.firstChildElement(QLatin1String("ReleaseDate")).text(); if (releaseDate.isEmpty()) { qWarning("Release date for \"%s\" is empty! Using the current date instead.", qPrintable(fileInfo.absoluteFilePath())); releaseDate = QDate::currentDate().toString(Qt::ISODate); } if (!QDate::fromString(releaseDate, Qt::ISODate).isValid()) { if (ignoreInvalidPackages) continue; throw QInstaller::Error(QString::fromLatin1("Release date for \"%1\" is invalid! %2" ". Supported format: YYYY-MM-DD").arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()), releaseDate)); } PackageInfo info; info.name = it->fileName(); info.version = packageElement.firstChildElement(QLatin1String("Version")).text(); // Version cannot start with comparison characters, be an empty string // or have whitespaces at the beginning or at the end if (!QRegExp(QLatin1String("(?![<=>\\s]+)(.+)")).exactMatch(info.version) || (info.version != info.version.trimmed())) { if (ignoreInvalidPackages) continue; throw QInstaller::Error(QString::fromLatin1("Component version for \"%1\" is invalid! %2") .arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()), info.version)); } info.dependencies = packageElement.firstChildElement(QLatin1String("Dependencies")).text() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); info.directory = it->filePath(); dict.push_back(info); qDebug() << "- it provides the package" << info.name << " - " << info.version; } if (!packagesToFilter->isEmpty() && packagesToFilter->at(0) != QString::fromLatin1( "X_fake_filter_component_for_online_only_installer_X")) { qWarning() << "The following explicitly given packages could not be found\n in package directory:" << *packagesToFilter; } if (dict.isEmpty()) qDebug() << "No available packages found at the specified location."; return dict; } PackageInfoVector QInstallerTools::createListOfRepositoryPackages(const QStringList &repositoryDirectories, QStringList *packagesToFilter, FilterType filterType) { qDebug() << "Collecting information about available repository packages..."; bool ignoreInvalidRepositories = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-repositories")); PackageInfoVector dict; QFileInfoList entries; foreach (const QString &repositoryDirectory, repositoryDirectories) entries.append(QFileInfo(repositoryDirectory)); for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) { qDebug() << "Process repository" << it->fileName(); QFile file(QString::fromLatin1("%1/Updates.xml").arg(it->filePath())); QFileInfo fileInfo(file); if (!fileInfo.exists()) { if (ignoreInvalidRepositories) { qDebug() << "- skip invalid repository"; continue; } throw QInstaller::Error(QString::fromLatin1("Repository \"%1\" does not contain a update " "description (Updates.xml is missing).").arg(QDir::toNativeSeparators(it->fileName()))); } if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Cannot open Updates.xml for reading:" << file.errorString(); continue; } QString error; QDomDocument doc; if (!doc.setContent(&file, &error)) { qDebug().nospace() << "Cannot fetch a valid version of Updates.xml from repository " << it->fileName() << ": " << error; continue; } file.close(); const QDomElement root = doc.documentElement(); if (root.tagName() != QLatin1String("Updates")) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", "Invalid content in \"%1\".").arg(QDir::toNativeSeparators(file.fileName()))); } const QDomNodeList children = root.childNodes(); for (int i = 0; i < children.count(); ++i) { const QDomElement el = children.at(i).toElement(); if ((!el.isNull()) && (el.tagName() == QLatin1String("PackageUpdate"))) { QInstallerTools::PackageInfo info; QDomElement c1 = el.firstChildElement(QInstaller::scName); if (!c1.isNull()) info.name = c1.text(); else continue; if (filterType == Exclude) { // Check for current package in exclude list, if found, skip it if (packagesToFilter->contains(info.name)) { continue; } } else { // Check for current package in include list, if not found, skip it if (!packagesToFilter->contains(info.name)) continue; } c1 = el.firstChildElement(QInstaller::scVersion); if (!c1.isNull()) info.version = c1.text(); else continue; info.directory = QString::fromLatin1("%1/%2").arg(it->filePath(), info.name); const QDomElement sha1 = el.firstChildElement(QInstaller::scSHA1); if (!sha1.isNull()) { info.metaFile = QString::fromLatin1("%1/%3%2").arg(info.directory, QString::fromLatin1("meta.7z"), info.version); } const QDomNodeList c2 = el.childNodes(); for (int j = 0; j < c2.count(); ++j) { const QDomElement c2Element = c2.at(j).toElement(); if (c2Element.tagName() == QInstaller::scDependencies) info.dependencies = c2Element.text() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); else if (c2Element.tagName() == QInstaller::scDownloadableArchives) { QStringList names = c2Element.text() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); foreach (const QString &name, names) { info.copiedFiles.append(QString::fromLatin1("%1/%3%2").arg(info.directory, name, info.version)); info.copiedFiles.append(QString::fromLatin1("%1/%3%2.sha1").arg(info.directory, name, info.version)); } } } QString metaString; { QTextStream metaStream(&metaString); el.save(metaStream, 0); } info.metaNode = metaString; dict.push_back(info); qDebug() << "- it provides the package" << info.name << " - " << info.version; } } } return dict; } QHash QInstallerTools::buildPathToVersionMapping(const PackageInfoVector &info) { QHash map; foreach (const PackageInfo &inf, info) map[inf.name] = inf.version; return map; } static void writeSHA1ToNodeWithName(QDomDocument &doc, QDomNodeList &list, const QByteArray &sha1sum, const QString &nodename = QString()) { if (nodename.isEmpty()) qDebug() << "Writing sha1sum node."; else qDebug() << "Searching sha1sum node for" << nodename; QString sha1Value = QString::fromLatin1(sha1sum.toHex().constData()); for (int i = 0; i < list.size(); ++i) { QDomNode curNode = list.at(i); QDomNode nameTag = curNode.firstChildElement(scName); if ((!nameTag.isNull() && nameTag.toElement().text() == nodename) || nodename.isEmpty()) { QDomNode sha1Node = curNode.firstChildElement(scSHA1); QDomNode newSha1Node = doc.createElement(scSHA1); newSha1Node.appendChild(doc.createTextNode(sha1Value)); if (!sha1Node.isNull() && sha1Node.hasChildNodes()) { QDomNode sha1NodeChild = sha1Node.firstChild(); QString sha1OldValue = sha1NodeChild.nodeValue(); if (sha1Value == sha1OldValue) { qDebug() << "- keeping the existing sha1sum" << sha1OldValue; continue; } else { qDebug() << "- clearing the old sha1sum" << sha1OldValue; sha1Node.removeChild(sha1NodeChild); } } if (sha1Node.isNull()) curNode.appendChild(newSha1Node); else curNode.replaceChild(newSha1Node, sha1Node); qDebug() << "- writing the sha1sum" << sha1Value; } } } void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QString &existingUnite7zUrl, const QHash &versionMapping, bool createSplitMetadata, bool createUnifiedMetadata) { QDomDocument doc; QDomElement root; // use existing Updates.xml, if any QFile existingUpdatesXml(QFileInfo(QDir(repoDir), QLatin1String("Updates.xml")).absoluteFilePath()); if (!existingUpdatesXml.open(QIODevice::ReadOnly) || !doc.setContent(&existingUpdatesXml)) { qDebug() << "Cannot find Updates.xml"; } else { root = doc.documentElement(); } existingUpdatesXml.close(); QDir dir(repoDir); const QStringList entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); QStringList absPaths; if (createUnifiedMetadata) { absPaths = unifyMetadata(repoDir, existingUnite7zUrl, doc); } if (createSplitMetadata) { splitMetadata(entryList, repoDir, doc, versionMapping); } else { // remove the files that got compressed foreach (const QString path, absPaths) QInstaller::removeFiles(path, true); } QInstaller::openForWrite(&existingUpdatesXml); QInstaller::blockingWrite(&existingUpdatesXml, doc.toByteArray()); existingUpdatesXml.close(); } QStringList QInstallerTools::unifyMetadata(const QString &repoDir, const QString &existingRepoDir, QDomDocument doc) { QStringList absPaths; QDir dir(repoDir); const QStringList entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); foreach (const QString &i, entryList) { dir.cd(i); const QString absPath = dir.absolutePath(); absPaths.append(absPath); dir.cdUp(); } QTemporaryDir existingRepoTempDir; QString existingRepoTemp = existingRepoTempDir.path(); if (!existingRepoDir.isEmpty()) { existingRepoTempDir.setAutoRemove(false); QFile archiveFile(existingRepoDir); QInstaller::openForRead(&archiveFile); Lib7z::extractArchive(&archiveFile, existingRepoTemp); QDir dir(existingRepoTemp); QStringList existingRepoEntries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); foreach (const QString existingRepoEntry, existingRepoEntries) { if (entryList.contains(existingRepoEntry)) { continue; } else { dir.cd(existingRepoEntry); const QString absPath = dir.absolutePath(); absPaths.append(absPath); } } } // Compress all metadata from repository to one single 7z const QString metadataFilename = QDateTime::currentDateTime(). toString(QLatin1String("yyyy-MM-dd-hhmm")) + QLatin1String("_meta.7z"); QDateTime dateTime = QDateTime::currentDateTime(); const QString tmpTarget = repoDir + QDir::separator() + metadataFilename; Lib7z::createArchive(tmpTarget, absPaths, Lib7z::TmpFile::No); QFile tmp(tmpTarget); tmp.open(QFile::ReadOnly); const QByteArray sha1Sum = QInstaller::calculateHash(&tmp, QCryptographicHash::Sha1); QDomNodeList elements = doc.elementsByTagName(QLatin1String("Updates")); writeSHA1ToNodeWithName(doc, elements, sha1Sum, QString()); qDebug() << "Updating the metadata node with name " << metadataFilename; if (elements.count() > 0) { QDomNode node = elements.at(0); QDomNode nameTag = node.firstChildElement(QLatin1String("MetadataName")); QDomNode newNodeTag = doc.createElement(QLatin1String("MetadataName")); newNodeTag.appendChild(doc.createTextNode(metadataFilename)); if (nameTag.isNull()) node.appendChild(newNodeTag); else node.replaceChild(newNodeTag, nameTag); } QInstaller::removeDirectory(existingRepoTemp, true); return absPaths; } void QInstallerTools::splitMetadata(const QStringList &entryList, const QString &repoDir, QDomDocument doc, const QHash &versionMapping) { QStringList absPaths; QDomNodeList elements = doc.elementsByTagName(QLatin1String("PackageUpdate")); QDir dir(repoDir); foreach (const QString &i, entryList) { dir.cd(i); const QString absPath = dir.absolutePath(); const QString path = QString(i).remove(repoDir); if (path.isNull()) continue; const QString versionPrefix = versionMapping[path]; const QString fn = QLatin1String(versionPrefix.toLatin1() + "meta.7z"); const QString tmpTarget = repoDir + QLatin1String("/") + fn; Lib7z::createArchive(tmpTarget, QStringList() << absPath, Lib7z::TmpFile::No); // remove the files that got compressed QInstaller::removeFiles(absPath, true); QFile tmp(tmpTarget); tmp.open(QFile::ReadOnly); const QByteArray sha1Sum = QInstaller::calculateHash(&tmp, QCryptographicHash::Sha1); writeSHA1ToNodeWithName(doc, elements, sha1Sum, path); const QString finalTarget = absPath + QLatin1String("/") + fn; if (!tmp.rename(finalTarget)) { throw QInstaller::Error(QString::fromLatin1("Cannot move file \"%1\" to \"%2\".").arg( QDir::toNativeSeparators(tmpTarget), QDir::toNativeSeparators(finalTarget))); } dir.cdUp(); } } void QInstallerTools::copyComponentData(const QStringList &packageDirs, const QString &repoDir, PackageInfoVector *const infos) { for (int i = 0; i < infos->count(); ++i) { const PackageInfo info = infos->at(i); const QString name = info.name; qDebug() << "Copying component data for" << name; const QString namedRepoDir = QString::fromLatin1("%1/%2").arg(repoDir, name); if (!QDir().mkpath(namedRepoDir)) { throw QInstaller::Error(QString::fromLatin1("Cannot create repository directory for component \"%1\".") .arg(name)); } if (info.copiedFiles.isEmpty()) { QStringList compressedFiles; QStringList filesToCompress; foreach (const QString &packageDir, packageDirs) { const QDir dataDir(QString::fromLatin1("%1/%2/data").arg(packageDir, name)); foreach (const QString &entry, dataDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files)) { QFileInfo fileInfo(dataDir.absoluteFilePath(entry)); if (fileInfo.isFile() && !fileInfo.isSymLink()) { const QString absoluteEntryFilePath = dataDir.absoluteFilePath(entry); if (Lib7z::isSupportedArchive(absoluteEntryFilePath)) { QFile tmp(absoluteEntryFilePath); QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, entry, info.version); qDebug() << "Copying archive from" << tmp.fileName() << "to" << target; if (!tmp.copy(target)) { throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3") .arg(QDir::toNativeSeparators(tmp.fileName()), QDir::toNativeSeparators(target), tmp.errorString())); } compressedFiles.append(target); } else { filesToCompress.append(absoluteEntryFilePath); } } else if (fileInfo.isDir()) { qDebug() << "Compressing data directory" << entry; QString target = QString::fromLatin1("%1/%3%2.7z").arg(namedRepoDir, entry, info.version); Lib7z::createArchive(target, QStringList() << dataDir.absoluteFilePath(entry), Lib7z::TmpFile::No); compressedFiles.append(target); } else if (fileInfo.isSymLink()) { filesToCompress.append(dataDir.absoluteFilePath(entry)); } } } if (!filesToCompress.isEmpty()) { qDebug() << "Compressing files found in data directory:" << filesToCompress; QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, QLatin1String("content.7z"), info.version); Lib7z::createArchive(target, filesToCompress, Lib7z::TmpFile::No); compressedFiles.append(target); } foreach (const QString &target, compressedFiles) { (*infos)[i].copiedFiles.append(target); QFile archiveFile(target); QFile archiveHashFile(archiveFile.fileName() + QLatin1String(".sha1")); qDebug() << "Hash is stored in" << archiveHashFile.fileName(); qDebug() << "Creating hash of archive" << archiveFile.fileName(); try { QInstaller::openForRead(&archiveFile); const QByteArray hashOfArchiveData = QInstaller::calculateHash(&archiveFile, QCryptographicHash::Sha1).toHex(); archiveFile.close(); QInstaller::openForWrite(&archiveHashFile); archiveHashFile.write(hashOfArchiveData); qDebug() << "Generated sha1 hash:" << hashOfArchiveData; (*infos)[i].copiedFiles.append(archiveHashFile.fileName()); archiveHashFile.close(); } catch (const QInstaller::Error &/*e*/) { archiveFile.close(); archiveHashFile.close(); throw; } } } else { foreach (const QString &file, (*infos)[i].copiedFiles) { QFileInfo fromInfo(file); QFile from(file); QString target = QString::fromLatin1("%1/%2").arg(namedRepoDir, fromInfo.fileName()); qDebug() << "Copying file from" << from.fileName() << "to" << target; if (!from.copy(target)) { throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3") .arg(QDir::toNativeSeparators(from.fileName()), QDir::toNativeSeparators(target), from.errorString())); } } } } } void QInstallerTools::filterNewComponents(const QString &repositoryDir, QInstallerTools::PackageInfoVector &packages) { QDomDocument doc; QFile file(repositoryDir + QLatin1String("/Updates.xml")); if (file.open(QFile::ReadOnly) && doc.setContent(&file)) { const QDomElement root = doc.documentElement(); if (root.tagName() != QLatin1String("Updates")) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", "Invalid content in \"%1\".").arg(QDir::toNativeSeparators(file.fileName()))); } file.close(); // close the file, we read the content already // read the already existing updates xml content const QDomNodeList children = root.childNodes(); QHash hash; for (int i = 0; i < children.count(); ++i) { const QDomElement el = children.at(i).toElement(); if ((!el.isNull()) && (el.tagName() == QLatin1String("PackageUpdate"))) { QInstallerTools::PackageInfo info; const QDomNodeList c2 = el.childNodes(); for (int j = 0; j < c2.count(); ++j) { const QDomElement c2Element = c2.at(j).toElement(); if (c2Element.tagName() == scName) info.name = c2Element.text(); else if (c2Element.tagName() == scVersion) info.version = c2Element.text(); } hash.insert(info.name, info); } } // remove all components that have no update (decision based on the version tag) for (int i = packages.count() - 1; i >= 0; --i) { const QInstallerTools::PackageInfo info = packages.at(i); // check if component already exists & version did not change if (hash.contains(info.name) && KDUpdater::compareVersion(info.version, hash.value(info.name).version) < 1) { packages.remove(i); // the version did not change, no need to update the component continue; } qDebug() << "Update component" << info.name << "in"<< repositoryDir << "."; } } } QString QInstallerTools::existingUniteMeta7z(const QString &repositoryDir) { QString uniteMeta7z = QString(); QFile file(repositoryDir + QLatin1String("/Updates.xml")); QDomDocument doc; if (file.open(QFile::ReadOnly) && doc.setContent(&file)) { QDomNodeList elements = doc.elementsByTagName(QLatin1String("MetadataName")); if (elements.count() > 0 && elements.at(0).isElement()) { uniteMeta7z = elements.at(0).toElement().text(); QFile metaFile(repositoryDir + QDir::separator() + uniteMeta7z); if (!metaFile.exists()) { throw QInstaller::Error(QString::fromLatin1("Unite meta7z \"%1\" does not exist in repository \"%2\"") .arg(QDir::toNativeSeparators(metaFile.fileName()), repositoryDir)); } } } return uniteMeta7z; } qt-installer-framework-4.0.1/tools/common/repositorygen.h0100777000000000000000000000633613761647206020622 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef QINSTALLER_REPOSITORYGEN_H #define QINSTALLER_REPOSITORYGEN_H #include #include #include #include #include namespace QInstallerTools { struct PackageInfo { QString name; QString version; QString directory; QStringList dependencies; QStringList copiedFiles; QString metaFile; QString metaNode; }; typedef QVector PackageInfoVector; enum FilterType { Include, Exclude }; void printRepositoryGenOptions(); QString makePathAbsolute(const QString &path); void copyWithException(const QString &source, const QString &target, const QString &kind = QString()); PackageInfoVector createListOfPackages(const QStringList &packagesDirectories, QStringList *packagesToFilter, FilterType ftype); PackageInfoVector createListOfRepositoryPackages(const QStringList &repositoryDirectories, QStringList *packagesToFilter, FilterType filterType); QHash buildPathToVersionMapping(const PackageInfoVector &info); void compressMetaDirectories(const QString &repoDir, const QString &existingUnite7zUrl, const QHash &versionMapping, bool createSplitMetadata, bool createUnifiedMetadata); QStringList unifyMetadata(const QString &repoDir, const QString &existingRepoDir, QDomDocument doc); void splitMetadata(const QStringList &entryList, const QString &repoDir, QDomDocument doc, const QHash &versionMapping); void copyMetaData(const QString &outDir, const QString &dataDir, const PackageInfoVector &packages, const QString &appName, const QString& appVersion, const QStringList &uniteMetadatas); void copyComponentData(const QStringList &packageDir, const QString &repoDir, PackageInfoVector *const infos); void filterNewComponents(const QString &repositoryDir, QInstallerTools::PackageInfoVector &packages); QString existingUniteMeta7z(const QString &repositoryDir); } // namespace QInstallerTools #endif // QINSTALLER_REPOSITORYGEN_H qt-installer-framework-4.0.1/tools/devtool/0040777000000000000000000000000013761647206015714 5ustar00qt-installer-framework-4.0.1/tools/devtool/binarydump.cpp0100777000000000000000000001323113761647206020572 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binarydump.h" #include #include #include #include #include #include int BinaryDump::dump(const QInstaller::ResourceCollectionManager &manager, const QString &target) { QDir targetDir(QFileInfo(target).absoluteFilePath()); if (targetDir.exists()) { if (!targetDir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) { std::cerr << qPrintable(QString::fromLatin1("Target directory \"%1\" already exists and " "is not empty.").arg(QDir::toNativeSeparators(targetDir.path()))) << std::endl; return EXIT_FAILURE; } } else { if (!QDir().mkpath(targetDir.path())) { std::cerr << qPrintable(QString::fromLatin1("Cannot create \"%1\".").arg( QDir::toNativeSeparators(targetDir.path()))) << std::endl; return EXIT_FAILURE; } } QInstaller::CopyDirectoryOperation copyMetadata(nullptr); copyMetadata.setArguments(QStringList() << QLatin1String(":/") << (targetDir.path() + QLatin1Char('/'))); // Add "/" at the end to make operation work. if (!copyMetadata.performOperation()) { std::cerr << qPrintable(copyMetadata.errorString()) << std::endl; return EXIT_FAILURE; } if (!targetDir.cd(QLatin1String("metadata"))) { std::cerr << qPrintable(QString::fromLatin1("Cannot switch to \"%1/metadata\".") .arg(QDir::toNativeSeparators(targetDir.path()))) << std::endl; return EXIT_FAILURE; } int result = EXIT_FAILURE; try { QFile updatesXml(targetDir.filePath(QLatin1String("Updates.xml"))); QInstaller::openForRead(&updatesXml); QString error; QDomDocument doc; if (!doc.setContent(&updatesXml, &error)) { throw QInstaller::Error(QString::fromLatin1("Cannot read: \"%1\": %2").arg( QDir::toNativeSeparators(updatesXml.fileName()), error)); } QHash versionMap; const QDomElement root = doc.documentElement(); const QDomNodeList rootChildNodes = root.childNodes(); for (int i = 0; i < rootChildNodes.count(); ++i) { const QDomElement element = rootChildNodes.at(i).toElement(); if (element.isNull()) continue; QString name, version; if (element.tagName() == QLatin1String("PackageUpdate")) { const QDomNodeList elementChildNodes = element.childNodes(); for (int j = 0; j < elementChildNodes.count(); ++j) { const QDomElement e = elementChildNodes.at(j).toElement(); if (e.tagName() == QLatin1String("Name")) name = e.text(); else if (e.tagName() == QLatin1String("Version")) version = e.text(); } versionMap.insert(name, version); } } foreach (const QString &name, versionMap.keys()) { const QInstaller::ResourceCollection c = manager.collectionByName(name.toUtf8()); if (c.resources().count() <= 0) continue; if (!targetDir.mkpath(name)) { throw QInstaller::Error(QString::fromLatin1("Cannot create target dir: %1.") .arg(targetDir.filePath(name))); } foreach (const QSharedPointer &resource, c.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) continue; // TODO: should we throw here? QFile target(targetDir.filePath(name) + QDir::separator() + QString::fromUtf8(resource->name())); QInstaller::openForWrite(&target); resource->copyData(&target); // copy the 7z files into the target directory if (!isOpen) // If we reach that point, either the resource was opened already... resource->close(); // or we did open it and have to close it again. } } result = EXIT_SUCCESS; } catch (const QInstaller::Error &error) { std::cerr << qPrintable(error.message()) << std::endl; } catch (...) { std::cerr << "Unknown exception caught." << std::endl; } return result; } qt-installer-framework-4.0.1/tools/devtool/binarydump.h0100777000000000000000000000277113761647206020246 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYDUMP_H #define BINARYDUMP_H #include class BinaryDump { Q_DISABLE_COPY(BinaryDump) public: BinaryDump() {} int dump(const QInstaller::ResourceCollectionManager &manager, const QString &target); }; #endif // BINARYDUMP_H qt-installer-framework-4.0.1/tools/devtool/binaryreplace.cpp0100777000000000000000000001631613761647206021247 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binaryreplace.h" #include #include #include #include #include #include #include #include #include #include #include #include BinaryReplace::BinaryReplace(const QInstaller::BinaryLayout &layout) : m_binaryLayout(layout) {} int BinaryReplace::replace(const QString &source, const QString &target) { const QUrl url = QUrl::fromUserInput(source); QFutureWatcher taskWatcher; if (url.isRelative() || url.isLocalFile()) { taskWatcher.setFuture(QtConcurrent::run(&QInstaller::CopyFileTask::doTask, new QInstaller::CopyFileTask(QInstaller::FileTaskItem(url.isRelative() ? QFileInfo(source).absoluteFilePath() : url.toLocalFile())))); } else { taskWatcher.setFuture(QtConcurrent::run(&QInstaller::DownloadFileTask::doTask, new QInstaller::DownloadFileTask(QInstaller::FileTaskItem(url.toString())))); } bool result = EXIT_FAILURE; try { taskWatcher.waitForFinished(); // throws on error const QFuture future = taskWatcher.future(); if (future.resultCount() <= 0) return result; QString newInstallerBasePath = future.result().target(); if (Lib7z::isSupportedArchive(newInstallerBasePath)) { QFile archive(newInstallerBasePath); if (archive.open(QIODevice::ReadOnly)) { try { Lib7z::extractArchive(&archive, QDir::tempPath()); const QVector files = Lib7z::listArchive(&archive); newInstallerBasePath = QDir::tempPath() + QLatin1Char('/') + files.value(0) .path; result = EXIT_SUCCESS; } catch (const Lib7z::SevenZipException& e) { std::cerr << qPrintable(QString::fromLatin1("Error while extracting \"%1\": %2") .arg(QDir::toNativeSeparators(newInstallerBasePath), e.message())) << std::endl; } catch (...) { std::cerr << qPrintable(QString::fromLatin1("Unknown exception caught while " "extracting \"%1\".").arg(QDir::toNativeSeparators(newInstallerBasePath))) << std::endl; } } else { std::cerr << qPrintable(QString::fromLatin1("Cannot open \"%1\" for reading: %2") .arg(QDir::toNativeSeparators(newInstallerBasePath), archive.errorString())) << std::endl; } if (!archive.remove()) { std::cerr << qPrintable(QString::fromLatin1("Cannot delete file \"%1\": %2") .arg(QDir::toNativeSeparators(newInstallerBasePath), archive.errorString())) << std::endl; } if (result != EXIT_SUCCESS) return result; } result = EXIT_FAILURE; try { QFile installerBaseNew(newInstallerBasePath); #ifndef Q_OS_MACOS QFile installerBaseOld(target); QInstaller::openForAppend(&installerBaseNew); installerBaseNew.seek(installerBaseNew.size()); if (m_binaryLayout.magicMarker == QInstaller::BinaryContent::MagicInstallerMarker) { QInstaller::openForRead(&installerBaseOld); installerBaseOld.seek(m_binaryLayout.metaResourcesSegment.start()); QInstaller::appendData(&installerBaseNew, &installerBaseOld, installerBaseOld .size() - installerBaseOld.pos()); installerBaseOld.close(); } else { QInstaller::appendInt64(&installerBaseNew, 0); QInstaller::appendInt64(&installerBaseNew, 4 * sizeof(qint64)); QInstaller::appendInt64(&installerBaseNew, QInstaller::BinaryContent::MagicUninstallerMarker); QInstaller::appendInt64(&installerBaseNew, QInstaller::BinaryContent::MagicCookie); } installerBaseNew.close(); #else QString bundlePath; QInstaller::isInBundle(target, &bundlePath); QFile installerBaseOld(QDir(bundlePath).filePath(bundlePath + QLatin1String("/Contents/MacOS/") + QFileInfo(bundlePath).completeBaseName())); #endif QFile backup(installerBaseOld.fileName() + QLatin1String(".bak")); if (backup.exists() && (!backup.remove())) { std::cerr << qPrintable(QString::fromLatin1("Cannot delete \"%1\": %2") .arg(QDir::toNativeSeparators(backup.fileName()), backup.errorString())) << std::endl; } const QString oldBasePath = installerBaseOld.fileName(); if (!installerBaseOld.rename(oldBasePath + QLatin1String(".bak"))) { std::cerr << qPrintable(QString::fromLatin1("Cannot rename \"%1\" to \"%2\": %3") .arg(oldBasePath, oldBasePath + QLatin1String(".bak"), installerBaseOld.errorString())) << std::endl; } if (!installerBaseNew.rename(oldBasePath)) { std::cerr << qPrintable(QString::fromLatin1("Cannot copy \"%1\" to \"%2\": %3") .arg(installerBaseNew.fileName(), oldBasePath, installerBaseNew.errorString())) << std::endl; } else { result = EXIT_SUCCESS; installerBaseNew.setPermissions(installerBaseOld.permissions()); } } catch (const QInstaller::Error &error) { std::cerr << qPrintable(error.message()) << std::endl; } } catch (const QInstaller::TaskException &e) { std::cerr << qPrintable(e.message()) << std::endl; } catch (const QUnhandledException &e) { std::cerr << e.what() << std::endl; } catch (...) { std::cerr << "Unknown exception caught."<< std::endl; } return result; } qt-installer-framework-4.0.1/tools/devtool/binaryreplace.h0100777000000000000000000000311213761647206020702 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef BINARYREPLACE_H #define BINARYREPLACE_H #include class BinaryReplace { Q_DISABLE_COPY(BinaryReplace) public: BinaryReplace(const QInstaller::BinaryLayout &layout); int replace(const QString &source, const QString &target); private: QInstaller::BinaryLayout m_binaryLayout; }; #endif // BINARYREPLACE_H qt-installer-framework-4.0.1/tools/devtool/devtool.pro0100777000000000000000000000060613761647206020114 0ustar00TEMPLATE = app TARGET = devtool QT = core network qml xml include(../../installerfw.pri) CONFIG += console DESTDIR = $$IFW_APP_PATH HEADERS += operationrunner.h \ binaryreplace.h \ binarydump.h SOURCES += main.cpp \ operationrunner.cpp \ binaryreplace.cpp \ binarydump.cpp osx:include(../../no_app_bundle.pri) target.path = $$[QT_INSTALL_BINS] INSTALLS += target qt-installer-framework-4.0.1/tools/devtool/main.cpp0100777000000000000000000002462213761647206017352 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "binarydump.h" #include "binaryreplace.h" #include "operationrunner.h" #include #include #include #include #include #include #include #include #include #include #include #include #include struct Command { const char* command; const char* description; qint32 argC; const char* arguments; const char* argDescription; } Commands[] = { { "dump", "Dumps the binary content that belongs to an installer or maintenance tool into " "target directory.", 2, " ", "The containing the data to " "dump.\nThe to dump the data in." }, { "update", "Updates existing installer or maintenance tool with a new installer base.", 2, " ", "The to update.\nThe to use as update." }, { "operation", "Executes an operation with with a given mode and a list of arguments. ", 2, " ", "The to run the operation with.\n" " 'mode' can be DO or UNDO. 'name' of the operation. 'args,...' " "used to run the operation." } }; #define DESCRITION_LENGTH 60 #define SETW_ALIGNLEFT(X) std::setw(X) << std::setiosflags(std::ios::left) static int fail(const QString &message) { std::cerr << qPrintable(message) << " See 'devtool --help'." << std::endl; return EXIT_FAILURE; } static QStringList split(int index, const QString &description) { QStringList result; if (description.length() <= DESCRITION_LENGTH) return result << description; const int lastIndexOf = description.left(index + DESCRITION_LENGTH) .lastIndexOf(QLatin1Char(' ')); result << description.left(lastIndexOf); return result + split(lastIndexOf + 1, description.mid(lastIndexOf + 1)); } // -- main int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setApplicationVersion(QLatin1String("2.0.0")); QCommandLineParser parser; QCommandLineOption help = parser.addHelpOption(); QCommandLineOption version = parser.addVersionOption(); QCommandLineOption verbose(QLatin1String("verbose"), QLatin1String("Verbose mode. Prints out " "more information.")); parser.addOption(verbose); parser.parse(app.arguments()); if (parser.isSet(version)) { parser.showVersion(); return EXIT_SUCCESS; } if (parser.isSet(help)) { const QString command = parser.positionalArguments().value(0); if (!command.isEmpty()) { for (const auto &c : Commands) { if (QLatin1String(c.command) == command) { parser.clearPositionalArguments(); parser.addPositionalArgument(QString::fromLatin1("%1 %2").arg(QLatin1String(c .command), QLatin1String(c.arguments)), QLatin1String(c.argDescription)); parser.showHelp(EXIT_SUCCESS); } } return fail(QString::fromLatin1("\"%1\" is not a devtool command.").arg(command)); } QString helpText = parser.helpText(); helpText.insert(helpText.indexOf(QLatin1Char(']')) + 1, QLatin1String(" command ")); std::cout << qPrintable(helpText) << std::endl; std::cout << "Available commands (mutually exclusive):" << std::endl; for (const auto &c : Commands) { QStringList lines = split(0, QLatin1String(c.description)); std::cout << SETW_ALIGNLEFT(2) << " " << SETW_ALIGNLEFT(16) << c.command << SETW_ALIGNLEFT(DESCRITION_LENGTH) << qPrintable(lines.takeFirst()) << std::endl; foreach (const QString &line, lines) { std::cout << SETW_ALIGNLEFT(18) << QByteArray(18, ' ').constData() << qPrintable(line) << std::endl; } } std::cout << std::endl << "Use 'devtool --help ' to read about a specific command." << std::endl; return EXIT_SUCCESS; } QStringList arguments = parser.positionalArguments(); if (arguments.isEmpty()) return fail(QLatin1String("Missing command.")); bool found = false; const QString command = arguments.takeFirst(); for (const auto &c : Commands) { if ((found = (QLatin1String(c.command) == command))) { if (arguments.count() != c.argC) return fail(QString::fromLatin1("%1: wrong argument count.").arg(command)); break; } } if (!found) return fail(QString::fromLatin1("\"%1\" is not a devtool command.").arg(command)); QInstaller::init(); QInstaller::setVerbose(parser.isSet(verbose)); QString bundlePath; QString path = QFileInfo(arguments.first()).absoluteFilePath(); if (QInstaller::isInBundle(path, &bundlePath)) { path = QDir(bundlePath).filePath(QLatin1String("Contents/Resources/installer.dat")); } #ifndef Q_OS_MACOS QFileInfo fi = QFileInfo(path); bundlePath = path; QString tmp = QDir(fi.path()).filePath(QLatin1String("installer.dat")); if (QFileInfo::exists(tmp)) path = tmp; #endif int result = EXIT_FAILURE; QVector resourceMappings; quint64 cookie = QInstaller::BinaryContent::MagicCookie; try { { QFile tmp(path); QInstaller::openForRead(&tmp); if (!tmp.seek(QInstaller::BinaryContent::findMagicCookie(&tmp, cookie) - sizeof(qint64))) throw QInstaller::Error(QLatin1String("Cannot seek to read magic marker.")); QInstaller::BinaryLayout layout; layout.magicMarker = QInstaller::retrieveInt64(&tmp); if (layout.magicMarker == QInstaller::BinaryContent::MagicUninstallerMarker) { QFileInfo fi(path); QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath); fi.setFile(bundlePath); path = fi.absolutePath() + QLatin1Char('/') + fi.baseName() + QLatin1String(".dat"); tmp.close(); tmp.setFileName(path); QInstaller::openForRead(&tmp); cookie = QInstaller::BinaryContent::MagicCookieDat; } layout = QInstaller::BinaryContent::binaryLayout(&tmp, cookie); tmp.close(); if (command == QLatin1String("update")) { BinaryReplace br(layout); // To update the binary we do not need any mapping. return br.replace(arguments.last(), QFileInfo(arguments.first()) .absoluteFilePath()); } } QFile file(path); QInstaller::openForRead(&file); qint64 magicMarker; QList operations; QInstaller::ResourceCollectionManager manager; QInstaller::BinaryContent::readBinaryContent(&file, &operations, &manager, &magicMarker, cookie); // map the inbuilt resources const QInstaller::ResourceCollection meta = manager.collectionByName("QResources"); foreach (const QSharedPointer &resource, meta.resources()) { const bool isOpen = resource->isOpen(); if ((!isOpen) && (!resource->open())) continue; // TODO: should we throw here? const QByteArray ba = resource->readAll(); if (!QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) throw QInstaller::Error(QLatin1String("Cannot register in-binary resource.")); resourceMappings.append(ba); if (!isOpen) resource->close(); } if (command == QLatin1String("dump")) { // To dump the content we do not need the binary format engine. BinaryDump bd; result = bd.dump(manager, arguments.last()); } else if (command == QLatin1String("operation")) { QInstaller::BinaryFormatEngineHandler::instance()->registerResources(manager .collections()); // setup the binary format engine OperationRunner runner(magicMarker, operations); const QStringList operationArguments = arguments.last().split(QLatin1Char(',')); if (operationArguments.first() == QLatin1String("DO")) result = runner.runOperation(operationArguments.mid(1), OperationRunner::RunMode::Do); else if (operationArguments.first() == QLatin1String("UNDO")) result = runner.runOperation(operationArguments.mid(1), OperationRunner::RunMode::Undo); else std::cerr << "Malformed argument: " << qPrintable(operationArguments.last()) << std::endl; } } catch (const QInstaller::Error &error) { std::cerr << qPrintable(error.message()) << std::endl; } catch (...) { std::cerr << "Unknown exception caught." << std::endl; } // unmap resources foreach (const QByteArray &rccData, resourceMappings) QResource::unregisterResource((const uchar*) rccData.data(), QLatin1String(":/metadata")); return result; } qt-installer-framework-4.0.1/tools/devtool/operationrunner.cpp0100777000000000000000000000655013761647206021660 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "operationrunner.h" #include #include #include #include #include OperationRunner::OperationRunner(qint64 magicMarker, const QList &oldOperations) : m_core(new QInstaller::PackageManagerCore(magicMarker, oldOperations)) { // We need a package manager core as some operations expect them to be available. } OperationRunner::~OperationRunner() { delete m_core; } int OperationRunner::runOperation(QStringList arguments, RunMode mode) { int result = EXIT_FAILURE; try { const QString name = arguments.takeFirst(); QScopedPointer op(KDUpdater::UpdateOperationFactory::instance() .create(name, m_core)); if (!op) { std::cerr << "Cannot instantiate operation: " << qPrintable(name) << std::endl; return EXIT_FAILURE; } if (QObject *const object = dynamic_cast (op.data())) { const QMetaObject *const mo = object->metaObject(); if (mo->indexOfSignal(mo->normalizedSignature("outputTextChanged(QString)")) > -1) connect(object, SIGNAL(outputTextChanged(QString)), this, SLOT(print(QString))); } op->setArguments(arguments); bool readyPerformed = false; if (mode == RunMode::Do) readyPerformed = op->performOperation(); if (mode == RunMode::Undo) readyPerformed = op->undoOperation(); if (readyPerformed) { result = EXIT_SUCCESS; std::cout << "Operation finished successfully." << std::endl; } else { std::cerr << "An error occurred while performing the operation: " << qPrintable(op->errorString()) << std::endl; } } catch (const QInstaller::Error &e) { std::cerr << qPrintable(e.message()) << std::endl; } catch (...) { std::cerr << "Unknown exception caught." << std::endl; } return result; } void OperationRunner::print(const QString &value) { std::cout << qPrintable(value) << std::endl; } qt-installer-framework-4.0.1/tools/devtool/operationrunner.h0100777000000000000000000000360113761647206021317 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef OPERATIONRUNNER_H #define OPERATIONRUNNER_H #include #include namespace QInstaller { struct OperationBlob; class PackageManagerCore; } class OperationRunner : public QObject { Q_OBJECT Q_DISABLE_COPY(OperationRunner) public: enum struct RunMode { Do, Undo }; OperationRunner(qint64 magicMarker, const QList &oldOperations); ~OperationRunner(); int runOperation(QStringList arguments, RunMode mode); private slots: void print(const QString &value); private: QInstaller::PackageManagerCore *m_core; }; #endif // OPERATIONRUNNER_H qt-installer-framework-4.0.1/tools/repocompare/0040777000000000000000000000000013761647206016554 5ustar00qt-installer-framework-4.0.1/tools/repocompare/main.cpp0100777000000000000000000000461313761647206020210 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include #include #include #include "mainwindow.h" #include "repositorymanager.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QCoreApplication::setApplicationName(QLatin1String("IFW_repocompare")); if (a.arguments().contains(QLatin1String("-i"))) { if (a.arguments().count() != 5) { qWarning() << "Usage: " << a.arguments().at(0) << " -i "; return -1; } const QString productionRepo = a.arguments().at(2); const QString updateRepo = a.arguments().at(3); const QString outputFile = a.arguments().at(4); RepositoryManager manager; manager.setProductionRepository(productionRepo); manager.setUpdateRepository(updateRepo); a.connect(&manager, &RepositoryManager::repositoriesCompared, &a, &QApplication::quit); qDebug() << "Waiting for server reply..."; a.exec(); qDebug() << "Writing into " << outputFile; manager.writeUpdateFile(outputFile); return 0; } else { MainWindow w; w.show(); return a.exec(); } } qt-installer-framework-4.0.1/tools/repocompare/mainwindow.cpp0100777000000000000000000001212713761647206021437 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include namespace { const QLatin1String productionIdentifier = QLatin1String("ProductionRepositories"); const QLatin1String updateIdentifier = QLatin1String("UpdateRepositories"); void uniqueAppend(QComboBox* box, const QString &url) { const int itemCount = box->count(); for (int i = 0; i < itemCount; ++i) { if (box->itemText(i) == url) return; } box->insertItem(0, url); } QStringList itemsToList(QComboBox* box) { QStringList result; const int itemCount = box->count(); for (int i = 0; i < itemCount; ++i) { result.append(box->itemText(i)); } return result; } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QSettings settings; ui->productionRepo->insertItems(0, settings.value(productionIdentifier).toStringList()); ui->updateRepo->insertItems(0, settings.value(updateIdentifier).toStringList()); connect(ui->actionExit, &QAction::triggered, this, &QWidget::close); connect(ui->productionButton, &QAbstractButton::clicked, this, &MainWindow::getProductionRepository); connect(ui->updateButton, &QAbstractButton::clicked, this, &MainWindow::getUpdateRepository); connect(ui->exportButton, &QAbstractButton::clicked, this, &MainWindow::createExportFile); connect(&manager, &RepositoryManager::repositoriesCompared, this, &MainWindow::displayRepositories); } MainWindow::~MainWindow() { QSettings settings; settings.setValue(productionIdentifier, itemsToList(ui->productionRepo)); settings.setValue(updateIdentifier, itemsToList(ui->updateRepo)); delete ui; } void MainWindow::getProductionRepository() { manager.setProductionRepository(ui->productionRepo->currentText()); } void MainWindow::getUpdateRepository() { manager.setUpdateRepository(ui->updateRepo->currentText()); } void MainWindow::displayRepositories() { uniqueAppend(ui->productionRepo, ui->productionRepo->currentText()); uniqueAppend(ui->updateRepo, ui->updateRepo->currentText()); // First we put everything into the treeview for (int i = 0; i < 2; ++i) { QMap* map; if (i == 0) map = manager.productionComponents(); else map = manager.updateComponents(); int indexIncrement = 4*i; for (QMap::iterator it = map->begin(); it != map->end(); ++it) { QList list = ui->treeWidget->findItems(it.key(), Qt::MatchExactly); QTreeWidgetItem* item; if (list.size()) item = list.at(0); else item = new QTreeWidgetItem(ui->treeWidget); item->setText(0, it.key()); item->setText(indexIncrement + 3, it.value().version); item->setText(indexIncrement + 4, it.value().releaseDate.toString(QLatin1String("yyyy-MM-dd"))); item->setText(indexIncrement + 5, it.value().checksum); item->setText(indexIncrement + 6, it.value().updateText); if (i != 0) { QString errorText; if (manager.updateRequired(it.key(), &errorText)) item->setText(1, QLatin1String("Yes")); else item->setText(1, QLatin1String("No")); item->setText(2, errorText); } } } } void MainWindow::createExportFile() { QString fileName = QFileDialog::getSaveFileName(this, QLatin1String("Export File")); if (fileName.isEmpty()) return; manager.writeUpdateFile(fileName); } qt-installer-framework-4.0.1/tools/repocompare/mainwindow.h0100777000000000000000000000374713761647206021114 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include "repositorymanager.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: void displayRepositories(); void getProductionRepository(); void getUpdateRepository(); void createExportFile(); private: void createRepositoryMap(const QByteArray &data, QMap &map); Ui::MainWindow *ui; RepositoryManager manager; }; #endif // MAINWINDOW_H qt-installer-framework-4.0.1/tools/repocompare/mainwindow.ui0100777000000000000000000001166713761647206021302 0ustar00 MainWindow 0 0 877 613 RepoCompare 0 0 Production Repository: 0 0 true Receive Update Repository: 0 0 true Receive Component Name Update required Status Old Version Old Date Old Checksum Old Update Text New Version New Date New Checksum New Update Text Qt::Horizontal 40 20 Export Update File 0 0 877 21 File Exit qt-installer-framework-4.0.1/tools/repocompare/repocompare.pro0100777000000000000000000000046113761647206021613 0ustar00TEMPLATE = app INCLUDEPATH += . .. TARGET = repocompare include(../../installerfw.pri) QT += widgets network SOURCES += main.cpp\ mainwindow.cpp \ repositorymanager.cpp HEADERS += mainwindow.h \ repositorymanager.h FORMS += mainwindow.ui osx:include(../../no_app_bundle.pri) qt-installer-framework-4.0.1/tools/repocompare/repositorymanager.cpp0100777000000000000000000001626513761647206023044 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "repositorymanager.h" #include #include #include #include #include #include #include #include #include namespace { qreal createVersionNumber(const QString &text) { QStringList items = text.split(QLatin1Char('.')); QString last = items.takeLast(); items.append(last.split(QLatin1Char('-'))); qreal value = 0; if (items.count() == 4) value += qreal(0.01) * items.takeLast().toInt(); int multiplier = 10000; do { value += multiplier * items.takeFirst().toInt(); multiplier /= 100; } while (items.count()); return value; } } RepositoryManager::RepositoryManager(QObject *parent) : QObject(parent) { manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &RepositoryManager::receiveRepository); productionMap.clear(); updateMap.clear(); } void RepositoryManager::setProductionRepository(const QString &repo) { QUrl url(repo); if (!url.isValid()) { QMessageBox::critical(nullptr, QLatin1String("Error"), QLatin1String("Specified URL is not valid")); return; } QNetworkRequest request(url); productionReply = manager->get(request); } void RepositoryManager::setUpdateRepository(const QString &repo) { QUrl url(repo); if (!url.isValid()) { QMessageBox::critical(nullptr, QLatin1String("Error"), QLatin1String("Specified URL is not valid")); return; } QNetworkRequest request(url); updateReply = manager->get(request); } void RepositoryManager::receiveRepository(QNetworkReply *reply) { QByteArray data = reply->readAll(); if (reply == productionReply) { createRepositoryMap(data, productionMap); } else if (reply == updateReply) { createRepositoryMap(data, updateMap); } reply->deleteLater(); if (productionMap.size() && updateMap.size()) compareRepositories(); } void RepositoryManager::createRepositoryMap(const QByteArray &data, QMap &map) { QXmlStreamReader reader(data); QString currentItem; ComponentDescription currentDescription; while (!reader.atEnd()) { QXmlStreamReader::TokenType type = reader.readNext(); if (type == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("PackageUpdate")) { // new package if (!currentItem.isEmpty()) map.insert(currentItem, currentDescription); currentDescription.updateText.clear(); currentDescription.version.clear(); currentDescription.checksum.clear(); } if (reader.name() == QLatin1String("SHA1")) currentDescription.checksum = reader.readElementText(); else if (reader.name() == QLatin1String("Version")) currentDescription.version = reader.readElementText(); else if (reader.name() == QLatin1String("ReleaseDate")) { currentDescription.releaseDate = QDate::fromString(reader.readElementText(), QLatin1String("yyyy-MM-dd")); } else if (reader.name() == QLatin1String("UpdateText")) currentDescription.updateText = reader.readElementText(); else if (reader.name() == QLatin1String("Name")) currentItem = reader.readElementText(); } } // Insert the last item if (!currentItem.isEmpty()) map.insert(currentItem, currentDescription); } void RepositoryManager::compareRepositories() { for (QMap::iterator it = updateMap.begin(); it != updateMap.end(); ++it) { // New item in the update if (!productionMap.contains(it.key())) { it.value().update = true; continue; } it.value().update = updateRequired(it.key()); } emit repositoriesCompared(); } bool RepositoryManager::updateRequired(const QString &componentName, QString *message) { if (!productionMap.contains(componentName) || !updateMap.contains(componentName)) qFatal("Accessing non existing component"); const ComponentDescription &productionDescription = productionMap.value(componentName); const ComponentDescription &updateDescription = updateMap.value(componentName); if (createVersionNumber(productionDescription.version) < createVersionNumber(updateDescription.version)) { if (productionDescription.releaseDate > updateDescription.releaseDate) { if (message) { *message = QString::fromLatin1("Error: Component %1 has wrong release date %2") .arg(componentName).arg(updateDescription.releaseDate.toString()); } return false; } else if (productionDescription.updateText == updateDescription.updateText) if (message) { *message = QString::fromLatin1("Warning: Component %1 has no new update text: %2") .arg(componentName).arg(updateDescription.updateText); } if (message && message->isEmpty()) *message = QLatin1String("Ok"); return true; } return false; } void RepositoryManager::writeUpdateFile(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { QMessageBox::critical(nullptr, QLatin1String("Error"), QString::fromLatin1("Cannot open file \"%1\" for writing: %2").arg( QDir::toNativeSeparators(fileName), file.errorString())); return; } QStringList items; for (QMap::const_iterator it = updateMap.constBegin(); it != updateMap.constEnd(); ++it) { if (it.value().update) items.append(it.key()); } file.write(items.join(QLatin1String(",")).toLatin1()); file.close(); } qt-installer-framework-4.0.1/tools/repocompare/repositorymanager.h0100777000000000000000000000500113761647206022473 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #ifndef REPOSITORYMANAGER_H #define REPOSITORYMANAGER_H #include #include #include #include struct ComponentDescription { QString version; QDate releaseDate; QString checksum; QString updateText; bool update; }; class RepositoryManager : public QObject { Q_OBJECT public: explicit RepositoryManager(QObject *parent = 0); bool updateRequired(const QString &componentName, QString *message = 0); QMap* productionComponents() { return &productionMap; } QMap* updateComponents() { return &updateMap; } signals: void repositoriesCompared(); public slots: void setProductionRepository(const QString &repo); void setUpdateRepository(const QString &repo); void writeUpdateFile(const QString &fileName); void receiveRepository(QNetworkReply *reply); void compareRepositories(); private: void createRepositoryMap(const QByteArray &data, QMap &map); QNetworkReply *productionReply; QNetworkReply *updateReply; QNetworkAccessManager *manager; QMap productionMap; QMap updateMap; }; #endif // REPOSITORYMANAGER_H qt-installer-framework-4.0.1/tools/repogen/0040777000000000000000000000000013761647206015677 5ustar00qt-installer-framework-4.0.1/tools/repogen/repogen.cpp0100777000000000000000000003306613761647206020052 0ustar00/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "common/repositorygen.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) using namespace QInstaller; static void printUsage() { const QString appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); std::cout << "Usage: " << appName << " [options] repository-dir" << std::endl; std::cout << std::endl; std::cout << "Options:" << std::endl; QInstallerTools::printRepositoryGenOptions(); std::cout << " -r|--remove Force removing target directory if existent." << std::endl; std::cout << " --update Update a set of existing components (defined by " << std::endl; std::cout << " --include or --exclude) in the repository" << std::endl; std::cout << " --update-new-components Update a set of existing components (defined by " << std::endl; std::cout << " --include or --exclude) in the repository with all new components" << std::endl; std::cout << " -v|--verbose Verbose output" << std::endl; std::cout << " --unite-metadata Combine all metadata into one 7z. This speeds up metadata " << std::endl; std::cout << " download phase." << std::endl; std::cout << " --component-metadata Creates one metadata 7z per component. " << std::endl; std::cout << std::endl; std::cout << "Example:" << std::endl; std::cout << " " << appName << " -p ../examples/packages repository/" << std::endl; } static int printErrorAndUsageAndExit(const QString &err) { std::cerr << qPrintable(err) << std::endl << std::endl; printUsage(); return 1; } int main(int argc, char** argv) { QString tmpMetaDir; int exitCode = EXIT_FAILURE; try { QCoreApplication app(argc, argv); QInstaller::init(); QStringList args = app.arguments().mid(1); QStringList filteredPackages; bool updateExistingRepository = false; QStringList packagesDirectories; QStringList repositoryDirectories; QInstallerTools::FilterType filterType = QInstallerTools::Exclude; bool remove = false; bool updateExistingRepositoryWithNewComponents = false; bool createUnifiedMetadata = true; bool createComponentMetadata = true; //TODO: use a for loop without removing values from args like it is in binarycreator.cpp //for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { while (!args.isEmpty() && args.first().startsWith(QLatin1Char('-'))) { if (args.first() == QLatin1String("--verbose") || args.first() == QLatin1String("-v")) { args.removeFirst(); setVerbose(true); } else if (args.first() == QLatin1String("--exclude") || args.first() == QLatin1String("-e")) { args.removeFirst(); if (!filteredPackages.isEmpty()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: --include and --exclude are mutually exclusive. Use either one or " "the other.")); } if (args.isEmpty() || args.first().startsWith(QLatin1Char('-'))) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Package to exclude missing")); } filteredPackages = args.first().split(QLatin1Char(',')); args.removeFirst(); } else if (args.first() == QLatin1String("--include") || args.first() == QLatin1String("-i")) { args.removeFirst(); if (!filteredPackages.isEmpty()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: --include and --exclude are mutually exclusive. Use either one or " "the other.")); } if (args.isEmpty() || args.first().startsWith(QLatin1Char('-'))) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Package to include missing")); } filteredPackages = args.first().split(QLatin1Char(',')); args.removeFirst(); filterType = QInstallerTools::Include; } else if (args.first() == QLatin1String("--update")) { args.removeFirst(); updateExistingRepository = true; } else if (args.first() == QLatin1String("--update-new-components")) { args.removeFirst(); updateExistingRepositoryWithNewComponents = true; createUnifiedMetadata = false; } else if (args.first() == QLatin1String("-p") || args.first() == QLatin1String("--packages")) { args.removeFirst(); if (args.isEmpty()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Packages parameter missing argument")); } const QDir dir(args.first()); if (!dir.exists()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Package directory not found at the specified location")); } if (dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).isEmpty()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Package directory is empty")); } packagesDirectories.append(args.first()); args.removeFirst(); } else if (args.first() == QLatin1String("--repository")) { args.removeFirst(); if (args.isEmpty()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Repository parameter missing argument")); } if (!QFileInfo(args.first()).exists()) { return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Only local filesystem repositories now supported")); } repositoryDirectories.append(args.first()); args.removeFirst(); } else if (args.first() == QLatin1String("--ignore-translations") || args.first() == QLatin1String("--ignore-invalid-packages")) { args.removeFirst(); } else if (args.first() == QLatin1String("-r") || args.first() == QLatin1String("--remove")) { remove = true; args.removeFirst(); } else if (args.first() == QLatin1String("--unite-metadata")) { createComponentMetadata = false; args.removeFirst(); } else if (args.first() == QLatin1String("--component-metadata")) { createUnifiedMetadata = false; args.removeFirst(); } else { printUsage(); return 1; } } if ((packagesDirectories.isEmpty() && repositoryDirectories.isEmpty()) || (args.count() != 1)) { printUsage(); return 1; } const bool update = updateExistingRepository || updateExistingRepositoryWithNewComponents; if (remove && update) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", "Argument -r|--remove and --update|--update-new-components are mutually exclusive!")); } const QString repositoryDir = QInstallerTools::makePathAbsolute(args.first()); if (remove) QInstaller::removeDirectory(repositoryDir); if (updateExistingRepositoryWithNewComponents) { QStringList meta7z = QDir(repositoryDir).entryList(QStringList() << QLatin1String("*_meta.7z"), QDir::Files); if (!meta7z.isEmpty()) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", "Cannot update \"%1\" with --update-new-components. Use --update instead. " "Currently it is not possible to update partial components inside one 7z.") .arg(meta7z.join(QLatin1Char(',')))); } } if (!update && QFile::exists(repositoryDir) && !QDir(repositoryDir).entryList( QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", "Repository target directory \"%1\" already exists.").arg(QDir::toNativeSeparators(repositoryDir))); } QInstallerTools::PackageInfoVector packages; QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories, &filteredPackages, filterType); packages.append(precompressedPackages); QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories, &filteredPackages, filterType); packages.append(preparedPackages); if (updateExistingRepositoryWithNewComponents) { QInstallerTools::filterNewComponents(repositoryDir, packages); if (packages.isEmpty()) { std::cout << QString::fromLatin1("Cannot find new components to update \"%1\".") .arg(repositoryDir) << std::endl; return EXIT_SUCCESS; } } QHash pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(packages); foreach (const QInstallerTools::PackageInfo &package, packages) { const QFileInfo fi(repositoryDir, package.name); if (fi.exists()) removeDirectory(fi.absoluteFilePath()); } QTemporaryDir tmp; tmp.setAutoRemove(false); tmpMetaDir = tmp.path(); QStringList directories; directories.append(packagesDirectories); directories.append(repositoryDirectories); QStringList unite7zFiles; foreach (const QString &repositoryDirectory, repositoryDirectories) { QDirIterator it(repositoryDirectory, QStringList(QLatin1String("*_meta.7z")) , QDir::Files | QDir::CaseSensitive); while (it.hasNext()) { it.next(); unite7zFiles.append(it.fileInfo().absoluteFilePath()); } } QInstallerTools::copyComponentData(directories, repositoryDir, &packages); QInstallerTools::copyMetaData(tmpMetaDir, repositoryDir, packages, QLatin1String("{AnyApplication}"), QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)), unite7zFiles); QString existing7z = QInstallerTools::existingUniteMeta7z(repositoryDir); if (!existing7z.isEmpty()) existing7z = repositoryDir + QDir::separator() + existing7z; QInstallerTools::compressMetaDirectories(tmpMetaDir, existing7z, pathToVersionMapping, createComponentMetadata, createUnifiedMetadata); QDirIterator it(repositoryDir, QStringList(QLatin1String("Updates*.xml")) << QLatin1String("*_meta.7z"), QDir::Files | QDir::CaseSensitive); while (it.hasNext()) { it.next(); QFile::remove(it.fileInfo().absoluteFilePath()); } QInstaller::moveDirectoryContents(tmpMetaDir, repositoryDir); exitCode = EXIT_SUCCESS; } catch (const Lib7z::SevenZipException &e) { std::cerr << "Caught 7zip exception: " << e.message() << std::endl; } catch (const QInstaller::Error &e) { std::cerr << "Caught exception: " << e.message() << std::endl; } catch (...) { std::cerr << "Unknown exception caught" << std::endl; } QInstaller::removeDirectory(tmpMetaDir, true); return exitCode; } qt-installer-framework-4.0.1/tools/repogen/repogen.pri0100777000000000000000000000003713761647206020052 0ustar00INCLUDEPATH += $$PWD/../common qt-installer-framework-4.0.1/tools/repogen/repogen.pro0100777000000000000000000000056113761647206020062 0ustar00TEMPLATE = app TARGET = repogen INCLUDEPATH += . .. include(repogen.pri) include(../../installerfw.pri) QT -= gui QT += qml xml CONFIG += console DESTDIR = $$IFW_APP_PATH SOURCES += repogen.cpp \ ../common/repositorygen.cpp HEADERS += ../common/repositorygen.h macx:include(../../no_app_bundle.pri) target.path = $$[QT_INSTALL_BINS] INSTALLS += target qt-installer-framework-4.0.1/tools/tools.pro0100777000000000000000000000016213761647206016121 0ustar00TEMPLATE = subdirs SUBDIRS += \ archivegen \ binarycreator \ repogen \ devtool \ repocompare